Hey, Scripting Guy!あの世からのデスクトップ管理

Microsoft Scripting Guys

この記事で使用しているコードのダウンロード: HeyScriptingGuy2007_11.exe (151KB)

皆様からの圧倒的なご要望により、 今月は、いつもと少し違うことをやってみることにしました。システム管理スクリプトの話でコラムを始めるのではなく、不気味な音楽を流しながら幽霊の話をすることにします。

注 : さて、厳密に言うと、本当に少し違うことをしたかったのであれば、今月のコラムは、趣向を変えてシステム管理スクリプトの話から入ったでしょう。でも、私たちに協力してくれますよね。よろしくお願いします。

何年も前に、ある Scripting Guy の玄祖母が亡くなりました。おばあさんが簡素な木棺に納められてから、おじいさんは恐ろしい悪夢を見るようになりました。その悪夢とは、最愛の妻が必死になってお墓から抜け出そうとしている、というものでした。繰り返される悪夢と繰り返される懇願により、最終的に、おじいさんは、遺体を掘り出すように自治体を説得しました。棺を開けたとき、その場に居合わせた人は身の毛のよだつ思いをしました。おばあさんの爪は反り返り、棺の内側が引っかき傷だらけだったのです。

いいですか、この話は完全に真実というわけではありません。実際、よく考えてみると、真実のかけらもないことがわかるでしょう。それでも、この話には重要な教訓が盛り込まれています。どんな教訓なのかはわかりませんが、どこかにあるのです。

ちょっと待ってください。今思い出しました。棺は、本来、故人を雨風から保護し、遺体が腐敗しないようにするために設計されました。残念ながら、棺には想定外の効力が付与されました。理論上の話ですが、棺を使用して、人を生き埋めにして抜け出せないようにすることが可能です。Scripting Guy の玄祖母の話からはっきりわかるように、全員で慎重に考えた計画でも、大惨事を招き、人が生き埋めになる場合があります (ここで、もう一度、不気味な音楽を流します)。

注 : もちろん、1860 年代に Franz Vester が考案した Improved Burial Case を選択した場合は別です。この棺には、地上にあるベルにつながったひもが用意されているため、早まって埋葬してしまった場合には、"故人" がベルを鳴らして助けを呼ぶことができます。Improved Burial Case には、折りたたみ式のはしごも用意されていますが、地下約 3 メートルに埋められた棺から脱出する際に、このはしごがどのように役立つかはよくわかっていません。だれかのガレージの上に埋葬されたのであれば、当然、このはしごは役に立つでしょう。そうでなければ、無益でしょう。

これとまったく同じこと (慎重に考えた計画でも大惨事を招くこと) がインターネット ファイアウォールにも当てはまります (少し誇張しすぎかもしれませんが)。ファイアウォールは、本来、悪意のあるユーザーの侵入を防ぐためにデザインされたものです。つまり、ファイアウォールは、着信ネットワーク トラフィックをブロックすることで、ハッカーや侵入者がコンピュータに近づけないようにすることができます。これはすばらしい機能ですが、生き埋めにされるという問題と同様、ここでも想定外の事態が発生しています。つまり、ファイアウォールによって、悪意のないユーザーもブロックされる場合があります。これは、特に、リモート コンピュータで管理タスクを実行する際に DCOM に依存する Windows® Management Instrumentation (WMI) について当てはまります。ファイアウォールは、着信するすべての DCOM トラフィックをブロックする傾向にあります。これにより、プログラムによってインターネット経由でコンピュータを管理することが (まったく不可能でないとしても) 非常に難しくなります。実際、ファイアウォールで追加のポートを開いて、ハッカーやクラッカーによる被害を受けやすい状態を作らない限り、インターネット経由でリモート コンピュータを管理することは、まったくもって不可能です。もちろん、WinRM (Windows リモート管理) を選択した場合は別です (ただし、折りたたみ式のはしごは用意されていません)。

Windows リモート管理とは

