嗨,Scripting Guy!

Hey,Scripting Guy!

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

今天的問題:我能使用指令碼鎖定工作站嗎?


我能使用指令碼鎖定工作站嗎?

嗨,Scripting Guy!我知道如何使用指令碼關閉電腦,甚至知道如何使用指令碼將使用者登出。但是,我到底該怎麼做,才能使用指令碼「鎖定」工作站?

-- TO-R

TO-R,您好。相信您對 Win32_OperatingSystem WMI 類別的 Win32Shutdown 方法已經十分熟悉;這個方法能讓您關機、重新開機,或是將目前的使用者登出。舉例來說,您可以使用以下指令碼將電腦關機:
Const SHUTDOWN = 1
strComputer = "."
Set objWMIService = GetObject_
    ("winmgmts:{impersonationLevel=impersonate,(Shutdown)}\\" & _
        strComputer & "\root\cimv2")
Set colOperating Systems = objWMIService.ExecQuery _
    ("Select * from Win32_OperatingSystem")
 
For Each objOperatingSystem in colOperatingSystems
    objOperatingSystem.Win32Shutdown(SHUTDOWN)
Next

然而,您卻無法使用 Win32Shutdown 方法鎖定電腦;說得再明白一點,WMI 中「沒有任何方法」可以鎖定電腦。事實上,針對使用指令碼鎖定電腦一事,我們惟一能想到的方法就是撰寫一個新的指令碼,純粹只是使用 Rundll32.exe 呼叫 user32.dll 的 LockWorkStation 方法:

On Error Resume Next
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "%windir%\System32\rundll32.exe user32.dll,LockWorkStation"

這個方法對本機電腦十分有用,但如果您想要鎖定的是遠端電腦,可能就不太管用了;因為您無法在執行 Rundll32.exe 時指定遠端電腦的名稱。不過沒關係:如果以上指令碼只能以本機方式執行,那麼我們只須要確定它是在「遠端電腦」上以本機方式執行即可。這個方法可行嗎?當然可以。

首先,請將原本的指令碼 - 也就是實際用來鎖定電腦的那個指令碼 - 另存為 Lock_workstation.vbs,為求簡單明暸,將它儲存至 C:\Scripts 之下。接著,請建立第二個指令碼 - 名稱由您自行決定 - 並將以下這段程式碼貼入其中:

Const OverwriteExisting = TRUE
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.CopyFile "C:\Scripts\lock_workstation.vbs", _
    "\\atl-ws-01\C$\Scripts\", OverWriteExisting
