PowerShell 的变量和作用域是初学者最容易掉坑、老鸟最爱利用的特性之一。搞懂它,你才能写出不乱套的高级脚本、函数、模块。下面用最清晰的方式系统讲解。
1. PowerShell 变量基础语法
| 写法 | 含义 | 示例 |
|---|---|---|
$name | 普通变量 | $name = "张三" |
${name} | 带边界变量(点、冒号、中划线等时必须) | ${ErrorActionPreference} |
$var = 100 | 自动类型(System.Int32) | |
[int]$var = "123" | 强制类型转换 | |
$null | 空值 | $result = $null |
2. PowerShell 作用域(Scope)完整层级(从内到外)
| 作用域名称 | 说明 | 创建时机 |
|---|---|---|
| Local | 当前作用域(函数内就是函数,脚本内就是脚本) | 随时存在 |
| Script | 当前脚本文件整个生命周期 | 运行脚本时创建 |
| Private | 只能在定义它的作用域访问 | 用 Private: 显式指定 |
| Global | 整个 PowerShell 会话(所有脚本、模块、控制台) | 启动 PowerShell 时存在 |
| AllUsers | 所有用户共享(极少用) | |
| Module | 模块内部专用(模块导出后外部不可见) | 导入模块时 |
| Using | 跨作用域访问远程/后台作业中的局部变量 | 仅在 Invoke-Command -ScriptBlock 中用 |
| Workflow | 工作流专用(已废弃) | |
| 数字作用域 | 0=当前,1=父级,2=父父级… |
3. 作用域修饰符(必须掌握!)
| 修饰符 | 含义 | 示例 |
|---|---|---|
$local:var | 当前作用域的变量(默认可省略) | $local:name = "本地" |
$script:var | 当前脚本文件的作用域 | $script:logPath = "C:\log.txt" |
$private:var | 私有变量,子作用域看不到 | $private:password = "123456" |
$global:var | 全局变量,所有地方都能访问 | $global:Debug = $true |
$using:var | 在远程/后台作业中访问调用者的局部变量 | 见后面例子 |
4. 经典坑与正确姿势(99%的人在这里翻车)
坑1:函数里直接改了外部变量(默认行为)
$Money = 1000
function Spend-Money {
$Money -= 200 # 这里创建了 Local 的新变量 $Money,不是外部那个!
}
Spend-Money
$Money # 仍然是 1000(没变!)
正确写法(3种):
# 方式1:用 global(慎用)
$global:Money -= 200
# 方式2:用 script(推荐,脚本级共享)
$script:Money -= 200
# 方式3:传参 + return(最推荐,函数式编程)
function Spend-Money($amount) {
return $Money - $amount
}
$Money = Spend-Money 200
坑2:dot sourcing(.)和作用域
# script.ps1 内容
$User = "李四"
# 普通调用:创建子作用域,变量不会留下来
.\script.ps1
$User # 为空
# 用点加载:脚本在当前作用域运行,变量会留下来
. .\script.ps1
$User # 输出 李四
坑3:Invoke-Command 远程/后台作业里访问本地变量
$name = "王五"
# 错误:远程会话根本看不到 $name
Invoke-Command -ComputerName Server01 -ScriptBlock {
Write-Output "你好 $name" # 输出 你好
}
# 正确:加 using:
Invoke-Command -ComputerName Server01 -ScriptBlock {
Write-Output "你好 $using:name" # 输出 你好 王五
}
# 后台作业也一样
$job = Start-Job { Write-Output "当前用户 $using:name" }
5. 推荐的变量作用域使用规范(企业级脚本必备)
| 场景 | 推荐作用域 | 理由 |
|---|---|---|
| 函数/脚本内部临时变量 | Local(默认) | 不污染外部 |
| 脚本级配置、路径、开关 | $script: | 脚本内所有函数共享,又不影响全局 |
| 调试开关、日志级别 | $global: | 整个会话都能随时改 |
| 密码、密钥、敏感信息 | $private: | 子函数都看不到,防止泄露 |
| 模块内部实现细节 | $private: | 导出函数看不到 |
| 模块导出配置 | 模块作用域(默认) | 外部可通过 ModuleName\Var 访问 |
| 远程/后台作业访问调用者变量 | $using: | 唯一合法方式 |
6. 快速查看当前所有作用域变量
# 查看当前作用域所有变量
Get-Variable
# 查看所有作用域(包括父级)
Get-Variable -Scope 0 # 当前
Get-Variable -Scope 1 # 父级
Get-Variable -Scope 2 # 爷爷级
# 神级命令:查看整个会话所有变量(含作用域)
Get-Variable -Include * | Sort-Object Scope,Name | Format-Table Scope,Name,Value,Options -AutoSize
7. 终极总结口诀(背下来就无敌)
- 函数里改变量,默认是新的 Local,不影响外面
- 想改外面,用
$script:或$global:或传参 - 想保护变量不被子函数看到,用
$private: - 远程/后台作业里访问本地变量,必须加
$using: - 用
. .\script.ps1才会把变量带出来,普通调用不会 - 99%的场景只用 Local +
$script:就够了,少用$global:
把上面这些吃透,你写出来的 PowerShell 函数、模块、自动化脚本就不会再出现“变量莫名其妙没了/乱了”的诡异问题。
有具体的脚本想让我帮你检查作用域问题,欢迎直接贴代码!