执行 PowerShell 脚本时遇到的各种错误及解决方法

2024-07-22 Windows

PowerShell 是 Windows 下强大的自动化和脚本工具,但在实际使用中,从初学者到老手都会遇到各种令人头疼的错误。本文整理了我日常使用中碰到的最常见的七类 PowerShell 脚本错误,附带错误信息示例和清晰的解决方案。


1. 执行策略限制(ExecutionPolicy)

错误信息

.\myscript.ps1 : 无法加载文件 .\myscript.ps1,因为在此系统上禁止运行脚本。
有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
所在位置 行:1 字符: 1
+ .\myscript.ps1
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [],PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

原因

PowerShell 默认执行策略为 Restricted,禁止运行任何 .ps1 脚本文件。这是安全设计,防止恶意脚本自动执行。

查看当前策略

Get-ExecutionPolicy
# 输出通常是 Restricted

解决方法

方法 命令 适用场景
临时绕过(推荐) powershell -ExecutionPolicy Bypass -File .\script.ps1 一次性执行,不改系统配置
当前用户放宽 Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 允许本地脚本、远程脚本需签名
全局放宽 Set-ExecutionPolicy RemoteSigned -Scope LocalMachine(需管理员) 开发机常用
完全放开(不推荐) Set-ExecutionPolicy Unrestricted 仅限隔离环境

建议:日常使用 RemoteSigned 即可——它允许本地编写的脚本直接运行,从网络下载的脚本需要数字签名或手动解除锁定。

解除单个文件的锁定

如果脚本是从网络下载的,即使设置了 RemoteSigned,Windows 也会标记该文件来自网络:

Unblock-File -Path .\downloaded-script.ps1

2. 路径中有空格未加引号

错误信息

C:\Program : 无法将"C:\Program"项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
所在位置 行:1 字符: 1
+ C:\Program Files\MyTool\script.ps1
+ ~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Program:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

原因

PowerShell 的路径解析机制:空格被视为参数分隔符,C:\Program Files\... 会被解析成尝试调用 C:\Program 命令并传入 Files\MyTool\script.ps1 作为参数。

解决方法

# ❌ 错误写法
C:\Program Files\MyTool\script.ps1

# ✅ 正确写法之一:使用调用运算符 &
& "C:\Program Files\MyTool\script.ps1"

# ✅ 正确写法之二:使用引号包裹并调用
. "C:\Program Files\MyTool\script.ps1"

# ✅ 正确写法之三:使用 Invoke-Expression(注意安全风险)
Invoke-Expression "C:\Program Files\MyTool\script.ps1"

# ✅ 正确写法之四:Tab 补全(PowerShell 会自动加引号和 &)
# 输入 C:\Prog 然后按 Tab
写法 优点 注意
& "path" 显式调用,最推荐 会创建子作用域
. "path" 在当前作用域执行(dot-sourcing) 脚本变量会污染当前会话
Invoke-Expression 灵活 存在注入风险,不推荐

3. 编码问题:中文乱码

错误信息

# 现象:脚本中的中文字符显示为乱码或导致语法错误
所在位置 行:5 字符: 15
+ Write-Host "鏂囦欢宸插垹闄?  # 原本应该是"文件已删除"
字符串缺少终止符: "。
    + CategoryInfo          : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

原因

  • Windows PowerShell 5.1:默认使用 ANSI 编码(中文系统为 GBK/CP936),如果你用 VS Code 保存为 UTF-8,脚本中的中文会变成乱码。
  • PowerShell 7 (pwsh):默认使用 UTF-8,但如果文件是 UTF-8 with BOM,有时也会出问题。
PowerShell 版本 默认脚本编码 建议保存格式
Windows PowerShell 5.1 ISE UTF-16 LE (Unicode) UTF-8 with BOM
Windows PowerShell 5.1 控制台 ANSI (GBK) UTF-8 with BOM
PowerShell 7 (pwsh.exe) UTF-8 UTF-8 (有无 BOM 均可)

