Windows PowerShellWindows PowerShell 구문

Don Jones

지난 달에는 스크립트를 실제로 작성하지 않고 Windows PowerShell을 직접 사용하여 관리 작업을 처리하는 몇 가지 방법에 대해 살펴보았습니다. 그러나 Windows PowerShell은 뛰어난 대화형 셸이기 때문에 강력하면서도 단순한 스크립트 언어를 사용함으로써 기능을 보다 적절히 활용하고 복잡한 작업을 자동화할 수 있습니다.

무엇보다도 먼저 Microsoft에서 다른 스크립트 언어를 정말로 필요로 하는지 생각해 보십시오. Microsoft는 로그온 스크립트 프로세서인 KiXtart와 Visual Basic® Scripting Edition(VBScript)을 제공합니다. 그럼에도 불구하고 대답은 예입니다. Microsoft에서는 다른 스크립트 언어가 정말로 필요했습니다. 지금부터 그 이유를 설명하겠습니다.

관리자가 많은 교육을 받지 않고도 사용할 수 있도록 하기 위해 Windows PowerShell™ 언어는 간단하면서도 직관적이어야 했습니다. 또한 Windows PowerShell 자체의 모든 강력한 기능을 사용자에게 제공할 수 있기 위해서는 유연성이 매우 높아야 했습니다.

Windows PowerShell은 Microsoft® .NET Framework를 기반으로 하기 때문에 스크립트 구문이 .NET 친화적이어야 했습니다. Windows PowerShell 스크립트 언어를 어셈블하기 위해 설계자는 기본적으로 매우 간단한 C#(C 샵이라고 읽으며 .NET Framework와 함께 제공되는 언어 중 하나) 구문을 선택했습니다. 왜 VBScript 형태의 구문을 고수하지 않았을까요? Windows PowerShell 스크립트 언어는 실제로 VBScript와 완전히 다르지는 않지만 C# 구문에 보다 가까운 언어입니다. PowerShell은 .NET Framework 프로그래밍을 배우는 데 일종의 디딤돌로서의 역할을 합니다. 나중에 Visual Studio®를 사용하여 C# 응용 프로그램을 작성하게 되더라도 대부분의 Windows PowerShell 스크립트 구문을 활용할 수 있습니다.

Windows PowerShell 스크립트 언어 또는 모든 스크립트 언어에서 가장 중요하게 고려되는 요소 중 하나는 바로 구문입니다. 구문이란 Windows PowerShell에서 논리 비교를 수행하여 비교 결과에 따라 각기 다른 작업을 수행하거나 하나 이상의 명령을 반복해서 수행하는 데 필요한 특별한 언어 요소입니다.

논리적으로 생각하기

논리 비교는 많은 스크립트 언어 구문의 핵심이며, Windows PowerShell의 경우에도 예외는 아닙니다. 비교는 기본적으로 두 개의 값이나 개체를 확인하여 비교 결과가 True와 False 중 어느 것인지 평가합니다. 예를 들어 "이 사용자의 암호 만료 날짜가 오늘인가?"라는 질문의 결과는 오늘이 만료 날짜이면 True이고 그렇지 않으면 False일 것입니다. 여기에서 True와 False의 첫 번째 문자를 대문자로 쓴 이유는 이 용어들이 Windows PowerShell에서 특별한 의미를 갖고 있기 때문입니다.

다음은 Windows PowerShell에서 수행할 수 있는 실제 논리 비교의 예입니다.

PS C:\> $a = 1
PS C:\> $b = 2
PS C:\> $a -eq $b
False

$a라는 변수를 만들어 값을 1로 설정했습니다. Windows PowerShell에서는 변수 이름이 항상 달러 기호로 시작하기 때문에 쉽게 알아볼 수 있습니다. =는 값을 할당하는 데 사용되기 때문에 기술적으로 대입 연산자라고 합니다. 그런 다음 두 번째 변수 $b를 만들고 2라는 값을 할당했습니다. 마지막으로 실제 논리 비교가 수행됩니다. 즉, Windows PowerShell이 -eq(같음) 연산자를 사용하여 $a와 $b의 내용을 비교합니다. PowerShell은 비교를 수행하여 두 값이 같지 않은 것을 확인한 다음 False라는 결과를 표시합니다.

