Hey, Scripting Guy!2008 Scripting Games 소식과 XML 정보!

Scripting Guys

이 기사의 코드 다운로드: HeyScriptingGuy2008_02.exe (151KB)

사람들이 스포츠계의 전설에 대해 이야기할 때는 항상 등장하는 몇몇 이름들이 있죠. 예를 들어 베이브 루스, 펠레, 무하마드 알리, 월터 페이튼, 스쿠터케이, 미스터랫, 조니 등...

아니 잠깐, 스쿠터케이(ScooterK)와 미스터랫(MrRat)이 누구냐고요? 설마, 농담이시죠? Winter Scripting Games(2월 15일부터 3월 3일까지 TechNet Script Center에서 개최, microsoft.com/technet/scriptcenter/funzone/games 참조)의 최신 소식을 놓친 분들께 알려드리지요. ScooterK와 MrRat은 2007 Winter Scripting Games에 참가하여 한 개 이상의 부문에서 만점을 기록한 진정한 전설입니다.

진짜 신나는 것은 바로 이거에요. 여러분은 펠레같이 전설적인 축구 선수가 될 수 있다고 생각하십니까? 아마도 힘들겠죠? 그러면 헤비급 세계 권투 챔피언은 어떨까요? 저희 Scripting Guys 중 몇명은 실제로 헤비급에 해당되기는 하지만, 권투 챔피언이 되기는 영 힘들 것 같네요. 그렇지만, 여러분은 ScooterK나 MrRat처럼 또 다른 전설이 될 수는 있습니다.

물론 뭐, 이론적으로는 여러분이 차세대 베이브 루스가 되지 말라는 법은 없겠죠. 다만, 하루 두 번 하는 경기 중간에 24개의 핫도그를 먹을 수 있다면 말입니다.

네네, 진정하시고요. 지금부터 ScooterK나 MrRat, 심지어 Bizzy나 H2Data와 같은 고수가 되는 방법을 알려드리겠습니다. 뭐 복잡한 것은 아니고, Script Center로 와서 Scripting Games에 참가하시면 됩니다. 2월 15일 저희는 10가지 이벤트(10개 스크립팅 과제)를 발표하고 여러분이 이중 하나라도, 아니면 혹시 전부 완수할 수 있는지 볼 것입니다. 주어진 문제를 해결하는 스크립트를 작성하여 전자 메일로 Scripting Guys에게 보내시면 됩니다. (자세한 내용은 Scripting Games 홈 페이지를 참조하십시오.) 그러면 저희는 여러분의 스크립트를 테스트하고 제대로 작동하면 점수를 드립니다. 10개 이벤트 모두를 성공적으로 완수해낸다면 여러분도 스포츠계의 전설이 되는 것입니다. 적어도 스크립팅 스포츠계에서는 전설이 되는 것이며, 이것도 대단한 영예라 할 수 있죠.

Scripting Games(2월 15일에서 3월 3일까지)는 도전과 재미로 가득한 이벤트입니다. 무엇보다도 모두에게 참여의 문이 열린 대회입니다. 시스템 관리 스크립팅이 다소 생소하다면 Beginners Division에 참여하여 VBScript, Windows PowerShellTM, Perl(올해 새로 추가) 등에서 초보자들을 위한 별도의 경합에 참여할 수 있습니다. Beginners Division은 너무 쉽다고요? 그렇다면 Advanced Division에서 동일한 VBScript, Windows PowerShell 및 Perl을 주제로 겨뤄보십시오.

이 대회(2월 15일부터 3월 3일까지라고 말했죠?)는 한 마디로 스크립팅 시즌 이벤트라고 할 수 있습니다. 이 기회를 절대 놓치지 마세요. 지금 바로 Script Center 홈 페이지에서 대회에 관한 여러 정보와 비결을 알아보고 대회가 공식적으로 시작되는 2월 15일에 홈 페이지를 다시 방문하십시오.

다시 한 번 강조하지만 대회 기간은 2월 15일부터 3월 3일까지입니다.

그런데 이번 달에는 Scripting Games 발표 소식에다가 새로운 Hey, Scripting Guy! 칼럼까지 작성하느라 숨 돌릴 틈이 없네요. 하지만 TechNet Magazine 독자 여러분의 행복을 위해 어쨌든 새 칼럼도 쓰기로 결심했답니다. 저희의 중요한 삶의 목표가 또 여러분의 행복 아니겠습니까?

