怠日記

写真・金魚・昆虫・プログラミングの趣味を語るサイトです。似たようなことをnoteにも書いたり書いてなかったり。

VBScript - スクリプトが使用しているメモリ量を取得する

WMI サービスを使ってスクリプトが使用しているメモリ量を取得できる。

サンプルスクリプト

次のスクリプトは、スクリプト(を実行している cscript.exe)のプロセスID、使用メモリ量、コマンドラインを表示する。

'検索するプロセス名
Dim processNameToSearch
processNameToSearch = "cscript.exe"
'WMIサービスを取得
Dim wmi
Set wmi = GetObject("winmgmts:\\.\Root\CIMV2")
'プロセス名で Win32_Process を検索
Dim result
Set result = wmi.ExecQuery("SELECT * FROM Win32_Process WHERE Name = '" & processNameToSearch & "'")
'検索結果を出力
Dim tmp
For Each tmp in result
    'プロセスID
    WScript.Echo "Process ID: " & tmp.ProcessId
    'プロセスが使用している物理メモリ量(バイト)
    WScript.Echo "Memory Usage: " & tmp.WorkingSetSize & " bytes"
    'コマンドライン
    WScript.Echo "CommandLine: " & tmp.CommandLine
Next

サンプルスクリプトの説明

まず GetObject 関数を使って WMI サービスへの参照を取得する。

Dim wmi
Set wmi = GetObject("winmgmts:\\.\Root\CIMV2")

関数の引数は WMI サービスへの接続文字列。

接続文字列は winmgmts:\\〈コンピューター名〉\〈WMI 名前空間 の形式で指定する。

  • winmgmts:\\: WMI サービスへの接続を表す文字列(固定)

  • 〈コンピューター名〉: 接続先のコンピューター名
    ローカルを指定するときは . にする。

  • 〈WMI 名前空間: 接続先の WMI 名前空間

今回はローカルコンピューターの WMI サービスに接続し、その参照を取得している。


続けて ExecQuery() で Win32_Process オブジェクトを取得する。
プロセス名が検索条件。

Dim result
Set result = wmi.ExecQuery("SELECT * FROM Win32_Process WHERE Name = '" & processNameToSearch & "'")

ExecQuery の引数には WQL と呼ばれる WMI 用の SQL を指定する。


最後に、検索結果を表示する。

  • ProcessId: プロセスID
  • WorkingSetSize: 使用メモリ量(バイト単位)
  • CommandLine: コマンドライン
Dim tmp
For Each tmp in result
    'プロセスID
    WScript.Echo "Process ID: " & tmp.ProcessId
    'プロセスが使用している物理メモリ量(バイト)
    WScript.Echo "Memory Usage: " & tmp.WorkingSetSize & " bytes"
    'コマンドライン
    WScript.Echo "CommandLine: " & tmp.CommandLine
Next

Win32_Process オブジェクトから取得できる項目はヘルプを参照のこと。

Win32_Process クラス - Win32 apps | Microsoft Learn

VBScript - システムのメモリ情報を取得する

WMI サービスを使って Win32_OperatingSystem より OS の状態を取得できる。

サンプルスクリプト

次のスクリプトは OS が使用できる物理メモリ量、現在の空き物理メモリ量を表示する。

'WbemFlagEnum 列挙
Const wbemFlagReturnImmediately = 16  '0x10
Const wbemFlagForwardOnly = 32        '0x20
'WMIサービスを取得
Dim wmi
Set wmi = GetObject("winmgmts:\\.\Root\CIMV2")
'Win32_OperatingSystemオブジェクトを取得
Dim result
Set result = wmi.ExecQuery("SELECT * FROM Win32_OperatingSystem", _
                           "WQL", _
                           wbemFlagReturnImmediately + wbemFlagForwardOnly)
Dim tmp
For Each tmp In result
    'OSが使用できる物理メモリ量(KB)
    WScript.Echo "Total Visible Memory: " & tmp.TotalVisibleMemorySize & " KB"
    '現在の空き物理メモリ量(KB)
    WScript.Echo "Free Physical Memory: " & tmp.FreePhysicalMemory & " KB"
Next

サンプルスクリプトの説明

まず GetObject 関数を使って WMI サービスへの参照を取得する。

Dim wmi
Set wmi = GetObject("winmgmts:\\.\Root\CIMV2")

関数の引数は WMI サービスへの接続文字列。

接続文字列は winmgmts:\\〈コンピューター名〉\〈WMI 名前空間 の形式で指定する。

  • winmgmts:\\: WMI サービスへの接続を表す文字列(固定)

  • 〈コンピューター名〉: 接続先のコンピューター名
    ローカルを指定するときは . にする。

  • 〈WMI 名前空間: 接続先の WMI 名前空間

