嗨,Scripting Guy!只要 5 分錢...就能為您回答 OU 相關問題

Microsoft Scripting Guy

下載本文程式碼: HeyScriptingGuy2007_03.exe (151KB)

問:如何才能顯示出對話方塊,好讓我從 Active Directory 中選取 OU?

是這樣的, 如果每一次有人向我們提出此問題,Scripting Guy 可以收五分錢,我們應該可以獲利不少 -- 其實算一算一共只能收到 $37.15 啦。但是如果是針對每一個「想要」提出此問題,只是沒有機會直接詢問的人,都給我們五分錢,那就真的發了 -- 不過金額一點也不重要。畢竟我們不是為了錢,才成為 Scripting Guy。我們之所以成為 Scripting Guy,是為了藉由幫助大家更快速、簡便的進行系統管理工作,而從中獲得成就感。

附註: 嚴格來說,我承認我們的確是為了錢才擔任 Scripting Guy 的工作啦。但是經理這麼告訴我們:「你們的確可以做大事、賺大錢,但前提是必須願意非常努力工作,堅持只做高品質的東西才行」。於是我們就下定決心,相信金錢並不代表一切。

反正也無所謂。重點是,許多人想知道如何顯示出對話方塊,以便能選取 OU,然後利用指令碼連接到該 OU。最近收到一封電子郵件中寫到,「你們已經說明如何顯示出可選擇資料夾的對話方塊,也告訴我們如何顯示出可選擇檔案的對話方塊。但是你們為什麼從不解說如何顯示出可從 Active Directory® 選取 OU 的對話方塊?」

這個嘛,首先說明我們的確已經教過大家如何顯示出可選取資料夾的對話方塊,範例就在 這裡。我們也說明過如何顯示出可選取檔案的對話方塊,不相信的話,請造訪網址 microsoft.com/technet/scriptcenter/resources/qanda/jan05/hey0128.mspx。這兩篇文章皆已受到認可,而大家也將這些技巧運用在指令碼中。這樣說來,我們為何還不告訴大家如何顯示出可從 Active Directory 選取 OU 的對話方塊?這是不是 Microsoft 的某種陰謀或詭計?

當然不是這樣的。(不過...所有搞陰謀的人都會這樣回答,不是嗎?)事實上,我們之所以還沒教大家如何顯示從 Active Directory 選取 OU 的對話方塊,其實是有原因的:這種對話方塊根本不存在。就像是棒球場上說的,看不到的球無法打擊。而編寫指令碼的說法則是,不存在的東西無法顯示。

我們本月的專欄就寫到這裡。下回見。

沒這麼好的事!TechNet Magazine 的編輯說,專欄不可能就這樣結束。他們說,「如果真的沒有這種對話方塊,那該怎麼辦?」「拜託,你們是 Scripting Guy 耶,難道不能建立一個對話方塊來解決這個問題嗎?我們還以為 Scripting Guy 可以解決所有指令碼的問題。」

毫無疑問的,TechNet Magazine 的編輯都被嚴重誤導了。可以解決所有指令碼的問題?並不是這麼一回事。事實上,我們這些 Scripting Guy 只有解決一種指令碼問題的能力。

不過幸好這唯一的能力,就是建立對話方塊,以便讓您從 Active Directory 選取 OU。請參閱 [圖 1]

沒錯,這的確是一串很長的指令碼。但您應該聽過這句話:要煎蛋餅就得打破雞蛋 (天下沒有白吃的午餐)。同樣的,要建立自訂對話方塊就得打破一些雞蛋 (專欄寫到一半有點餓了,所以停下來吃點心)。現在滿足了口腹之慾,就要來看看能否清楚說明整個運作方式。

在這個指令碼中,我們使用 Internet Explorer® 物件模型,建立虛擬對話方塊。我們要建立 Internet Explorer 執行個體,從 Active Directory 取得 OU 集合,然後在 Internet Explorer 視窗的清單方塊中,顯示這些 OU。我們會等到使用者選取 OU 之後,再取得選取項目的 ADsPath、解除「對話方塊」,然後再繼續執行。

