2011-10-17 30 views
1

我發現了多個在線教程,用於使用c#建立與遠程計算機的WMI連接。這些教程描述瞭如下過程:當提供不正確憑據時,WMI API掛起

ConnectionOptions cOpts = new ConnectionOptions(); 
ManagementObjectCollection moCollection; 
ManagementObjectSearcher moSearcher; 
ManagementScope mScope; 
ObjectQuery oQuery; 

mScope = new ManagementScope(String.Format("\\\\{0}\\{1}", host.hostname, "ROOT\\CIMV2"), cOpts); 
oQuery = new ObjectQuery("Select * from Win32_OperatingSystem"); 
moSearcher = new ManagementObjectSearcher(mScope, oQuery); 

moCollection = moSearcher.Get(); 

快樂的路徑情況 - 連接到本地主機,或連接到具有適當憑據的遠程主機 - 工作正常。我正在開發一個項目,在當前登錄帳戶無法訪問我們嘗試連接的遠程主機的情況下,我們需要支持該案例。也就是說,我們需要了解這種情況,將錯誤的憑證提交給用戶,並提示他們再次提供憑證。

當我在遠程計算機上沒有上下文的ConnectionOptions對象中指定憑據時,我對moSearcher.Get()的調用無限期地掛起(看似)。同樣,對ManagementScope中的Connect()函數的調用以相同的方式掛起。

我們在C++中執行等效的WMI命令的地方有類似的邏輯,並且我可以報告,如果提供了不正確的憑據,那麼這些邏輯幾乎可以立即返回。返回適當的「訪問被拒絕」消息。我現在用於測試目的的主機與我們在測試現有C++邏輯時使用的主機相同,因此我沒有理由相信WMI在我們的環境中配置不正確。

我已經在c#中搜索了有關WMI連接的超時問題。我已經探索了ConnectionOptions和moSearcher.Options的Timeout屬性。我還查看了可以與ManagementObjectSearcher實例關聯的EnumerationOptions對象的ReturnImmediately屬性。這些選項對我來說沒有預期的效果。

我想我可以在一個單獨的線程中執行這些WMI命令,並用監視代碼圍繞該線程,如果監視代碼沒有在合理的時間內返回,就會殺死它。這似乎是相當數量的工作將推到所有的C#WMI例程的用戶,我希望有一個更簡單的方法。另外,我不確定用這種方式殺死一個優秀的線程能夠恰當地清理WMI連接。

對遠程主機執行ping操作對我沒有任何好處,因爲知道主機已啓動並正在運行並不會告訴我我擁有的憑據是否合適(並且c#WMI調用將掛起)。是否有另一種方法來驗證對遠程主機的憑據?

總是有可能有一個明顯的國旗或API我失蹤,因爲我會認爲其他人已經遇到了這個問題。任何信息/協助將不勝感激。感謝您閱讀這篇冗長的文章。

回答

0

我不知道所有的特殊功能,但這裏有一個小程序來幫助您解決應該能夠包裹在一個線程中你的日常,並給它5秒執行:

void Fake() { 
    bool ok = false; 
    ConnectionOptions cOpts = new ConnectionOptions(); 
    ManagementObjectCollection moCollection; 
    ManagementObjectSearcher moSearcher; 
    ManagementScope mScope; 
    ObjectQuery oQuery; 
    if (cOpts != null) { 
    mScope = new ManagementScope(String.Format("\\\\{0}\\{1}", host.hostname, "ROOT\\CIMV2"), cOpts); 
    if (mScope != null) { 
     oQuery = new ObjectQuery("Select * from Win32_OperatingSystem"); 
     if (oQuery != null) { 
     moSearcher = new ManagementObjectSearcher(mScope, oQuery); 
     if (moSearcher != null) { 
      ManualResetEvent mre = new ManualResetEvent(false); 
      Thread thread1 = new Thread(() => { 
      moCollection = moSearcher.Get(); 
      mre.Set(); 
      }; 
      thread1.Start(); 
      ok = mre.WaitOne(5000); // wait 5 seconds 
     } else { 
      Console.WriteLine("ManagementObjectSearcher failed"); 
     } 
     } else { 
     Console.WriteLine("ObjectQuery failed"); 
     } 
    } else { 
     Console.WriteLine("ManagementScope failed"); 
    } 
    } else { 
    Console.WriteLine("ConnectionOptions failed"); 
    } 
} 

希望能幫助或給你一些想法。

+0

感謝jp的快速響應。單獨的線程代碼是一個選項。讓我感覺更好的是發現其他人在以我的方式行使這些API時遇到同樣的問題。 – Dan

+0

還要注意,錯誤檢查一直在通知你,開發者,有什麼不對。如果你的代碼通過錯誤檢查步驟完成了'moCollection = moSearcher.Get()'這一行,那麼你可能需要查找Get()函數來查看它是否有任何重載或錯誤代碼它提供。希望這有幫助。 – jp2code

+0

例如,這個鏈接>> http://msdn.microsoft.com/en-us/library/67a77ef1.aspx <<說,「對直接調用者的完全信任。該成員不能被部分可信的代碼使用。 '「 – jp2code

0

我接受了jp的建議,將WMI API調用包圍在一個單獨的線程中,如果它們超時,可能會被終止。測試時,單獨的線程拋出System.UnauthorizedAccessException類型的異常。我刪除了線程邏輯並添加了一條catch語句來處理這種異常類型。果然,在調用ManagementObjectSearcher.Get()之後,異常幾乎立即被捕獲。

try 
{ 
    moCollection = moSearcher.Get(); 
} 

catch (System.UnauthorizedAccessException) 
{ 
    return Program.ERROR_FUNCTION_FAILED; 
} 

catch (System.Runtime.InteropServices.COMException) 
{ 
    MessageBox.Show("Error, caught COMException."); 
    return Program.ERROR_FUNCTION_FAILED; 
} 

(注意System.Runtime.InteropServices。在我的代碼中已經存在COMException catch語句)

當我作爲父線程的一部分執行時,我不知道爲什麼不引發此異常(或者至少未通過VS 2010 IDE引起用戶注意) 。無論如何,這正是我正在尋找的,並且與在C++中的WMI連接例程的行爲一致。

相關問題