今回はローカルコンピューターの WMI サービスに接続し、その参照を取得している。


続けて ExecQuery() で Win32_OperatingSystem オブジェクトを取得する。

Dim result
Set result = wmi.ExecQuery("SELECT * FROM Win32_OperatingSystem", _
                           "WQL", _
                           wbemFlagReturnImmediately + wbemFlagForwardOnly)

ExecQuery の引数には WQL と呼ばれる WMI 用の SQL を指定する。


最後に、取得したオブジェクトからメモリ量を取得して出力する。

  • TotalVisibleMemorySize: OS が使用できる物理メモリ量(キロバイト単位)

  • FreePhysicalMemory: 現在の空き物理メモリ量(キロバイト単位)

Dim tmp
For Each tmp In result
    'OSが使用できる物理メモリ量(KB)
    WScript.Echo "Total Visible Memory: " & tmp.TotalVisibleMemorySize & " KB"
    '現在の空き物理メモリ量(KB)
    WScript.Echo "Free Physical Memory: " & tmp.FreePhysicalMemory & " KB"
Next

Win32_OperatingSystem オブジェクトからはメモリ情報以外も取得できる。

scp コマンドの使い方

リモート⇔ローカル間でファイルやディレクトリをコピーするには scp コマンドを使う。




リモートのファイルをローカルにコピーするには


リモートコンピューター(IPアドレス: 192.0.2.0)のユーザー john のファイル /home/john/foo.txt をローカルにコピーするには、次のように入力する。

% scp john@192.0.2.0:/home/john/foo.txt foo.txt

IPアドレスの部分はホスト名でもよい。
ホスト名が「hostname」の場合、次のように入力する。

% scp john@hostname:/home/john/foo.txt foo.txt

ファイルのタイムスタンプやパーミッションを保持するには -p オプションを付ける。

% scp -p john@192.0.2.0:/home/john/foo.txt foo.txt

もし接続先に SSH 接続をしたことがない場合、次のようなメッセージが表示される。

そのまま接続してよいなら「yes」を入力、中断するなら「no」を入力する。

The authenticity of host '192.0.2.0 (192.0.2.0)' can't be established.
RSA key fingerprint is 1a:2b:3c:4d:5e:6f:7g:8h:9i:0j:1k:2l:3m:4n:5o:6p.
Are you sure you want to continue connecting (yes/no)?    ←ここに yes または no を入力

既知のホストファイルに接続先を追加した旨のメッセージが表示される。

