Windows PowerShell진행률 보고서

Don Jones

최근에 꽤 길고 복잡한 Windows PowerShell 스크립트를 작성했는데, 이 스크립트는 실행될 때 상당히 오랫동안 응답하지 않습니다. 예약된 작업으로 실행되도록 이 스크립트를 작성했기 때문에 출력의 대부분이 시각적인 방식으로는 제공되지 않습니다. 처음으로 큰 테스트를 위해 실행했을 때 필자는 실수로 무한 루프를

작성했거나 다른 문제가 있는지 걱정하지 않을 수 없었습니다.

셸에 작은 커서만 깜박이고 있으므로 스크립트가 중지되었는지 여부를 알 수가 없었습니다. 스크립트를 중단하기 위해 Ctrl+C를 재빨리 눌렀기 때문에 겉으로 보기에는 확신할 수 없었던 것입니다. 이런 문제를 해결하려면 진행률 보고 기능을 추가해야 합니다.

들어가는 말

필자는 먼저 스크립트가 수행하는 작업에 대해 정확하게 알 수 있도록 상태 메시지를 추가하려고 했습니다. 셸을 통해 Write-Verbose cmdlet을 사용하면 이 작업을 비교적 쉽게 수행할 수 있습니다. 이제 셸에서 직접 실습해 보겠습니다.

Write-Verbose "Test Message"

이렇게 해보면 아무 작업도 수행되지 않은 것을 알 수 있습니다. Write-Verbose는 기본적으로 출력을 표시하지 않는 특수 Verbose 파이프라인으로 개체를 전송하기 때문입니다. 기본 제공 셸 변수인 $VerbosePreference가 이 파이프라인을 제어합니다. 이 변수의 기본값은 자세한 정보가 출력되지 않도록 하는 SilentlyContinue입니다. 하지만 값을 Continue로 설정하면 파이프라인이 열립니다.

$VerbosePreference = "Continue"

이제 스크립트에 Write-Verbose 문을 여러 개 추가하여 스크립트가 실행될 때 그 진행 과정을 자세히 볼 수 있습니다. 이 방법은 테스트 및 문제 해결을 완료한 경우 스크립트 시작 부분에서 $VerbosePreference를 다시 SilentlyContinue로 설정하여 추가적인 메시지가 더 이상 표시되지 않도록 할 수 있다는 점에서 유용합니다.

즉, Write-Verbose 문을 모두 제거할 필요가 없습니다. 실제로 이 문은 스크립트에 남아 있기 때문에 스크립트를 수동으로 실행해야 할 경우 필요에 따라 Verbose 파이프라인을 손쉽게 다시 설정할 수 있습니다.

실제 진행률이 필요한 경우

스크립트가 무한 루프에 빠진 것이 아니며 완벽하게 작동한다는 것을 확인한 후 필자는 확실히 하기 위해 Verbose 파이프라인을 해제하고 다시 실행했습니다.

여기서 문제는 스크립트가 정상적으로 작동한다는 것은 알고 있지만 아무런 메시지 없이 커서만 깜박인다는 점입니다. 필자는 인내심이 그리 많지 않아서 무작정 기다리는 것을 좋아하지 않습니다.

즉, 스크립트가 얼마나 진행되었으며 언제 완료될지를 알 필요가 있었습니다. 기본적으로 진행률 표시줄과 같은 기능이 필요합니다.

다행히 Windows PowerShellTM에는 Write-Progress cmdlet이 포함되어 있습니다. 이 cmdlet은 Windows®에서 볼 수 있는 그래픽 진행률 표시줄을 제공하지는 않지만 그림 1과 같은 훌륭한 진행률 표시줄을 제공합니다. 이것은 Windows Server® 2003 또는 Windows XP의 텍스트 기반 설치 부분에 사용되는 파일 복사 진행률 표시줄과 비슷합니다.

그림 1 스크립트의 진행률

그림 1** 스크립트의 진행률 **(더 크게 보려면 이미지를 클릭하십시오.)

Write-Progress를 사용하려면 약간의 설명이 필요합니다. 예를 들어서 설명하면 이해가 더 빠르겠지요. 다음 스크립트를 예로 들겠습니다.

for ($a=1; $a -lt 100; $a++) {
  Write-Progress -Activity "Working..." `
   -PercentComplete $a -CurrentOperation
   "$a% complete" `
   -Status "Please wait."
  Start-Sleep 1
}

이 스크립트는 Write-Progress를 사용하여 진행률 표시줄을 표시합니다. Start-Sleep을 사용하여 루프를 통과할 때마다 스크립트를 1초 동안 일시 중지하여 진행률을 볼 수 있을 정도로 느리게 실행합니다. 일시 중지하지 않으면 루프는 0부터 100까지 너무 빠르게 카운트를 실행하기 때문에 진행률 표시줄이 화면에서 잠깐 깜박이는 형태로만 표시됩니다.

여기서 볼 수 있듯이, Working으로 설정한 Activity가 진행률 표시줄의 맨 위에 표시됩니다. Status는 바로 아래에 표시되고 CurrentOperation은 맨 밑에 표시됩니다. 셸에서는 한 번에 하나의 진행률 표시줄만 사용할 수 있습니다. Write-Progress를 사용하면 현재 진행률 표시줄이 표시되지 않은 경우 하나를 새로 만들고 현재 진행률 표시줄이 표시된 경우 이를 업데이트합니다.

