「我不總是測試我的腳本,但當我這樣做時,我會在生產環境中進行測試。」
別撒謊。你以前也這樣做過。我們都曾經這樣做過。但是,在生產環境中運行 PowerShell 腳本時,並不需要冒險。只要記住使用內置的 PowerShell WhatIf 參數!
在對環境進行更改之前,知道該 PowerShell 命令會做什麼,這不是很好嗎?想象一下,你可以問自己的命令:“如果你運行了,你會做什麼?”你可以使用 WhatIf 參數。
所有已編譯的 PowerShell cmdlet 都包含一個名為 WhatIf 的參數。該參數可幫助您評估命令是否按您的預期工作,或者是否會引起核災。
方便的 WhatIf 參數不僅適用於所有內置的 cmdlet,還適用於您的腳本和高級功能!如果您的代碼將更改環境中的內容,您可以選擇實施失敗安全機制。
先決條件
本文將進行一個演練。如果您在此過程中想要跟隨,您應該準備好一些東西。
- A Windows computer capable of running Powershell v5.1. (Windows 10 and above recommended)
- A script editor like Notepad++, the Windows PowerShell ISE or Visual Studio Code.
請注意,在本文中,我將在一台運行 Windows 10 的機器上使用 Visual Studio Code 1.38(2019 年 8 月)。
WhatIf PowerShell 參數:定義
簡而言之,WhatIf
參數是一個內建的開關參數,對於所有高級功能和 cmdlet 都可用(通過在腳本和函數中添加 PowerShell 的CmdletBinding
關鍵字)。使用時,該命令會向控制台報告命令的預期效果,但實際上不執行該命令。
所有的 cmdlet 和高級功能都提供了 WhatIf 參數。在本文中,我們將使用Get-Service
、Stop-Service
和New-Item
cmdlet 來演示此參數。
檢查 Powershell WhatIf 支持
如果您不確定某個命令是否支持 WhatIf
,有兩種快速的方法可以檢查。
使用 Get-Command
您可以使用 Get-Command
命令使用 Syntax
參數查看命令的元數據,如下所示。如果看到 -WhatIf
的參考,則支持 WhatIf
。

Get-Command <CommandName> -Syntax
使用 Tab Completion
您還可以使用 Tab Completion 檢查是否支持 WhatIf
參數。只需在 PowerShell 控制台中輸入要檢查的命令,然後在空格、破折號、’Wh’ 和 Tab 鍵之後。
如果出現 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
參數只是模擬操作。您正在影響 WhatIf
的行為。
WhatIf
行为也可以在更高的级别设置,通过操作自动变量 $WhatIfPreference
影响所有命令。
$WhatIfPreference
变量是布尔值。它只能是 True
或 False
。默认情况下,它被设置为 False,表示除非在命令级别覆盖,否则所有命令的 WhatIf
支持都被禁用。如果设置为 True
,所有支持它的命令,无论是显式地使用 WhatIf
参数还是不使用,都将处于“WhatIf
模式”。
你可以通过将 $WhatIfPreference
的值更改为 True
来测试。使用 $WhatIfPreference = $true
。你可以看到下面使用 New-Item
不使用 WhatIf
参数时的行为就像传递了该参数一样。

PS51> $WhatIfPreference = $true
如果你已将
$WhatIfPreference
更改为True
,别忘了通过$WhatIfPreference = $false
将其改回False
。
在本节中,你已经学会了如何在现有的 cmdlet 中使用 WhatIf 支持。在下一个操作中,你将学习如何在自定义脚本和函数中构建 WhatIf 支持。
在函数中实现 Powershell WhatIf 支持
在您嘗試在腳本中實現WhatIf
支援之前,了解如何正確地執行這項任務是非常重要的。在下一節中,您將看到錯誤和正確的執行方式。
錯誤的執行方式:不要重新發明輪子
腳本開發人員經常會重新發明輪子,自行實現一些if/then邏輯來支援WhatIf
。下面是一個例子。
請注意,開發人員定義了自己的WhatIf
開關參數。然後,根據該參數的值,他們使用if/then構造來處理當使用或不使用WhatIf
參數時的邏輯。
當以下面的方式運行上述函數並使用WhatIf參數時,它看起來完成了它的工作。該函數實際上沒有刪除任何內容,並且向控制台返回了一則訊息。

PS51> Remove-LogFile -name log.txt -WhatIf
如果它能正常運作,那麼這種方法有什麼問題呢?因為您正在忽略高級函數的內建功能。您需要將此功能嵌入到您創建的每個函數中,而不僅僅專注於在關閉命令時該命令將執行的操作。
相反地,不要重新發明輪子,使用SupportsShouldProcess
關鍵字 結合 $PSCmdlet.ShouldProcess()
。即將介紹的內容。
正確使用:使用SupportsShouldProcess
使用[CmdletBinding()]
關鍵字的所有函數都會變成”高級”函數。該關鍵字為函數添加了各種功能,包括WhatIf
支援。
所有高級函數都支援WhatIf
功能,但你需要自行利用它。為此,你必須首先在[CmdletBinding()]
括號之間使用SupportsShouldProcess
關鍵字,如下所示。
現在,該函數允許你在$PSCmdlet
函數變數上調用ShouldProcess()
方法,以確定是否將WhatIf
參數傳遞給函數。當使用WhatIf
參數時,ShouldProcess()
返回False
。否則,它將始終返回True
。
WHATIF PARAMETER USED | SHOULDPROCESS() RESULT |
---|---|
True | False |
False | True |
現在,當使用WhatIf
參數執行Remove-LogFile
時,您可以看到下面的內容;它顯示與內建的 cmdlet 相同的行為。

PS51> Remove-LogFile -name log.txt -WhatIf
摘要
在本文中,您了解了 PowerShell 的 WhatIf 參數。現在您應該知道它是如何工作的以及它可以帶來什麼好處。
您還應該知道,下次在需要 PowerShell 函數的失敗安全機制時,不要重新發明輪子。相反,利用現有的 PowerShell WhatIf
支援!