Windows PowerShell드롭 상자

Don Jones

목차

Cmdlet가 되어 보기
필터링 함수
실제 물체를 통해 생각해 보기
실제 응용 프로그램
시연해 보기

필자가 최근에 진행한 Windows PowerShell 강좌에서 일부 학생들은 셸 파이프라인의 모든 항목을 머릿속으로 그려보는 데 어려움을 겪었습니다.파이프라인은 전혀 간단한 개념이 아니기 때문에 파이프라인이 어떤 식으로 전개되는지 정확하게 그려보는 것이 학생들에게는 매우 어려울 수 있습니다.파이프라인에서 직접 작동하는 필터링 함수에

대한 개념을 설명할 때 이 내용이 정말 어려운 것이었음을 몇몇 학생들이 짓고 있던 난감한 표정에서 읽을 수 있었습니다.

어려워하는 학생들의 이해를 돕기 위해 다음 날 상자 하나, 몇 개의 이름표 스티커와 탁구공을 가지고 다시 설명했습니다.물론 Windows PowerShell®이 재미있겠느냐고 말하는 사람은 아무도 없었습니다만다음 명령줄을 통해 시연해 보기로 했습니다.

Get-Process | Where { $_.VM –gt 1000 } | Sort VM
–descending | Export-CSV C:\Procs.csv

Cmdlet가 되어 보기

여러분도 알다시피 학교 동창회나 이와 비슷한 큰 규모의 행사에서 항상 착용하는 "안녕하세요. 제 이름은 ...입니다."와 같은 이름표 스티커를 사용하여 각 학생에게 cmdlet 이름을 나눠 주었습니다.탁구공이 Windows® 프로세스 개체(더 구체적으로 말하자면 System.Diagnostics.Process 형식의 개체)를 나타낸다고 설명한 다음 학생들에게 프로세스 개체를 생성할 수 있는 것으로 보이는 cmdlet 이름을 얘기해 보도록 했습니다.

학생들은 서로가 가진 이름표를 둘러본 후 망설임 없이 Get-Process를 선택했습니다.이것이 필자가 Windows PowerShell에 cmdlet 이름을 사용하기 좋아하는 주된 이유 중 하나입니다.즉, 이름은 해당 성격을 바로 나타내기 때문입니다.

따라서 Get-Process를 맡은 학생이 모든 탁구공을 주워 상자에 넣었습니다.상자는 셸의 파이프라인을 나타내고 학생이 수행한 작업이 바로 cmdlet에서 수행하는 작업입니다.즉, cmdlet는 하나 이상의 개체를 생성한 다음 파이프라인에 넣습니다.

그러면 파이프라인의 다음 cmdlet가 그 다음 작업을 수행합니다.이 예제에서는 Where-Object cmdlet 이름표를 받은 학생이 탁구공을 모두 집어 들어 한 번에 하나씩 각 탁구공의 VM 속성이 1,000보다 큰지 확인했습니다.셸에서 "VM"은 가상 메모리를 나타냅니다. 이 실습을 위해 필자는 각 탁구공에 다양한 가상 메모리 크기를 마커로 적어 두었습니다.

VM이 1,000 이상인 모든 공(프로세스)은 다시 상자(파이프라인)에 넣고 VM 값이 그보다 낮은 나머지 공은 다시 볼 수 없도록 쓰레기통에 버렸습니다.솔직히 말하자면 실제로 공을 버린 것은 아니고 다음 수업 시간에 다시 사용했습니다.

그런 다음 Sort-Object를 맡은 학생이 상자에 담긴 탁구공을 해당 VM 속성을 기준으로 순서대로 배치했습니다.사실 이 작업은 제대로 계획하지 못한 실습 중 하나였습니다. 공이 이곳저곳으로 굴러다니지 않도록 하는 데는 약간 문제가 있었습니다.따라서 다음 수업에는 탁구공 역할을 할 주사위를 준비하거나 달걀 상자 몇 개를 바로 쓸 수 있도록 준비해 둬야겠습니다.

