Get-WmiCustom (aka: Get-WMIObject with timeout!)

Was this helpful? Share It!

Get-WmiCustom (aka: Get-WMIObject with timeout!)

  • Comments 5

I make heavy use of WMI.

But when using it to gather information from customer’s machines for assessments, I sometimes find the occasional broken WMI repository. There are a number of ways in which WMI can become corrupted and return weird results. Most of the times you would just get errors, such as “Class not registered” or “provider load failure”. I can handle those errors from within scripts.

But there are some, more subtle - and annoying – ways in which the WMI repository can get corrupted. the situations I am talking about are the ones when WMI will accept your query… will say it is executing it… but it will never actually return any error, and just stay stuck performing your query forever. Until your client application decides to time out. Which in some cases does not happen.

Now that was my issue – when my assessment script (which was using the handy Powershell Get-WmiObject cmdlet) would hit one of those machines… the whole script would hang forever and never finish its job. Ok, sure, the solution to this would be actually FIXING the WMI repository and then try again. But remember I am talking of an assessment: if the information I am getting is just one piece of a bigger puzzle, and I don’t necessarily care about it and can continue without that information – I want to be able to do it, to skip that info, maybe the whole section, report an error saying I am not able to get that information, and continue to get the remaining info. I can still fix the issue on the machine afterward AND then run the assessment script again, but in the first place I just want to get a picture of how the system looks like. With the good and with the bad things. Especially, I do want to take that whole picture – not just a piece of it.

Unfortunately, the Get-WmiObject cmdlet does not let you specify a timeout. Therefore I cooked my own function which has a compatible behaviour to that of Get-WmiObject, but with an added “-timeout” parameter which can be set. I dubbed it “Get-WmiCustom”

Function Get-WmiCustom([string]$computername,[string]$namespace,[string]$class,[int]$timeout=15)
{
$ConnectionOptions = new-object System.Management.ConnectionOptions
$EnumerationOptions = new-object System.Management.EnumerationOptions

$timeoutseconds = new-timespan -seconds $timeout
$EnumerationOptions.set_timeout($timeoutseconds)

$assembledpath = "\\" + $computername + "\" + $namespace
#write-host $assembledpath -foregroundcolor yellow

$Scope = new-object System.Management.ManagementScope $assembledpath, $ConnectionOptions
$Scope.Connect()

$querystring = "SELECT * FROM " + $class
#write-host $querystring

$query = new-object System.Management.ObjectQuery $querystring
$searcher = new-object System.Management.ManagementObjectSearcher
$searcher.set_options($EnumerationOptions)
$searcher.Query = $querystring
$searcher.Scope = $Scope

trap { $_ } $result = $searcher.get()

return $result
}

You can call it as follows, which is similar to how you would call get-WmiObject

get-wmicustom -class Win32_Service -namespace "root\cimv2" -computername server1.domain.dom

or, of course, specifying the timeout (in seconds):

get-wmicustom -class Win32_Service -namespace "root\cimv2" -computername server1.domain.dom –timeout 1

and obviously, since the function returns objects just like the original cmdlet, it is also possible to pipe them to other commands:

get-wmicustom -class Win32_Service -namespace "root\cimv2" -computername server1.domain.dom –timeout 1 | Format-Table

Leave a Comment
  • Please add 7 and 2 and type the answer here:
  • Post
  • So I stopped the time:

    First timeout message after 20 seconds.

    Second timeout message after another 20 seconds.

    Exception calling "Connect" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"

    At line:9 char:5

    +     $Scope.Connect()

    +     ~~~~~~~~~~~~~~~~

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : COMException

    Exception calling "Get" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"

    At line:17 char:17

    +     trap { $_ } $result = $searcher.get()

    +                 ~~~~~~~~~~~~~~~~~~~~~~~~~

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : COMException

  • Hi, very useful little function. I know I'm a few years behind this being posted, so hopefully you're still around. My question here is, how would I use your function when I need to run a query? this is the get-wmi I'm using...

    $LogFiles = Get-Wmiobject -computername $Server -Query "Select * from CIM_DataFile Where Drive = '$LogDrive' And Path = '$LogQueryPath' And Extension = 'log'" | Sort LastModified

    problem is, run time can vary greatly depending on the number of logs which could be anywhere from less than 10 to somewhere in the hundreds of thousands and I can't have an excessive run time...

  • @laderio - not sure... either you are passing a wrong server name, or there is a firewall in between.

    @Laurie - Yes I am still around. The BEST solution is to make sure that WMI actually works on all your machines. That way you don't have to worry about timeouts as data will eventually come. Unfortunately in the past I have seen situations where WMI was broken on some customers machines and I had to run my collection tool on them but was not allowed to fix or modify anything: for me at the time was preferable to collect partial information (and know that some machines were broken) rather than blocking my whole data collection exercise forever...

  • Ok sorted it at the top of the function I placed:

    $ErrorActionPreference = "Stop"

    Then I wrapped your functions code in a try{} and then used the catch{} to handle the errors as required.

  • @Liam - this function was originally written to work on Powershell v1 - there was no Try/Catch support in Powershell at the time - hence the use of trap for error handling. On v2/3 there will of course be more elegant ways.

Page 1 of 1 (5 items)