Scripting Guy 為您解答問題

Hey, Scripting Guy!

歡迎使用 TechNet 專欄,Microsoft Scripting Guy 會在此為您解答有關系統管理指令碼的常見問題。您有關於系統管理指令碼方面的問題嗎?請將電子郵件傳送到 scripter@microsoft.com。我們無法保證能夠逐一回答每個問題,不過我們會盡力而為。

資源

如何讓使用者從印表機清單中選擇預設印表機?

Hey, Scripting Guy! Question

嗨,Scripting Guy!在登入指令碼中,如何讓使用者從電腦上已安裝的印表機清單中選擇預設印表機?

        -- JD

Hey, Scripting Guy! Answer

JD,您好。您知道嗎?有許多人來信說道:「嗨,Scripting Guy!您為什麼將自己限制在系統管理指令碼的範圍內?您難道不知道自己有能力讓世界更美好嗎?」

老實說,有時候我們 - 什麼?有多少人來信表示我們有能力讓世界更美好?其實,計算這種東西並非我們的行事風格。不過,我們確信 -- 嘿,您知道嗎?談到這類事情時,數字真的沒有太大意義。重點在於即使我們將焦點完全放在系統管理指令碼,我們仍然具有影響力,而且可以讓世界更美好。

舉一個現成的例子?今年的「超級杯足球聯賽」之後,我們針對比賽期間播放的其中一則廣告做了特殊註解。在這則廣告中,有一個為美國汽車製造業者工作的機器人犯了小錯誤,然後就立即被開除 (有趣的是,Microsoft 也有完全相同的原則。但是,所幸沒有任何 Scripting Guy 曾經錯)。在一些新工作面試失敗之後,機器人發現他 (還是她?) 站在橋上,準備跳下並結束一切。不過,在千鈞一髮之際,他 (還是她?) 醒了過來,發現這只是一場惡夢。

如同我們在二月份的專欄提到,Scripting Guy 對這則廣告所傳達的訊息有點困惑。我們能想出的最好解釋,就是汽車製造業者想要告訴員工們一點:如果您犯了錯,我們就會開除您,而且如果您被開除,您可能就會自殺。這點還真是激勵人心且令人振奮。我們認為廣告所傳達的訊息很奇怪,尤其是在過去幾年來美國汽車製造業者已經解雇了大量員工的情況下更是如此。

我們知道讀者在想什麼:這傳達的訊息奇怪,對吧?但是,即使那個人 Scripting Guy,區區一人之力能怎麼辦?好吧,下面是某個人對這件事的對策。昨晚,撰寫本專欄的 Scripting Guy 在「超級杯足球聯賽」之後第一次看到該則機器人廣告。而且,您知道嗎?廣告結尾已經變了。在新的版本中,機器人沒有站在橋上,準備跳下自殺。這只代表一件事:汽車製造業者讀過《嗨,Scripting Guy!》專欄、瞭解廣告方式的錯誤,然後變更了廣告。

好吧,事實上,在新的版本中,機器人看到一個相似的機器人被粗魯地丟進垃圾堆。但是,至少他們往正確的方向邁進一步了。

這則故事的寓意 (是的,所有《嗨,Scripting Guy!》的故事在某方面都具有寓意) 在於一個人可以改變現況,一個人確實有能力讓世界更美好。或許,您可以將虛構的機器人從自殺的想法中拯救出來,讓世界更美好。如果要更進一步,您可以想出一種方式,讓使用者從電腦上已安裝的印表機清單中選擇預設印表機,來改變現況:

Script Center
<SCRIPT Language="VBScript">

    Sub Window_Onload
        strComputer = "."

        Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
        Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")

        For Each objPrinter in colPrinters
            strPrinter = objPrinter.Name
            Set objOption = Document.createElement("OPTION")
            objOption.Text = strprinter
            objOption.Value = strPrinter
            AvailablePrinters.Add(objOption)
        Next
    End Sub

    Sub SetDefault
        strPrinter = AvailablePrinters.Value
        Set WshNetwork = CreateObject("Wscript.Network")
        WshNetwork.SetDefaultPrinter strPrinter
        Msgbox strprinter & " has been set as your default printer."
    End Sub

</SCRIPT>

<select size="5" name="AvailablePrinters"></select><p>
<input type="button" value="Set as Default" onClick="SetDefault">

讓我們談一下目前擁有的條件。我們目前擁有的是 HTA (HTML 應用程式)。HTA 只是一種讓指令碼作者建立圖形化使用者介面的方式。它們基本上就是設計成在本機電腦以外執行的網頁 (帶有 .hta 副檔名)。(是的,我們知道這種說明太好。如果您需要 HTA 的詳細資訊,請參閱 HTA 開發人員中心 (英文))。VBScript 沒有可建立圖形化使用者介面的原生方法。雖然這是個問題,但是我們可以透過建立 HTA,然後從登入指令碼內部呼叫該 HTA,藉以解決該問題。

而這就是我們在此的做法:我們建立了一個 .hta 檔,然後要將這個檔案複製到每部電腦上 (但是這沒有問題,登入指令碼也可以這樣做)。在登入指令碼內部,我們接著需要兩行程式碼來顯示此 HTA,然後讓使用者選取預設印表機:

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "C:\Scripts\Test.hta"

那麼,當這個 HTA 顯示時,使用者將看見什麼內容?他們將看見最基本的內容,像下面這樣:

HTA

是的,我們很了解。但是,如果您想讓它更好看,就要自己動手。