마지막으로 Export-CSV 역할을 맡은 학생이 공을 집어 들고 CSV 파일에 해당 정보를 적었습니다.실제로는 프로세스 속성을 플립 차트에 기록했고 이 플립 차트를 CSV 파일이라고 가정했습니다.

필터링 함수

다음으로 간단한 파이프라인을 통해 좀 더 복잡한 필터링 함수를 살펴보기로 했습니다.그림 1에 표시된 필터링 함수와 명령줄을 예로 들었습니다.

그림 1 필터링 함수 및 명령줄 예제

Function Do-Something {
 BEGIN { }
 PROCESS {
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty "TimeStamp" (Get-Date)
  $obj | Add-Member NoteProperty "ProcessName" ($_.Name)
  Write-Output $obj
 }
 END {}
}
Get-Process | Do-Something | Format-Table *

우선 필터링 함수가 수행하는 작업이 무엇인지 간단히 설명하겠습니다.핵심은 이 함수에는 BEGIN, PROCESS, END라는 세 가지 스크립트 블록이 있다는 것입니다.

BEGIN 스크립트 블록은 파이프라인에서 함수가 사용될 때 처음 실행되며데이터베이스 연결 열기와 같은 설정 작업을 수행할 수 있습니다.

그런 다음 PROCESS 스크립트 블록이 파이프라인을 통해 함수로 전달된 개체마다 한 번씩 실행됩니다.PROCESS 스크립트 블록 내에서 $_ 변수는 현재 파이프라인 개체로 자동으로 채워집니다.따라서 10개의 개체가 파이프라인을 통해 전달되면 PROCESS 스크립트 블록이 10번 실행됩니다.

마지막으로 파이프라인을 통해 전달된 개체가 모두 실행되면 END 스크립트 블록이 실행되어 데이터베이스 연결 닫기와 같은 필요한 정리 작업을 수행합니다.

이러한 스크립트 블록 내에서 Write-Output을 사용하여 작성된 모든 항목은 다음 cmdlet를 위해 파이프라인에 저장됩니다.Write-Output을 통해 작성되지 않은 항목은 모두 삭제됩니다.

이 예제에서 명령은 Get-Process로 시작되므로 Get-Process를 맡은 학생이 강의실 여기저기에 굴러다니고 있던 모든 탁구공을 찾아서 파이프라인 상자에 넣을 동안 우리는 잠시 기다리게 되었습니다.작업을 마친 후에는 "Do-Something" 필터링 함수를 맡은 학생이 작업을 이어서 수행했습니다.

이 학생은 먼저 BEGIN 스크립트 블록을 실행했습니다.비어 있으므로 특별히 수행할 작업이 없었습니다.그 다음 모든 탁구공(파이프라인 개체)을 주워 한 번에 하나씩 살펴보았습니다.공이 약 12개였는데 이 학생이 모든 공을 무릎 위에 놓으려고 애쓰는 모습이 조금 우스꽝스러웠습니다. 여러분이 그 광경을 보았어야 했는데요.

어쨌든 한 번에 하나씩 프로세스 개체를 주은 다음 PROCESS 스크립트 블록을 실행했습니다.즉, PROCESS 스크립트 블록을 통해 새 사용자 지정 개체를 만들었습니다.필자는 특별히 노란색 탁구공을 사용자 지정 개체로 사용했으며 노란색 탁구공은 가까운 스포츠 용품 가게에서 쉽게 구할 수 있었습니다.이러한 새 탁구공에 현재 살펴보고 있는 프로세스 개체의 이름과 함께 현재 날짜와 시간을 기록했습니다.

그런 다음 이 새로운 사용자 지정 개체를 파이프라인에 기록했습니다. 즉, 노란색 탁구공을 상자에 넣은 것입니다. 원래 프로세스 개체를 나타내는 탁구공은 버렸습니다.상자에 있는 약 12개의 각 프로세스 개체를 나타내는 탁구공에 대해 이 작업을 수행했습니다.이 작업을 통해 모든 흰색 탁구공이 노란색 탁구공(사용자 지정 개체)으로 교체되었습니다.마지막으로 END 스크립트 블록을 실행했습니다. 이 스크립트 블록은 비어 있으므로 아무런 작업도 수행하지 않았습니다.

