PowerShell 기능 마스터하기: 단계별 가이드

한 번 PowerShell 스크립트 작성에 익숙해지면 코드 모듈화에 대해 배워야 합니다. 모듈화는 코드를 구성 요소로 생성하는 것을 가리키는 멋진 용어입니다. PowerShell 세계에서는 PowerShell 함수가 이를 수행하는 가장 좋은 방법 중 하나입니다.

PowerShell 스크립트를 작성할 때 코드를 작성하는 방법에는 여러 가지 옵션이 있습니다. 수백 가지 작업을 수행하는 천 줄의 코드를 작성하여 코드 블록을 하나로 유지할 수 있습니다. 그러나 그렇게 하면 재앙이 됩니다. 대신 함수를 작성해야 합니다.

함수는 코드의 사용성과 가독성을 크게 향상시켜 작업을 훨씬 쉽게 만들어 줍니다. 이 튜토리얼에서는 함수 작성, 함수 매개변수 추가 및 관리, 함수가 파이프라인 입력을 받을 수 있도록 설정하는 방법을 배우게 됩니다. 그러나 먼저 용어를 살펴보겠습니다.

이 게시물은 저의 책 PowerShell for Sysadmins: Workflow Automation Made Easy에서 추출되었습니다. 이 튜토리얼에서 무언가를 배운다면, 함수 및 다른 PowerShell 관련 정보를 더 알아보기 위해 이 책을 확인해 보세요.

함수 vs. Cmdlet

함수의 개념은 이미 익숙할 수도 있습니다. 이미 사용한 적이 있는 cmdlet과 비슷한 것 같습니다. 예를 들어, Start-ServiceWrite-Host와 같은 명령어는 함수와 비슷합니다. 이들은 하나의 문제를 해결하는 이름이 지정된 코드 조각입니다. 함수와 cmdlet의 차이점은 이러한 구성요소가 각각 어떻게 작성되는지입니다.

A cmdlet isn’t written with PowerShell. It’s written in another language, typically something like C#. The cmdlet is then compiled and made available inside PowerShell.

반면, 함수는 다른 언어가 아닌 PowerShell로 작성됩니다.

아래에 표시된대로 Get-Command cmdlet과 해당 CommandType 매개변수를 사용하여 cmdlet과 함수를 구분할 수 있습니다.

Get-Command –CommandType Function

위의 명령은 현재 PowerShell 세션에 로드된 모든 함수 또는 PowerShell에서 사용 가능한 모듈 내의 함수를 반환합니다.

관련: PowerShell 모듈 이해 및 작성

사전 요구 사항

모든 예제를 따라하려면 사용 가능한 PowerShell 버전이 있어야 합니다. 이 자습서에는 특정 버전 요구 사항이 없습니다. 또한 Visual Studio Code와 같은 좋은 코드 편집기를 사용하여 코드 스니펫을 복사, 붙여넣기 및 실행할 수 있도록 해야 합니다.

간단한 함수 작성하기

함수를 사용하기 전에 먼저 정의해야 합니다. 함수를 정의하기 위해서는 함수 키워드를 사용하고, 그 뒤에는 설명적이고 사용자 정의된 이름을 사용한 다음 중괄호 집합을 사용합니다. 중괄호 안에는 PowerShell이 실행하도록 원하는 스크립트 블록이 들어갑니다.

아래에서는 기본 함수와 해당 함수를 실행하는 것을 볼 수 있습니다. 이 함수인 Install-SoftwareWrite-Host를 사용하여 콘솔에 메시지를 표시합니다. 정의된 후에는 이 함수의 이름을 사용하여 스크립트 블록 내의 코드를 실행할 수 있습니다.

PS> function Install-Software { Write-Host 'I installed some software. Yippee!' }
PS> Install-Software
I installed some software, Yippee!

동사-명사로 명명하기

A function’s name is important. You can name your functions whatever you want, but the name should always describe what the function does. The function-naming convention in PowerShell is the Verb-Noun syntax.

