掌握 PowerShell 的 WhatIf 参数

“我并不总是测试我的脚本,但当我这么做时,我是在生产环境中进行的”

别撒谎。在某个时候,我们都曾经这样做过。但在生产环境中运行PowerShell脚本并不一定有风险。只需记住使用内置的PowerShell WhatIf参数!

在PowerShell脚本对生产环境进行更改之前,了解该PowerShell命令会做什么是不是件好事?想象一下在执行命令之前能够询问:“如果你要运行,你会做什么?”您可以使用WhatIf参数。

所有编译的PowerShell cmdlet都包含一个名为WhatIf的参数。该参数帮助您评估命令是否会按照您的预期工作,或者是否会引发核反应堆的融化。

方便的WhatIf参数不仅适用于所有内置的cmdlet,而且也适用于您的脚本和高级功能!如果您的代码将更改环境中的内容,您就可以选择实施它,以确保有一个安全机制。

先决条件

本文将进行逐步介绍。如果您想在这个过程中跟随,您应该有一些事先准备好的东西。

请注意,在本文中,我将在Windows 10计算机上使用Visual Studio Code 1.38(2019年8月)。

WhatIf PowerShell参数:定义

简而言之,WhatIf参数是所有高级函数和cmdlet(通过将PowerShell CmdletBinding关键字添加到脚本和函数中)都可用的内置开关参数。当使用时,该命令会向控制台报告命令的预期效果。但实际上不会执行该命令。

所有cmdlet和高级函数都具有可用的WhatIf参数。在本文中,我们将使用Get-ServiceStop-ServiceNew-Item cmdlet演示此参数。

检查PowerShell WhatIf支持

如果您不确定特定命令是否支持WhatIf,有两种快速检查的方法。

使用Get-Command

您可以使用Get-Command命令通过使用下面显示的Syntax参数查看命令元数据。如果看到-WhatIf引用,则支持WhatIf

Get-Command <CommandName> -Syntax

使用Tab Completion

您还可以通过使用制表符补全检查WhatIf参数的支持。只需在PowerShell控制台中键入要检查的命令,然后加上空格、破折号、’Wh’和制表键。

如果出现WhatIf,则说明该命令具有WhatIf参数。

PS> <CommandName> -Wh[tab]

使用PowerShell WhatIf参数与Cmdlet

有许多不同的方法可以利用WhatIf参数。在这一部分,您将学习如何立即开始使用内置的cmdlet来使用WhatIf参数。

创建文件

像所有的cmdlet一样,New-Item cmdlet有一个WhatIf参数。在这个例子中,您将使用New-Item cmdlet来创建一个名为newfile1.txt的文件,该文件位于相同的工作目录中。

如果您运行下面的命令,它将创建名为newfile.txt的文件。

PS51> New-Item -ItemType File -Path .\newfile1.txt

但如果此命令创建的文件可能会导致问题,该怎么办?没问题。您可以在最后添加WhatIf参数。

New-Item -ItemType File -Path .\newfile1.txt -WhatIf

停止服务

您还可以使用Stop-Service cmdlet来使用WhatIf参数。在这个例子中,您正在获取前五个服务的列表,并使用Stop-Service命令停止它们。但您并没有。

相反,您只是在PowerShell控制台看到输出消息,让您知道Stop-Service cmdlet将停止哪些服务。

PS51> (Get-Service)[0..4] | Stop-Service -WhatIf

全局更改Powershell WhatIf行为

到目前为止,您应该知道仅使用WhatIf参数与cmdlet或高级函数模拟操作。您正在影响命令级别的WhatIf行为。

WhatIf行为还可以在影响所有命令的更高级别进行设置,方法是通过操作自动变量$WhatIfPreference

$WhatIfPreference变量是布尔型的,只能是TrueFalse。默认情况下,它设置为False,表示WhatIf支持在所有命令上都被禁用,除非在命令级别被覆盖。如果设置为True所有支持它的命令,无论是明确使用WhatIf参数还是不使用,都将处于“WhatIf模式”中。

