Using invoke-command with a timeout

Welcome Forums General PowerShell Q&A Using invoke-command with a timeout

This topic contains 6 replies, has 5 voices, and was last updated by

 
Participant
4 months ago.

  • Author
    Posts
  • #74662

    Participant
    Points: 1
    Rank: Member

    I use invoke-command to execute a scriptblock on a remote host.
    My code looks like:

    $my_remote_command = invoke-Command -Session $my_session -ScriptBlock {
    #
    Get-ChildItem c:\ *.* -Recurse | select name > c:\myfolder\myfile.txt
    #
    } 
    

    I need to stop the script block after 30 second, even if myfile.txt is not yet complete.
    How can I set a timeout?
    Regards
    marius

  • #74666

    Keymaster
    Points: 12
    Team Member
    Rank: Member

    You could kick it as a job.

    $Job = Start-Job -ScriptBlock {
    
        Invoke-Command -ComputerName localhost -ScriptBlock {
        #
            Get-ChildItem c:\scripts\*.* -Recurse | select name | Out-File 'C:\Scripts\myfile.txt'
        #
        } 
    
    
    }
    
    $Job | Wait-Job -Timeout 10
    $Job | Stop-Job
    
    • #77980
      js

      Participant
      Points: 202
      Helping Hand
      Rank: Participant

      Is there a way to make resolve-dnsname timeout in 1 second? stop-job (or remove-job -force) takes about 4 seconds.

      $job = start-job -scriptblock { Resolve-DnsName 1.1.1.1 }
      $job | wait-job -timeout 1
      measure-command { $job | stop-job }
      
      Days              : 0
      Hours             : 0
      Minutes           : 0
      Seconds           : 4
      Milliseconds      : 148
      Ticks             : 41484183
      TotalDays         : 4.80141006944444E-05
      TotalHours        : 0.00115233841666667
      TotalMinutes      : 0.069140305
      TotalSeconds      : 4.1484183
      TotalMilliseconds : 4148.4183
      
  • #77988

    Participant
    Points: 0
    Rank: Member

    You can try using the -quicktimeout Parameter of the Resolve-DNSName cmdlet. It does not let you specify a timeout value, but it's quicker than the default.

    • #78016
      js

      Participant
      Points: 202
      Helping Hand
      Rank: Participant

      -quicktimeout has no effect in this case. Just try any ip without a hostname.

      I think if the first post here isn't updated, it doesn't appear on the main page.

    • #78022
      js

      Participant
      Points: 202
      Helping Hand
      Rank: Participant

      Oh well. In this case, -dnsonly fixes it.

  • #104366

    Participant
    Points: 1
    Rank: Member

    OK so from what I can see above the solution is to run Invoke-Command within a job, downside is that it will time out the whole lot when the job is stopped.

    So in my example I had an actual problem where I wanted to retrieve information about services running on several hundred servers. I didn't want the Invoke-Command to halt after a specific time but, if there was a server that wasn't responding, it would timeout for that particular computer so that the batch wouldn't be waiting for it.

    In my case I had one duff server that was making the query take 30 mins to run, with the code below the whole lot runs in about 2.5 mins, less then a tenth of the time.

    Basically I've just put the start-job within the ICM.

    Hopefully someone may find this useful

    #Array of Servers
    $ComputerName = @('Server01','Server02','Server03')
    
    # service to check
    $svcName="sql*"
    
    $out=Invoke-Command -computername $ComputerName -ArgumentList $svcName{
        param($svcName)
    
        $jbID=Start-Job -ArgumentList $svcName{
            param($svcName)
    
            $objArray=@();
    
            get-service  -DisplayName "$svcName"| foreach-object{
                
                # get service startmode and time
                $filter="Name='"+$_.ServiceName+"'"; # can't put filter variable into function filter!
                $s=Get-WmiObject -Class Win32_Service -Filter $filter
                 
                $ProcessInfo=Get-WmiObject -Class Win32_Process -Filter "ProcessID='$($s.processid)'" -ea 0
                if($_.Status -eq 'Running'){
                    $lastStarted=$s.ConvertToDateTime($ProcessInfo.CreationDate)
                }else{
                    $lastStarted='N/A'
                }
                
                $ht = @{
                    DisplayName=$_.DisplayName;
                    ServiceName=$_.ServiceName;
                    Status=$_.Status;
                    ServiceType=$_.ServiceType;
                    StartMode=$s.startmode;    
                    lastStarted=$lastStarted;
                    LogOnAs=$s.StartName;
                };
    
                $Obj=New-Object -TypeName PSObject -Property $ht
    
    		    $objArray+=$Obj
    	    }
    
            $objArray;
        }
    
        for ($i2=1; $i2 -le 30; $i2++){
            if((Get-Job $jbID.id).State -notmatch 'Running'){
                BREAK;
            }
            sleep -Seconds 1
        }
        $out=Get-Job $jbID.id | Receive-Job
        Stop-Job $jbID.id
        remove-Job $jbID.id
        Write-Output $out
    }
    
    $out|select pscomputername,DisplayName,lastStarted,ServiceName,LogOnAs,StartMode,ServiceType,Status |ft -a
    

The topic ‘Using invoke-command with a timeout’ is closed to new replies.