함수 이름은 항상 동사로 시작하여 대시와 명사가 이어져야 합니다. “승인된” 동사 목록을 찾으려면 Get-Verb cmdlet을 사용하십시오.

함수 동작 변경하기

함수의 동작을 변경하려면 아래와 같이 함수가 실행하는 코드를 간단히 변경할 수 있습니다.

PS> function Install-Software { Write-Host 'You installed some software, Yay!' }
PS> Install-Software
You installed some software, Yay!

함수 내부의 코드를 변경한 이후에는 약간 다른 메시지가 표시될 것입니다.

고급 함수 정의하기

함수를 다양한 위치에 정의할 수 있습니다. 위 섹션에서는 튜토리얼에서 단순히 코드를 PowerShell 콘솔에 복사하여 붙여넣은 것으로 가정합니다. 하지만 이것이 유일한 방법은 아닙니다. 스크립트나 모듈에 함수를 정의하고, 해당 스크립트나 모듈을 호출하여 함수를 메모리에 로드하는 방식으로 함수를 정의할 수도 있습니다.

이전 섹션에서는 작은 함수로 작업했기 때문에 콘솔에서 정의하는 것은 큰 문제가 되지 않았습니다. 하지만 대부분의 경우에는 훨씬 더 큰 함수가 있을 것입니다. 그럴 경우 스크립트나 모듈에 함수를 정의하고, 해당 스크립트나 모듈을 호출하여 함수를 메모리에 로드하는 방식으로 정의하는 것이 더 쉽습니다.

큰 기능을 조정할 때마다 큰 함수를 다시 입력하는 것은 조금 답답할 수 있다는 것을 상상할 수 있습니다.

I suggest you now open your favorite editor and store the function in a .ps1 file as you work through the rest of the tutorial.

함수에 매개변수 추가하기

PowerShell 함수는 임의의 수의 매개변수를 가질 수 있습니다. 사용자 정의 함수를 만들 때, 매개변수를 포함할지 여부를 선택하고 이러한 매개변수가 어떻게 작동할지 결정할 수 있습니다. 매개변수는 필수일 수도 선택적일 수도 있으며, 모든 것을 허용하거나 제한된 가능한 인수 목록 중 하나를 허용할 수도 있습니다.

관련 정보: PowerShell 매개변수에 대해 알고 싶은 모든 것

예를 들어, 앞서 언급한 Install-Software 함수를 통해 설치하는 가상의 소프트웨어는 여러 버전이 있을 수 있습니다. 그러나 현재 Install-Software 함수는 사용자가 설치하려는 버전을 지정할 수 있는 방법을 제공하지 않습니다.

함수를 사용하는 유일한 사람이라면, 특정 버전이 필요할 때마다 내부 코드를 변경할 수 있을 것입니다. 그러나 이는 시간 낭비일 뿐만 아니라 잠재적인 오류가 발생할 수도 있으며, 다른 사람들이 코드를 사용할 수 있도록 하려면 좋지 않습니다.

함수에 매개변수를 도입하면 다양성을 가질 수 있습니다. 변수가 동일한 상황의 여러 버전을 처리할 수 있는 스크립트를 작성할 수 있게 했던 것처럼, 매개변수를 사용하면 한 가지 일을 여러 가지 방법으로 수행하는 단일 함수를 작성할 수 있습니다.

이 경우, 동일한 소프트웨어의 여러 버전을 설치하고 여러 컴퓨터에 설치하려는 것입니다.

먼저 함수에 매개변수를 추가하여 설치할 버전을 지정할 수 있도록 합시다.

간단한 매개변수 생성하기

함수에 매개변수를 생성하려면 param 블록을 사용해야 합니다. param 블록은 함수의 매개변수를 모두 보유합니다. 아래에 표시된 대로 param 키워드 다음에 괄호로 둘러싼 param 블록을 정의하세요.

function Install-Software {
	[CmdletBinding()]
	param()

	Write-Host 'I installed software version 2. Yippee!'
}

