讓 PowerShell 更親民 - 加上簡易 GUI 操作介面
| | 0 | | 2,038 |
最近在寫的 PowerShell 小工具,處理過程會有多個選項要請使用者挑一個,最自然的設計方式通常會像這樣:
$prompt = "請選擇套餐組合"
$options = @("早上三個、晚上四個", "早上四個、晚上三個", "啃! 把拎杯當猴子逆?")
Write-Host $prompt -ForegroundColor Cyan
$idx = 1
$options | ForEach-Object {
Write-Host " $idx. $_" -ForegroundColor Yellow
$idx++
}
$selIdx = -1
while ($true) {
$input = Read-Host "請輸入選項編號(1-$($options.Count))"
if ([int]::TryParse($input, [ref]$selIdx) -and $selIdx -ge 1 -and $selIdx -le $options.Count) {
break
}
else {
Write-Host "請輸入有效數字。" -ForegroundColor Red
}
}
Write-Host "您選擇了 $selIdx. $($options[$selIdx - 1])" -ForegroundColor Green
這種 CLI 風格對資訊人員不是問題,甚至有回到家的感覺。
PowerShell 具腳本特性,程式邏輯公開可供檢視,比起二進位執行檔較無包藏惡意程式疑慮,接受度高。簡單小工具若沒用到第三方程式庫 DLL,單一檔案即可運作,不需安裝、部署,具高度可攜性。基於這些優點,縱然 PowerShell 開發起來不如 C# 順手,但這幾年仍是我寫簡單小工具的優先選項。只是要將 PowerShell 推廣給廣大使用者群,純文字操作介面往往成為阻礙。
像這次小工具的使用者便是非資訊背景的行政或業務人員,全無 DOS/Linux 經驗,想到必須要教這輩子只用過 GUI 的老爹老媽大哥小妹凱子馬子學會操作 CLI,那畫面太美我不敢看。
我想到一個解法:既然 PowerShell 可以調用 System.Windows.Forms API,那麼動態產生一個 Winows Form 放三個按鈕不是難事。效果會像這樣:
程式的特色是完全使用 Windows 內建程式庫,不依賴任何第三方元件,用一個 .ps1 檔全部搞定,PowerShell 5.1 / 7 都可執行。
靠 Github Copilot 幫忙,我還嘗試了一些花式技巧,像是:用 [System.Windows.Forms.TextRenderer]::MeasureText() 測量文字寬度決定視窗大小、使用 System.Drawing.Bitmap 動態產生表單左上角的圖示檔。有了 AI,Coding 變得更好玩了~
完整程式範例如下,有興趣的同學請自取參考。
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Function ShowOptionFormUI {
param(
[Parameter(Mandatory=$true)]
[string]$title,
[Parameter(Mandatory=$true)]
$options
)
$optionCount = $options.Length
# Create a temporary form to help with text sizing
$tempForm = New-Object System.Windows.Forms.Form
$tempForm.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::None
$tempFont = $tempForm.Font
$maxBtnWidth = ($options | ForEach-Object {
$btnTextSize = [System.Windows.Forms.TextRenderer]::MeasureText($_, $tempFont)
$btnTextSize.Width + 30 # Add padding
} | Measure-Object -Maximum).Maximum
$tempForm.Dispose()
[int]$width = [Math]::Max($maxBtnWidth, 200)
[int]$height = 25 * $optionCount
$form = New-Object System.Windows.Forms.Form
$form.Text = $title
$form.ClientSize = New-Object System.Drawing.Size(($width + 20), ($height + 20))
$form.MaximizeBox = $false
$form.MinimizeBox = $false
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
# 動態產生表單圖示
$bitmap = New-Object System.Drawing.Bitmap 32, 32
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
$graphics.Clear([System.Drawing.Color]::Transparent)
$brush = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::Red)
$graphics.FillEllipse($brush, 0, 0, 32, 32)
$pen = New-Object System.Drawing.Pen([System.Drawing.Color]::Black, 2)
$graphics.DrawEllipse($pen, 0, 0, 32, 32)
$font = New-Object System.Drawing.Font("Tahoma", 16, [System.Drawing.FontStyle]::Bold)
$stringFormat = New-Object System.Drawing.StringFormat
$stringFormat.Alignment = [System.Drawing.StringAlignment]::Center
$stringFormat.LineAlignment = [System.Drawing.StringAlignment]::Center
$brush.Color = [System.Drawing.Color]::White
$graphics.DrawString("?", $font, $brush, [System.Drawing.RectangleF]::new(4, 4, 26, 26), $stringFormat)
$font.Dispose()
$stringFormat.Dispose()
$graphics.Dispose()
$brush.Dispose()
$pen.Dispose()
$form.Icon = [System.Drawing.Icon]::FromHandle($bitmap.GetHicon())
$bitmap.Dispose()
$flowPanel = New-Object System.Windows.Forms.FlowLayoutPanel
$flowPanel.Dock = [System.Windows.Forms.DockStyle]::Fill
$flowPanel.FlowDirection = [System.Windows.Forms.FlowDirection]::TopDown
$flowPanel.WrapContents = $false
$flowPanel.AutoScroll = $true
$form.Controls.Add($flowPanel)
$form.Tag = ''
$options | ForEach-Object {
$button = New-Object System.Windows.Forms.Button
$button.Text = $_
$button.Width = $flowPanel.ClientSize.Width - 10
$button.Height = 25
$button.Margin = New-Object System.Windows.Forms.Padding(5, 2, 5, 2)
$button.Add_Click({
param($senderButton)
$form.Tag = $senderButton.Text
$form.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.Close()
})
$flowPanel.Controls.Add($button)
}
$form.Topmost = $true
if ($form.ShowDialog() -eq 'OK') {
return $form.Tag
}
return $null
}
$options = @("早上三個、晚上四個", "早上四個、晚上三個", "啃! 把拎杯當猴子逆?")
$result = (ShowOptionFormUI "請選擇套餐組合" $options)
if ($null -ne $result) {
[System.Windows.Forms.MessageBox]::Show("你選擇了: $result", "點餐結果") | Out-Null
}
This post discusses creating a user-friendly PowerShell tool using Windows Forms for non-technical users. The tool dynamically generates a Windows Form with buttons and an icon, allowing users to select options via a graphical interface. The provided PowerShell script demonstrates how to achieve this without third-party components.
Comments
Be the first to post a comment