Reputation: 170
This is my first time using Jobs in powershell. I have placed a function into a job and I have a while loop which displays an ETA countdown. I want the countdown to pause/adjust if it reaches a predefined time and the function hasn't finished processing.
I have created the countdown successfully, but trying variations of Receive-Job
and Get-Job
. I have also made a global variable which changes from 0 to 1 when the function completes. The while loop is currently looking at the variable in an infinite loop until it changes
$Completion = "0"
$TWOLength = "10"
$ScanFunction = {InitiateScan -Type "Auto"}
$ScanJob = Start-Job -ScriptBlock $ScanFunction
$iTWO=1
Do {
$TLlabel.Text = "Scanning Computer ETA: "+$LoadProVal+" Seconds"
$TLPB.Value = -($LoadProVal-$LoadProMax)
$TLform.Refresh()
$LoadProVal--
$iTWO++
$TLform.Refresh()
Start-Sleep 1
}
While ($iTWO -le $TWOLength)
While ($Completion -ne "1"){
#Do Loop Infinite until Variable Changes
Receive-Job $ScanJob -Keep
Write-Host $InitialScan
Start-Sleep 5
}
When that code runs I get the error message The term 'InitiateScan' in not recognized
once it starts processing the Receive-Job $ScanJob -Keep
While loop.
If I put the Receive-Job
before the While loop the error doesn't occur which is why I added the -Keep parameter
The desired end result should be:
-Start Scan in Job
-Start Countdown
-When reach $TWOLength
, check job $Completion
Variable
-If $Completion
not 1, wait and check again
-If $Completion
is 1, end loop and move on
Upvotes: 1
Views: 155
Reputation: 439427
For a background job to see a function, it must be defined as part of its script block (or be part of an auto-loading module / imported from a module).
Background jobs run as separate PowerShell processes (that don't load the user's $PROFILE
).
One option is to pass the function's definition to the script block to execute in the background and redefine it there.
Note that you must similarly redefine other functions, if any, that this function calls.
A simplified example:
# Define the function to use in the background job.
function Initiate-Scan { "hi: $args" }
# Start the job and (re)define the function in the script block, via
# passing the function body as an argument.
$jb = Start-Job {
${function:Initiate-Scan} = $args[0]; Initiate-Scan -Type Auto
} -Args ${function:Initiate-Scan}
# Get the job's output.
Receive-Job $jb -Wait -AutoRemoveJob
The above yields hi: -Type Auto
, demonstrating that the function was successfully redefined in the background job.
An alternative is to define the functions in a script block passed to the -InitializationScript
parameter:
# Define the function to use in the background job.
function Initiate-Scan { "hi: $args" }
# Start the job and (re)define the function in the initialization script
# script block, so that the main script block can use it.
$jb = Start-Job -InitializationScript (
[scriptblock]::Create("function Initiate-Scan { ${function:Initiate-Scan} }")
) -ScriptBlock {
Initiate-Scan -Type Auto
}
# Get the job's output.
Receive-Job $jb -Wait -AutoRemoveJob
Note: The script block must be created from a string with [scriptblock]::Create()
, because - due to a bug - $using:
for referencing values from the caller's scope doesn't work as of PowerShell 7.0 - see this GitHub issue.
Once the bug gets fixed, you could do the following:
# !! Doesn't work as of PowerShell 7.0
-InitializationScript { ${function:Initiate-Scan} = ${using:function:Initiate-Scan} }
Upvotes: 1