打开记事本,脚本敲下 Get-Process | Where-Object { $_.CPU -gt 100},编写保存成 .ps1 文件,脚本右键选择“使用 PowerShell 运行”——这就是编写最朴素的 PowerShell 脚本。它跟 bat 批处理最大的脚本区别在于:管道里流的不是文本,是编写对象。你拿到的脚本是进程对象的 CPU 属性,一个数字,编写能直接比较大小,脚本不用去截字符串、编写算列宽。脚本
我最早写 PowerShell 是编写为了批量改文件后缀。几百个 .txt 要变成 .log,脚本用资源管理器得点到手抽筋。编写脚本三行就完事:
Get-ChildItem *.txt | ForEach-Object { Rename-Item $_.FullName -NewName ($_.Name -replace '\.txt$',脚本'.log') } 这里有个细节:$_ 是管道里当前对象。FullName 和 Name 都是属性,不用加括号调用方法。但 -replace 是运算符,不是方法,写起来反而更顺。我第一次写的时候用了 $_.Name.Replace('.txt','.log'),结果把文件名中间出现的 .txt 也换了,比如 data.txt.bak 变成 data.log.bak。正则里的 $ 锚定结尾,才没出岔子。
变量声明用 $ 开头,类型不强求。但你要是写 $count = 0 然后 $count++,它自动当整数。写 $name = "server01" 就是字符串。弱类型省事,也容易踩坑。比如 $result = Get-Process 拿到的是数组,$result.Count 能跑,但只有一个进程时 .Count 在旧版 PowerShell 里会报错——得用 @($result).Count 强制包一层。这坑我踩过两次才记住。
函数定义跟其他语言差不多:
function Get-BigFile { param( [string]$Path = "C:\", [int]$SizeMB = 100 ) Get-ChildItem $Path -Recurse -File | Where-Object { $_.Length / 1MB -gt $SizeMB } | Select-Object FullName, @{ N='SizeMB';E={ [math]::Round($_.Length/1MB,2)}} } param 块里可以给默认值,调用时 Get-BigFile -Path D:\ -SizeMB 500 就行。注意 Select-Object 里那个哈希表,N 是列名,E 是表达式。算出来的大小保留两位小数,否则屏幕上全是 123.456789012345 这种。
错误处理别用 try/catch 包所有东西。PowerShell 默认不把非终止错误当异常,Get-ChildItem 遇到没权限的文件夹只会往错误流里写一行,脚本继续跑。要让它停下来,得加 -ErrorAction Stop。我见过有人写了 try { Get-ChildItem C:\ -Recurse } catch { "出错了" },结果跑了半小时,catch 块一次没进——因为错误根本没抛出来。
写脚本免不了要处理路径。Join-Path 比手动拼字符串靠谱,它会处理反斜杠。但 Join-Path "C:\temp" "sub\file.txt" 出来是 C:\temp\sub\file.txt,没问题。可如果你从注册表读了个带引号的路径,比如 "C:\Program Files\",直接拼就会变成 C:\Program Files\\sub。这时候用 [System.IO.Path]::Combine() 更稳,它自动去重。
调试脚本别老靠 Write-Host 打印。用 Set-PSDebug -Trace 1 能逐行显示执行过程,变量值也带出来。或者干脆在 VSCode 里装 PowerShell 扩展,F5 启动调试,断点、监视、调用栈全有。比在控制台里 Write-Host "到这里了" 高效得多。
最后说个实际场景。有台服务器每天凌晨要清理 7 天前的日志。任务计划程序里填 powershell.exe -File "D:\scripts\CleanLogs.ps1",脚本内容:
$cutoff = (Get-Date).AddDays(-7) Get-ChildItem "D:\logs\*.log" | Where-Object { $_.LastWriteTime -lt $cutoff } | Remove-Item -Force 注意 -Force 对付只读文件。还有,任务计划里“起始于”目录要设对,否则脚本里的相对路径全乱套。我吃过这个亏——脚本里写 .\config.xml,手动跑没事,计划任务跑就找不到文件,因为工作目录默认是 C:\Windows\System32。
PowerShell 脚本写多了会发现,它不像 Python 那么“干净”,但跟 Windows 系统咬合得紧。注册表、WMI、事件日志、IIS、Hyper-V,全都有现成 cmdlet。写个巡检脚本,二十行能查磁盘、内存、服务状态,输出成 HTML 报告发邮件。这东西不优雅,但管用。