PowerShell 技能连载 - 用网格视图窗口显示列表视图(第 3 部分)

在前一个技能中我们介绍了 ConvertObject-ToHashTable 函数,它能方便地将对象显示在一个网格视图窗口中。

以下代码是一个改进的版本,能够根据字母顺序排列属性,并且可以由您决定每一列的名称。缺省情况下,Out-GridView 的列名为 “Property” 和 “Value”,但您将它们改为任意名称:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function ConvertObject-ToHashTable
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
$object,

[string]
$PropertyName = "Property",

[string]
$ValueName = "Value"
)

process
{
$object |
Get-Member -MemberType *Property |
Select-Object -ExpandProperty Name |
Sort-Object |
ForEach-Object { [PSCustomObject]@{
$PropertyName = $_
$ValueName = $object.$_}
}
}
}

Get-ComputerInfo |
# by default, columns are named "Property" and "Value"
ConvertObject-ToHashTable |
Out-GridView


Get-WmiObject -Class Win32_BIOS |
# specify how you'd like to call the columns displayed in a grid view window
ConvertObject-ToHashTable -PropertyName Information -ValueName Data |
Out-GridView

PowerShell 技能连载 - 用网格视图窗口显示列表视图(第 2 部分)

Out-GridView 是一个有用的 cmdlet。但如果只是用它来显示一个单一对象的所有属性时不太理想,因为这样显示出来只有一行。在前一个技能中我们解释了将一个对象转换为一个哈希表能解决这个问题。它实际上是将一个网格视图工作在“列表视图”模式。

因为这个方法在许多场景中十分有用,以下是一个封装好的名为 ConvertObject-ToHashTable 的函数,以及一系列示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function ConvertObject-ToHashTable
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
$object
)

process
{
$object |
Get-Member -MemberType *Property |
Select-Object -ExpandProperty Name |
Sort-Object |
ForEach-Object { [PSCustomObject]@{
Item = $_
Value = $object.$_}
}
}
}

systeminfo.exe /FO CSV | ConvertFrom-Csv | ConvertObject-ToHashTable | Out-GridView

Get-ComputerInfo | ConvertObject-ToHashTable | Out-GridView

Get-WmiObject -Class Win32_BIOS | ConvertObject-ToHashTable | Out-GridView

PowerShell 技能连载 - 用网格视图窗口显示列表视图(第 1 部分)

一个最简单的硬件清单功能可以用一行代码实现:

1
2
$data = systeminfo.exe /FO CSV | ConvertFrom-Csv
$data | Out-GridView

一个更现代的方法是使用新的 Get-ComputerInfo cmdlet:

1
2
$data = Get-ComputerInfo
$data | Out-GridView