您可以通过通过$WhatIfPreference = $true更改$WhatIfPreference的值来测试此功能。您可以看到,使用New-Item不带WhatIf参数现在就像传递了该参数一样。

PS51> $WhatIfPreference = $true

如果您已将$WhatIfPreference更改为True,请不要忘记通过$WhatIfPreference = $false将其改回False

在本节中,您学会了如何在现有的cmdlet中使用WhatIf支持。在下一步中,您将学习如何在自定义脚本和函数中构建WhatIf支持。

在函数中实现PowerShell WhatIf支持

在尝试在脚本中实现WhatIf支持 之前,了解有错误和正确的方法是至关重要的。您将在接下来的部分看到它们是什么。

错误的做法:不要重复造轮子

脚本开发人员常常会重复造轮子,使用一些if/then逻辑来实现自己的WhatIf支持。下面是一个示例。

请注意,开发人员已经定义了自己的WhatIf开关参数。然后,使用该参数的值,他们使用了if/then结构来处理当使用或不使用WhatIf参数时的逻辑。

Function Remove-LogFile {
    param (
        [Parameter(Mandatory)]
        [string]$name,

        [switch]$WhatIf
    )
    
    if ($WhatIf.IsPresent) { # WhatIf开关打开。
        Write-Host "WhatIf: I will remove the log file ""$name""" -ForegroundColor Yellow
    } else {
        # WhatIf开关关闭。
        Write-Host "Delete log file ""$name""" -ForegroundColor Green
    }
}

当使用如下所示的WhatIf参数运行上述函数时,看起来它完成了它的工作。该函数实际上并未删除任何内容,并向控制台返回了一条消息。

PS51> Remove-LogFile -name log.txt -WhatIf

如果它能运行,那么这种方法有什么问题呢?因为您忽略了高级函数的内置功能。您将需要将此功能集成到您创建的每个函数中,而不仅仅专注于在关闭时命令将执行什么操作。

相反,不要重复造轮子,使用SupportsShouldProcess关键字与$PSCmdlet.ShouldProcess()结合起来。就是这样。

正确做法:使用SupportsShouldProcess

所有使用[CmdletBinding()]关键字的函数都会使它们变成“高级”函数。这个关键字为函数添加了各种功能,包括WhatIf支持。

所有高级函数都支持WhatIf功能,但是你可以选择是否利用它。要这样做,你必须首先在[CmdletBinding()]括号中使用SupportsShouldProcess关键字,就像下面所示。

[CmdletBinding(SupportsShouldProcess)]

现在,该函数允许你在$PSCmdlet函数变量上调用ShouldProcess()方法,以确定WhatIf参数是否传递给了函数。当使用WhatIf参数时,ShouldProcess()返回False。否则,它将始终返回True

Function Remove-LogFile {
     [cmdletbinding(SupportsShouldProcess)]
     param (
         [Parameter(Mandatory)]
         [string]$name
     )
     if ($PSCmdlet.ShouldProcess($name)) {
         ## 没有使用-WhatIf参数。函数应该像正常一样处理。
         Write-Host ("Delete log file " + $name) -ForegroundColor Green
     } else {
         ## 使用了-WhatIf参数。函数不应该处理。
     }
 }
WHATIF PARAMETER USED SHOULDPROCESS() RESULT
True False
False True

现在您可以看到,当使用WhatIf参数执行Remove-LogFile时,它显示与内置cmdlet相同的行为。

PS51> Remove-LogFile -name log.txt -WhatIf

摘要

在本文中,您了解了PowerShell的WhatIf参数。您现在应该了解它是如何工作的以及它可以带来什么好处。

您还应该知道,下次在需要为PowerShell函数添加安全保障时,不要重新发明轮子。相反,利用现有的PowerShellWhatIf支持!

进一步阅读

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