WinRM SDK (msdn2.microsoft.com/aa384426) によると、Windows リモート管理は WS-Management プロトコルのマイクロソフト実装であり、WS-Management プロトコルはさまざまなベンダのハードウェアやオペレーティング システムの相互運用を可能にする標準的な SOAP ベースでファイアウォール対応のプロトコルだそうです。なかなかすごいでしょう。今月のコラムでは、WS-Management プロトコルの詳細について説明するつもりはありません。このプロトコルの詳細については、WinRM SDK を参照することをお勧めします。今月のコラムで関心があるのは、WinRM が Windows Server® 2003 R2、Windows Vista®、および Windows Server 2008 で使用できることと、WinRM を使用するとインターネット経由でコンピュータを管理できることだけです。ポート 80 は、ほとんどのファイアウォールで開いているインターネット サービスの標準ポートですが、WinRM では、リモート コンピュータの管理にポート 80 を使用します (ただし、WinRM と既定の転送メカニズム HTTP で使用されるポートは、必要に応じて変更できます)。

今月のコラムでは、WinRM のインストール方法や構成方法についても説明しません。これらの作業に役立つ情報は、既に十分提供されています (msdn2.microsoft.com/aa384372)。ただし、1 つの重要なポイントについては説明しておきましょう。WinRM を使用してリモート コンピュータから情報を取得する場合 (もちろん、これがそもそも WinRM を使用する主な理由だと思いますが)、ローカル コンピュータとリモート コンピュータの両方で WinRM が実行されている必要があります。

これはどういうことでしょうか。つまり、クライアント コンピュータを Windows Vista にアップグレードしていない場合 (そんなことは、ないといいのですが)、またはサーバーを Windows Server 2003 R2 や Windows Server 2008 にアップグレードしていない場合、少なくとも現時点では、WinRM はあまり役に立たないということです。言うまでもありませんが、今後は状況が変わるでしょう (もちろん、ファイアウォールで許可されていれば、WMI や DCOM を使用してリモート コンピュータを管理することができます)。

クラスのすべてのプロパティとインスタンスを返す

注意事項や免責事項を気にする人は、おそらくいないでしょう。その訳のわからない文言の代わりに、WinRM を活用したスクリプトの作成方法を紹介しましょう。偶然にも、atl-fs-01.fabrikam.com という名前のコンピュータに接続して、そのコンピュータにインストールされているすべてのサービスの詳細情報を返すという、HTTP プロトコルとポート 80 を使用した実に簡単なスクリプトが見つかりました。完全なスクリプトについては、図 1 を参照してください。

Figure 1 Silverlight プロジェクトのコンポーネント

ファイル 説明
CreateSilverlight.js Silverlight の初期スタートアップ設定の指定に使用される JScript スクリプト (初期リリースでは、JScript スクリプトだけをサポートしていました)。ユーザー インターフェイスとグラフィック オブジェクトの構成に使用される XAML ファイルを含みます。
SampleProject.js JScript 関数を入力できる、単なる空のファイルです。
Silverlight.js Silverlight コントロールの初期化に使用するファイルです。
SampleProject.html これこそがおもしろい部分です。SampleProject.html は 3 つの .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

ご覧のとおり、まず、strComputer という名前の変数にコンピュータの DNS 名 (atl-fs-01.fabrikam.com) を代入します。または、コンピュータの IP アドレス (または IPv6 アドレス) を使用して接続することもできます。IP アドレスを代入する場合の例を以下に示します。

strComputer = "192.168.1.1"

strComputer 変数に値を代入したら、次に、WSMan.Automation オブジェクトのインスタンスを作成します。その後、CreateSession メソッドを呼び出して、この場合は、(先ほど説明したように) HTTP プロトコルを使用して、リモート コンピュータに接続します。

Set objSession = objWRM.CreateSession _
    ("http://" & strComputer)

既に説明したとおり、このスクリプトでは、リモート コンピュータにインストールされているサービスに関する情報を返します。さらに、少なくとも、この最初の例では、すべてのサービスの全プロパティ情報が必要です。結局どういうことなのでしょうか。つまり、リモート コンピュータの Win32_Service クラスにバインドする URI リソースを指定する必要があります。

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 クラスの場合は、(cimv2 名前空間ではなく) 既定の名前空間を指定するという点に注意して、URI クラスを変更するだけです。

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 BLOB が返されます。

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 BLOB

<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 の熟練者でない場合はどうでしょうか。この場合、選択肢は 2 つあります。1 つは、WinRM の XML 機能を使用するためのいくつかの秘訣を紹介する来月のコラムが公開されるまで待ちます。もう 1 つは、サンプル スクリプトで行った処理を実行します。このサンプル スクリプトでは、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 ストリームは 1 つの大きなデータ BLOB としてではなく個別の情報として返されます。その後、スクリプトでは、XML データをアイテム単位で 1 つずつ読み取ります)。

