Windows PowerShell간단한 명령, 강력한 관리

Don Jones

이 칼럼은 Windows PowerShell의 시험판 버전을 기준으로 작성되었습니다. 이 문서에 수록된 모든 정보는 변경될 수 있습니다.

오랜 기다림 끝에 드디어 Windows PowerShell이 출시를 기다리고 있습니다. 이제 Windows 관리자에게 이 소식을 전할 때가 된 것입니다. Windows PowerShell은 다양한 관리 작업을 자동화하여 효과적이고도 효율적으로 작업을 수행할 수 있는 가장 쉽고 유연한 방법을 제공합니다.

그리고 무엇보다도 중요한 사실은 Microsoft에서 Windows PowerShell™을 기반으로 하여 Exchange Server 2007 및 System Center 2007과 같은 제품의 그래픽 관리 콘솔을 만들고 있다는 것입니다. 이 말은 곧 Windows PowerShell 내에서 대부분의 관리 작업을 수행할 수 있게 된다는 것을 뜻합니다. Microsoft에서는 앞으로 더 많은 제품의 관리 기능에 대해 같은 작업을 진행해 나갈 계획입니다. 결국 Windows PowerShell은 거의 모든 Microsoft 서버 제품의 관리 작업에 사용할 수 있는 첫 번째 통합 관리 도구가 될 것입니다. 이 새 칼럼에서는 정기적으로 Windows PowerShell에 대해 설명함으로써 여러분이 Windows PowerShell에 친숙해질 수 있도록 지원하려고 합니다. Windows PowerShell 소프트웨어 사본을 다운로드하십시오.

강력함과 단순함

이름에서 알 수 있듯이 Windows PowerShell은 Windows NT® 3.1부터 있었던 명령 프롬프트(Cmd.exe)와 비슷한 셸입니다. Cmd.exe는 그대로 유지되지만 Windows PowerShell이 있기 때문에 이젠 사용할 이유가 거의 없습니다.

Windows PowerShell은 Cmd.exe와 비슷한 점이 많지만 Windows PowerShell이 훨씬 강력합니다. Cmd.exe와 마찬가지로 Windows PowerShell에도 기본 제공 스크립트 언어가 있지만 Cmd.exe의 기본 배치 언어에 비해 유연성이 훨씬 큽니다. 얼마나 유연하냐구요? Windows PowerShell에서는 대여섯 개의 기본 제공 키워드만으로 구성된 언어를 사용하여 매우 복잡한 작업을 자동화할 수 있습니다.

지금까지는 스크립트에 대한 이야기였지만 보안에 대해서도 이야기해 보지요. Windows PowerShell에는 지난 10여 년 동안 쌓아온 Microsoft의 보안 관련 경험이 녹아 있습니다. 기본적으로 Windows PowerShell은 스크립트를 실행하지 않으며 개별 명령을 대화식으로만 실행할 수 있습니다. 스크립트 기능을 활성화한 경우에는 Windows PowerShell에서 디지털 서명된 스크립트만 실행하도록 지정할 수 있습니다. 이 모든 것은 Windows PowerShell이, 우수한 언어이기는 하지만 악의적인 스크립트를 만드는 데 많이 활용되고 있는 VBScript의 전철을 밟지 않도록 하기 위한 것입니다. 앞으로도 VBScript를 계속 사용할 수 있기는 하지만 그보다는 Windows PowerShell이 다양한 작업에 활용하기 쉬운 도구라는 것을 알게 될 것입니다.

Cmd.exe로 수행했던 거의 모든 작업은 Windows PowerShell로도 수행할 수 있습니다. 예를 들어 ipconfig를 실행하여 동일한 결과물을 얻을 수 있습니다. 그러나 Windows PowerShell은 외부 실행 파일이 아닌 완전히 새로운 명령인 cmdlet을 지원합니다. 이러한 cmdlet은 "커맨드 렛"이라고 읽으며 Windows PowerShell 내부에 구현되어 있습니다. Windows PowerShell을 시작할 때 가장 유용하게 사용할 수 있는 cmdlet을 보려면 화면 옆쪽의 "바로 사용할 수 있는 유용한 10가지 cmdlet"을 참조하십시오.