여기서는 작업이 완료되면 진행률 표시줄이 사라지도록 하는 명령을 지정하지 않았습니다. 완료된 경우 진행률 표시줄이 사라지도록 하려면 스크립트 끝 부분에 다음을 추가하면 됩니다.

Write-Progress -Activity "Working..." `
 -Completed -Status "All done."

일반적으로 진행률 표시줄은 스크립트가 완료되면 자동으로 사라지지만, 스크립트에서 수행할 다른 작업이 있다면 해당 진행률 표시줄과 관련된 작업이 완료될 때 이를 숨겨야 합니다. 이 경우 -Completed 매개 변수를 사용하면 진행률 표시줄이 제거됩니다.

남은 시간

Write-Progress의 또 다른 일반적인 용도는 실제 진행률 표시줄이 아니라 "남은 시간(초)" 표시를 만드는 것입니다. 다음은 이 작업에 대한 예입니다.

for ($a=100; $a -gt 1; $a--) {
  Write-Progress -Activity "Working..." `
   -SecondsRemaining $a -CurrentOperation
   "$a% complete" `
   -Status "Please wait."
  Start-Sleep 1
}

여기에서는 100에서 1까지 카운트다운을 실행하도록 루프를 변경하고 PercentComplete 대신 Write-Progress의 SecondsRemaining 매개 변수를 사용했습니다. 그림 2에서 그 결과를 볼 수 있습니다. 그림에서 볼 수 있듯이 진행률 표시가 사라지고 대신 카운트다운 시계가 나타납니다. 셸은 초 단위의 총 남은 시간을 자동으로 시, 분, 초로 변환하여 사용자에게 더 익숙한 정보를 제공합니다. 여기에 표시된 완료율은 필자가 제공한 CurrentOperation 매개 변수이므로 실제로 100부터 카운트다운을 실행합니다. 완료율이 실제로 계산되는 것은 아닙니다. Windows PowerShell에서는 "% complete" 문자열 앞에 단순히 $a의 현재 값을 표시합니다.

그림 2 스크립트 완료까지 남은 시간

그림 2** 스크립트 완료까지 남은 시간 **(더 크게 보려면 이미지를 클릭하십시오.)

진행 정보를 제공하는 스크립트

필자는 수행할 작업에 대해 알려 주도록 스크립트를 작성하는 것을 선호합니다. 자세한 정보를 출력하는 형태를 사용하거나 간단히 진행률 표시줄을 사용할 수도 있습니다. 이러한 방식은 필자처럼 인내심이 부족한 사람을 위한 것일 수도 있고 필자의 스크립트를 실행해야 하는 사람에게 필요할 수도 있습니다. 어떠한 형태로든 상태 및 진행률 정보를 표시하면 많은 이점을 얻게 됩니다.

이달의 Cmdlet: Tee-Object

이번 달에는 필자가 자주 사용하는 문제 해결 cmdlet 중 하나를 살펴보겠습니다. 다음 코드를 예로 들어 보겠습니다.

Get-WMIObject Win32_Service | Where { $_.State -ne "Running"
-and $_.StartMode -eq "Automatic" } | ForEach-Object { $_.Start() }

이 코드는 자동으로 시작되도록 설정되었지만 어떤 이유에서든 아직 시작되지 않은 모든 서비스를 시작하기 위한 것입니다. 그러나 코드는 실제로 작동하지 않으며 파이프라인 속을 들여다볼 수 없기 때문에 작동하지 않는 이유를 찾는 것이 까다로울 수 있습니다. 즉, Tee-Object를 사용하지 않으면 내부를 들여다볼 수 없습니다.

Tee-Object는 개체를 파일로(또는 변수로) 리디렉션하고 이를 파이프라인으로 전달합니다. 예를 들면 다음과 같습니다.

Get-WMIObject Win32_Service | Tee-Object AllServices.csv | Where 
{ $_.State -ne "Running" -and $_.StartMode -eq "Automatic" } | 
Tee-Object FilteredServices.csv | ForEach-Object { $_.Start() }

이렇게 수정하면 각 파이프라인 명령 뒤에 무엇이 수행되는지 알 수 있으며, 이를 통해 FilteredServices.csv 파일에 아무것도 포함되어 있지 않은 것을 곧 발견하게 됩니다. 당연하게도 이 스크립트는 작동하지 않았습니다. 조금 더 조사해 보면 문제의 근본 원인은 StartMode가 "Automatic"이 아니라 "Auto"이기 때문임을 알 수 있습니다. Tee-Object를 통해 문제가 발생한 정확한 위치를 알 수 있습니다.

Don JonesTechNet Magazine의 객원 편집자이자 Windows PowerShell: TFM(SAPIEN Press, 2007)의 공동 저자입니다. Windows PowerShell 강사(www.ScriptingTraining.com 참조)이기도 한 그는 웹 사이트 ScriptingAnswers.com을 통해 연락할 수 있습니다.

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