마무리를 위해 Format-Table을 맡은 학생이 다음 작업을 수행했습니다.이 학생은 상자에 있는 모든 탁구공(노란색 "사용자 지정" 개체)을 꺼낸 후 각 공에 적힌 속성을 이용하여 표를 만들었습니다.그 결과 플립 차트에 TimeStamp와 ProcessName이라는 두 개의 열과 약 12개의 행이 있는 표가 그려졌습니다.

실제 물체를 통해 생각해 보기

이 실습은 강좌를 듣는 모든 학생들이 파이프라인 및 필터링 함수를 제대로 이해할 수 있도록 진행되었습니다.탁구공은 셸에 대해서만 설명하는 경우 다소 추상적인 개념으로 느껴질 수 있는 개체를 나타내는 데 정말 효과적이었습니다.

모든 학생들은 cmdlet가 이러한 개체를 처리하는 방법, 파이프라인에서 결과가 저장되는 방법 및 다음 cmdlet가 이러한 결과를 선택하여 이후 개체를 처리하는 방법을 파악할 수 있었습니다.필터링 함수의 이벤트 시퀀스는 PROCESS 스크립트 블록이 한 번에 하나의 입력을 처리하는 방법이라는 점에서 보다 파악하기 쉬웠습니다.

여기서는 또한 새 사용자 지정 개체를 만들어 파이프라인에 저장하는 방법에 대해서도 직접 시연해 보였습니다.이러한 실습은 새 사용자 지정 개체가 Format-Table과 같은 다른 cmdlet에서 사용될 수 있으므로 보다 유연한 방식으로 데이터를 사용하거나 나타낼 수 있다는 단순한 설명과는 달리 사용자 지정 개체를 만듦으로써 얻을 수 있는 이점을 구체적으로 설명하는 데도 도움이 되었습니다.

실제 응용 프로그램

학생들이 궁금해 하는 주된 질문은 파이프라인 및 우리가 시연해 본 이러한 필터링 함수를 실제 응용 프로그램에서 어떻게 사용할 수 있는지에 대한 것이었습니다.최근 컨퍼런스 세션에 사용하기 위해 몇 가지 예제를 만들어 두었기 때문에 이에 대해 답해 주는 것은 쉬운 일이었습니다. 이러한 예제는 scriptinganswers.com/essentials/index.php/2008/03/25/techmentor-2008-san-francisco-auditing-examples에서 다운로드할 수 있습니다.

이 중 한 가지 예제는 여러 컴퓨터의 WMI(Windows Management Instrumentation)에 포함된 Win32_UserAccount 클래스에서 여러 속성을 나열하기 위한 것입니다.컴퓨터 이름이 C:\Computers.txt에 표시되어 있다고 가정할 경우 다음과 같은 간단한 명령으로 이 작업을 수행할 수 있습니다.

Gwmi win32_useraccount –comp (gc c:\computers.txt)

문제는 어떤 컴퓨터에서 각 인스턴스가 생성되었는지 나타내는 속성이 Win32_UserAccount 클래스에는 없다는 것입니다. 즉, 결과 목록은 여러 컴퓨터의 계정을 두서없이 표시하므로 유용하지 않습니다.필자는 원본 컴퓨터 이름을 포함하고 필자가 필요로 하는 클래스 속성을 선택하는 새 사용자 지정 개체를 만들어 이 문제를 해결했습니다. 이 사용자 지정 개체에 대한 코드는 그림 2에 나와 있습니다.

그림 2 사용자 지정 개체를 사용하여 컴퓨터 이름을 수집하고 속성 선택

function Get-UserInventory {
  PROCESS {
    # $_ is a computer name
    $users = gwmi win32_useraccount -ComputerName $_
    foreach ($user in $users) {
      $obj = New-Object
      $obj | Add-Member NoteProperty Computer $_
      $obj | Add-Member NotePropertyPasswordExpires ($user.PasswordExpires)
      $obj | Add-Member NoteProperty Disabled ($user.Disabled)
      $obj | Add-Member NotePropertyFullName ($user.FullName)
      $obj | Add-Member NoteProperty Lockout ($user.Lockout)
      $obj | Add-Member NoteProperty Name ($user.Name)
      $obj | Add-Member NotePropertyPasswordRequired ($user.PasswordRequired)
      $obj | Add-Member NotePropertyPasswordChangeable ($user.PasswordChangeable)
    }
  }
}