一方、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 つ作成します。1 つのオブジェクトには XML データ ストリーム (strWinRMXML) を読み込み、もう 1 つのオブジェクトには 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 出力を自分で操作する方法をいくつか紹介する予定です。

クラスの特定のインスタンスとプロパティを返す

言うまでもなく、1 つの問題点を除き、これは大変すばらしいことです。その問題点は、このスクリプトが通常の作業方法を十分反映していない可能性があるということです。もちろん、クラスのすべてのインスタンスの全プロパティを返すことが必要な場合もありますが、あるクラスの特定のプロパティまたはインスタンスのみを返す場合もあり、後者の場合の方が多いでしょう。たとえば、実行中のサービスに関する情報のみを返す必要のある場合があります。これは、次のようなコードを使用して、通常の WMI スクリプトで行う操作です。

Set colItems = objWMIService.ExecQuery _
  ("Select * From Win32_Service " & _
   "Where State = 'Running'")

これ自体はすばらしいことですが、一体どうやって、リソース文字列を変更して上記の処理を行えるようにするのでしょうか。

正直なところ、ExecQuery ステートメントと同じようにするために、リソース文字列を変更するつもりはありません。リソース文字列を変更する必要はありますが、他にもすべきことはいくつかあります。

このことを念頭に置いて、図 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 スクリプトとほとんど同じように見えますが、重要な違いがいくつかあります。まず、リソース文字列に割り当てている値に注目してください。

strResource = _
  "https://schemas.microsoft.com" & _
  "/wbem/wsman/1/wmi/root/cimv2/*"

フィルタ処理されたクエリを記述する際には、操作するクラス (Win32_Service) の名前は指定しておらず、クラスが存在する名前空間 (root/cimv2) に接続しているだけです。最後にアスタリスク (*) を付け加えることを忘れないでください。忘れた場合は、スクリプトでエラーが発生し、"...、クラス名は '*' (アスタリスク) でなければなりません" というメッセージが表示されます。これは、単にクラス名を * にする必要があることを示しているメッセージです。

さらに、フィルタと言語も定義する必要があります。

strFilter = _
  "Select * From Win32_Service " & _
  "Where State = 'Running'"
strDialect = _
  "https://schemas.microsoft.com" & _
  "/wbem/wsman/1/WQL"

フィルタは簡単に理解できるでしょう。フィルタには、WQL (Windows Management Instrumentation Query Language) クエリ ("Select * From Win32_Service Where State = 'Running'") を設定します。一方、言語は、フィルタの作成時に使用されるクエリ言語です。現時点で、使用できるクエリ言語は、WQL の 1 つだけです。それにもかかわらず、言語を指定する必要があります。指定しないと、クエリでエラーが発生し、"フィルタ言語...はサポートされていません" というメッセージが表示されます。

注 : おかしなことに、Enumerate メソッドの呼び出し時には、エラー メッセージにより言語の指定を削除することが推奨されます。この推奨事項には従わないでください。フィルタ処理されたクエリを実行する場合は、言語を指定する必要があり、WQL を指定する必要があります。これで以上です。

あともう 1 つ必要な変更点は、Enumerate メソッドの呼び出し時に生じます。この時点で、フィルタを表す変数 (strFilter) と言語を表す変数 (strDialect) と共に、リソースを表す変数 (strResource) も渡す必要があります。

Set objResponse = _
  objSession.Enumerate _
  (strResource, strFilter, strDialect)

試してみて結果をご覧ください。

クラスの特定のインスタンスとプロパティを返すという処理はどうなったのでしょうか。たとえば、コンピュータで実行中のすべてのサービスの Name と DisplayName だけを返すことに関心があるとします。そのときはどうすればよいのでしょうか。

このような場合は、Name と DisplayName だけが表示されるように XML を操作することができます。これは可能ですが、間違いなくやや注意が必要な作業です。この作業を簡単に行うのに必要な作業は、フィルタを割り当てる際に、これらのプロパティを指定するだけです。

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 の処理はどうなるでしょうか)。来月のコラムは、是が非でも購読しなければなりませんね。

Scripting Guys の小話