정확히 일년 전(벌써 그렇게 됐나요?) 저희는 스크립트를 사용하여 XML 파일을 읽는 방법에 대해 칼럼을 게재했었습니다. 그때는 스크립트를 사용하여 XML 파일을 생성, 작성, 수정하는 방법은 다루지 않았었죠. 이번에는 모두 알려드리겠습니다. XML 파일을 생성할 수 있는 스크립트는 어떻게 작성하는지 궁금하시죠? 여러분의 이 갈증을 풀어드리는 데 1년이나 걸렸군요. 죄송합니다. 그림 1을 보시면 이 스크립트가 나와 있습니다. 꽤 복잡해 보이지만 지금부터 모두 차근차근 설명해 드리겠습니다.

Figure 1 XML 파일 만들기

Set xmlDoc = _
  CreateObject("Microsoft.XMLDOM")  
  
Set objRoot = _
  xmlDoc.createElement("ITChecklist")  
xmlDoc.appendChild objRoot  

Set objRecord = _
  xmlDoc.createElement("ComputerAudit") 
objRoot.appendChild objRecord 
  
Set objName = _
  xmlDoc.createElement("ComputerName")  
objName.Text = "atl-ws-001"
objRecord.appendChild objName  

Set objDate = _
  xmlDoc.createElement("AuditDate")  
objDate.Text = Date  
objRecord.appendChild objDate  

Set objIntro = _
  xmlDoc.createProcessingInstruction _
  ("xml","version='1.0'")  
xmlDoc.insertBefore _
  objIntro,xmlDoc.childNodes(0)  

xmlDoc.Save "C:\Scripts\Audits.xml"  

먼저 Microsoft.XMLDOM 개체의 인스턴스를 만듭니다. 짐작하셨겠지만 이것은 우리가 XML 파일을 사용하여 작업할 수 있게 해주는 개체입니다. 여기서 우리의 목표는 그림 2와 같이 간단한 XML 파일을 만드는 것입니다.

그림 2 목표: 간단한 XML 파일

그림 2** 목표: 간단한 XML 파일 **

이런 XML 파일을 만들려면 우선 루트 노드(ITChecklist)를 생성해야 합니다. 어떻게 하냐고요? 다음과 같습니다.

Set objRoot = _
  xmlDoc.createElement("ITChecklist")  
xmlDoc.appendChild objRoot  

아주 간단하죠? 루트 노드에 지정할 이름을 createElement 메서드에 전달하고 호출한 다음 appendChild 메서드의 유일한 메서드 매개 변수에 새 요소(objRoot)에 대한 개체 참조를 지정하고 메서드를 호출하면 됩니다. 그러면 이제 루트 노드가 생성된 것입니다.

그러나 아직 끝난 것은 아니죠. 이제 ComputerAudit 노드를 생성해야 합니다. 이 노드는 ITChecklist 노드의 하위 노드로, 단일 컴퓨터의 정보를 표시합니다. 보시다시피 이 노드를 생성하는 코드는 루트 노드를 만드는 코드와 비슷합니다.

Set objRecord = _
  xmlDoc.createElement("ComputerAudit") 
objRoot.appendChild objRecord 

유일한 차이점은 루트 노드를 만들 때는 XML 문서 자체에서 appendChild를 호출했는데(개체 참조 xmlDoc 확인), 루트에 새 하위 노드를 추가할 때는 XML 문서가 아닌 루트 노드(objRoot)에서 appendChild를 호출한다는 것입니다. 너무 쉽죠?

ComputerName 노드와 AuditDate 노드를 ComputerAudit의 하위 노드로 추가하는 방법도 역시 간단합니다. 비슷한 절차를 거치는데요, createElement를 호출하여 새 노드를 만들고, appendChild를 호출하여 이 새 노드를 파일에 추가하면 됩니다.

(돌발 퀴즈: 이때 appendChild는 어디서 호출할까요? 그렇습니다. 방금 생성한 상위(ComputerAudit) 노드인 objRecord에서 호출합니다.)

그리고 ComputerName 노드와 AuditDate 노드는 값을 포함해야 하기 때문에 문서에 추가하기 직전 이들 각 노드의 Text 속성 값도 반드시 지정해야 합니다.

ComputerName 노드를 실제로 생성하는 아래 코드를 보시면 보다 명확히 이해할 수 있습니다.