Get-Content c:\computers.txt | 
  Get-UserInventory | 
  where { $_.PasswordRequired -eq $False } | 
  selectComputer,Name | 
  Export-Csv c:\BasUsersBad.csv

마지막 명령줄에서는 사용자 지정 개체를 생성하는 필터링 함수에 모든 컴퓨터 이름을 전달합니다.다음으로 PasswordRequired 속성이 False인 사용자를 제외한 모든 사용자를 필터링했습니다. 이 방법은 문제가 발생한 계정에 대한 감사 보고서를 만들기 위한 것입니다.그런 다음 Computer 및 Name 속성을 유지하기만 하면 됩니다. 그러면 만료되지 않는 암호를 사용하므로 주의가 필요한 계정 이름과 컴퓨터 이름이 수록된 최종 보고서를 얻을 수 있습니다.필터링 함수를 사용하면 확인할 속성만 선택하는 과정에서 원본 컴퓨터 이름을 출력에 추가할 수 있으므로 이러한 여러 컴퓨터에 대한 보고서를 얻을 수 있습니다.

이 작업을 수행할 수 있는 다른 유사한 방법이 여럿 있지만 이 방법이 가장 간단할 것입니다.또한 중요한 개념과 기술을 파악하기에도 좋습니다.

시연해 보기

파이프라인에 대해 잘 안다 하더라도 여기에는 한 가지 더 배울 점이 있습니다.실제 물체를 대입하여 생각해 보면 수행하고자 하는 것이 무엇인지 쉽게 파악할 수 있습니다.

따라서 이후에 Windows PowerShell 개념을 익히는 데 어려움을 겪게 되면 컴퓨터에서 바로 작업하기 보다는 일상 생활에서 사용하는 물체를 통해 작업을 시연해 보는 것이 도움이 될 수 있습니다.이를 위해서는 탁구공(또는 구할 수 있는 경우 주사위)을 넣은 작은 가방을 언제든지 이용할 수 있도록 준비해 두는 것이 좋습니다.

이달의 Cmdlet:Out-File

> 기호를 사용하여 cmdlet 출력을 파일에 연결한 적이 얼마나 됩니까?이것은 Get-Process > Processes.txt와 같습니다.여러분은 외면만 약간 바뀐 Out-File cmdlet를 사용하고 있다는 것을 알고 있습니까?정확한 함수를 수행하는 명령은 다음과 같습니다.Get-Process | Out-File Processes.txt.

물론 여기에는 입력 작업이 약간 더 필요하지만 전체 Out-File cmdlet를 입력해야 하는 이유는 무엇일까요?한 가지 이유는 Out-File을 입력한 경우 이를 읽을 때 그 의미를 더 명확하게 이해할 수 있기 때문입니다.6개월 후에 누군가가 여러분이 작성한 스크립트 중 하나를 살펴보고 > 기호가 무엇을 의미하는지 궁금해 할 수도 있습니다. 결국 이것은 여러분이 설명해야 할 일이 됩니다.

그와 반대로 Out-File에서는 파일이 매우 명확한 방식으로 생성되고 작성됩니다.또한 Out-File에서는 -force 및 -noClobber 매개 변수와 함께 -append 매개 변수(>> 기호와 매우 유사함)를 사용할 수 있으므로 기존 파일을 덮어쓸지 여부를 제어할 수 있습니다.마지막으로 Out-File을 입력하면 -whatif 매개 변수도 사용할 수 있습니다.이 유용한 매개 변수는 Out-File의 작업 결과를 실제 수행 없이 보여 줍니다.위험을 최소한으로 줄이면서 복잡한 명령줄을 테스트할 수 있는 최고의 방법이지 않습니까?

Don JonesWindows PowerShell:TFM의 공동 저자이며 Windows PowerShell 강좌(www.ScriptingTraining.com)를 진행하고 있습니다.

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