strComputer = "atl-ws-01"
Set objWMIService = GetObject _
("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
Error = objWMIService.Create _
    ("cscript c:\scripts\lock_workstation.vbs", null, null, _
        intProcessID)

這個程式碼的作用何在?這個程式碼一開始先是將我們的第一個指令檔 - C:\Scripts\Lock_workstation.vbs - 複製到遠端電腦 atl-ws-01 的 C:\Scripts 資料夾之下。這裡有兩件事是我們必須記住的。第一,這個指令碼假定您並未停用遠端電腦上的系統管理共用 (C$);第二,它假定 C:\Scripts 這個資料夾已經存在於遠端電腦上 (當然,沒有任何理由非得將這個檔案複製到 C:\Scripts 之下不可;您也可以將它複製到自己想要的任何資料夾中)。

這段指令碼的第一部份執行完畢之後,Lock_workstation.vbs 檔案便會存放於遠端電腦上的 C:\Scripts 資料夾之下。在這個指令碼的第二部份中,我們將會連線至遠端電腦上的 WMI 服務,並接著呼叫 Create 方法 (這個方法恰好是 Win32_Process 類別的一部份)。而我們到底要使用 Create 方法來做什麼呢?其實不過就是執行 Lock_workstation.vbs 這個指令碼罷了。然而,最棒的地方在於,Create 方法會讓這個指令碼在「遠端電腦」上執行。因為指令碼是在遠端電腦上執行的,Rundll32.exe 可以運作,而遠端電腦也會被鎖定。自己試試看,相信您就會明白了。

注意:但會有一個問題:這個指令碼是在登入遠端電腦之使用者的安全性內容之下執行的。如果該名使用者沒有鎖定電腦的權限,這個指令碼便會失敗。

當然,這至少將會導致二個問題。先來看看比較簡單的問題:您是否有辦法寫出一段將工作站「解除鎖定」的指令碼?就我們所知,這是辦不到的;事實上,針對將工作站解除鎖定一事,我們惟一知道的方法就是由某人親自走到電腦前方,按下 Ctrl-Alt-Delete 鍵,然後再登入。往好處想,至少您仍能對一部已遭鎖定的工作站執行指令檔;畢竟一部遭到鎖定的電腦仍處於啟動及執行狀態。

第二個問題較為刁鑽:有沒有任何方法,可以判斷一部電腦是否已經「確實」遭到鎖定?答案是,沒有萬無一失的方法;至少我們並不知道有這種方法。但是,這裡有個指令碼「可能」行得通,只要符合以下條件:

1. 已將遠端電腦設定為使用螢幕保護裝置。

2. 每次執行螢幕保護裝置時,即自動鎖定工作站。

3. 「等候逾時」期間已過,且螢幕保護裝置已確實在執行 (例如,根據預設,螢幕保護裝置必須等到電腦已經停止作用 - 或遭到鎖定 - 十分鐘之後才會啟動)。

如果上述條件全部符合,您就能透過下面這個指令碼得知電腦是否已經遭到鎖定;它的做法是先擷取螢幕保護裝置的執行檔檔名,再檢查該執行檔是否正在執行 (藉由查看 Win32_Process 類別的例項)。如果螢幕保護裝置正在執行,則根據定義,電腦一定已經遭到鎖定:

On Error Resume Next
HKEY_CURRENT_USER = &H80000001
strComputer = "crowtrobot2"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
strKeyPath = "Control Panel\Desktop"
ValueName = "ScrnSave.exe"
objWMIService.GetStringValue HKEY_CURRENT_USER, strKeyPath, ValueName, strValue
strValue = Replace(strValue, "\", "\\")
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery _
    ("Select * From Win32_Process Where ExecutablePath ='" & strValue & "'")
If colItems.Count > 0 Then
    Wscript.Echo "The computer is locked."
Else
    Wscript.Echo "The computer is not locked."
End If

請注意,這段指令碼其實沒有它看起來那麼複雜;其中有一行較為詭譎的程式碼:

strValue = Replace(strValue, "\", "\\")

這行程式碼是必要的,因為 ExecutablePath 的格式類似於:

C:\WINDOWS\System32\logon.scr

然而,當您在 WMI 查詢中使用路徑時,所有斜線字元均須重複輸入兩次,例如:

C:\\WINDOWS\\System32\\logon.scr

而這正是 Replace 函數的作用:將每個 \ 取代為 \\。

如同先前說過的一般,這段指令碼絕非萬無一失,但它是我們目前為止所能想到最好的方法。如果您還想要讓它更保險一點,您可以繼續加入程式碼,以確保電腦確實使用了螢幕保護裝置 (ScreenSaverActive),同時確保螢幕保護裝置每次執行時,就會自動將工作站鎖定 (ScreenSaverSecure)。如果您想要將這段指令碼修改到最棒的程度,您甚至可以判斷出螢幕保護裝置的等候逾時值 (ScreenSaverTimeout),然後將指令碼暫停同等的時間,接著再查看螢幕保護裝置是否正在執行。

當然,即使您做了這麼多努力,某些問題還是無法解決的。畢竟,這個程式碼無法分辨「電腦遭到鎖定」以及「尚無使用者登入電腦」這兩種情況有何不同;它只能告訴我們螢幕保護裝置是否正在執行。是否有方法可以判斷電腦是否已經有使用者登入了?坦白說,我們並不確定,但這是我們目前正在研究的議題。


如需詳細資訊

查看嗨,Scripting Guy!- 過往文件

 

回到頁首 回到頁首