이 시점에서 함수의 실제 기능은 전혀 변경되지 않았습니다. 단지 매개변수를 준비하기 위해 배관을 설치한 것뿐입니다.

현재 함수는 실제로 소프트웨어를 설치하지는 않습니다. 단지 Write-Host cmdlet을 사용하여 소프트웨어 설치를 시뮬레이션하고 함수 작성에 집중할 수 있습니다.

param 블록을 추가한 후에는 아래에 표시된 대로 param 블록의 괄호 안에 매개변수를 생성할 수 있습니다.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string] $Version
	)
	
	Write-Host "I installed software version $Version. Yippee!"

}

위의 param 블록 안에서 먼저 매개변수 블록을 정의해야 합니다. 여기서 사용되는 Parameter() 블록은 “고급 매개변수”로 변환됩니다. 여기에 표시된 빈 Parameter 블록은 아무 작업도 수행하지 않지만 필수입니다. 다음 섹션에서 사용 방법을 설명하겠습니다.

대신에 [string] 유형에 집중합시다. 매개 변수 이름 앞에 대괄호 사이에 매개 변수의 유형을 넣음으로써 매개 변수의 값을 특정 유형으로 캐스트합니다. PowerShell은 항상 이 매개 변수로 전달된 값을 문자열로 변환하려고 시도합니다 – 이미 문자열이 아닌 경우에만. 위에서 $Version으로 전달된 모든 것이 항상 문자열로 처리됩니다.

매개 변수를 유형으로 캐스트하는 것은 필수적이지는 않지만, 적극 권장합니다. 이렇게 하면 유형이 명시적으로 정의되며, 나중에 발생하는 오류를 크게 줄일 수 있습니다.

Write-Host 문에도 $Version을 추가합니다. 따라서 Version 매개 변수로 Install-Software 함수를 실행하고 버전 번호를 전달하면 아래와 같이 그에 해당하는 문이 표시됩니다.

PS> Install-Software -Version 2
I installed software version 2. Yippee!

이제이 매개 변수로 무엇을 할 수 있는지 알아봅시다.

필수 매개 변수 특성

매개 변수 블록을 사용하여 매개 변수의 동작을 변경할 수 있는 다양한 매개 변수 특성을 제어할 수 있습니다. 예를 들어, 함수를 호출하는 사람이 특정 매개 변수를 전달해야하는지 확인하려면 해당 매개 변수를 필수로 정의할 수 있습니다.

기본적으로 매개 변수는 선택적입니다. 아래에 표시된대로 매개 변수 블록 내에서 Mandatory 키워드를 사용하여 사용자가 버전을 전달하도록 강제합니다.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Write-Host "I installed software version $Version. Yippee!"

}

위의 함수를 실행하면 다음과 같은 프롬프트를 받게됩니다.

Prompting for a mandatory parameter

Mandatory 속성을 설정한 후에 매개변수 없이 함수를 실행하면 사용자가 값을 입력할 때까지 실행이 중단됩니다. 이제 함수는 사용자가 Version 매개변수에 값을 지정할 때까지 대기합니다. 입력한 후에 PowerShell이 함수를 실행합니다.

강제 매개변수 프롬프트를 피하려면 아래에서와 같이 함수를 호출할 때 매개변수에 값을 전달하면 됩니다.

Install-Software -Version 2

기본 매개변수 값

예를 들어, 특정 매개변수에 동일한 값을 계속 전달해야 하는 경우 대기하고 있는 시간 중 대부분의 경우에 대해 기본 매개변수 값을 정의할 수 있습니다.

예를 들어, 이 소프트웨어의 버전 2를 90%의 확률로 설치하려는 경우 이 함수를 실행할 때마다 값을 설정하고 싶지 않은 경우 $Version 매개변수에 기본값 2를 할당할 수 있습니다. 아래에 이 예제를 볼 수 있습니다.

function Install-Software {
	[CmdletBinding()]
	param(
		[Parameter()]
		[string]$Version = 2
	)

	Write-Host "I installed software version $Version. Yippee!"

}