Windows PowerShell 연산자는 지금까지 다른 스크립트 언어에서 보던 연산자와 조금 다를 뿐만 아니라 C#과도 다릅니다. 대부분의 언어에서는 = 연산자가 값이 같은지 검사하거나 값을 대입하는 데 사용되지만 Windows PowerShell에서는 각 함수에 대한 전용 연산자를 사용하여 혼란을 줄였습니다. 그림 1에서는 Windows PowerShell 비교 연산자와 이미 알고 있는 다른 언어(예: VBScript)의 같음 연산자를 보여 줍니다.

Figure 1 PowerShell 비교 연산자

연산자 이름 설명
-eq 같음 값이 동일한지 테스트합니다. 다른 언어에서는 = 또는 ==를 사용하여 값이 동일한지 테스트합니다.
-ne 같지 않음 값이 같지 않은지 테스트합니다. 다른 언어에서는 <> 또는 !=를 사용하여 값이 같지 않은지 테스트합니다.
-gt 보다 큼 한 값이 다른 값보다 큰지 테스트합니다. 다른 언어에서는 > 문자를 사용합니다.
-lt 보다 작음 한 값이 다른 값보다 작은지 테스트합니다. 다른 언어에서는 < 문자를 사용합니다.
-ge 크거나 같음 한 값이 다른 값보다 크거나 같은지 테스트합니다. VBScript 및 다른 언어의 >=와 비슷합니다.
-le 작거나 같음 한 값이 다른 값보다 작거나 같은지 테스트합니다. VBScript 및 다른 언어의 <=와 비슷합니다.

이러한 비교 연산자에는 또 다른 흥미로운 특징이 있습니다. 다음 비교를 살펴봅시다.

PS C:\> $a = "TechNet"
PS C:\> $b = "technet"
PS C:\> $a -eq $b
True

기본적으로 비교 연산자는 대/소문자를 구분하지 않습니다. 즉, 대문자가 포함된 TechNet이 "technet"과 같다고 인식합니다. 대부분의 관리 작업에서는 대/소문자를 구분할 필요가 없기 때문에 편리한 방법입니다. 그러나 필요한 경우에는 비교 연산자 앞에 문자 c를 추가하여 대/소문자를 구분하는 비교를 수행할 수 있습니다.

PS C:\> $a -ceq $b
False

마찬가지로 Windows PowerShell이 비교 작업에서 대/소문자를 구분하는지 여부가 혼동될 경우에는 문자 i를 앞에 추가하여 대/소문자를 구분하지 않도록 할 수 있습니다.

PS C:\> $a -ieq $b
True

논리 비교의 결과는 항상 True와 False 중 하나라는 것을 기억하십시오.

결정

지금까지 논리 비교를 작성하는 방법을 배웠으므로 이제 논리 비교를 구문에 사용할 수 있습니다. 첫 번째 구문에서는 Windows PowerShell에서 비교 결과에 따라 결정을 내리는 방법을 보여 줍니다. 이 구문에서는 If 구문이 호출되며, 여기에는 몇 가지 변형이 있습니다. 다음은 가장 간단한 예입니다.

PS C:\> if ($a -eq $b) {
>> Write-Host "They are equal"
>> }
>>
They are equal

여기에는 몇 가지 흥미로운 점이 있습니다. 먼저 변수 $a와 $b에는 "TechNet"과 "technet"이라는 값이 여전히 들어 있으며 If 키워드를 사용하여 구문을 시작했습니다. 그런 다음 수행하려는 논리 비교를 괄호 안에 입력했습니다. 괄호 뒤에 호출하게 될 조건 코드의 시작을 뜻하는 중괄호를 입력했습니다. 이 경우 조건 코드는 비교 연산에서 반환된 결과가 True일 때 실행됩니다. 앞의 예제에서 보았듯이 이 비교 연산은 True를 반환하므로 조건 코드가 실행될 것으로 예상할 수 있습니다. Write-Host "They are equal"을 조건 코드로 입력하고 Enter 키를 누릅니다. 마지막으로 닫는 중괄호를 입력하여 조건 코드 섹션을 완료하고 Enter 키를 두 번 누릅니다. 빈 줄에 입력되는 두 번째 Enter 키를 통해 파서는 코드 작성이 완료되었다는 것을 인식하고 코드 실행을 준비합니다.

