为什么要从批处理迁到 PowerShell
批处理擅长跑顺序命令,但文本处理靠字符串拼接、错误处理靠 ERRORLEVEL、路径含空格就容易崩。PowerShell 的对象管道让每一步都能拿到结构化数据(文件对象、服务对象、注册表项),筛选、排序、统计都变成属性操作。迁移不是逐行翻译,而是把“解析文本”的旧思路换成“操作对象”的新思路。
基本信息
| 适用平台 | Windows PowerShell 5.1 与 PowerShell 7+;bat 在任意 Windows 可跑 |
|---|---|
| 退出码 | 外部命令看 $LASTEXITCODE,内部命令成败看 $? |
| 错误处理 | try/catch + -ErrorAction Stop 才是真正的失败中断 |
| 执行策略 | 脚本受 ExecutionPolicy 约束,计划任务里要指定 -ExecutionPolicy |
常见写法对照
| 批处理写法 | PowerShell 等价写法 |
|---|---|
| for %%f in (*.log) do ... | Get-ChildItem *.log | ForEach-Object { ... } |
| if exist file | if (Test-Path file) { } |
| findstr /s /i key *.* | Select-String -Path *.* -Pattern key -SimpleMatch |
| set /a n+=1 | $n++ 或 $n += 1 |
| %ERRORLEVEL% | $LASTEXITCODE 与 $? |
| del /q /f file | Remove-Item file -Force |
| dir /b | Get-ChildItem -Name |
| copy /y a b | Copy-Item a b -Force |
典型使用场景
- 维护老脚本:把易崩的批处理逐步替换成等价的 PowerShell 段
- 需要统计与排序:批处理做不到,PowerShell 一行就够
- 需要结构化输出:导出 CSV、JSON 交给监控或报表系统
- 需要精细错误处理:区分“命令没找到”“权限不足”“业务返回非零”
- 跨机器批量:与 Invoke-Command、CIM 会话天然衔接
对照示例
对照示例
# 旧写法:dir 输出再手工数(不可靠)
# 新写法:直接对对象做统计
(Get-ChildItem D:\Logs -File | Where-Object LastWriteTime -gt (Get-Date).Date).Count
# 按扩展名分组看体积
Get-ChildItem D:\Logs -File -Recurse |
Group-Object Extension |
Select-Object Name, Count, @{n='MB';e={[math]::Round((($_.Group | Measure-Object Length -Sum).Sum)/1MB,1)}}
# 外部命令的退出码判断
robocopy D:\Src D:\Dst /E
if ($LASTEXITCODE -ge 8) { throw "备份失败,退出码 $LASTEXITCODE" }$LASTEXITCODE 只反映上一条外部程序的退出码,内部 cmdlet 出错不会改它;反过来 $? 只关心最近一条命令是否成功。把两者混用做判断是迁移后最常见的逻辑错误。
批处理的 del 与 rd 换成 Remove-Item 后,-Recurse 的影响范围要重新评估:老脚本可能因为引号问题“恰好”没删掉东西,改写成 PowerShell 后反而真的执行了,先在测试目录验证。
计划任务里调用 PowerShell 脚本必须显式写全路径与执行策略参数,工作目录默认为 %windir%\system32,脚本里尽量使用绝对路径,别依赖“当前目录”。