WPF PowerShell GUI の作成: 関数、入力、および結果

PowerShellはコマンドラインツールですが、グラフィカルインターフェースの基盤としても使用することができます。特定の場合には、コマンドラインが最適なインターフェースではありません。

Not a reader? Watch this related video.

サービスデスクのためのPowerShell GUIを構築することは、その一例です。これは、グラフィカルツールを作成する方が適切な場合の一つです。デモのためにお問い合わせください!

PowerShellは.NETの機能と特徴を使用し、公開することができます。その結果、作成したスクリプトのGUIフロントエンドを作成することが可能です。PowerShellのGUI構築は、初心者の場合には複雑に思えるかもしれません。

しかし、PowerShellスクリプトの基本的な経験がある場合は、スクリプトのGUI作成の実践を学び、適応する理由はありません。

この投稿では、Windows Presentation Framework(WPF)を使用してPowerShell GUIを作成する方法について学びます。

事前条件

始める前に、次の要件を満たしていることを確認してください:

  1. Visual Studio 2017以降 – これを使用してWPFを使用したグラフィカルユーザーインターフェースを作成します。無料/コミュニティ版をダウンロードできます。
  2. A script editor – I use Visual Studio Code, but you can also use another text editor of your choice. Some other options are Notepad++ and the built-in PowerShell ISE
  3. A Windows 10 computer with Windows PowerShell 5.1.

スクリプトの構築

この投稿では、Main.ps1というシンプルなスクリプトを作成します。Win32_LogicalDisk WMIクラスをクエリすることで、ローカルまたはリモートシステムからディスク情報を取得するコードを記述します。

まず最初にGUIでラップするためのスクリプトが必要です。この投稿では、コンピュータ名を指定してディスク情報をクエリするスクリプトを使用しますが、GUIを作成するためには必ずしも必要ではありません。この投稿で学んだ技術を使って、独自のスクリプトにGUIを適応させてください。

例として、以下のアクションを実行する関数を作成します。

  1. クエリするコンピュータの名前を入力する
  2. コンピュータをクエリして、固定ディスクの情報を変数に保存する
  3. 結果を返す

関数の作成

このプロジェクトで使用するGet-FixedDiskという関数は以下のとおりです。このプロジェクトの目的は、ターゲットマシン上の着脱可能なまたは固定ディスクに関する情報を取得することです。

このコードはそのまま使用できますが、関数をdot sourceしてコマンドを手動で入力する必要がない場合には、GUIの作成が有益です。

Function Get-FixedDisk {
    [CmdletBinding()]
    # このparam()ブロックは、パラメータ宣言の開始を示します
    param (
        <# 
            このパラメータは、ターゲットコンピュータの名前を受け入れます。
            また、値が指定されていない場合に関数が実行されないように、必須の設定になっています。
        #>
        [Parameter(Mandatory)]
        [string]$Computer
    )
    <#
        すべての論理ディスクのリストを取得し、結果を変数$DiskInfoに保存するWMIクエリコマンド
    #>
    $DiskInfo = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter 'DriveType=3'
   $DiskInfo
}

コードにparam()ブロックが追加されたことがわかります。これにより、関数がデータ型に基づいて入力を受け入れるように指示されます。

例では、Computerパラメータが追加され、文字列値を受け入れるようになっています。また、Mandatoryパラメータ属性を追加することで、Computerパラメータが実行時に指定されていない場合に関数が実行されないようになります。

次に、18行目には、実際のWMIクエリコマンドが表示されており、すべての論理ディスクのリストを取得し、結果を$DiskInfo変数に保存しています。また、DriveType=3のディスクのみを取得するフィルタも追加しています。このフィルタにより、ローカルの固定ディスクに関する情報のみが表示されます。

コードのインポート(ドットソース)

この時点で、動作するスクリプトができたので、テストする準備ができています。しかし、スクリプトをテストする前に、コードをPowerShellセッションにインポートする必要があります。PowerShellセッションにコードを読み込む方法の一つは、ドットソースすることです。

スクリプトをドットソースするには、スクリプトのパスの前にドット(.)とスペースを入力します。スクリプトがC:\PoshGUI-sampleフォルダにある場合、以下のようにドットソースすることができます。

PS C:\PoshGUI-sample> . .\Main.ps1

現在の作業ディレクトリにいない場合は、フルパスを指定することもできます。以下のコード例では、スクリプトのフルパスが表示されています。

PS C:>. C:\PoshGUI-sample\Main.ps1

コードをメモリにインポートしたので、作成した関数のテストを続けることができます。以下の例では、Get-FixedDisk関数が使用されてコンピューターposhLabExcをクエリしていることが示されています。

PS51> Get-FixedDisk -Computer poshLabExc

DeviceID     : C:
DriveType    : 3
ProviderName :
FreeSpace    : 53037772800
Size         : 135838822400
VolumeName   : Windows

DeviceID     : D:
DriveType    : 3
ProviderName :
FreeSpace    : 14872641536
Size         : 17178750976
VolumeName   : Temporary Storage

DeviceID     : E:
DriveType    : 3
ProviderName :
FreeSpace    : 488202240
Size         : 524283904
VolumeName   : System Reserved

