mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
764 字
2 分钟
PowerShell 实用指南
2021-04-20

凌晨三点,服务器告警:某个 Windows 服务的日志文件涨到了 50GB,磁盘即将写满。你 SSH 登上去,想用 dir 看看哪些文件最大,输出却只有一串文件名。需要按大小排序?需要筛选扩展名?需要批量压缩?在 CMD 里这些操作要写批处理脚本,但在 PowerShell 里,一条管道命令就够了。PowerShell 不是”加强版的 CMD”,而是一个面向对象的脚本语言,理解它的管道模型和 Cmdlet 体系,日常运维效率可以提升数倍。

一、PowerShell 与 CMD 的区别#

1.1 核心差异#

特性CMDPowerShell
数据类型纯文本.NET 对象
管道传递字符串流对象流
命令命名随意(dir, copy动词-名词(Get-ChildItem
别名系统兼容 CMD/Linux 命令别名
远程管理无原生支持WinRM(Windows 远程管理) 原生支持
脚本语言批处理(极弱)完整编程语言
可扩展性模块、Cmdlet、Provider

1.2 版本演进#

版本系统重大变化
1.0Windows XP初始版本
2.0Windows 7ISE(集成脚本环境)、远程
3.0Windows 8工作流、计划任务
5.0Windows 10类定义、DSC
7.x跨平台.NET Core 重写,跨平台

二、Cmdlet 与管道#

2.1 Cmdlet 命名规范#

Cmdlet 遵循 动词-名词 命名:

Terminal window
Get-Process # 获取进程
Stop-Process # 停止进程
Set-Location # 设置位置
New-Item # 创建项
Remove-Item # 删除项
Write-Output # 写入输出

常用动词:

动词用途示例
Get查询/获取Get-Service
Set修改/设置Set-ExecutionPolicy
New创建New-Item
Remove删除Remove-Item
Start启动Start-Service
Stop停止Stop-Process
Add添加Add-Member
Select选择Select-Object
Where过滤Where-Object
ForEach遍历ForEach-Object

2.2 管道:对象流#

PowerShell 管道传递的是 .NET 对象,不是文本字符串。这是它与 Unix Shell 的本质区别:

Terminal window
# CMD/Unix: 文本处理
dir | findstr ".log" | sort
# PowerShell: 对象处理
Get-ChildItem |
Where-Object { $_.Extension -eq ".log" } |
Sort-Object Length -Descending |
Select-Object Name, Length, LastWriteTime

$_ 是管道中的当前对象变量。

2.3 常用管道命令#

Terminal window
# 过滤
Get-Process | Where-Object { $_.CPU -gt 100 }
# 选择属性
Get-Process | Select-Object Name, CPU, WorkingSet
# 排序
Get-ChildItem | Sort-Object Length -Descending
# 分组
Get-Process | Group-Object Company
# 统计
Get-ChildItem | Measure-Object Length -Sum -Average
# 去重
1,2,2,3,3,3 | Select-Object -Unique
# 取前 N 条
Get-Process | Select-Object -First 10

2.4 输出格式化#

Terminal window
# 表格
Get-Process | Format-Table Name, CPU -AutoSize
# 列表(属性竖排)
Get-Process | Format-List Name, CPU, WorkingSet
# 宽格式
Get-ChildItem | Format-Wide Name -Column 4
# 自定义
Get-Process | Format-Table @{
Label="进程名"; Expression={$_.Name}
}, @{
Label="内存(MB)"; Expression={[math]::Round($_.WorkingSet64/1MB, 2)}
}

三、变量与数据类型#

3.1 变量#

Terminal window
# 变量以 $ 开头
$name = "PowerShell"
$count = 42
$pi = 3.14159
$items = @(1, 2, 3) # 数组
$dict = @{ a = 1; b = 2 } # 哈希表
# 强类型
[int]$age = 30
[string]$title = "Admin"
# 变量作用域
$script:config = @{} # 脚本作用域
$global:count = 0 # 全局作用域
$env:PATH # 环境变量

3.2 数据类型#

Terminal window
# 基本类型
[int] 42
[string] "hello"
[bool] $true / $false
[datetime] Get-Date
# 集合类型
[array] @(1, 2, 3)
[hashtable] @{ key = "value" }
# .NET 类型
[System.IO.FileInfo]
[System.Net.WebClient]
[System.Text.StringBuilder]

3.3 类型转换#

Terminal window
# 显式转换
[int]"42" # 字符串 → 整数
[string]42 # 整数 → 字符串
[datetime]"2025-01-01"
# -as 操作符(转换失败返回 $null 而非报错)
"42" -as [int] # 42
"hello" -as [int] # $null
"3.14" -as [double] # 3.14

四、控制流#

4.1 条件判断#

if/elseif/else
if ($age -gt 18) {
"Adult"
} elseif ($age -gt 12) {
"Teenager"
} else {
"Child"
}
# switch
switch ($day) {
"Monday" { "Start of week" }
"Friday" { "End of week" }
default { "Midweek" }
}
# switch 支持正则和通配符
switch -regex ($path) {
"\.log$" { "Log file" }
"\.txt$" { "Text file" }
default { "Unknown" }
}

4.2 比较操作符#

操作符含义示例
-eq等于$a -eq 10
-ne不等于$a -ne 10
-gt大于$a -gt 10
-ge大于等于$a -ge 10
-lt小于$a -lt 10
-le小于等于$a -le 10
-like通配符匹配"hello" -like "h*"
-notlike通配符不匹配"hello" -notlike "x*"
-match正则匹配"abc" -match "^a"
-notmatch正则不匹配"abc" -notmatch "^x"
-contains集合包含@(1,2,3) -contains 2
-in在集合中2 -in @(1,2,3)

4.3 循环#

Terminal window
# for
for ($i = 0; $i -lt 10; $i++) {
Write-Output $i
}
# foreach
foreach ($item in $collection) {
Write-Output $item
}
# while
while ($condition) {
# ...
}
# do-while
do {
# 至少执行一次
} while ($condition)
# ForEach-Object(管道)
1..10 | ForEach-Object { $_ * 2 }

五、函数与脚本块#

5.1 函数#

Terminal window
# 简单函数
function Get-Greeting {
param(
[string]$Name = "World"
)
return "Hello, $Name!"
}
Get-Greeting -Name "PowerShell"
# 高级函数(支持管道输入)
function Get-FileSize {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
[string]$Path
)
process {
$item = Get-Item $Path
[PSCustomObject]@{
Name = $item.Name
SizeKB = [math]::Round($item.Length / 1KB, 2)
}
}
}
# 使用管道
"C:\temp\file1.txt", "C:\temp\file2.txt" | Get-FileSize

5.2 脚本块#

Terminal window
# 匿名函数
$filter = { $_.Length -gt 1MB }
Get-ChildItem | Where-Object $filter
# 调用脚本块
$block = { param($x) $x * 2 }
& $block 21 # 42
# 传递脚本块
function Invoke-Twice {
param([scriptblock]$Action)
& $Action
& $Action
}
Invoke-Twice { Write-Output "Hello" }

六、文件与注册表操作#

6.1 文件操作#

Terminal window
# 浏览文件系统
Get-ChildItem -Path "C:\temp" -Recurse -Filter "*.log"
Set-Location "C:\temp"
Get-Location
# 文件读写
Get-Content "config.txt" # 读取
Set-Content "output.txt" "Hello" # 写入
Add-Content "log.txt" "New entry" # 追加
Import-Csv "data.csv" | Format-Table # 读取 CSV
# 文件管理
Copy-Item "src.txt" "dst.txt"
Move-Item "old.txt" "new.txt"
Remove-Item "temp.txt" -Force
New-Item -ItemType File -Path "new.txt"
New-Item -ItemType Directory -Path "logs"
# 搜索
Select-String -Path "*.log" -Pattern "ERROR"

6.2 注册表操作#

Terminal window
# 浏览注册表
Set-Location HKLM:\SOFTWARE
Get-ChildItem
# 读取
Get-ItemProperty "HKLM:\SOFTWARE\MyApp"
# 写入
New-ItemProperty -Path "HKLM:\SOFTWARE\MyApp" `
-Name "Version" -Value "1.0" -PropertyType String
# 删除
Remove-ItemProperty -Path "HKLM:\SOFTWARE\MyApp" -Name "Version"

七、远程管理#

7.1 WinRM 配置#

Terminal window
# 启用 WinRM(需管理员权限)
Enable-PSRemoting -Force
# 信任远程主机
Set-Item WSMan:\localhost\Client\TrustedHosts "192.168.1.*" -Force
# 测试连接
Test-WSMan -ComputerName "server01"

7.2 远程执行#

Terminal window
# 单次远程命令
Invoke-Command -ComputerName "server01" -ScriptBlock {
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5
}
# 带参数
Invoke-Command -ComputerName "server01" -ArgumentList "nginx" -ScriptBlock {
param($name)
Get-Service -Name $name
}
# 多台服务器
Invoke-Command -ComputerName "server01", "server02", "server03" -ScriptBlock {
Get-Service | Where-Object { $_.Status -eq "Stopped" }
}

7.3 远程会话#

Terminal window
# 建立持久会话
$session = New-PSSession -ComputerName "server01"
# 在会话中执行多个命令
Invoke-Command -Session $session -ScriptBlock { Get-Process }
Invoke-Command -Session $session -ScriptBlock { Get-Service }
# 交互式会话
Enter-PSSession -ComputerName "server01"
# 现在直接在远程服务器操作
Exit-PSSession
# 清理
Remove-PSSession $session

八、错误处理#

8.1 错误类型#

Terminal window
# 终止错误(异常)
# 非终止错误(错误流)
# 查看错误
$Error[0] # 最近一个错误
$Error[0].Exception.Message # 错误消息
# 错误偏好设置
$ErrorActionPreference = "Stop" # 非终止错误当作终止错误处理

8.2 try/catch/finally#

Terminal window
try {
$result = Get-Content "nonexistent.txt" -ErrorAction Stop
} catch [System.IO.FileNotFoundException] {
Write-Warning "File not found: $_"
} catch {
Write-Error "Unexpected error: $_"
} finally {
# 无论是否出错都会执行
Write-Output "Cleanup done"
}

8.3 常用错误处理模式#

Terminal window
# -ErrorAction 参数
Get-ChildItem -Path "C:\maybe-missing" -ErrorAction SilentlyContinue
# -ErrorVariable 捕获错误
Get-ChildItem "nonexistent" -ErrorVariable myErr -ErrorAction SilentlyContinue
if ($myErr) {
Write-Warning "Error occurred: $($myErr[0].Exception.Message)"
}

九、模块管理#

9.1 模块操作#

Terminal window
# 查找模块
Find-Module -Name "Azure*"
# 安装模块
Install-Module -Name "Az" -Scope CurrentUser
# 导入模块
Import-Module Az.Compute
# 查看已安装模块
Get-Module -ListAvailable
# 查看已加载模块
Get-Module
# 更新模块
Update-Module "Az"

9.2 常用模块#

模块用途
AzAzure 管理
SqlServerSQL Server 管理
ActiveDirectoryAD 域管理
Pester测试框架
PSReadLine命令行增强
ImportExcelExcel 操作

十、实用技巧#

10.1 性能优化#

Terminal window
# 差:管道中频繁调用外部命令
Get-ChildItem | ForEach-Object { cmd /c "echo $_" }
# 好:使用 PowerShell 原生命令
Get-ChildItem | ForEach-Object { Write-Output $_.Name }
# 差:循环中重复查询
foreach ($name in $names) {
Get-ADUser -Identity $name # 每次都查询
}
# 好:一次查询
$users = Get-ADUser -Filter { Name -in $names }

10.2 安全实践#

Terminal window
# 执行策略
Get-ExecutionPolicy
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# 安全执行脚本
powershell -ExecutionPolicy Bypass -File script.ps1
# 不要在脚本中硬编码密码
# 使用 Get-Credential
$cred = Get-Credential
Invoke-Command -ComputerName "server01" -Credential $cred -ScriptBlock { ... }
# 使用 SecureString
$secPassword = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("admin", $secPassword)

10.3 命令速查#

需求命令
查找命令Get-Command *process*
查看帮助Get-Help Get-Process -Full
查看别名Get-Alias -Definition Get-ChildItem
查看成员`Get-Process
查看类型`Get-Process
查看历史Get-History
执行历史Invoke-History 5

参考资料#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

PowerShell 实用指南
https://blog.souloss.com/posts/language/language-powershell-guide/
作者
Souloss
发布于
2021-04-20
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时