Scripting Guy 為您解答問題

Hey, Scripting Guy!

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

資源

如何設定 Active Directory 帳戶讓密碼永遠不過期?

Hey, Scripting Guy! Question

嗨,Scripting Guy!如何設定 Active Directory 帳戶讓密碼永遠不過期?

        -- BB

Hey, Scripting Guy! Answer

BB,你好。開始以前,我們有個問題要問:你同不同意第 22 條軍規是有史以來最偉大的四本小說之一?我們之所以問這個問題,是因為 Scripting 小子最近上英文課的時候,老師要求他從一份書單中選擇一本書來閱讀。「嗨,Scripting 老爸!」他說。「你讀過這些書嗎?這裡面有哪一本書好看嗎?」

「天哪!Scripting 小子!」Scripting 老爸回答。「書單上有第 22 條軍規欵!第 22 條軍規是有史以來最偉大的四部小說之一。人人都知道。」

「好吧,那我就看這本吧!」Scripting 小子回答。

當然,從此以後,Scripting 老爸耳根子就永遠不得清淨,抱怨一句接一句簡直就是沒完沒了:

  • 「這本書有夠怪的!」

  • 「這本書根本就沒道理。」

  • 「我還以為你說這是一本書咧!」

  • 「都是你啦!是你的錯!」

https://technet.microsoft.com/en-us/scriptcenter/dd793612.aspx

附註:其實最後一句抱怨跟第 22 條軍規完全無關,那只是 Scripting 老爸每天都會聽到的標準埋怨。

為了給他點顏色瞧瞧,讓他知道厲害!Scripting 老爸到處尋找志同道合的夥伴,認同第 22 條軍規是有史以來最偉大的四部小說之一。你會支持 Scripting 老爸嗎?BB。好啦!看來不給點甜頭不行,給你一支指令碼怎麼樣?這支指令碼能夠設定 Active Directory 使用者帳戶,讓帳戶密碼永不過期:

Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000
 
Set objUser = GetObject("LDAP://cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com")

intUserAccountControl = objUser.Get("userAccountControl")
 
If Not objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then
    objUser.Put "userAccountControl", _
        objUser.userAccountControl XOR ADS_UF_DONT_EXPIRE_PASSWD
    objUser.SetInfo
End If

你說什麼?「條件還不夠好?」哇!你還真是個強硬不妥協的談判對手啊,BB!我看這樣好了:我們先來解釋這支指令碼如何運作,怎麼樣?就這麼說定嘍?好,就這麼辦。

如你所見,指令碼一開始先定義常數 ADS_UF_DONT_EXPIRE_PASSWD,然後為這個常數指定十六進位值 &h10000。重新設定帳戶時會需要這個常數,以便讓帳戶密碼永不過期。

定義常數之後,我們要連線到 Active Directory 中的 Ken Myer 使用者帳戶。因為 Ken 有一個 CN 等於 Ken Myer,也因為他的帳戶是位於 Fabrikam.com 的 Finance OU 中,程式碼必須以如下方式連線至該帳戶:

Set objUser = GetObject("LDAP://cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com")

這下怪的地方來了 (只是有一點怪,不是很怪啦)。是這樣的,其實決定密碼是否過期的 Active Directory 屬性是包含於 userAccountControl 屬性之中。userAccountControl 屬性是所謂的「位元遮罩」屬性:也就是說,它是包含多個值的單一屬性。這點很重要嗎?絕對重要。因為 userAccountControl 包含多個值,我們沒辦法直截了當地將它設定為,比方說,True 或 False。而是必須使用「位元邏輯」切換控制密碼有效期限的特定屬性。這只是事先預告一下,說明為什麼你將要看到的一些程式碼會看起來有點不太尋常,當然還不只是有點不尋常啦。

附註:關於位元邏輯,今天我們就不多說了;如需詳細資訊,請參閱 Microsoft Windows 2000 Scripting Guide (英文) 的本節

下一步,我們要判斷帳戶是否尚未過期的密碼,畢竟如果 Ken 已經有尚未過期的密碼,我們就不必多此一舉了,對不對?我們運用位元邏輯,使用下列這行程式碼來判定「密碼尚未過期」屬性 (以常數 ADS_UF_DONT_EXPIRE_PASSWD 表示) 是不是還沒 啟用 (請注意我是用是不是還沒這樣的句法):

If Not objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then

我們剛剛已經說過了,userAccountControl 屬性其實是由一些不同的屬性值組成,暫時就將它們當作好像控制台上的參數。在這裡我們所做的只是查看是否已開啟密碼過期參數而已 (還是以常數 ADS_UF_DONT_EXPIRE_PASSWD 來表示)。如果已開啟參數,我們就沒事了;如果尚未開啟,就必須將它開啟。位元邏輯常搞得人暈頭轉向的,尤其是乍看之下最難懂。但是,至少在這個範例中,基本概念是很簡單的:我們採用個別參數 (屬性),不是開啟 (啟用它) 就是關閉 (停用它)。

下面兩行程式碼就是執行這項作業。在第一行中,我們是使用 Put 方法,變更本機快取中的 userAccountControl 值。(這個本機快取到底是怎麼回事?如果你不確定,請參閱這個 指令碼猜謎解答 (英文),取得詳細資訊。)請注意,這裡必須傳遞兩個參數給 Put 方法:

  • userAccountControl 是我們要修改的屬性。

  • objUser.userAccountControl XOR ADS_UF_DONT_EXPIRE_PASSWD 是「切換」「密碼尚未過期」屬性值的位元程式碼。我們只是想說:如果以常數 ADS_UF_DONT_EXPIRE_PASSWD 表示的參數 (屬性) 已開啟,則將它關閉;如果已關閉,則將它開啟。這項作業很容易,因為 XOR 運算子只是將位元值切換為開或關而已;這就是為何必須確認 Ken Myer 的帳戶目前確實沒有永不過期的密碼。如果它已經有不過期的密碼,XOR 會切換該值,而給它過期的密碼。

懂了吧?有時候我們確實知道自己在幹什麼,可不是胡搞瞎稿。

在下一行我們要呼叫 SetInfo 方法,將變更寫回 Active Directory,這樣整個程序就完成了。

當然,很多人可能會更有興趣走另外一條路,也就是,考慮到密碼永不過期的情況,然後進行設定,以便讓密碼確實過期。下面的指令碼就是執行這項作業,查看是否已啟用「密碼永遠不會到期」屬性,若已啟用,則加以停用 (同樣地,使用 XOR 只是切換值而已):

Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000
 
Set objUser = GetObject("LDAP://cn=Ken Myer, ou=Finance, dc=fabrikam, dc=com")

intUserAccountControl = objUser.Get("userAccountControl")
 
If objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then
    objUser.Put "userAccountControl", _
        objUser.userAccountControl XOR ADS_UF_DONT_EXPIRE_PASSWD
    objUser.SetInfo
End If

你說怎麼樣?BB:這樣夠不夠?你會不會投票支持第 22 條軍規是有史以來最偉大的四本小說之一?那你是答應嘍?!

附註:要是您覺得好奇,清單上的另外三本書 - 人人都知道 - 就是:《永不讓步》、《獵人之夜》和《老人與海》。啊!對了!我們本來也想在書單中加入《火腿加綠蛋》,只是我們想,這本書好像不算是小說。不過倒是本蠻不錯的書。