附註:這是否會成為史上最花俏、美麗的對話方塊?如果對您而言,「花俏和美麗」代表連 [確定] 或 [取消] 按鈕都沒有的極簡風格,答案就是肯定的。不過以我們的看法,這裡的訴求只是要提供最基本的基礎架構。若您希望美化或修改對話方塊,請自行發揮。

(天哪,如果每次回答「不好意思,您得自行發揮」都能拿到五分錢,我們就真的會變成有錢人。請將捐款寄給 The Scripting Guys,並由 TechNet Magazine 代收。)

為了讓我們的說明能夠容納於已分配的空間,我們必須先快速瀏覽一些事項。舉例而言,對於下列程式碼區塊,我們只能說它會建立 350 x 400 像素的 Internet Explorer 執行個體,如此一來,便隱藏了位址列和狀態列:

Set objExplorer = CreateObject( _
    "InternetExplorer.Application")

objExplorer.Navigate "about:blank"   
objExplorer.ToolBar = 0
objExplorer.StatusBar = 0
objExplorer.Width= 350
objExplorer.Height = 400 
objExplorer.Left = 400
objExplorer.Top = 400
objExplorer.Visible = 1             

當然這些都是為了提供我們一個空白的 Internet Explorer 視窗。為了取得網域中的 OU 清單,我們需要先搜尋 Active Directory。我們無法在此詳細解釋 Active Directory 的搜尋方式;如需相關資訊,請參閱 Script Center 中的兩篇式連載 (microsoft.com/technet/scriptcenter/resources/tales/sg0405.mspx)。我們只能告訴您這是我們在 fabrikam.com 網域中,用於擷取每個 OU 名稱和 ADsPath 的程式碼:

objCommand.CommandText = _
    "SELECT Name, ADsPath FROM 'LDAP://DC=fabrikam,DC=com' WHERE objectCategory=
    'organizationalUnit' ORDER BY Name"

為了讓您更方便使用,我們還將 OU 依名稱字母排序。這就是 ORDER BY Name 子句的目的 (別客氣;畢竟我們人生的目的,就是為大眾服務)。

呼叫 Execute 方法時,會取得 fabrikam.com 所有 OU 組成的資料錄集。這意味著下一步就是要在清單方塊中顯示出每個 OU。

那麼究竟該怎麼做?首先,我們需要在記憶體中建立整個清單方塊。初學者或許不太了解,這個意思是使用此程式碼行,將 <SELECT> 標籤儲存在名為 strHTML 的變數中:

strHTML = "<select size = '20' name='OUList' style='width:300px'>"

這行程式碼的功用到底是什麼?其實我們只是建立標準的 HTML 清單方塊 (利用 <SELECT> 標籤來達到目的)。在建立的過程中,我們將清單方塊命名為 OUList,且設定為每次顯示 20 個項目,並為 300 像素 (300px) 寬。如果您略懂 HTML,應該頗為熟悉上述程式碼。

接下來,我們需要增加一些項目 (也就是 OU) 到清單方塊中。巧的是,我們的資料錄集恰好是由網域中每個 OU 的資訊所組成。因此,我們可以設定 Do Until 迴圈,於整個資料錄集之中循環,擷取資訊,然後將每個 OU 加入清單方塊。在迴圈裡,我們使用下列程式碼 (再次說明,這是在清單方塊中新增項目的標準 HTML) 來新增每個 OU,設定項目以便於清單中顯示 OU 名稱,而且若您按一下清單方塊中的 OU,ADsPath 就會傳送到指令碼中:

strHTML = strHTML & "<option value= " & _
    Chr(34) & objRecordSet.Fields
    ("AdsPath").Value & Chr(34)
strHTML = strHTML & ">" & objRecordSet.
    Fields("Name").Value

