PowerShell Receive-Job does not work in script - powershell

When I execute $job = Start-Job { dir } an then Receive-Job $job in PowerShell console I get normal output. But when I make similar .ps1 script and run it there is no output. Other commands work correctly. How do I receive job result in scripts?

Just try wait job is completed before receive.
$job = Start-Job { dir }
Wait-Job $job | out-null
receive-job $job
other way
$job = Start-Job { dir }
while ($job.state -ne "Completed") {}
receive-job $job

You need to wait for the job to finish:
Start-Job { dir } | Wait-Job | Receive-Job

Related

Script-Block parsing issues

I am running some code that is read from an encrypted file and converted into a ScriptBlock. The code will be a full complex script, but for simplicity let's assume it is the following:
"$(date) Agent started." | Out-File -FilePath 'C:\TMP\test_agent.log' -Append
while($true) {
'$(date) Will check back in 30 seconds...' | Out-File -FilePath 'C:\TMP\test_agent.log' -Append
Start-Sleep -Seconds 30
}
Below is the simple code that launches it, and it works just fine (the $sStr variable contains the above script as a string):
$job = Start-Job -ScriptBlock {
$sb = $executioncontext.invokecommand.NewScriptBlock($args[0])
Invoke-Command -ScriptBlock $sb
} -ArgumentList $sStr | Wait-Job -Timeout 1 | Receive-Job
Again, this works fine. However, I need this to run as a new PowerShell process. But when I try the below the ScriptBlock is not parsed properly and I get errors. Here is the modified launcher:
$job = Start-Job -ScriptBlock {
$sb = $executioncontext.invokecommand.NewScriptBlock($args[0])
powershell "Invoke-Command -ScriptBlock $sb"
} -ArgumentList $sStr | Wait-Job -Timeout 1 | Receive-Job
How to start a new powershell process (and kill the parent) so that the ScriptBlock is correctly parsed and executed?
Thanks!
Maybe you could solve your problem with a PowerShell background job, which can be created via Start-Job. Start-Job also has a -ScriptBlock parameter.
Example 7 of Get-Job shows you how to check if the job is already completed, and how you can retrieve the results of the job.
Hope that helps.

How to know that the script should exit when exit comes within a job?

I have a script which starts a job Start-Job which monitors a process. Whenever this process dies, the script will automatically restart the process, and then restart the script.
If the script can't restart the process it will send an e-mail and should exit PowerShell completely, to avoid the restart of the script. I did this by just exiting inside the job, but that doesn't seem to work.
How can I tell my script to not restart, if the process could not be restarted?
Here's my code:
$sb = {
while ((Get-Process LogikWebserver).Responding) { sleep -m 50 }
if (!(Get-Process LogikWebserver).Responding) {
#restart process
try {
Start-Process "$processpath\LogikWebserver.exe" -EA Stop
sleep -s 2
if (Get-Process LogikWebserver -EA Stop) {
Send-MailMessage
}
} catch {
Send-MailMessage
<# With this exit I want to tell the script to exit completely #>
exit
}
}
}
# start and get job
Start-Job -Name LogikWebserverWatch -ScriptBlock $sb
Wait-Job -Name LogikWebserverWatch
Get-Job -Name LogikWebserverWatch | Remove-Job -Force
# restart script
$skript = "{0}\{1}" -f $PSScriptRoot, "Watch-LogikWebserver.ps1"
& $skript
Don't catch exceptions inside the scriptblock. Receive the job output and catch exceptions there. Also, use an infinite loop for re-running the job rather than re-running the script.
$sb = {
while ((Get-Process LogikWebserver).Responding) {
Start-Sleep -Milliseconds 50
}
# restart process (at this point .Responding was already false, thus no
# point in checking again)
Start-Process "$processpath\LogikWebserver.exe" -ErrorAction Stop
Start-Sleep -Seconds 2
if (Get-Process LogikWebserver -ErrorAction Stop) {
Send-MailMessage
}
}
while ($true) {
# start and get job
try {
Start-Job -Name LogikWebserverWatch -ScriptBlock $sb |
Wait-Job |
Receive-Job -ErrorAction Stop
} catch {
Send-MailMessage
exit
} finally {
Get-Job -Name LogikWebserverWatch | Remove-Job -Force
}
}

How to check if a background job has timed out in powershell

I have this as part of a script
$timeoutSeconds = $timeoutMinutes * 60
$job = Start-Job -ScriptBlock $block -ArgumentList #($environment, $filter)
Wait-Job $job -Timeout $timeoutSeconds
Stop-Job $job
Remove-Job $job
And I would like to raise an error (is part of an octopus deploy step) if it's timed out
Thanks
How about something like this:
Wait-Job $job -Timeout $timeoutSeconds
if ($job.state -eq 'Running') {
Write-Error "Job timed out but did not complete."
}
$jobResults = Receive-Job $job
$jobResults
Stop-Job $job
Remove-Job $job

start-job to run script parallelly

Please help , really very much worried
How to transform the below script using start-job , I have 6 Modules to compare , but sequentially it's taking too much time I am trying to adopt start-job option so that I can run this compare parallelly or in background
Tried this -
Start-Job -Name "Comparecontrol" -filepath $ExecuteSbtWithDcmDm -ArgumentList $CompareControl,"",$false,$false | Out-Null
echolog $THISSCRIPT $DCM_UPDATE_LOG_FILE $LLINFO "Finished Control Master Comparison
Main Script
The general flow would be something like this:
$jobs = #()
$jobs += Start-Job -scriptblock {...}
...
$jobs += Start-Job -scriptblock {...}
Wait-Job $jobs
$results = Receive-Job $jobs
You can use a job name as an alternative to storing the job instance returned by Start-Job e.g.:
$jobName = 'CompareControl'
foreach ($script in $scripts)
{
Start-Job -Name $jobName-scriptblock {&$script} -ArgumentList ...
}
Wait-Job -Name $jobName
$results = Receive-Job -Name $jobName

Resubmit hanging job (start-job)

I am starting several jobs (with Start-Job) and at the end of my script i do a check to see if the jobs have been running more than X seconds. I would then like to take the Running and Failed jobs and restart them until they succeed.
The jobs are named after the server that I'd like to run against (with for example Test-Connection).
My problem is that I can't figure out how to re-submit the jobs!
get-job | where { $_.state -eq "running" } | remove-job -force | start-job -ScriptBlock { echo $_ }
How can I pipe the Name of the failed/hanged job(s) to the new job I am starting?
How can i wait for the remove-job to finish before I continue on Start-Job?
Kind regards:)
One way to restart failed jobs:
Start-Job -Name Foo -ScriptBlock {
$ErrorActionPreference = 'Stop'
Get-Item C:\DoesNotExists
} | Wait-Job > $null
Get-Job | ? { $_.State -eq 'Failed' } | % {
Start-Job -Name $_.Name -ScriptBlock { iex $args[0] } -ArgumentList $_.Command | Wait-Job | Receive-Job
}