PowerShell GUIの構築

この時点で、Main.ps1という名前のスクリプトファイルが作成され、スクリプト内でGet-FixedDisk関数が作成されました。関数が動作することもテストして確認しました。

スクリプトが動作することがわかったので、GUIの構築を開始できます。

PowerShell GUIフォームの設計

まず、GUIの外観や使用する要素を計画します。このシンプルな例では、GUIには次の要素があります:

  • a text box where the computer name can be entered
  • a button to execute the function
  • a text box where we can display the results

次に、構築を開始できます!

GUIを作成するには、Visual Studioを開き、新しいプロジェクトを作成します。

Visual Studioが開いたら、ファイル (1) → 新規作成 (2) → プロジェクト (3)をクリックします。

Creating a new Visual Studio project

新規プロジェクトウィンドウで、Visual C# (1)を選び、WPFアプリ (.NET Framework) (2)を選択し、名前をPoshGUI-sample (3)に変更してOKをクリックします。

Choosing a Visual Studio project

プロジェクトが作成されると、MainWindow.xamlという名前の空のフォームが表示されます。

Visual Studio MainWindow.xaml

このフォームを私たちの要件に合わせてフォーマットする必要があります。以下に追加すべきコントロールとフォーマットを示します。

  • ウィンドウ
    • タイトル: ディスク情報
    • 高さ: 326
    • 幅: 403
  • コントロール (4)
    • ラベル
      • コンテンツ: “コンピュータ名:”
      • マージン: 10, 10, 0, 0
    • テキストボックス
      • 名前: txtComputer
      • テキスト: “”
      • 高さ: 23
      • 幅: 174
    • ボタン
      • 名前: btnQuery
      • コンテンツ: クエリ
      • マージン: 0, 13, 12, 0
    • テキストボックス
      • 名前: txtResults
      • テキスト: “”
      • 読み取り専用: 真
      • マージン: 10, 60, 0, 0
      • 高さ: 225
      • 幅: 373

最終的なフォームの見た目は、以下の画像に示されているものに似ているようになります。ウィンドウのレイアウトを自由に再配置することができます。創造的に取り組んでください!

PowerShell GUI Template

スクリプトとPowerShell GUIの組み合わせ

デザインに満足したら、スクリプトと統合を開始できます。

PowerShellはフォームをネイティブで表示することができません。フォームを表示するためには、スクリプトの先頭にコードを追加して、WPFフォームのレンダリングをサポートする必要があります。

Add-Type -AssemblyName PresentationFramework

次に、以下のアクションを実行するコードを追加します:

  1. フォームのXAMLコードをインポートして読み込む
  2. 名前付きコントロールに割り当てられた動的な変数を作成する
  3. フォームを表示する

以下は、スクリプト内の更新されたコードです。

注意:次の行の$xamlFileを修正し、MainWindow.xamlファイルのフルパスを指定してください。

Add-Type -AssemblyName PresentationFramework

Function Get-FixedDisk {
    [CmdletBinding()]
    # このparam()ブロックはパラメータの宣言の開始を示します
    param (
        <# 
            このパラメータは対象のコンピュータ名を受け入れます。
            また、値を指定しないと関数が実行されないように必須にも設定されています。
        #>
        [Parameter(Mandatory)]
        [string]$Computer
    )
    <#
        全ての論理ディスクのリストを取得し、結果を$DiskInfoという変数に保存するWMIクエリコマンド
    #>
    $DiskInfo = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter 'DriveType=3'
    $DiskInfo
}

# XAMLファイルはどこにありますか?
$xamlFile = "C:\PoshGUI-sample\MainWindow.xaml"

#ウィンドウを作成する
$inputXML = Get-Content $xamlFile -Raw
$inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^<Win.*', '<Window'
[XML]$XAML = $inputXML

# XAMLを読み込む
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
try {
    $window = [Windows.Markup.XamlReader]::Load( $reader )
} catch {
    Write-Warning $_.Exception
    throw
}

# フォームコントロールの名前に基づいて変数を作成します。
# 変数の名前は 'var_<control name>' となります。

$xaml.SelectNodes("//*[@Name]") | ForEach-Object {
    #"アイテム $($_.Name) を試しています"
    try {
        Set-Variable -Name "var_$($_.Name)" -Value $window.FindName($_.Name) -ErrorAction Stop
    } catch {
        throw
    }
}
Get-Variable var_*

$Null = $window.ShowDialog()

注意: $Null = $window.ShowDialog() は常にスクリプト内で最後の行である必要があります。

このコードをMain.ps1スクリプトを実行して実行すると、以下の例の出力が表示されます。

PowerShell GUI variable and field mappings

ご覧の通り、3つの名前付きコントロールには変数が割り当てられました。これらの変数名は、コントロールロジックコードを追加する際にスクリプト内で参照されます。

  • var_btnQuery
  • var_btnComputer
  • var_txtResults

スクリプトは現時点ではフォームの表示のみ可能であり、コントロールはまだコードが追加されていないため無効です。

ボタンのクリックイベントコードを追加する