이 구문은 스크립트 파일에서 실행하고 있는 것이 아닙니다. 이 구문은 단순히 Windows PowerShell 명령줄에 입력한 것입니다. 이 기능은 Windows PowerShell을 다른 Windows 스크립트 언어와 차별화하는 요소로, 스크립트를 대화형으로 작성할 수 있을 뿐만 아니라 영구적인 저장을 위해 파일로 저장할 수도 있습니다.

여는 중괄호를 입력하고 Enter 키를 누르면 바로 Windows PowerShell에 >> 프롬프트가 표시됩니다. 이 프롬프트의 의미는 "구문이 시작되었으므로 구문에 넣을 내용을 입력하십시오."라는 뜻입니다. 닫는 중괄호를 입력하고 Enter 키를 두 번 누른 즉시 Windows PowerShell은 구문을 실행하여 논리 비교가 True임을 확인하고 조건 코드를 실행합니다. PowerShell이 정상 프롬프트로 돌아오기 전에 "They are equal"이 표시되는 것을 보고 조건 코드가 실행되었음을 알 수 있습니다. Windows PowerShell을 사용하여 대화형으로 스크립트를 작성하면 코드를 영구적인 스크립트로 어셈블하기 전에 빠르게 테스트할 수 있기 때문에 배우기도 쉽고 디버깅도 쉽게 수행할 수 있습니다.

Windows PowerShell은 Enter 키를 누르는 것에 대해 특별히 까다롭지 않습니다. 예를 들어 다음 코드는 앞의 예제와 동일하게 작동합니다.

PS C:\> if ($a -eq $b) { Write-Host "They are equal" }
They are equal

이 경우에는 한 줄에 모든 내용을 입력했기 때문에 Windows PowerShell에서 >> 프롬프트를 표시하지 않으며 줄의 끝에서 Enter 키를 누를 때 구문이 바로 실행됩니다. Windows PowerShell은 구문을 실행해도 좋다는 것을 어떻게 알 수 있을까요? 그것은 바로 닫는 중괄호가 입력되는 순간에 구문이 완료되기 때문입니다.

필자는 앞에서 If 구문의 변형에 대해 언급했었습니다. 다음은 셸 대신 PS1 스크립트 파일에 사용된 전체 예제입니다.

if ($a -eq $b) {
  Write-Host "They are equal"
} elseif ($a -lt $b) {
  Write Host "One is less than the other"
} else {
  Write Host "One is greater than the other"
}

이 구문도 마찬가지로 If 키워드로 시작됩니다. 그러나 비교 결과가 False인 경우를 위해 Elseif 키워드를 사용하여 다른 비교를 추가했습니다. 두 번째 비교 결과도 False이면 마지막 키워드 Else가 마지막으로 실행될 코드 집합을 제공합니다.

반복

Windows PowerShell에는 비교 결과가 True나 False가 될 때까지 반복해서 코드를 실행할 수 있는 여러 구문이 있습니다. 프로그래머는 이러한 구문을 루프 구문이라고 합니다. 또한 가장 유용한 루프 구문 중 하나는 컬렉션의 개체를 열거하고 한 줄 이상의 코드를 각 개체에 대해 실행할 수 있는 기능을 제공합니다. 이 구문이 바로 foreach 구문이며, 다음과 같이 사용됩니다.

PS C:\> $names = get-content "c:\computers.txt"
PS C:\> foreach ($name in $names) {
>> Write-Host $name
>> }
>>
don-pc
testbed