解决方法

方案一:保存时选择正确编码(VS Code)

# VS Code 底部状态栏点击编码 → 选择"通过编码保存" →
# 对于 PS 5.1:选择 "UTF-8 with BOM"
# 对于 PS 7: 选择 "UTF-8"

方案二:在脚本顶部显式指定编码

如果必须使用 UTF-8 脚本在 PS 5.1 中运行:

# 在 PowerShell 控制台中:
powershell -ExecutionPolicy Bypass -File .\script.ps1

# PS 5.1 中可以通过读取 UTF-8 文件来执行:
$script = Get-Content -Path ".\script.ps1" -Encoding UTF8 -Raw
Invoke-Expression $script

方案三:统一升级到 PowerShell 7

# 安装 PowerShell 7(推荐)
winget install Microsoft.PowerShell
# 之后用 pwsh.exe 代替 powershell.exe 执行脚本

4. 模块未安装或导入失败

错误信息

Import-Module : 未加载指定的模块"Az",因为在任何模块目录中都没有找到有效模块文件。
所在位置 行:1 字符: 1
+ Import-Module Az
+ ~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (Az:String) [Import-Module], FileNotFoundException
    + FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand

常见场景和解决

场景 错误特征 解决方法
模块未安装 ModuleNotFound Install-Module -Name Az -Force
模块版本不兼容 Version mismatch Install-Module -Name Az -RequiredVersion 10.0.0
PS 版本不支持 模块要求 PS 7+ 升级到 pwsh 或找旧版模块
路径不在 $env:PSModulePath 同上 ModuleNotFound 手动 Import-Module "D:\MyModules\MyModule"
需要管理员权限安装 Access denied 以管理员身份运行 Install-Module 或加 -Scope CurrentUser

诊断命令

# 查看已安装的模块
Get-Module -ListAvailable

# 查看模块安装路径
$env:PSModulePath -split ';'

# 查看模块是否在仓库中
Find-Module -Name Az

# 查看模块依赖
Find-Module -Name Az | Select-Object -ExpandProperty Dependencies

离线环境安装

# 在联网机器上下载模块(保存为 .nupkg)
Save-Module -Name Az -Path "D:\OfflineModules"

# 复制到离线机器后安装
Install-Module -Name Az -Repository "D:\OfflineModules"

5. 权限不足(需要管理员)

错误信息

New-Item : 拒绝访问路径"C:\Program Files\MyApp\config.json"。
所在位置 行:1 字符: 1
+ New-Item -Path "C:\Program Files\MyApp\config.json"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (C:\Program Files\MyApp\config.json:String) [New-Item], UnauthorizedAccessException
    + FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.NewItemCommand

检测是否需要管理员

# 检查当前是否以管理员身份运行
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
if (-not $isAdmin) {
    Write-Host "请以管理员身份重新运行此脚本" -ForegroundColor Red
}

脚本中自动提升权限

# 检测并自动以管理员身份重新启动
if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
    $arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
    Start-Process powershell.exe -Verb RunAs -ArgumentList $arguments
    exit
}

# 之后的代码将以管理员权限运行
Write-Host "当前以管理员身份运行" -ForegroundColor Green

常见需要管理员的操作

操作 是否需要管理员
修改 C:\Program Files\ 下的文件 ✅ 需要
修改 C:\Windows\System32\ 下的文件 ✅ 需要
安装全局 PowerShell 模块 ✅ 需要(-Scope CurrentUser 可绕过)
修改系统环境变量 ✅ 需要
启动/停止 Windows 服务 ✅ 需要
修改注册表 HKLM ✅ 需要
用户目录下的操作 ❌ 不需要
修改注册表 HKCU ❌ 不需要
读取文件/服务状态 ❌ 通常不需要

6. 脚本签名问题

错误信息

.\script.ps1 : 文件 .\script.ps1 未经数字签名。无法在当前系统上运行该脚本。
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