運が良ければ、おもしろくすばらしい WinRM の世界に取り掛かるには、これで十分でしょう。当然ながら、かつてドイツで普及していた "死体仮置場" に触れることなく、WinRM に関するコラムを終えることはできません。死体仮置場がある都市では、遺体はすぐに埋葬されませんでした。その代わり、遺体は、手足の指に多数のひもや針金が取り付けられた状態で暖かい部屋に置かれていました。もちろん、ほんの少しでも動いた場合は、警報が鳴って助けが呼ばれるという考えの基に、このような措置が取られていました。死体は、生存の望みが確実に絶たれて、もうどうしようもないことが明確になるまで、死体仮置場で保管されました。

言われてみると、死体仮置場は Scripting Guys チームに配属された場合によく似ていますね。もちろん、死体仮置場からの生還者は誰一人いませんでした。一方、Scripting Guys チームに配属された場合は....。

Dr. Scripto のスクリプト パズル

2007 年 6 月、Scripting Guys は、フロリダ州オーランドで開催された Tech•Ed 2007 カンファレンスに出席しました。ただカンファレンスに出席するだけでは満足できないため、楽しむことに決めました。それだけでなく、他の参加者も楽しんでもよいはずだと考えました。このアイデアから生まれたのが、『Dr. Scripto's Fun Book』です。この書籍には、スクリプトに関連したパズルや他のさまざまな情報を盛り込みました。私たちは TechNet Magazine と協力して (つまり、エキスポ ホールの彼らのブースの一角を譲ってもらうように説得して)、近くを通った人に Fun Book を配布しました。

後でわかったことですが、Fun Book は非常に好評でした (Dr. Scripto ボブルヘッド人形の人気には及びませんが、それに近いものがありました)。TechNet Magazine チームの日和見主義的なすばらしい人々は、Fun Book に対して別の見方をし、この Scripting Guys の成功を投資対象と考え、Scripting Guys が自分たちの成功に投資をすることができないと判断し、TechNet Magazine 用にパズルを作成するように依頼してきました。Scripting Guy の Jean Ross が少しだけ後ろを向いた隙に、Scripting Guy の Greg Stemp は「もちろんです、やりましょう」と承諾しました。それで、「Dr. Scripto のスクリプト パズル」というセクションを設けることになりました。がんばってください。

スクリプトの大移動

このパズルでは、上部セクションにあるすべての文字を解読して (VBScript の) スクリプトを作成します。でも心配しないでください。すべてを解読する必要はありません。1 列ずつ解読すれば問題ありません。上部セクションの各列の文字は、下部セクションの空白になっている同じ列のボックスに挿入します。次に例を示します。

ご覧のとおり、1 列目には、S、C、T という文字があります。この 3 文字は、下部セクションにも含まれる文字ですが、その順序はわかっていません。ただし、すべての文字を適切な順序に並べ替えると、下部セクション (左から右に読みます) では、論理的な文字列になります。解決策を見てみましょう。

1 列目の S、C、T が、下部のセクションでは T、S、C という順に並べ替えられていることがわかります。これらの文字は "The Script Center" の各単語の最初の文字になります。実際のパズルの難易度はもう少し高くなります。文字列は、もう少し長くなり、最終結果が完全なスクリプトになるためです。

ヒント : 最終的なスクリプトでは、まずファイルへの完全なパスを指定し、ファイル名を解析して表示します。

健闘をお祈りします。

ANSWER:

Dr. Scripto のスクリプト パズル

解答 : 「スクリプトの大移動」、2007 年 11 月

このパズルでは、各列の文字を下部セクションの適切なボックスに移動して、下部セクションの内容がスクリプトになるようにする必要があります。スクリプト自体は次のとおりです。

name = "C:\Scripts\Test.txt"
arr = Split(name, "\")
index = Ubound(arr)
Wscript.Echo "Filename: " _
& arr(index)
        

パズルのグリッド上では、次のようになります。

Microsoft Scripting Guys は、マイクロソフトの仕事をしています、というよりもマイクロソフトにより雇われています。野球をプレイしたり監督したり観戦したり (または他のさまざまな活動を) しているのでない限り、彼らは TechNet スクリプト センターを運営しています。詳細については、www.scriptingguys.com を参照してください。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; 許可なしに一部または全体を複製することは禁止されています.