바로 사용할 수 있는 유용한 10가지 cmdlet

  • Get-Command는 사용 가능한 모든 cmdlet을 검색합니다.
  • Get-Help는 cmdlet 및 개념에 대한 도움말 정보를 표시합니다.
  • Get-WMIObject는 WMI를 사용하여 관리 정보를 검색합니다.
  • Get-EventLog는 Windows 이벤트 로그를 검색합니다.
  • Get-Process는 단일 활성 프로세스 또는 활성 프로세스 목록을 검색합니다.
  • Get-Service는 Windows 서비스를 검색합니다.
  • Get-Content는 텍스트 파일을 읽고, 각 줄을 자식 개체로 취급합니다.
  • Add-Content는 텍스트 파일에 내용을 추가합니다.
  • Copy-Item은 파일, 폴더 및 기타 개체를 복사합니다.
  • Get-Acl은 ACL(액세스 제어 목록)을 검색합니다.

Windows PowerShell에서 제공되는 전체 cmdlet 목록을 보려면 windowssdk.msdn.microsoft.com/en-us/library/ms714408.aspx를 참조하십시오.

모든 cmdlet은 동사-명사 형식의 표준 이름을 갖기 때문에 쉽게 알아보고 기억할 수 있습니다. 예를 들어 Get-Command cmdlet을 실행하면 사용할 수 있는 모든 cmdlet이 나열됩니다. 관리자에게 가장 유용한 cmdlet은 아마도 Get-WMIObject일 것입니다. Server2에서 실행되고 있는 서비스 팩을 알고 싶으면 다음과 같이 명령을 실행하면 됩니다.

Get-WMIObject Win32_OperatingSystem –Property ServicePackMajorVersion
 –Computer Server2

VBScript를 사용하여 이 같은 정보를 검색하려면 여러 줄의 코드를 작성해야 합니다. 다른 cmdlet 또한 서비스(Start-Service, Stop-Service 등), 프로세스(Stop-Process 등), 파일(Rename-Item, Copy-Item, Remove-Item, Move-Item 등) 및 여러 가지 작업에 사용할 수 있습니다. 이 중 많은 cmdlet은 별칭이라는 바로 가기 이름을 가집니다. Get-WMIObject는 gwmi라고만 입력해도 됩니다. Get-Alias를 실행하면 이러한 바로 가기 이름을 보여 주는 목록이 표시됩니다.

개체 지향이 중요한 이유

Microsoft® .NET Framework를 기반으로 하는 Windows PowerShell은 완전히 개체 지향적입니다. 일반적으로 개체 지향이라고 하면 소프트웨어 개발자만 좋아하지만 이 경우에는 관리자도 개체 지향 특성으로 인해 많은 시간을 절약할 수 있습니다. 왜냐하면 관리자가 텍스트 기반 셸 내에서 다양한 개체와 관련된 작업을 직접 수행할 수 있기 때문입니다. 다음 예를 살펴보겠습니다.

Get-Process | Sort-Object pm –desc | Select-Object –first 10

이 예에서는 파이프(나중에 자세히 설명함)로 구분된 세 개의 다른 cmdlet이 한 줄에 들어 있습니다. 첫 번째 cmdlet은 실행 중인 모든 프로세스를 검색한 다음 검색된 개체를 파이프를 통해 Sort-Object에 전달합니다. 이 두 번째 cmdlet은 각 프로세스 개체의 pm(실제 메모리라는 의미) 속성을 정렬하여 내림차순으로 배치합니다. 정렬된 프로세스 개체 컬렉션은 파이프를 통해 처음 10개의 개체를 선택해서 표시하는 Select-Object에 전달됩니다. 결과는 무엇일까요? 이 간단한 코드의 결과로 그림 1에서 보듯이 시스템에서 실제 메모리를 가장 많이 사용하는 상위 10개 구성 요소가 표시됩니다. 이 방법은 문제 해결을 위해 빠르게 상황을 검토할 수 있는 매우 효율적인 방법입니다.

그림 1 간단한 cmdlet으로 문제 해결

