Hey, Scripting Guy!무덤에서 일어난 데스크톱 관리
Microsoft Scripting Guys
이 기사의 코드 다운로드: HeyScriptingGuy2007_09.exe (151KB)
압도적인 대중의 요구에 따라 우리는 이번 달에는 좀 색다른 일을 할 수 있겠다고 생각했습니다. 시스템 관리 스크립팅에 관한 논의 대신 - 음산한 음악 넣어주시고 - 귀신 이야기로 시작해보고자 합니다.
참고로, 그래요. 물론 굳이 말하자면 이번 달에 우리가 진짜로 좀 다르게 해보겠다면 평소와 달리 진지하게 실제 시스템 관리 스크립팅에 관한 설명으로 들어가야겠지만, 그냥 평소 하던 대로 가는 게 낫겠죠? 감사합니다!
오랜 옛날, 스크립팅계의 몇 대조뻘 되는 할머니께서 타계하셨습니다. 할머니가 검소한 목관에 안치된 직후부터 할아버지는 사랑스러운 아내가 무덤 밖으로 나오려고 필사적으로 애쓰는 끔찍한 악몽에 시달리게 되었습니다. 반복되는 악몽과 여러 번의 탄원을 거쳐 할아버지는 마침내 지역 관계 당국에 시신 발굴을 설득시켰습니다. 관을 열어 본 사람들은 할머니의 손톱이 뒤쪽으로 구부러져 있고 관 안쪽이 온통 할퀸 자국으로 덮여 있는 것을 보고 오싹해졌습니다!
그렇습니다. 이 이야기는 완전한 사실이 아닐 수도 있습니다. 사실 생각하면 할수록 사실에 가까운 부분이 거의 없다는 것을 알 수 있습니다. 그럼에도 불구하고 이 이야기는 중요한 교훈을 담고 있습니다. 그 내용은 잘 모르겠는데 이 이야기 어딘가에는 그 교훈이 있습니다.
잠깐, 이제 기억이 나네요! 관은 본디 자연 작용으로부터 고인을 보호하고 시신의 부패를 방지하기 위해 만들어진 것입니다. 그러나 공교롭게도 관은 의도하지 않은 결과를 초래하였습니다. 적어도 이론적으로는 사람을 산 채로 묻어서 절대 빠져나오지 못하게 할 수도 있는 것입니다. 스크립팅계 몇 대조 할머니의 이야기가 확실히 보여주듯이, 신이 아닌 이상 아무리 잘 짜여진 계획이라도 생매장처럼 의도하지 않은 사태를 낳을 수 있다는 것입니다(음산한 음악 한 번 더).
참고로, 1860년대에 Franz Vester가 고안안 개량식 관(Improved Burial Case)을 택할 수도 있겠습니다. 이 관에는 끈이 하나 들어 있는데 이 끈은 땅 위의 벨에 연결되어 있어서 혹시나 생매장이 이루어졌을 경우 '망자'가 벨을 울려 도움을 청할 수 있게 되어 있습니다. 이 개량식 관에는 접이식 사다리도 들어 있었는데, 땅 아래로 6피트 깊이에 묻혀 있는 관에서 탈출하는 데 접이식 사다리가 어떻게 도움이 될 것인지는 저희도 잘 모르겠습니다. 만일 누군가의 차고 위에 묻히게 된다면 접이식 사다리가 도움이 될 수도 있겠지만, 그게 아니라면....
이와 똑같은 교훈, 그러니까 아무리 잘 짜여진 계획도 의도하지 않은 사태를 불러올 수 있다는 교훈은 인터넷 방화벽에서도 그대로 적용됩니다. 일반적으로, 방화벽은 원래 악의적 침입을 막기 위해 고안되었습니다. 방화벽은 네트워크 트래픽의 유입을 차단하여 해커와 침입자가 컴퓨터에 들어오는 것을 막는 데 도움이 됩니다. 그 자체로는 훌륭합니다. 그러나 생매장의 문제와 마찬가지로, 여기서도 의도하지 않은 결과가 발생합니다. 방화벽은 문제가 없는 트래픽도 차단합니다. 이것은 DCOM을 이용하여 원격 컴퓨터에서 관리 작업을 수행하는 WMI(Windows® Management Instrumentation)의 경우에 특히 두드러집니다. 방화벽은 유입되는 모든 DCOM 트래픽을 차단하기 때문에 컴퓨터를 인터넷을 통해 프로그램 방식으로 관리하는 것을 (완전히 불가능하지는 않더라도) 매우 어렵게 합니다. 사실 방화벽에서 추가로 포트를 열어 해커와 크래커의 공격에 더 취약한 상태가 되지 않고서는, 그것은 절대 불가능합니다. 물론, WinRM(Windows 원격 관리)(접이식 사다리는 없음)을 사용할 수 있습니다.
Windows 원격 관리(WinRM)란 무엇일까요?
WinRM SDK(msdn2.microsoft.com/aa384426)에 따르면 WinRM이란 "서로 다른 업체에서 제공한 운영 체제와 하드웨어의 호환을 가능케 하는 방화벽 친화적인 표준 SOAP 기반 프로토콜인 WS 관리 프로토콜을 Microsoft식으로 구현한 것"입니다. 멋있지 않습니까? 이번 달 칼럼에서는 WS 관리 프로토콜을 자세히 다루지 않을 것이므로 상세한 내용이 궁금하시면 WinRM SDK를 읽어보시기 바랍니다. 현재 우리가 관심을 갖는 것은 오로지, WinRM을 Windows Server® 2003 R2, Windows Vista®, Windows Server 2008에서 사용할 수 있다는 점, 그리고 그것이 인터넷을 통해 컴퓨터를 관리할 수 있게 한다는 점입니다. WinRM은 대부분의 방화벽에서 열어두는 표준 인터넷 서비스 포트인 포트 80을 이용해서 이러한 기능을 제공합니다. 그러나 WinRM에서 사용하는 포트와 기본 전송 메커니즘인 HTTP는 필요에 따라 변경할 수 있습니다.
이번 칼럼에서는 또한 WinRM의 설치와 구성 방법의 설명에도 시간을 들이지 않겠습니다. 그에 관해서는 이미 충분한 정보가 제공되어 있습니다(msdn2.microsoft.com/aa384372). 그러나 한 가지 중요한 사항은 잠시 강조하고 넘어가야겠습니다. WinRM을 이용하여 원격 컴퓨터에서 정보를 불러오려면(물론, 이것이 WinRM을 사용하는 가장 우선적인 이유임), 로컬 컴퓨터와 원격 컴퓨터 양쪽에서 WinRM이 실행되어야 합니다.
이것이 의미하는 바가 무엇일까요? 즉, 여러분이 아직 클라이언트 컴퓨터를 Windows Vista로 업그레이드하지 않았거나(그렇지 않다고 말해주세요!), 서버를 Windows Server 2003 R2 또는 Windows Server 2008로 업그레이드하지 않았다면 WinRM은, 최소한 현재까지는, 그다지 실용성이 없다는 것입니다. 그러나 말할 필요도 없이 앞으로는 그렇지 않을 것입니다. 그리고 물론, 방화벽에서 허용하는 것으로 가정한다면 언제든 WMI와 DCOM을 이용하여 원격 컴퓨터를 관리할 수 있습니다.
클래스의 모든 속성과 인스턴스의 반환
그러나 면책 조항을 누가 다 일일이 신경 쓰겠습니까? 알 수 없는 어려운 법률 용어들은 뒤로 하고, WinRM을 활용하는 스크립트의 작성 방법을 우리가 파악할 수 있는지만 살펴봅시다. 우연히도 때마침, HTTP 프로토콜과 포트 80을 사용하여 atl-fs-01.fabrikam.com이라는 컴퓨터에 접속한 다음, 그 컴퓨터에 설치된 모든 서비스에 대한 모든 정보를 반환하는 작고 간단한 스크립트를 갖게 되었다고 합시다. 그림 1에서 이 스크립트의 아름다운 면모를 감상할 수 있겠습니다.
Figure 1 Silverlight 프로젝트 구성 요소
파일 | 설명 |
CreateSilverlight.js | 사용자 인터페이스와 그래픽 개체의 구성에 사용되는 XAML 파일 등을 비롯하여, 초기 Silverlight 시작 설정을 지정하는 데 사용되는 JScript 스크립트(Silverlight 초기 릴리스에서는 JScript 스크립트만 지원)입니다. |
SampleProject.js | JScript 함수를 넣을 수 있는 빈 파일입니다. |
Silverlight.js | Silverlight 컨트롤을 초기화할 때 사용되는 파일입니다. |
SampleProject.html | 모든 효과가 이루어지는 곳입니다. SampleProject.html은 세 .js 파일에서 읽을 코드가 들어 있는 단순한 HTML 파일입니다. 또한 Silverlight 컨트롤을 인스턴스화하는 코드도 들어 있습니다. |
SampleProject.xaml | 이 파일은 어디에 사용될까요? 알고 싶다면 이 칼럼을 다시 읽어 보십시오. |
Figure 1 원격 컴퓨터의 서비스 목록 표시
strComputer = "atl-fs-01.fabrikam.com"
Set objWRM = CreateObject("WSMan.Automation")
Set objSession = objWRM.CreateSession("http://" & strComputer)
strResource = "https://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service"
Set objResponse = objSession.Enumerate(strResource)
Do Until objResponse.AtEndOfStream
DisplayOutput(objResponse.ReadItem)
Loop
Sub DisplayOutput(strWinRMXml)
Set xmlFile = CreateObject("MSXml2.DOMDocument.3.0")
Set xslFile = CreateObject("MSXml2.DOMDocument.3.0")
xmlFile.LoadXml(strWinRMXml)
xslFile.Load("WsmTxt.xsl")
Wscript.Echo xmlFile.TransformNode(xslFile)
End Sub
그림에서 알 수 있듯이 우선 컴퓨터의 DNS 이름(atl-fs-01.fabrikam.com)을 strComputer라는 변수에 할당하는 것부터 시작하겠습니다. 아니면 컴퓨터의 IP 주소를 사용해서 (또는 그 IPv6 주소를 사용해서라도) 연결을 구성할 수 있겠습니다. 예를 들면 다음과 같습니다.
strComputer = "192.168.1.1"
strComputer에 값을 할당한 후 WSMan.Automation 개체의 인스턴스를 만든 다음, CreateSession 메서드를 호출하여 원격 컴퓨터에 접속합니다. 이 경우에는 (우리가 그렇게 하겠다고 말한 것처럼) HTTP 프로토콜을 사용합니다.
Set objSession = objWRM.CreateSession _
("http://" & strComputer)
앞서 언급했듯이, 우리는 원격 컴퓨터에 설치된 서비스에 관한 정보를 반환하고자 합니다. 또한, 그리고 최소한 이 첫 번째 예에 대해서만큼은 모든 서비스의 모든 속성에 대한 정보를 반환하고자 합니다. 이것이 의미하는 바는 과연 무엇일까요? 그것은 원격 컴퓨터의 Win32_Service 클래스로 바인딩해주는 URI Resource를 명시해야 한다는 것을 의미합니다.
strResource = _
"https://schemas.microsoft.com" & _
"/wbem/wsman/1/wmi/root/cimv2" & _
"/Win32_Service"
인정합니다. 그리 보기 예쁜 URI는 아니지요. 하지만 생각해보면 예쁜 URI를 한 번이라도 본 적이 있는지 잘 모르겠군요. 그러나 다행히도 대부분의 URI는 항상 반복되는 동일한 내용으로 되어 있습니다. 맨 마지막의 WMI 경로만 신경 쓰시면 됩니다.
https://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service
무척 간단합니다. 그런데 root/cimv2/Win32_Process 클래스로 연결하고자 한다면 어떻게 해야 할까요? 그 때는 그에 맞게 URI 경로만 수정해주면 됩니다.
https://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process
root/default/SystemRestore 클래스에 관심이 있습니까? 그 경우에도 URI 클래스만 수정하면 되는데, 위의 cimv2 네임스페이스가 아닌 기본(default) 네임스페이스를 지정하도록 유의해야 합니다.
https://schemas.microsoft.com/wbem/wsman/1/wmi/root/default/SystemRestore
그리고 기타 등등... URI의 https://schemas.microsoft.com/wbem/wsman/1/wmi 부분도 넣어야 한다는 것이 다소 유감이지만 그러나,
이 지점에서 일부 데이터를 얻을 준비가 됩니다. 이를 위해서는 Enumerate 메서드를 호출, strResource 변수를 유일한 메서드 매개 변수로서 보내기만 하면 됩니다.
Set objResponse = _
objSession.Enumerate(strResource)
이 코드는 atl-fs-01 컴퓨터에 설치된 서비스에 대한 정보를 objResponse에 채우게 될까요? 물론입니다. 그러나 다른 표준 WMI 스크립트와 달리 각기 고유의 속성과 속성 메서드를 갖는 일련의 개체를 얻지 못합니다. 대신, 그림 2의 것과 유사한 거대한 XML 덩어리를 얻게 됩니다.
Figure 2 예쁜 색
<Canvas
xmlns="https://schemas.microsoft.com/client/2007"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Width="800"
Height="300">
<Canvas.Background>
<LinearGradientBrush>
<GradientStop Color="Blue" Offset="0.0" />
<GradientStop Color="Black" Offset="1.0" />
</LinearGradientBrush>
</Canvas.Background>
</Canvas>
Figure 2 거대한 XML 덩어리
<p:Win32_Service xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="
https://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service" xmlns:ci
m="http://schemas.dmtf.org/wbem/wscim/1/common" xsi:type="p:Win32_Service_Type"
xml:lang="en-US"><p:AcceptPause>false</p:AcceptPause><p:AcceptStop>false</p:Acce
ptStop><p:Caption>Windows Media Center Service Launcher</p:Caption><p:CheckPoint
>0</p:CheckPoint><p:CreationClassName>Win32_Service</p:CreationClassName><p:Desc
ription>Starts Windows Media Center Scheduler and Windows Media Center Receiver
services at startup if TV is enabled within Windows Media Center.</p:Description
><p:DesktopInteract>false</p:DesktopInteract><p:DisplayName>Windows Media Center
XML 전문가라면 그리 큰 문제는 아닙니다. XML에 익숙한 사람이라면 누구라도 큰 어려움 없이 이 정보를 구문 해석해서 결과를 출력할 수 있을 것입니다(그럼에도 불구하고, WinRM SDK의 표현을 빌리자면 이 정보는 '사람이 읽을 수 있는 형식'이 아님). 그런데 XML 전문가가 아닌 경우에는 어떻게 해야 할까요? 그 경우에는 두 가지 선택이 가능합니다. 첫째, 다음 달까지 기다리는 방법입니다. 다음 달에는 저희가 WinRM의 XML을 다루는 몇 가지 트릭을 알려드리겠습니다. 아니면 두 번째 방법으로, 저희가 샘플 스크립트에서 했던 것처럼 WinRM과 함께 설치되는 XSL 변환을 채택하는 것입니다.
XSL 변환이란?
XSL 변환은 XML 파일이 어떻게 표시되어야 하는가를 기술한 템플릿일 뿐입니다. XSL 파일에 대한 모든 내용을 다루려면 이 달 칼럼으로는 형편없이 부족합니다. 실제로, XSL 파일을 피상적으로만 다루려 해도 이 달 칼럼의 분량을 훨씬 넘어설 것입니다. 따라서 WsmTxt.xsl(기본 제공되는 변환의 이름)이 실제로 어떻게 작동하는지는 설명하지 않겠습니다. 대신, 스크립트에서 그 변환을 어떻게 사용할 수 있는지만 보여드리겠습니다.
Enumerate 메서드를 호출하면 WinRM에서는 XML 데이터 스트림을 돌려보냅니다. 이 데이터를 처리하는 가장 쉬운 방법은 데이터 스트림의 끝에 도달할 때까지 계속 실행되는 Do Until 루프를 설정하는 것입니다. 아래 저희가 한 것처럼 말입니다.
Do Until objResponse.AtEndOfStream
DisplayOutput(objResponse.ReadItem)
Loop
코드에서 볼 수 있듯이, 루프 내부에서 저희는 DisplayOutput이라는 서브루틴을 호출했습니다. 그 서브루틴을 호출할 때 그 스트림의 ReadItem 메서드의 값을 서브루틴 매개 변수로 하여 함께 보냅니다. 이 접근 방식 전체를 통해 알 수 있듯이 XML 스트림은 하나의 큰 데이터 덩어리가 아닌 여러 개로 나뉜 조각으로 반송됩니다. 그러면 우리의 스크립트는 이 XML 데이터를 한 번에 하나의 덩어리 또는 한 품목으로 읽어냅니다.
한편 DisplayOutput 서브루틴은 다음과 같은 형태를 갖습니다.
Sub DisplayOutput(strWinRMXml)
Set xmlFile = _
CreateObject("MSXml2.DOMDocument.3.0")
Set xslFile = _
CreateObject("MSXml2.DOMDocument.3.0")
xmlFile.LoadXml(strWinRMXml)
xslFile.Load("WsmTxt.xsl")
Wscript.Echo xmlFile.TransformNode(xslFile)
End Sub
요약하자면 MSXml2.DOMDocument.3.0 개체의 인스턴스를 2개 만드는 것으로 시작했습니다. 한 개체에 XML 데이터 스트림(strWinRMXML)을 로딩하고 다른 개체에는 XSL 파일(WsmTxt.xsl)을 로딩했습니다. 이 시점에서 TransformNode 메서드를 호출, XSL의 정보를 사용해서 XML 스트림으로부터 포착한 데이터에 형식을 부여하고 표시하도록 했습니다.
그렇죠. 약간은 혼란스럽습니다. 그러나 최소한 그 출력 결과는 (완벽과는 거리가 멀더라도) 다소 읽기 쉽습니다(그림 3 참고).
Figure 3 텍스트 칠하기
<TextBlock
Name="Test"
FontSize="40"
FontFamily="Georgia"
FontWeight="Bold"
Canvas.Top="20"
Canvas.Left="20"
Text="The TechNet Script Center">
<TextBlock.Foreground>
<SolidColorBrush Name="test_brush" Color="red"/>
</TextBlock.Foreground>
</TextBlock>
Figure 3 좀더 정돈된 형태의 XML
Win32_Service
AcceptPause = false
AcceptStop = true
Caption = User Profile Service
CheckPoint = 0
CreationClassName = Win32_Service
Description = This service is responsible for loading and unloading user profiles. If this service is stopped or disabled, users will no longer be able to successfully logon or logoff, applications may have problems getting to users' data, and components registered to receive profile event notifications will not receive them.
앞서 말했듯이 이 정도라면 괜찮은 편이지만 그리 훌륭하다고 할 수는 없으므로, 우리는 다음 달에 이를 더 다듬어 여러분 혼자 XML 출력을 다룰 수 있는 몇 가지 방법을 보여드리겠습니다.
클래스의 일부 선별된 인스턴스와 속성의 반환
말할 필요도 없이 이것은 단 한가지만 빼고는 매우 멋진 착상입니다. 그것은 여러분의 일반적인 작업 처리 방식을 온전히 반영하는 것이 아닐 수도 있다는 점입니다. 그렇죠, 클래스의 모든 인스턴스의 모든 속성을 반환하고자 할 경우도 있겠지만, 클래스의 일부 속성 또는 인스턴스만 반환하고자 할 경우도 (오히려 더 많이) 있을 수 있습니다. 예를 들어, 정규 WMI 스크립트에서 다음과 유사한 코드를 사용하여 수행하는 것처럼 실행 중인 서비스에 관한 정보만 반환되도록 하고자 할 수 있습니다.
Set colItems = objWMIService.ExecQuery _
("Select * From Win32_Service " & _
"Where State = 'Running'")
멋집니다. 그러나 Resource 문자열을 대체 어떻게 수정해서 그와 동등하게 만들겠습니까?
물론, 완전히 솔직하게 말하자면 ExecQuery 구문과 동등하게 만들기 위해 Resource 문자열을 수정하지는 않을 것입니다. 분명히 Resource 문자열은 수정해야 하겠지만, 다른 일도 몇 가지 해야 할 것입니다.
이 점을 염두에 두고 그림 4을 살짝 살펴보겠습니다. 이것은 어느 컴퓨터에서 실행 중인 서비스(설치된 모든 서비스가 아닌)에 대한 정보를 반환하는 WinRM 스크립트입니다.
Figure 4 TextBlock 트릭
<TextBlock.Triggers>
<EventTrigger RoutedEvent=
"TextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Test"
Storyboard.TargetProperty="Opacity"
From="0.0" To="1.0"
Duration="0:0:5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
Figure 4 실행 중인 서비스 찾기
strComputer = "atl-fs-01.fabrikam.com"
Set objWRM = CreateObject("WSMan.Automation")
Set objSession = objWRM.CreateSession("http://" & strComputer)
strResource = "https://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/*"
strFilter = "Select * From Win32_Service Where State = 'Running'"
strDialect = "https://schemas.microsoft.com/wbem/wsman/1/WQL"
Set objResponse = objSession.Enumerate(strResource, strFilter, strDialect)
Do Until objResponse.AtEndOfStream
DisplayOutput(objResponse.ReadItem)
Loop
Sub DisplayOutput(strWinRMXml)
Set xmlFile = CreateObject("MSXml2.DOMDocument.3.0")
Set xslFile = CreateObject("MSXml2.DOMDocument.3.0")
xmlFile.LoadXml(strWinRMXml)
xslFile.Load("WsmTxt.xsl")
Wscript.Echo xmlFile.TransformNode(xslFile)
End Sub
일견 이것은 앞서 보여드린 첫 번째 WinRM 스크립트와 완전히 동일해 보이지만 몇 가지 중요한 차이점이 있습니다. 우선 한 가지로, Resource 문자열에 할당한 값을 살펴보겠습니다.
strResource = _
"https://schemas.microsoft.com" & _
"/wbem/wsman/1/wmi/root/cimv2/*"
유의할 점은 필터링된 쿼리를 작성할 때는 다루고자 하는 클래스의 실제 이름(Win32_Service)을 명시하지 않고 그 클래스가 있는 네임스페이스(root/cimv2)로 연결하기만 한다는 점입니다. 마지막에 별표(*)를 붙이는 것만 기억하십시오. 그렇게 하지 않으면 스크립트가 오류를 일으키고 "... the class name must be '*' (star)"라는 결과 메시지가 나타납니다. 이것은 단지 클래스 이름을 *로 해야 한다는 것을 의미합니다.
또한 Filter와 Dialect를 정의해야 합니다.
strFilter = _
"Select * From Win32_Service " & _
"Where State = 'Running'"
strDialect = _
"https://schemas.microsoft.com" & _
"/wbem/wsman/1/WQL"
Filter는 이해하기 쉬워야 합니다. 여기에 WQL(Windows Management Instrumentation Query Language) 쿼리("Select * From Win32_Service Where State = 'Running'")를 놓기 때문입니다. 한편 Dialect는 Filter를 만들 때 사용하는 쿼리 언어입니다. 현재로서 허용된 쿼리 언어는 WQL 하나뿐입니다. 그럼에도 불구하고 Dialect는 반드시 명시되어야 하며, 그렇지 않으면 스크립트는 "filter dialect ... is not supported."라는 메시지와 함께 오류를 일으킵니다.
참고로, 재미있게도 이 오류 메시지는 Enumerate 메서드를 호출할 때는 Dialect를 제거하라는 뜻을 제시합니다. 여러분은 이 권고안을 따르지 말아야 합니다. 필터링된 쿼리를 수행할 때는 Dialect가 반드시 명시되어야 하며 반드시 WQL이어야 합니다. 끝.
유일하게 필요한 변경은 Enumerate 메서드를 호출하는 경우에 발생합니다. 이 지점에서 Resource(strResource)를 나타내는 변수뿐만 아니라 Filter(strFilter)와 Dialect(strDialect)를 나타내는 변수도 따라 보내야 합니다.
Set objResponse = _
objSession.Enumerate _
(strResource, strFilter, strDialect)
직접 결과를 확인하십시오.
그러면 클래스의 일부 선별된 속성만 반환하는 것은 어떨까요? 예를 들어 어느 컴퓨터에서 실행되는 모든 서비스의 Name 및 DisplayName만 반환하고자 한다고 가정합시다. 그러면 어떻게 해야 할까요?
그와 같은 경우에는 Name 및 DisplayName만 표시되도록 XML을 조작할 수 있습니다. 가능하지만 확실히 까다로운 방법입니다. 더 쉬운 방법은 Filter를 할당할 때 그러한 속성들만 명시하는 것입니다.
strFilter = _
"Select Name, DisplayName " & _
"From Win32_Service " & _
"Where State = 'Running'"
그렇게 하면 다음과 같이 각 서비스의 Name 및 DisplayName만 얻게 될 것입니다.
XmlFragment
DisplayName = Windows Event Log
Name = EventLog
XmlFragment
DisplayName = COM+ Event System
Name = EventSystem
인정합니다. 형식이 다소 엉뚱하지요. (XmlFragment 따위는 대체 뭘까요?) 그래서 다음 달에 더 다듬겠다는 얘깁니다.
기대하시라
아주 운이 없지만 않다면, WinRM의 거칠고 놀라운 세계의 탐험을 시작하는 데에는 이 정도로 충분합니다. 물론 과거 독일에서 유행했던 '대기 영안실'에 관해 언급하지 않고 WinRM에 관한 칼럼을 마칠 수는 없을 것입니다. 대기 영안실이 있는 도시에서는 시체가 즉시 매장되지 않았습니다. 대신 손가락과 발가락에 여러 개의 줄과 철사를 감고 따뜻한 방 안에 안치되었습니다. 물론, 그 발상은 아주 작은 동작으로도 경보를 울리고 도움을 청할 수 있게 한다는 것이었습니다. 이 사람들이 전혀 살아날 가망이 없으며 결코 아무 것도 할 수 없다는 것이 명백해질 때까지 이 시체들은 대기 영안실에 보관되었습니다.
그러고 보면 대기 영안실이라는 것은 Scripting Guys 팀에 배속되는 것과 매우 유사한 면이 있습니다. 아닌가요? 물론, 대기 영안실에서 다시 살아 나온 사람은 전혀 없습니다만, Scripting Guys 팀에 배속되었던 사람들은...
Dr. Scripto의 Scripting Perplexer
2007년 6월, Scripting Guys는 플로리다 올랜도에서 열린 Tech•Ed 2007 컨퍼런스에 참석했습니다. 컨퍼런스 참석에만 그치지 않고 우리는 좀 즐겨보기로 했습니다. 우리는 다른 사람들도 역시 즐길 수 있을 것이라고 생각했습니다. 이러한 생각으로 우리는 스크립팅 관련 퍼즐과 기타 다양한 정보를 수록한 소책자, Dr. Scripto's Fun Book을 들고 나왔습니다. 우리는 TechNet Magazine과 협력하여, 즉 Expo Hall에 설치된 이들의 부스에서 아주 작은 구석 자리 하나를 달라고 해서 지나가는 사람들에게 그 Fun Book을 나눠주었습니다.
결과적으로, 그 Fun Book은 매우 인기 있는 품목이었습니다(Dr. Scripto 버블 머리 인형보다는 못했지만 거의 근접했지요). 기회를 놓칠 리 없는 영리한 TechNet Magazine 사람들은 Scripting Guys의 성공을 활용할 수 있는 방법을 하나 더 포착해서(Scripting Guys 스스로는 자신의 성공을 제대로 활용할 수 없을 것 같으므로), 자신들을 위한 퍼즐을 몇 개 만들어 달라고 부탁해왔습니다. Scripting Guy 팀원인 Jean Ross가 잠시 돌아선 사이, 같은 팀원인 Greg Stemp가 말해 버렸습니다. "하죠, 뭐!" 그래서 나왔습니다. Dr. Scripto의 Scripting Perplexer입니다. 즐겨보세요.
Drop-In Scripting
이 퍼즐에서 맨 위의 모든 문자들을 해독하면 스크립트가 만들어집니다(VBScript). 그러나 걱정하지 마십시오. 전부를 한 번에 해독할 필요는 없습니다. 한 번에 한 열씩 해독하면 됩니다. 맨 위 섹션 각 열의 문자가 맨 아래 섹션 동일 열의 빈 공간에 채워집니다. 예를 들면 다음과 같습니다.
예에서 보듯이, 열 1에는 문자 S, C, T가 있습니다. 이 세 문자는 알 수 없는 순서로 아래의 격자 모양 표에 속합니다. 그러나 모든 문자가 적절한 순서로 내려가면, 맨 아래 격자는 왼쪽에서 오른쪽으로 읽을 때 논리적인 의미를 나타냅니다. 해답을 살펴보십시오.
열 1의 문자 S, C, T가 T, S, C의 순서로 내려옵니다. 이것은 "The Script Center"의 각 단어 첫 문자입니다. 실제 퍼즐은 이보다 더 어렵습니다. 더 길 뿐더러 최종 결과가 하나의 완전한 스크립트를 구성하기 때문입니다.
한 가지 힌트를 드리자면, 최종 스크립트는 한 파일의 전체 경로로 시작되어 구문 분석을 진행하고 단지 파일 이름만 표시합니다.
행운을 기원합니다!
name = "C:\Scripts\Test.txt"
arr = Split(name, "\")
index = Ubound(arr)
Wscript.Echo "Filename: " _
& arr(index)
Microsoft Scripting Guys는 Microsoft에서 고용되어 일하고 있는 Microsoft의 직원들입니다. 이들은 좋아하는 야구 경기와 기타 여러 활동을 하는 시간을 제외하고는 항상 TechNet 스크립트 센터를 운영합니다. 자세한 내용은 www.scriptingguys.com에서 확인하십시오.
© 2008 Microsoft Corporation 및 CMP Media, LLC. All rights reserved. 이 문서의 전부 또는 일부를 무단으로 복제하는 행위는 금지됩니다..