既然您瞭解了基本案例,接下來我們就深入探討一下 HTA 本身。就 HTML 標記而言,其實沒有太多內容:我們所擁有的只有名為 AvailablePrinters 的清單方塊 (使用 <SELECT> 標記新增至 HTA ) 和按鈕 (<INPUT TYPE = "BUTTON">):

<select size="5" name="AvailablePrinters"></select><p>
<input type="button" value="Set as Default" onClick="SetDefault">

這裡的想法是,您從清單方塊中選取印表機,然後按一下按鈕。如此一來,您所選取的印表機將會設定成預設印表機。

沒錯:就跟變魔術一樣。

如果您已經完成許多 HTML 標記,可能會發現我們的清單方塊是空的,它並未包含單一安裝的印表機。為什麼?好吧,請記住,我們的完整想法是:我們需要一個動態清單方塊。每次 HTA 啟動時,該清單方塊就會填入上述電腦中安裝的印表機 (而且只有這些印表機)。我們應該要怎麼?當然是使用下面的副程式:

Sub Window_Onload
    strComputer = "."

    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")

    For Each objPrinter in colPrinters
        strPrinter = objPrinter.Name
        Set objOption = Document.createElement("OPTION")
        objOption.Text = strPrinter
        objOption.Value = strPrinter
        AvailablePrinters.Add(objOption)
    Next
End Sub

不用說,這是名為 Window_Onload 的副程式。在 HTA (或網頁) 中,任何含有該名稱的副程式會在 HTA 開啟或重新整理時執行。在此副程式內部,我們首先要使用以下程式碼區塊來擷取本機電腦上安裝之所有印表機的集合:

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colPrinters = objWMIService.ExecQuery("Select * From Win32_Printer")

這很簡單,對吧?主要問題在於:我們要如何處理這個印表機集合?

一開始,我們先設定 For Each 迴圈來逐一處理集合中的每部印表機。接著,我們要針對每部印表機抓取 Name 屬性的值,然後將它儲存在名為 strPrinter 的變數中。然後,我們要直接執行下面這行程式碼:

Set objOption = Document.createElement("OPTION")

我們在此所做的就是建立 HTML Option 物件的執行個體。如名稱所示,這個物件代表清單方塊中的個別選項。建立「空白」選項之後,我們接著要將印表機名稱指派至選項的 TextValue 屬性:

objOption.Text = strPrinter
objOption.Value = strPrinter

在這裡稍微解釋一下,Text 屬性代表清單方塊中顯示的實際文字,而 Value 屬性則是指派至該選項的值。針對此特定清單方塊,我們讓 Text 和 Value 完全相同,但是它們不需要完全相同。例如,假設您有一個允許使用者選取美國各州的清單方塊。您就可以將選項的 Text 設定為 Washington。如此一來,使用者就會在清單方塊中看見名稱 Washington。不過在此同時,您可以將該選項的 Value 設定為 WA。如此一來,使用者就會在清單方塊中看見「易記」名稱,但您仍然可以在指令碼中使用正式郵遞區號縮寫。

在指派屬性值之後,我們接著要呼叫 Add 方法並將選項 (亦即,第一部印表機的名稱) 新增至清單方塊:

AvailablePrinters.Add(objOption)

然後,我們要對集合中的下一部印表機重複此程序。

Window_Onload 副程式會將本機電腦上安裝之所有印表機的名稱填入清單方塊中。為了讓其中一部印表機成為預設印表機,我們必須從清單方塊中選取印表機,然後按一下 [設成預設值] 按鈕。按一下按鈕會導致下列副程式執行:

Sub SetDefault
    strPrinter = AvailablePrinters.Value
    Set WshNetwork = CreateObject("Wscript.Network")
    WshNetwork.SetDefaultPrinter strPrinter
    Msgbox strPrinter & " has been set as your default printer."
End Sub

如您所見,我們在這個副程式中沒有設定太複雜的內容。一開始,我們從清單方塊中選取的項目抓取 Value,然後將該屬性指派至名為 strPrinter 的變數:

strPrinter = AvailablePrinters.Value

我們會使用下列兩行程式碼來建立 Wscript.Network 物件的執行個體,然後呼叫 SetDefaultPrinter 方法,以便讓選取的印表機成為預設印表機:

Set WshNetwork = CreateObject("Wscript.Network")
WshNetwork.SetDefaultPrinter strPrinter

接著,我們會顯示一則訊息,表示選取的印表機已經成為預設印表機。

這基本上就是我們的做法。不可否認,我們在此沒有設定任何錯誤處理,而且沒有提供明顯的方法,讓使用者在沒有選擇新預設印表機的情況下關閉對話方塊。同樣地,我們也可以讓它更複雜,例如以不同的顏色顯示目前預設印表機的名稱。但是,請想一想:如果我們做了所有工作,您可能會開始覺得沒有人需要您,並可能因此想要從橋上跳下或將自己丟在垃圾堆裡。這表示,我們沒有做的這些事情實際上都是為了您好。

您不必客氣。

那麼,Scripting Guys 接下來將處理哪些世界級的問題呢?呃,全世界的問題一定很多。不過,我們只會將眼光放在其中最重大的問題:也就是那些以男性...功能障礙...為訴求的廣告。雖然我們試著不要太假正經,不過您是否曾經看過這類廣告呢?請想像一下,當您在書店裡逛來逛去,只是想要找一本書時,但卻突然發現 - 呃,您知道我的意思。或者是當您想要在餐廳裡吃份三明治時,抬頭一看卻看見兩個老大不小、應該更懂分寸的人在互毆。何謂適時適地?請相信我:就某些事情而言,這句話永遠不適用。