Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2017年11月06日] [更新 2017年11月18日] Delphi 一般・その他
   
Delphi で Windows PowerShell を使用する
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
[整理番号 - 1010]







Windows PowerShell を Delphi で使用する


PowerShell は .NET Framework 上で動作するコマンドラインツールです.Windows 7 から標準で実装されています.PowerShell は,コマンド入力や出力の表示ウィンドウまたは PowerShell のスクリプトの実行環境を意味します.

本ページは PowerShell を Delphi で利用する際の参考用の記事です.PowerShell の使用方法やコマンド類あるいはスクリプトの文法の解説記事ではありません.PowerShell の使用方法や解説はネット上に多くの記事があります.また,参考書も多く出版されています.
本ページではコマンドプロンプト (Cmd.exe) の操作との関係についても説明していきます.





01_PowerShell の起動とバージョン確認


PowerShell のコンソールウィンドウ (コマンドウィンドウ) は [ファイル名を指定して実行] で PowerShell を指定して起動できます.[スタートメニュー] からは [アクセサリ] のリストからも選択して起動できます.
また,コマンドプロンプト (Cmd.exe) と同じようにエクスプローラのアドレスバーに PowerShell とタイプすることでも起動できます.エクスプローラから起動した場合は,起動したディレクトリがカレントディレクトリになります.

スタートメニューから起動した場合は,他の方法で起動した場合とウィンドウのキャプション,あるいはウィンドウのサイズやフォントサイズ,文字の色等が異なることがあります.

PowerShell.exe は以下の場所にあります.64 ビット版の Windows には 32 ビットと 64 ビット版の PowerShell.exe があります.
管理者権限での実行方法もコマンドプロンプトと同じです.


// Windows 7 の PowerShell.exe の場所
// C:\Windows の環境変数は %systemroot% 

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe  //32bit Windows (32bit版)
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe  //64bit Windows の 64bit版
C:\Windows\syswow64\WindowsPowerShell\v1.0\powershell.exe  //64bit Windows の 32bit版


下図は PowerShell のコンソールウィンドウを起動して,バージョン情報の $PSVersionTable の値を表示しています.
PowerShell では変数等のオブジェクトの先頭に $ を付けます.PSVersionTable は下図のようなバージョン情報の変数で,PowerShell では自動変数 (シェル変数) とも呼ばれていますが,Delphi で言えば予約語,予約オブジェクトということになるのかも知れません.
変数をコマンドとして実行すると,その値を表示します.

PowerShell のコンソールウィンドウを閉じるコマンドは EXIT です.



図1
PowerShell のウィンドウとバージョン情報




02_Delphi から PowerShell のコンソールウィンドウを起動


Delphi から PowerShell を起動するのは,Delphi で他のプログラムを起動するのと同じです.
エクセルを起動する時は excel.exe, コマンドプロンプトを起動する時は Cmd.exe, PowerShell を起動する時は PowerShell.exe を起動します.
以下は ShellExecute 関数で起動する例です.


リスト1
PowerShell を起動するだけのコード..exe は省略可能
implementation

uses
  ShellAPI;

{$R *.DFM}

//=============================================================================
//  PowerShellを起動
//  ShellExecuteの使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShellExecute(0, '', 'PowerShell.exe', nil, nil, SW_SHOWNORMAL);
end;


下図の下のコードは,ShellExecute 関数で PowerShell を起動し,ウィンドウのキャプションを変更しています.Sleep 関数を使用して PowerShell 起動終了を待っていますが,この方法は暫定的な方法です.参考リンクの記事のように,ShellExecuteEx 関数,あるいは CreateProcess 関数を使用して起動終了を待つのが本来の方法です.

PowerShell のクラス名はコマンドプロンプト (Cmd.exe) と同じ ConsoleWindowClass です.これと同じクラス名のプログラムが常駐していることがあります.そのため,単に FindWindow だけで検出しても自分自身が起動した PowerShell を検出できないことがあります.以下の [... コマンドプロンプトを閉じる方法] の記事も参考にしてください.



[備考 1]
本サンプルを管理者権限で実行すると,起動した PowerShell のウィンドウのキャプションを変更することはできません.


[備考 2]
Delphi から PowerShell を起動する時は,後述のセキュリティ (実行ポリシー) 設定変更のオプションを指定して起動すると便利です.



図2
PowerShell のウィンドウを起動

リスト2
PowerShell を起動してウィンドウのキャプションを変更
implementation

uses
  ShellAPI;

{$R *.DFM}

const
  FWndClassName = 'ConsoleWindowClass';

//-----------------------------------------------------------------------------
//  ウィンドウハンドルからウィンドウクラス名を取得
//-----------------------------------------------------------------------------
function GetClassNameStr(hWindow: HWND): string;
var
  Buffer : array[0..MAX_PATH-1] of Char;
  Len    : Integer;
