1. 程式人生 > >WMI問題全解(Windows管理規範)

WMI問題全解(Windows管理規範)

問題 1:WMI 是什麼,它能幫我做什麼?

Windows 管理規範(Windows Management Instrumentation)是一項核心的 Windows 管理技術;使用者可以使用 WMI 管理本地和遠端計算機。WMI 通過程式設計和指令碼語言為日常管理提供了一條連續一致的途徑。例如,使用者可以:

• 在遠端計算機器上啟動一個程序。 

• 設定一個在特定日期和時間執行的程序。

 • 遠端啟動計算機。

 • 獲得本地或遠端計算機的已安裝程式列表。 

 • 查詢本地或遠端計算機的 Windows 事件日誌。

WMI 中的“Instrumentation”特指 WMI 可以獲得關於計算機內部狀態的資訊,這與汽車儀表盤獲得並顯示引擎的狀態資訊非常類似。WMI 對磁碟、程序、和其他 Windows 系統物件進行建模,從而實現“指示”功能。這些計算機系統物件採用類來建立模型,例如 Win32_LogicalDisk 或 Win32_Process; 如您所料,Win32_LogicalDisk 類用於建立在計算機上安裝的邏輯磁碟的模型,Win32_Process 類用於建立正在計算機上執行的任何程序的模型。這些類基於一個名為通用資訊模型(Common Information Model,CIM)的可擴充套件架構。CIM 架構是分散式管理任務組(Distributed Management Task Force)的一個公開標準(

http://www.dmtf.org).

WMI 的功能還包括事件觸發、遠端呼叫、查詢、檢視、架構的使用者擴充套件、指示等等。

問題 2: WMI 適用於那些平臺?

WMI 適用於所有最新版本的 Windows。WMI 附帶在 Windows Me、Windows 2000、Windows XP 和 Windows Server 2003 之中。

對於 Windows 98 和 Windows NT 4.0,可以訪問http://www.microsoft.com/downloads. 並搜尋“Windows Management Instrumentation (WMI) CORE 1.5 (Windows 95/98/NT 4.0)”。

注意:在 Windows NT 4.0 上安裝並執行 WMI 之前,需要首先安裝 Service Pack 4 或更高版本。

WMI 需要的其他軟體包括:

1. Microsoft? Internet Explorer 5.0 或更高版本。
 
2. Windows Script Host(WSH)。Windows 2000、Windows XP、Windows Server 2003、和 Windows Me 附帶的 WSH,而不是 Windows NT4 或 Windows 98 附帶的 WSH。您可以從以下地址下載 WSHhttp://www.microsoft.com/downloads. WSH 的最新版本—— 包括在 Windows XP 和 Windows Server 2003 之中——是 WSH 5.6。

問題 3:如果 WMI 向外界暴露特定的功能,我如何才能知道?

一旦熟悉了資訊的分類方式,使用者就可以方便地搜尋自己想要的類,並確定自己想要的功能是否存在。 請注意:為了完成一個特定的任務,您可能需要使用多個類。例如,假定您想要獲得一臺計算機的基本系統資訊。 儘管可以使用 Win32_OperatingSystem 類來獲得可用記憶體的相關資訊,但如果同時需要獲得關於計算機可用磁碟的資訊,您必須使用第二個類 Win32_LogicalDisk。請看問題為什麼我的指令碼可以在某個版本的 Windows 上執行,但在另外一個版本的 Windows 上卻不能執行? 想要知道 WMI 可以做什麼、不可以做什麼?

CIM Studio 是一種工具,使用者可以通過它瀏覽 Windows 2000 或更高版本平臺上的 WMI 類。想要進一步瞭解這個工具,以及其中包含的內容(CIM Studio 中包含一系列由 WMITools.exe 安裝的工具),請訪問http://www.microsoft.com 並搜尋關鍵字“WMI tools”。您也可以執行微軟不提供支援的 Wbemtest.exe 工具——安裝 WMI 的時候自動被安裝——來瀏覽 WMI 資料。

在 Windows XP 或 Windows Server 2003 上,使用者可以使用以下指令碼搜尋類名中包含特定關鍵字的類。 請將該指令碼儲存為一個名為 Search.vbs 的文字檔案然後執行,並指定想要搜尋的關鍵字。例如,想要搜尋名稱中包含 “service”的類,
請在命令提示行執行以下命令:

cscript search.vbs service

' Script for finding a class in WMI Repository
 
Set args = wscript.arguments
If args.Count <= 0 Then
    Wscript.Echo "Tool to search for a matching class in the WMI Repository. "
    Wscript.Echo "USAGE: <keywordToSearch> [<namespaceToSearchIn>]"
    Wscript.Echo "Example1: Cscript search.vbs service"
    Wscript.Echo "Example2: Cscript search.vbs video root\cimv2"
Else
    ' If no Namespace is specified then the Default is the ROOT namespace
    rootNamespace = "\\.\ROOT"
    keyword = args(0)
    If args.Count > 1 Then
        rootNamespace = args(1)
    End If   
    EnumNameSpace rootNamespace
    Wscript.Echo vbNewLine
End if
 
' Subroutine to recurse through the namespaces
 
Sub EnumNameSpace(parentNamespaceName)
 
Set objService = GetObject("winmgmts:" & parentNamespaceName)
 
Set collMatchingClasses = objService.Execquery _
    ("Select * From meta_class Where __class " & _
    "Like '%" & keyword & "%'")
If (collMatchingClasses.count > 0) Then
    Wscript.Echo vbNewLine
    Wscript.Echo vbNewLine
    Wscript.Echo "Matching Classes Under Namespace: " & parentNamespaceName
 
    For Each matchingClass in collMatchingClasses
        Wscript.Echo "    " & matchingClass.Path_.CLASS
    Next   
End if
 
Set collSubNamespaces = objService.Execquery _
    ("select * from __namespace")
For Each subNameSpace in collSubNamespaces
    EnumNameSpace subNameSpace.path_.namespace + _
        "\" + subNameSpace.Name
Next
 
End Sub

該指令碼只能執行在 Windows XP 或 Server 2003 之上,因為作為 WMI 查詢語言一部分的 LIKE 運算子只能用於這兩個平臺。

問題 4:如果 WMI 沒有提供我想要的功能,我應該怎麼辦?

使用者遲早會發現 WMI 無法完成有些自己想要的任務或者無法高效地完成。 在這種情況下,您應該首先檢查作業系統提供的其他指令碼技術是否可以提供該功能。 例如,ADSI(Active Directory Service Interfaces)可以幫助使用者管理 Active Directory;CDO(Collaboration Data Objects)提供了在指令碼中傳送電子郵件的功能。如果 Windows 作業系統沒有提供合適的指令碼介面,也許某些第三方的軟體可以提供您所需要的功能。

如果確實沒有這樣的指令碼介面,理論上講您可以編寫一個 WMI 提供者來提供相應的功能。不過,不能用指令碼語言來編寫 WMI;而必需使用 C++ 或 C#。關於這方面的更多資訊,請參閱 MSDN 的“Using WMI”(使用 WMI)部分,其中一些主題介紹瞭如何編寫典型的 WMI 提供者。如果您想要使用 .NET Framework 來編寫提供者,請在 MSDN 庫中搜索“Managing Applications Using WMI”(使用 WMI 管理應用程式)。

問題 5:在哪裡可以找到使用 WMI 的示例指令碼?

Microsoft Developers Network(MSDN)和 TechNet 都是獲得示例的好地方。以下是一些指向這些站點上的有用資源的連結:

Microsoft.public.windowsxp.wmi

Microsoft.public.windows.server.scripting

問題 6: 為什麼我的指令碼可以在某個版本的 Windows 上執行,但在另外一個版本的 Windows 上卻不能執行?

這個問題通常是由於新版本的 Windows 中引入了一些新的類、屬性、或方法,但較早版本的作業系統沒有包含它們。想要驗證可用性,請在 MSDN 中查詢 WMI 軟體開發工具包(SDK)中每個類的“Requirements”(要求)部分(http://msdn.microsoft.com/library/default.asp). 例如,Win32_PingStatus 類的“要求”中指定該類需要 Windows XP 或 Windows Server 2003。所以試圖在 Windows 2000 上訪問 Win32_PingStatus 類的指令碼將會導致“Class not found”(無法找到類)錯誤。

與此類似,一些 WMI 資料提供者,例如 SNMP Provider 要麼在所有作業系統上不可用,要麼不是 WMI 預設安裝的一部分。關於這些提供者的 SDK 主題都包含指向 “About WMI”(關於 WMI )部分的“Operating System Availability of WMI Components”(WMI 元件的作業系統要求)主題的引用。

想要獲得標準 WMI 提供者的列表,請參考“WMI Reference”(WMI 參考)下的“WMI Providers”(WMI 提供者)。

一般情況下,當一個新的提供者被新增到 Windows 的一個新版本中,它的功能在先前版本的 Windows 中不會提供。例如,由 Ping 提供者定義的Win32_PingStatus 類不會在 Windows 2000 中提供。因為這些新的提供者通常利用了 Windows 新版本中的某些功能,但這些功能在較早版本中並不存在。

問題 7:為什麼 WMI 操作返回一個錯誤?
在開始之前,請首先確認錯誤是否的確是一個 WMI 錯誤。WMI 錯誤編號從 8004xxxx 開始(例如 80041001)。您可以查詢 WMI 錯誤編號並返回程式碼,方法是訪問http://msdn.microsoft.com/library/default.asp 並搜尋“WMI Return Codes”(WMI 返回程式碼)。如果找不到需要的資訊,請嘗試在 MSDN 中搜索特定的錯誤編號。

如果在執行指令碼的過程中沒有返回任何錯誤編號,您可以檢視位於 %windir%\system32\wbem\logs 資料夾的 WMI 日誌檔案。如果很難判斷剛剛執行的指令碼返回的是什麼錯誤,請刪除所有日誌然後重新執行一次。這樣應該可以輕鬆找到與指令碼相關的錯誤。

如果在日誌檔案中找不到錯誤,您也許需要重新設定日誌的記錄等級。要獲得儘可能多的資訊,請將記錄等級設定為“詳細”(verbose)。如果作業系統是 Windows 2000、Windows NT 和 Windows Me/98/95,修改記錄等級之後需要重啟 WMI;對於 Windows XP 和 Windows Server 2003 則無需這樣。關於配置記錄等級的詳細資訊,請訪問http://msdn.microsoft.com/library/default.asp 並搜尋“Logging WMI Activity”(記錄 WMI 操作)。

錯誤也可能被記錄在 Windows 事件日誌中。檢視來源為 Winmgmt的事件。

在 Windows XP 或 Windows Server 2003 上,您可以使用 MSFT_WMIProvider 類來診斷提供者操作,例如提供者的載入和解除安裝、對查詢的響應、執行一個方法、等等。舉個例子,在提供者取消對一個查詢的響應之前,WMI 會生成 MSFT_WmiProvider_CancelQuery_Pre 類的一個例項。在取消發生之後會生成 MSFT_WmiProvider_CancelQuery_Post 類的一個例項。如果一段特定指令碼中的查詢操作失敗了,您可以編寫一段指令碼來等待這些事件類的例項被生成。如果監視到指令碼接收了一個事件,資料將會指出相關的 提供者、提供者的型別、正在被處理的查詢、以及相關的名稱空間。

以下是一段示例指令碼,用於診斷 Ping 提供者的問題。這段指令碼可以報告作為 Ping 操作組成部分的所有動作,例如提供者的載入、查詢接收、錯誤生成。這些資訊可以幫助使用者診斷問題出在提供者中還是 WMI 服務中。請在輸出中查詢 ResultCode 不等於 0 的事件;一般來說,錯誤程式碼不等於 0 說明操作失敗了。

請將以下程式碼儲存到一個 .VBS 檔案並執行指令碼。

Option Explicit
 
Sub Sink_OnObjectReady(oInst, oCtx)
    instcount = instCount+1
    Wscript.echo "Event " & cstr(instCount) & vbTab & _
        oInst.GetObjectText_ & vbNewLine       
End Sub
 
Sub Sink_OnCompleted(Hresult, oErr, oCtx)   
End Sub
 
'msftTroubleShooting.vbs starts here
 
DIM oLctr, oSvc, OSink, instCount, SrvName, SrvUserName, SrvPswd, args, argcount
 
Set args = wscript.arguments
 
SrvName = "."
SrvUserName = Null
SrvPswd = Null
instcount = 0
 
argcount = args.Count
 
If (argcount > 0)  Then
    If args(0) = "/?" or args(0) = "?"   Then
        Wscript.Echo "Usage:        cscript msftTroubleShooting.vbs " _
            [ServerName=Null|?] [UserName=Null] [Password=Null]"
        Wscript.Echo "Example:    cscript msftTroubleShooting.vbs "
        Wscript.Echo "Example:    cscript msftTroubleShooting.vbs computerABC"
        Wscript.Echo "Example:    cscript msftTroubleShooting.vbs "
        Wscript.Echo "computerABC admin adminPswd"
        Wscript.Quit 1
    End If
End If
 
Set oLctr = createObject("WbemScripting.Swbemlocator")
 
On Error Resume Next
If argcount = 0 Then
    Set oSvc = oLctr.ConnectServer(,"root\cimv2")
    SrvName = " Local Computer "
Else
    srvname = args(0)
    If argcount >= 2 Then
        SrvUserName = args(1)
    End If
    If argcount >= 3 Then
        SrvPswd = args(2)
    End If
    Set oSvc = oLctr.ConnectServer(srvname,"root\cimv2",SrvUserName,SrvPswd)
End If
 
If Err = 0 Tthen
    Wscript.Echo "Connection to " & srvname & " is thru"  & vbNewLine
Else
    Wscript.Echo "The Error is " & err.description & _
        " and the Error number is " & err.number
    Wscript.Quit 1
End If
 
On Error Goto 0
 
Set oSink = WScript.CreateObject("WbemScripting.SWbemSink","Sink_")
oSvc.ExecNotificationQueryAsync oSink, _
    "Select * From MSFT_WmiProvider_OperationEvent Where " & _
        "provider = 'WMIPingProvider'"
 
Wscript.Echo "To stop the script press ctrl + C" & vbNewLine
Wscript.Echo "Waiting for events......"  & vbNewLine
 
While True
    Wscript.Sleep 10000    
Wend

問題 8:WMI 不工作。如何解決這個問題?

執行指令碼、諸如 CIM Studio 這樣的基於 WMI 的工具或者執行 WMI 控制元件的時候,可能會遇到 WMI 服務錯誤。指令碼可能不執行,或者可能收到一個“Access Denied”(拒絕訪問)錯誤;導致這種錯誤的原因可能是 WMI 沒有執行,或者名稱空間沒有被正確地配置。引起錯誤的原因還可能是 WMI 提供者提供的類沒有被載入,或者 WMI 儲存庫(儲存類定義的場所)已經損壞。

請遵循以下步驟來診斷 WMI 服務的 WMI 問題:

1. 如果連線遠端計算機出現故障,請在本地計算機上執行指令碼。

2. 重啟 WMI 服務。

3. 重建 WMI 儲存庫。

4. 重新註冊所有 WMI 元件。

5. 重新安裝作業系統。

6. 聯絡 Microsoft 產品支援服務。

如果連線遠端計算機出現故障,請在本地計算機上執行指令碼。
如果連線遠端計算機出現故障,在採取其它措施之前應該首先嚐試在本地計算機上執行指令碼。如果指令碼可以在本地計算機上執行,請參考主題:如何使用 WMI 管理遠端計算機? 如果指令碼在本地計算機上也無法執行,請執行以下診斷步驟:

如果一個本地 WMI 操作返回預料之外的錯誤程式碼,或者無法啟動 WMI Control,請首先確定本地 WMI 服務是否正在執行。請將以下程式碼儲存到一個 .VBS 檔案並在命令提示行執行該指令碼:

Set Svc = GetObject ("winmgmts:root\default")

如果指令碼成功執行,表明 WMI 服務正常工作,它可能不是導致故障的原因。

如果指令碼執行失敗,請驗證指令碼中指定的名稱空間是否是一個有效的名稱空間。示例程式碼嘗試連線 root\default 名稱空間。如果該名稱空間不存在,您將會得到一個錯誤 WBEM_E_INVALID_NAMESPACE (0x8004100E)。

如果名稱空間存在,但試圖連線的類不存在會怎樣呢?在這種情況下,當試圖訪問該類時,可能會看到以下這些錯誤程式碼:

• WBEM_E_NOT_FOUND ( 0x80041002)

• WBEM_E_OUT_OF_MEMORY (0x80041006)

連線類失敗還可能表明 WMI 儲存庫已經損壞。在這種情況下,您可能會看到以下錯誤程式碼中的一個:

• WBEM_E_INITIALIZATION_FAILURE????( 0x80041014 )

• WBEM_E_CRITICAL_ERROR ( 0x8004100a )

• WBEM_E_FAILED ( 0x80041001)

如果認為儲存庫已經損壞,最應該採取的動作就是重建儲存庫。

重啟 WMI 服務。

通常 WMI 服務(winmgmt)總是執行的;任何時候當計算機啟動的時候它也啟動,並直到計算機關閉的時候才關閉。如果該服務意外地停止了,可以在命令列鍵入 net start winmgmt 重啟。除此之外,每次使用基於 WMI 的工具(例如 Wbemtest)或指令碼連線 WMI namespace 的時候,該服務也會自動重啟。通常在 WMI 服務停止的情況下執行一段使用 WMI 的指令碼也會使其自動重啟。

如果遇到關於 WMI 服務的故障,您也許需要手工停止並重啟該服務。請按照以下步驟操作:

1. 首先,啟用 WMI 的“詳細的日誌記錄”選項;這將在 WMI 錯誤日誌中提供更加詳細的資訊,可能有助於故障的診斷。可以配置以下注冊表值來啟用“詳細的日誌記錄”:
    1. 設定 HKLM\Software\Microsoft\WBEM\CIMOM\Logging 為 2。
    2. 設定 HKLM\Software\Microsoft\WBEM\CIMOM\Logging file Max Size 為 4000000。

2. 停止 WMI 服務。眾所周知,WMI 服務名為“winmgmt”。可以通過執行以下命令來停止該服務:
winmgmt /kill

如果正在執行 Windows XP 或 Windows Server 2003,WMI 服務執行在一個名為 Svchost 的程序之內;該程序還包含執行在同一帳戶下的其他服務。除此之外,您還可能看到計算機上執行著多個 Svchost 例項。不要嘗試停止 Svchost 本身;相反,請使用以下兩個命令來停止 WMI 服務:winmgmt /kill 或 net stop winmgmt

3. 如果步驟 2 成功,請跳過該步驟,直接進入步驟 4。如果步驟 2 沒能成功停止 winmgmt 服務,請重啟計算機然後進入步驟 4。

4. 再次執行指令碼。如果指令碼執行失敗,您可能需要重建 WMI Repository。

重建儲存庫。

WMI Repository 是 WMI 提供者建立的類定義的集中儲存位置,它位於 %systemDrive%\%windir%\system32\wbem\Repository 資料夾。如果感覺儲存庫已經損壞,您應該重建它。注意:這麼做可能會導致儲存庫中的 WMI 資訊丟失。您可能需要手工恢復這些資訊,方法是執行可以將資訊放入儲存庫的特定應用程式。要重建儲存庫,請按以下步驟操作:

1. 停止 WMI 服務。

2. 在命令列鍵入以下命令:

cd /d %windir%\system32\wbem

rename Repository Rep_bak

3. 這個命令將會重新命名包含 WMI Repository 的檔案。重新命名檔案之後,作業系統將無法找到儲存庫。在這種情況下,Windows 會在使用者下次訪問 WMI 的時候嘗試重建儲存庫。如果 AutoRecover(自動恢復)機制失敗,您可以嘗試手工重建儲存庫。

通過 WMI AutoRecover 機制重建儲存庫:

• 建立一個到 Root\Default 的 WMI 連線;可以通過執行一段指令碼或者類似 Wbemtest.exe 的基於 WMI 的工具做到這一點。如果連線成功,儲存庫就會被重建。如果連線失敗,請嘗試手工重建儲存庫。

手工重建 WMI 儲存庫:

• 想要手工重建儲存庫,應該首先編輯一個批處理檔案,該檔案將會向儲存庫補充資訊。登錄檔鍵 HKLM\Software\Microsoft\WBEM\CIMOM\Autorecover MOFs 包含一個 WMI(或作業系統) 安裝時的 Managed Object Format 檔案(MOF 檔案)列表。想要重建儲存庫,請將登錄檔值中列出的檔名複製到一個名為 WMI_Recover.bat 的批處理檔案;確保包含了副檔名為 .MOF 和 .MFL 的檔案。(MFL 檔案中包含了類、屬性和方法的本地化描述。)
在記事本中,這個批處理檔案應該象下面這樣:

C:\WINDOWS\system32\WBEM\cimwin32.mof
C:\WINDOWS\system32\WBEM\cimwin32.mfl
C:\WINDOWS\system32\WBEM\system.mof
C:\WINDOWS\system32\WBEM\wmipcima.mof
C:\WINDOWS\system32\WBEM\wmipcima.mfl

• 在批處理檔案的每行開頭新增 Mofcomp 命令。Mofcomp.exe 是一個作業系統工具,用於編譯 MOF 檔案,並將檔案中包含的資訊新增到 WMI 儲存庫中。例如,您的批處理檔案可能象下面這樣:

Mofcomp C:\WINDOWS\system32\WBEM\cimwin32.mof
Mofcomp C:\WINDOWS\system32\WBEM\cimwin32.mfl
Mofcomp C:\WINDOWS\system32\WBEM\system.mof
Mofcomp C:\WINDOWS\system32\WBEM\wmipcima.mof
Mofcomp C:\WINDOWS\system32\WBEM\wmipcima.mfl

• 執行這個批處理檔案。

• 您也可以使用以下命令編譯所有的 MOF 和 MFL 檔案:

cd /d %windir%\system32\wbem

for %i in (*.mof,*.mfl) do Mofcomp %i

• 命令完成之後,請檢查 .\Logs\Mofcomp.log,檢視是否有編譯錯誤發生。

4. 再次執行指令碼。

重新註冊 WMI 元件

如果到 root\default 的連線仍然失敗,無法被正確註冊的 WMI 元件可能是導致故障的原因。WMI 使用的 .DLL 和 .EXE 檔案位於 %windir%\system32\wbem。您也許需要重新註冊該目錄內的所有 .DLL 和 .EXE 檔案。如果執行在 64 位的系統之上,您可能還需要檢查位於 %windir%\sysWOW64\wbem 的 .DLL 和 .EXE 檔案。

1. 要重新註冊 WMI 元件,請在命令提示行執行以下命令:

cd /d %windir%\system32\wbem

for %i in (*.dll) do RegSvr32 -s %i

for %i in (*.exe) do %i /RegServer

2. 再次執行指令碼。 

重新安裝作業系統

如果仍然無法連線到 root\default,您需要重新安裝作業系統。重新安裝 Windows,然後嘗試再次執行指令碼。

聯絡 Microsoft 產品支援服務

問題 9:如何設定 WMI 名稱空間的安全性?

使用 WMI 控制元件設定名稱空間的安全性

WMI 控制元件提供了一種管理名稱空間安全性的方法。可以在命令提示行執行以下命令來啟動 WMI 控制元件:

wmimgmt

在安裝了 WMI 的 Windows 9x 或 Windows NT4 計算機上,輸入以下命令:

wbemcntl.exe

或者您也可以通過以下方式訪問 WMI Control 和“安全性”選項卡:

1. 右鍵單擊“我的電腦”,然後單擊 管理。

2.雙擊 服務和應用程式 ,然後雙擊 WMI 控制元件。

3. 右鍵單擊 WMI 控制元件 ,然後單擊 屬性。

4. 在 WMI 控制元件屬性 對話方塊中單擊 安全 選項卡。

5. 一個名為 Root ,前面帶加號 (+) 的資料夾將會出現。如果必要,展開這個樹狀結構,定位到想要設定許可權的名稱空間。

6. 單擊 安全設定 按鈕。一組使用者和許可權顯示出來。如果使用者在這個列表中,請按照需要修改許可權。如果使用者不再這個列表中,請單擊 新增 按鈕,然後從賬戶所在的位置(本地計算機、域等等)新增使用者。

注意:

• 為了檢視和設定 namespace 安全性,使用者必需擁有 讀取安全設定 和 編輯安全設定 許可權。系統管理員預設具備這些許可權,並可以按照需要將許可權賦予其他使用者。

• 如果一個使用者需要遠端訪問名稱空間,必須為其選中 遠端啟用 許可權。

• 預設情況下,針對一個名稱空間設定的使用者許可權只對該名稱空間有效。如果希望使用者可以訪問該名稱空間和其下所有子名稱空間,或者只能訪問子名稱空間,請單擊 高階 按鈕。單擊 編輯 並在出現的對話方塊中指定允許訪問的範圍。

問題 10:如何使用 WMI 管理遠端計算機?

使用 WMI 工具連線遠端名稱空間

1. 想使用類似 CIM Studio 或 Wbemtest 這樣的工具進行遠端連線,必需按照以下格式指定一個名稱空間:“\\<machinename>\root\<namespace>”
例如:\\myserver\root\cimv2

2. 身份驗證可以使用 Kerberos 或 NTLM 進行處理。如果使用 NTLM 或預設(非 Kerberos)驗證,請指定如下內容:

User:<domain>\<User>
Password:<password>
Authority:保留空白,或者輸入“NTLMDomain:<domain>”。如果想要包含 Authority 引數,請把“<domain>\”從 User 引數中去掉,只輸入使用者名稱即可。例如:

User:kenmyer
Password:45Tgfr98q
Authority:NTLMDomain:fabrikam
 
3. 要使用 Kerberos 認證,請按如下指定:

User:<domain>\<User>
Password:<password>
Authority:在這裡輸入“Kerberos:<domain>\<machinename>”。例如:

User:kenmyer
Password:45Tgfr98q
Authority:Kerberos:fabrikam\atl-ws-01

使用指令碼連線到遠端計算機上的 WMI

1. 開始之前,請確保對遠端名稱空間擁有相應的許可權。 如果擁有許可權,您可以在不指定使用者身份資訊的情況下連線到遠端計算機。WMI 將使用您登陸時輸入的使用者身份進行連線。

2. 如果不指定使用者身份資訊,您可以使用被稱作 別名字串 的簡短連線語法連線到遠端計算機。更多資訊,請訪問:http://msdn.microsoft.com/library/default.asp 並搜尋 “Constructing a Moniker String”(構造一個別名字串)。例如,以下別名字串將連線到一個名為 TargetComputer 的遠端計算機的預設名稱空間(因為沒有指定名稱空間,會自動連線到預設的名稱空間):

•Set objWMIService = GetObject("winmgmts:\\TargetComputer”)

• 如果 TargetComputer 位於另外一個域中,還必需在名稱空間中包含域名。否則將會返回一個“拒絕訪問”錯誤。例如,以下名稱空間連線到位於 DomainName 域的 TargetComputer 計算機:

Set objWMIService = GetObject("winmgmts:\\DomainName\TargetComputer”)

• 儘管不是必需的,您也可以在別名字串中指定 WMI 名稱空間。這對連線到不同平臺是非常有幫助的,因為在不同版本的作業系統上預設的名稱空間不完全相同。例如,在 Windows 2000、Windows XP 和 Windows Server 2003 上,預設的名稱空間是 root\cimv2;但是,在 Windows NT 4.0 和 Windows 98 上,預設的名稱空間是 root\default。

以下別名字串連線到遠端計算機 TargetComputer 的 root\cimv2 名稱空間:

Set objWMIService = GetObject("winmgmts:\\TargetComputer\root\cimv2)

• 如果需要處理多種平臺,您可能還需要指定 Impersonation(模擬)級別; 儘管 Windows 2000 和更高版本的預設 Impersonation 級別為“Impersonate”,但之前版本的 Windows 的預設 Impersonation 級別為“Identify”。如果需要處理 Windows NT 4.0 和(或)Windows 98 計算機,需要在別名字串中包含 Impersonation 級別;使用委派的時候也需要包含 Impersonation 級別。

以下別名連線到 TargetComputer 的 root\cimv2 名稱空間,並且指定了“Impersonate”作為 Impersonation 級別:

Set objWMIService =    GetObject _
    ("winmgmts:{impersonationLevel=Impersonate}!\\TargetComputer\root\cimv2")

• 最後,您可能還需要根據作業系統版本的不同來設定 Authentication(身份驗證)級別。您可以通過指定 Authentication 級別來請求 DCOM 的身份驗證型別和在整個連線過程中需要用到的隱私資料。它的設定的範圍從“無身份驗證”一直到“每資料保加密身份驗證”(per-packet encrypted authentication)。

以下別名連線到名為 TargetComputer 的計算機的 root\cimv2 名稱空間,同時指定了 Impersonation 級別為“Impersonate”。另外,它還將 Authentication 級別配置為 pkt:

Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate," _ &   
         "authenticationLevel=pkt}!\\  _
            TargetComputer\root\cimv2")

3. 也可以在指令碼中指定使用者的身份驗證資訊;這樣,即使您用一個標準使用者賬戶登入到遠端計算機,仍然可以執行需要管理員許可權的指令碼。更多資訊,請訪問:http://msdn.microsoft.com/library/default.asp 並搜尋 “Creating a WMI Script”(建立 WMI 指令碼)。

wbemImpersonationLevelImpersonate = 3
wbemAuthenticationLevelPktPrivacy = 6

Set objLocator = CreateObject("WbemScripting.SWbemLocator")
Set objService = objLocator.ConnectServer _
    ("TargetComputer", "root\cimv2", "UserName", "Password")
objService.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate
objservices.Security_.AuthenticationLevel = wbemAuthenticationLevelPktPrivacy

注意。一般來說,在指令碼程式碼中寫入管理員密碼是不明智的。更好的辦法是在每次執行的時候詢問密碼。

使用 WMIC 連線 WMI

如果對遠端名稱空間擁有許可權並且遠端計算機支援遠端操作,則連線的時候可以不指定使用者名稱和密碼,WMIC 會自動使用當前的使用者身份資訊。例如:

WMIC /NODE:"computer1" OS GET Caption,CSDVersion,CSName

如果需要使用委派,應該在 WMIC 連線字串中包含 /IMPLEVEL:Delegate 和 /AUTHORITY 設定。例如:

WMIC /NODE:"computer1" /IMPLEVEL:Delegate /AUTHORITY:"Kerberos:domain\computer1" OS

另外,您也可以選擇指定使用者賬戶和密碼(對於 WMI 指令碼,預設只有管理員擁有 WMI 遠端連線許可權)。例如:

WMIC /NODE:"computer1" /USER:"domainname\username" OS GET Caption,CSDVersion

下面這個命令的例子包含了密碼和使用者名稱:

WMIC /NODE:"computer1" /USER:"domainname\username" /PASSWORD:"userpassword" OS GET Caption,CSDVersion,CSName

“拒絕訪問”(Access Denied)錯誤意味著什麼?

試圖連線到 WMI 名稱空間或物件的時候可能會遇到“Access Denied”錯誤。Access Denied 錯誤有多種型別:

0x80041003 (WBEM_E_ACCESS_DENIED)
試圖連線名稱空間的程序如果沒有必需的 WMI 許可權通常是出現該錯誤的原因。試圖進行遠端訪問的賬戶應該是目標計算機的管理員;另外,該賬戶的具體許可權也需要被啟用。
要解決該錯誤,請檢查遠端計算機上的名稱空間的安全性,確定是否為該賬戶啟用了相應的許可權。

0x80070005 (DCOM ACCESS_DENIED)
如果遠端計算機不能識別連線使用者或者對其具有某種形式的限制(例如,該使用者被鎖定),就會導致該錯誤。 這種情況大多數是因為賬戶屬於另外一個域。對 WMI 安全性的最新修改也可能導致該錯誤發生:

• 以前版本允許的空密碼在 Windows XP 和 Windows Server 2003 中不被允許。

• WMI 不支援針對 Windows 98 客戶端的非同步回撥。從 Windows 98 計算機到 Windows XP 計算機的 SWbemServices.ExecNotificationQueryAsync 呼叫將會向 Windows 98 計算機返回一個“拒絕訪問”錯誤。

• DCOM 訪問設定可能發生了改變。

• 如果目標計算機執行 Windows XP,登錄檔鍵 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa 下的 Forceguest 值可能被設定為強制禁止 Guest 賬戶(值為 0)。

0x800706xx (DCOM RPC 錯誤)

如果遠端計算機配置了防火牆,通常會導致該錯誤。 您需要在防火牆上開啟特定埠,允許通過 DCOM 進行遠端管理。

或者,計算機可能在對映 IP 和主機名方面出現了問題。要測試這種可能性,請嘗試在連線字串中使用 IP 地址代替主機名:

Set objWMIService = GetObject("winmgmts:\\192.168.1.1")

要排除遠端錯誤

1. 請檢查使用者是否可以訪問遠端計算機。在命令提示行執行以下命令:

2. 在遠端計算機上啟用“詳細的日誌記錄”,然後重新執行指令碼。指令碼執行之後, 檢查遠端計算機上的日誌檔案(%windir%\system32\wbem\Logs\)。

3. 啟用稽核事件來判斷哪一個賬戶連線失敗。啟用之後,您將在事件日誌中看到類似如下的事件:

Event Type: Failure Audit

Event Source: Security

Event Category: Logon/Logoff

Event ID: 529

Date: 6/14/2004

Time: 10:52:35 AM

User: NT AUTHORITY\SYSTEM

Computer: <remote machine>

Description:

Logon Failure:

Reason: Unknown user name or bad password

User Name: xuser

Domain: NTDEV

Logon Type: 3

Logon Process: NtLmSsp

Authentication Package: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0

Workstation Name: <console Machine >

4. Check the DCOM configuration for the Access\Launch permission; the user running the script must have this permission.

5. 如果所有這些檢查都正常,如果使用者可以被遠端計算機識別,但仍然會發生“DCOM 拒絕訪問”錯誤,請聯絡產品支援服務(http://support.microsoft.com/default.aspx)並提供以下資訊:

• 每臺計算機執行的作業系統。

• 安裝歷史

• 導致錯誤發生的步驟

• 發生錯誤的指令碼或工具

• 進行 WMI 連線的使用者身份資訊,包括“身份驗證”和“模擬”的級別。

• 兩臺計算機的 %windir%\system32\wbem\logs 目錄的 zip 檔案

問題 11:遠端操作涉及到第三臺計算機的時候為何失敗?

如果客戶端計算機(計算機 A)需要通過遠端伺服器(計算機 B)將域身份驗證資訊轉發給第三臺計算機(計算機 C)時,就需要用到委派。類似這樣的情況,也就是說一個特定操作需要涉及兩次或更多網路通訊時,需要使用委派。如果不通過委派,計算機 B 就無法轉發來自計算機 A 的身份驗證資訊;從而導致到計算機 C 的連線失敗。

以下兩種情況需要使用委派。

• 通過 WMI 伺服器列舉所有印表機。在這種情況下,WMI 試圖蒐集連線到印表機伺服器的遠端印表機的屬性,該操作需要用到委派。您可以在計算機 A 上執行一段指令碼,它連線到列印伺服器 B。接著,列印伺服器 B 再試圖訪問連線到計算機 C 的印表機。

• 從 WMI 伺服器通過 NT 驗證連線到 SQL Server。只有藉助委派,WMI 才能將伺服器上的身份驗證資訊轉發到 SQL Server。如果 SQL Server 採用 SQL Server 標準身份驗證(基於 SQL Server 的安全性),而不是 NT 驗證,則連線 SQL server 的連線字串不需要委派。

委派支援的情境如下:

• 三臺計算機必須全部執行 Windows 2000、Windows XP 或 Windows Server 2003。委派不能被用於 Windows NT 4.0 或 Windows 98。

• 必須在 Active Directory 中為計算機 B 啟用委派。

完成這些步驟之後,計算機 B 可以受到信任進行委派了。例如,假設計算機 B 向位於計算機 C 的遠端檔案共享傳送一個請求。在這種情況下,計算機 C 可以使用轉發來的身份驗證資訊來驗證最初在計算機 A 上執行客戶程序的使用者。

儘管委派是一種可用的管理選項,但通常不建議使用,因為如果計算機 A 把身份驗證資訊提供給計算機 B,計算機 B 就可以在任何地方使用這些身份驗證資訊,從而可能帶來安全隱患。

以下指令碼可以在 Active Directory 中為一個計算機賬戶啟用委派。已經在 Windows Server 2003 域中使用管理員賬戶對該指令碼進行了測試。另外:

• WMI 客戶端計算機(計算機 A )執行 Windows XP SP1 Professional。

• WMI 伺服器(計算機 B)執行 Windows Server 2003。

• 三臺計算機位於同一個 Active Directory 域中。委派要求所有計算機位於同一個域中。

• 在這個例子中,檔案伺服器共享(計算機 C)與 WMI 客戶端位於同一臺物理計算機上。當然,共享也可以位於相同域中的另外一臺計算機上。

'Purpose:    Script to enable delegation on a computer and
'then perform an operation that requires delegation

'Requirements:  The client computer must be a member of the same Active Directory
'domain as the WMI Server specified in the argument to this script

'Permissions required:  The user that runs this script should be a member of
'the Domain Administrators group in the Active Directory
 
Const UF_TRUSTED_FOR_DELEGATION  = &H80000
Set args  = Wscript.Arguments
 
' Terminate unless two arguments are specified when starting
'the script
If args.Count <> 2 then
    Wscript.Echo "You must provide a server name and delegation command line."
    Wscript.Echo "For example, start the script using syntax similar to this:"
    Wscript.Echo "cscript.exe this.vbs <WMI Server> <Delegation Command Line>"
    Wscript.Echo "cscript.exe this.vbs computer2 "
    Wscript.echo "\\computer1\c$\windows\system32\calc.exe"
    Wscript.Quit 1
end if
 
serverName = args(0)
argCommandLine = args(1)
 
' Connect locally and get the domain and DS_Computer object to
' examine and/or modify
Set svc = GetObject("winmgmts:root\cimv2")
 
' Get some local machine variables to understand the environment we are working in

Set objEnum = svc.ExecQuery _
    ("Select domain, name From win32_computerSystem", "WQL", 48)
 
For Each obj in objEnum
    domain = obj.Domain
    computerName = obj.Name
Next
 
' Get the connection to the root\directory\ldap namespace to enable delegation
' on the remote computer from the local machine

Set svc = GetObject("Winmgmts:root\directory\ldap")
 
' Create the required context object

Set octx = CreateObject("wbemscripting.swbemnamedvalueset")
octx.Add "__PUT_EXT_PROPERTIES", Array("ds_userAccountControl")
octx.Add "__PUT_EXTENSIONS", true
octx.Add "__PUT_EXT_CLIENT_REQUEST", true
 
' Variable to determine whether or not we have modified the userAccountControl
'and whether or not we have to modify it back when we are done

modified = False
 
Set objEnum = svc.ExecQuery _
    ("Select * From ds_computer Where ds_cn = '" & serverName & "'", "WQL", 48)
 
For Each obj in objEnum
 
' Store this variable to memory for restoration after this operation completes

    userAccountControlOriginal = obj.ds_userAccountControl
 
' Test to see if the computer is already trusted for delegation
    If CBool(userAccountControlOriginal And UF_TRUSTED_FOR_DELEGATION ) = False Then
 
        Wscript.Echo "Computer account not trusted for delegation yet"
                       
        ' Resume On Error while we try this initially
        On Error Resume Next
 
        ' Add this constant value to the value contained already
        obj.ds_userAccountControl = userAccountControlOriginal + _
            UF_TRUSTED_FOR_DELEGATION
 
        ' This should trust the computer account for delegation               
        obj.Put_ 1, octx
 
        If (Err.Number = 0) Then
        ' Set the flag so we know to modify it back to original setting
            modified = True            
        Else
            Wscript.Echo Hex(Err.Number) & " " & _
                Err.Description
            Wscript.Quit 1
        End If
 
                On Error Goto 0:
 
    Else
    ' Already trusted for delegation so
    ' continue with delegation code here
        Wscript.Echo "Computer account is trusted for delegation already"
 
    End If
 
    ' Get the locator object
    Set lctr = CreateObject("WbemScripting.SWbemLocator")
 
    ' Get the service object from the remote server specifying the Kerberos authority
    Set delegationService = lctr.ConnectServer _
        (serverName, "root\cimv2", , , , _
            "kerberos:" & trim(domain) & "\" & Trim(serverName))
 
    ' Delegation level impersonation
    delegationService.Security_.ImpersonationLevel = 4
 
    ' Get the object that will be used to test the delegation hop
    Set process = delegationService.Get("win32_process")
 
    ' Get the inparameter object for the method
    Set inparams = process.methods_("Create").inparameters
           
    ' Set the inparameter commandline value
    inparams.CommandLine = argCommandLine
 
    ' Execute the method
    Set oReturn = process.ExecMethod_("Create", inparams)
 
    ' Echo the output
    If (oReturn.ReturnValue = 0) Then
        Wscript.Echo oReturn.ProcessId & _
            " is the Process ID from the process " & _
                "creation using delegation"
    Else
        Wscript.Echo "An error occurred, the return value for the " & _
            "Win32_Process.Create method is " & _
                oReturn.ReturnValue
    End If
 
    ' Set the value back to the original value
    If modified = True Then
           
        ' Subtract the added delegation privilege from the computer account      
        obj.ds_userAccountControl = _
            userAccountControlOriginal - UF_TRUSTED_FOR_DELEGATION
 
        ' Restore the original setting
        obj.put_ 1, octx
 
    End If                       
Next

如果其中的一臺計算機執行 Windows NT 4.0 或 Windows 98,則以上指令碼不可用。如果目標位於 Windows NT 4.0 檔案共享上,指令碼也會執行失敗。

可以按照以下步驟手工設定委派:

1. 單擊 開始 按鈕,然後單擊 所有程式。

2. 指向 管理工具 然後單擊 Active Directory 使用者和計算機。

3. 在“Active Directory 使用者和計算機”中展開 計算機 節點,找到想要設定委派的計算機

4. 右鍵單擊該計算機並單擊 屬性。

5. 選擇 信任此計算機進行委派 ,然後單擊 確定。

問題 12:為什麼我的查詢需要很長時間才能完成?

這通常是因為查詢會返回大量的資料。如果查詢請求一個非常龐大的資料集,但您只對其中一個子集感興趣,通常可以對返回資訊進行限制以提高操作速度。WQL(WMI 查詢語言)可以幫助使用者過濾返回的例項(記錄)或者屬性(欄位)集合。想要檢視範例,請訪問http://msdn.microsoft.com/library 並搜尋“Querying with WQL”(利用 WQL 進行查詢),另外請參考主題“SELECT Statement for Data Queries”(用於資料查詢的 SELECT 語句)。

在一些情況下,provider 已經基於特定的屬性在過濾方面進行了優化。在 WHERE 字句中指定這些資訊可以改善效能,因為 provider 能夠動態地過濾結果集,不再依賴 WMI 在獲得整個資料空間之後執行的‘後過濾’。CIM_DataFile 的 Drive 和 Path 屬性都是優化屬性的典型例子。

預設情況下,WMI 查詢會返回一個列舉器,允許在兩個方向上多次瀏覽集合;這意味著您可以遍歷集合中的條目,如果願意的話,還可以遍歷第二次、第三次。當返回的資料集比較龐大時,此種類型的列舉器需要佔用非常大的記憶體,從而影響效能。在發起此類查詢的時候,您可以通過指定 WBEM_FLAG_FORWARD_ONLY 標記來避免這個問題。雖然只能使用此種類型的列舉器遍歷一遍集合,但每個物件在使用之後都會從記憶體中釋放,從而避免了效能的下降。更多資訊,請參見 Making a Semisynchronous Call with VBScript(http://msdn.microsoft.com/library/en-us/wmisdk/wmi/making_a_semisynchronous_call_with_vbscript.asp).??

問題 13:如何列出特定計算機上已經安裝的所有應用?

Win32_Product WMI 類代表通過 Windows Installer 安裝的所有應用程式。但是,這個 WMI 類可能不會列出所有出現在‘新增/刪除程式’中的程式。 解決該問題的一種方法是從登錄檔中搜集已安裝程式的資訊(注意:並不是所有程式在安裝的時候都會向登錄檔寫入資訊)。本主題給出了達到此目的的兩種方法:使用指令碼直接讀取登錄檔中的資訊,使用 MOF 檔案和指令碼從 WMI 中獲取該資訊。

1. 以下指令碼用於列出計算機上已經安裝的應用程式。使用 WMI System Registry Provider 直接從登錄檔中搜集資訊的指令碼:

strHost = "."
Const HKLM = &H80000002
Set objReg = GetObject("winmgmts://" & strHost & _
    "/root/default:StdRegProv")
Const strBaseKey = _
    "Software\Microsoft\Windows\CurrentVersion\Uninstall\"
objReg.EnumKey HKLM, strBaseKey, arrSubKeys
 
For Each strSubKey In arrSubKeys
    intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, _
        "DisplayName", strValue)
    If intRet <> 0 Then
        intRet = objReg.GetStringValue(HKLM, strBaseKey & strSubKey, _
        "QuietDisplayName", strValue)
    End If
    If (strValue <> "") and (intRet = 0) Then
        WScript.Echo strValue
    End If
Next

2. 以下 MOF 檔案和它的配套指令碼展示了另外一種從登錄檔中獲取已安裝應用的方法。如果使用 MOF 檔案,請按以下步驟操作:

步驟 1:複製以下 MOF 語法到記事本並儲存為一個 .MOF 檔案(例如 products.mof)。

qualifier dynamic:ToInstance;
qualifier ProviderClsid:ToInstance;
qualifier ClassContext:ToInstance;
qualifier propertycontext:ToInstance;
 
[dynamic, provider("RegProv"),
ProviderClsid("{fe9af5c0-d3b6-11ce-a5b6-00aa00680c3f}"),
ClassContext
("local|HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
]
class Products {
   [key] string KeyName;
   [read, propertycontext("DisplayName")]      string DisplayName;
   [read, propertycontext("DisplayVersion")]      string  DisplayVersion;
   [read, propertycontext("InstallLocation")]      string InstallLocation;
};

步驟 2:在命令提示行鍵入 mofcomp products.mof.該命令將 MOF 檔案存入 WMI 儲存庫。

步驟 3:MOF 存入儲存庫之後,使用以下指令碼獲取資料。

strComputer = "." 
Set WMI = GetObject("winmgmts:\\" & strComputer & _
    "\root\default")
Set colItems = WMI.ExecQuery("Select * from Products")
For Each objItem In colItems
    WScript.Echo "DisplayName: "  & objItem.DisplayName
    WScript.Echo "DisplayVersion: " & objItem.DisplayVersion
    WScript.Echo "InstallLocation: " & objItem.InstallLocation
    WScript.Echo "KeyName: " & objItem.KeyName
Next

問題 14:如何獲得性能計數器資料?

對 Cooked Counter Provider——使用 WMI 獲取效能資料的最快最方便的方法——的支援在 Windows XP 中首次引入。在 Windows 2000 上,您同樣可以獲取效能資料;不過,由於這些資料以“未經加工”的格式出現,您必需自己格式化這些資料以獲得有用的計數器數值。與此形成對比,在 Windows XP 和 Windows Server 2003 上,可以通過 Win32_PerfFormattedData 類直接獲取效能資料。更多資訊,請參見“示例:獲得經過加工的效能資料”:http://msdn.microsoft.com/library/en-us/wmisdk/wmi/example__obtaining_cookedperformance_data.asp.

如果想查詢針對每種計數器型別的正確公式,請首先使用 WMI SDK (“Performance Counter Classes”主題)或針對該屬性的“類似”限定器確定屬性的數值計數器型別。該計數器型別的公式可以在位於以下地址的 "WMI Performance Counter Types"(WMI 效能計數器型別) 一節中找到:http://msdn.microsoft.com/library/en-us/wmisdk/wmi/wmi_performance_counter_types.asp.