그림 1** 간단한 cmdlet으로 문제 해결 **(더 크게 보려면 이미지를 클릭하십시오.)

Windows PowerShell을 효과적으로 사용하기 위해서는 파이프(일반적으로 키보드의 백슬래시 키에 있는 세로 줄 문자)를 반드시 사용해야 합니다. 이 문자를 사용하면 한 cmdlet에서 다른 cmdlet에 개체를 전달하여 결과 값을 조정하거나, 결과의 표시 형식을 지정하는 등의 작업을 수행할 수 있습니다. 이 메커니즘은 모든 cmdlet이 일반 텍스트 대신 개체를 반환하므로, 이후의 cmdlet이 온전한 개체를 가지고 작업을 수행할 수 있기 때문에 가능합니다.

Windows PowerShell에서는 변수에도 개체 개념이 적용될 정도로 개체의 사용이 광범위합니다. 또한 변수를 미리 선언할 필요 없이 변수 이름 앞에 달러 기호($)를 넣고 사용하면 됩니다. 반드시 필요한 것은 아니지만 변수에 넣을 데이터 형식을 Windows PowerShell에 알려 줄 수도 있습니다. 이렇게 하면 Windows PowerShell에서 해당 변수가 매우 강력한 .NET Framework 형식 중 하나에 매핑되기 때문에 여러 가지 추가적인 기본 기능을 사용할 수 있습니다. 예를 들어 컴퓨터 이름을 입력 받아 해당 컴퓨터의 서비스 팩 버전을 검색하려는 경우, 컴퓨터 이름을 입력하는 사용자가 두 개의 백슬래시(예: \\Server2)를 포함할 수 있습니다. 그러나 Get-WMIObject cmdlet의 경우 백슬래시가 필요하지 않기 때문에 다음과 같이 컴퓨터 이름을 String 변수에 저장한 다음 Replace 메서드를 사용하여 백슬래시를 빈 문자열로 바꿀 수 있습니다.

