I am using Invoke-Command
, and within the -ScriptBlock
I am using Start-Job
. I have to use $Using:var
within Start-Job
but the session is looking for the declared variables in the local session (declared before Invoke-Command
). Here's a very brief example of what I'm doing:
Invoke-Command -ComputerName $computer -ScriptBlock {
$sourcePath = 'C:\Source'
$destPath = 'C:\dest.zip'
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
$includeBaseDirectory = $false
Start-Job -Name "compress_archive" -ScriptBlock {
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::CreateFromDirectory("$using:sourcePath","$using:destPathTemp",$using:compressionLevel,$using:includeBaseDirectory)
}
}
Invoke-Command : The value of the using variable '$using:sourcePath' cannot be retrieved because it has not been set in the local session.
At line:1 char:1
+ Invoke-Command -ComputerName vode-fbtest -ScriptBlock {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Invoke-Command], RuntimeException
+ FullyQualifiedErrorId : UsingVariableIsUndefined,Microsoft.PowerShell.Commands.InvokeCommandCommand
If I omit $using
when calling variables in the Start-Job -ScriptBlock {}
then I get a Cannot find an overload for "CreateFromDirectory" and the argument count: "4".
error because the variables are not defined in that scope.
Is there a way to use $using
for variables within the remote session rather than the local one, or possibly another scope I can specify that would source variables from the remote session? I could declare these variables locally before the Invoke-Command
to fix this but that would require a significant bit of work due to the variables containing dynamic values (all of this is in a foreach ($obj in $objects)
, the data for which is retrieved on the remote computer so I would need to restructure the whole script if I can't make this work).
I'm using PS v5.1 on Windows Server 2012 R2 (both source host and -ComputerName
host on which the command is invoked) if that makes any difference.
Looking at this answer I see that you can expose variables to lower level script blocks but I need to actually declare the variable from within the remote session. The value needs to come from the computer on which the remote session is running. Can you declare the variable from within the remote session in a fashion that makes it available to script blocks within the top-level script block?
PetSerAl, as countless times before, has provided the crucial pointer in a terse comment on the question:
You need to:
use
[scriptblock]::Create()
to create the script block to pass toStart-Job
dynamically, from a stringmake the
[scriptblock]::Create()
call inside theInvoke-Command
script block, because only that ensures that the variables declared in there are the ones referenced in the[scriptblock]::Create()
-created script block via the$using:
scope specifier.{ ... }
withStart-Job
, as in your attempt, the$using:
references do not refer to theInvoke-Command
script block's scope, but to the scope of the caller ofInvoke-Command
, i.e. to the variables visible to the code that makes the overallInvoke-Command
call.$using:...
references would be smart enough to handle nested scopes, as in this case, but that is not the case as of PowerShell Core 7.0.0-preview.3.Caveat: As PetSerAl points out, if you use
Invoke-Command
with a command-scoped ad-hoc session (implied by using-ComputerName
) - rather than a longer-lived session created prior withNew-PSSession
and passed toInvoke-Command
with-Session
- the background job gets terminated when theInvoke-Command
call returns, before it (likely) has a chance to finish. While you could pipe theStart-Job
call to... | Receive-Job -Wait -AutoRemove
, that would only be worth it if you started multiple jobs.Therefore: