一、PowerShell 概述
1.1 PowerShell 是什么
PowerShell 是微软开发的新一代命令行 Shell 和脚本语言,但它的能力远不止于此。准确地说,PowerShell 是一个包含三重要素的完整平台:
- 命令行 Shell:与 CMD、Bash 一样,可以在终端中交互式地输入命令并立即看到结果。
- 脚本语言:基于 .NET 平台的完整编程语言,支持变量、函数、类、异常处理等所有现代编程特性。
- 配置管理框架:通过 Desired State Configuration (DSC) 实现声明式的系统配置管理。
与传统的文本 Shell 不同,PowerShell 的核心设计理念是 "面向对象"。在 Bash 或 CMD 中,命令的输出是纯文本字符串;而在 PowerShell 中,命令之间传递的是结构化的 .NET 对象。这是一个根本性的区别,也是 PowerShell 最强大的特性。
面向对象 Shell
传统 Shell 的痛点:在 Bash 中,如果你要获取文件列表中所有大于 1MB 的文件,需要先用 ls -l 输出文本,然后用 awk 解析文本列,再用 sort 排序 -- 每一步都在和字符串搏斗。
PowerShell 的解法:Get-ChildItem | Where-Object { $_.Length -gt 1MB } | Sort-Object Length -- 文件对象自带了 Length 属性,无需解析文本,直接按属性筛选和排序。
1.2 PowerShell 版本历史
PowerShell 的发展经历了几个关键阶段,理解版本差异对于选择正确的工具非常重要。
| 版本 |
基于平台 |
发布年份 |
跨平台 |
说明 |
| PowerShell 1.0 |
.NET Framework 2.0 |
2006 |
否 |
第一个版本,引入 cmdlet 概念和对象管道 |
| PowerShell 2.0 |
.NET Framework 3.5 |
2009 |
否 |
引入远程管理、后台作业、脚本调试 |
| PowerShell 3.0 |
.NET Framework 4.0 |
2012 |
否 |
引入 Workflow、模块自动加载、CIM |
| PowerShell 4.0 |
.NET Framework 4.5 |
2013 |
否 |
引入 Desired State Configuration (DSC) |
| PowerShell 5.0/5.1 |
.NET Framework 4.6 |
2016 |
否 |
Windows 预装版本,类定义、PackageManagement |
| PowerShell 7.0-7.5 |
.NET Core 3.1 / .NET 8/9 |
2020-2025 |
是 |
跨平台版本,向后兼容,新操作符,错误流改进 |
关键决策:Windows 10/11 预装的是 Windows PowerShell 5.1(命令为 powershell.exe)。建议额外安装 PowerShell 7.x(命令为 pwsh.exe),它是真正的跨平台版本,功能更强大且持续更新。两个版本可以共存。
1.3 PowerShell 与其他 Shell 的本质区别
以下表格清晰地对比了 PowerShell 与 Bash、CMD 的核心差异:
| 特性 |
Bash |
CMD |
PowerShell |
| 管道传递 |
纯文本 |
纯文本 |
.NET 对象
|
| 命令命名 |
简短、不一致 |
简短、不一致 |
动词-名词(标准) |
| 脚本语法 |
类 C(松散) |
批处理(原始) |
类 C#(严谨) |
| 对象系统 |
无 |
无 |
完整 .NET 类型系统 |
| 跨平台 |
是 |
仅 Windows |
5.1 仅 Windows / 7+ 跨平台 |
| 扩展性 |
外部工具 |
有限 |
模块系统 + NuGet |
| 远程管理 |
SSH |
有限 |
WinRM + SSH 双协议 |
1.4 安装与环境
不同平台上安装 PowerShell 的方式如下:
winget install Microsoft.PowerShell
brew install powershell/tap/powershell
wget -q https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y powershell
pwsh --version
版本检测技巧
在 PowerShell 中,$PSVersionTable 是一个自动变量,包含完整的版本信息。运行 $PSVersionTable 即可查看 PSVersion、PSEdition(Desktop 表示 5.1,Core 表示 7.x)、CLRVersion 等关键信息。
章节小结
PowerShell 是一个面向对象的现代化 Shell 和脚本语言,与 Bash/CMD 有本质区别。Windows 10/11 预装 PowerShell 5.1,建议安装 PowerShell 7+ 以获得跨平台支持和最新功能。安装后可使用 $PSVersionTable 验证版本。无论你使用哪种 Shell,面向对象管道都是 PowerShell 最核心的概念。
二、PowerShell 基础
2.1 启动 PowerShell
在 Windows 上有多种方式启动 PowerShell:
| 方式 |
操作 |
说明 |
| Windows Terminal |
Win + X → Windows Terminal |
推荐方式,支持多标签、多 Shell |
| 搜索运行 |
Win + S → 输入 "powershell" |
快速启动 Windows PowerShell 5.1 |
| 运行对话框 |
Win + R → 输入 "pwsh" 或 "powershell" |
pwsh 启动 7.x,powershell 启动 5.1 |
| VS Code 终端 |
Ctrl + ` → 选择 PowerShell 配置文件 |
集成开发环境,最常用 |
| ISE |
Win + R → 输入 "powershell_ise" |
旧版集成脚本环境(5.1 独占) |
推荐配置:Windows Terminal + PowerShell 7
在 Microsoft Store 中安装 Windows Terminal 和 PowerShell,然后将 Windows Terminal 的默认配置文件设为 PowerShell 7。这样每次打开终端就是最新的 PowerShell 环境,且享受 Windows Terminal 提供的多标签、GPU 加速、自定义主题等高级功能。
2.2 基本命令
以下是最常用的 PowerShell 基本命令:
| 命令 |
别名 |
说明 |
示例 |
| Get-Location |
pwd |
显示当前工作目录 |
Get-Location |
| Set-Location |
cd |
切换工作目录 |
cd C:\Projects |
| Get-ChildItem |
ls、dir |
列出目录内容 |
ls -Recurse |
| Get-Content |
cat、type |
读取文件内容 |
cat README.md |
| Set-Content |
sc |
写入文件内容 |
'Hello' | Out-File test.txt |
| New-Item |
ni |
创建文件或目录 |
ni -ItemType File test.txt |
| Remove-Item |
rm、del |
删除文件或目录 |
rm -Recurse folder |
| Copy-Item |
cp、copy |
复制文件或目录 |
cp file.txt backup.txt |
| Move-Item |
mv、move |
移动或重命名 |
mv old.txt new.txt |
| Clear-Host |
cls、clear |
清屏 |
cls |
实际使用中,你大多会使用别名来操作,因为别名更短、更符合直觉。但理解完整命令名有助于你读懂官方文档和编写脚本。
2.3 别名系统
PowerShell 的别名系统非常完善,几乎所有常用命令都有别名。别名分为两类:
- 标准别名:由 PowerShell 内置,如
ls → Get-ChildItem
- 兼容别名:为了兼容 CMD 和 Unix 用户,如
dir、type、del
Get-Alias
Get-Alias -Definition Get-ChildItem
Get-Alias -Name ls
Set-Alias -Name gs -Value Get-Service
Remove-Item Alias:gs
2.4 获取帮助系统
PowerShell 拥有非常完善的帮助系统,学会使用帮助是掌握 PowerShell 的第一步。
Get-Help Get-ChildItem
Get-Help Get-ChildItem -Detailed
Get-Help Get-ChildItem -Examples
Get-Help Get-ChildItem -Online
Update-Help
Get-Command -Noun Item
Get-Command -Verb Get
Get-Command -Name *service*
核心要点:在学习 PowerShell 的过程中,Get-Help 和 Get-Command 是你最需要记住的两个命令。遇到不认识的命令,用 Get-Help 查用法;想找合适的命令,用 Get-Command 搜索。自学的起点就是这两个命令。
2.5 动词-名词命名规范
PowerShell 的所有 cmdlet(命令)都遵循 动词-名词 命名规范。这种设计的目的是让命令名称具有自解释性,即使你从未见过某个命令,也能从名称中猜出它的用途。
| 动词 |
含义 |
示例命令 |
| Get |
获取信息(只读) |
Get-Process, Get-Service, Get-Content |
| Set |
设置或修改 |
Set-Location, Set-Content, Set-ItemProperty |
| New |
创建新资源 |
New-Item, New-Object, New-PSDrive |
| Remove |
删除资源 |
Remove-Item, Remove-Variable, Remove-Module |
| Copy |
复制资源 |
Copy-Item, Copy-ItemProperty |
| Move |
移动资源 |
Move-Item, Move-ItemProperty |
| Invoke |
执行操作 |
Invoke-Command, Invoke-WebRequest, Invoke-Expression |
| Test |
测试条件 |
Test-Path, Test-Connection, Test-NetConnection |
| Format |
格式化输出 |
Format-Table, Format-List, Format-Wide |
| Export |
导出数据 |
Export-Csv, Export-Clixml |
| Import |
导入数据 |
Import-Csv, Import-Module, Import-Clixml |
| Out |
输出数据 |
Out-File, Out-Null, Out-GridView |
PowerShell 对动词的选择有严格规范,完整的已批准动词列表可通过 Get-Verb 查看。在编写自定义函数时,也应遵循此规范以保持一致性。
发现命令的技巧
如果你想知道"PowerShell 能不能管理服务"——就用 Get-Command -Noun Service。你会发现 Get-Service、New-Service、Set-Service、Restart-Service 等所有与服务相关的命令。名词是发现命令的钥匙。
章节小结
PowerShell 的日常操作习惯后与 Bash 差别不大(别名系统做了很好的兼容),但背后的完整命令名采用动词-名词规范,具有极强的自解释性。Get-Help 是你最好的老师,Get-Command -Noun 是发现命令的最佳方式。Windows Terminal + PowerShell 7 是推荐的开发环境组合。
三、对象管道核心概念
3.1 管道基础
管道是 PowerShell 最核心的概念。在 PowerShell 中,管道操作符 | 将前一个命令的输出对象直接传递给下一个命令作为输入。与 Bash 的文本管道有着本质的区别。
对象 vs 文本:核心差异
Bash 管道:ls -l | grep "\.txt" | awk '{print $5}'
每个命令输出的是字符串,下一个命令需要用 grep、awk、sed 等工具来解析文本。如果输出的格式变了(比如不同语言环境的日期格式),文本解析就会出错。
PowerShell 管道:Get-ChildItem | Where-Object { $_.Extension -eq ".txt" } | Select-Object Length
每个命令输出的是.NET 对象,下一个命令直接访问对象的属性(如 .Extension、.Length),永远不会因为文本格式变化而出错。你还可以继续使用对象的其他方法。
Get-ChildItem *.txt | Where-Object { $_.Length -gt 1KB } | Sort-Object Length -Descending
Get-ChildItem | Get-Member
Get-ChildItem | Get-Member -MemberType Property
核心要点:Get-Member 是探索对象结构的利器。每当你不确定管道中的对象有什么属性时,就在管道末尾加上 | Get-Member。这个习惯能让你快速理解任何 PowerShell 命令的输出结构。
3.2 Select-Object:选择和计算属性
Select-Object 用于从对象中选择特定属性,或者创建计算属性:
Get-Process | Select-Object Name, CPU, WorkingSet
Get-Process | Select-Object -First 5
Get-Process | Select-Object -Property * -ExcludeProperty *Module*
Get-ChildItem | Select-Object Name, @{
Name = "SizeInKB"
Expression = { [math]::Round($_.Length / 1KB, 2) }
}, @{
Name = "IsLarge"
Expression = { if ($_.Length -gt 1MB) { "Yes" } else { "No" } }
}
Get-Service | Select-Object Name, Status, @{
Name = "CanStop"
Expression = { $_.CanStop }
}
3.3 Where-Object:筛选对象
Where-Object 按条件筛选管道中的对象,只保留满足条件的对象继续传递。
Get-Service | Where-Object Status -eq 'Running'
Get-Service | Where-Object { $_.Status -eq 'Running' }
Get-Process | Where-Object { $_.CPU -gt 100 -and $_.WorkingSet -gt 100MB }
Get-Process | Where-Object { $_.ProcessName -eq 'powershell' -or $_.ProcessName -eq 'pwsh' }
Get-Service | Where-Object Status -ne 'Running'
Get-Service | Where-Object Name -like '*sql*'
PowerShell 的比较操作符与 Bash 不同,需要特别记忆:
| 操作符 |
含义 |
示例 |
| -eq |
等于 (Equal) |
$_.Status -eq 'Running' |
| -ne |
不等于 (Not Equal) |
$_.Status -ne 'Stopped' |
| -gt |
大于 (Greater Than) |
$_.Length -gt 1MB |
| -lt |
小于 (Less Than) |
$_.Length -lt 1KB |
| -ge |
大于等于 |
$_.CPU -ge 50 |
| -le |
小于等于 |
$_.Priority -le 5 |
| -like |
通配符匹配 |
$_.Name -like '*sql*' |
| -match |
正则表达式匹配 |
$_.Name -match '^sql\d' |
| -contains |
集合包含 |
$list -contains 'item' |
| -in |
元素在集合中 |
'item' -in $list |
| -is |
类型判断 |
$_ -is [System.IO.FileInfo] |
3.4 Sort-Object, Group-Object, Measure-Object
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
Get-ChildItem | Sort-Object Extension, Length -Descending
Get-ChildItem -Recurse | Group-Object Extension | Sort-Object Count -Descending
Get-Service | Group-Object Status
Get-ChildItem -Recurse -File | Measure-Object Length -Sum -Average -Max -Min
Get-Content log.txt | Measure-Object -Line
3.5 ForEach-Object:遍历处理
Get-Process | ForEach-Object { $_.ProcessName }
Get-Process | ForEach-Object ProcessName
Get-Process | ForEach-Object -Begin {
"Starting process analysis..."
} -Process {
if ($_.WorkingSet -gt 100MB) {
[PSCustomObject]@{
Name = $_.ProcessName
MemoryMB = [math]::Round($_.WorkingSet / 1MB, 2)
CPU = $_.CPU
}
}
} -End {
"Analysis complete."
}
(Get-Process)[0]
(Get-Process)[-1]
(Get-Process)[0..4]
3.6 管道处理模式
了解 PowerShell 管道的内部处理模式,有助于编写高效脚本:
| 模式 |
说明 |
别名/类比 |
| 慢速模式(逐个处理) |
管道中的每个 cmdlet 依次处理。cmdlet A 输出第一个对象后,cmdlet B 立即开始处理该对象,无需等待 A 全部完成。 |
像流水线 |
| 快速模式(收集-处理) |
某些 cmdlet(如 Sort-Object、Group-Object)必须等所有输入对象到齐后才能处理,会先收集所有对象再操作。 |
像批处理 |
cmdlet 脚本开发中,begin、process、end 三个块分别对应"管道启动时"、"每个对象到来时"和"管道结束时"的处理逻辑:
function Test-Pipeline {
begin {
Write-Host "Begin: 初始化,只执行一次"
}
process {
Write-Host "Process: 收到对象 $_ ,每来一个对象执行一次"
}
end {
Write-Host "End: 清理工作,只执行一次"
}
}
1..3 | Test-Pipeline
章节小结
对象管道是 PowerShell 的灵魂。关键命令是 Select-Object(选择属性)、Where-Object(筛选对象)、Sort-Object(排序)、Group-Object(分组)和 ForEach-Object(遍历)。Get-Member 用于探索对象结构。比较操作符(-eq、-gt、-like 等)是筛选的基础。理解 begin/process/end 三阶段模型有助于编写高效的管道处理函数。
四、PowerShell 驱动提供程序
4.1 PSDrive 概念
PowerShell 提供程序(Provider)是一种统一的数据访问模型。它将不同类型的数据存储(文件系统、注册表、环境变量、证书存储等)抽象为"驱动器"(PSDrive),让你可以用 相同的命令 来操作截然不同的数据源。
这意味着你可以在注册表中使用 cd、ls、Get-Item 等命令,就像操作文件系统一样自然。
Get-PSDrive
| Drive |
提供程序 |
数据来源 |
示例 |
| C: |
FileSystem |
本地磁盘文件系统 |
Get-ChildItem C:\Windows |
| HKCU: |
Registry |
HKEY_CURRENT_USER 注册表 |
Get-Item HKCU:\Control Panel\Desktop |
| HKLM: |
Registry |
HKEY_LOCAL_MACHINE 注册表 |
Get-ChildItem HKLM:\Software |
| Env: |
Environment |
系统环境变量 |
Get-Item Env:PATH |
| Cert: |
Certificate |
Windows 证书存储 |
Get-ChildItem Cert:\CurrentUser\My |
| Function: |
Function |
PowerShell 函数 |
Get-ChildItem Function: |
| Variable: |
Variable |
PowerShell 变量 |
Get-ChildItem Variable: |
| Alias: |
Alias |
PowerShell 别名 |
Get-ChildItem Alias: |
4.2 使用 Item cmdlet 统一管理
PowerShell 提供了一组 *-Item cmdlet,可以跨所有 Provider 统一操作:
Get-Item C:\Windows\System32\notepad.exe
Get-Item HKCU:\Control Panel\Desktop
Get-Item Env:PATH
Get-Item Function:Get-ChildItem
Set-Item Env:MyVar "Hello"
New-Item -ItemType Directory -Path C:\MyProject
New-Item -ItemType File -Path C:\MyProject\readme.txt
New-Item -Path HKCU:\Software\MyApp
Remove-Item C:\MyProject\readme.txt
Remove-Item HKLM:\Software\MyApp -Recurse
Test-Path C:\Windows
Test-Path HKCU:\Software\Microsoft
4.3 注册表操作示例
在 PowerShell 中操作注册表非常直观,因为注册表被呈现为文件系统一样的树形结构:
Get-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion -Name ProgramFilesDir
Set-Location HKLM:\Software\Microsoft\Windows\CurrentVersion
Get-ChildItem
New-Item -Path HKCU:\Software\MyCompany\MyApp
Set-ItemProperty -Path HKCU:\Software\MyCompany\MyApp -Name ConfigValue -Value "123"
Get-ItemProperty -Path HKCU:\Software\MyCompany\MyApp -Name ConfigValue
Remove-ItemProperty -Path HKCU:\Software\MyCompany\MyApp -Name ConfigValue
Remove-Item -Path HKCU:\Software\MyCompany -Recurse
操作注册表需谨慎
注册表是 Windows 系统的核心数据库,错误的修改可能导致系统不稳定甚至无法启动。建议在操作前先使用 -WhatIf 参数预览结果,例如 Remove-Item -Path HKLM:\... -WhatIf。对于重要的注册表修改,请先备份。
4.4 环境变量管理
PowerShell 提供两种方式访问环境变量:Provider 方式和 $env: 前缀方式。
Get-ChildItem Env:
Get-Item Env:PATH
Set-Item Env:MY_VAR "my value"
$env:PATH
$env:MY_VAR = "my value"
[Environment]::SetEnvironmentVariable("MY_VAR", "my value", "User")
[Environment]::SetEnvironmentVariable("MY_VAR", "my value", "Machine")
$oldPath = [Environment]::GetEnvironmentVariable("Path", "User")
$newPath = $oldPath + ";C:\MyTools"
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
4.5 证书存储访问
证书存储(Cert:)是 Windows 安全体系的重要组成部分,PowerShell 提供了便捷的访问方式:
Get-ChildItem Cert:\CurrentUser\My
Get-ChildItem Cert:\CurrentUser\My |
Where-Object { $_.NotAfter -lt (Get-Date).AddDays(30) -and $_.NotAfter -gt (Get-Date) }
Get-ChildItem Cert:\CurrentUser\Root
$cert = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -like "*MyCert*" }
Export-Certificate -Cert $cert -FilePath C:\exported.cer
章节小结
PSDrive 和 Provider 是 PowerShell 统一数据访问模型的核心。文件系统、注册表、环境变量、证书、函数、变量、别名——所有这些数据源都可以用相同的 Get-Item、Set-Item、New-Item、Remove-Item 命令来操作。这种一致性大大降低了学习成本。注册表和环境变量操作是日常系统管理的核心场景。
五、变量与数据类型
5.1 变量基础
在 PowerShell 中,变量以 $ 符号开头,支持强类型和弱类型两种声明方式:
$name = "John Doe"
$age = 30
$isAdmin = $true
$salary = 50000.50
[string]$firstName = "John"
[int]$count = 10
[datetime]$birthday = "1990-01-15"
[bool]$enabled = $false
$name.GetType()
[int]"42"
[string]42
[datetime]"2026-05-04"
5.2 基本数据类型
| 类型 |
加速器 |
说明 |
示例 |
| 字符串 |
[string] |
文本数据,支持单引号和双引号 |
"Hello $name" 支持插值 |
| 整数 |
[int] |
32位整数,范围 ±2^31 |
$count = 100 |
| 长整型 |
[long] |
64位整数,范围 ±2^63 |
$big = 2147483648L |
| 浮点 |
[double] |
双精度浮点数 |
$pi = 3.14159 |
| 布尔 |
[bool] |
逻辑值 |
$true / $false |
| 日期 |
[datetime] |
日期和时间 |
Get-Date |
| 数组 |
[array] |
元素集合 |
@(1,2,3) |
| 哈希表 |
[hashtable] |
键值对集合 |
@{Name="A"} |
| XML |
[xml] |
XML 文档对象 |
[xml]$xml = Get-Content file.xml |
| PSCustomObject |
[PSCustomObject] |
自定义对象 |
[PSCustomObject]@{Name="A"} |
$name = "World"
Write-Output 'Hello $name'
Write-Output "Hello $name"
Write-Output "Line1`nLine2"
Write-Output "Tab`there"
$arr = @(1, 2, 3, 4, 5)
$arr2 = 1..5
$arr[0]
$arr[-1]
$arr[0..2]
$arr += 6
$user = @{
Name = "Alice"
Age = 30
Skills = @("PowerShell", "Python", "SQL")
Active = $true
}
Write-Output $user.Name
Write-Output $user["Age"] # 另一种访问方式 → 30
$user.Add("Department", "Engineering")
$user.Keys
$user.Values
5.3 类型转换与加速器
类型加速器(Type Accelerator)是 PowerShell 中常用类型的简写名称,用于快速类型转换:
$num = [int]"42"
$pi = [double]"3.14159"
$date = [datetime]"2026-05-04 10:30:00"
$date.AddDays(7)
[xml]$config = Get-Content app.config
$config.configuration.appSettings.add | ForEach-Object { $_.key + "=" + $_.value }
[regex]$pattern = "^\d{3}-\d{4}$"
$pattern.IsMatch("123-4567")
$unique = [System.Collections.Generic.HashSet[int]]@(1,2,2,3,3,3)
[PSObject].Assembly.GetType("System.Management.Automation.TypeAccelerators")::Get
5.4 自动变量
PowerShell 预定义了许多自动变量(Automatic Variables),它们在脚本中非常有用:
| 自动变量 |
说明 |
| $_ (或 $PSItem) |
管道中的当前对象,Where-Object {$_.Status -eq 'Running'} |
| $? |
上一条命令的执行状态,$true 成功 / $false 失败 |
| $true |
布尔值 True |
| $false |
布尔值 False |
| $null |
空值,表示不存在的对象 |
| $PSVersionTable |
PowerShell 版本信息哈希表 |
| $PSScriptRoot |
当前脚本所在的目录路径 |
| $PSCommandPath |
当前脚本的完整路径 |
| $MyInvocation |
当前命令的调用信息 |
| $Error |
当前会话中所有错误的数组 |
| $Host |
当前宿主程序对象(控制台窗口等信息) |
| $Home |
用户主目录路径 |
| $Profile |
当前用户当前主机的配置文件路径 |
| $PWD |
当前工作目录路径(等同于 Get-Location) |
| $Args |
传递给脚本或函数的参数数组 |
5.5 变量作用域
PowerShell 定义了四个变量作用域,理解作用域对于编写可靠脚本至关重要:
| 作用域 |
关键字 |
可见范围 |
说明 |
| 全局 |
$global: |
整个 PowerShell 会话 |
所有脚本和函数都能访问 |
| 脚本 |
$script: |
当前脚本文件 |
同一脚本内的所有函数共享 |
| 本地(默认) |
$local: 或无前缀 |
当前作用域(通常是函数内) |
默认作用域,对外部不可见 |
| 私有 |
$private: |
当前作用域,子作用域也不可见 |
最严格的作用域限制 |
$global:appName = "MyApp"
$script:config = "debug"
function Test-Scope {
$localVar = "local"
$private:hidden = "secret"
Write-Host "全局: $global:appName"
Write-Host "脚本: $script:config"
Write-Host "本地: $localVar"
$global:appName = "Modified"
}
Get-Variable -Scope Global
Get-Variable -Scope Script
命名约定
推荐使用 PascalCase 命名变量(如 $LogFilePath、$ConnectionString)。对于函数内部的临时变量,可以使用 camelCase(如 $tempFile、$resultData)。避免使用与自动变量名冲突的名称(如 $error、$host)。
章节小结
PowerShell 变量以 $ 开头,支持强类型和弱类型。数据类型包括 string、int、bool、array、hashtable 等。类型加速器([int]、[string]、[datetime] 等)用于快速类型转换。自动变量($_、$?、$true、$null 等)是脚本开发的基础工具,理解它们的作用能大幅提高编码效率。变量作用域(Global、Script、Local、Private)是避免命名冲突的关键。
六、PowerShell 脚本编程
6.1 脚本文件 .ps1 与执行策略
PowerShell 脚本以 .ps1 为扩展名。出于安全考虑,Windows 默认禁止运行未经签名的脚本。执行策略(ExecutionPolicy)控制哪些脚本可以运行:
Get-ExecutionPolicy
Set-ExecutionPolicy RemoteSigned
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
.\MyScript.ps1
& "C:\Scripts\My Script.ps1"
安全警告:不要盲目运行未知脚本
执行策略不是为了限制你的操作,而是为了防止无意中运行恶意脚本。RemoteSigned 是一般推荐的安全级别——它允许你运行自己编写的脚本,同时阻止来自互联网的未签名脚本自动运行。如果你从网上复制了脚本内容并保存为 .ps1 文件,可能需要右键点击文件 → 属性 → 解除锁定(Unblock)。
6.2 函数定义
PowerShell 函数支持多种定义方式,从简单到高级:
function Get-Hello {
Write-Host "Hello, World!"
}
function Get-Greeting {
param(
[string]$Name,
[int]$Age
)
"Hello $Name, you are $Age years old."
}
function Get-GreetingWithDefault {
param(
[string]$Name = "Guest",
[switch]$ShowDate
)
$greeting = "Hello, $Name"
if ($ShowDate) {
$greeting += " - Today is $(Get-Date -Format 'yyyy-MM-dd')"
}
$greeting
}
Get-Greeting -Name "Alice" -Age 30
Get-GreetingWithDefault -ShowDate
6.3 高级函数
高级函数(Advanced Function)通过 [CmdletBinding()] 属性声明,获得与内置 cmdlet 相同的功能,包括管到输入支持、-Verbose、-Debug、-WhatIf 等通用参数:
function Measure-FileSize {
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[string[]]$Path,
[Parameter()]
[ValidateSet('Bytes', 'KB', 'MB', 'GB')]
[string]$Unit = 'KB',
[Parameter()]
[switch]$Recurse
)
begin {
$multiplier = @{ 'Bytes' = 1; 'KB' = 1KB; 'MB' = 1MB; 'GB' = 1GB }
Write-Verbose "Using unit: $Unit"
}
process {
foreach ($p in $Path) {
$items = if ($Recurse) {
Get-ChildItem -Path $p -Recurse -File
} else {
Get-ChildItem -Path $p -File
}
foreach ($item in $items) {
[PSCustomObject]@{
FileName = $item.Name
Size = [math]::Round($item.Length / $multiplier[$Unit], 2)
Unit = $Unit
FullPath = $item.FullName
}
}
}
}
}
Get-ChildItem *.txt | Measure-FileSize -Unit MB -Verbose
Measure-FileSize -Path C:\Windows\System32 -Recurse -Unit MB
6.4 模块管理
模块是组织和共享 PowerShell 代码的基本单元。PowerShell 支持多种模块类型:
| 模块类型 |
文件扩展名 |
说明 |
加载方式 |
| 脚本模块 |
.psm1 |
包含 PowerShell 函数的文件 |
Import-Module .\MyModule.psm1 |
| 二进制模块 |
.dll |
用 C# 编译的 cmdlet |
Import-Module .\MyModule.dll |
| 清单模块 |
.psd1 |
包含模块元数据的清单文件 |
Import-Module .\MyModule |
| 动态模块 |
内存中 |
运行时动态创建的模块 |
New-Module |
Get-Module
Get-Module -ListAvailable
Import-Module ActiveDirectory
Import-Module .\MyTools.psm1 -Force
Remove-Module MyTools
6.5 错误处理
PowerShell 的错误处理机制比 Bash 强大得多,支持结构化异常处理:
try {
$result = 10 / 0
}
catch [System.DivideByZeroException] {
Write-Warning "除零错误:$($_.Exception.Message)"
}
catch {
Write-Error "未预期的错误:$($_.Exception.Message)"
}
finally {
Write-Host "清理工作:无论如何都会执行"
}
$ErrorActionPreference = 'Stop'
$ErrorActionPreference = 'Continue'
$ErrorActionPreference = 'SilentlyContinue'
$ErrorActionPreference = 'Inquire'
Get-Item nonexistent.txt -ErrorAction SilentlyContinue
Get-Item nonexistent.txt -ErrorAction Stop
trap {
Write-Warning "发生错误:$($_.InvocationInfo.PositionMessage)"
continue
}
if ($?) {
Write-Host "命令成功"
} else {
Write-Host "命令失败"
}
最佳实践:在编写脚本时,始终使用 try/catch 包裹可能失败的代码。设置 $ErrorActionPreference = 'Stop' 确保所有错误都被捕获。在脚本开头添加 Set-StrictMode -Version Latest 以启用严格的变量和引用检查。
章节小结
.ps1 脚本文件需要设置执行策略(推荐 RemoteSigned)才能运行。PowerShell 函数支持从简单声明到带 [CmdletBinding()] 属性、管道输入的高级函数。模块(.psm1)是代码的组织和复用单位。try/catch/finally 是推荐的错误处理方式,$ErrorActionPreference 控制错误的全局处理行为。
七、流程控制
7.1 if/elseif/else 条件
$score = 85
if ($score -ge 90) {
Write-Output "优秀"
} elseif ($score -ge 80) {
Write-Output "良好"
} elseif ($score -ge 60) {
Write-Output "及格"
} else {
Write-Output "不及格"
}
$result = ($score -ge 60) ? "Pass" : "Fail"
$name = $inputName ?? "Default Name"
$count = $inputCount ?? 0
$value = $a ?? $b ?? $c ?? "fallback"
7.2 switch 语句
PowerShell 的 switch 语句功能非常强大,支持多种匹配模式:
$day = "Monday"
switch ($day) {
"Monday" { "星期一" }
"Tuesday" { "星期二" }
"Wednesday" { "星期三" }
"Thursday" { "星期四" }
"Friday" { "星期五" }
default { "周末 or invalid" }
}
switch -Regex ("192.168.1.100") {
"^192\.168\.\d+\.\d+$" { "内网地址" }
"^10\.\d+\.\d+\.\d+$" { "A类私有地址" }
"^172\.(1[6-9]|2\d|3[01])\.\d+\.\d+$" { "B类私有地址" }
default { "公网地址" }
}
switch -Wildcard ("report-2026-q1.xlsx") {
"report-*.xlsx" { "Excel 报告" }
"report-*.pdf" { "PDF 报告" }
"*.txt" { "文本文件" }
default { "其他文件" }
}
$colors = @("Red", "Green", "Blue", "Yellow")
switch ($colors) {
"Red" { "红色" }
"Green" { "绿色" }
"Blue" { "蓝色" }
default { "未知颜色:$_" }
}
7.3 循环结构
$services = Get-Service
foreach ($svc in $services) {
if ($svc.Status -eq 'Running') {
Write-Output "$($svc.Name) 正在运行"
}
}
$services.ForEach({
if ($_.Status -eq 'Running') { "$($_.Name) 正在运行" }
})
for ($i = 0; $i -lt 10; $i++) {
Write-Output "第 $i 次迭代"
}
$count = 0
while ($count -lt 5) {
Write-Output "Count: $count"
$count++
}
$rand = 0
do {
$rand = Get-Random -Minimum 0 -Maximum 10
Write-Output "随机数: $rand"
} while ($rand -ne 7)
do {
Write-Output "至少执行一次"
} until ($false)
foreach ($i in 1..10) {
if ($i -eq 3) { continue }
if ($i -eq 8) { break }
Write-Output "i = $i"
}
:outerLoop for ($i = 0; $i -lt 5; $i++) {
for ($j = 0; $j -lt 5; $j++) {
if ($i -eq 2 -and $j -eq 3) {
break outerLoop
}
Write-Output "($i, $j)"
}
}
章节小结
PowerShell 支持完整的流程控制结构:if/elseif/else 条件判断、功能强大的 switch 语句(支持正则和通配符)、foreach 循环以及 for/while/do..while 传统循环。PowerShell 7+ 还新增了三元操作符 ? : 和空值合并操作符 ??。break 和 continue 控制循环流程,标签循环可用于跳出多层嵌套。
八、远程管理与系统管理
8.1 PowerShell Remoting
PowerShell Remoting 是 PowerShell 最强大的功能之一,它允许你在远程计算机上执行命令,就像在本地执行一样。基于 WinRM(Windows Remote Management)协议。
Get-Service WinRM
Test-WSMan -ComputerName Server01
Enter-PSSession -ComputerName Server01 -Credential (Get-Credential)
Exit-PSSession
Invoke-Command -ComputerName Server01 -ScriptBlock {
Get-Service | Where-Object Status -eq 'Running'
}
$computers = @("Server01", "Server02", "Server03")
Invoke-Command -ComputerName $computers -ScriptBlock {
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5
}
$session = New-PSSession -ComputerName Server01
Invoke-Command -Session $session -ScriptBlock { $PSVersionTable }
Remove-PSSession $session
Enter-PSSession -HostName user@server01 -SSHTransport
Invoke-Command -HostName server01 -UserName admin -ScriptBlock { Get-Service }
8.2 WinRM 配置
winrm get winrm/config
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "Server01,Server02,*.contoso.com"
New-SelfSignedCertificate -DnsName "server01.contoso.com" -CertStoreLocation Cert:\LocalMachine\My
New-WSManInstance Winrm/config/Listener -SelectorSet @{Address="*";Transport="HTTPS"}
Set-Item WSMan:\localhost\Service\AllowUnencrypted $false
Set-Item WSMan:\localhost\Service\Auth\Basic $false
安全注意事项
PowerShell Remoting 默认使用 HTTP + Kerberos 认证,在域环境中是安全的。在工作组环境中,需要配置 TrustedHosts,但此时建议强制启用 HTTPS 加密。不要在生产环境中使用 AllowUnencrypted = true,除非你完全了解安全风险。
8.3 常用系统管理任务
Get-Service
Get-Service -Name *sql*
Start-Service -Name Spooler
Stop-Service -Name Spooler
Restart-Service -Name Spooler
Set-Service -Name Spooler -StartupType Automatic
Get-Process
Get-Process -Name notepad
Stop-Process -Name notepad
Get-Process | Sort-Object WorkingSet -Desc | Select-Object -First 10
Get-EventLog -LogName Application -Newest 10
Get-WinEvent -LogName System -MaxEvents 20
Get-WinEvent -FilterHashtable @{
LogName = 'Application'
Level = 2
StartTime = (Get-Date).AddDays(-1)
}
Test-Connection -ComputerName google.com -Count 2
Test-NetConnection -ComputerName github.com -Port 443
Get-NetIPAddress
Get-NetAdapter
Get-NetFirewallRule | Where-Object Enabled -eq True
8.4 WMI/CIM
WMI(Windows Management Instrumentation)是 Windows 系统管理的底层接口。CIM(Common Information Model)是 WMI 的跨平台替代方案:
Get-WmiObject -Class Win32_ComputerSystem
Get-WmiObject -Class Win32_Bios
Get-WmiObject -Class Win32_LogicalDisk
Get-CimInstance -ClassName Win32_ComputerSystem
Get-CimInstance -ClassName Win32_LogicalDisk | Select-Object DeviceID, Size, FreeSpace
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name LIKE '%sql%'"
Get-CimInstance Win32_OperatingSystem
Get-CimInstance Win32_Processor
Get-CimInstance Win32_PhysicalMemory
Get-CimInstance Win32_DiskDrive
Get-CimInstance Win32_NetworkAdapterConfiguration
Get-CimInstance Win32_Service
Get-CimInstance -ComputerName Server01 -ClassName Win32_ComputerSystem
$cimSession = New-CimSession -ComputerName Server01, Server02
Get-CimInstance -CimSession $cimSession -ClassName Win32_LogicalDisk
Remove-CimSession $cimSession
WMI vs CIM 的区别
WMI(Get-WmiObject):Windows 特定的实现,基于 DCOM 协议,仅限 Windows 平台。
CIM(Get-CimInstance):跨平台的标准化实现,基于 WS-Management 协议,使用更现代的 API,支持 PowerShell 7+ 和 Linux/macOS。
推荐:在新脚本中使用 CIM(Get-CimInstance),它有更好的性能和更一致的接口。Get-WmiObject 已被标记为弃用。
8.5 文件系统监控
使用 .NET 的 FileSystemWatcher 可以监控文件系统的变化:
function Watch-FileSystem {
param(
[string]$Path = ".",
[string]$Filter = "*.*",
[switch]$IncludeSubdirectories
)
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = Resolve-Path $Path
$watcher.Filter = $Filter
$watcher.IncludeSubdirectories = $IncludeSubdirectories
$watcher.EnableRaisingEvents = $true
$action = {
$details = $Event.SourceEventArgs
Write-Host "文件变更: $($details.ChangeType) - $($details.FullPath)" -ForegroundColor Cyan
}
Register-ObjectEvent $watcher "Created" -Action $action -SourceIdentifier FileCreated
Register-ObjectEvent $watcher "Changed" -Action $action -SourceIdentifier FileChanged
Register-ObjectEvent $watcher "Deleted" -Action $action -SourceIdentifier FileDeleted
Write-Host "正在监控: $Path (按 Ctrl+C 停止)" -ForegroundColor Green
while ($true) {
Start-Sleep -Seconds 1
}
}
Watch-FileSystem -Path C:\Logs -Filter "*.log" -IncludeSubdirectories
章节小结
PowerShell Remoting(基于 WinRM)实现在远程计算机上执行命令,Enter-PSSession 用于交互式会话,Invoke-Command 用于单次或批量执行。系统管理方面,PowerShell 提供了统一的服务、进程、事件日志、网络等管理命令。CIM(Get-CimInstance)是获取系统信息的推荐方式。FileSystemWatcher 可用于监控文件系统变更。
九、格式化与输出
9.1 格式化命令
PowerShell 提供了一组 Format-* cmdlet 来控制控制台输出的显示方式:
Get-Process | Format-Table Name, CPU, WorkingSet -AutoSize
Get-Process | Format-Table -Property Name, CPU, @{
Label = "Memory(MB)"
Expression = { [math]::Round($_.WorkingSet / 1MB, 2) }
} -AutoSize
Get-Service | Format-Table -Property Name, Status -GroupBy Status
Get-Process -Id $pid | Format-List -Property *
Get-Service | Format-Wide -Column 4
Get-Process -Id $pid | Format-Custom -Depth 2
9.2 导出命令
Get-Process | Select-Object Name, CPU, WorkingSet | Export-Csv -Path processes.csv -NoTypeInformation
$services = Get-Service | Select-Object Name, Status, DisplayName
$services | ConvertTo-Json -Depth 2 | Out-File services.json
$data = Get-Content config.json | ConvertFrom-Json
Get-Process | ConvertTo-Xml -As Document | Out-File processes.xml
Get-Process | ConvertTo-Html -Property Name, CPU, WorkingSet -Title "进程报表" |
Out-File report.html
Get-Process | Export-Clixml -Path processes.clixml
$processes = Import-Clixml -Path processes.clixml
Get-Service | Out-File -FilePath services.txt -Encoding utf8
Get-Process | Out-GridView -Title "进程管理"
New-Item -Path C:\temp -ItemType Directory -ErrorAction SilentlyContinue | Out-Null
9.3 控制台输出控制
Write-Host "成功消息" -ForegroundColor Green -BackgroundColor Black
Write-Host "警告消息" -ForegroundColor Yellow
Write-Host "错误消息" -ForegroundColor Red -BackgroundColor DarkRed
Write-Output "这条消息会进入管道"
Write-Verbose "正在处理文件..."
Write-Debug "当前变量值: $var"
Write-Warning "这个操作可能耗时较长"
Write-Error "文件未找到"
1..100 | ForEach-Object {
Write-Progress -Activity "正在处理" -Status "进度: $_%" -PercentComplete $_
Start-Sleep -Milliseconds 50
}
Write-Information "这是一条信息消息" -InformationAction Continue
| 输出命令 |
输出流 |
用途 |
管道传递 |
| Write-Output |
主输出流(1) |
正常输出 |
是 |
| Write-Host |
信息流(6) |
彩色输出到控制台 |
否 |
| Write-Verbose |
详细流(4) |
详细执行信息 |
否 |
| Write-Debug |
调试流(5) |
调试信息 |
否 |
| Write-Warning |
警告流(3) |
警告信息 |
否 |
| Write-Error |
错误流(2) |
错误记录 |
否 |
| Write-Progress |
进度流(6) |
进度条 |
否 |
| Write-Information |
信息流(6) |
结构化信息 |
否 |
最佳实践:在脚本中,使用 Write-Output 返回数据(数据会进入管道),使用 Write-Verbose 提供细节信息,使用 Write-Warning 报告潜在问题,使用 Write-Error 报告错误。不要使用 Write-Host 输出数据,因为它会绕过管道流。
章节小结
Format-Table、Format-List、Format-Wide 控制控制台输出格式。Export-Csv、ConvertTo-Json、ConvertTo-Html 用于导出数据。PowerShell 有 6 个输出流,正确使用不同的 Write-* 命令可以提高脚本的可读性和可维护性。Write-Output 是返回数据的正确方式,Write-Verbose 和 Write-Debug 提供可选细节。
十、PowerShell 环境配置
10.1 配置文件 $PROFILE
$PROFILE 是一个自动变量,指向当前用户当前主机的 PowerShell 配置文件。每次启动 PowerShell 时,会自动执行此配置文件中的代码。
PowerShell 有多个配置文件,按加载顺序排列:
| 优先级 |
配置文件路径 |
作用范围 |
| 1 |
$PSHOME\profile.ps1 |
所有用户、所有主机 |
| 2 |
$PSHOME\Microsoft.PowerShell_profile.ps1 |
所有用户、当前主机 |
| 3 |
$PROFILE.CurrentUserAllHosts |
当前用户、所有主机 |
| 4 |
$PROFILE(= CurrentUserCurrentHost) |
当前用户、当前主机(最常用) |
$PROFILE
$PROFILE | Get-Member -MemberType NoteProperty
Test-Path $PROFILE
if (-not (Test-Path $PROFILE)) {
New-Item -Path $PROFILE -ItemType File -Force
Write-Host "已创建配置文件: $PROFILE"
}
code $PROFILE
. $PROFILE
10.2 常用 $PROFILE 配置模板
function prompt {
$location = Get-Location
$branch = & git branch --show-current 2>$null
if ($branch) {
"PS [$location] ($branch) > "
} else {
"PS [$location] > "
}
}
Set-Alias -Name grep -Value Select-String
Set-Alias -Name touch -Value New-Item
Set-Alias -Name which -Value Get-Command
function gs { git status }
function ga { git add @args }
function gc { git commit -m @args }
function gp { git push }
function gl { git log --oneline --graph --all --decorate }
function projects { Set-Location C:\Users\$env:USERNAME\Projects }
function notes { Set-Location D:\claude\www.shjiaoai.com\LearningNotes }
$env:EDITOR = "code"
$env:PAGER = "less"
Set-PSReadLineOption -PredictionSource History
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineOption -EditMode Windows
Set-PSReadLineKeyHandler -Chord 'Ctrl+d' -Function DeleteChar
Import-Module -Name PSReadLine -ErrorAction SilentlyContinue
$SortByDefault = @{Expression={"Name"}; Ascending=$true}
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
Write-Host "配置文件已加载" -ForegroundColor Green
PSReadLine 配置技巧
Set-PSReadLineOption -PredictionSource History 启用基于历史命令的自动补全建议(类似 Fish Shell 的体验)。配合 -PredictionViewStyle ListView 可以显示下拉列表供选择。这是提升交互式使用体验最有效的单一配置。
10.3 PowerShell Gallery
PowerShell Gallery 是微软官方的模块仓库(类似 npm 或 PyPI),地址为 https://www.powershellgallery.com/。
Get-PackageProvider -Name NuGet -ForceBootstrap
Find-Module -Name *PSReadLine*
Find-Module -Name *Pester*
Find-Module -Name *WindowsUpdate*
Install-Module -Name Pester -Scope CurrentUser -Force
Install-Module -Name PSWindowsUpdate -Scope CurrentUser
Get-InstalledModule
Update-Module -Name Pester
Uninstall-Module -Name Pester
Save-Module -Name Pester -Path C:\OfflineModules
10.4 常用模块推荐
| 模块名称 |
用途 |
安装命令 |
| PSReadLine |
命令行编辑增强(语法高亮、自动补全) |
Install-Module PSReadLine |
| Pester |
单元测试框架(PowerShell 版 xUnit) |
Install-Module Pester |
| PSWindowsUpdate |
Windows Update 管理 |
Install-Module PSWindowsUpdate |
| Terminal-Icons |
文件图标美化(在终端中显示图标) |
Install-Module Terminal-Icons |
| PSFzf |
集成 fzf 模糊搜索工具 |
Install-Module PSFzf |
| PSScriptAnalyzer |
代码检查(PowerShell 版 ESLint) |
Install-Module PSScriptAnalyzer |
| Microsoft.Graph |
Microsoft Graph API 管理 |
Install-Module Microsoft.Graph |
| Az |
Azure 云资源管理 |
Install-Module Az |
| PowerShellGet |
模块包管理器本身 |
通常预装 |
| PSExcel |
Excel 文件读写(无需安装 Office) |
Install-Module PSExcel |
章节小结
$PROFILE 是 PowerShell 的配置文件,用于自定义别名、函数、提示符和行为。配置 PSReadLine 的预测功能可以极大提升交互体验。PowerShell Gallery 提供了丰富的第三方模块,Find-Module 搜索、Install-Module 安装、Get-InstalledModule 查看已安装的模块。推荐安装 PSReadLine、Pester(测试)、PSScriptAnalyzer(代码检查)、Terminal-Icons(美化)等常用模块。
十一、PowerShell 调试与最佳实践
11.1 调试技术
PowerShell 提供了多种调试方法,从简单的写日志到专业的断点调试:
Set-PSBreakpoint -Script .\MyScript.ps1 -Line 10
Set-PSBreakpoint -Script .\MyScript.ps1 -Variable myVar
Set-PSBreakpoint -Script .\MyScript.ps1 -Command Get-Service
Get-PSBreakpoint
Remove-PSBreakpoint -Id 0
Remove-PSBreakpoint -Script .\MyScript.ps1
function Process-Data {
param($data)
$result = $data * 2
Wait-Debugger
$result += 10
return $result
}
11.2 PSScriptAnalyzer
PSScriptAnalyzer 是 PowerShell 的静态代码分析工具,相当于 PowerShell 版的 ESLint 或 Pylint:
Install-Module -Name PSScriptAnalyzer -Scope CurrentUser
Invoke-ScriptAnalyzer -Path .\MyScript.ps1
Invoke-ScriptAnalyzer -Path .\MyModule\
Invoke-ScriptAnalyzer -Path .\MyScript.ps1 -ExcludeRule PSAvoidUsingCmdletAliases
$settings = @{
Rules = @{
PSAvoidUsingCmdletAliases = @{ Enable = $true }
PSUseDeclaredVarsMoreThanAssignments = @{ Enable = $false }
}
}
Invoke-ScriptAnalyzer -Path .\MyScript.ps1 -Settings $settings
11.3 Pester 单元测试
Pester 是 PowerShell 的单元测试框架,是确保脚本质量的重要工具:
Install-Module -Name Pester -Scope CurrentUser -Force
BeforeAll {
. .\MyScript.ps1
}
Describe "Get-Greeting 函数测试" {
It "应返回正确的问候语" {
$result = Get-Greeting -Name "World"
$result | Should -Be "Hello World, you are 0 years old."
}
It "应支持年龄参数" {
$result = Get-Greeting -Name "Alice" -Age 30
$result | Should -Be "Hello Alice, you are 30 years old."
}
It "参数为空时不应抛出异常" {
{ Get-Greeting } | Should -Not -Throw
}
}
Describe "Measure-FileSize 函数测试" {
It "应正确计算文件大小" {
$tempFile = New-TemporaryFile
Set-Content -Path $tempFile -Value "A" * 1000
$result = $tempFile.FullName | Measure-FileSize -Unit KB
$result.Size | Should -BeGreaterThan 0
Remove-Item $tempFile
}
}
Invoke-Pester -Path .\MyFunction.Tests.ps1
Invoke-Pester -Path .\Tests\ -OutputFile test-results.xml -OutputFormat NUnitXml
测试驱动开发:推荐在编写 PowerShell 函数时使用 Pester 编写测试。一个良好的测试应该覆盖正常路径、边界条件和错误路径。养成先写测试(或至少同时写测试)的习惯,可以显著提高脚本的可靠性。
11.4 安全最佳实践
$secureString = Read-Host -Prompt "输入密码" -AsSecureString
$credential = New-Object System.Management.Automation.PSCredential("username", $secureString)
$credential | Export-Clixml -Path "C:\secrets\mycred.xml"
$cred = Import-Clixml -Path "C:\secrets\mycred.xml"
$cert = New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My `
-Subject "CN=My Code Signing Cert" -Type CodeSigningCert
Set-AuthenticodeSignature -FilePath .\MyScript.ps1 -Certificate $cert
$password = "P@ssw0rd123"
$password = $env:MY_APP_PASSWORD
Install-Module -Name SomeModule -Scope CurrentUser
function Set-UserAge {
param(
[Parameter(Mandatory)]
[ValidateRange(0, 150)]
[int]$Age
)
Write-Output "年龄设置为: $Age"
}
11.5 错误处理模式
function Invoke-CriticalOperation {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$FilePath
)
begin {
if (-not (Test-Path $FilePath)) {
throw "文件不存在: $FilePath"
}
$caller = (Get-PSCallStack)[1].Command
Write-Verbose "被 [$caller] 调用,处理文件: $FilePath"
}
process {
try {
$content = Get-Content -Path $FilePath -ErrorAction Stop
$result = $content | ForEach-Object {
try {
[PSCustomObject]@{
Raw = $_
Length = $_.Length
IsEmpty = [string]::IsNullOrWhiteSpace($_)
}
}
catch {
Write-Warning "行处理失败: $($_.Exception.Message)"
continue
}
}
return $result
}
catch {
$errorInfo = [PSCustomObject]@{
Time = Get-Date
Function = $MyInvocation.MyCommand
FilePath = $FilePath
Exception = $_.Exception.Message
Line = $_.InvocationInfo.ScriptLineNumber
}
Write-Error "操作失败: $($errorInfo | ConvertTo-Json -Compress)"
throw
}
finally {
Write-Verbose "文件处理完成: $FilePath"
}
}
}
章节小结
PowerShell 支持设置断点调试(Set-PSBreakpoint),VS Code 提供图形化调试体验。PSScriptAnalyzer 是代码质量检查工具,Pester 是单元测试框架。安全方面应使用安全字符串处理密码、Export-Clixml 加密存储凭据、数字签名脚本、最小权限原则安装模块。多层错误处理模式(内层 try/catch 继续、外层 try/catch 终止)提供了灵活的错误控制。
十二、在 Claude Code 中使用 PowerShell
12.1 Claude Code 在 Windows 上的默认 Shell 问题
Claude Code 默认使用 Bash 语法来执行命令。在 Linux 和 macOS 上这不是问题,但在 Windows 上,默认的 cmd.exe 或 PowerShell 可能无法直接理解 Bash 语法的命令。
例如,Claude Code 可能会尝试运行 ls -la 或 grep "pattern" file.txt,这些命令在 PowerShell 中有不同的语法和别名。虽然 PowerShell 有别名系统(如 ls 映射到 Get-ChildItem),但许多 Bash 特有的命令(如 grep、awk、sed)在 PowerShell 中并不存在。
Get-ChildItem | Where-Object { $_.Extension -eq ".txt" }
(Get-Content file.txt).Count
$env:PATH -split ';'
Get-Content list.txt | Sort-Object -Unique
Get-Content file.txt | Select-Object -First 5
12.2 让 Claude Code 使用 PowerShell
你可以通过配置 settings.json 来让 Claude Code 使用 PowerShell 而不是 cmd.exe。
方法1:在项目根目录创建 .claude/settings.json:
{
"shellCommand": {
"command": "pwsh.exe -NoProfile -Command",
"args": []
}
}
方法2:全局设置(在用户目录 ~/.claude/settings.json 中配置):
{
"shellCommand": {
"command": "pwsh.exe",
"args": ["-NoProfile", "-Command", "$input"]
}
}
配置注意事项
修改 shellCommand 配置后,Claude Code 会使用指定的 Shell 执行所有命令。请确保 pwsh.exe 在 PATH 中(即可以在终端中直接输入 pwsh 启动)。如果 PowerShell 7 未安装,可使用 powershell.exe(Windows PowerShell 5.1)代替。
12.3 推荐工作流:PowerShell 7 + Windows Terminal
在 Windows 上使用 Claude Code 的推荐工作流:
- 安装 PowerShell 7:从 Microsoft Store 或 GitHub Releases 安装最新版 PowerShell 7。
- 安装 Windows Terminal:从 Microsoft Store 安装 Windows Terminal,并将默认配置文件设置为 PowerShell 7。
- 配置 Claude Code:在
.claude/settings.json 中设置 Shell 为 PowerShell 7。
- 优化 $PROFILE:配置 $PROFILE 文件,添加常用的别名和函数。
- 安装 PSReadLine:确保 PSReadLine 已更新到最新版本,启用预测式自动补全。
Write-Host "===== 环境检查 =====" -ForegroundColor Cyan
$psVersion = $PSVersionTable.PSVersion
Write-Host "PowerShell 版本: $psVersion"
if ($psVersion.Major -lt 7) {
Write-Warning "建议升级到 PowerShell 7"
}
$claudePath = Get-Command claude -ErrorAction SilentlyContinue
if ($claudePath) {
Write-Host "Claude Code 路径: $($claudePath.Source)" -ForegroundColor Green
} else {
Write-Warning "Claude Code 未安装或不在 PATH 中"
Write-Host "安装命令: npm install -g @anthropic-ai/claude-code"
}
$settingsPath = "$env:USERPROFILE\.claude\settings.json"
if (Test-Path $settingsPath) {
Write-Host "Claude Code 设置: $settingsPath" -ForegroundColor Green
Get-Content $settingsPath | ConvertFrom-Json | Format-List
} else {
Write-Warning "Claude Code 全局设置文件不存在"
}
if ($env:ANTHROPIC_API_KEY) {
Write-Host "API Key: 已设置 ✓" -ForegroundColor Green
} else {
Write-Warning "API Key: 未设置"
Write-Host "请设置: `$env:ANTHROPIC_API_KEY = '你的密钥'"
}
Write-Host "=====================" -ForegroundColor Cyan
12.4 在 Claude Code 提示词中指定 PowerShell
当你在 Claude Code 中编写提示词时,可以明确指定使用 PowerShell 语法,这样 Claude Code 会生成适合 PowerShell 环境的命令和代码:
提示词模板示例
"请使用 PowerShell 7 语法执行以下任务。所有命令需要在 Windows 环境中运行,请使用 PowerShell cmdlet 而非 Bash 命令。例如:使用 Get-ChildItem 而非 ls,使用 Select-String 而非 grep。"
你也可以在项目根目录的 CLAUDE.md 文件中添加以下内容,让 Claude Code 自动了解你的 PowerShell 偏好:
## 开发环境
- 操作系统:Windows 11
- Shell:PowerShell 7 (pwsh.exe)
- 终端:Windows Terminal
- Claude Code 运行于 PowerShell 环境
## Shell 命令约定
- 文件操作使用 PowerShell cmdlet(Get-ChildItem, Select-String 等)
- 管道操作使用对象管道(Where-Object, ForEach-Object 等)
- 环境变量使用 $env: 语法
- 路径使用反斜杠 \ 或正斜杠 /(PowerShell 两者皆支持)
- 命令执行使用 & 调用运算符
12.5 实用 PowerShell 提示词模板
以下是一些在 Claude Code 中使用的实用 PowerShell 相关提示词模板:
| 场景 |
提示词模板 |
| 文件批量操作 |
"用 PowerShell 批量重命名当前目录下的所有 .txt 文件,添加前缀 'note_'" |
| 系统信息收集 |
"使用 PowerShell 收集本机系统信息(OS版本、CPU、内存、磁盘)并以表格形式输出" |
| 日志分析 |
"编写一个 PowerShell 脚本分析 Windows 事件日志,查找过去24小时内的错误事件" |
| 进程管理 |
"使用 PowerShell 查找内存占用前5的进程,并以美观的表格输出" |
| 模块管理 |
"编写 PowerShell 脚本检查并安装缺失的常用模块(PSReadLine, Pester, PSScriptAnalyzer)" |
| 定时任务 |
"使用 PowerShell 创建 Windows 计划任务,每天凌晨3点运行备份脚本" |
| 脚本优化 |
"帮我优化这个 PowerShell 脚本,添加错误处理、Verbose 输出和 WhatIf 支持" |
核心建议:在 Windows 上使用 Claude Code 时,强烈建议在项目 CLAUDE.md 中明确声明使用 PowerShell 环境。这样 Claude Code 在生成命令时会自动采用 PowerShell 语法,避免在 Windows 上执行不兼容的 Bash 命令。配合 settings.json 中配置的 pwsh.exe,可以打造流畅的 Windows + Claude Code 开发体验。
章节小结
Claude Code 在 Windows 上默认使用 Bash 语法可能导致不兼容。通过 .claude/settings.json 配置 pwsh.exe 作为默认 Shell,并在 CLAUDE.md 中声明 PowerShell 环境,可以让 Claude Code 生成适配 Windows 的命令。推荐的开发组合是 PowerShell 7 + Windows Terminal + Claude Code。在提示词中明确指定 PowerShell 语法要求,可以获得更准确的结果。
十三、核心要点总结
PowerShell 全景路线图
以下是完整的 PowerShell 知识体系总结。掌握这些内容后,你就能在日常开发、系统管理和 Claude Code 使用中充分发挥 PowerShell 的能力。
| 领域 |
核心知识点 |
关键命令/概念 |
熟练度目标 |
| 基础命令 |
文件操作、导航、获取帮助 |
Get-ChildItem, Set-Location, Get-Help, Get-Command, Get-Member |
日常使用,无需思考 |
| 对象管道 |
筛选、排序、分组、遍历、选择属性 |
Where-Object, Sort-Object, Group-Object, ForEach-Object, Select-Object |
能够组合3个以上命令的管道 |
| 提供程序 |
统一访问文件、注册表、环境变量、证书 |
Get-Item, Set-Item, New-Item, $env:, HKCU:, Cert: |
能在注册表中自如导航 |
| 脚本编程 |
函数、高级函数、模块、错误处理 |
function, [CmdletBinding()], param, try/catch, .psm1 |
能编写可重用的工具函数 |
| 流程控制 |
条件、循环、switch 高级匹配 |
if/else, switch, foreach, for, while |
能编写复杂逻辑脚本 |
| 远程管理 |
WinRM 远程执行、CIM 查询 |
Invoke-Command, Enter-PSSession, Get-CimInstance |
能管理多台远程计算机 |
| 系统管理 |
服务、进程、事件日志、网络 |
Get-Service, Get-Process, Get-WinEvent, Test-NetConnection |
能完成日常系统管理任务 |
| 环境配置 |
$PROFILE、PSReadLine、模块安装 |
$PROFILE, Install-Module, Set-PSReadLineOption, PowerShell Gallery |
拥有个性化的开发环境 |
| 调试与测试 |
断点、代码检查、单元测试 |
Set-PSBreakpoint, PSScriptAnalyzer, Pester |
能对脚本进行系统测试 |
| Claude Code 集成 |
配置 PowerShell 为默认 Shell |
settings.json, CLAUDE.md, pwsh.exe |
流畅地在 Windows 上使用 Claude Code |
核心中的核心——最需要牢记的10个知识点:
Get-Help 命令名 -- 获取任何命令的帮助(-Examples 看示例)
Get-Command -Noun 名词 -- 按名词发现所有相关命令
命令 | Get-Member -- 查看对象的属性和方法
Where-Object { 条件 } -- 筛选管道中的对象
Select-Object -First N -- 选择对象或创建计算属性
ForEach-Object { 处理逻辑 } -- 对每个对象执行操作
try { } catch { } finally { } -- 结构化错误处理
$PROFILE -- 配置文件,自定义环境的起点
Install-Module 模块名 -- 从 PowerShell Gallery 安装模块
$PSVersionTable -- 查看 PowerShell 版本和环境信息
PowerShell 的哲学
PowerShell 的设计哲学可以概括为三点:
1. 面向对象而非文本:管道中传递的是结构化对象,而不是需要解析的字符串。这消除了 Shell 脚本中最容易出错的环节——文本解析。
2. 命名一致性:所有命令遵循动词-名词规范,Get-Command、Get-Service、Get-Process —— 看到名字就知道功能。这种一致性让"发现命令"变得简单。
3. 一切皆命令:函数、脚本、外部程序、cmdlet,都被统一为"命令"的概念。无论来源如何,调用方式一致,可以无缝组合。
学习路径建议
第1周:掌握基础命令(Get-ChildItem, Set-Location)和获取帮助(Get-Help, Get-Command)。每天至少打开终端操作10次。
第2周:掌握对象管道(Where-Object, Select-Object, ForEach-Object)。尝试用一行命令完成日常文件管理任务。
第3周:学习编写函数和脚本。从简单的工具函数开始,逐步加入参数和错误处理。
第4周:学习远程管理、模块使用、配置 $PROFILE。配置个性化的 PowerShell 环境。
持续:阅读他人写的优质 PowerShell 脚本,坚持代码审查,使用 Pester 编写测试。
Get-Service |
Where-Object Status -eq 'Running' |
Group-Object StartType |
Select-Object @{N='启动类型';E={$_.Name}}, Count |
Sort-Object Count -Descending |
Format-Table -AutoSize
全文总结
PowerShell 是一个面向对象的现代化 Shell 和脚本语言,它彻底改变了 Windows 系统的管理和自动化方式。与传统的 Bash 不同,PowerShell 的管道传递 .NET 对象而非纯文本,命令遵循标准的动词-名词命名规范,脚本可以访问完整的 .NET 类型系统。
从基础的文件操作到复杂的系统管理,从本地自动化到远程计算机管理,PowerShell 提供了一套统一、一致的工具集。在 Windows 上,它不仅是替代 CMD 的升级版命令行,更是系统管理员和开发者的核心生产力工具。
对于使用 Claude Code 的 Windows 用户,配置 PowerShell 7 作为默认 Shell,并在 CLAUDE.md 中声明使用 PowerShell 环境,可以避免跨平台语法不兼容的问题,获得更流畅的开发体验。
掌握 PowerShell 不是一蹴而就的事,但只要你坚持从日常操作中积累,不断尝试用一行管道命令解决实际问题,你很快就能体会到"对象管道 + 统一命令 + 完整 .NET 支持"带来的强大生产力提升。
记住:Get-Help 是你最好的老师,Get-Command 是你最有力的发现工具,管道是你最强大的武器。