[string]$c = Read-Host "Enter computer name"
$c = $c.Replace("\","")
    Get-WMIObject Win32_OperatingSystem
    –Property  ServicePackMajorVersion
    –Computer $c

–Computer 매개 변수에 대한 값은 $c 변수에 지정되어 있습니다. 이 변수는 처음부터 문자열로 만들어졌기 때문에 Replace 메서드를 포함한 .NET Framework String 형식의 모든 기능을 사용할 수 있습니다. 물론 이 모든 기능을 배우려면 많은 시간이 걸리겠지만 예를 이용하면 쉽게 배울 수 있습니다. Windows PowerShell 자체에서도 쉽게 배울 수 있는 방법이 제공됩니다. 예를 들어 $c = $c.(마침표에 주의)를 입력하고 Tab 키를 누르면 Windows PowerShell에 String 형식의 첫 번째 메서드인 Clone()이 표시됩니다. Tab 키를 계속 누르고 있으면 사용할 수 있는 모든 메서드가 차례로 표시됩니다. 이 방법을 통해 String으로 수행할 수 있는 작업에 대한 모든 정보를 볼 수 있습니다.

간단한 작업을 예로 들어 보겠습니다. 파일에서 한 줄에 하나의 이름이 들어 있는 컴퓨터 이름 목록을 읽은 다음 각 컴퓨터의 서비스 팩 번호를 표시하는 작업을 수행하려면 VBScript에서는 10줄 이상의 코드가 필요하고, cmd.exe에서는 복잡한 배치 파일을 사용해야 하지만 Windows PowerShell에서는 단 한 줄만으로 이 작업을 수행할 수 있습니다.

Get-Content "c:\computers.txt" | foreach  
{ $_; gwmi Win32_OperatingSystem -prop 
ServicePackMajorVersion -comp $_ }

Get-Content cmdlet은 C:\Computers.txt의 내용을 읽습니다. 파일의 각 줄은 자체 권한으로 개체가 됩니다. 이 개체, 즉 컴퓨터 이름 컬렉션은 파일을 통해 ForEach-Object cmdlet의 별칭인 foreach 명령에 전달됩니다. 중괄호 내의 명령이 파이프를 통해 전달된 각 개체에 대해 한 번씩 실행됩니다. 이 예에서는 각 컴퓨터 이름에 대해 한 번씩 명령이 실행됩니다. 특수 $_ 변수에 현재 개체(현재 컴퓨터 이름)가 포함됩니다.

중괄호 내에는 실제로 두 개의 명령이 있습니다. 첫 번째 명령은 단순히 $_의 내용을 출력하여 현재 컴퓨터 이름을 표시합니다. 두 번째 명령은 앞에서 살펴보았던 gwmi입니다. 이렇게 해서 파일에 나열된 모든 컴퓨터의 서비스 팩 버전 목록을 얻을 수 있습니다. 이 모든 작업이 한 줄로 된 비교적 간단한 명령으로 완료되었습니다.

–Property 및 –Computer 매개 변수 이름에는 약어가 사용되었습니다. Windows PowerShell에서는 매개 변수 이름을 고유하게 구별할 수만 있으면 됩니다.

가독성 및 재사용

그러나 모든 명령과 매개 변수를 한 줄로 작성하면 가독성이 떨어집니다. Windows PowerShell에서는 가독성을 높일 수 있도록 여러 줄로 나누어서 입력할 수 있기 때문에 스크립트를 작성하지 않고 셸에 직접 입력할 수 있습니다. 다음 예를 살펴보겠습니다.

PS C:\> $names = get-content "c:\computers.txt"
PS C:\> foreach ($name in $names) {
>> $name
>> gwmi Win32_OperatingSystem -prop ServicePackMajorVersion -comp $name
>> }
>>

이 예에서는 파일의 내용이 변수 $names에 저장됩니다. 이 예에서도 foreach가 사용되기는 하지만 파이프라인을 통해 입력되지 않기 때문에 ($name in $names)처럼 루프의 실행 대상이 되는 개체의 컬렉션과 각 개체를 저장할 변수를 지정해야 합니다. 나머지 부분은 모두 동일하며 이제 Enter 키를 누르면 코드가 실행되어 결과가 표시됩니다.

이 코드를 반복해서 사용하려는 경우 이 코드를 함수로 만들 수 있습니다. 다시 한번 이 코드를 셸에 직접 입력합니다.

PS C:\> function Get-ServicePacks ($file) {
>> $names = get-content $file
>> foreach ($name in $names) {
>> $name
>> gwmi win32_operatingsystem -prop servicepackmajorversion -comp $name
>> }
>> }
>>

위에서 볼 수 있는 것처럼 실제로 변경된 부분이 많지 않습니다. 이 코드는 이전 예를 Get-ServicePacks(Windows PowerShell 동사-명사 명명 규칙에 따름)라는 함수로 묶었을 뿐입니다. 이 함수에서는 함수를 실행할 때 다른 파일을 지정할 수 있도록 이전 예의 Get-Content cmdlet 대신 $file이라는 입력 매개 변수를 사용했습니다. 이제 함수를 정의했으므로 cmdlet을 호출하는 것과 동일한 방식으로 함수의 이름을 호출하여 실행하고 입력 매개 변수를 전달합니다.

PS C:\> Get-ServicePacks c:\computers.txt

그림 2에서는 실행 결과를 보여 줍니다.

이 함수는 Windows PowerShell 인스턴스가 실행 중인 동안에만 존재한다는 단점을 갖고 있습니다. 셸을 닫으면 함수가 제거됩니다. Windows PowerShell이 시작될 때마다 실행되는 자동 실행 스크립트의 일종인 Windows PowerShell 프로필에 함수를 복사할 수 있습니다. 이렇게 하면 열려 있는 모든 Windows PowerShell 창에서 함수를 사용할 수 있습니다. 원하는 경우에는 함수를 독립형 스크립트로 만들어서 스크립트의 경로와 파일 이름을 입력하는 것만으로도 함수를 실행할 수 있습니다.

그림 2 Get-ServicePacks 함수의 실행 결과

그림 2** Get-ServicePacks 함수의 실행 결과 **

파일(또는 폴더)로 구성된 세상

Windows PowerShell에는 함수와 cmdlet 외에도 많은 것이 있습니다. 다른 기능의 간단한 예로, 파일 관리에 대해 살펴보겠습니다. Cmd.exe에서 C:를 입력하여 C 드라이브로 전환한 다음 cd \test를 입력하여 C:\Test 폴더로 이동하는 방식으로 드라이브와 폴더를 탐색하는 방법을 많이 사용해 왔을 것입니다. Windows PowerShell에서도 이와 동일한 방법으로 탐색 작업을 수행할 수 있습니다. Windows PowerShell에서는 cd가 Set-Location cmdlet의 별칭입니다.

사용할 수 있는 모든 드라이브를 나열하는 cmdlet인 Get-PSDrive를 실행합니다. 일반적으로 볼 수 있는 C:, D: 및 A: 드라이브뿐만 아니라 Cert, Env, HKCU 및 HKLM이라는 여러 가지 이름이 표시됩니다. Windows PowerShell에서는 실제로 다양한 유형의 저장소 자원이 "드라이브"로 표시되기 때문에 로컬 인증서 저장소, 환경 변수 및 레지스트리를 익숙한 파일 형식의 탐색 인터페이스를 통해 사용할 수 있습니다.

Set-Location HKLM: (약어를 좋아하는 경우 cd hklm:)을 입력하고 Enter 키를 눌러 HKEY_LOCAL_MACHINE 레지스트리 하이브로 이동합니다. 그런 다음 cd software\microsoft를 실행하여 SOFTWARE\Microsoft 키로 이동합니다. Get-ChildItem cmdlet의 별칭인 dir을 사용하여 레지스트리의 이 부분에 있는 하위 키를 나열할 수 있습니다. 키를 제거하려는 경우 파일이나 폴더를 제거하듯이 del을 사용하여 키를 제거합니다. 필수 키를 제거하거나 레지스트리를 잘못 수정할 경우 심각한 문제가 발생할 수 있으므로 신중해야 합니다.

이와 같은 유연성은 모두 레지스트리 및 인증서 저장소와 같은 자원을 파일 시스템과 비슷한 형식으로 매핑하는 공급자가 제공하는 것입니다. Microsoft는 추가 공급자를 통해 Windows PowerShell을 확장할 계획으로, Exchange Server 저장소를 파일 시스템처럼 탐색하는 등의 기능을 제공하려고 합니다. 이 기술은 Windows에 사용되는 다양한 저장소를 동일한 형태로 표시할 수 있고 이미 익숙해져 있는 명령 시스템과 기술을 사용하여 관리할 수 있다는 점에 매우 중요한 의미를 갖습니다.

안전성을 고려한 설계

이미 언급했듯이 Windows PowerShell은 보안과 안전성을 고려하여 설계되었습니다. Windows PowerShell의 기본 보안 기능은 실행 정책입니다. 기본적으로 이 정책은 "Restricted"로 설정되며, Get-ExecutionPolicy cmdlet을 실행하여 확인할 수 있습니다. Restricted 모드에서는 스크립트가 실행되지 않습니다. 이 모드가 기본 모드이므로 Windows PowerShell은 기본적으로 스크립트를 실행하는 데 사용할 수 없습니다.

Set-ExecutionPolicy cmdlet을 사용하여 다른 모드를 지정할 수 있습니다. 개인적으로 RemoteSigned 모드를 권장합니다. 이 모드에서는 디지털 서명 없이 로컬 스크립트(원격 스크립트는 해당되지 않음)를 실행할 수 있으므로 가장 손쉽게 스크립트를 개발하고 테스트할 수 있습니다. AllSigned 모드에서는 신뢰할 수 있는 게시자가 발행한 인증서를 사용하여 디지털 서명된 스크립트만 실행할 수 있습니다. 마지막으로 Unrestricted 정책에서는 모든 스크립트가 실행됩니다. 이 정책을 적용하면 Windows PowerShell에서 악의적인 스크립트가 자유롭게 실행되어 컴퓨터에 손상을 줄 수 있으므로 이 정책은 사용하지 않는 것이 좋습니다. 실행 정책은 로컬 정책에 우선하는 그룹 정책을 통해서도 제어할 수 있습니다. 그룹 정책 설정이 로컬 설정에 우선하는 경우 Set-ExecutionPolicy가 경고 메시지를 표시합니다.

또한 Windows PowerShell에서는 사용자가 경로를 지정하지 않은 경우 현재 디렉터리에서 스크립트가 실행되지 않습니다. 이것은 명령 하이재킹을 막기 위한 것입니다. 누군가가 IPConfig.ps1(PS1은 Windows PowerShell 스크립트 파일의 확장명임)이라는 스크립트를 만들었다고 가정합시다. 이러한 파일을 현재 폴더에서 실행할 수 있다면 Windows 프로그램인 Ipconfig.exe를 실행하기 위해 ipconfig를 입력했을 때 이 사용자가 만든 스크립트가 실행되는 위험이 존재합니다. Windows PowerShell에서는 스크립트가 현재 폴더에서 실행되지 않기 때문에 이러한 실수가 발생할 수 없습니다. 스크립트를 현재 폴더에서 실행하려면 .\myscript와 같이 경로를 지정하면 됩니다. 현재 폴더에 대한 명시적 참조는 셸 명령이 아닌 스크립트의 실행을 보장합니다.

또한 Windows PowerShell은 보다 안전한 실험 방법을 제공합니다. 예를 들어 다음과 같은 예를 살펴보겠습니다. 이 코드는 절대 실행하지 마십시오.

Get-Process | Stop-Process

Get-Process cmdlet은 프로세스 개체 컬렉션을 만들며, 이 컬렉션은 파이프를 통해 Stop-Process cmdlet에 전달되어 해당 프로세스가 실제로 중지됩니다. 결과적으로 중요한 Windows 프로세스가 종료되면서 약 5초 후에 블루 스크린 중지 오류가 발생합니다. 하지만 이러한 cmdlet을 실제로 실행하지 않고서도 다음과 같이 -Whatif 매개 변수를 추가하면 발생하는 작업을 매우 쉽게 확인할 수 있습니다.

Get-process | Stop-Process -Whatif

Windows PowerShell에서 이 코드를 실행할 때 cmdlet이 실제로 실행되지는 않지만 cmdlet으로 인해 수행되는 내용이 표시됩니다. 별칭 help를 사용하여 액세스할 수 있는 Windows PowerShell의 온라인 도움말 시스템에는 -Whatif 매개 변수에 대한 설명이 아직까지 포함되어 있지 않지만 기억해 두시기 바랍니다. 이 매개 변수는 스크립트와 cmdlet을 실제로 실행하지 않고 테스트를 통해 결과를 확인할 수 있기 때문에 잠재적 위험이나 손상을 걱정하지 않아도 되는 유용한 도구입니다.

결론

이 Windows PowerShell 버전에서 다루지 않은 기능 중에서 가장 중요한 기능은 ADSI(Active Directory® Services Interface)에 대한 지원일 것입니다. Windows PowerShell에는 Active Directory 및 다른 디렉터리 서비스와 함께 사용할 수 있는 매우 강력한 .NET 클래스가 있기는 하지만 편리한 Get-ADSIObject cmdlet이 아직 없기 때문에 디렉터리 개체 작업이 약간 어렵습니다.

또한 Windows PowerShell은 동일한 작업을 수행할 수 있는 매우 다양한 방법을 제공합니다. 좋은 일이기는 하지만 특정 작업에 대해 5-6개의 다른 예를 통해 작동 방법을 익혀야 하기 때문에 Windows PowerShell을 배우는 데 약간의 혼란을 느낄 수 있습니다.

이 모든 것은 시간이 지남에 따라 해결될 것이며 Windows PowerShell 팀은 지속적으로 제품에 기능을 추가해 나갈 것입니다. 이 같은 정보를 지속적으로 확인하고 싶으면 Windows PowerShell 팀의 블로그(영문)를 참조하십시오.

Don JonesScriptingAnswers.com의 창립자이자 Windows PowerShell: TFM(SAPIEN Press, 2006)의 공동 저자입니다. 문의 사항이 있으시면 don@scriptinganswers.com으로 연락하십시오.

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