不具合修正中です。潜在的なバグのパターンを定義する機能に不具合あるので直します。あと、SAS9.4TS1M4に合わせて、キーワードを修正しないといけない。
SASプログラムとログを解析するユーティリティを開発するための備忘録です。This is a memo to develop utility that analyzes the SAS log.
2017年5月8日月曜日
2016年8月3日水曜日
SAS Metadata API
調べ物のメモです。
メターデータのAPIを使うと、ユーザのDescriptionやメールアドレスを設定できます。
rc = metadata_setattr("omsobj:Person?@Name='ogawan'","Desc", "hogehoge");
メターデータのAPIを使うと、ユーザのDescriptionやメールアドレスを設定できます。
2016年7月13日水曜日
次に作りたいツール, Metadata Serverに登録されているユーザにグループを設定/解除するスクリプト
決定版のスクリプトがないので、自分で作ることにします。
欲しい機能を書きとめておきます。
欲しい機能を書きとめておきます。
- ユーザを登録する機能
- ユーザを削除する機能
- 全ユーザとそのグループとロールの一覧を表示する機能
- 全グループの一覧を表示する機能
- ユーザに対して1つ以上のグループを設定する機能
- ユーザに対して1つ以上のロールを設定する機能
- 変更前にバックアップ用のデータをファイルに保存する機能
- UNIXのシェルから実行できること
- エラーのログファイルを指定できること
- 指定されたファイルを読み込んで、まとめて複数のユーザを登録できること
- 指定されたファイルを読み込んで、まとめて複数のユーザを削除できること
GUIを組みたいが、APIとしてはJavaかC#を使う必要がある。
C#はDelphiを選ぶ前に試しで画面組んだが、もう5年以上も触っていない。
UNIXのログインしてスクリプトたたかずに、PCクライアントからツールを起動して、登録と確認できたら良いです。
まずは、スクリプトを目標にします。
2016年3月27日日曜日
VBScriptでタスクスケジューラの複数のタスクをXMLに出力、削除、作成
EGで登録したスケジュールのタスクを、他のユーザへ定期的に引き渡すためにVBScriptを組みました。特定のタスクをXMLファイルに出力、削除、登録します。
SCHTASKSを使っていますが、これ1つの操作で1タスクしか定義できません。じゃあPowerShellで書こうかと思ったのですが、お客様先の環境だと使えないことが多いためVBScriptで書きました。
SCHTASKSを使っていますが、これ1つの操作で1タスクしか定義できません。じゃあPowerShellで書こうかと思ったのですが、お客様先の環境だと使えないことが多いためVBScriptで書きました。
- tasks_list.vbs でXMLファイルを作成
- tasks_delete.vbs でタスクを削除
- tasks_create.vbs でタスクを作成
キーワードを含む名前のタスクをXML形式で出力します。
'----
' Windowsのタスク スケジューラから指定された名前のタスクをXML形式で表示します。
' 標準出力にはログ、標準エラー出力にはXMLを出力します。
' 使用例: C:\Windows\System32\cscript //b c:\temp\tasks_list.vbs 1> tasks.log 2> tasks.xml
'----
Option Explicit
Dim objShell
Dim objExec
Dim objDictionary
Dim objFso
Dim strLine
Dim strCmd
Dim Count
Dim Name
Dim QuitCode
Const MINIMIZE_WINDOW = 2
Const SCHTASKS = "C:\Windows\System32\SCHTASKS.EXE"
Const KEYWORD = "スケジュール - "
'----
' チェック関数
'----
Function CheckError(fnName)
CheckError = False
Dim strmsg
Dim errNum
If Err.Number <> 0 Then
strmsg = "ERROE: #" & Hex(Err.Number) & " in module " & fnName & " " & Err.Description
WScript.Stdout.WriteLine strmsg
CheckError = True
End If
End Function
'----
' オブジェクト生成
'----
Set objShell = WScript.CreateObject("WScript.Shell")
Set objDictionary = WScript.CreateObject("Scripting.Dictionary")
Set objFso = WScript.CreateObject("Scripting.FileSystemObject")
'----
' タスク一覧表示
'----
Sub Main()
Dim ExitCode
Dim ErrCount
'----
' タスク一覧から削除対象のタスク名を取得
'----
Set objExec = objShell.Exec(SCHTASKS & " /query /fo:csv")
Count = 0
Do Until objExec.StdOut.AtEndOfStream
strLine = objExec.StdOut.ReadLine
If InStr(strLine, KEYWORD) <> 0 Then
Count = Count + 1
objDictionary.Add Count, Mid(strLine, 1, InStr(strLine, ""","))
End If
Loop
If objExec.ExitCode <> 0 Then
Do Until objExec.StdErr.AtEndOfStream
WScript.StdOut.WriteLine objExec.StdErr.ReadLine
Loop
Err.Raise(51)
End If
Set objExec = Nothing
'----
' 件数を出力
'----
WScript.StdOut.WriteLine "NOTE: found " & Count & " tasks to export."
'----
' タスクをXML形式で表示
'----
For Each Name In objDictionary.Keys
strCmd = SCHTASKS & " /query /xml /tn:" & objDictionary(Name)
WScript.StdOut.WriteLine strCmd
Set objExec = objShell.Exec(strCmd)
WScript.StdErr.WriteLine("")
Do Until objExec.StdOut.AtEndOfStream
WScript.StdErr.WriteLine(objExec.StdOut.ReadLine)
Loop
WScript.StdErr.WriteLine("")
If objExec.ExitCode <> 0 Then
Do Until objExec.StdErr.AtEndOfStream
WScript.StdOut.WriteLine objExec.StdErr.ReadLine
Loop
Err.Raise(51)
End If
Set objExec = Nothing
Next
End Sub
'----
' 処理実行
'----
Sub Try()
Call Main()
End Sub
'----
' エラー捕捉
'----
Sub Catch()
On Error Resume Next
Call Try()
End Sub
'----
' 処理実行
'----
QuitCode=0
WScript.StdOut.WriteLine "NOTE: script=" & WScript.ScriptFullName & " date=" & Now()
Call Catch()
If CheckError("Catch") Then
QuitCode = 1
End If
'----
' 終了
'----
Set objShell = Nothing
Set objDictionary = Nothing
Set objFso = Nothing
WScript.StdOut.WriteLine "NOTE: script finished with exit code " & QuitCode
WScript.Quit QuitCode
特定の名前のタスクを削除します。
'----
' Windowsのタスク スケジューラから指定された名前のタスクを削除します。
' 標準出力に削除のログを出力します。
' 使用例: C:\Windows\System32\cscript //b c:\temp\tasks_delete.vbs > tasks_delete_%date:~-2,2%.log
'----
Option Explicit
Dim objShell
Dim objExec
Dim objDictionary
Dim objFso
Dim strLine
Dim strCmd
Dim Count
Dim Name
Dim objFile
Dim QuitCode
Const SCSHTASKS = "C:\Windows\System32\SCHTASKS.EXE"
'----
' 削除するタスク名の名前
'----
Const KEYWORD = "スケジュール - "
'----
' チェック関数
'----
Function CheckError(fnName)
CheckError = False
Dim strmsg
Dim errNum
If Err.Number <> 0 Then
strmsg = "ERROE: #" & Hex(Err.Number) & " in module " & fnName & " " & Err.Description
WScript.Stdout.WriteLine strmsg
CheckError = True
End If
End Function
'----
' オブジェクト生成
'----
Set objShell = WScript.CreateObject("WScript.Shell")
Set objDictionary = WScript.CreateObject("Scripting.Dictionary")
Set objFso = WScript.CreateObject("Scripting.FileSystemObject")
'----
' タスク削除
'----
Sub Main()
Dim ExitCode
Dim ErrCount
'----
' タスク一覧から削除対象のタスク名を取得
'----
Set objExec = objShell.Exec(SCSHTASKS & " /query /fo:csv")
Count = 0
Do Until objExec.StdOut.AtEndOfStream
strLine = objExec.StdOut.ReadLine
If InStr(strLine, KEYWORD) <> 0 Then
Count = Count + 1
objDictionary.Add Count, Mid(strLine, 1, InStr(strLine, ""","))
End If
Loop
If objExec.ExitCode <> 0 Then
Do Until objExec.StdErr.AtEndOfStream
WScript.StdOut.WriteLine objExec.StdErr.ReadLine
Loop
Err.Raise(51)
End If
Set objExec = Nothing
'----
' 件数を出力
'----
WScript.StdOut.WriteLine "NOTE: found " & Count & " tasks to delete."
'----
' タスクを削除
'----
For Each Name In objDictionary.Keys
strCmd = SCSHTASKS & " /delete /f /tn " & objDictionary(Name)
WScript.StdOut.WriteLine strCmd
Set objExec = objShell.Exec(strCmd)
Do Until objExec.StdOut.AtEndOfStream
WScript.StdOut.WriteLine objExec.StdOut.ReadLine
Loop
If objExec.ExitCode <> 0 Then
Do Until objExec.StdErr.AtEndOfStream
WScript.StdOut.WriteLine objExec.StdErr.ReadLine
Loop
Err.Raise(51)
End If
Set objExec = Nothing
Next
End Sub
'----
' 処理実行
'----
Sub Try()
Call Main()
End Sub
'----
' エラー捕捉
'----
Sub Catch()
On Error Resume Next
Call Try()
End Sub
'----
' 処理実行
'----
QuitCode = 0
WScript.StdOut.WriteLine "NOTE: script=" & WScript.ScriptFullName & " date=" & Now()
Call Catch()
If CheckError("Catch") Then
QuitCode = 1
End If
'----
' 終了
'----
Set objShell = Nothing
Set objDictionary = Nothing
Set objFso = Nothing
WScript.StdOut.WriteLine "NOTE: script finished with exit code " & QuitCode
WScript.Quit QuitCode
XMLファイルからタスクを作成します。
'---- ' WindowsのタスクをXMLファイルから定義します。 ' 引数に tasks_list.vbs で作成したXMLファイルを指定します。 ' タスクの実行ユーザは、スクリプトの実行者に置き換えられます。 ' 使用例: C:\Windows\System32\cscript //b c:\temp\tasks_create.vbs tasks.xml '---- Option Explicit Dim objShell Dim objExec Dim objDictionary Dim objFso Dim strLine Dim strCmd Dim Count Dim Name Dim objFile Dim xmlFile Dim QuitCode Const SCSHTASKS = "C:\Windows\System32\SCHTASKS.EXE" '---- ' 実行ユーザのキーワード '---- Const KEYWORD = "" '---- ' チェック関数 '---- Function CheckError(fnName) CheckError = False Dim strmsg Dim errNum If Err.Number <> 0 Then strmsg = "ERROE: #" & Hex(Err.Number) & " in module " & fnName & " " & Err.Description WScript.Stdout.WriteLine strmsg CheckError = True End If End Function '---- ' XMLのコメントからユーザ名を取得 '---- Function XmlUserName(Buf) Dim Pos1, Pos2 Const Keyword1 = "username=" Const Keyword2 = " -->" XmlUserName = "N/A" Pos1 = InStr(Buf, Keyword1) Pos2 = InStr(Buf, Keyword2) If Pos1 <> 0 And Pos2 <> 0 Then XmlUserName = Mid(Buf, Pos1 + Len(Keyword1), Pos2 - (Pos1 + Len(Keyword1))) End If End Function '---- ' XMLのコメントからタスク名を取得 '---- Function XmlTaskName(Buf) Dim Pos1, Pos2 Dim AryStrings Const Keyword1 = "<!-- end " Const Keyword2 = "username=" XmlTaskName = "N/A" Pos1 = InStr(Buf, Keyword1) Pos2 = InStr(Buf, Keyword2) If Pos1 <> 0 And Pos2 <> 0 Then XmlTaskName = Trim(Mid(Buf, Pos1 + Len(Keyword1), Pos2 - (Pos1 + Len(Keyword1)))) XmlTaskName = Mid(XmlTaskName, 2, Len(XmlTaskName) - 2) AryStrings = Split(XmlTaskName, "\") XmlTaskName = AryStrings(UBound(AryStrings)) End If End Function '---- ' オブジェクト生成 '---- Set objShell = WScript.CreateObject("WScript.Shell") Set objDictionary = WScript.CreateObject("Scripting.Dictionary") Set objFso = WScript.CreateObject("Scripting.FileSystemObject") '---- ' タスク定義 '---- Sub Main() Dim UserName Dim TaskName Dim FilePath '---- ' テンポラリファイルのパスを設定 '---- FilePath = objShell.ExpandEnvironmentStrings("%TEMP%") & "\task.xml" '---- ' 引数のXMLファイルを開く '---- If WScript.Arguments.Count <> 1 Then Err.Rase(51) End If Set objFile = objFso.OpenTextFile(WScript.Arguments.Item(0)) Count = 0 strLine = objFile.ReadLine Do Until objFile.AtEndOfStream If InStr(strLine, "<!-- begin") <> 0 Then Set xmlFile = objFSO.OpenTextFile(FilePath, 2, True) strLine = objFile.ReadLine Do Until objFile.AtEndOfStream or (InStr(strLine, "<!-- end") <> 0) ' ユーザIDを書き換える If InStr(strLine, KEYWORD) = 1 Then strLine = " " & objShell.ExpandEnvironmentStrings("%USERDOMAIN%") & "\" & objShell.ExpandEnvironmentStrings("%USERNAME%") & " " End If xmlFile.WriteLine strLine strLine = objFile.ReadLine Loop UserName = xmlUserName(strLine) TaskName = xmlTaskName(strLine) xmlFile.Close '---- ' タスク登録 '---- Count = Count + 1 strCmd = SCSHTASKS & " /create /xml """ & FilePath & """ /tn:""EG\" & UserName & "." & Right("000" & Count, 3) & " " & TaskName & """" WScript.StdOut.WriteLine strCmd Set objExec = objShell.Exec(strCmd) Do Until objExec.StdOut.AtEndOfStream WScript.StdOut.WriteLine objExec.StdOut.ReadLine Loop If objExec.ExitCode <> 0 Then Do Until objExec.StdErr.AtEndOfStream WScript.StdOut.WriteLine objExec.StdErr.ReadLine Loop Err.Raise(51) End If Set objExec = Nothing End If If objFile.AtEndOfStream = False Then strLine = objFile.ReadLine End If Loop '---- ' 件数を出力 '---- WScript.StdOut.WriteLine "NOTE: create " & Count & " tasks." '---- ' テンポラリのXMLファイルを削除 '---- objFso.DeleteFile FilePath, True End Sub '---- ' 処理実行 '---- Sub Try() Call Main() End Sub '---- ' エラー捕捉 '---- Sub Catch() On Error Resume Next Call Try() End Sub '---- ' 処理実行 '---- QuitCode = 0 WScript.StdOut.WriteLine "NOTE: script=" & WScript.ScriptFullName & " date=" & Now() Call Catch() If CheckError("Catch") Then QuitCode = 1 End If '---- ' 終了 '---- Set objShell = Nothing Set objDictionary = Nothing Set objFso = Nothing WScript.StdOut.WriteLine "NOTE: script finished with exit code " & QuitCode WScript.Quit QuitCode
2016年2月21日日曜日
SAS Log Utility 1.8.1.1, ログファイルのエンコーディングを判定
Vectorに新しいバージョンの公開を依頼しました。今回の修正内容は以下のとおりです。
ログファイルのエンコーディング判定は、ココの情報が役立ちました。これが無ければ、短時間で実装できなかったです。
ListViewのソートは、DEBUGのシンボルを定義したときと、外したときで動作が異なっていました。原因分からず。機能的には、だいぶ落ち着いてきたと思います。そろそろメジャーバージョンを上げて、処理構造の無駄を取り除きたいです。
- 不具合の修正
- SASログファイルのエンコーディングを自動判定
- SJIS, JIS, EUC, UTF8N, UTF8, UTF7など複数のエンコーディングに対応
- Optionsのメニューの構成を変更
- 日本語のマッチングパターン(keyword.ini)を訂正
ログファイルのエンコーディング判定は、ココの情報が役立ちました。これが無ければ、短時間で実装できなかったです。
ListViewのソートは、DEBUGのシンボルを定義したときと、外したときで動作が異なっていました。原因分からず。機能的には、だいぶ落ち着いてきたと思います。そろそろメジャーバージョンを上げて、処理構造の無駄を取り除きたいです。
2016年2月17日水曜日
EncodeDetect.pas
開発のメモです。
ログファイルのエンコーディング判定の関数、下にネタがあります。
これを使ってコードを判定、TEncodeingを生成した後します。
StringListからEncodingを指定して、読み取ると正しく読み取れました。
試しにElapsed Timeの表示に組み込んだらあっさりと動きました。
ログファイルのエンコーディング判定の関数、下にネタがあります。
EncodeDetect : EncodeDetectリファレンス
http://www.watercolor-city.net/ct_delphi/delphi_tiburon/doc_thirdparty/tp_ed_ref.htmこれを使ってコードを判定、TEncodeingを生成した後します。
StringListからEncodingを指定して、読み取ると正しく読み取れました。
試しにElapsed Timeの表示に組み込んだらあっさりと動きました。
2016年2月15日月曜日
2016年2月14日日曜日
SAS Log Utilityの概要
2009年に書いたツールの概要を加筆します。
SAS Log Utilityの概要について説明します。
概要
SAS Log Utilityは、SASプログラムが出力するログファイルを分析して、パフォーマンス診断や入出力の解析に役立つ情報を作成します。SAS Log Utilityを使うと以下のことができます。
SAS Log Utilityの概要について説明します。
概要
SAS Log Utilityは、SASプログラムが出力するログファイルを分析して、パフォーマンス診断や入出力の解析に役立つ情報を作成します。SAS Log Utilityを使うと以下のことができます。
- SASプログラムの処理時間をDATAステップで集計して、ボトルネックとなっている処理を見つけることができます。
- SASプログラムがどのようなデータを読み書きしているか、DATAステップ又はプロシージャ単位で捉えて、データの流れを理解することができます。
- MPRINTのログを捉えて、マクロ単位の処理時間を集計します。
- 複数のSASプログラムがどのようなデータを読み書きし、プログラム間でのデータの連携を可視化します。
- SASログからDATAステップ/プロシージャ単位の処理時間を抽出
- SASログから処理時間を抽出し、データセット単位で処理に要した時間を集計
- SASログからDATAステップ/プロシージャの入出力を抽出し、データの生成、読み取り、更新、削除の流れを表形式に出力
- 設定ファイルの切り替えで、日本語と英語のSASログに対応
- エラーにつながるNOTE:のメッセージをSASログから捕捉
- INIファイルを追加、修正して日本語、英語以外のSASログを解析可能
- SASログからMPRINTのログを抽出し、マクロ単位の処理時間を集計
- SASログの分析結果をExcelに出力
SAS Log Utility 1.7.1.16, 不具合修正と設定ファイルの切り替え機能を追加
Vectorに新しいバージョンの公開を依頼しました。今回の修正内容は以下のとおりです。
今回、日本語、英語の設定を分けたのが大きな変更点です。仕組みとしてはnlsフォルダの下に、ISO言語省略名のサブフォルダを定義して、INIファイルを作成すれば、他の言語も追加できます。が、まだ検証できていません。
修正した不具合は以下のものです。
他の言語の対応は、時間のあるときに試したいです。
開発で謎なのが、Patterns... のボタンにアイコンを表示していたのですが、いつのまにか表示されなくなりました。IDEの中だと、鉛筆のマークが出ているのですが、実行すると消えてしまいます。この検証はまた時間のあるときに行います。
- 不具合の修正
- 日本語と英語の設定ファイルを分けて、nlsのサブフォルダ下に移動
- システムのデフォルトの言語から、設定ファイルを切り替えるように修正
- Optionsのメニューの構成を変更
今回、日本語、英語の設定を分けたのが大きな変更点です。仕組みとしてはnlsフォルダの下に、ISO言語省略名のサブフォルダを定義して、INIファイルを作成すれば、他の言語も追加できます。が、まだ検証できていません。
修正した不具合は以下のものです。
- FILENAMEを使わないで直接ファイルのパスを指定しているときに、入出力を捕捉できない
- データセット名の変更が正しくCRUD表に反映されない
- 英語のSASログで、データセットの書き込み(W)が正しく反映されない
他の言語の対応は、時間のあるときに試したいです。
開発で謎なのが、Patterns... のボタンにアイコンを表示していたのですが、いつのまにか表示されなくなりました。IDEの中だと、鉛筆のマークが出ているのですが、実行すると消えてしまいます。この検証はまた時間のあるときに行います。
2016年2月13日土曜日
Delphi 条件付コンパイルの設定
開発のメモです。
リリース、デバッグ版とは別にインターナルのバージョンを作りました。条件付コンパイルの設定が分からなかったので、設定画面を貼り付けておきます。Vectorに載せるリリース版から分岐して、仕事で使うためのバージョンを作成しました。
土曜日の作業で、英語版の設定ファイルが8割がたできました。
明日、まとめてVectorに新しいバージョンを載せたいです。
2016年2月9日火曜日
NLS下のフォルダを探して、メニューを設定する(2)
開発のメモです。
設定ボタンの配置を換えました。
設定ボタンに16x16のアイコンを設定しました。
ISO言語省略名の選択は、ラジオボタンのタイプに変更しました。
潜在的なバグを見つけ出すパターンの設定は、Potential Problemのタブの下に移動しました。
言語の設定を切り替えるたびに、設定ファイルを読み直すように実装しました。
今日は、有給休暇でした。
銀行の手続きで3時間も掛かりました。
2016年2月7日日曜日
2016年2月1日月曜日
SAS Log Utility, 多言語対応の仕組みを考える
多言語対応で必要なものは何?
設定ファイルは、ISO言語省略名ごとに保持できるようにしたい。
どこに、設定ファイルを保持するか?
!SASROOT\nls\ja の形に倣って設定ファイルを配置するか?
それとも、設定ファイルの後ろにISO言語省略名を付与するのか?
LOCALEの取得は、Windows.GetLocaleInfoでできる。
言語の切り替えは、メニューから行う。
切り替えはツールの再起動なしで、反映できるようにしたい。
言語を切り替えて、ダイアログの表示を切り替えられるか?
reinit.ReinitializeFormsは使えるのか?
reinit.LoadNewResourceModuleは使えるのか?
他に使い出のあるものは何?
マイグレーション案件、面倒なことが色々ある。
何か効率化できるネタはないか。
VAの構成って面倒、設定だけではなくエビデンスの取得もできる何かが欲しい。
移行で毎回手を焼くのが、過去データの移送と変換です。
量が多いので、並列化したり、夜間に差分検出して移送する、中断、再開の制御を入れています。
他には?
BI Serverの構成が面倒です。
SMCの管理は苦手なのです、私はね。
設定ファイルは、ISO言語省略名ごとに保持できるようにしたい。
どこに、設定ファイルを保持するか?
!SASROOT\nls\ja の形に倣って設定ファイルを配置するか?
それとも、設定ファイルの後ろにISO言語省略名を付与するのか?
LOCALEの取得は、Windows.GetLocaleInfoでできる。
言語の切り替えは、メニューから行う。
切り替えはツールの再起動なしで、反映できるようにしたい。
言語を切り替えて、ダイアログの表示を切り替えられるか?
reinit.ReinitializeFormsは使えるのか?
reinit.LoadNewResourceModuleは使えるのか?
他に使い出のあるものは何?
マイグレーション案件、面倒なことが色々ある。
何か効率化できるネタはないか。
VAの構成って面倒、設定だけではなくエビデンスの取得もできる何かが欲しい。
移行で毎回手を焼くのが、過去データの移送と変換です。
量が多いので、並列化したり、夜間に差分検出して移送する、中断、再開の制御を入れています。
他には?
BI Serverの構成が面倒です。
SMCの管理は苦手なのです、私はね。
2016年1月30日土曜日
きっと役立つ、バグになりそうなNOTE:のチェック
SAS Log Utilityには、エラーでもなく、ワーニングでもないけど、バグになりそうなメッセージをチェックする機能があります。2013年頃投稿、2016年1月30日更新です。
関数の引数無効とかは、意外と気がつきにくいです。
- 変数 ABC は初期化されていません
- 以下の箇所で文字値を数値に変換しました
- 以下の箇所で数値を文字値に変換しました
- ステートメントに BY値を繰り返すデータセットが複数あります
- 欠損値を含んだ計算により、以下の箇所で欠損値が生成されました
- 切り捨てられた行があります
- カラム999で0による割り算がありました
- 関数XYZ(行999 カラム999の引数は無効です
- LOST CARD.
- NOEXECオプションが指定
- ループが発生したため、DATAステップの実行を中止しました
- 引用符で囲まれた文字列の後の識別子の意味は
- 数値をプリントするには小さすぎるW.D出力形式
- ライブラリABCは存在しません
- クエリは元のデータに要約統計量の結果を再マージします
- データセットABCにオブザベーションがありません
- ファイルABC(memtype=DATA)は見つかりませんが、DELETEステートメントに存在します
- ABCは未参照のラベル定義です
- ABCに対して、無効なデータが行999カラム999にあります
- ステートメントが行の終端に達したので、次の行を読み込みます
- 要約化中にディスク処理が発生しました
- CASE式にELSE句がありません
関数の引数無効とかは、意外と気がつきにくいです。
SAS Log Utility 1.6.1.8, 不具合修正
Vectorに登録の申請をしました。
修正したのは以下の点です。
ステータスバーに言語省略名を表示したのは、多言語対応の準備です。
行末のタブ又は空白を削除するようにしたのは、SASログをEXCELファイルに貼って渡す人がいて、処理の区切りを正確に判定できなかったためです。これがメモリリークの原因のひとつになっていました。ちなみに、EXCELに貼り付けて渡すとダブルクォートがエスケープされて、正しくパースできないことがありますので、私はWinZipで圧縮して渡します。
記録まで
修正したのは以下の点です。
- NOTE:でチェックするパターンを追加
- ステータスバーにISO言語省略名を表示
- ログの行末に追加されている空白又はタブを削除して処理
- ListViewのソートの不具合を修正
ステータスバーに言語省略名を表示したのは、多言語対応の準備です。
行末のタブ又は空白を削除するようにしたのは、SASログをEXCELファイルに貼って渡す人がいて、処理の区切りを正確に判定できなかったためです。これがメモリリークの原因のひとつになっていました。ちなみに、EXCELに貼り付けて渡すとダブルクォートがエスケープされて、正しくパースできないことがありますので、私はWinZipで圧縮して渡します。
記録まで
2016年1月28日木曜日
SAS Log Inspector 1.3.1.2, リリース
機能は変えず、組み込みのマッチングパターンを24種類に増やしました。どんなパターンが定義されているかは、以下の画像をご覧ください。Vectorに公開の依頼を投げました。
SAS Log Inspectorの機能
- 複数のログファイルからエラー、バグに繋がるNOTEを集計
- 日本語と英語版のメッセージに対応
- Excelファイルにログをチェックした結果をエクスポート
- 任意のチェック項目を検査対象から外すことができる
- Notepadを起動して、該当のログファイルを参照できる
- マッチングパターンを画面から追加、修正できる
2016年1月17日日曜日
Windows.GetLocaleInfoでLanguage Tagを取得
ツールのI18Nの検討メモです。
設定ファイルの言語を区別するため、Language Tag(ja, JP, en-usとか)を取得する方法を探しています。ログ解析の設定を日本語、英語と切り替えられるようにするための調査です。ネット上を探すとそのまま使えるサンプルが見つからないため、DelphiForFun HomeにあったDemoのコードを参考にしてサンプルコードを作りました。
試すときは、Formの上に、ButtonとListViewを配置し、ListViewの形式をvsReport、カラムを5つ定義してください。参考にしたのは以下のURLの情報です。
Locale Constants Demo
Language Tagの定義を探していたら、以下の情報が見つかりました。昔々、VAX Notes上でお世話になった記憶が微かにあります。
国際化プログラミング
設定ファイルの言語を区別するため、Language Tag(ja, JP, en-usとか)を取得する方法を探しています。ログ解析の設定を日本語、英語と切り替えられるようにするための調査です。ネット上を探すとそのまま使えるサンプルが見つからないため、DelphiForFun HomeにあったDemoのコードを参考にしてサンプルコードを作りました。
試すときは、Formの上に、ButtonとListViewを配置し、ListViewの形式をvsReport、カラムを5つ定義してください。参考にしたのは以下のURLの情報です。
Locale Constants Demo
Language Tagの定義を探していたら、以下の情報が見つかりました。昔々、VAX Notes上でお世話になった記憶が微かにあります。
国際化プログラミング
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, shellapi, Vcl.ComCtrls;
type
TForm1 = class(TForm)
ListView1: TListView;
Button1: TButton;
procedure FormActivate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TRec = Record
Code: Cardinal;
Name: String;
Text: String;
end;
const
rSet: Array [0 .. 79] of TRec = (
(Code: LOCALE_ILANGUAGE; Name: '言語ID'; Text: 'LOCALE_ILANGUAGE'),
(Code: LOCALE_SLANGUAGE; Name: '言語名'; Text: 'LOCALE_SLANGUAGE'),
(Code: LOCALE_SENGLANGUAGE; Name: '言語英語名'; Text: 'LOCALE_SENGLANGUAGE'),
(Code: LOCALE_SABBREVLANGNAME; Name: '言語省略名'; Text: 'LOCALE_SABBREVLANGNAME'),
(Code: LOCALE_SNATIVELANGNAME; Name: '言語固有名'; Text: 'LOCALE_SNATIVELANGNAME'),
(Code: LOCALE_ICOUNTRY; Name: '国コード'; Text: 'LOCALE_ICOUNTRY'),
(Code: LOCALE_SCOUNTRY; Name: '国名'; Text: 'LOCALE_SCOUNTRY'),
(Code: LOCALE_SENGCOUNTRY; Name: '国英語名'; Text: 'LOCALE_SENGCOUNTRY'),
(Code: LOCALE_SABBREVCTRYNAME; Name: '国省略名'; Text: 'LOCALE_SABBREVCTRYNAME'),
(Code: LOCALE_SNATIVECTRYNAME; Name: '国固有名'; Text: 'LOCALE_SNATIVECTRYNAME'),
(Code: LOCALE_IDEFAULTLANGUAGE; Name: 'デフォルト言語ID'; Text: 'LOCALE_IDEFAULTLANGUAGE'),
(Code: LOCALE_IDEFAULTCOUNTRY; Name: 'デフォルト国コード'; Text: 'LOCALE_IDEFAULTCOUNTRY'),
(Code: LOCALE_IDEFAULTCODEPAGE; Name: 'デフォルトOEMコードページ'; Text: 'LOCALE_IDEFAULTCODEPAGE'),
(Code: LOCALE_IDEFAULTANSICODEPAGE; Name: 'デフォルトANSIコードページ'; Text: 'LOCALE_IDEFAULTANSICODEPAGE'),
(Code: LOCALE_IDEFAULTMACCODEPAGE; Name: 'デフォルトMACコードページ'; Text: 'LOCALE_IDEFAULTMACCODEPAGE'),
(Code: LOCALE_FONTSIGNATURE; Name: 'フォント署名'; Text: 'LOCALE_FONTSIGNATURE'),
(Code: LOCALE_SISO639LANGNAME; Name: 'ISO言語省略名'; Text: 'LOCALE_SISO639LANGNAME'),
(Code: LOCALE_SISO3166CTRYNAME; Name: 'ISO国省略名'; Text: 'LOCALE_SISO3166CTRYNAME'),
(Code: LOCALE_SLIST; Name: '区切り記号'; Text: 'LOCALE_SLIST'),
(Code: LOCALE_IMEASURE; Name: '単位'; Text: 'LOCALE_IMEASURE'),
(Code: LOCALE_SDECIMAL; Name: '小数点の記号'; Text: 'LOCALE_SDECIMAL'),
(Code: LOCALE_STHOUSAND; Name: '桁区切り記号'; Text: 'LOCALE_STHOUSAND'),
(Code: LOCALE_SGROUPING; Name: '区切る桁数'; Text: 'LOCALE_SGROUPING'),
(Code: LOCALE_IDIGITS; Name: '小数点以下の桁数'; Text: 'LOCALE_IDIGITS'),
(Code: LOCALE_ILZERO; Name: '少数前ゼロの桁数'; Text: 'LOCALE_ILZERO'),
(Code: LOCALE_INEGNUMBER; Name: '負の値の形式'; Text: 'LOCALE_INEGNUMBER'),
(Code: LOCALE_SNATIVEDIGITS; Name: '0から9の表記'; Text: 'LOCALE_SNATIVEDIGITS'),
(Code: LOCALE_SPOSITIVESIGN; Name: '正の記号'; Text: 'LOCALE_SPOSITIVESIGN'),
(Code: LOCALE_SNEGATIVESIGN; Name: '負の記号'; Text: 'LOCALE_SNEGATIVESIGN'),
(Code: LOCALE_IPOSSIGNPOSN; Name: '正の記号の位置'; Text: 'LOCALE_IPOSSIGNPOSN'),
(Code: LOCALE_INEGSIGNPOSN; Name: '負の記号の位置'; Text: 'LOCALE_INEGSIGNPOSN'),
(Code: LOCALE_SCURRENCY; Name: '通貨記号'; Text: 'LOCALE_SCURRENCY'),
(Code: LOCALE_SINTLSYMBOL; Name: '国際通貨記号'; Text: 'LOCALE_SINTLSYMBOL'),
(Code: LOCALE_SMONDECIMALSEP; Name: '小数点の記号'; Text: 'LOCALE_SMONDECIMALSEP'),
(Code: LOCALE_SMONTHOUSANDSEP; Name: '桁区切り記号'; Text: 'LOCALE_SMONTHOUSANDSEP'),
(Code: LOCALE_SMONGROUPING; Name: '区切る桁数'; Text: 'LOCALE_SMONGROUPING'),
(Code: LOCALE_ICURRDIGITS; Name: '小数点以下の桁数'; Text: 'LOCALE_ICURRDIGITS'),
(Code: LOCALE_IINTLCURRDIGITS; Name: '小数点以下の桁数'; Text: 'LOCALE_IINTLCURRDIGITS'),
(Code: LOCALE_ICURRENCY; Name: '正の値の形式'; Text: 'LOCALE_ICURRENCY'),
(Code: LOCALE_INEGCURR; Name: '負の値の形式'; Text: 'LOCALE_INEGCURR'),
(Code: LOCALE_IPOSSYMPRECEDES; Name: '正の通貨記号の位置'; Text: 'LOCALE_IPOSSYMPRECEDES'),
(Code: LOCALE_IPOSSEPBYSPACE; Name: '正の通貨記号の分離位置'; Text: 'LOCALE_IPOSSEPBYSPACE'),
(Code: LOCALE_INEGSYMPRECEDES; Name: '負の通貨記号の位置'; Text: 'LOCALE_INEGSYMPRECEDES'),
(Code: LOCALE_INEGSEPBYSPACE; Name: '負の通貨記号の分離位置'; Text: 'LOCALE_INEGSEPBYSPACE'),
(Code: LOCALE_SDATE; Name: '区切り記号'; Text: 'LOCALE_SDATE'),
(Code: LOCALE_SSHORTDATE; Name: '短い形式'; Text: 'LOCALE_SSHORTDATE'),
(Code: LOCALE_SLONGDATE; Name: '長い形式'; Text: 'LOCALE_SLONGDATE'),
(Code: LOCALE_IDATE; Name: '短い形式の年月日順'; Text: 'LOCALE_IDATE'),
(Code: LOCALE_ILDATE; Name: '長い形式の年月日順'; Text: 'LOCALE_ILDATE'),
(Code: LOCALE_ICENTURY; Name: '年の桁数'; Text: 'LOCALE_ICENTURY'),
(Code: LOCALE_IDAYLZERO; Name: '日前ゼロの有無'; Text: 'LOCALE_IDAYLZERO'),
(Code: LOCALE_IMONLZERO; Name: '月前ゼロの有無'; Text: 'LOCALE_IMONLZERO'),
(Code: LOCALE_ICALENDARType; Name: 'カレンダの種類'; Text: 'LOCALE_ICALENDARType'),
(Code: LOCALE_IOPTIONALCALENDAR; Name: '追加カレンダの種類'; Text: 'LOCALE_IOPTIONALCALENDAR'),
(Code: LOCALE_IFIRSTDAYOFWEEK; Name: '週の先頭日'; Text: 'LOCALE_IFIRSTDAYOFWEEK'),
(Code: LOCALE_IFIRSTWEEKOFYEAR; Name: '年の先頭月'; Text: 'LOCALE_IFIRSTWEEKOFYEAR'),
(Code: LOCALE_SDAYNAME1; Name: '週の第1日名'; Text: 'LOCALE_SDAYNAME1'),
(Code: LOCALE_SDAYNAME2; Name: '週の第2日名'; Text: 'LOCALE_SDAYNAME2'),
(Code: LOCALE_SDAYNAME3; Name: '週の第3日名'; Text: 'LOCALE_SDAYNAME3'),
(Code: LOCALE_SDAYNAME7; Name: '週の第7日名'; Text: 'LOCALE_SDAYNAME7'),
(Code: LOCALE_SABBREVDAYNAME1; Name: '週の第1日省略名'; Text: 'LOCALE_SABBREVDAYNAME1'),
(Code: LOCALE_SABBREVDAYNAME2; Name: '週の第2日省略名'; Text: 'LOCALE_SABBREVDAYNAME2'),
(Code: LOCALE_SABBREVDAYNAME3; Name: '週の第3日省略名'; Text: 'LOCALE_SABBREVDAYNAME3'),
(Code: LOCALE_SABBREVDAYNAME7; Name: '週の第7日省略名'; Text: 'LOCALE_SABBREVDAYNAME7'),
(Code: LOCALE_SMONTHNAME1; Name: '年の第1月名'; Text: 'LOCALE_SMONTHNAME1'),
(Code: LOCALE_SMONTHNAME2; Name: '年の第2月名'; Text: 'LOCALE_SMONTHNAME2'),
(Code: LOCALE_SMONTHNAME3; Name: '年の第3月名'; Text: 'LOCALE_SMONTHNAME3'),
(Code: LOCALE_SMONTHNAME12; Name: '年の第12月名'; Text: 'LOCALE_SMONTHNAME12'),
(Code: LOCALE_SMONTHNAME13; Name: '年の第13月名'; Text: 'LOCALE_SMONTHNAME13'),
(Code: LOCALE_SABBREVMONTHNAME1; Name: '年の第1月省略名'; Text: 'LOCALE_SABBREVMONTHNAME1'),
(Code: LOCALE_SABBREVMONTHNAME2; Name: '年の第2月省略名'; Text: 'LOCALE_SABBREVMONTHNAME2'),
(Code: LOCALE_SABBREVMONTHNAME3; Name: '年の第3月省略名'; Text: 'LOCALE_SABBREVMONTHNAME3'),
(Code: LOCALE_SABBREVMONTHNAME12; Name: '年の第12月省略名'; Text: 'LOCALE_SABBREVMONTHNAME12'),
(Code: LOCALE_STIME; Name: '区切り記号'; Text: 'LOCALE_STIME'),
(Code: LOCALE_STIMEFORMAT; Name: '時間の形式'; Text: 'LOCALE_STIMEFORMAT'),
(Code: LOCALE_ITIME; Name: '時間制(12/24)'; Text: 'LOCALE_ITIME'),
(Code: LOCALE_ITIMEMARKPOSN; Name: '午前午後記号の位置'; Text: 'LOCALE_ITIMEMARKPOSN'),
(Code: LOCALE_ITLZERO; Name: '時刻前ゼロの有無'; Text: 'LOCALE_ITLZERO'),
(Code: LOCALE_S1159; Name: '午前の記号'; Text: 'LOCALE_S1159'),
(Code: LOCALE_S2359; Name: '午後の記号'; Text: 'LOCALE_S2359')
);
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.Close;
end;
procedure TForm1.FormActivate(Sender: TObject);
var
buf: array [1 .. 100] of char;
i: integer;
AItem: TListItem;
begin
for i := Low(rSet) to High(rSet) do
begin
Windows.GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, rSet[i].Code, @buf, 100);
AItem := ListView1.Items.Add;
AItem.Caption := Format('%.3d', [i + 1]);
AItem.SubItems.Add(rSet[i].Name);
AItem.SubItems.Add(rSet[i].Text);
AItem.SubItems.Add(Format('%d', [rSet[i].Code]));
AItem.SubItems.Add(string(buf));
end;
end;
end.
2016年1月4日月曜日
AdvListViewのソートを使う方法
実装を何度も忘れたのでメモします。
AdvListViewでソートを使うためには以下の設定が必要です。
AdvListViewでソートを使うためには以下の設定が必要です。
- SortShow := True を設定
- AdvListViewの各カラムにTagの番号を設定します。
- イベント OnColumnClick のハンドラを定義しその中で
- SortColumnをカラムのタグから指定
procedure TForm1.AdvListView1ColumnClick(Sender: TObject; Column: TListColumn); var tag: integer; begin tag := Column.Tag; AdvListView1.SortColumn := tag; end;便利!
SAS Log Utility 1.6.1.5, 文字列のパターンをINIファイルで定義
年末年始の休みを使って、SAS Log Utilityを更新しました。
- 潜在的な問題のパターンをINIファイルに定義
- ログを解析するためのパターンをINIファイルに定義
Vectorに新バージョンの登録を依頼しました。SAS Log Utilityは仕事でもっとも良く使うツールです。これまで、SASのバージョンアップの度に、マッチングのパターンを変えてはビルドしていました。とはいえ、いつも同じバージョンのSASを使っていないので、その都度直してビルドするのは面倒です。そんな理由で、設定のフォームを作って修正できるようにしました。
追加したOptionsのメニュー
バグに繋がりそうなNOTE:のパターン
処理時間、データセット名を捕捉するためのパターン定義
マッチングのパターンですが、"Keyword Setting"では、データセット名やファイル名などのメタ文字を定義できるようにしました。たとえば"[:dsn:]"でデータセット名のパターンを定義します。これは、Nリテラルのデータセット名をすっきりと定義、参照するために実装した機能です。
定義しているパターン(Keyword)の件数は固定です。このパターンは、行の種類を特定するためと、行の中に含まれる情報を抽出するための2種類があります。情報を抽出するとは、「999 オブザベーション」とかのデータ数、データセット名、ファイル名などを取り出すことです。
それと英語のパターン定義は、外しました。将来、多言語対応で設定を切り替えられるようにするため、いったんパターンから外しました。
INIファイルの書式が、桁固定で分かりにくいが、それはゆくゆく直します。いまは使えることの方が大事なので後回しです。
2015年12月28日月曜日
EGPからログを抽出するVBScript
EGPからログを抽出するスクリプトを作りました。EGPをZIPのファイルにコピーして、そのなかからresult.logのファイルを特定し、1つのファイルに出力しています。この方法は、公式ではなくNon Supportです。EGPのファイルが壊れたときに救済手段として、どこかに紹介されていました。
DebugFlag = Trueだと、メッセージのダイアログを表示します。あと、ログファイルの並び順は意識していません。
DebugFlag = Trueだと、メッセージのダイアログを表示します。あと、ログファイルの並び順は意識していません。
'---
' プログラム: EGPのファイルからSASログを抽出します。
' 説明: EGPの拡張子をZIPに変更して、ZIPのフォルダからresult.logのファイルを抽出
' 作成者: mining
'
' 引数1: EGPのファイルパス
' 引数2: ログファイルのパス
' 実行例: cscript foo.vbs C:\temp\foo.egp C:\temp\foo.log
'
'---
Option Explicit
On Error Resume Next
'---
' 定数
'---
Const FOF_SILENT = &H4 ' 進捗ダイアログを表示しない
Const FOF_NOCONFIRMATION = &H10 ' 上書き確認ダイアログを表示しない
Const ForWriting = 2 ' テキストファイルのオープン
Const ForReading = 1 ' テキストファイルのオープン
Const TristateUseDefault = -2 ' Opens the file using the system default.
Const TristateTrue = -1 ' Opens the file as Unicode.
Const TristateFalse = 0 ' Opens the file as ASCII.
Const DebugFlag = True
'---
' 変数
'---
Dim objShell
Dim objFso
Dim objTs
Dim sZipFile
Dim sTempFolder
Dim sEgpFilePath
Dim sLogFilePath
Dim ErrCount
Dim WarCount
Dim sMsg
'---
' オブジェクト生成します。
'---
Set objShell = CreateObject("Shell.Application")
Set objFso = CreateObject("Scripting.FileSystemObject")
'---
' 引数をチェックします。
'--
If WScript.Arguments.Count <> 2 Then
Call MsgBox("引数1にEGP、引数2にログファイルを指定してください。", vbOKOnly + vbExclamation, WScript.ScriptName)
WScript.Quit(1)
End If
sEgpFilePath = WScript.Arguments.Item(0)
sLogFilePath = WScript.Arguments.Item(1)
If objFso.FileExists(sEgpFilePath) = False Then
Call MsgBox("引数1で指定したファイルが存在しません。", vbOKOnly + vbExclamation, WScript.ScriptName)
WScript.Quit(1)
End If
'---
' デバッグ用のメッセージ出力
'---
Sub DebugMsg(msg)
If DebugFlag = True Then
Call MsgBox(msg, vbOKOnly + vbInformation, WScript.ScriptName)
End If
End Sub
'---
' ZIPファイルを指定したフォルダに解凍
'---
Sub Unzip(objShell, sFile, sFolder)
Dim objFilesInZip
Dim objFolder
Set objFilesInZip = objShell.Namespace(sFile).Items
If Err.Number <> 0 Then
Exit Sub
End If
Set objFolder = objShell.Namespace(sFolder)
If Err.Number <> 0 Then
Exit Sub
End If
If (Not objFolder Is Nothing) Then
objFolder.CopyHere objFilesInZip, FOF_NOCONFIRMATION + FOF_SILENT
Else
Err.Raise 432 ' オートメーションの操作中にファイル名またはクラス名を見つけられませんでした。
End If
Set objFilesInZip = Nothing
Set objFolder = Nothing
End Sub
'---
' フォルダを作成
'---
Sub CreateUnzipFolder(objFso, sFolder)
objFso.CreateFolder sFolder
End Sub
'---
' フォルダを削除
'---
Sub DeleteUnzipFolder(objFso, sFolder)
If objFso.FolderExists(sFolder) = True Then
objFso.DeleteFolder sFolder, True
End If
End Sub
'---
' テンポラリのフォルダのパスを作成
'---
Function CreateFolderPath(objFso, sFolder)
Const TemporaryFolder = 2
Dim objTempFolder
Set objTempFolder = objFso.GetSpecialFolder(TemporaryFolder)
CreateFolderPath = objFso.BuildPath(objTempFolder.Path, sFolder)
Set objTempFolder = Nothing
End Function
'---
' サブフォルダからresult.logを探して、objTsに出力
'---
Sub SearchLog(objFso, objTs, tmpFolderItems)
Const FileName = "result.log"
Dim objFolderItemsB
Dim objItem
Dim Stream
For Each objItem in tmpFolderItems
' 取り出した物がファイルかフォルダかを判定
If objItem.IsFolder Then
' フォルダであれば、再帰呼び出しでフォルダ階層を手繰ります。
Set objFolderItemsB = objItem.GetFolder
Call SearchLog(objFso, objTs, objFolderItemsB.Items())
ElseIf objItem.Name = FileName Then
' ファイル名が一致したら、テキストを読み取りobjTSに出力します。
Set Stream = CreateObject("ADODB.Stream")
Stream.Charset = "UTF-8"
Stream.Type = 2
Stream.Open
Stream.LoadFromFile(objItem.Path)
objTs.Write(Stream.ReadText)
Stream.Close
Set Stream = Nothing
End If
Next
Set objItem = Nothing
Set objFolderItemsB = Nothing
End Sub
'---
' ログファイルからERROR, WARNINGの件数をカウント
'---
Sub CountLog(objFso, sLogFile, byRef ErrCount, byRef WarCount)
Const KeyError = "e ERROR"
Const KeyWarning = "w WARNING"
Dim objTs
Dim sBuf
On Error Goto 0
ErrCount = 0
WarCount = 0
Set objTs = objFso.OpenTextFile(sLogFile, ForReading, False, TristateTrue)
If Err.Number <> 0 Then
Exit Sub
End If
Do Until objTs.AtEndOfLine = True
sBuf = objTs.ReadLine
If Left(sBuf, Len(KeyError)) = KeyError Then
ErrCount = ErrCount + 1
ElseIf Left(sBuf, Len(KeyWarning)) = KeyWarning Then
WarCount = WarCount + 1
End If
Loop
objTs.Close
If Err.Number <> 0 Then
Exit Sub
End If
Set objTs = Nothing
End Sub
'---
' エラーチェック
'---
Function CheckError(fnName)
Checkerror = False
Dim strmsg
Dim errNum
If Err.Number <> 0 Then
strmsg = "Error #" & Hex(Err.Number) & vbCrLf & "In Function " & fnName & vbCrLf & Err.Description
Call MsgBox(strmsg, vbOkOnly + vbCritical, WScript.ScriptName)
Checkerror = True
End If
End Function
'---
' ログファイルを開きます。
'---
Set objTs = objFso.CreateTextFile(sLogFilePath, True, True)
If CheckError("objFso.CreateTextFile") Then
WScript.Quit(1)
End If
'---
' EGPの拡張子をZIPに変更してコピーします。
'---
sZipFile = CreateFolderPath(objFso, objFso.GetTempName & ".zip")
Call DebugMsg("EGPの拡張子をZIPに変えてコピー:" & sZipFile)
objFso.CopyFile sEgpFilePath, sZipFile
If CheckError("objFso.CopyFile") Then
WScript.Quit(1)
End If
'---
' 解凍先のテンポラリのフォルダを作成します。
'---
sTempFolder = CreateFolderPath(objFso, objFso.GetTempName)
Call DebugMsg("テンポラリのフォルダを作成:" & sTempFolder)
Call CreateUnzipFolder(objFso, sTempFolder)
If CheckError("CreateUnzipFolder") Then
WScript.Quit(1)
End If
'---
' ZIPファイルを解凍します。
'---
Call DebugMsg("ZIPファイルを解凍:" & sZipFile)
Call Unzip(objShell, sZipFile, sTempFolder)
If CheckError("Unzip") Then
WScript.Quit(1)
End If
'---
' テンポラリフォルダからログファイル探してobjTSに出力します。
'---
Call DebugMsg("テンポラリのフォルダからログを収集:" & sTempFolder)
Call SearchLog(objFso, objTs, (objShell.NameSpace(sTempFolder)).Items)
If CheckError("SearchLog") Then
WScript.Quit(1)
End If
'---
' ログファイルを閉じます。
'---
objTs.Close
If CheckError("objTs.Close") Then
WScript.Quit(1)
End If
'---
' テンポラリのフォルダを削除します。
'---
Call DebugMsg("テンポラリのフォルダを削除:" & sTempFolder)
Call DeleteUnzipFolder(objFso, sTempFolder)
If CheckError("DeleteUnzipFolder") Then
WScript.Quit(1)
End If
'---
' ZIPファイルを削除します。
'---
Call DebugMsg("ZIPファイルを削除:" & sZipFile)
objFso.DeleteFile sZipFile
If CheckError("objFso.DeleteFile") Then
WScript.Quit(1)
End If
'---
' Error, Warningの件数を数えます。
'---
Call CountLog(objFso, sLogFilePath, ErrCount, WarCount)
If CheckError("objFso.DeleteFile") Then
WScript.Quit(1)
End If
Call DebugMsg("ERROR件数:" & CStr(ErrCount) & " WARNING件数:" & CStr(WarCount))
'---
' オブジェクトを破棄します。
'---
Set objTs = Nothing
Set objFso = Nothing
Set objShell = Nothing
'---
' 終了
'---
WScript.Quit(0)
登録:
投稿
(
Atom
)