Set objName = _
  xmlDoc.createElement("ComputerName")  
objName.Text = "atl-ws-001"
objRecord.appendChild objName  

예상하셨겠지만, AuditDate를 생성하는 코드 또한 거의 동일합니다. createElement를 호출할 때 노드 이름을 다르게 지정하고 Text 속성에 다른 값을 지정하면 되는 것입니다.

이거 너무 쉬운거 아닌가요?

첫 번째이자 이 예에서는 유일한 레코드의 노드를 생성했으면 아래의 간단한 코드 블록을 실행합니다.

Set objIntro = _
 xmlDoc.createProcessingInstruction _
  ("xml","version='1.0'")  
xmlDoc.insertBefore _
  objIntro,xmlDoc.childNodes(0)  

이 코드는 파일의 시작 부분에 <?xml version="1.0" ?> 태그를 삽입하여 정확한 형식의 XML 문서가 생성되도록 합니다.

이제 남은 일은 Save 메서드를 호출하고 새 파일을 C:\Scripts\Audits.xml로 저장하는 것입니다.

xmlDoc.Save "C:\Scripts\Audits.xml"  

이렇게 간단히 새로운 XML 문서가 탄생했습니다.

이 정보는 사실상 매우 유용합니다. 이제 스크립트를 사용하여 새 XML 파일을 만들 수 있는 것입니다. 물론, 새 XML 파일을 만드는 것보다는 기존 파일에 단순히 새 데이터를 추가해야 하는 경우가 더 많기는 하죠. 따라서 Scripting Guys가 지금부터 기존 파일에 새 데이터를 추가하는 방법을 알려드리겠습니다.

원래 저희는 기존 XML 파일에 데이터를 추가하는 방법까지는 설명하지 않을 생각이었어요. 그렇지만 너무 마음이 여린 저희는 TechNet Magazine 독자들께 한 가지 제안을 해보기로 했습니다. 지금 이 매거진을 읽고 계신 여러분 모두 2008 Winter Scripting Games에 참여하신다면, 그 보답으로 저희는 스크립트를 사용하여 XML 파일에 데이터를 추가하는 방법을 보여드리는 것이죠. 자, 그럼 모두 Scripting Games에 참여하기로 약속하신겁니다?

저희는 끝까지 기다릴거예요. 거기 서울에 계신 분, 약속하시죠?

꼭 참여하시는 겁니다? Scripting Games에서 여러분 모두 좋은 시간 보내실 거예요. 그건 저희가 약속드리죠.

자, 그럼 약속은 약속이니까 이제 스크립트로 기존 XML 파일에 데이터를 추가하는 방법에 대해 설명하겠습니다. 그림 3을 한번 보세요.

Figure 3 XML 파일에 추가

Set xmlDoc = _
  CreateObject("Microsoft.XMLDOM")

xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Audits.xml")

Set objRoot = xmlDoc.documentElement
  
Set objRecord = _
  xmlDoc.createElement("ComputerAudit")
objRoot.appendChild objRecord

Set objFieldValue = _
  xmlDoc.createElement("ComputerName")
objFieldValue.Text = "atl-ws-100"
objRecord.appendChild objFieldValue

Set objFieldValue = _
  xmlDoc.createElement("AuditDate")
objFieldValue.Text = Date
objRecord.appendChild objFieldValue
  
xmlDoc.Save "C:\Scripts\Audits.xml"  

보다시피 XML 파일 생성 스크립트와 크게 다르지는 않습니다. 먼저 Microsoft.XMLDOM 개체의 인스턴스를 만든 다음, Async 속성을 False로 설정하여 문서를 비동기가 아닌 동기적으로 로드하도록 스크립트에 지시합니다. 이것에 어떤 차이가 있을까요? 문서를 비동기적으로 로드하면 문서가 완전히 로드되지 않았는데도 스크립트가 계속 실행될 수 있습니다. 아직 생성되지도 않은 문서에 작업을 수행하려 하면 당연히 문제가 발생하지요. 따라서 XML 파일이 반드시 동기적으로 로드되게 하여 파일이 완전히 로드된 후에 스크립트가 진행되도록 해야 하는 것입니다.

이제 Load 메서드를 호출하여 C:\Scripts\Audits.xml 파일을 엽니다. 파일이 열리면 아래의 코드 줄을 사용하여 documentElement 클래스의 인스턴스를 생성합니다. 이 인스턴스는 우리를 이 문서 루트에 묶어 두는 효과가 있습니다. 여기서는 물론 ITChecklist 노드가 되겠죠.

