【问题标题】:How do I keep function and variable names from colliding?如何防止函数名和变量名发生冲突?
【发布时间】:2026-01-28 05:25:02
【问题描述】:

我正在制作一个脚本来安装几个程序。

安装.ps1

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$here\includes\script1.ps1"
. "$here\includes\script2.ps1"

Write-Host "Installing program 1"

Install-ProgramOne

Write-Host "Installing program 2"

Install-ProgramTwo

script1.ps1

param (
    [string] $getCommand = "msiexec /a program1.msi /q"
)

function Get-Command {
    $getCommand
}

function Install-ProgramOne {
    iex $(Get-Command)
}

script2.ps1

param (
    [string] $getCommand = "msiexec /a program2.msi /q"
)

function Get-Command {
    $getCommand
}

function Install-ProgramTwo {
    iex $(Get-Command)
}

当包含两个文件时,$getCommand 变量将被覆盖。

C# 中有命名空间,Ruby 中有模块,但我不知道如何在 Powershell 中保持命名空间分开。

【问题讨论】:

  • 您想要这样做有什么特别的原因吗?即使有了基思的修复,我也看不到增加复杂性的好处。一个包含要启动的命令数组和调用数组中每个命令的 foreach 循环的脚本可以用更少的代码完成此操作。
  • 这不是*.com/questions/5586692/…的骗子吗?
  • @CitizenRon 我使用 Pester 测试了我的脚本。它们最终具有几乎相同的结构,所以我想遵循 DRY。

标签: powershell


【解决方案1】:

$getCommand 变量本身不是变量,而是一个参数。具有指定默认值的参数。也就是说,为点源脚本文件设置脚本参数并不是一个好主意。这些类型的文件通常只包含函数库和共享/全局变量。

V2 及更高版本中更好的方法是使用模块。模块是变量和函数的容器,您可以在其中控制导出的内容和私有的内容。这就是我对你的两个脚本所做的:

script1.psm1

# private to this module
$getCommand = "msiexec /a program1.msi /q"

function Get-Command {
    $getCommand
}

function Install-ProgramOne {
    iex $(Get-Command)
}

Export-ModuleMember -Function Install-ProgramOne 

script2.psm1

# private to this module
$getCommand = "msiexec /a program2.msi /q"

function Get-Command {
    $getCommand
}

function Install-ProgramTwo {
    iex $(Get-Command)
}

Export-ModuleMember -Function Install-ProgramTwo

这样的用法:

Import-Module $PSScriptRoot\script1.psm1
Import-Module $PSScriptRoot\script2.psm1

Install-ProgramOne
Install-ProgramTwo 

【讨论】:

  • 我喜欢这种方法。我没有意识到创建模块是一个如此简单的过程。谢谢。
【解决方案2】:

您是在“点源”您的脚本,而不是运行它们。这基本上意味着“将所有内容转储到 GLOBAL 命名空间”。如果您只是运行脚本而不是点源它们,那么它们每个都有自己的本地范围。一般来说,我认为应该运行带参数的脚本,而不是点源。

不点源的问题在于,默认情况下,您声明的函数将在脚本完成时超出范围。为了避免这种情况,你可以这样定义你的函数:

function global:Install-ProgramOne
{

}

然后只运行脚本而不是点源,$getcommand 将对您运行的每个脚本都是本地的。

【讨论】: