首页 > 解决方案 > 在不继承变量和范围的情况下从另一个运行一个 PowerShell 脚本

问题描述

通常在 PowerShell 中这是有效的:

# parent.ps1

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

Write-Host $x

运行时parent.ps1,它会打印出来,1因为child.ps1它继承了它。

我可以为我的脚本防止这种情况吗?

我可以$private:x = 1,但是 parent 有很多变量,所以它很冗长且容易出错。

有没有办法在child.ps1不继承范围的情况下调用?
或者也许是一种在父级私有中标记所有内容的方法?

标签: powershell

解决方案


不,如果不使用范围定义调用范围(及其祖先范围)中的所有变量,$private:则无法阻止 PowerShell 的动态范围。

也就是说,在给定范围内创建变量(不带$private:)使其对其所有后代范围可见,例如脚本(直接调用或通过&)运行的子范围。

此外,某些自动(内置)变量是用 option 定义的AllScope,这总是使它们在所有范围内可见,而不仅仅是后代范围内。

解决方法

  • 进行中:

    • 使用(PowerShell v6+) 或(v7+)通过线程作业调用您的脚本;例如:Start-ThreadJobForEach-Object -Parallel

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

      • 线程作业和创建的线程ForEach-Object -Parallel不继承调用者的状态(v7+ 中的当前位置除外)[1]

    • 在脚本开始时,通过枚举所有变量Get-Variable并创建您明确设置为的本地副本$null(您需要忽略源自无法覆盖的内置变量的错误) - 这将有效地隐藏祖先范围的变量。

  • 进程外:

    • powershell -File ...通过新的 PowerShell 进程(或pwsh -File ...)或通过后台作业(使用)调用您的脚本Start-Job
      • 警告:除了降低性能外,由于跨进程 XML 序列化序列化类型保真度可能会丢失 - 有关详细信息,请参阅此答案

[1] 请注意,现在正在考虑提供将调用者的状态复制到线程的选项ForEach-Object -Parallel请参阅此 GitHub 功能请求


推荐阅读