一个最简单方法是用 Group-Object 创建一个哈希表:将原始数据用某个属性,例如 UserName` 来分组。然后,在网格视图窗口中显示哈希表的键。当用户选择了一个对象时,将选中的项目作为哈希表的键,找到原始项目:

1
2
3
4
5
6
7
$data = Get-ComputerInfo

$data |
Get-Member -MemberType *Property |
Select-Object -ExpandProperty Name |
ForEach-Object { $hash = @{}} { $hash[$_] = $data.$_ } { $hash } |
Out-GridView

现在网格视图窗口以更好的方式显示信息。这段代码用 Get-Member 来查找信息对象 $data 中暴露的属性名。它接下来创建一个哈希表,每个属性代表一个键,每个值代表一个属性值。

本质上,网格视图窗口现在显示的是多个键值对,而不是单一的一个对象。

PowerShell 技能连载 - 快速创建逗号分隔的字符串(第 2 部分)

在前一个技能中我们演示了如何用 PowerShell 命令模式方便地创建引号包围的字符串列表。这可以很方便地创建代码,节省很多打字工作。

以下是一个在日常 PowerShell 编码工作中有用的函数:

1
function s+ { "'$($args -join "','")'" | Set-ClipBoard }

下一次您在代码中需要一个引号包围的字符串列表时,只需要键入:

1
2
3
4
5
6
7
8
9
10
PS> s+ start stop pause end whatever

PS> 'start','stop','pause','end','whatever'
start
stop
pause
end
whatever

PS>

执行完之后,引号包围的字符串就会存在您的剪贴板中,接下来您可以将它们粘贴到任何需要的地方。

PowerShell 技能连载 - 快速创建逗号分隔的字符串(第 1 部分)

这是一个非常简单的创建引号包起来的字符串的列表的例子:

1
& { "'$($args -join "','")'" } hello this is a test

以下是执行结果:

1
'hello','this','is','a','test'

这个例子有效利用了 PowerShell 的“命令模式”,字面量被当作参数使用。您还可以将结果通过管道导出到 Set-Clipboard 指令执行,然后将结果贴回代码中。这比起手工为每个字符串添加引号方便多了。

1
2
3
4
PS> & { "'$($args -join "','")'" } hello this is a test  | Set-ClipBoard

PS> Get-ClipBoard
'hello','this','is','a','test'

PowerShell 技能连载 - 用网格视图窗口作为选择对话框(第二部分)

在前一个技能中我们介绍了如何使用哈希表来显示简单的选择对话框,而当用户选择了一个对象时,返回完整的对象。

哈希表基本上可以使用任何数据作为键。在前一个例子中,我们使用字符串作为键。它也可以是其它对象。这可以让您做选择对话框的时候十分灵活。

只需要使用 Select-Object 来选择希望在网格视图窗口中显示的属性,并且用它来作为哈希表的键。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# create a hash table where the key is the selected properties to display,
# and the value is the original object
$hashTable = Get-WmiObject -Class Win32_NetworkAdapterConfiguration |
# sort the objects by a property of your choice
Sort-Object -Property Description |
# use an ordered hash table to keep sort order
# (requires PowerShell 3; for older PowerShell remove [Ordered])
ForEach-Object { $ht = [Ordered]@{}}{
# specify the properties that you would like to show in a grid view window
$key = $_ | Select-Object -Property Description, IPAddress, MacAddress
$ht.Add($key, $_)
}{$ht}
Group-Object -Property Description, Index -AsHashTable -AsString

# show the keys in the grid view window
$hashTable.Keys |
Out-GridView -Title "Select Network Card" -OutputMode Single |
ForEach-Object {
# and retrieve the original (full) object by using
# the selected item as key into your hash table
$selectedObject = $hashTable[$_]
$selectedObject | Select-Object -Property *
}

当您运行这段代码时,网格视图窗口显示一个网络适配器的列表,并且只显示选择的属性 (Description、IPAddress 和 MacAddress)。

当用户选择了一个元素,这段代码返回原始的(完整)对象。这样即便网格视图窗口显示的是对象的一部分,整个对象任然可以用。

PowerShell 技能连载 - 用网格视图窗口作为选择对话框(第一部分)

如何使用网格视图窗口作为一个简单的选择对话框呢?

当您将对象用管道输出到网格视图窗口中,所有属性都会显示出来。通常情况下这可以工作得很好,只需要这样一行代码:

1
Get-Service | Out-GridView -Title "Select Service" -OutputMode Single

有些时候,特别是一个对象有诸多属性时,可能会让用户看不过来:

1
2
Get-WmiObject -Class Win32_NetworkAdapterConfiguration |
Out-GridView -Title "Select Network Card" -OutputMode Single

要简化这个对话框,您可以使用我们之前在用户配置文件管理中的方法,使用一个哈希表。只需要选择一个属性作为键。这个属性必须是唯一的。接下来,试试这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
Get-WmiObject -Class Win32_NetworkAdapterConfiguration |
Out-GridView -Title "Select Network Card" -OutputMode Single

$hashTable = Get-WmiObject -Class Win32_NetworkAdapterConfiguration |
Group-Object -Property Description -AsHashTable -AsString

$hashTable.Keys |
Sort-Object |
Out-GridView -Title "Select Network Card" -OutputMode Single |
ForEach-Object {
$hashTable[$_]
}

如您所见,只有选择中的属性会在网格视图窗口中显示,当用户选择了一个元素,将获取到完整的对象。这和服务列表的工作方式很像:

1
2
3
4
5
6
7
8
9
$hashTable = Get-Service |
Group-Object -Property DisplayName -AsHashTable -AsString

$hashTable.Keys |
Sort-Object |
Out-GridView -Title "Select Service" -OutputMode Single |
ForEach-Object {
$hashTable[$_]
}

PowerShell 技能连载 - 通过对话框移除用户配置文件(第二部分)

在前一个技能中我们演示了如何用一个用一个网格视图窗口显示所有可用的用户配置文件,并且可以选中一条并删除:

1
2
3
4
5
6
7
8
9
#requires -RunAsAdministrator

Get-WmiObject -ClassName Win32_UserProfile -Filter "Special=False AND Loaded=False" |
Add-Member -MemberType ScriptProperty -Name UserName -Value { (New-Object System.Security.Principal.SecurityIdentifier($this.Sid)).Translate([System.Security.Principal.NTAccount]).Value } -PassThru |
Out-GridView -Title "Select User Profile" -OutputMode Single |
ForEach-Object {
# uncomment the line below to actually remove the selected user profile!
#$_.Delete()
}

它可以像预期中的那样工作,网格视图窗口显示许多不需要的信息。如果您想用它作为一个服务桌面程序,您肯定只希望显示其中的一部分信息。

您当然可以在将结果通过管道导出到网格视图窗口之前使用 Select-Object 来控制显示哪些信息。然而,这将会改变数据的类型,而且这将导致无法访问对象的一些成员,例如使用 Delete() 来删除用户配置文件。

所以这是一个更普遍的问题:

如何用网格视图窗口来显示自定义数据,而当用户选择一条记录时,返回原始的对象?

一个简单的方法是用 Group-Object 来创建一个哈希表:将原始的数据通过类似 “UserName” 等属性来分组。然后,在网格视图窗口中显示哈希表的键。当用户选择了一个对象时,将选中的作为键,来访问哈希表中的原始对象:

1
2
3
4
5
6
7
8
9
10
11
12
#requires -RunAsAdministrator

$hashTable = Get-WmiObject -ClassName Win32_UserProfile -Filter "Special=False AND Loaded=False" |
Add-Member -MemberType ScriptProperty -Name UserName -Value { (New-Object System.Security.Principal.SecurityIdentifier($this.Sid)).Translate([System.Security.Principal.NTAccount]).Value } -PassThru |
Group-Object -Property UserName -AsHashTable -AsString

$hashTable.Keys |
Sort-Object |
Out-GridView -Title "Select User Profile" -OutputMode Single |
ForEach-Object {
# uncomment the line below to actually remove the selected user profile!
# $hashTable[$_].Delete()

现在这个工具使用起来方便多了:网格视图窗口只显示用户名,而当您选择了一项后,可以获取到原始对象,进而做删除操作。

PowerShell 技能连载 - 通过对话框移除用户配置文件

我们收到了许多关于处理用户配置文件的技能的反馈,所以我们决定增加一系列额外的技能文章。

在前一个技能中我们演示了如何用 WMI 删除用户配置文件。有一些用户推荐使用 Remove-WmiObject 来替代 WMI 内部的 Delete() 方法。然而,Remove-WmiObject 无法删除用户配置文件实例。

以下代码汇总了我们在之前的技能中提到的所有细节。它列出所有用户配置文件,除了当前加载的和系统账户的。您可以选择一个,PowerShell 会帮您移除这个用户配置文件。

请注意以下代码并不会删除任何内容。要防止丢失数据,我们注释掉了删除操作的代码。当您去掉注释,真正地删除用户配置文件之前,请确保您知道会发生什么!

1
2
3
4
5
6
7
8
9
#requires -RunAsAdministrator

Get-WmiObject -ClassName Win32_UserProfile -Filter "Special=False AND Loaded=False" |
Add-Member -MemberType ScriptProperty -Name UserName -Value { (New-Object System.Security.Principal.SecurityIdentifier($this.Sid)).Translate([System.Security.Principal.NTAccount]).Value } -PassThru |
Out-GridView -Title "Select User Profile" -OutputMode Single |
ForEach-Object {
# uncomment the line below to actually remove the selected user profile!
#$_.Delete()
}

Are you an experienced professional PowerShell user? Then learning from default course work isn’t your thing. Consider learning the tricks of the trade from one another! Meet the most creative and sophisticated fellow PowerShellers, along with Microsoft PowerShell team members and PowerShell inventor Jeffrey Snover. Attend this years’ PowerShell Conference EU, taking place April 17-20 in Hanover, Germany, for the leading edge. 35 international top speakers, 80 sessions, and security workshops are waiting for you, including two exciting evening events. The conference is limited to 300 delegates. More details at www.psconf.eu.

PowerShell 技能连载 - 查找用户配置文件

我们收到了许多关于处理用户配置文件的技能的反馈,所以我们决定增加一系列额外的技能文章。

通常,每次当用户登录一个系统时,无论是本地登录还是远程登录,将会创建一个用户配置文件。所以随着时间的增长,可能会存在许多孤岛的用户配置文件。如果您想管理用户配置文件(包括删除不需要的),请确保排除系统使用的用户配置文件。它们可以通过 “Special” 属性来识别。

以下是一段在网格视图窗口中显示显示所有普通的用户配置文件,并且允许您选择一条记录的代码:

1
2
3
4
5
$selected = Get-CimInstance -ClassName Win32_UserProfile -Filter "Special=False" |
Add-Member -MemberType ScriptProperty -Name UserName -Value { (New-Object System.Security.Principal.SecurityIdentifier($this.Sid)).Translate([System.Security.Principal.NTAccount]).Value } -PassThru |
Out-GridView -Title "Select User Profile" -OutputMode Single

$selected