Set objRoot = xmlDoc.documentElement

이제부터는 일사천리로 진행됩니다. 새 노드를 파일에 추가하는 appendChild 메서드를 사용하여 ComputerAudit 노드의 새 인스턴스를 만듭니다. 그런 다음 ComputerName 노드와 AuditDate 노드에 대해 적절한 값(각각 atl-ws-100 및 현재 날짜)을 지정하여 두 노드의 새 인스턴스를 만듭니다. 생성된 이 두 항목을 조금 전에 만든 새 ComputerAudit 노드에 넣고 Save 메서드를 호출하여 파일을 저장하면 끝입니다. 이제 Scripting Games나 준비하러 가면 되는 거죠.

예, 그렇죠. 2월 15일부터 3월 3일까지 TechNet Script Center에서 열린다는 그 이벤트말입니다.

지금까지 아주 좋습니다. 이제 새 XML 파일을 만들고 이 파일에 새 레코드를 추가할 수도 있습니다. 그런데 이것이 전부는 아닙니다. 예를 들어 파일의 기존 레코드를 수정해야 할 때는 어떻게 하죠? 그림 4에는 파일의 기존 레코드를 수정하는 방법 중 하나가 나와 있습니다.

Figure 4 XML 수정

Set xmlDoc = _
  CreateObject("Microsoft.XMLDOM")

xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Audits.xml")

Set colNodes=xmlDoc.selectNodes _
  ("/ITChecklist/ComputerAudit " & _
   "[ComputerName = 'atl-ws-100']/AuditDate")

For Each objNode in colNodes
   objNode.Text = Date
Next
  
xmlDoc.Save "C:\Scripts\Audits.xml"  

이 스크립트의 핵심 동작은 쿼리의 반환 레코드를 결정하는 selectNodes 메서드를 호출할 때 발생합니다. 그림과 같이 selectNodes를 호출할 때는 두 가지 조건을 주의해서 지정해야 합니다. 즉, 레코드의 ComputerName 특성이 atl-ws-100이어야 하고, AuditDate 특성만 반환되도록 해야 합니다.

왜 그런지 잘 모르겠다면 XML 파일 작업에 대한 Scripting Guys의 첫 번째 기사(technetmagazine.com/issues/2007/02/HeyScriptingGuy)를 읽어 보십시오. 여기에는 selectNodes 쿼리 구문에 대한 자세한 설명이 나와 있습니다.

이제 원하는 대로 selectNodes는 지정한 조건에 맞는 모든 XML 레코드의 컬렉션을 반환합니다. 이는 곧 AuditDate 특성(유일하게 요청한 특성)의 값을 업데이트할 수 있음을 의미합니다. 즉, 컬렉션의 모든 항목을 대상으로 반복하도록 For Each 루프를 설정하고 이 루프에서 AuditDate에 새 값을 지정하여 업데이트할 수 있습니다.

For Each objNode in colNodes
   objNode.Text = Date
Next

그런데 한 번에 두 개 이상의 특성을 수정할 수도 있을까요? 물론입니다. 그러나 이 내용은 다음 칼럼에서 다루도록 하겠습니다.

혹시 말이죠, 파일에서 모든 컴퓨터의 감사 날짜를 업데이트하는 방법도 알고 싶으세요? 간단합니다. 그림 5의 스크립트를 사용하면 됩니다.

Figure 5 감사 날짜 변경

Set xmlDoc = _
  CreateObject("Microsoft.XMLDOM")

xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Audits.xml")

Set colNodes=xmlDoc.selectNodes _
  ("/ITChecklist/ComputerAudit/AuditDate")

For Each objNode in colNodes
   objNode.Text = Date
Next
  
xmlDoc.Save "C:\Scripts\Audits.xml"

이 스크립트와 앞서 살펴본 XML 수정 스크립트의 유일한 차이점이 무엇인지 아시겠어요? 이 스크립트에서는 ComputerName이 atl-ws-100인 레코드만 표시하도록 지정하지 않는다는 점이 다르죠. 이 조건을 지정하지 않기 때문에 기본적으로 모든 레코드가 반환됩니다.

마지막으로 스크립트를 하나만 더 살펴보겠습니다. atl-ws-100이라는 이 끈질긴 조건이 마지막 제 역할을 다한 후 저세상으로 떠났다고 가정해 봅시다.

