第22章 优化可传参脚本
21.1 起点
我们基于之前章节的代码清单22.1做了小幅修改:我们将输出结果为被选择的对象,而不是格式化之后的表格。
代码清单22.1 起点:Get-DiskInventory.ps1
<#
.SYNOPSIS
Get-DiskInventory retrieves logical disk information from one or more computers.
.DESCRIPTION
Get-DiskInventory uses WMI to retrieve the Win32_LogicalDisk instance from one or more computers.It displays each disk's drvie letter,free space,total size,and percentage fo free space.
.PARAMETER computername
The computer name,or names to query.Default:Localhost.
.EXAMPLE
Get-DiskInventory -computername SERVER-R2 -drivetype 3
#>
param (
$computername = 'localhost',
$drivetype = 3
)
Get-WmiObject -class Win32_LogicalDisk -computer $computername `
-filter "drivetype=$drivetype" |
Sort-Object -property DeviceID |
Select-Object -property DeviceID,
@{label='FreeSpace(MB)';expression={$_.FreeSpace / 1MB -as [int]}},
@{label='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{label='%Free';expression={$_.FreeSpace / $_.Size * 100 -as [int]}}
为什么我们使用Select-Object而不是Foramt-Table?因为我们通常感觉写一个脚本所产生的结果是已格式化的并不是一个好主意。毕竟,如果某个用户需要CSV格式的文件,而脚本输出格式化后的表,该用户就无法完成工作。通过本次修改,我们可以通过下述方式获得格式化后的表。
PS C:\>.\Get-DiskInventory | Format-Table
或者通过下述方式运行获取CSV文件。
PS C:\>.\Get-DiskInventory | Export-CSV disk.csv
关键点是输出对象(也就是Select-Object完成的工作),对照格式化的显示结果,将会使得我们的脚本从长远角度来说更加灵活。
22.2 让PowerShell去做最难的工作
我们只需在上述脚本的基础上再多加一行脚本,就能展现PowerShell的奇妙。这使得从技术上来说,把我们的脚本变为所谓的“高级脚本”,使得大量的PowerShell能做的事得以展现。代码清单22.2展现了修订后的脚本。
代码清单22.2 将Get-DiskInventory.ps1变为高级脚本
<#
.SYNOPSIS
Get-DiskInventory retrieves logical disk information from one or more computers.
.DESCRIPTION
Get-DiskInventory uses WMI to retrieve the Win32_LogicalDisk instance from one or more computers.It displays each disk's drvie letter,free space,total size,and percentage fo free space.
.PARAMETER computername
The computer name,or names to query.Default:Localhost.
.EXAMPLE
Get-DiskInventory -computername SERVER-R2 -drivetype 3
#>
[CmdletBinding()]
param (
$computername = 'localhost',
$drivetype = 3
)
Get-WmiObject -class Win32_LogicalDisk -computer $computername `
-filter "drivetype=$drivetype" |
Sort-Object -property DeviceID |
Select-Object -property DeviceID,
@{label='FreeSpace(MB)';expression={$_.FreeSpace / 1MB -as [int]}},
@{label='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{label='%Free';expression={$_.FreeSpace / $_.Size * 100 -as [int]}}
在基于备注的帮助代码后面,将[CmdletBinding()]指示符置于脚本的第一行非常重要。PowerShell只会在该位置查看该指示符。加上这个指示符之后,脚本还会正常运行。但我们已经启用了好几个功能,我们会在接下来进行探索。
22.3 将参数定义为强制化参数
代码清单22.3 为Get-DiskInventory.ps1添加一个强制参数
<#
.SYNOPSIS
Get-DiskInventory retrieves logical disk information from one or more computers.
.DESCRIPTION
Get-DiskInventory uses WMI to retrieve the Win32_LogicalDisk instance from one or more computers.It displays each disk's drvie letter,free space,total size,and percentage fo free space.
.PARAMETER computername
The computer name,or names to query.Default:Localhost.
.EXAMPLE
Get-DiskInventory -computername SERVER-R2 -drivetype 3
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[string]$computername = 'localhost',
[int]$drivetype = 3
)
Get-WmiObject -class Win32_LogicalDisk -computer $computername `
-filter "drivetype=$drivetype" |
Sort-Object -property DeviceID |
Select-Object -property DeviceID,
@{label='FreeSpace(MB)';expression={$_.FreeSpace / 1MB -as [int]}},
@{label='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{label='%Free';expression={$_.FreeSpace / $_.Size * 100 -as [int]}}
仅仅使用[Parameter(Mandatory=$True)]这样一个描述符,会使得当用户忘记提供计算机名称时,PowerShell就会提示用户输入该参数。为了更进一步帮助PowerShell识别用户传入的参数,我们定义两个输入参数的数据类型:-computerName定义为[string]类型,而-drivetype定义为[int]类型。
22.4 添加参数别名
假如你认为-hostname比-computerName更容易记忆的话,你可以将该名称作为备用名称添加,也就是参数别名。这只需要另外一个修饰符,如代码清单22.4所示。
<#
.SYNOPSIS
Get-DiskInventory retrieves logical disk information from one or more computers.
.DESCRIPTION
Get-DiskInventory uses WMI to retrieve the Win32_LogicalDisk instance from one or more computers.It displays each disk's drvie letter,free space,total size,and percentage fo free space.
.PARAMETER computername
The computer name,or names to query.Default:Localhost.
.EXAMPLE
Get-DiskInventory -computername SERVER-R2 -drivetype 3
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[Alias('hostname')]
[string]$computername = 'localhost',
[int]$drivetype = 3
)
Get-WmiObject -class Win32_LogicalDisk -computer $computername `
-filter "drivetype=$drivetype" |
Sort-Object -property DeviceID |
Select-Object -property DeviceID,
@{label='FreeSpace(MB)';expression={$_.FreeSpace / 1MB -as [int]}},
@{label='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{label='%Free';expression={$_.FreeSpace / $_.Size * 100 -as [int]}}
完成小幅修改后,我们现在可以运行下述代码。
PS C:\>.\Get-DiskInventory -host SERVER2
再次声明,新增的标签是-computername参数的一部分,因此对-drivetype参数不生效。现在-computername参数的定义占了3行。当然,我们也能将三行连成一行。
[Parameter(Mandatory=$True)][Alias('hostname')][string]$computername
22.5 验证输入的参数
驱动器类型3是本地磁盘。类型2是可移动磁盘。我们希望阻止使用我们脚本的用户使用2、3类型之外的数字。代码22.5展示了我们所需的小幅修改。
代码清单22.5 Get-DiskInventory.ps1添加参数验证
<#
.SYNOPSIS
Get-DiskInventory retrieves logical disk information from one or more computers.
.DESCRIPTION
Get-DiskInventory uses WMI to retrieve the Win32_LogicalDisk instance from one or more computers.It displays each disk's drvie letter,free space,total size,and percentage fo free space.
.PARAMETER computername
The computer name,or names to query.Default:Localhost.
.EXAMPLE
Get-DiskInventory -computername SERVER-R2 -drivetype 3
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[Alias('hostname')]
[string]$computername = 'localhost',
[ValidateSet(2,3)]
[int]$drivetype = 3
)
Get-WmiObject -class Win32_LogicalDisk -computer $computername `
-filter "drivetype=$drivetype" |
Sort-Object -property DeviceID |
Select-Object -property DeviceID,
@{label='FreeSpace(MB)';expression={$_.FreeSpace / 1MB -as [int]}},
@{label='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{label='%Free';expression={$_.FreeSpace / $_.Size * 100 -as [int]}}
新的标签告诉PowerShell,对于参数-drivetype,只允许传入2和3这两个值,并且3是默认值。
22.6 通过添加详细输出获得易用性体验
在第19章中,我们提到,很多脚本使用者喜欢看到脚本输出执行的进度,我们倾向于使用Write-Verbose而不是Write-Host产生这些信息。下面让我们来看一个实际例子。
我们在代码清单22.6中添加一些详细输出。
代码清单22.6 为Get-DiskInventory.ps1添加详细输出
<#
.SYNOPSIS
Get-DiskInventory retrieves logical disk information from one or more computers.
.DESCRIPTION
Get-DiskInventory uses WMI to retrieve the Win32_LogicalDisk instance from one or more computers.It displays each disk's drvie letter,free space,total size,and percentage fo free space.
.PARAMETER computername
The computer name,or names to query.Default:Localhost.
.EXAMPLE
Get-DiskInventory -computername SERVER-R2 -drivetype 3
#>
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[Alias('hostname')]
[string]$computername = 'localhost',
[ValidateSet(2,3)]
[int]$drivetype = 3
)
Write-Verbose "Connecting to $computername"
Write-Verbose "Looking for drive type $drivetype"
Get-WmiObject -class Win32_LogicalDisk -computer $computername `
-filter "drivetype=$drivetype" |
Sort-Object -property DeviceID |
Select-Object -property DeviceID,
@{label='FreeSpace(MB)';expression={$_.FreeSpace / 1MB -as [int]}},
@{label='Size(GB)';expression={$_.Size / 1GB -as [int]}},
@{label='%Free';expression={$_.FreeSpace / $_.Size * 100 -as [int]}}
Write-Verbose "Finished running command"
下面尝试以两种方式运行该脚本。第一次尝试不会显示任何详细输出。
PS C:\>.\Get-DiskInventory -computername localhost
下面是第二次尝试,也就是我们希望显示详细输出。
PS C:\>.\Get-DiskInventory -computername localhost -verbose