먼저 Windows PowerShell Get-Content cmdlet을 실행하여 c:\computers.txt 파일의 내용을 검색합니다. 이 파일은 저자가 직접 만든 파일로 각 줄에 하나의 컴퓨터 이름이 들어 있습니다. Windows PowerShell에서는 각 줄이 하나의 개체로 취급되므로 파일은 기본적으로 그러한 개체의 모음입니다. 이 개체 모음이 $names 변수에 할당됩니다. Foreach 키워드를 사용하여 $names 모음을 열거하도록 지정하고, 루프가 실행될 때마다 현재 개체를 나타내기 위해 $name 변수를 사용합니다. 루프 코드는 중괄호 안쪽으로 진행됩니다. 이제 파일에 있는 각 이름을 명령줄에 출력합니다. 알고 있는 바대로 구문 뒤에 표시된 출력은 Windows PowerShell에 의해 수행된 작업입니다. 이 기능을 통해 관리 스크립트 작업에서 얻을 수 있는 장점을 확실히 알 수 있을 것입니다. 예를 들어 서버 이름 목록을 작성한 다음 Windows PowerShell에서 각 서버 이름을 순서대로 검색할 수 있습니다.

실제 구문

이제 논리 비교, If 구문 및 foreach 구문을 사용하여 유용한 작업을 수행해 보겠습니다. 일련의 서버에 있는 Messenger 서비스의 상태를 빠르게 확인하려는 경우를 예로 들어 보겠습니다. 대부분의 서버에서 서비스가 중지되어 있을 것으로 생각되므로 서비스가 중지된 서버를 모두 나열하는 것보다는, Messenger 서비스가 실제로 시작된 서버에 대해 작업을 수행해야 하므로 이러한 서버만을 나열하려고 합니다.

Windows PowerShell Get-Service cmdlet을 사용하면 필요한 로컬 컴퓨터 정보를 검색할 수 있지만 불행히도 우리가 목표로 하는 원격 컴퓨터의 정보는 검색할 수 없습니다. 그러나 다행스럽게도 원격 컴퓨터와의 통신을 지원하는 Get-WMIObject cmdlet을 사용하여 WMI(Windows Management Instrumentation)를 통해 이 정보에 액세스할 수 있습니다. 다음 스크립트에서 이 작업을 수행합니다.

$names = get-content c:\computers.txt
foreach ($name in $names) {
  $svc = get-wmiobject win32_service '
   -computer $name -filter "name='messenger'"
  if ($svc.started -eq $True ) {
    write-host "$name has Messenger running"
  }
}

세 번째 줄에 있는 ' 문자가 보이십니까? 이 문자는 다음 줄이 연결되는 줄이라는 것을 나타냅니다. 이 기능은 줄바꿈을 하지 않으면 전체 줄을 Magazine에 표시하기 힘든 지금과 같은 경우에 유용합니다. 또한 If 구문에서 $svc.started와 $True가 비교됩니다. $True 변수는 Windows PowerShell에서 부울 값 True를 나타내는 특수 변수입니다. 마찬가지로 $False 변수는 부울 값 False를 나타냅니다. 실제로 간단하게 작업을 수행할 수 있었습니다.

$names = get-content c:\computers.txt
foreach ($name in $names) {
  $svc = get-wmiobject win32_service '
   -computer $name -filter "name='messenger'"
  if ($svc.started) {
    write-host "$name has Messenger running"
  }
}

If 구문의 조건은 True와 False 중 하나여야 한다는 것을 기억하십시오. 이 스크립트의 첫 번째 버전에서 설명한 것처럼 일반적으로 두 값을 비교하면 True나 False가 반환됩니다. 그러나 Started 속성의 값은 True나 False이기 때문에 True나 False를 실제로 비교할 필요가 없습니다.

유용한 도구

이제 구문을 사용해서 작업을 수행할 수 있는 간단하고 유용한 관리 도구가 완성되었습니다. Windows PowerShell에서 대화형으로 구문을 입력하든지 아니면 손쉬운 재사용을 위해 구문을 PS1 파일로 저장하든지 이 도구는 다양한 컴퓨터에서 실행되고 있는 서비스의 상태를 확인할 수 있는 간편한 도구이며, 구문을 사용하여 관리 작업을 자동화하는 방법을 보여 주는 훌륭한 데모입니다.

Don Jones는 SAPIEN Technologies의 프로젝트 및 서비스 담당 이사이자 Windows PowerShell: TFM(SAPIEN Press, 2006)의 공동 저자입니다. 문의 사항이 있으면 ScriptingAnswers.com으로 연락하십시오.

© 2008 Microsoft Corporation 및 CMP Media, LLC. All rights reserved. 이 문서의 전부 또는 일부를 무단으로 복제하는 행위는 금지됩니다..