여기서 잠깐, 컴퓨터는 죽으면 어디로 갈까요? 대개는 Scripting Guys 중 한 명에게 가는 것 같습니다. 실제로 본 칼럼을 쓰고 있는 이 Scripting Guy도 전에 "Microsoft를 위해 애써왔으니 랩톱 컴퓨터를 한 대 선사한다"면서 랩톱 컴퓨터를 받은 적이 있습니다. 고마운 일이었지만 컴퓨터가 고장나서 켜지지도 않는다는 것이 문제였죠. 그정도는 괜찮았을지도 모르는데, 알고보니 하드 디스크도 없더군요.

컴퓨터라는 거대한 실리콘 집합체의 수명을 완전히 끝내려면 XML 파일에서 atl-ws-100을 삭제해야 합니다. 구체적으로 어떻게요? 그림 6을 보십시오.

Figure 6 XML 파일에서 삭제

Set xmlDoc = _
  CreateObject("Microsoft.XMLDOM")

xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Audits.xml")

Set colNodes=xmlDoc.selectNodes _
  ("/ITChecklist/ComputerAudit " & _
   "[ComputerName = 'atl-ws-100']")

For Each objNode in colNodes
  xmlDoc.documentElement.removeChild _
    (objNode)
Next
  
xmlDoc.Save "C:\Scripts\Audits.xml"  

보시다시피 이 스크립트는 AuditDate 속성을 수정하는 이전 스크립트와 비슷합니다. 다만 두 가지가 다릅니다. 첫째는 selectNodes 쿼리에 속성 값을 지정하지 않기 때문에 atl-ws-100에 대해 전체 XML 레코드가 반환된다는 것입니다.

Set colNodes=xmlDoc.selectNodes _
  ("/ITChecklist/ComputerAudit " & _
   "[ComputerName = 'atl-ws-100']")

둘째는 For Each 루프에서 removeChild 메서드를 호출하여 ComputerName이 atl-ws-100인 레코드를 모두 삭제한다는 점입니다.

xmlDoc.documentElement.removeChild _
  (objNode)

이것으로 끝입니다. 이제 atl-ws-100은 우리에게서 완전히 떠나는 것이죠.

혹시 TechNet Magazine 편집자 중 아직 이번 달 칼럼을 읽고 있는 사람이 있나요? 아, 모두 이번 달 스크립팅 퀴즈를 풀러 갔다고요? 그거 다행이군요. 이제 우릴 감시하는 사람들이 없으니 한 가지 말씀드리죠. 지금 이 칼럼을 읽든 기타 무엇을 하든지 당장 그만두고 바로 Script Center를 방문하여 Scripting Games를 준비하세요. TechNet Magazine이야 오랫동안 게시되니 언제라도 읽을 수 있지 않습니까? 그렇지만 Scripting Games는 일년에 한 번만 일정 기간(구체적으로 말하면 2월 15일부터 3월 3일까지) 동안만 개최됩니다. 이 귀중한 기회를 놓쳐서는 안 되죠!

한 가지 말씀드리자면, TechNet Magazine을 그만 읽으라고 했지만, 사실상 칼럼 본문은 이미 다 읽은 셈입니다. 그렇죠? 희한한 일이죠.

Dr. Scripto의 Scripting Perplexer

매달 퍼즐 풀이 실력뿐만 아니라 스크립팅 기술까지 시험해 볼 수 있는 문제입니다.

2008년 2월: 불가사의한 기호

컴퓨터 키보드에는 이상한 모양의 문자들이 가득합니다. 게다가 이러한 문자는 대부분 VBScript나 Windows PowerShell과 같은 스크립팅 언어에서 특정한 용도로 사용됩니다. 각 기호가 스크립팅 시에 어떤 용도로 사용되는지 맞춰 보십시오. 예를 보여 주기 위해 첫 번째 기호는 이미 답이 적혀 있습니다.

ANSWER:

Dr. Scripto의 Scripting Perplexer

답: 불가사의한 기호, 2008년 2월

  

Scripting Guys는 Microsoft에서 고용되어 일하고 있는 Microsoft의 직원들입니다. 이들은 좋아하는 야구 경기와 기타 여러 활동을 하는 시간을 제외하고는 항상 TechNet 스크립트 센터를 운영합니다. 자세한 내용은 www.scriptingguys.com에서 확인하십시오.

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