PowerShell是一个基于对象的Shell,在写一行程序,脚本和函数时,給了我们很大的灵活性。当生成详细的报告时,我们需要从代码中自定义我们的数据输出,或者可以通过管道输送到其它的命令。我们还需要能够控制和定制代码的输出,这样我们可以合并来自多个源的数据到一个单独的对象。在这一节中,我们将学习下基本的构建定制的对象
首先我们要做的时创建一个邮箱对象的集合,将用来作为一组新的自定义对象的数据源:
$mailboxes = Get-Mailbox
可以添加自定义的属性用于后续整个管道的对象属性,如Select-Object和Format-Table
$mailboxes |
Select-Object Name,
Database,
@{name="Title";expression={(Get-User $_.Name).Title}},
@{name="Dept";expression={(Get-User $_.Name).Department}}
另外一个简单的方法就时可以分配一个哈希表的属性参数到new-Object中
$mailboxes | %{
New-Object PSObject -Property @{
Name = $_.Name
Database = $_.Database
Title = (Get-User $_.Name).Title
Dept = (Get-User $_.Name).Department
}
}
你也可以使用New-Object去创建一个新的自定义对象,然后使用Add-Member命令附上一些所属的自定义属性
$mailboxes | %{
$obj = New-Object PSObject
$obj | Add-Member NoteProperty Name $_.Name
$obj | Add-Member NoteProperty Database $_.Database
$obj | Add-Member NoteProperty Title (Get-User $_.Name).Title
$obj | Add-Member NoteProperty Dept (Get-User $_.Name).Department
Write-Output $obj
}
这三个代码示例中会输出相同的自定义对象,这里主要使用到了Get-Mailbox和Get-User命令。
自定义对象工作原理
首先,我们构建自定义对象就是为了能够合并来自多个数据源的数据到一个单一的对象中。Get-Mailbox命令不会返回绑定到一个用户的Title和Department属性,而Get-User命令需要用来检索这些信息。所以当我们想要生成一个报告,而报告的信息包括Get-Mailbox和Get-User单独用户的检索,那么我们就可以构建一个自定义的对象,用来包括所有的信息。这样我们通过管道把这些对象传递到其它命令中,用于把这些信息导出到一个文件中。
我们可以修改以上的代码示例,通过管道将结果输出到一个CSV文件中
$mailboxes |
Select-Object Name,
Database,
@{n="Title";e={(Get-User $_.Name).Title}},
@{n="Dept";e={(Get-User $_.Name).Department}} |
Export-CSV –Path C:\report.csv -NoType
看看上面的示例中运行的结果
在看看文件中的结果
CSV文件中的内容:
可以看到有些结果是不太理想???中文解决方法??导出CSV中文乱码。。。
请记住,即使你可以使用Format-Table命令去创建计算机属性,如果你想使用Select-Object,就像前面的示例能够,当讲报告信息输出到CSV文件或者HTML格式时,你会发现很多无用的数据在报告中。
在使用Select-Object构建自定义的对象时,我们可以对象中选择现有的属性,然后通过管道增加一个或多个计算属性。这是通过使用一个哈希表,在哈希表键值和脚本块中定义了一个自定义的属性名称作为哈希表的值。脚本块是一个表达式,可以运行一个或多个命令来定义自定义属性的值。我们之前的示例中,你可以看到,我们通过get-User命令去获取用户的Title和Department属性,然后把这些属性的值赋值給新的对象。
创建计算属性的语法有点类似使用名称和表达式去创建一个哈希表,你也可以缩写这些关键词,例如:
$mailboxes |
Select-Object Name,
Database,
@{n="Title";e={(Get-User $_.Name).Title}},
@{n="Dept";e={(Get-User $_.Name).Department}}
在上面的示例中,我们把Name简写为n,把Expression简写为e。使用n和e只是为了更加的方便。你也可以使用lable或l去提供属性名称。
创建一个自定义的对象,使用new-Object命令然后分配一个哈希表属性参数是一个快速和简单的方法。唯一的问题就是,这种方法可能导致返回的属性的顺序是随机的。这是因为.NET Framework分配随机数值到哈希表中,而这些属性又是基于这些值的,所以显示的顺序不是我们定义的顺序。如果你想按你需要的顺序输出,那么就需要使用管道命令Select-Object去按顺序选择属性名称。
创建一个空的自定义对象,然后手动通过Add-Member命令需要更多的输入,所以这种语法也没有广泛使用。但是当你想穿件一个脚本方法或者搅拌属性的时候,它又会很好用,这是一种高级的技术,在后续的示例中我们比较少用。
更多自定义对象命令示例
下面看看另外一种创建自定义对象的方法,这里我们使用了Select-Object命令,看看下面的示例:
$mailboxes | %{
$obj = "" | Select-Object Name,Database,Title,Dept
$obj.Name = $_.Name
$obj.Database = $_.Database
$obj.Title = (Get-User $_.Name).Title
$obj.Dept = (Get-User $_.Name).Department
Write-Output $obj
}
当心并发管道错误
在前面的示例中,变量$mailboxes存放的邮箱信息,我们都是通过PowerShell使用远程Session来处理多条命令。理想的情况下,我们只需要这样便能实现:
Get-Mailbox | %{
New-Object PSObject -Property @{
Name = $_.Name
Database = $_.Database
Title = (Get-User $_.Name).Title
Dept = (Get-User $_.Name).Department
}
}
但是不幸是,即时这个语法是完全有效的,但是它不会一直工作在Exchange Management Shell中。这是因为,当Get-Mailbox命令通过管道把对象传递給ForEach-Object时,我们也在尝试运行get-user命令去建立一个自定义的对象,远程PowerShell是不支持同时执行多个管道的。为了避免这个,我们可以使用之前的示例的方法,首先将一些结果存放在变量中,然后通过管道把变量传递給ForEach-Object。