PowerShell WhatIf 매개 변수 마스터하기

“나는 항상 스크립트를 테스트하지는 않지만, 테스트할 때는 실제 운영 환경에서 수행합니다.”

거짓말하지 마세요. 당신도 한 번쯤은 해봤을 겁니다. 운영 환경에서 PowerShell 스크립트를 실행할 때는 위험할 필요가 없습니다. PowerShell 내장 WhatIf 매개변수를 사용하면 됩니다!

PowerShell 명령이 환경에 변경을 가하기 전에 그 명령이 무엇을 할지 알 수 있다면 좋지 않을까요? 명령에 대해 “실행한다면 어떻게 될까?” 라고 물어볼 수 있습니다. 이를 위해 WhatIf 매개변수를 사용할 수 있습니다.

모든 컴파일된 PowerShell cmdlet에는 WhatIf라는 매개변수가 있습니다. 이 매개변수는 명령이 예상대로 작동하는지 또는 핵 융합을 시작하는지 평가하는 데 도움을 줍니다.

편리한 WhatIf 매개변수는 내장된 cmdlet뿐만 아니라 스크립트와 고급 기능에도 사용할 수 있습니다! 코드가 환경에 변경을 가할 경우, 이를 구현할지 여부를 선택할 수 있는 보호 장치가 있습니다.

전제 조건

이 문서는 단계별 안내서입니다. 이 여정 동안 따라해보고 싶다면 몇 가지 사전 준비 사항이 있어야 합니다.

이 문서에서는 Windows 10 기기에서 2019년 8월에 출시된 Visual Studio Code 1.38 버전을 사용합니다.

WhatIf PowerShell 매개변수: 정의됨

요약하면, WhatIf 매개변수는 모든 고급 기능과 cmdlet에서 사용할 수 있는 내장된 스위치 매개변수입니다(PowerShell 스크립트와 함수에 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

탭 자동완성 사용

탭 자동완성을 사용하여 WhatIf 매개변수 지원을 확인할 수도 있습니다. PowerShell 콘솔에 확인하려는 명령을 입력한 후 공백, 대시, ‘Wh’ 및 탭 키를 누릅니다.

WhatIf이 표시되면 해당 명령에 WhatIf 매개변수가 있는 것입니다.

PS> <CommandName> -Wh[tab]

Cmdlet과 함께 PowerShell WhatIf 매개변수 사용하기

WhatIf 매개변수를 활용하는 여러 가지 방법이 있습니다. 이 섹션에서는 내장된 cmdlet을 사용하여 즉시 WhatIf 매개변수를 사용하는 방법을 배우게 됩니다.

파일 생성

New-Item cmdlet은 다른 모든 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 동작 전역적으로 변경하기

이 시점에서 알아두어야 할 점은 cmdlet 또는 고급 함수에서 WhatIf 매개변수를 사용하면 작업이 시뮬레이션될 뿐입니다. 명령 수준에서 WhatIf 동작에 영향을 줍니다.

WhatIf 동작은 자동 변수 $WhatIfPreference를 조작하여 모든 명령에 영향을 주는 높은 수준에서도 설정할 수 있습니다.

$WhatIfPreference 변수는 부울 값입니다. True 또는 False만 가능합니다. 기본값은 False로, 명령 수준에서 재정의하지 않는 한 모든 명령에서 WhatIf 지원이 비활성화됩니다. True로 설정하면, WhatIf 매개변수를 명시적으로 사용하든지 여부에 상관없이 모든 지원 명령이 “WhatIf” 모드로 됩니다.

$WhatIfPreference 값을 True로 변경하여 $WhatIfPreference = $true를 통해 테스트할 수 있습니다. 아래의 New-Item을 사용하여 WhatIf 매개변수 없이 이제 매개변수가 전달된 것처럼 동작합니다.

PS51> $WhatIfPreference = $true

$WhatIfPreferenceTrue로 변경한 경우, $WhatIfPreference = $false를 통해 다시 False로 변경하는 것을 잊지 마세요.

이 절에서는 기존 cmdlet과 함께 WhatIf 지원을 사용하는 방법을 배웠습니다. 다음 단계에서는 사용자 정의 스크립트와 함수에서 WhatIf 지원을 구축하는 방법을 배우게 될 것입니다.

함수에서 Powershell WhatIf 지원 구현하기

WhatIf 지원을 스크립트에 구현하기 전에, 잘못된 방법과 올바른 방법이 있다는 것을 알고 있어야 합니다. 다음 섹션에서 그 방법들을 알아보겠습니다.

잘못된 방법: 바퀴를 다시 발명하지 마세요

스크립트 개발자가 자체 WhatIf 지원을 만들기 위해 if/then 논리와 함께 바퀴를 다시 발명하는 일은 흔치 않지는 않습니다. 아래 예시를 살펴보세요.

개발자가 자체 WhatIf 스위치 매개변수를 정의한 것을 볼 수 있습니다. 그리고 그 매개변수의 값에 따라 WhatIf 매개변수를 사용했을 때 논리를 처리하기 위해 if/then 구조를 사용했습니다.

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)]

함수는 이제 WhatIf 매개변수가 함수에 전달되었는지 여부를 확인하기 위해 $PSCmdlet 함수 변수에 있는 ShouldProcess() 메서드를 호출할 수 있습니다. 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 함수에 대한 안전장치가 필요한 경우 다시 발명하지 말고 기존의 PowerShell WhatIf 지원을 활용해야 함을 알아야 합니다!

추가 읽기

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