Does Invoke-Command run in the current scope, or a

2019-08-17 09:26发布

问题:

I was informed in a comment on another post that:

As for Invoke-Command: unfortunately, the docs are incorrect: by default, local invocation happens in a child scope, but you can opt into same-scope execution with -NoNewScope. – mklement0

However, according to the help documentation(emphasis added):

You can also use Invoke-Command on a local computer to evaluate or run a string in a script block as a command. Windows PowerShell converts the script block to a command and runs the command immediately in the current scope, instead of just echoing the string at the command line.

This appears to work as expected:

PS C:\> $TestVar = 99
PS C:\> Invoke-Command { Get-Variable TestVar }

Name                           Value
----                           -----
TestVar                        99

If the documentation was wrong, I would expect that to cause the variable to be unavailable to the Invoke-Command. Is the documentation correct after all?

回答1:

The documentation gives mixed information and the quoted section in the question is definitely outdated/incorrect.

The section of help that gives the correct info is under -NoNewScope which states:

Indicates that this cmdlet runs the specified command in the current scope. By default, Invoke-Command runs commands in their own scope.

This parameter is valid only in commands that are run in the current session, that is, commands that omit both the ComputerName and Session parameters.

This parameter was introduced in Windows PowerShell 3.0.

The following shows the scope information from -NoNewScope is correct(demonstrated with numbered scopes):

$TestVar = 99
Invoke-Command { Get-Variable TestVar -Scope 0 } #Scope 0, current scope
Invoke-Command { Get-Variable TestVar -Scope 1 } #Scope 1, parent scope
Invoke-Command { Get-Variable TestVar -Scope 0 } -NoNewScope #Scope 0, current scope

Results from the first command will return an error saying the variable can't be found:

PS C:\> Invoke-Command { Get-Variable TestVar -Scope 0 } #Scope 0, current scope
Get-Variable : Cannot find a variable with the name 'TestVar'.

The other commands will return the variable information as expected. However, as mentioned in the comment on the other post, -NoNewScope has to be used to explicitly tell Invoke-Command to use the current scope or else it will run in a child scope by default.

The only reason the command in the question worked is because variables are available to child scopes by default and no scope needed to be declared since neither the -ComputerName or -Session parameter were used.