🐶

PowerShellにも設定画面がほしい

に公開

何言ってやがんだとか思われるんでしょーがおっさんは本気です。
テキストで設定シコシコ書くのはさ、もーDOS時代にとっくに飽きてんだわ。おっさん。
ってわけで面倒事はPropertyGridに全部放り投げます。おいコラ、働けよ、計算機。

ちなみにPropertyGridってのはソフト屋なら某IDEで絶対見たことあるコレのコト

本題

いやもーここ数年弄ってない動的フォーム生成とか中々脳にキますな

function ShowSettingDialog {
    param (
        [Parameter(Mandatory = $true)] [string]        $Title,
        [Parameter(Mandatory = $true)] [System.Object] $Setting
    )
    begin {}
    process {
        # フォーム生成
        $frmMain = New-Object System.Windows.Forms.Form -Property @{
            Text          = $Title                                                      # タイトル
            StartPosition = 'CenterScreen'                                              # 表示位置
            Size          = New-Object System.Drawing.Size(480,320)
            Padding       = New-Object System.Windows.Forms.Padding(5)
        }

        $tlpMain = New-Object System.Windows.Forms.TableLayoutPanel -Property @{
            Dock     = [System.Windows.Forms.DockStyle]::Fill
            RowCount = 2
        }

        $pnlBody = New-Object System.Windows.Forms.Panel -Property @{
            Dock = [System.Windows.Forms.DockStyle]::Fill
        }
        $grdProp = New-Object System.Windows.Forms.PropertyGrid -Property @{
            Dock           = [System.Windows.Forms.DockStyle]::Fill
            SelectedObject = $Setting
        }

        $pnlTail = New-Object System.Windows.Forms.Panel -Property @{
            Dock = [System.Windows.Forms.DockStyle]::Fill
        }
        $btnOK = New-Object System.Windows.Forms.Button -Property @{
            Dock                    = [System.Windows.Forms.DockStyle]::Right
            Size                    = New-Object System.Drawing.Size(128, 0) # ボタン巾のみ指定可能
            Text                    = "OK"
            UseVisualStyleBackColor = $true
            DialogResult            = [Windows.Forms.DialogResult]::OK
        }
        $btnCancel = New-Object System.Windows.Forms.Button -Property @{
            Dock                    = [System.Windows.Forms.DockStyle]::Right
            Size                    = New-Object System.Drawing.Size(128, 0) # ボタン巾のみ指定可能
            Text                    = "Cancel"
            UseVisualStyleBackColor = $true
            DialogResult            = [Windows.Forms.DialogResult]::Cancel
        }
        
        $null = $pnlBody.Controls.Add($grdProp)
        $null = $pnlTail.Controls.Add($btnOK)
        $null = $pnlTail.Controls.Add($btnCancel)
        $null = $tlpMain.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Percent, 100)))
        $null = $tlpMain.RowStyles.Add((New-Object System.Windows.Forms.RowStyle([System.Windows.Forms.SizeType]::Absolute, 50))) # ボタン高さはコレ
        $null = $tlpMain.Controls.Add($pnlBody, 0, 0)
        $null = $tlpMain.Controls.Add($pnlTail, 0, 1)
        $null = $frmMain.Controls.Add($tlpMain)

        # フォーム表示
        $null = $frmMain.ShowDialog()

        return $frmMain.DialogResult
    }
    end {}
}

使い方

で、まぁコレをこんな感じで使うんですわ

class AppSettings {
    [System.ComponentModel.Description("名前")]
    [string]$AppName
    [int]$Version
    [bool]$AutoUpdate
    [string]$LogFilePath
    [System.Diagnostics.SourceLevels]$LogLevel
}
$settings = [AppSettings]@{
    AppName = "My Application"
    Version = 1
    AutoUpdate = $true
    LogFilePath = "C:\app.log"
    LogLevel = [System.Diagnostics.SourceLevels]::Information
}
$ret = ShowSettingDialog "Title" $settings
if ($ret -eq "OK") {
    $settings
}

ってわけでコレが冒頭のアレになります
つまりクラス定義して変数ブチ込んであとは.Net様に全てお任せ

説明

データグリッドちゅーのはクラスメンバのプロパティに属性つけて
その指示に従って編集方法とかある程度変えられる代物です
でPowerShellから簡単に使える属性はこんな感じ

class AppSettings {
    [System.ComponentModel.Description("説明文")]
    [string]$AppName
    [int]$Version
    [bool]$AutoUpdate
    # Enumは勝手にコンボになる
    [System.Diagnostics.SourceLevels]$LogLevel
    # 子要素に直接クラスがある場合は展開用の属性が必要
    # でも実は子要素がクラスの配列の場合はこんなことしなくていい謎
    [System.ComponentModel.TypeConverter(([System.ComponentModel.ExpandableObjectConverter]))]
    [AppSettingsChild] Child
}
class AppSettingsChild {
    [string]$Sample
}

他の属性はこの辺見てChatGPTなり何なりにお願いすれば大体オッケー
https://dobon.net/vb/dotnet/control/propertygrid.html

ただしカスタム属性は単発利用では苦労に見合わない感じなんで避けたほうがいいかと
無駄に努力してどーにかする方法を考えてみましたwww
https://zenn.dev/notstrings/articles/b524f7467b8b7f

ところでコイツ、現実的にはConvertFrom-Jsonで取ってきた設定を編集すんですが
何も考えずConvertFrom-Jsonしちゃうと値がPSCustomObjectにすり替わりますんで
ConvertFrom系使ったらそのまま突っ込まずにクラスへの変換が必要です
https://zenn.dev/notstrings/articles/77a87cc56f0979

Discussion