Timeout Get-WMIObject cmdlet

2019-01-25 22:24发布

I run a script which performs many WMI-querys - but the cmdlet hangs if the server doesn't answer.. Is there any way I can make this (or any other cmndlet for that matter) timeout and exit if X seconds has passed?

Edit

Thanks to a tip from mjolinor the solution is to run this as -asjob and set a timeout in a while loop. But this is run from within a job already (started with Start-Job). So how do I know I am controlling the correct job?

This is my code from inside my already started job:

Get-WmiObject Win32_Service -ComputerName $server -AsJob

$Complete = Get-date

While (Get-Job -State Running){
    If ($(New-TimeSpan $Complete $(Get-Date)).totalseconds -ge 5) {
        echo "five seconds has passed, removing"
        Get-Job  | Remove-Job -Force
    }
    echo "still running"
    Start-Sleep -Seconds 3
}

PS: My jobs started with Start-Jobs are already taken care of..

6条回答
小情绪 Triste *
2楼-- · 2019-01-25 22:45

I've modified Daniel Muscetta's Get-WmiCustom to also support passing credentials.

I know this post is a little old, hopefully this helps someone else.

# Define modified custom get-wmiobject for timeout with credential from http://blogs.msdn.com/b/dmuscett/archive/2009/05/27/get_2d00_wmicustom.aspx
Function Get-WmiCustom([string]$Class,[string]$ComputerName,[string]$Namespace = "root\cimv2",[int]$Timeout=15, [pscredential]$Credential) 
{ 
    $ConnectionOptions = new-object System.Management.ConnectionOptions
    $EnumerationOptions = new-object System.Management.EnumerationOptions

    if($Credential){
        $ConnectionOptions.Username = $Credential.UserName;
        $ConnectionOptions.SecurePassword = $Credential.Password;
    }


    $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 
}
查看更多
相关推荐>>
3楼-- · 2019-01-25 22:51

when creating the job using get-wmiobject assign that job to a variable, then that variable can be piped into get-job for status or receive-job for results

$ThisJob = start-job -scriptblock {param ($Target) Get-WmiObject -Class Win32_Service -ComputerName $Target -AsJob} -ArgumentList $server
$Timer = [System.Diagnostics.Stopwatch]::StartNew()
While ($ThisJob | Get-Job | where {$_.State -imatch "Running"}){
    If ($Timer.Elapsed.Seconds -ge 5) {
        echo "five seconds has passed, removing"
        $ThisJob | Get-Job | Remove-Job -Force
        } # end if
    echo "still running"
    Start-Sleep -Seconds 3
    } # end while

$Results = $ThisJob | where {$_.State -inotmatch "failed"} | receive-job
$Timer.Stop | out-null
查看更多
The star\"
4楼-- · 2019-01-25 22:56

The only two solutions I've seen for this problem are:

  1. Run the queries as background jobs and put a timer on them, then stop/remove the jobs that run too long.

  2. Fix your servers.

查看更多
仙女界的扛把子
5楼-- · 2019-01-25 23:01
成全新的幸福
6楼-- · 2019-01-25 23:04

In addition to what has been said, not a bullet proof solution but consider pinging your servers first (Test-Connection), it can speed up execution time in case you have no responding machines.

查看更多
冷血范
7楼-- · 2019-01-25 23:07

You could try the get-wmiCustom function, posted here. Wouldn't it be nice if get-wmiObject had a timeout parameter? Let's upvote this thing.

查看更多
登录 后发表回答