begin
  FillChar(Buffer, SizeOf(Buffer), #0);
  Len := GetClassName(hWindow, Buffer, Length(Buffer));
  if Len > 0 then Result := Buffer else Result := '';
end;

//-----------------------------------------------------------------------------
//  EnumWindowsのコールバック関数
//  ウィンドウハンドル取得用
//-----------------------------------------------------------------------------
function EnumWindowsHandleProc(hWindow: hWnd; lPar: PNativeInt):
  Boolean; Stdcall;
var
  LWndClass : string;
begin
  Result := True;
  if IsWindowVisible(hWindow) then begin
    //ウィンドウのクラス名が同じだったら
    LWndClass := GetClassNameStr(hWindow);
    if LWndClass = FWndClassName then begin
      lPar^ := hWindow;
      Result := False;
    end;
  end;
end;


//=============================================================================
//  PowerShellを起動
//  ShellExecuteの使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile   : string;
  LParams    : string;
  LCmdWnd    : HWND;
  LhInstance : HWND;
  LText      : string;
begin
  LExeFile := 'PowerShell.exe';
  LParams  := '';

  LhInstance := ShellExecute(0, '', PChar(LExeFile), PChar(LParams), nil, SW_SHOWNORMAL);

  if LhInstance > 32 then begin
    //起動に成功したらハンドルが有効になるまで少しタイムラグを持たせる
    //ウィンドウハンドルに対する操作が必要なければ不要
    Sleep(100);
    LCmdWnd := 0;
    EnumWindows(@EnumWindowsHandleProc, LPARAM(@LCmdWnd));

    //ウィンドウのタイトルの文字列を変更してしまう
    LText := 'パワーシェル';
    SetWindowText(LCmdWnd, PChar(LText));
  end;
end;




03_PowerShell のコマンドレットとエイリアス


ここまでは単に PowerShell のコンソールウィンドウを起動するだけでした.本項では実際にコマンドを実行して,その結果を表示してみます.コマンドプロンプトとの違いについても説明していきます.

PowerShell にはコマンドレット (CommandLet) と呼ばれるコマンドがあります.これは「動詞-名詞」という形式になっていています.例えば以下の Get-ChildItem というのは,この後に続くディレクト内のアイテムのコレクションを取得します.
この例では,取得したアイテムを $A という変数に代入しています.そして,この $A を表示します.

このようなコマンドレット以外にも Cmd.exe で使用するようなコマンドも用意されています.それらの多くはコマンドレッドのエイリアス (別名) として実装されています.したがって,PowwrShell のコマンドのことをコマンドレットと言っても差支えないかも知れません.

# はコメントの意味です.この # 以降の記述はコマンドラインとして与えても無視されます.複数行のコメントは <# で開始し,#> で終了とします.


$A=Get-ChildItem d:\000\写真画像;$A  # コマンドレットを使用
cd d:\000\写真画像;dir               # エイリアスを使用


次のサンプルはコマンドを指定して PowerShell を起動します.コマンド実行後にウィンドウが閉じないように noExit オプションを指定しています.コマンドプロンプトでは /k または /c オプションでコマンド実行後にコマンドプロンプトを閉じるか表示したままにするかを指定しますが,PowerShell では何も指定しないと,コマンド実行後にコマンドウィンドウが閉じるようになっています.
既に起動中の PowerShell のウィンドでコマンドを実行した場合はウィンドウは閉じません.

このサンプルでは複数のコマンドを実行します.コマンドプロンプトでは複数のコマンドを 1 行で記述する時は & (アンパサンド) で区切りますが,PowerShell では ; (セミコロン) を使用します.



図3
コマンドの実行結果

リスト3
指定ディレクトリ内のアイテムを列挙する例
複数のコマンドは ; (セミコロン) で区切って指定する
コマンド実行後にウィンドウを閉じないよう noExit オプションを指定している
implementation

uses
  ShellAPI;

{$R *.DFM}

//=============================================================================
//  PowerShellを起動
//  ShellExecuteの使用にはusesにShellAPIが必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LExeFile : string;
  LParams  : string;
begin
  LExeFile := 'PowerShell.exe';
  LParams  := '-noExit dir;cd D:\';

  ShellExecute(0, '', PChar(LExeFile), PChar(LParams), nil, SW_SHOWNORMAL);
end;


PowerShell を起動する時,拡張子が .ps1 のスクリプトファイルを実行するには,以下のように,起動オプションにセキュリティ (実行ポリシー) の設定を追加します.
セキュリティ (実行ポリシー) については後述の記事とその参考リンクで確認してください.


リスト4
PowerShell 起動時にスクリプトファイルを実行する例
セキュリティ (実行ポリシー) の変更が必要
procedure TForm1.Button2Click(Sender: TObject);
var
  LExeFile : string;
  LParams  : string;
begin
  LExeFile := 'PowerShell.exe';
  LParams  := '-noExit  -ExecutionPolicy RemoteSigned -File .\DirList.ps1' ;

  ShellExecute(0, '', PChar(LExeFile), PChar(LParams), nil, SW_SHOWNORMAL);
end;




04_PowerShell のヘルプ


コマンドプロンプトではコマンドプロンプトのウィンドウでコマンドのヘルプを表示することができました.PowerShell でも以下のようなコマンドでヘルプを表示することができます.
Dir は Get-ChildItem のエイリアスなので,Get-Help Dir を実行すると Get-Help Get-ChildItem と同じ結果となります.


Get-Command                                            # コマンド,コマンドレット一覧
Get-Command -CommandType Cmdlet | Select-Object Name   # コマンドレットの一覧
Get-Help Get-ChildItem                                 # Get-ChildItemのヘルプ
Get-Help Get-ChildItem -Detailed                       # Get-ChildItemの詳細なヘルプ
Get-Help Dir                                           # Get-ChildItemのヘルプと同じ





05_テキストファイルへのリダイレクトと保存時のコードページ


コマンドプロンプト (Cmd.exe) と同じように実行結果をテキストファイルにリダイレクトすることもできます.以下のコマンドはその例です.この場合,リダイレクト先のファイル名にディレクトリ名がないので,現在のディレクトリ (カレントディレクトリ) に保存されます.


dir > 000.txt   # 実行結果を000.txtというテキストファイルへ保存


テキストはユニコードでの保存となります.コードページは BOM 付きの UTF-16LE となっているようてすが,保存する際の文字コードがユニコードのコードポイントになるとは限らないようです.つまり,ユニコードな文字が正しく保存できるとは限りません.PowwrShell のこの仕様については筆者には理解できていません.Cmd.exe のような /U オプションがあれば可能なのかも知れませんが,確認できていません.
テキストファイルに保存する際のコードページのエンコード方法については参考書やネットの記事で確認してください.

コンソールウィンドウの文字のコードページであれば,chcp で変更できます.ただし,そのコードページで表示可能なフォントでないと正常に表示できません.デフォルトのコードページは 932 の Shift-JIS です.






06_PowerShell のコンソールウィンドウのプロパティ変更


PowerShell コンソールウィンドウのサイズ,文字の色等のプロパティの設定方法はコマンドプロンプトと同じです.つまり,コンソールアプリケーションのプロパティの設定と同じです.
拙作の [コマンドプロンプトのフォント変更コマンドツール] も使用できます.ただし,背景色と文字の色の変更は 16 進数を意味する $ を付けると変更できません.$ なしで指定してくたさい.

PowerShell では (Get-Host).UI.RawUI オブジェクトのプロパティを使用して,コンソール画面の背景色,文字列の色,あるいはウィンドウのサイズ等の取得や変更の操作が可能です.



図4
背景色と文字の色を変更

Write-Host コマンドレットで文字列を表示する際,ForegroundColor や BackgroundColor パラメータを使用して文字列の前景色や背景色を設定することもできます.
下図は前景色を Red (赤) にしている例です.


図5
文字列の前景色の設定例




07_起動中の PowerShell コンソールウィンドウへのコマンド送信


起動中の PowerShell のコンソールウィンドウに,自アプリからコマンドを送信するには,以下の記事のサンプルが利用できます.


図6
起動中の PowerShell にコマンドを送信

起動中の PowerShell のコンソールウィンドウに対して,コマンドとしてスクリプトファイルを実行するには,スクリプトファイルが実行可能な状態になっている必要があります.そのためには後述のセキュリティ (実行ポリシー) の変更が必要です.
スクリプトファイルが実行可能になっていれば,下図のように実行可能です.


図7
起動中の PowerShell にコマンドを送信
  • スクリプトファイルの実行
  • EXE を実行したディレクトリ内の DirList.ps1 を実行
  • .\ はカレントディレクトリの意味




08_スクリプトファイルの実行とセキュリティ ( 実行ポリシー ) 設定


PowerShell がその真価を発揮するのはスクリプトです.PowerShell のスクリプト言語は非常に強力です.詳しい内容は参考書やネットで調べてください.
スクリプトは,スクリプトファイルと呼ばれるテキストファイルで保存して実行します.スクリプトファイルの拡張子は PowerShell のバージョンに関係なく .ps1 です.文字のコードページは Shift-JIS で構いません.

拡張子が .BAT の Cmd.exe のパッチファイルは実行形式のファイルですが,PowerShell のスクリプトファイルは実行ファイルではありません..ps1 を PowerShell に関連付けしても実行できません.セキュリティの観点からそうなっています.
もし,実行ファイルとなっていると,ウイルスとして実行させたり,メールなどに添付して配布して実行させることが簡単にできてしまうためにこの仕様になっています.

PowerShell のコンソールウィンドウでスクリプトファイルを実行するには,PowerShell を管理者権限で起動します.起動したらコマンドレッド Set-ExecutionPolicy RemoteSigned を実行してセキュリティの設定を変更します.その後でスクリプトファイルを実行します.
スコープを現在実行中のプロセスに限定すれば,Set-ExecutionPolicy RemoteSigned -Scope Process の実行で,管理者権限で PwoerShell を起動しなくてもせセキュリティの変更が可能です.

下図は実際にこのコマンドでセキュリティの設定を変更したところです.変更の確認で Y を入力して設定を有効にしています.



[備考]
Delphi から PowerShell を起動する時は,-ExecutionPolicy RemoteSigned オプションを指定して起動すれば上記の操作は必要ありません.起動オプションでセキュリティの設定を変更する場合は,変更確認の表示は現れません.また,管理者権限で PowerShell を起動しなくても変更可能です.
次項以降のサンプルではこの起動オプションを指定して PowerShell を起動しています.

[ファイル名を指定して実行] のダイアログから PowerShell を起動する時も
    PowerShell -ExecutionPolicy RemoteSigned
で起動すれば,スクリプトファイルが実行可能な状態になります.



図8
セキュリティの変更




09_PowerShell コマンドの実行結果をリダイレクト


以下のリンクの記事に掲載しているコマンドラインのリダイレクトのユニット,[TJvCreateProcess を使用したコマンドラインのリダイレクト] も PowerShell を使用できます.これらは,PowerShell のコンソールウィンドウを表示しないでコマンドやスクリプトファイルを実行し,その結果を文字列として取得したい場合に利用できます.

これ以降のサンプルではこのリダイレクトのユニットを利用した以下のようなコードを使用してテストしています.この PowerShell のテスト用プログラムでは PowerShell のフルパス (絶対パス) を取得し,セキュリティの変更オプション -ExecutionPolicy RemoteSigned を常に追加するようにしています.スクリプトの実行結果は TMemo に表示します.

下図は $A=Get-ChildItem d:\000\写真画像;$A というコマンドの実行結果です.



図9
リダイレクトユニットを使用したテスト用のプログラム
  • 上の TEdit にコマンドを入力
  • [実行] ボタンで実行
  • 結果を下の TMemo に表示

リスト5
コマンドのリダイレクトユニットを使用した PowerShell のテスト用プログラム
implementation

uses
  plCommandRedirect;

{$R *.dfm}

//=============================================================================
//  フォーム表示開始時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
  LExeFullPath : string;
begin
  Caption := 'PowerShell テスト用';

  //PowerShell.exeのフルパスを取得
  FPSExeFullPath := '"' + SysUtils.GetEnvironmentVariable('Systemroot')
                  + '\System32\WindowsPowerShell\v1.0\powershell.exe"';

  LExeFullPath := SysUtils.AnsiDequotedStr(FPSExeFullPath, '"');
  if not FileExists(LExeFullPath) then FPSExeFullPath := '';


  Edit1.Font.Charset := ANSI_CHARSET;
  Edit1.Font.Name    := 'Courier New';
  Edit1.Font.Size    := 9;

  Memo1.Font.Charset := DEFAULT_CHARSET;
  Memo1.Font.Name    := 'MS ゴシック';
  Memo1.Font.Size    := 9;

  //実行するPowerShellのコマンド
  Edit1.Text := '$Dir=Get-ChildItem -Name ;$Dir';
end;

//=============================================================================
//  リダイレクトの実行
//  出力のリダイレクト先はMemo1
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LCmdRedirect : TplCommandRedirect;
  LCmdLine     : string;
begin
  Memo1.Clear;
  Memo1.Update;

  if FPSExeFullPath = '' then begin
    Memo1.Lines.Add('PowerShell が見つかりませんでした');
  end else begin
    LCmdRedirect  := TplCommandRedirect.Create;
    try
      Memo1.Clear;
      LCmdLine   := FPSExeFullPath + ' -ExecutionPolicy RemoteSigned ' + Edit1.Text;
      Memo1.Text := LCmdRedirect.GrabStdOutText(LCmdLine);
      if Memo1.Text = '' then begin
        Memo1.Lines.Add('コマンドの実行に失敗したかも知れません');
      end;
    finally
      FreeAndNil(LCmdRedirect);
    end;
  end;
end;


次は,スクリプトで Get-ChildItem コマンドレットを実行する例です.
単に指定ディレクトリ内のアイテムを列挙するだけではなく,Recurse オプションでディレクトリ内を再帰的に検索するようにしています.また,foreach を使用して,ファイル名だけを 1 つづ表示していきます.
スクリプトコードの下のコードは実行したコマンドです.図はその実行結果です.

以下のスクリプトのコードを DirList.ps1 という名前で保存します.そしてその下に示すコマンドを実行します. -File はファイル名を指定するパラメータです.
ファイル名はフルパス (絶対パス) または相対パスで指定します.現在のディレクトリは .\ です.Delphi では現在のディレクトリの場合 .\ を省略できますが,PowerShell では省略できません.



リスト6
スクリプトファイル DirList.ps1 のスクリプトコード
指定ディレクトリ内を再帰的に検索してファイル名だけを列挙.その下は実行したコマンド
$DirList = Get-ChildItem D:\000\写真画像 -Recurse
foreach ($FileName in $DirList)
  {$FileName.Name}

-File .\DirList.ps1


図10
スクリプトファイルの実行結果

次は数値演算のスクリプトの例です.このスクリプトのコードを AddTest.ps1 というファイル名で保存して実行しています.スクリプトコードの下のコードは実行したコマンドです.実行結果はその下の図です.


リスト7
スクリプトファイル AddTest.ps1 のスクリプトコード
数値演算の例.その下は実行したコマンド
$A = 100
$B = 500
$C = $A + $B
$C

-File .\AddTest.ps1


図11
スクリプトファイルの実行結果

引数付きのスクリプトの例です.上と同じ数値演算ですが,ここでは整数としています.
スクリプトファイルで引数を受け取るには Param 関数を使用します.[Int] は整数を意味します.変数の型を指定しない場合は文字列と解釈されます.
このスクリプトのコードを AddTest.ps1 というファイル名で保存して実行します.スクリプトコードの下のコードは実行したコマンドです.実行結果はその下の図です.


リスト8
スクリプトファイル AddTest.ps1 のスクリプトコード
引数付きのスクリプトの例.その下は実行したコマンド
Param([int]$A, [Int]$B)
echo "A : $A"
echo "B : $B"
$C = $A + $B
$C

-File .\AddTest.ps1 200 300


図12
スクリプトファイルの実行結果




10_WSH の VBScript 等のスクリプトを PowerShell 用に変換


WSH で使用されている VBS (VBScript) と JScript のコードを PowerShell のスクリプトに移植する際の参考用のサンプルです.

次のコードは,下記の参考リンクの記事に掲載している VBScript のコードです.それを PowerShell のスクリプトのコードにしたのがその下のコードです.
VBScript では COM オブジェクトを CreateObject で生成していますが,PowerShell ではコマンドレット new-object で生成します.もちろん変数やオブジェクトには $ を付けます.文字列の結合は + です.改行文字は `r`n です.` はバッククォートです.[Shift] + [@] で入力できます.
このサンプルでは変数 $Str をそのまま出力しています.



リスト9
VBS (VBScript) のコード.その次は PowerShell のスクリプト.その次は実行したコマンド
' ファイルのプロパティをダイアログで表示する

Set FS = CreateObject("Scripting.FileSystemObject")
Set F  = FS.GetFile("BW_Delphi.jpg")

str = ""
str = str & "ファイル名: "   & F.Name & vbCrLf
str = str & "最終アクセス: " & F.DateLastAccessed & vbCrLf
str = str & "最終変更: "     & F.DateLastModified & vbCrLf
str = str & "サイズ: "       & F.Size
MsgBox str

$FS = new-object -comobject Scripting.FileSystemObject 
$F  = $FS.GetFile("BW_Delphi.jpg")

$str = ""                       
$str = $str + "ファイル名   : "  + $F.Name + "`r`n"
$str = $str + "最終アクセス : "  + $F.DateLastAccessed + "`r`n"
$str = $str + "最終変更     : "  + $F.DateLastModified + "`r`n"
$str = $str + "サイズ       : "  + $F.Size
$Str

-File .\FInfo.ps1


図13
スクリプトファイルの実行結果

以下のように,new-object コマンドレットで wscript.shell オブジェクトを生成して,その popup メソッドを使用すれば PowerShell でもダイアログを表示することができます.


$FS = new-object -comobject Scripting.FileSystemObject 
$F  = $FS.GetFile("BW_Delphi.jpg")

$str = ""                       
$str = $str + "ファイル名   : "  + $F.Name + "`r`n"
$str = $str + "最終アクセス : "  + $F.DateLastAccessed + "`r`n"
$str = $str + "最終変更     : "  + $F.DateLastModified + "`r`n"
$str = $str + "サイズ       : "  + $F.Size

$wsobj = new-object -comobject wscript.shell
$wsobj.popup($Str)


図14
WScript のメッセージダイアログを表示

文字列の出力は write-host コマンドレットを使用すると以下のように書けます.ただし,この場合は空白もそのまま出力されます.


$FS = new-object -comobject Scripting.FileSystemObject 
$F  = $FS.GetFile("BW_Delphi.jpg")

write-host "ファイル名   :" $F.Name "`r`n"
write-host "最終アクセス :" $F.DateLastAccessed "`r`n"
write-host "最終変更     :" $F.DateLastModified "`r`n"
write-host "サイズ       :" $F.Size


また,$Host.UI.Writeline は 1 行単位の出力とすることができます.


$FS = new-object -comobject Scripting.FileSystemObject 
$F  = $FS.GetFile("BW_Delphi.jpg")

$Host.UI.WriteLine("ファイル名   : " + $F.Name)
$Host.UI.WriteLine("最終アクセス : " + $F.DateLastAccessed)
$Host.UI.WriteLine("最終変更     : " + $F.DateLastModified)
$Host.UI.WriteLine("サイズ       : " + $F.Size)


以下のように write-host コマンドレット等を使用しなくても出力してくれます.
実際の問題として,オブジェクトのプロパティの値さえ取得さえできれば,後は Delphi 側のコーディングでどうにでも加工でききます.


$FS = new-object -comobject Scripting.FileSystemObject 
$F  = $FS.GetFile("BW_Delphi.jpg")

"ファイル名   : " + $F.Name
"最終アクセス : " + $F.DateLastAccessed
"最終変更     : " + $F.DateLastModified
"サイズ       : " + $F.Size


次の例は,下記の参考リンクの記事に掲載している JScript のサンプルを PowerShell のスクリプトに移植する例です.上のサンプルと同じように new-object コマンドレットを使用して COM オブジェクト SAPI.SpVoice を生成しています.
このスクリプトを実行するとコンピュータが英語で Hello と発声します.Windows 8.1 / 10 であれば日本語も発声させることができます.


リスト10
WSH (JScript) のコード.その次は PowerShell のスクリプト.その次は実行したコマンド
var tts = WScript.CreateObject("SAPI.SpVoice");
tts.Rate = 2;
tts.Speak("Hello!");

$tts = new-object -comobject SAPI.SpVoice
$tts.Rate = 2
$tts.Speak("Hello!")
"speak end"

-File .\Voice.ps1


この例のようにコマンドやスクリブの実行結果の表示が必要ないか,スクリプトでメッセージを表示すれば十分であれば,リダイレクトのユニットを使用する必要はありません.ShellExecute 関数の最後の引数を SW_HIDE にして PowerShell を起動すれば十分です.




11_PowerShell で WMI の機能を使用


PoweShell で WMI の機能を使用するには Get-WmiObject コマンドレットで WMI のオブジェクトを生成します.
以下のコマンドはその例です.Win32_OperatingSystem クラスのメンバとその値を取得します.このコマンドで全てのメンバとその値が取得できるわけではありません.

Get-WmiObject -Class Win32_OperatingSystem


図15
WMI の機能を使用する

以下は上のサンプルで使用した Win32_OperatingSystem クラスにどんなメンバがあるか調べて列挙するためのコマンドです.
| (バーティカルバー) はパイプライン (単にパイプと言うこともある) の意味です.| は [Shift] [\] で入力てきます.
コマンドプロンプトのパイプの対象はテキストですが,PoweShell では取得したオブジェクトあるいはそのオブジェクトのコレクションも対象です.Get-Member コマンドレットは取得したコレクションのメンバ名を列挙しす.

Get-WmiObject -Class Win32_OperatingSystem | Get-Member


図16
Win32_OperatingSystem クラスのメンバを列挙

次の例は Win32_LogicalDisk で論理ドライブのコレクションを取得し,その内,DriveType メンバの値が 3 のドライブだけのいくつかのプロパティの値を取得して表示します.
このスクリプトを Wmi.ps1 と言う名前で保存して,このスクリプトファイルを実行します.


リスト11
論理ドライブの情報を取得するスクリプトのコード例とコマンド
$disks = get-wmiobject Win32_LogicalDisk | Where-Object{$_.DriveType -eq 3}
foreach ($disk in $disks)
{
    $Host.UI.WriteLine("ドライブレター : " + $disk.DeviceID)
    $Host.UI.WriteLine("容量           : " + $disk.Size)
    $Host.UI.WriteLine("容量       : " + $disk.FreeSpace)

    $used = [Long]$disk.Size - [Long]$disk.FreeSpace
    $Host.UI.WriteLine("使用量         : " + $used)

    $Host.UI.WriteLine("")
}

-File .\Wmi.ps1


パイプラインやフィルタ処理,Where-Object については以下の記事に詳しい説明があります.


図17
WMI を使用した論理ドライブの情報取得結果




12_PowerShell で .NET Framework アセンブリを使用


.NET Framework のアセンブリ (DLL) の機能を使用するには,Add-Type コマンドレットで必要な,対象の .NET アセンブリ (DLL) を読み込みます.
以下では System.Windows.Forms を読み込んで [System.Windows.Forms.MessageBox] の Show メソッドでメッセージボックスを表示します.このスクリプトを Dialog.ps1 と言う名前で保存し実行した結果が下の図です.

スクリプトのコードの 1 行が長くなり改行表示するには,このスクリプトコードのように,` (バッククォート) を行末に記述します.` は [Shift] + [@] で入力できます.



リスト12
.NET Framework アセンブリを使用してメッセージボックスを表示.その下は実行したコマンド
Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("こんちは")
[System.Windows.Forms.MessageBox]::Show("終了しました",`
                                        "ダイアログのタイトル"`
                                        ,"AbortRetryIgnore"`
                                        ,"Information"`
                                        ,"button2")

-File .\Dialog.ps1


図18
スクリプトを実行するとダイアログを表示する

図19
上の図のダイアログで [OK] をクリックすると別のダイアログを表示する

図20
スクリプトが終了するとクリックしたボタンの値を表示

VBScript のサンプルでもそうでしたが,PowerShell でダイアログを表示した場合,テーマは適用されません.後述の PowerShell ISE でスクリプトを実行すれば,下図のようにテーマが適用されます.


図21
PowerShell ISE でスクリプトを実行してダイアログを表示した場合

以下は Windows の音声合成エンジンを使用する例です.
このスクリプトを実行するとコンピュータが英語で Hello と発声します.Windows 8.1 / 10 であれば日本語も発声させることができます.
-AssemblyName は,上のサンプルと同じ -Assembly にしても動作します.


リスト13
スクリプトファイル Voice.ps1 のスクリプトコード
.NET Framework アセンブリで音声合成エンジンを操作する例.その下は実行したコマンド
Add-Type -AssemblyName System.speech
$objVoice = New-Object System.Speech.Synthesis.SpeechSynthesizer
$objVoice.Speak("Hello")
"speak end"

-File .\Voice.ps1




13_スクリプトにおける数値の書式設定


WMI の Win32_OperatingSystem クラスのサンプルでは表示形式を指定しなくても PowerShell が自動で出力の書式を設定して表示しています.これらの表示形式は Format 関係のコマンドレットを使用して指定するができます.
また,数値や文字列も書式が設定できます.以下のスクリプトはそれを確認するためのコードです.
このスクリプトを Format.ps1 の名前で保存して実行したのがその下の図です.

最初の 《 [String]::Format("{0,10:00000}", $Value) 》 は .NET Framework の String.Format を使用して設定しています.
{0,10:00000} の最初の 0 は数値または変数のインデックスで,右側の何番目かの変数を示す値です.この値は 0 ペースの値で,0 が 1番目,1 が 2 番目,3 番目は 2 になります.この例では 1 つしかないので 0 です.
その次の 10 は表示桁数です.正の値の時は右寄せ,負の値の時は左寄せの表示になります.その次の 0 の羅列は実際の書式です.表示したい桁数分の 0 を羅列しています.このようにすると上位の桁が 0 でパディングされて 0 で埋められます.

2 番目の 《 [String]::Format("{0,10:#}", $Value) 》 は同じく String.Format を使用していますが,書式に # を指定しています.# を指定すると先行する 0 は表示しません.

3 番目の 《 "{0:00000}" -F $Value 》 は String.Format のエイリアスである -F を使用する例です.表示桁数の指定かないので左寄せで表示します.実際の表示桁は : (コロン) の後の 0 の数です.

4 番目の 《 "{0,-15} {1,15:#,###.00}" -F $ValueStr, $ValueFloat 》 は文字列と数値の 2 つの書式を設定しています.1 番目が文字列,2 番目が数値です.共に 15 桁の表示としていますが,文字列は負の値なので左寄せ,数値は右寄せの表示となります.
#,###.00 は.整数部を 3 桁ごとに , (カンマ) を表示し,小数点以下は 2 桁とする指定です.小数点 3 桁目は四捨五入されます.

5 番目の 《 $ValueFloat.ToString("#,###") 》は ToString を使用する例です.小数点以下の指定がない場合は,小数点以下の値は四捨五入して表示されます.

6 番目は "#.00" と "0.00" の違いの確認用です.
最後は,文字列であれば書式を指定しなくてもこのように書けるという例です.



リスト14
数値等の書式を確認するためのスクリプト
$Value = 20
[String]::Format("{0,10:00000}", $Value)
"--------------------------------------------"

$Value = 20
[String]::Format("{0,10:#}", $Value)
"--------------------------------------------"

$Value = 20
"{0:00000}" -F $Value
"--------------------------------------------"

$ValueStr = "ABCDEF"
$ValueFloat = 123456789.20
"{0,-15} {1,15:#,###.00}" -F $ValueStr, $ValueFloat
"--------------------------------------------"

$ValueFloat = 123456789.20
$ValueFloat.ToString("#,###")
"--------------------------------------------"

$ValueFloat = 0.124
$ValueFloat.ToString("#.00")
$ValueFloat.ToString("0.00")
"--------------------------------------------"

$ValueFloat = 12349.20
"数値の書式例 :{0,15:#,###.00}" -F $ValueFloat


図22
数値の書式設定結果




14_スクリプトにおける日付時刻の書式設定


次のスクリプトは日付時刻の値を書式付きの文字列にする例と,日付形式の文字列を日付時刻型の値に変換するコードの例です.
日付時刻を文字列にする書式は "yyyy年MM月dd日 tt HH時mm分ss秒fff" となります.年月日,時分秒等は適当な文字にすることができますが,なくても構いません.ミリセコンドは fff ですが,多くの場合必要はないかも知れません.
tt は 午前または午後の表示です.ない場合は午前も午後の表示もしません.

年月日の MM, dd, 時分秒の HH, mm, ss を各々 1 桁にすると先行する 0 を表示しません.また,時の HH を小文字の hh にすると 12 時間形式の時刻表示となります.大文字の HH は 24 時間形式です.このスクリプトでは Get-Date コマンドレットで現在の日付時刻を取得して表示します.

年の書式を ggyy にすると和暦形式の表示になりますが,そのままだと元号が「西暦」で西暦の下 2 桁の年表示になります. このスクリプトでは .NET Framework の機能を使用して和暦表示にするようにして, ToString で書式文字列にしています.

日付時刻形式の文字列は,[DateTime] で型指定すると日付時刻型の値にすることができます.文字列に年月日等の文字列があっても日付時刻の値にすることができます.



リスト15
日付時刻の値を書式付き文字列にするテスト用スクリプト
Get-Date -Format "yyyy年MM月dd日 HH時mm分ss秒fff"
Get-Date -Format "yyyy年MM月dd日 hh時mm分ss秒fff"
""
Get-Date -Format "yyyy年M月d日 tt H時m分s秒"
Get-Date -Format "yyyy年M月d日 tt h時m分s秒"
""
$cult = New-Object system.Globalization.CultureInfo("ja-JP")
$cult.DateTimeFormat.Calendar = New-Object System.Globalization.JapaneseCalendar
$date = Get-Date
$date.ToString("ggyy年MM月dd日 H時m分s秒", $cult)
""
$date = ([DateTime] "2004/10/05 13:25:05")
$date.ToString("yyyy年MM月dd日 HH時mm分ss秒")


図23
日付時刻型の書式設定結果




15_PowerShell スクリプトのテスト用プログラム
plRedirectForPS.zip [1,154 KB] 2017年11月18日版(ソースコード, EXE 同梱)


ここまでのテストで使用したテスト用のプログラムをダウンロードできます.上のリンクからダウンロードしてください.このファイルには,下図のようなテスト用のプログラムも同梱しています.

TMemo を 2 つ配置しています.最初の TMemo に,スクリプトのコードをクリップボードから貼り付けて実行できます.[実行] ボタンをクリックすると,TEdit に入力しているファイル名のファイルにスクリプトのコードを保存して,そのファイルを読み出して実行します.
実行結果は 2 番目の TMemo に表示します.

結果の表示おける TMemo の右端の折り返し位置は,PowerShell のプロパティの [画面バッファーサイズ] の [幅] の値によって決まります.



図24
実行結果を TMemo にリダイレクト

このテスト用プログラムから PowerShell のウィンドウを起動すると,実行結果をその PowerShell のコンソールウィンドウに表示します.
対象となる PowerShell のウィンドウは,このテスト用プログラム実行中に起動した PowerShell のウィンドウだけです.別の方法で起動した PowerShell には出力しません.
下図のように,引数付きのスクリプトも実行できます.


図25
実行結果を PowerShell のウィンドウに表示




16_PowerShell の総合開発環境 PowerShell ISE


PowerShell には総合開発環境としての PowerShell ISE があります.これも Windows 7 から実装されています.実行ファイル名は PowerShell_ISE.exe です.64 ビットの Windows には 32 ビット版と 64 ビット版の両方があります.


図26
PowerShell ISE
(Windows 7)
図27
PowerShell ISE
(Windows 10)