Овладение параметром PowerShell WhatIf

«Я не всегда тестирую свои сценарии, но когда делаю это, я делаю это в продакшн»

Не лги. Ты делал это раньше. Мы все делали это в определенный момент времени. Однако, запуск PowerShell сценариев в продакшн среде не обязательно является рискованным. Просто помни использовать встроенный параметр PowerShell WhatIf!

Не было бы здорово знать, что бы делала эта команда PowerShell перед тем, как она внесет изменения в вашу среду? Представьте, что вы можете спросить у своей команды: «Что бы вы сделали, если бы запустились?» Вы можете использовать параметр WhatIf.

Все скомпилированные сценарии PowerShell включают параметр с именем WhatIf. Этот параметр помогает вам оценить, будет ли команда работать, как вы ожидаете, или запустит ядерный плавильный котел.

Удобный параметр WhatIf доступен не только для всех встроенных командлетов, но и для ваших сценариев и расширенных функций! Если ваш код будет вносить изменения в вашу среду, у вас есть возможность использовать механизм безопасности в случае неудачи, если вы решите его реализовать.

Необходимые условия

Эта статья будет пошаговым руководством. Если вы хотите следовать за мной в этом путешествии, у вас должно быть несколько вещей.

Обратите внимание, что в этой статье я буду использовать Visual Studio Code 1.38 (август 2019 года) на компьютере с Windows 10.

Параметр WhatIf в PowerShell: Определение

Вкратце, параметр WhatIf является встроенным переключателем параметра, доступным со всеми расширенными функциями и командлетами (путем добавления ключевого слова PowerShell CmdletBinding в сценарии и функциях). При использовании этой команды отчет ожидаемого эффекта команды выводится в консоль, но сама команда не выполняется.

Все командлеты и расширенные функции имеют параметр WhatIf. В этой статье мы продемонстрируем использование этого параметра с помощью командлетов Get-Service, Stop-Service и New-Item.

Проверка поддержки параметра WhatIf в PowerShell

Если вы не уверены, поддерживает ли определенная команда WhatIf, есть два быстрых способа проверки.

Использование команды Get-Command

Вы можете использовать команду Get-Command для просмотра метаданных команды, используя параметр Syntax, как показано ниже. Если вы видите ссылку на -WhatIf, значит поддерживается WhatIf.

Get-Command <CommandName> -Syntax

Использование автодополнения

Вы также можете проверить поддержку параметра WhatIf с помощью автодополнения. Просто введите команду, которую хотите проверить, в консоли PowerShell, а затем пробел, тире, ‘Wh’ и клавишу табуляции.

Если появляется WhatIf, значит эта команда имеет параметр WhatIf.

PS> <CommandName> -Wh[tab]

Использование параметра PowerShell WhatIf с командлетами

Существует множество различных способов использования параметра WhatIf. В этом разделе вы узнаете, как начать использовать параметр WhatIf немедленно с помощью встроенных cmdlet-ов.

Создание файла

Как и у всех cmdlet-ов, у cmdlet-а New-Item есть параметр WhatIf. В этом примере вы будете использовать cmdlet New-Item для создания файла с именем newfile1.txt в текущем рабочем каталоге.

Если вы выполните нижеприведенную команду, она создаст файл с именем newfile.txt.

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

Но что, если эта команда создает файл, который может вызвать проблемы, если он создается неудачно? Нет проблем. Вы можете добавить параметр WhatIf в конец.

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

Остановка службы

Вы также можете использовать параметр WhatIf с cmdlet-ом Stop-Service. В этом примере вы получаете список первых пяти служб и останавливаете их с помощью команды Stop-Service. Но вы этого не делаете.

Вместо этого вы только видите сообщение в выводе консоли PowerShell, которое сообщает вам, какие службы остановил бы cmdlet Stop-Service.

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

Изменение глобального поведения WhatIf в Powershell

На данный момент вы должны знать, что использование параметра WhatIf с cmdlet-ом или расширенной функцией только симулирует операцию. Вы влияете на поведение WhatIf на уровне команды.

Поведение WhatIf также можно установить на более высоком уровне, что влияет на все команды путем изменения автоматической переменной $WhatIfPreference.

Переменная $WhatIfPreference имеет тип boolean. Она может быть только True или False. По умолчанию она установлена в False, что означает, что поддержка WhatIf отключена для всех команд, если не переопределена на уровне команды. Если установить на True, все команды, поддерживающие это, будут работать в режиме “WhatIf”, независимо от явного использования параметра WhatIf.

Вы можете проверить это, изменив значение $WhatIfPreference на True с помощью $WhatIfPreference = $true. Как видно ниже, при использовании команды New-Item без параметра WhatIf она будет работать так, как если бы параметр был передан.

PS51> $WhatIfPreference = $true

Если вы изменили значение $WhatIfPreference на True, не забудьте вернуть его обратно на False с помощью $WhatIfPreference = $false.

На этом этапе вы узнали, как использовать поддержку WhatIf с существующими командами. В следующем действии вы узнаете, как добавить поддержку WhatIf в свои собственные скрипты и функции.

Реализация поддержки WhatIf в функциях PowerShell

Перед тем, как приступить к реализации поддержки WhatIf в своих скриптах, важно знать, что есть правильный и неправильный способы это делать. В следующих разделах вы узнаете, какие это способы.

Неправильный способ: не изобретайте велосипед

Не редкость, когда разработчики скриптов изобретают свой собственный механизм поддержки WhatIf с помощью конструкций if/then. Ниже приведен пример.

Обратите внимание, что разработчик определил собственный параметр переключения 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, но вам нужно воспользоваться этим. Для этого вы должны использовать ключевое слово SupportsShouldProcess внутри квадратных скобок [CmdletBinding()], как показано ниже.

[CmdletBinding(SupportsShouldProcess)]

Теперь функция позволяет вызывать метод ShouldProcess() на переменной функции $PSCmdlet, чтобы определить, был ли передан параметр 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

Теперь вы можете видеть ниже, когда Remove-LogFile выполняется с параметром WhatIf; он отображает ту же самую функциональность, что и встроенные cmdlet’ы.

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

Резюме

В этой статье вы узнали о параметре PowerShell WhatIf. Теперь вы должны понимать, как он работает и какие преимущества он может принести.

Вы также должны знать, что в следующий раз, когда вам понадобится надежная защита для ваших функций PowerShell, не стоит изобретать велосипед. Вместо этого воспользуйтесь существующей поддержкой PowerShell для параметра WhatIf!

Дальнейшее чтение

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