スクリプトを変更してGUIをインポートして表示することができたので、次はコントロールにコードを追加してディスク情報データを取得して表示します。

このプロジェクトでは、btnQueryボタンのみがアクションに割り当てられます。他のコントロールは入力および出力/表示コントロールとしてのみ使用されます。つまり、btnQueryにはclickイベントコードのみを追加する必要があります。

btnQueryclickアクションを追加するには、以下のコードを対応する変数名$var_btnQueryに割り当てます。以下のコードをスクリプトのGet-Variable var_*$Null = $window.ShowDialog()のコード参照の間にコピーして挿入してください。

$var_btnQuery.Add_Click( {
   #結果ボックスをクリアする
   $var_txtResults.Text = ""
       if ($result = Get-FixedDisk -Computer $var_txtComputer.Text) {
           foreach ($item in $result) {
               $var_txtResults.Text = $var_txtResults.Text + "DeviceID: $($item.DeviceID)`n"
               $var_txtResults.Text = $var_txtResults.Text + "VolumeName: $($item.VolumeName)`n"
               $var_txtResults.Text = $var_txtResults.Text + "FreeSpace: $($item.FreeSpace)`n"
               $var_txtResults.Text = $var_txtResults.Text + "Size: $($item.Size)`n`n"
           }
       }       
   })

$var_txtComputer.Text = $env:COMPUTERNAME

完成したPowerShell GUIのテスト

すべてのパーツがカバーされたので、以下に私たちが設計したスクリプトに機能とPowerShell GUIが組み込まれた完成したコードがあります。

Add-Type -AssemblyName PresentationFramework

Function Get-FixedDisk {
    [CmdletBinding()]
    # このparam()ブロックは、パラメータ宣言の開始を示します。
    param (
        <# 
            このパラメータは、対象コンピュータの名前を受け入れます。
            必須の設定も行っているため、値を指定しないと関数が実行されません。
        #>
        [Parameter(Mandatory)]
        [string]$Computer
    )
    <#
        すべての論理ディスクのリストを取得し、結果を$DiskInfoという変数に保存するWMIクエリコマンドです。
    #>
    $DiskInfo = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter 'DriveType=3'
   $DiskInfo
}

#XAMLファイルはどこにありますか?
$xamlFile = "C:\Users\june\source\repos\PoshGUI-sample\PoshGUI-sample\MainWindow.xaml"

#ウィンドウを作成する
$inputXML = Get-Content $xamlFile -Raw
$inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^<Win.*', '<Window'
[xml]$XAML = $inputXML
#XAMLを読み込む

$reader = (New-Object System.Xml.XmlNodeReader $xaml)
try {
    $window = [Windows.Markup.XamlReader]::Load( $reader )
}
catch {
    Write-Warning $_.Exception
    throw
}

#フォームコントロールの名前に基づいて変数を作成する
#変数は 'var_<コントロール名>' という名前になります

$xaml.SelectNodes("//*[@Name]") | ForEach-Object {
    #"アイテム $($_.Name) を試行中";
    try {
        Set-Variable -Name "var_$($_.Name)" -Value $window.FindName($_.Name) -ErrorAction Stop
    } catch {
        throw
   }
}

Get-Variable var_*

$var_btnQuery.Add_Click( {
   #結果ボックスをクリアする
   $var_txtResults.Text = ""
       if ($result = Get-FixedDisk -Computer $var_txtComputer.Text) {
           foreach ($item in $result) {
               $var_txtResults.Text = $var_txtResults.Text + "DeviceID: $($item.DeviceID)`n"
               $var_txtResults.Text = $var_txtResults.Text + "VolumeName: $($item.VolumeName)`n"
               $var_txtResults.Text = $var_txtResults.Text + "FreeSpace: $($item.FreeSpace)`n"
               $var_txtResults.Text = $var_txtResults.Text + "Size: $($item.Size)`n`n"
           }
       }       
   })

$var_txtComputer.Text = $env:COMPUTERNAME
$Null = $window.ShowDialog()

以下のように、PowerShellでスクリプトを呼び出すと、PowerShell GUIウィンドウが表示されます。その後、機能をテストするために有効なコンピュータ名を入力できます。

PowerShell GUI Example Result

ユーザーのなりすましの機会をなくす認証方法で、呼び出し元を安全に検証します。 Specops Secure Service Deskでヘルプデスクハッカーをブロックします。 無料でお試しください!

要約

この記事では、入力を受け取り結果を返す単純な関数の作成方法について学びました。また、基本的なWPF PowerShell GUIの作成方法や、作成したPowerShellスクリプトのフロントエンドとしてインポートする方法も学びました。

これは単純なスクリプトとGUIの組み合わせです。以下のようなさまざまな改善ができます:

  • サイズと空き容量をGB値として表示するように書式設定する。
  • 表示されるプロパティの名前を変更する。
  • 結果を表示するためにGridViewを使用する。TextBoxの代わりに。
  • CSVファイルからサーバーリストをループ処理するためのインポートボタンを追加する。

要件に基づいて機能を修正および追加するのはあなた次第です。

さらに読む

Source:
https://adamtheautomator.com/powershell-gui/