(既知のホストファイル → ~/.ssh/known_hosts

Warning: Permanently added '192.0.2.0' (RSA) to the list of known hosts.

パスワードの入力プロンプトが表示されるので、接続先ユーザーのパスワードを入力する。

Password:    ←ここにパスワードを入力

リモートコンピューターのファイルがコピーされた。

foo.txt                                                               100%   44KB  43.8KB/s   00:00

VBScript - 処理時間を計測する

Timer 関数を使うことで、ある処理にかかる時間を簡単に計測できる。

Timer 関数は午前0時00分からの経過時間を秒で返す。

処理開始と処理終了のタイミングでそれぞれ Timer 関数を実行し、その差を求めれば処理時間となる。

処理時間の計測例

次のスクリプトは、ファイルを1000個開く(なければ作る)のにかかった時間を表示する。

Dim startTime
startTime = Timer
With CreateObject("Scripting.FileSystemObject")
  Dim i
  For i = 1 To 1000
    With .OpenTextFile("C:\tmp\file-" & Right("00000" & i, 5) & ".txt", 2, True)
      'TODO: ファイルに対する何らかの処理を書く
    End With
  Next
End With
Dim endTime
endTime = Timer
WScript.Echo "Processing time (sec) : " & (endTime - startTime)

スクリプトの実行結果は次のようになる。

Processing time (sec) : 2.703125

留意事項

Timer 関数は午前0時00分からの経過時間を返すので、日付をまたぐ処理は正しく時間が計算できない。

たとえば処理開始が23時50分、処理終了が0時10分だった場合、処理時間はマイナスとなる(はず)。

Timer 関数の戻り値

処理開始: 85800
処理終了: 600

したがって処理終了(600) - 処理開始(85800) = -85200 秒となる。


「処理終了 < 処理開始」だった場合(つまり日付が変わった場合)は、次のように計算すれば求められそう。

(検証はいずれ)

(処理開始時の Timer 関数の値 + 処理開始~午前0時00分の秒数 + 処理終了時の Timer 関数の値) - 処理終了時の Timer 関数の値

ただこうしても2日以上またがれたら対応できない。

csh - xargs コマンド

xargs コマンドは標準入力やファイルからリストを読み込み、コマンドラインを作成し実行する。

たとえば、ファイル filelist にファイル名のリストが記録されているとする。
そのファイルに記録されたファイル名それぞれの内容を出力するには、以下のように書く。

cat filelist | xargs cat

ls コマンドで返ってきたファイルの内容を出力することも可。

ls test* | xargs cat


xargs コマンドは通常、引数がコマンドの最後に追加されていく。

引数が指定される場所を変更したいときは -I オプションを使う。

オプションは「-I ReplaceString」の形式で指定する。
ReplaceString が置換文字列を表す。
置換文字列は任意の文字列でよい。

たとえば以下の場合、{} が置換文字列となる。

ls test* | xargs -I {} cat {} >> ret.txt

ls test* の実行結果が以下の場合

test1.txt
test2.txt
test3.txt

次のコマンドが実行されることになる。

cat test1.txt >> ret.txt
cat test2.txt >> ret.txt
cat test3.txt >> ret.txt

コマンドに指定したファイルが存在しなくても、後続のコマンドは実行されていく。

たとえば test2.txt が存在しなくても、test1.txt と test3.txt の内容は ret.txt に書き込まれる。

VBScript - StringBuilder による文字列の連結

VBScript での文字列の連結には & 演算子を使うのが一般的だが、.NET Framework の StringBuilder クラスを使って連結することもできる。

手軽に使えて & 演算子より性能も良い。大量の文字列を連結するケースでは StringBuilder の利用も検討したい。

サンプルスクリプト

次のスクリプトは、3つの文字列(“Hello”、” “、”World!“)を StringBuilder で連結して表示する。

Dim sb
Set sb = CreateObject("System.Text.StringBuilder")
sb.Append_3 "Hello"
sb.Append_3 " "
sb.Append_3 "World!"
sb.Append_3 vbCrLf
WScript.Echo sb.ToString

StringBuilder のインスタンス生成

StringBuilder を使うには、System.Text.StringBuilder のオブジェクトを生成する。

Set sb = CreateObject("System.Text.StringBuilder")

StringBuilder のプロパティ、メソッド

StringBuilder の主なプロパティやメソッドは次のとおり。

Length プロパティ

格納されている文字列の文字数を取得する。

' "Hello World!〈CR〉〈LF〉" が格納されている場合
WScript.Echo sb.Length
' → 14

Append_3 メソッド

指定した文字列を追加する。

sb.Append_3 "Hello"
sb.Append_3 " "
sb.Append_3 "World!"

AppendFormat_2 メソッド

指定した書式指定に従い処理した文字列を追加する。

書式指定の対応する位置に、指定した文字列が入る。

たとえば、次のように書くと {0} の部分が “Hello” に、{1} の部分が “World!” になる。

sb.AppendFormat_2 "{0} {1}", "Hello", "World!"

AppendLine メソッド(使用不可)

AppendLine メソッドは指定した文字列の末尾に改行文字を加えて追加する。

しかし VBScript からは呼び出せなかった。

なぜかはわからないが「Microsoft VBScript 実行時エラー: オブジェクトでサポートされていないプロパティまたは メソッドです。」になってしまった。

仕方がないので Append_3 メソッドで代用するしかない。

sb.Append_3 "foo"
sb.Append_3 vbCrLf

または AppendFormat_2 メソッドでもよい。

sb.AppendFormat_2 "{0}{1}", "bar", vbCrLf

Clear メソッド(使用不可)

すべての文字列を削除する Clear メソッドも呼び出せなかった。

インスタンスの再作成で代用する。

Set sb = CreateObject("System.Text.StringBuilder")

ToString メソッド

格納されている文字列を取得する。

' "Hello World!" が格納されている場合
WScript.Echo sb.ToString
' → Hello World!

VBScript - 文字の数値文字参照を取得する

文字を Unicode のコードポイントで表記する方式を「数値文字参照」と言う。

AscW 関数を使って、指定した文字の数値文字参照を取得する方法を紹介する。

数値文字参照の表記

数値文字参照は “&#” + Unicode コードポイント + “;” のように表記する。

たとえば、“あ” のコードポイントは 12354 なので、これを数値文字参照で表すと “” となる。

数値文字参照の取得

AscW 関数で取得した Unicode コードポイントを、次のように編集するだけで数値文字参照になる。

WScript.Echo "&#" & CStr(AscW("あ")) & ";"
' → あ