기본 매개변수가 있더라도 전달된 매개변수를 전달할 수 없습니다. 전달된 값은 기본값을 무시합니다.

매개변수 유효성 검사 속성 추가하기

매개변수를 통해 함수에 전달할 수 있는 값의 범위를 제한하는 것은 항상 좋은 아이디어입니다. 그것을 수행하는 가장 좋은 방법은 매개변수 유효성 검사 속성을 사용하는 것입니다.

사용자(또는 당신)가 함수나 스크립트에 전달할 수 있는 정보를 제한하는 것은 함수 내부의 불필요한 코드를 없애줍니다. 예를 들어, 버전 3이 기존 버전인 것을 알고 있는 경우에 Install-Software 함수에 값 3을 전달한다고 가정해 보겠습니다.

당신의 기능은 모든 사용자가 어떤 버전이 있는지 알고 있다고 가정하고 있기 때문에, 버전 4를 지정하려고 할 때 어떤 일이 발생하는지 고려하지 않습니다. 이 경우, 해당 폴더를 찾지 못하므로 함수가 실패합니다.

매개변수 유효성 검사 없이 삶

아래 예제를 살펴보세요. 파일 경로에서 $Version 문자열을 사용할 때 발생하는 경우입니다. 누군가가 기존 폴더 이름을 완성하지 못하는 값을 전달하면(예: SoftwareV3 또는 SoftwareV4), 코드가 실패합니다.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
	)

	Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version

}
Failing on unexpected parameter values

이 문제를 해결하기 위해 오류 처리 코드를 작성하거나 사용자가 기존 소프트웨어의 버전만 전달하도록 요구함으로써 문제를 조기에 해결할 수 있습니다. 사용자의 입력을 제한하기 위해 매개변수 유효성 검사를 추가하세요.

매개변수 유효성 검사 추가

다양한 종류의 매개변수 유효성 검사가 있지만, Install-Software 함수에 대해 [ValidateSet 속성](https://adamtheautomator.com/powershell-validateset/)이 가장 적합합니다. ValidateSet 유효성 검사 속성을 사용하면 매개변수에 허용되는 값 목록을 지정할 수 있습니다. 문자열 1 또는 2만 처리하는 경우 사용자가 이러한 값만 지정할 수 있도록 하여 함수가 즉시 실패하고 실패 이유를 사용자에게 알릴 수 있습니다.

다음과 같이 param 블록 안에 매개변수 유효성 검사 속성을 추가하세요. 원래 Parameter 블록 바로 아래에 추가하세요.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version
	)

	Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version

}

ValidateSet 속성의 괄호 안에 항목 세트(12)를 추가함으로써 PowerShell에게 Version에 유효한 값은 1 또는 2뿐이라는 것을 알립니다. 사용자가 세트에 있는 값 이외의 값을 전달하려고 할 경우, 아래에 표시된 오류 메시지를 받게 되며, 이 메시지에서는 사용자에게 제한된 옵션만 사용 가능하다는 내용을 알려줍니다.

Parameter validation stopping PowerShell function execution

ValidateSet 속성은 일반적인 유효성 검사 속성이지만, 다른 유효성 검사 속성도 사용할 수 있습니다. 매개변수 값이 제한될 수 있는 모든 방법을 자세히 알아보려면 Microsoft 문서를 참조하십시오.

파이프라인 입력 받기

지금까지 일반적인 -ParameterName <Value> 구문을 사용하여 전달할 수 있는 매개변수가 있는 함수를 만들었습니다. 이 방법은 작동하지만 PowerShell 파이프라인을 사용하여 매개변수에 값을 전달할 수도 있습니다. Install-Software 함수에 파이프라인 기능을 추가해 보겠습니다.

관련 정보: ATA PowerShell 매개변수 기사에서 파이프라인 입력 받기

