创建 WPF PowerShell GUI:函数、输入和结果

PowerShell是一个命令行工具,但你知道它也可以作为图形界面的基础吗?有时,命令行并不是特定情况下最好的界面类型。为您的服务台构建一个PowerShell GUI就是一个很好的例子。这是一个更适合构建图形工具的时候。

Not a reader? Watch this related video.

在帮助台重置密码时,强制执行最终用户验证。通过Specops Secure Service Desk减少社交工程漏洞。联系我们了解演示!

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类,从本地或远程系统中获取磁盘信息。

你需要一个脚本来首先包装一个图形用户界面。我选择使用一个允许你提供计算机名称并查询磁盘信息的脚本。当然,并不一定要构建一个图形用户界面。使用本文学到的技术来使你的图形用户界面适应你自己的脚本。

作为示例脚本,我将创建一个执行以下操作的函数:

  1. 接受输入以查询计算机的名称
  2. 查询计算机并将固定磁盘信息存储到一个变量中
  3. 返回结果

编写函数

以下是你将在这个项目中使用的函数,它被称为Get-FixedDisk。这个项目的目的是获取有关目标计算机上的非可移动或固定磁盘的信息。

虽然这段代码可以直接使用,但如果你只想执行一个快速查询而不必每次都加载函数并手动输入命令,创建一个图形用户界面会很有益。

Function Get-FixedDisk {
    [CmdletBinding()]
    # 此 param() 块表示参数声明的开始
    param (
        <# 
            此参数接受目标计算机的名称。
            还将其设置为强制执行,以确保在未指定值的情况下不执行该函数。
        #>
        [Parameter(Mandatory)]
        [string]$Computer
    )
    <#
        WMI 查询命令,获取所有逻辑磁盘的列表,并将结果保存到名为 $DiskInfo 的变量中
    #>
    $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,然后点击确定

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
    )
    <#
        WMI查询命令,获取所有逻辑磁盘的列表,并将结果保存到名为$DiskInfo的变量中
    #>
    $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

如你所见,这三个命名控件被分配了它们的变量。当我们在脚本中添加控件逻辑代码时,将在后面引用这些变量名。

  • var_btnQuery
  • var_btnComputer
  • var_txtResults

请记住,此时脚本只能显示表单,但由于您尚未添加代码,控件是无效的。

添加按钮点击事件代码

现在您已成功修改脚本以导入和显示 GUI,请开始添加代码到控件以检索和显示磁盘信息数据。

在此项目中,仅将为btnQuery按钮分配一个操作。其他控件将仅用作输入和输出/显示控件。这意味着我们只需要向btnQuery添加一个click事件代码。

要将btnQuery添加click动作,请将以下代码分配给其对应的变量名$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
    )
    <#
        WMI 查询命令,获取所有逻辑磁盘的列表,并将结果保存到名为 $DiskInfo 的变量中
    #>
    $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_<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_*

$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组合。可以进行许多改进,例如:

根据您的需求修改和添加功能完全取决于您。

进一步阅读

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