5

Normally in PowerShell this works:

# parent.ps1

$x = 1
&"$PSScriptRoot/child.ps1"
# child.ps1

Write-Host $x

When parent.ps1 runs, it prints out 1 since child.ps1 has inherited it.

Can I prevent this for my script?

I can do $private:x = 1, but parent has many variables, so it's verbose and error-prone.

Is there a way to call child.ps1 without inheriting scope?
Or maybe a way to mark everything in parent private?

3
  • Would starting another Powershell process be an option? Commented May 17, 2020 at 1:11
  • Maybe, I am a bit concerned if parent can run in either powershell.exe or pwsh.exe I would need to know which one to start? Commented May 17, 2020 at 1:16
  • $host is your friend. ;-) Commented May 17, 2020 at 1:30

1 Answer 1

5

No, short of defining all variables in the calling scope (and its ancestral scopes) with the $private: scope, you cannot prevent PowerShell's dynamic scoping.

That is, creating a variable in a given scope (without $private:) makes it visible to all its descendant scopes, such as the child scope in which a script (invoked directly or via &) runs.

Also, certain automatic (built-in) variable are defined with option AllScope, which invariably makes them visible in all scopes, not just descendant ones.

Workarounds:

  • In-process:

    • Call your script via a thread job, using Start-ThreadJob (PowerShell v6+) or with ForEach-Object -Parallel (v7+); e.g.:

      • ForEach-Object -Parallel { $PSScriptRoot/child.ps1 }

      • Thread jobs and the threads created by ForEach-Object -Parallel do not inherit the caller's state (with the exception of the current location in v7+)[1].

    • At the start of your script, enumerate all variables via Get-Variable and create local copies that you explicitly set to $null (you'll need to ignore errors stemming from built-in variables that you cannot override) - this will effectively shadow the variables from ancestral scopes.

  • Out-of-process:

    • Call your script via a new PowerShell process (powershell -File ... or pwsh -File ...) or via a background job (using Start-Job).
      • Caveat: In addition to decreased performance, due to cross-process XML-serialized serialization type fidelity may be lost - see this answer for details.

[1] Note that providing an opt-in for copying the caller's state to the ForEach-Object -Parallel threads is now being considered; see this GitHub feature request.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.