為何要將 ADsPath 傳送給指令碼?很簡單。假設我們傳送的是 OU 名稱,而該名稱假定為 Finance,則會難以繫結到該 OU;畢竟 Finance 本身並非有效的 ADSI 繫結字串。然而,如果我們傳回 ADsPath (LDAP://ou=Finance,dc=fabrikam,dc=com),就可以輕鬆繫結。這是因為 ADsPath 完全符合我們尋找和連結到 Active Directory 物件的需求。

附帶一提,我們之所以在清單方塊中顯示名稱,是因為假設您的 OU 名稱是唯一的。但不一定都是如此;例如 OUs North America\Research and Europe\Research 也有相同的名稱 (Research)。如果您的 OU 名稱重複,最好在清單方塊中使用不同的屬性來代替,例如 ADsPath 或 distinguishedName。這必須由您自己來決定。(鉲鏘!又是五分進帳!)

對了,記憶體中的清單方塊還沒建立完成:每個加入方塊的項目都會加入變數 strHTML。這些都在計劃之中:將整個清單方塊的程式碼儲存到變數 strHTML,然後使用該變數值,即可實際將清單方塊加入 Internet Explorer 的執行個體中。

待所有 OU 加入完成之後,我們便使用下列程式碼來表示清單方塊的結束:

strHTML = strHTML & "</select>"

此時,strHTML 中已包含所有建立清單方塊所需的 HTML 標記,最棒的是還有一個清單方塊,其中每個項目皆代表 Active Directory 的 OU。也就是說,我們現在可以將 strHTML 的值,指派給 Internet Explorer 文件的 InnerHTML 屬性:

objExplorer.Document.Body.InnerHTML = strHTML

這會傳回一個清單方塊,其中顯示所有網域中的 OU。

等等,先別走啊;我們還沒做完呢。舉例來說,我們還需要一些程式碼,才能暫停指令碼直到使用者在對話方塊中選取 OU 為止;若沒有這些程式碼,雖然仍可顯示清單方塊,但不論使用者是否進行選取動作,指令碼仍會繼續執行。那就糟糕了!為了要避免發生這種情況,我們可以使用以下程式碼區塊:

Do While objExplorer.Document.Body.All.OUList.Value = ""
    Wscript.Sleep 300
Loop

上述程式碼的作用,是不斷重複檢查清單方塊的值 (如果您還記得,我們之前已命名為 OUList,這也是其中一位 Scripting Guy 為女兒取的名字)。如果值為空字串 (表示未選取任何項目),只要暫停指令碼 300 毫秒,然後繼續迴圈後,再檢查一次。這樣的動作會繼續進行:a) 直到永遠;b) 直到使用者選取清單方塊的項目為止;或者 c) 直到使用者關閉 Internet Explorer 視窗為止。

讓我們假設使用者在清單方塊中選取某個 OU。如果是這種情況,我們便取得該值 (您應該還記得,這是 OU 的 ADsPath) 並指派給變數 strTargetOU:

strTargetOU = objExplorer.Document.Body.All.OUList.Value

接著使用 Quit 方法來解除 Internet Explorer 的執行個體,如下所示:

objExplorer.Quit

此時已經快要大功告成。我們先檢查 strTargetOU 是否等於空字串:

If strTargetOU = "" Then
    Wscript.Quit
End If

如果是,就表示使用者未選取 OU 即關閉 Internet Explorer;此時我們使用 Wscript.Quit 方法來中止指令碼 (我們假設如果使用者不選擇 OU,就表示他不打算執行指令碼)。然而,若 strTargetOU 不等於空字串,我們就傳回變數值:

Wscript.Echo strTargetOU

當然,在實際指令碼中,您可以直接在 Active Directory 中繫結到該 OU,而非只是單純回應 ADsPath。不過您應該知道標準答案 -- 至少是我們的標準答案:這個就得靠您自行發揮了。

如先前所述,以及 [圖 2] 所示,這並非很花俏的對話方塊,但絕對可以使用,而且比手動輸入 ADsPath (假設您知道 ADsPath) 更加簡單。此外,這還可以讓您有機會自訂程式碼和對話方塊,以符合自己的需求。

Figure 2 A simple script dialog

Figure 2** A simple script dialog **

現在,但願我們所寫過有關如何顯示對話方塊,以便從 Active Directory 選取 OU 的每篇專欄,都能換來五分錢。畢竟這樣我們就能拿到比 TechNet Magazine 平時多五分錢的酬勞。

對了,我們可不是在抱怨喔。

Microsoft Scripting Guy 的工作是...沒錯,就是 Microsoft 聘請的員工。在比賽、訓練、看棒球賽 (以及其他各種活動) 之餘,他們也負責管理 TechNet Script Center。請造訪他們的網址 www.scriptingguys.com

© 2008 Microsoft Corporation and CMP Media, LLC. 保留所有權利;未經允許,嚴禁部分或全部複製.