If I understand the PowerShell Scopes documentation, it should be possible to assign to $using
scope variables from threads started using Start-ThreadJob
. The documentation says (emphasis mine):
The
Using
scope modifier is supported in the following contexts:
- ...
- Thread jobs, started via
Start-ThreadJob
orForEach-Object -Parallel
(separate thread session)Depending on the context, embedded variable values are either independent copies of the data in the caller's scope or references to it.
...
In thread sessions, they are passed by reference. This means it is possible to modify call scope variables in a different thread. To safely modify variables requires thread synchronization.
Yet the following fails to run:
$foo = 1
Start-ThreadJob {
Write-Host $using:foo
$using:foo = 2
} | Wait-Job | Out-Null
Write-Host $foo
It errors on $using:foo = 2
with:
The assignment expression is not valid. The input to an assignment operator must be an object that is able to accept assignments, such as a variable or a property.
Printing the variable with Write-Host $using:foo
works correctly.
I'm using PowerShell 7.1.
You can't overwrite the $using:
variable reference - but you can use it to dereference a variable value in the calling scope, at which point you can then mutate it (assuming a reference-type value was assigned to the original variable):
$foo = @{
Value = 1
}
Start-ThreadJob {
Write-Host $using:foo
$foo = $using:foo
$foo.Value = 2
} | Wait-Job | Out-Null
Write-Host $foo.Value
To ensure thread synchronization, I'd recommended a synchronized hashtable as your container type:
$foo = [hashtable]::Synchronized(@{
Value = 1
})
1..4 |%{Start-ThreadJob {
Write-Host $using:foo
$foo = $using:foo
$foo.Value++
}} | Wait-Job | Out-Null
Write-Host $foo.Value
At which point you should see the (4-times incremented) value of 5