Powershell バックグラウンドジョブをGUIで状況確認

#背景
並列で多数のマシンのInvoke-Commandを送りたい時など、
バックグラウンドジョブは非常に便利。
ただ、ジョブを発行した後の状況確認が手間がかかって不便。
なのでGUIで状況確認できるようにした。

#概要
VisualStudioでxamlファイルを生成し、
PowerShellで読み込んでWPFアプリとして動かす。
ジョブ情報取得・メッセージ詳細確認を感覚的に行いたい。

#画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402977/08fa5e65-73a2-f5dc-eb44-5484088ea217.png)

DataGridにId,Name,State,メッセージを表示。
DataGridで行を選択し詳細ボタンをクリックすると下部のScrollViewerにメッセージ全文が表示される。

#使い方
Job発行した後にこの関数を呼び出す。
バックグラウンドジョブはセッション内でしか追えないので、
直接実行するのではなくShellから呼び出したほうが良い。

#ソースコード
```MonitorBackgroundJob.ps1
function MonitorBackgroundJob{
    try{
        # Add-Typeでアセンブリをロードする
        Add-Type -AssemblyName presentationframework
    }catch{
        #Alread Type added.
    }
    try{
        #XAMLファイルを読み込んでxmlに変換
        [xml]$xaml = Get-Content -Path "$($PSScriptRoot)\mainWindow.xaml"

        #Powershellで読み込む時に不要な要素を削除
        $xaml.window.RemoveAttribute("x:Class")
        $xaml.window.RemoveAttribute("mc:Ignorable")

    }catch{

    }
   
       
    #読み込んだxamlをXmlNodeReaderにキャスト
    $xamlReader = $xaml -as "System.Xml.XmlNodeReader"

    #Windows.Markup.XamlReaderで読み込み
    $mainWindow = [Windows.Markup.XamlReader]::Load($xamlReader)

    #プロパティ取得
    $Button_Initialize = $mainWindow.FindName("Button_Initialize")
    $Button_Update = $mainWindow.FindName("Button_Update")
    $Button_Detail = $mainWindow.FindName("Button_Detail")
    $DataGrid_Jobs = $mainWindow.FindName("DataGrid_Jobs")
    $ScrollViewer_Detail = $mainWindow.FindName("ScrollViewer_Detail")

    #イベントハンドラ
    #初期化ボタンクリック時
    $mainWindow.FindName("Button_Collect").add_Click({ Button_Collect_Click })
    function Button_Collect_Click{
        $DataGrid_Jobs.Items.Clear()
        foreach($job in Get-Job){
            $Info = Receive-Job -Id $job.ID -Keep

            #複数行の場合、配列でわたってくるのでを文字列に連結
            if($Info -ne $null){
                if($Info.GetType().Name -eq "Object[]"){
                    $Info = $Info -join " "
                }
            }

            $DataGrid_Jobs.AddChild([pscustomobject]@{ID=$job.ID;Name=$job.Name;State=$job.State;Info=$Info})
        }
        
        $DataGrid_Jobs.Items.Refresh()
            
    }

    #詳細ボタンクリック時
    $mainWindow.FindName("Button_Detail").add_Click({ Button_Detail_Click })
    function Button_Detail_Click{
        $Info = Receive-Job -Id $DataGrid_Jobs.SelectedItem.Id -Keep
        $Info = $Info -join "`n"
        $ScrollViewer_Detail.Content = $Info
    }


    #表示
    $mainWindow.showDialog() | out-null


}
```

```mainWindow.xaml
<Window x:Name="MainWindow1" x:Class="Xaml取り出し_バックグラウンドジョブ_.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Xaml取り出し_バックグラウンドジョブ_"
        mc:Ignorable="d"
        Title="バックグラウンドジョブメッセージ収集" Height="450" Width="800">
    <Grid>
        <Grid>
            <Button x:Name="Button_Collect" Content="収集" HorizontalAlignment="Left" Height="44" Margin="675,10,0,0" VerticalAlignment="Top" Width="107"/>
            <Button x:Name="Button_Detail" Content="詳細" HorizontalAlignment="Left" Height="44" Margin="675,60,0,0" VerticalAlignment="Top" Width="107"/>
            <DataGrid x:Name="DataGrid_Jobs" HorizontalAlignment="Left" Height="144" Margin="10,10,0,0" VerticalAlignment="Top" Width="660" IsReadOnly="True">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Id" Binding="{Binding Id}" Width="30" />
                    <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="200"/>
                    <DataGridTextColumn Header="State" Binding="{Binding State}" Width="80"/>
                    <DataGridTextColumn Header="Info" Binding="{Binding Info}" Width="340"/>
                </DataGrid.Columns>
            </DataGrid>
            <ScrollViewer x:Name="ScrollViewer_Detail" HorizontalAlignment="Left" Height="251" Margin="10,158,0,0" VerticalAlignment="Top" Width="772"/>

        </Grid>

    </Grid>
</Window>
```