먼저 코드에 다른 매개변수를 추가하여 소프트웨어를 설치할 컴퓨터를 지정하십시오. 또한 Write-Host 참조에도 해당 매개변수를 추가하여 설치를 시뮬레이션하십시오.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[string]$Version
		[ValidateSet('1','2')],
		
		[Parameter(Mandatory)]
		[string]$ComputerName
	)

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

함수에 ComputerName 매개변수를 추가한 후, 아래와 같이 컴퓨터 이름과 버전의 값을 Install-Software 함수에 전달하여 컴퓨터 이름 목록을 반복할 수 있습니다.

$computers = @("SRV1", "SRV2", "SRV3")
foreach ($pc in $computers) {
	Install-Software -Version 2 -ComputerName $pc
}

이 모든 작업 대신에, 대신에 파이프라인을 사용하는 방법을 배워야 합니다.

함수 파이프라인 호환성 구현하기

이전에 작성한 간단한 함수로는 PowerShell 파이프라인의 이점을 활용할 수 없습니다. 함수가 어떤 유형의 파이프라인 입력을 받아들일지 결정하고 구현해야 합니다.

A PowerShell function uses two kinds of pipeline input: ByValue (entire object) and ByPropertyName (a single object property). Here, because the $computers array contains only strings, you’ll pass those strings via ByValue.

파이프라인 지원을 추가하려면 아래와 같이 원하는 매개변수에 매개변수 속성을 추가하면 됩니다. 두 개의 키워드 중 하나인 ValueFromPipeline 또는 ValueFromPipelineByPropertyName를 사용하십시오.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

		[Parameter(Mandatory, ValueFromPipeline)]
		[string]$ComputerName
	)

	Write-Host "I installed software version $Version on $ComputerName. Yippee!"

}

업데이트된 Install-Software 함수를로드한 후 다음과 같이 호출하십시오.

$computers = @("SRV1", "SRV2", "SRV3")
$computers | Install-Software -Version 2

스크립트를 다시 실행하면 다음과 같은 결과를 얻을 수 있습니다.

I installed software version 2 on SRV3. Yippee!

Install-Software이 배열의 마지막 문자열에 대해서만 실행됨을 알 수 있습니다. 이 문제를 다음 섹션에서 해결하는 방법을 알아보겠습니다.

process 블록 추가하기

모든 객체에 대해 PowerShell에이 함수를 실행하도록 지시하려면 process 블록을 포함해야합니다. 프로세스 블록 내부에는 함수가 파이프 라인 입력을받을 때마다 실행하려는 코드를 넣으십시오. 아래에 표시된대로 스크립트에 process 블록을 추가하십시오.

function Install-Software {
	param(
		[Parameter(Mandatory)]
		[ValidateSet('1','2')]
		[string]$Version,

		[Parameter(Mandatory, ValueFromPipeline)]
		[string]$ComputerName
	)

	process {
		Write-Host "I installed software version $Version on $ComputerName. Yippee!"
	}
}

이제 이전과 마찬가지로 함수를 호출하십시오. Install-Software 함수는 이제 세 줄을 반환합니다 (객체당 하나).

I installed software version 2 on SRV1. Yippee!
I installed software version 2 on SRV2. Yippee!
I installed software version 2 on SRV3. Yippee!

process 블록에는 실행하려는 주 코드가 포함됩니다. 또한 함수 호출 시 시작 및 끝에 실행되는 코드에는 begin 및 end 블록을 사용할 수 있습니다. Microsoft 문서를 통해 begin, process 및 end 블록에 대해 더 자세히 알아볼 수 있습니다.

다음 단계

함수를 사용하면 코드를 개별적인 빌딩 블록으로 구성할 수 있습니다. 이를 통해 작업을 더 작고 관리 가능한 청크로 분할하는뿐만 아니라 가독성이 높고 테스트 가능한 코드를 작성하도록 강제 할 수 있습니다.

I now challenge you to look through some old scripts and see where you can add a PowerShell function. Look for patterns in code. Build a function from those patterns. Notice where you’re copying/pasting code snippets and turn those into PowerShell functions!

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