点源脚本时PowerShell作用域冲突

点源脚本时PowerShell作用域冲突,powershell,scope,Powershell,Scope,我在点源powershell脚本时遇到一些范围问题。 假设我有一个脚本“A.ps1”: $VERSION = "1.0" # Dot source B.ps1 . .\B.ps1 function Write-Version { Write-Host "A.ps1 version $VERSION" } Write-Version 还有一个脚本B.ps1 $VERSION = "2.0" function Write-Version { Write-Host "B.ps1 version

我在点源powershell脚本时遇到一些范围问题。 假设我有一个脚本“A.ps1”:

$VERSION = "1.0"

# Dot source B.ps1
. .\B.ps1

function Write-Version { Write-Host "A.ps1 version $VERSION" }
Write-Version
还有一个脚本B.ps1

$VERSION = "2.0"
function Write-Version { Write-Host "B.ps1 version $VERSION" }
Write-Version
运行A.ps1的输出将为:

B.ps1 version 2.0
A.ps1 version 2.0
发生这种情况的原因很明显。B.ps1中的
$VERSION
变量被放入A.ps1的范围并覆盖该变量。实际上,
Write Version
也会发生这种情况,但是这里A.ps1覆盖了B的版本,但是因为在这种情况发生之前在B.ps1中调用了
Write Version
,所以我们仍然可以看到B的Write Version函数的输出

当然,问题是如何防止这种情况??我尝试了各种范围选项,但这似乎不工作时,点采购。由于在B.ps1中有我在A的作用域中确实需要的函数,所以仅仅调用B.ps1可能不是一个选项


有人有什么想法吗?

模块是在Powershell V2中创建的,用于解决dot采购的此类问题。使用psm1扩展名保存脚本,并在代码中使用Import Module cmdlet,而不是点源。

您可以通过将B.ps1设置为模块并将其重命名为B.psm1来完成此操作。添加
Export ModuleMember
,使您的功能可用于其他脚本

这将是B.psm1:

$VERSION = "2.0"
function Write-Version { Write-Host "B.ps1 version $VERSION" }
Write-Version

# Only items specified here will be exported. If Export-ModuleMember is not used,
# ALL members (functions, variables, and aliases) will be exported. In this case
# if $VERSION was exported, $VERSION will be set to "2.0" in script A.ps1
Export-ModuleMember -Function Write-Version
而A.ps1将是:

$VERSION = "1.0"

# Import B.psm1
Import-Module .\B.psm1

function Write-Version { Write-Host "A.ps1 version $VERSION" }
Write-Version

# Use B.psm1's `Write-Version` function
B\Write-Version

如前所述,解决方案之一是将脚本转换为PS模块

但是,只要您不需要将函数中的源函数点到全局源(我面临这个问题,不确定是否有办法解决它:),您就可以这样解决问题:

ScopesA.ps1:

$VERSION = "1.0"
$overridenFromAntotherFile = "original"

# Invoke ScopesB.ps1 via &
& .\ScopesB.ps1

Function Write-Version { Write-Host "ScopesA.ps1 version $VERSION" }
Write-Version

Write-Host $overridenFromAntotherFile
范围b.ps1:

$VERSION = '2.0'
$global:overridenFromAntotherFile = 'overriden'
function Write-Version { Write-Host "ScopesB.ps1 version $VERSION" }
Write-Version
输出:

ScopesB.ps1 version 2.0
ScopesA.ps1 version 1.0
overriden
我们的想法是使用&invocation而不是dot-sourcing(您可以在my中阅读它们,但除了&invocks而不将其添加到当前范围和.invocks并添加到范围之外,没有什么可说的了)


而且,您仍然可以通过scope修饰符从ScopeB.ps1访问您的全局作用域(在中还提到了示例)。这是用上面脚本中的另一个文件变量来解释的。

有趣的问题。如果是我,我不会在两个脚本中重复使用相同的变量名,如果它们在同一个会话中使用……关于您的问题的所有内容都是有效的,两个答案也是有效的(您应该使用模块)——除了您的前提。您声明B输出2.0,A输出1.0。(如果这是真的,你甚至不需要发布这个问题!)事实上,输出2.0,这就是你的全部观点。(是的,我知道这只是一个打字错误,但一个字符会有多大的不同:-)@msorens是的,谢谢你发现了这一点。你的推理完全正确。我将修改这篇文章。一些关于Export ModuleMember的有用信息可以防止在试图弄清楚为什么不导入特定内容时产生混淆:如果脚本模块不包含Export ModuleMember命令,则会导出脚本模块中的函数,但不会导出变量和别名。当脚本模块包含导出模块EMBER命令时,仅导出导出模块EMBER命令中指定的成员。好的!谢谢你记下来。我将为示例添加一条注释。谢谢您的回答。我将标记Rynant的答案,因为它有更多的信息。不过我希望我能把这两个都标上。