Using invoke-command with a timeout

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

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

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

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.

-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.

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

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

Just to add to that other thread https://powershell.org/forums/topic/using-invoke-command-with-a-timeout/, which is closed for some reason. Invoke-command has an -asjob parameter already. And with multiple computers, they get run as child jobs that you can check on.

invoke-command comp1,comp2,comp3 { pwd } -asjob

get-job -Includechildjob

And you can see which ones aren’t completed…