原因

当执行策略设置为 AllSigned 时,所有脚本都必须经过受信任的发布者签名。

解决方法

方法 命令 适用场景
调整执行策略 Set-ExecutionPolicy RemoteSigned -Scope CurrentUser 仅签远程脚本,本地不签
自签名证书 见下方代码 企业内部部署
解除阻止 Unblock-File .\script.ps1 文件来自可信来源
临时绕过 powershell -ExecutionPolicy Bypass -File .\script.ps1 单次执行

创建自签名证书并签名脚本

# 1. 创建自签名证书
$cert = New-SelfSignedCertificate -Subject "CN=MyPowerShellScripts" `
    -Type CodeSigningCert `
    -CertStoreLocation "Cert:\CurrentUser\My"

# 2. 签名脚本
Set-AuthenticodeSignature -FilePath ".\script.ps1" -Certificate $cert

# 3. 验证签名
Get-AuthenticodeSignature -FilePath ".\script.ps1"
# Status 应为 Valid

# 4.(可选)将证书导出给其他机器信任
Export-Certificate -Cert $cert -FilePath ".\MyPSRoot.cer"

7. 兼容性问题(PS 5.1 vs PS 7)

常见不兼容现象

特性 PowerShell 5.1 PowerShell 7
默认编码 Windows-1252 / GBK UTF-8
&& / \|\| 运算符 ❌ 不支持 ✅ 支持
三元运算符 a ? b : c ❌ 不支持 ✅ 支持
ForEach-Object -Parallel ❌ 不支持 ✅ 支持
ConvertFrom-Json 深度限制 100 层 1024 层
WPF/WinForms GUI ✅ 原生支持 ⚠️ 需额外配置
Invoke-WebRequest IE 引擎解析 DOM 基础解析
Out-GridView ✅ 支持 ⚠️ 需安装模块
COM 对象 ✅ 原生支持 ⚠️ 部分支持

错误示例:PS 7 特有语法在 PS 5.1 中报错

# 这段代码在 PS 7 中没问题,在 PS 5.1 中会报错
$result = Test-Path "C:\Windows" ? "存在" : "不存在"
# PS 5.1 错误:Unexpected token '?' in expression or statement.

检查当前版本

$PSVersionTable.PSVersion
# 输出示例:Major  Minor  Build  Revision
#           -----  -----  -----  --------
#           5      1      19041  4291

多版本兼容写法

# 条件判断替代三元运算符(兼容 PS 5.1)
if (Test-Path "C:\Windows") {
    $result = "存在"
} else {
    $result = "不存在"
}

# 使用 #requires 限制脚本运行环境
#requires -Version 7.0
# 如果版本不满足,脚本会直接中止并提示用户

# 动态检测版本并分支
if ($PSVersionTable.PSVersion.Major -ge 7) {
    # PS 7+ 代码路径
    $null = Test-Path "C:\Windows" ? $true : $false
} else {
    # PS 5.1 兼容代码
    $null = if (Test-Path "C:\Windows") { $true } else { $false }
}

快速排查清单

遇到 PowerShell 脚本报错时,按以下顺序排查:

  1. 阅读错误信息的第一行和最后一行——通常已经说明了根本原因
  2. $Error[0] \| Format-List -Force —— 查看完整错误详情
  3. $Error[0].Exception.InnerException —— 查看内部异常
  4. 检查执行策略:Get-ExecutionPolicy
  5. 检查 PowerShell 版本:$PSVersionTable
  6. 检查路径和文件是否存在:Test-Path .\script.ps1
  7. 检查是否以管理员身份运行(如果涉及系统级操作)
  8. 检查文件编码:Get-Content .\script.ps1 -Encoding UTF8

熟练掌握这七类错误及其解决方案,可以帮你节省大量排查时间。建议将本文加入收藏,遇到问题时按图索骥。如果你有更多实战中的 PowerShell 错误案例,欢迎在评论区分享!