PowerShell实现数据中心能耗优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Get-EnergyConsumption {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$ServerName
)

$cpuUsage = (Get-Counter -ComputerName $ServerName '\Processor(_Total)\% Processor Time').CounterSamples.CookedValue
$memoryUsage = (Get-Counter -ComputerName $ServerName '\Memory\Available MBytes').CounterSamples.CookedValue

# 计算能耗估算(基于Intel Xeon处理器能效模型)
$energyCost = [math]::Round(($cpuUsage * 0.7) + ($memoryUsage * 0.05), 2)

[PSCustomObject]@{
ServerName = $ServerName
Timestamp = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
CPUUsage = "$cpuUsage%"
MemoryAvailable = "${memoryUsage}MB"
EstimatedPower = "${energyCost}W"
OptimizationSuggestion = if ($cpuUsage -lt 30) {'建议启用节能模式'} else {'建议优化负载分配'}
}
}

# 监控服务器集群
'SRV01','SRV02','SRV03' | ForEach-Object {
Get-EnergyConsumption -ServerName $_ -Verbose
} | Export-Csv -Path "Energy_Report_$(Get-Date -Format yyyyMMdd).csv"

核心功能:

  1. 实时监控服务器CPU/内存使用率
  2. 基于能效模型估算功耗
  3. 生成节能优化建议

扩展方向:

  • 集成IPMI接口获取实际功耗
  • 添加自动电源模式调整功能
  • 与Kubernetes集成实现智能调度

PowerShell 技能连载 - 跨平台脚本编写技巧

随着PowerShell Core的发展,PowerShell已经成为真正的跨平台自动化工具。本文将介绍如何编写在Windows、Linux和macOS上都能正常运行的PowerShell脚本。

检测操作系统平台

首先,让我们学习如何检测脚本运行的操作系统平台:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Get-CurrentPlatform {
if ($IsWindows -or ($PSVersionTable.PSVersion.Major -lt 6 -and $env:OS -eq "Windows_NT")) {
return "Windows"
}
elseif ($IsLinux) {
return "Linux"
}
elseif ($IsMacOS) {
return "macOS"
}
else {
return "Unknown"
}
}

$platform = Get-CurrentPlatform
Write-Host "当前运行平台: $platform"

处理文件路径

在不同操作系统上,文件路径的格式和分隔符有所不同。使用PowerShell提供的内置方法可以解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function Get-CrossPlatformPath {
param(
[string]$Path
)

# 使用Join-Path确保路径分隔符正确
$normalizedPath = $Path

# 处理根路径
if ($IsWindows -or ($PSVersionTable.PSVersion.Major -lt 6 -and $env:OS -eq "Windows_NT")) {
# 在Windows上,确保使用正确的驱动器表示法
if (-not $normalizedPath.Contains(':') -and $normalizedPath.StartsWith('/')) {
$normalizedPath = "C:$normalizedPath"
}
}
else {
# 在Linux/macOS上,将Windows路径转换为Unix风格
if ($normalizedPath -match '^[A-Za-z]:') {
$normalizedPath = $normalizedPath -replace '^[A-Za-z]:', ''
$normalizedPath = $normalizedPath -replace '\\', '/'
$normalizedPath = "/$normalizedPath"
}
}

# 确保所有分隔符都是平台适用的
$normalizedPath = $normalizedPath -replace '[/\\]', [System.IO.Path]::DirectorySeparatorChar

return $normalizedPath
}

# 示例
$path = "/temp/test.txt"
$platformPath = Get-CrossPlatformPath -Path $path
Write-Host "跨平台路径: $platformPath"

执行平台特定命令

有时候,我们需要根据不同的平台执行不同的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function Invoke-PlatformCommand {
param(
[string]$WindowsCommand,
[string]$LinuxCommand,
[string]$MacOSCommand
)

$platform = Get-CurrentPlatform

switch ($platform) {
"Windows" {
Write-Host "执行Windows命令: $WindowsCommand" -ForegroundColor Cyan
Invoke-Expression -Command $WindowsCommand
}
"Linux" {
Write-Host "执行Linux命令: $LinuxCommand" -ForegroundColor Green
Invoke-Expression -Command $LinuxCommand
}
"macOS" {
Write-Host "执行macOS命令: $MacOSCommand" -ForegroundColor Magenta
Invoke-Expression -Command $MacOSCommand
}
default {
Write-Error "不支持的平台: $platform"
}
}
}

# 示例:获取系统信息
Invoke-PlatformCommand -WindowsCommand "Get-ComputerInfo | Select-Object WindowsProductName, OsVersion" `
-LinuxCommand "uname -a" `
-MacOSCommand "system_profiler SPSoftwareDataType | grep 'System Version'"

创建跨平台服务管理函数

下面是一个管理服务的跨平台函数示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
function Manage-CrossPlatformService {
param(
[Parameter(Mandatory = $true)]
[string]$ServiceName,

[Parameter(Mandatory = $true)]
[ValidateSet("Start", "Stop", "Restart", "Status")]
[string]$Action
)

$platform = Get-CurrentPlatform

switch ($platform) {
"Windows" {
switch ($Action) {
"Start" {
Start-Service -Name $ServiceName
Write-Host "已启动Windows服务 $ServiceName" -ForegroundColor Green
}
"Stop" {
Stop-Service -Name $ServiceName
Write-Host "已停止Windows服务 $ServiceName" -ForegroundColor Yellow
}
"Restart" {
Restart-Service -Name $ServiceName
Write-Host "已重启Windows服务 $ServiceName" -ForegroundColor Cyan
}
"Status" {
Get-Service -Name $ServiceName
}
}
}
"Linux" {
switch ($Action) {
"Start" {
sudo systemctl start $ServiceName
Write-Host "已启动Linux服务 $ServiceName" -ForegroundColor Green
}
"Stop" {
sudo systemctl stop $ServiceName
Write-Host "已停止Linux服务 $ServiceName" -ForegroundColor Yellow
}
"Restart" {
sudo systemctl restart $ServiceName
Write-Host "已重启Linux服务 $ServiceName" -ForegroundColor Cyan
}
"Status" {
sudo systemctl status $ServiceName
}
}
}
"macOS" {
switch ($Action) {
"Start" {
sudo launchctl load /Library/LaunchDaemons/$ServiceName.plist
Write-Host "已启动macOS服务 $ServiceName" -ForegroundColor Green
}
"Stop" {
sudo launchctl unload /Library/LaunchDaemons/$ServiceName.plist
Write-Host "已停止macOS服务 $ServiceName" -ForegroundColor Yellow
}
"Restart" {
sudo launchctl unload /Library/LaunchDaemons/$ServiceName.plist
sudo launchctl load /Library/LaunchDaemons/$ServiceName.plist
Write-Host "已重启macOS服务 $ServiceName" -ForegroundColor Cyan
}
"Status" {
sudo launchctl list | grep $ServiceName
}
}
}
default {
Write-Error "不支持的平台: $platform"
}
}
}

# 示例:服务管理
# Manage-CrossPlatformService -ServiceName "spooler" -Action "Status"

创建跨平台进程管理函数

下面是一个管理进程的跨平台函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function Get-CrossPlatformProcess {
param(
[string]$Name = ""
)

$platform = Get-CurrentPlatform

switch ($platform) {
"Windows" {
if ($Name) {
Get-Process -Name $Name -ErrorAction SilentlyContinue
}
else {
Get-Process
}
}
{ $_ -in "Linux", "macOS" } {
if ($Name) {
$processInfo = Invoke-Expression "ps -ef | grep $Name | grep -v grep"
if ($processInfo) {
$processInfo
}
else {
Write-Host "未找到名称包含 '$Name' 的进程。" -ForegroundColor Yellow
}
}
else {
Invoke-Expression "ps -ef"
}
}
default {
Write-Error "不支持的平台: $platform"
}
}
}

# 示例:查找进程
# Get-CrossPlatformProcess -Name "pwsh"

跨平台环境变量处理

不同操作系统的环境变量处理方式有所不同,下面是一个统一的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
function Get-CrossPlatformEnvironmentVariable {
param(
[Parameter(Mandatory = $true)]
[string]$Name
)

$platform = Get-CurrentPlatform

switch ($platform) {
"Windows" {
return [System.Environment]::GetEnvironmentVariable($Name)
}
{ $_ -in "Linux", "macOS" } {
$value = Invoke-Expression "echo `$${Name}"
return $value
}
default {
Write-Error "不支持的平台: $platform"
return $null
}
}
}

function Set-CrossPlatformEnvironmentVariable {
param(
[Parameter(Mandatory = $true)]
[string]$Name,

[Parameter(Mandatory = $true)]
[string]$Value,

[ValidateSet("Process", "User", "Machine")]
[string]$Scope = "Process"
)

$platform = Get-CurrentPlatform

switch ($platform) {
"Windows" {
[System.Environment]::SetEnvironmentVariable($Name, $Value, $Scope)
Write-Host "已设置Windows环境变量 $Name=$Value (作用域: $Scope)" -ForegroundColor Green
}
{ $_ -in "Linux", "macOS" } {
# Linux/macOS只支持进程级别的即时设置
Invoke-Expression "`$env:$Name = `"$Value`""

# 如果需要永久设置,需要写入配置文件
if ($Scope -ne "Process") {
Write-Host "在Linux/macOS上永久设置环境变量,需要添加到配置文件中:" -ForegroundColor Yellow
if ($Scope -eq "User") {
Write-Host "添加 'export $Name=$Value' 到 ~/.profile 或 ~/.bash_profile" -ForegroundColor Cyan
}
elseif ($Scope -eq "Machine") {
Write-Host "添加 'export $Name=$Value' 到 /etc/profile 或 /etc/environment" -ForegroundColor Cyan
}
}
else {
Write-Host "已设置Linux/macOS环境变量 $Name=$Value (仅当前进程有效)" -ForegroundColor Green
}
}
default {
Write-Error "不支持的平台: $platform"
}
}
}

# 示例:获取和设置环境变量
# $path = Get-CrossPlatformEnvironmentVariable -Name "PATH"
# Set-CrossPlatformEnvironmentVariable -Name "TEST_VAR" -Value "TestValue" -Scope "Process"

创建跨平台文件系统监控函数

下面是一个监控文件系统变化的跨平台函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
function Start-CrossPlatformFileWatcher {
param(
[Parameter(Mandatory = $true)]
[string]$Path,

[string]$Filter = "*.*",

[switch]$IncludeSubdirectories
)

$platform = Get-CurrentPlatform

# 确保路径适合当前平台
$Path = Get-CrossPlatformPath -Path $Path

# 创建FileSystemWatcher对象(适用于所有平台)
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $Path
$watcher.Filter = $Filter
$watcher.IncludeSubdirectories = $IncludeSubdirectories

# 定义事件处理程序
$action = {
$event = $Event.SourceEventArgs
$name = $event.Name
$changeType = $event.ChangeType
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

Write-Host "[$timestamp] 文件 $name$changeType" -ForegroundColor Green
}

# 注册事件
$handlers = @()
$handlers += Register-ObjectEvent -InputObject $watcher -EventName Created -Action $action
$handlers += Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $action
$handlers += Register-ObjectEvent -InputObject $watcher -EventName Deleted -Action $action
$handlers += Register-ObjectEvent -InputObject $watcher -EventName Renamed -Action $action

# 启用监控
$watcher.EnableRaisingEvents = $true

Write-Host "开始监控文件夹: $Path" -ForegroundColor Cyan
Write-Host "按Ctrl+C停止监控..." -ForegroundColor Yellow

try {
# 保持脚本运行
while ($true) { Start-Sleep -Seconds 1 }
}
finally {
# 清理
$watcher.EnableRaisingEvents = $false
$handlers | ForEach-Object { Unregister-Event -SubscriptionId $_.Id }
$watcher.Dispose()
Write-Host "已停止监控." -ForegroundColor Cyan
}
}

# 示例:监控目录变化
# Start-CrossPlatformFileWatcher -Path "/tmp" -Filter "*.txt" -IncludeSubdirectories

实用的跨平台脚本模板

下面是一个通用的跨平台脚本模板,您可以作为基础进行扩展:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env pwsh
<#
.SYNOPSIS
跨平台PowerShell脚本模板。
.DESCRIPTION
这是一个在Windows、Linux和macOS上都能正常运行的PowerShell脚本模板。
.PARAMETER Action
要执行的操作。
.EXAMPLE
./cross-platform-script.ps1 -Action "CheckSystem"
#>

param(
[Parameter(Mandatory = $true)]
[ValidateSet("CheckSystem", "ListFiles", "GetProcesses")]
[string]$Action
)

# 平台检测
function Get-CurrentPlatform {
if ($IsWindows -or ($PSVersionTable.PSVersion.Major -lt 6 -and $env:OS -eq "Windows_NT")) {
return "Windows"
}
elseif ($IsLinux) {
return "Linux"
}
elseif ($IsMacOS) {
return "macOS"
}
else {
return "Unknown"
}
}

# 平台特定命令执行
function Invoke-PlatformCommand {
param(
[string]$WindowsCommand,
[string]$LinuxCommand,
[string]$MacOSCommand
)

$platform = Get-CurrentPlatform

switch ($platform) {
"Windows" {
if ($WindowsCommand) {
return Invoke-Expression -Command $WindowsCommand
}
}
"Linux" {
if ($LinuxCommand) {
return Invoke-Expression -Command $LinuxCommand
}
}
"macOS" {
if ($MacOSCommand) {
return Invoke-Expression -Command $MacOSCommand
}
}
default {
Write-Error "不支持的平台: $platform"
return $null
}
}
}

# 主函数
function Main {
$platform = Get-CurrentPlatform
Write-Host "当前平台: $platform" -ForegroundColor Cyan

switch ($Action) {
"CheckSystem" {
Write-Host "系统信息:" -ForegroundColor Green
switch ($platform) {
"Windows" { Get-ComputerInfo | Select-Object WindowsProductName, OsVersion, CsName }
"Linux" {
$osInfo = Invoke-Expression "cat /etc/os-release"
$hostname = Invoke-Expression "hostname"
Write-Host "主机名: $hostname"
Write-Host $osInfo
}
"macOS" {
$osInfo = Invoke-Expression "sw_vers"
$hostname = Invoke-Expression "hostname"
Write-Host "主机名: $hostname"
Write-Host $osInfo
}
}
}
"ListFiles" {
$currentDir = Get-Location
Write-Host "当前目录 ($currentDir) 的文件:" -ForegroundColor Green
Get-ChildItem | Select-Object Name, Length, LastWriteTime
}
"GetProcesses" {
Write-Host "运行中的进程:" -ForegroundColor Green
switch ($platform) {
"Windows" { Get-Process | Sort-Object -Property CPU -Descending | Select-Object -First 10 Name, CPU, WorkingSet }
{ $_ -in "Linux", "macOS" } {
Invoke-Expression "ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -11"
}
}
}
}
}

# 执行主函数
Main

最佳实践总结

  1. 始终检测平台:使用$IsWindows$IsLinux$IsMacOS变量确定当前平台。
  2. 使用内置路径处理:利用Join-PathSplit-Path[System.IO.Path]类处理跨平台路径。
  3. 避免硬编码路径分隔符:使用[System.IO.Path]::DirectorySeparatorChar代替硬编码的\/
  4. 利用条件逻辑:为不同平台编写特定的代码分支。
  5. 使用.NET Core的跨平台API:尽可能使用.NET Core提供的跨平台API而不是平台特定命令。
  6. 测试、测试再测试:在所有目标平台上测试您的脚本。

通过遵循这些技巧和最佳实践,您可以编写出在所有主要操作系统上都能无缝运行的PowerShell脚本,充分发挥PowerShell跨平台能力的优势。

PowerShell 技能连载 - 教育设备同步管理

在教育设备管理领域,设备同步对于确保教学资源的统一性和可访问性至关重要。本文将介绍如何使用PowerShell构建一个教育设备同步管理系统,包括设备配置、内容同步、状态监控等功能。

设备配置

首先,让我们创建一个用于管理教育设备配置的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
function Manage-EducationConfig {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$SchoolID,

[Parameter()]
[string[]]$DeviceTypes,

[Parameter()]
[string[]]$ConfigTypes,

[Parameter()]
[hashtable]$ConfigSettings,

[Parameter()]
[string]$ReportPath,

[Parameter()]
[switch]$AutoApply
)

try {
$manager = [PSCustomObject]@{
SchoolID = $SchoolID
StartTime = Get-Date
Configurations = @{}
Status = @{}
Changes = @()
}

# 获取学校信息
$school = Get-SchoolInfo -SchoolID $SchoolID

# 管理配置
foreach ($type in $DeviceTypes) {
$manager.Configurations[$type] = @{}
$manager.Status[$type] = @{}

foreach ($device in $school.Devices[$type]) {
$config = [PSCustomObject]@{
DeviceID = $device.ID
Status = "Unknown"
Settings = @{}
Compliance = 0
Changes = @()
}

# 获取设备配置
$deviceConfig = Get-DeviceConfig `
-Device $device `
-Types $ConfigTypes

$config.Settings = $deviceConfig

# 检查配置合规性
$compliance = Check-ConfigCompliance `
-Config $deviceConfig `
-Settings $ConfigSettings

$config.Compliance = $compliance

# 生成配置更改
$changes = Generate-ConfigChanges `
-Config $deviceConfig `
-Settings $ConfigSettings

if ($changes.Count -gt 0) {
$config.Status = "NeedsUpdate"
$config.Changes = $changes
$manager.Changes += $changes

# 自动应用配置
if ($AutoApply) {
$applyResult = Apply-DeviceConfig `
-Device $device `
-Changes $changes

if ($applyResult.Success) {
$config.Status = "Updated"
}
}
}
else {
$config.Status = "Compliant"
}

$manager.Configurations[$type][$device.ID] = $config
$manager.Status[$type][$device.ID] = [PSCustomObject]@{
Status = $config.Status
Compliance = $config.Compliance
Changes = $config.Changes
}
}
}

# 生成报告
if ($ReportPath) {
$report = Generate-ConfigReport `
-Manager $manager `
-School $school

$report | ConvertTo-Json -Depth 10 | Out-File -FilePath $ReportPath
}

# 更新管理器状态
$manager.EndTime = Get-Date

return $manager
}
catch {
Write-Error "设备配置管理失败:$_"
return $null
}
}

内容同步

接下来,创建一个用于管理教育内容同步的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
function Manage-EducationSync {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$SyncID,

[Parameter()]
[string[]]$ContentTypes,

[Parameter()]
[ValidateSet("RealTime", "Scheduled", "Manual")]
[string]$SyncMode = "Scheduled",

[Parameter()]
[hashtable]$SyncConfig,

[Parameter()]
[string]$LogPath
)

try {
$manager = [PSCustomObject]@{
SyncID = $SyncID
StartTime = Get-Date
SyncStatus = @{}
Content = @{}
Errors = @()
}

# 获取同步配置
$config = Get-SyncConfig -SyncID $SyncID

# 管理同步
foreach ($type in $ContentTypes) {
$sync = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Content = @()
Statistics = @{}
}

# 应用同步配置
$typeConfig = Apply-SyncConfig `
-Config $config `
-Type $type `
-Mode $SyncMode `
-Settings $SyncConfig

$sync.Config = $typeConfig

# 同步内容
$content = Sync-EducationContent `
-Type $type `
-Config $typeConfig

$sync.Content = $content
$manager.Content[$type] = $content

# 计算同步统计
$statistics = Calculate-SyncStatistics `
-Content $content `
-Type $type

$sync.Statistics = $statistics

# 验证同步结果
$errors = Validate-SyncResults `
-Content $content `
-Config $typeConfig

if ($errors.Count -gt 0) {
$sync.Status = "Error"
$manager.Errors += $errors
}
else {
$sync.Status = "Success"
}

$manager.SyncStatus[$type] = $sync
}

# 记录同步日志
if ($LogPath) {
$manager | ConvertTo-Json -Depth 10 | Out-File -FilePath $LogPath
}

# 更新管理器状态
$manager.EndTime = Get-Date

return $manager
}
catch {
Write-Error "内容同步管理失败:$_"
return $null
}
}

状态监控

最后,创建一个用于监控教育设备状态的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
function Monitor-EducationStatus {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$MonitorID,

[Parameter()]
[string[]]$MonitorTypes,

[Parameter()]
[ValidateSet("Active", "Inactive", "Maintenance")]
[string]$Status = "Active",

[Parameter()]
[hashtable]$MonitorRules,

[Parameter()]
[string]$ReportPath
)

try {
$monitor = [PSCustomObject]@{
MonitorID = $MonitorID
StartTime = Get-Date
MonitorStatus = @{}
Metrics = @{}
Alerts = @()
}

# 获取监控配置
$config = Get-MonitorConfig -MonitorID $MonitorID

# 监控状态
foreach ($type in $MonitorTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = $Status
Rules = @{}
Metrics = @{}
Alerts = @()
}

# 应用监控规则
$rules = Apply-MonitorRules `
-Config $config `
-Type $type `
-Status $Status `
-Rules $MonitorRules

$status.Rules = $rules

# 收集监控指标
$metrics = Collect-MonitorMetrics `
-Type $type `
-Rules $rules

$status.Metrics = $metrics
$monitor.Metrics[$type] = $metrics

# 检查告警条件
$alerts = Check-MonitorAlerts `
-Metrics $metrics `
-Rules $rules

if ($alerts.Count -gt 0) {
$status.Status = "Alert"
$status.Alerts = $alerts
$monitor.Alerts += $alerts
}

$monitor.MonitorStatus[$type] = $status
}

# 生成报告
if ($ReportPath) {
$report = Generate-MonitorReport `
-Monitor $monitor `
-Config $config

$report | ConvertTo-Json -Depth 10 | Out-File -FilePath $ReportPath
}

# 更新监控器状态
$monitor.EndTime = Get-Date

return $monitor
}
catch {
Write-Error "状态监控失败:$_"
return $null
}
}

使用示例

以下是如何使用这些函数来管理教育设备同步的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 管理设备配置
$manager = Manage-EducationConfig -SchoolID "SCH001" `
-DeviceTypes @("Desktop", "Laptop", "Tablet") `
-ConfigTypes @("System", "Application", "Security") `
-ConfigSettings @{
"System" = @{
"OSVersion" = "Windows 11"
"Updates" = "Automatic"
"Backup" = "Enabled"
}
"Application" = @{
"Office" = "Latest"
"Browser" = "Chrome"
"Antivirus" = "Enabled"
}
"Security" = @{
"Firewall" = "Enabled"
"Encryption" = "Enabled"
"Access" = "Restricted"
}
} `
-ReportPath "C:\Reports\config_management.json" `
-AutoApply

# 管理内容同步
$syncManager = Manage-EducationSync -SyncID "SYNC001" `
-ContentTypes @("Courseware", "Resources", "Assignments") `
-SyncMode "Scheduled" `
-SyncConfig @{
"Courseware" = @{
"Interval" = 24
"Priority" = "High"
"Retention" = 30
}
"Resources" = @{
"Interval" = 12
"Priority" = "Medium"
"Retention" = 90
}
"Assignments" = @{
"Interval" = 6
"Priority" = "High"
"Retention" = 365
}
} `
-LogPath "C:\Logs\sync_management.json"

# 监控设备状态
$monitor = Monitor-EducationStatus -MonitorID "MON001" `
-MonitorTypes @("System", "Network", "Storage") `
-Status "Active" `
-MonitorRules @{
"System" = @{
"CPUUsage" = 80
"MemoryUsage" = 85
"DiskSpace" = 90
}
"Network" = @{
"Bandwidth" = 80
"Latency" = 100
"PacketLoss" = 1
}
"Storage" = @{
"Usage" = 85
"IOPS" = 1000
"Latency" = 50
}
} `
-ReportPath "C:\Reports\status_monitoring.json"

最佳实践

  1. 管理设备配置
  2. 同步教育内容
  3. 监控设备状态
  4. 保持详细的运行记录
  5. 定期进行性能评估
  6. 实施同步策略
  7. 建立预警机制
  8. 保持系统文档更新

PowerShell 技能连载 - Azure AD安全审计自动化

在云身份管理日益重要的今天,定期安全审计成为保障企业数字资产的关键。本文演示如何通过PowerShell自动执行Azure AD安全配置检测,实现实时安全态势监控。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
function Invoke-AzureADSecurityAudit {
param(
[string]$TenantId,
[switch]$ExportReport
)

try {
# 连接Azure AD
Connect-AzureAD -TenantId $TenantId | Out-Null

# 安全基线检测
$results = @(
[PSCustomObject]@{
CheckItem = '多重认证状态'
Result = (Get-AzureADMSAuthorizationPolicy).DefaultUserRolePermissions.AllowedToCreateApps
},
[PSCustomObject]@{
CheckItem = '旧协议支持状态'
Result = (Get-AzureADDirectorySetting | Where-Object {$_.DisplayName -eq 'OrganizationProperties'}).Values
}
)

# 生成报告
if ($ExportReport) {
$results | Export-Csv -Path "./SecurityAudit_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation
}

return $results
}
catch {
Write-Error "审计失败:$_"
}
finally {
Disconnect-AzureAD
}
}

实现原理分析:

  1. 通过AzureAD模块实现与云身份服务的认证连接
  2. 检测关键安全配置项包括MFA实施状态和旧版协议支持情况
  3. 支持CSV报告导出功能便于存档分析
  4. 自动清理会话确保操作安全性
  5. 结构化返回结果便于后续处理

该脚本将原本需要人工操作的审计流程自动化,特别适合需要持续合规监控的金融和医疗行业应用场景。

PowerShell 技能连载 - 配置管理

在系统管理中,配置管理对于确保系统一致性和可维护性至关重要。本文将介绍如何使用PowerShell构建一个配置管理系统,包括配置收集、验证和部署等功能。

配置收集

首先,让我们创建一个用于管理配置收集的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
function Collect-SystemConfigs {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$CollectionID,

[Parameter()]
[string[]]$ConfigTypes,

[Parameter()]
[ValidateSet("Full", "Quick", "Custom")]
[string]$CollectionMode = "Full",

[Parameter()]
[hashtable]$CollectionConfig,

[Parameter()]
[string]$LogPath
)

try {
$collector = [PSCustomObject]@{
CollectionID = $CollectionID
StartTime = Get-Date
CollectionStatus = @{}
Configs = @{}
Issues = @()
}

# 获取收集配置
$config = Get-CollectionConfig -CollectionID $CollectionID

# 管理收集
foreach ($type in $ConfigTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Configs = @{}
Issues = @()
}

# 应用收集配置
$typeConfig = Apply-CollectionConfig `
-Config $config `
-Type $type `
-Mode $CollectionMode `
-Settings $CollectionConfig

$status.Config = $typeConfig

# 收集系统配置
$configs = Collect-ConfigData `
-Type $type `
-Config $typeConfig

$status.Configs = $configs
$collector.Configs[$type] = $configs

# 检查收集问题
$issues = Check-CollectionIssues `
-Configs $configs `
-Config $typeConfig

$status.Issues = $issues
$collector.Issues += $issues

# 更新收集状态
if ($issues.Count -gt 0) {
$status.Status = "Warning"
}
else {
$status.Status = "Success"
}

$collector.CollectionStatus[$type] = $status
}

# 记录收集日志
if ($LogPath) {
$collector | ConvertTo-Json -Depth 10 | Out-File -FilePath $LogPath
}

# 更新收集器状态
$collector.EndTime = Get-Date

return $collector
}
catch {
Write-Error "配置收集失败:$_"
return $null
}
}

配置验证

接下来,创建一个用于管理配置验证的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
function Validate-SystemConfigs {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ValidationID,

[Parameter()]
[string[]]$ValidationTypes,

[Parameter()]
[ValidateSet("Compliance", "Security", "Performance")]
[string]$ValidationMode = "Compliance",

[Parameter()]
[hashtable]$ValidationConfig,

[Parameter()]
[string]$ReportPath
)

try {
$validator = [PSCustomObject]@{
ValidationID = $ValidationID
StartTime = Get-Date
ValidationStatus = @{}
Validation = @{}
Findings = @()
}

# 获取验证配置
$config = Get-ValidationConfig -ValidationID $ValidationID

# 管理验证
foreach ($type in $ValidationTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Validation = @{}
Findings = @()
}

# 应用验证配置
$typeConfig = Apply-ValidationConfig `
-Config $config `
-Type $type `
-Mode $ValidationMode `
-Settings $ValidationConfig

$status.Config = $typeConfig

# 验证系统配置
$validation = Validate-ConfigData `
-Type $type `
-Config $typeConfig

$status.Validation = $validation
$validator.Validation[$type] = $validation

# 生成验证结果
$findings = Generate-ValidationFindings `
-Validation $validation `
-Config $typeConfig

$status.Findings = $findings
$validator.Findings += $findings

# 更新验证状态
if ($findings.Count -gt 0) {
$status.Status = "Failed"
}
else {
$status.Status = "Passed"
}

$validator.ValidationStatus[$type] = $status
}

# 生成报告
if ($ReportPath) {
$report = Generate-ValidationReport `
-Validator $validator `
-Config $config

$report | ConvertTo-Json -Depth 10 | Out-File -FilePath $ReportPath
}

# 更新验证器状态
$validator.EndTime = Get-Date

return $validator
}
catch {
Write-Error "配置验证失败:$_"
return $null
}
}

配置部署

最后,创建一个用于管理配置部署的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
function Deploy-SystemConfigs {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$DeploymentID,

[Parameter()]
[string[]]$DeploymentTypes,

[Parameter()]
[ValidateSet("Rolling", "BlueGreen", "Canary")]
[string]$DeploymentMode = "Rolling",

[Parameter()]
[hashtable]$DeploymentConfig,

[Parameter()]
[string]$ReportPath
)

try {
$deployer = [PSCustomObject]@{
DeploymentID = $DeploymentID
StartTime = Get-Date
DeploymentStatus = @{}
Deployment = @{}
Results = @()
}

# 获取部署配置
$config = Get-DeploymentConfig -DeploymentID $DeploymentID

# 管理部署
foreach ($type in $DeploymentTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Deployment = @{}
Results = @()
}

# 应用部署配置
$typeConfig = Apply-DeploymentConfig `
-Config $config `
-Type $type `
-Mode $DeploymentMode `
-Settings $DeploymentConfig

$status.Config = $typeConfig

# 部署系统配置
$deployment = Deploy-ConfigData `
-Type $type `
-Config $typeConfig

$status.Deployment = $deployment
$deployer.Deployment[$type] = $deployment

# 生成部署结果
$results = Generate-DeploymentResults `
-Deployment $deployment `
-Config $typeConfig

$status.Results = $results
$deployer.Results += $results

# 更新部署状态
if ($results.Count -gt 0) {
$status.Status = "Success"
}
else {
$status.Status = "Failed"
}

$deployer.DeploymentStatus[$type] = $status
}

# 生成报告
if ($ReportPath) {
$report = Generate-DeploymentReport `
-Deployer $deployer `
-Config $config

$report | ConvertTo-Json -Depth 10 | Out-File -FilePath $ReportPath
}

# 更新部署器状态
$deployer.EndTime = Get-Date

return $deployer
}
catch {
Write-Error "配置部署失败:$_"
return $null
}
}

使用示例

以下是如何使用这些函数来管理配置的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# 收集系统配置
$collector = Collect-SystemConfigs -CollectionID "COLLECTION001" `
-ConfigTypes @("System", "Application", "Network", "Security") `
-CollectionMode "Full" `
-CollectionConfig @{
"System" = @{
"Scope" = @("OS", "Service", "Process")
"Format" = "JSON"
"Filter" = "Status = Active"
"Report" = $true
}
"Application" = @{
"Scope" = @("App", "Service", "Database")
"Format" = "JSON"
"Filter" = "Status = Active"
"Report" = $true
}
"Network" = @{
"Scope" = @("Interface", "Protocol", "Route")
"Format" = "JSON"
"Filter" = "Status = Active"
"Report" = $true
}
"Security" = @{
"Scope" = @("Policy", "Rule", "Access")
"Format" = "JSON"
"Filter" = "Status = Active"
"Report" = $true
}
} `
-LogPath "C:\Logs\config_collection.json"

# 验证系统配置
$validator = Validate-SystemConfigs -ValidationID "VALIDATION001" `
-ValidationTypes @("System", "Application", "Network", "Security") `
-ValidationMode "Compliance" `
-ValidationConfig @{
"System" = @{
"Standard" = @("Policy", "Baseline", "Checklist")
"Check" = @("Compliance", "Security", "Performance")
"Report" = $true
}
"Application" = @{
"Standard" = @("Policy", "Baseline", "Checklist")
"Check" = @("Compliance", "Security", "Performance")
"Report" = $true
}
"Network" = @{
"Standard" = @("Policy", "Baseline", "Checklist")
"Check" = @("Compliance", "Security", "Performance")
"Report" = $true
}
"Security" = @{
"Standard" = @("Policy", "Baseline", "Checklist")
"Check" = @("Compliance", "Security", "Performance")
"Report" = $true
}
} `
-ReportPath "C:\Reports\config_validation.json"

# 部署系统配置
$deployer = Deploy-SystemConfigs -DeploymentID "DEPLOYMENT001" `
-DeploymentTypes @("System", "Application", "Network", "Security") `
-DeploymentMode "Rolling" `
-DeploymentConfig @{
"System" = @{
"Method" = @("Backup", "Rollback", "Verify")
"Schedule" = "OffHours"
"Timeout" = 120
"Report" = $true
}
"Application" = @{
"Method" = @("Backup", "Rollback", "Verify")
"Schedule" = "OffHours"
"Timeout" = 120
"Report" = $true
}
"Network" = @{
"Method" = @("Backup", "Rollback", "Verify")
"Schedule" = "OffHours"
"Timeout" = 120
"Report" = $true
}
"Security" = @{
"Method" = @("Backup", "Rollback", "Verify")
"Schedule" = "OffHours"
"Timeout" = 120
"Report" = $true
}
} `
-ReportPath "C:\Reports\config_deployment.json"

最佳实践

  1. 实施配置收集
  2. 验证配置合规性
  3. 管理配置部署
  4. 保持详细的配置记录
  5. 定期进行配置审查
  6. 实施回滚策略
  7. 建立配置控制
  8. 保持系统文档更新

PowerShell 技能连载 - Docker 管理技巧

在 PowerShell 中管理 Docker 容器和镜像是一项重要任务,本文将介绍一些实用的 Docker 管理技巧。

首先,让我们看看基本的 Docker 操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 创建 Docker 信息获取函数
function Get-DockerInfo {
param(
[string]$Host
)

try {
$docker = "docker"
if ($Host) {
$docker += " -H $Host"
}

$info = & $docker info --format "{{json .}}" | ConvertFrom-Json
$images = & $docker images --format "{{json .}}" | ConvertFrom-Json
$containers = & $docker ps -a --format "{{json .}}" | ConvertFrom-Json

return [PSCustomObject]@{
Host = $info.Name
Version = $info.ServerVersion
Images = $images.Count
Containers = $containers.Count
RunningContainers = ($containers | Where-Object { $_.Status -like "*Up*" }).Count
SystemInfo = [PSCustomObject]@{
CPUs = $info.NCPU
Memory = [math]::Round([double]$info.MemTotal / 1GB, 2)
Storage = [math]::Round([double]$info.DockerRootDir / 1GB, 2)
}
}
}
catch {
Write-Host "获取 Docker 信息失败:$_"
}
}

Docker 镜像管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 创建 Docker 镜像管理函数
function Manage-DockerImage {
param(
[string]$Host,
[string]$ImageName,
[string]$Tag = "latest",
[ValidateSet("build", "pull", "push", "remove")]
[string]$Action,
[string]$DockerfilePath,
[string]$Registry
)

try {
$docker = "docker"
if ($Host) {
$docker += " -H $Host"
}

switch ($Action) {
"build" {
if (-not $DockerfilePath) {
throw "构建镜像需要指定 Dockerfile 路径"
}
& $docker build -t "$ImageName`:$Tag" $DockerfilePath
}
"pull" {
$image = if ($Registry) { "$Registry/$ImageName" } else { $ImageName }
& $docker pull "$image`:$Tag"
}
"push" {
if (-not $Registry) {
throw "推送镜像需要指定镜像仓库"
}
& $docker push "$Registry/$ImageName`:$Tag"
}
"remove" {
& $docker rmi "$ImageName`:$Tag"
}
}

Write-Host "镜像操作完成"
}
catch {
Write-Host "镜像操作失败:$_"
}
}

Docker 容器管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 创建 Docker 容器管理函数
function Manage-DockerContainer {
param(
[string]$Host,
[string]$ContainerName,
[ValidateSet("create", "start", "stop", "restart", "remove")]
[string]$Action,
[string]$Image,
[hashtable]$Environment,
[string[]]$Ports,
[string[]]$Volumes
)

try {
$docker = "docker"
if ($Host) {
$docker += " -H $Host"
}

switch ($Action) {
"create" {
$envParams = $Environment.GetEnumerator() | ForEach-Object { "-e", "$($_.Key)=$($_.Value)" }
$portParams = $Ports | ForEach-Object { "-p", $_ }
$volumeParams = $Volumes | ForEach-Object { "-v", $_ }

& $docker create --name $ContainerName $envParams $portParams $volumeParams $Image
}
"start" {
& $docker start $ContainerName
}
"stop" {
& $docker stop $ContainerName
}
"restart" {
& $docker restart $ContainerName
}
"remove" {
& $docker rm -f $ContainerName
}
}

Write-Host "容器操作完成"
}
catch {
Write-Host "容器操作失败:$_"
}
}

Docker 网络管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 创建 Docker 网络管理函数
function Manage-DockerNetwork {
param(
[string]$Host,
[string]$NetworkName,
[ValidateSet("create", "remove", "connect", "disconnect")]
[string]$Action,
[string]$Driver = "bridge",
[string]$Subnet,
[string]$Gateway,
[string]$ContainerName
)

try {
$docker = "docker"
if ($Host) {
$docker += " -H $Host"
}

switch ($Action) {
"create" {
$params = @("network", "create")
if ($Subnet) { $params += "--subnet", $Subnet }
if ($Gateway) { $params += "--gateway", $Gateway }
$params += "--driver", $Driver, $NetworkName

& $docker $params
}
"remove" {
& $docker network rm $NetworkName
}
"connect" {
if (-not $ContainerName) {
throw "连接网络需要指定容器名称"
}
& $docker network connect $NetworkName $ContainerName
}
"disconnect" {
if (-not $ContainerName) {
throw "断开网络需要指定容器名称"
}
& $docker network disconnect $NetworkName $ContainerName
}
}

Write-Host "网络操作完成"
}
catch {
Write-Host "网络操作失败:$_"
}
}

Docker 资源监控:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 创建 Docker 资源监控函数
function Monitor-DockerResources {
param(
[string]$Host,
[string]$ContainerName,
[int]$Interval = 60,
[int]$Duration = 3600
)

try {
$docker = "docker"
if ($Host) {
$docker += " -H $Host"
}

$startTime = Get-Date
$metrics = @()

while ((Get-Date) - $startTime).TotalSeconds -lt $Duration {
$stats = & $docker stats $ContainerName --no-stream --format "{{json .}}" | ConvertFrom-Json

$metrics += [PSCustomObject]@{
Timestamp = Get-Date
Container = $stats.Name
CPU = [math]::Round([double]$stats.CPUPerc.TrimEnd('%'), 2)
Memory = [math]::Round([double]$stats.MemUsage.Split('/')[0].Trim() / 1MB, 2)
MemoryLimit = [math]::Round([double]$stats.MemUsage.Split('/')[1].Trim() / 1MB, 2)
NetworkIO = [PSCustomObject]@{
RX = [math]::Round([double]$stats.NetIO.Split('/')[0].Trim() / 1MB, 2)
TX = [math]::Round([double]$stats.NetIO.Split('/')[1].Trim() / 1MB, 2)
}
BlockIO = [PSCustomObject]@{
Read = [math]::Round([double]$stats.BlockIO.Split('/')[0].Trim() / 1MB, 2)
Write = [math]::Round([double]$stats.BlockIO.Split('/')[1].Trim() / 1MB, 2)
}
}

Start-Sleep -Seconds $Interval
}

return $metrics
}
catch {
Write-Host "监控失败:$_"
}
}

这些技巧将帮助您更有效地管理 Docker 环境。记住,在处理 Docker 容器和镜像时,始终要注意资源使用和安全性。同时,建议使用适当的监控和日志记录机制来跟踪容器的运行状态。

PowerShell 技能连载 - 性能监控管理

在系统管理中,性能监控对于确保系统的稳定性和可用性至关重要。本文将介绍如何使用PowerShell构建一个性能监控管理系统,包括资源监控、性能分析和告警管理等功能。

资源监控

首先,让我们创建一个用于管理资源监控的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
function Monitor-SystemResources {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$MonitorID,

[Parameter()]
[string[]]$ResourceTypes,

[Parameter()]
[ValidateSet("RealTime", "Scheduled", "OnDemand")]
[string]$MonitorMode = "RealTime",

[Parameter()]
[hashtable]$MonitorConfig,

[Parameter()]
[string]$LogPath
)

try {
$monitor = [PSCustomObject]@{
MonitorID = $MonitorID
StartTime = Get-Date
ResourceStatus = @{}
Metrics = @{}
Alerts = @()
}

# 获取监控配置
$config = Get-MonitorConfig -MonitorID $MonitorID

# 管理监控
foreach ($type in $ResourceTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Metrics = @{}
Alerts = @()
}

# 应用监控配置
$typeConfig = Apply-MonitorConfig `
-Config $config `
-Type $type `
-Mode $MonitorMode `
-Settings $MonitorConfig

$status.Config = $typeConfig

# 收集资源指标
$metrics = Collect-ResourceMetrics `
-Type $type `
-Config $typeConfig

$status.Metrics = $metrics
$monitor.Metrics[$type] = $metrics

# 检查资源告警
$alerts = Check-ResourceAlerts `
-Metrics $metrics `
-Config $typeConfig

$status.Alerts = $alerts
$monitor.Alerts += $alerts

# 更新资源状态
if ($alerts.Count -gt 0) {
$status.Status = "Warning"
}
else {
$status.Status = "Normal"
}

$monitor.ResourceStatus[$type] = $status
}

# 记录监控日志
if ($LogPath) {
$monitor | ConvertTo-Json -Depth 10 | Out-File -FilePath $LogPath
}

# 更新监控器状态
$monitor.EndTime = Get-Date

return $monitor
}
catch {
Write-Error "资源监控失败:$_"
return $null
}
}

性能分析

接下来,创建一个用于管理性能分析的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
function Analyze-SystemPerformance {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$AnalysisID,

[Parameter()]
[string[]]$AnalysisTypes,

[Parameter()]
[ValidateSet("Trend", "Bottleneck", "Capacity")]
[string]$AnalysisMode = "Trend",

[Parameter()]
[hashtable]$AnalysisConfig,

[Parameter()]
[string]$ReportPath
)

try {
$analyzer = [PSCustomObject]@{
AnalysisID = $AnalysisID
StartTime = Get-Date
AnalysisStatus = @{}
Trends = @{}
Recommendations = @()
}

# 获取分析配置
$config = Get-AnalysisConfig -AnalysisID $AnalysisID

# 管理分析
foreach ($type in $AnalysisTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Trends = @{}
Recommendations = @()
}

# 应用分析配置
$typeConfig = Apply-AnalysisConfig `
-Config $config `
-Type $type `
-Mode $AnalysisMode `
-Settings $AnalysisConfig

$status.Config = $typeConfig

# 分析性能趋势
$trends = Analyze-PerformanceTrends `
-Type $type `
-Config $typeConfig

$status.Trends = $trends
$analyzer.Trends[$type] = $trends

# 生成优化建议
$recommendations = Generate-OptimizationRecommendations `
-Trends $trends `
-Config $typeConfig

$status.Recommendations = $recommendations
$analyzer.Recommendations += $recommendations

# 更新分析状态
if ($recommendations.Count -gt 0) {
$status.Status = "OptimizationNeeded"
}
else {
$status.Status = "Optimal"
}

$analyzer.AnalysisStatus[$type] = $status
}

# 生成报告
if ($ReportPath) {
$report = Generate-AnalysisReport `
-Analyzer $analyzer `
-Config $config

$report | ConvertTo-Json -Depth 10 | Out-File -FilePath $ReportPath
}

# 更新分析器状态
$analyzer.EndTime = Get-Date

return $analyzer
}
catch {
Write-Error "性能分析失败:$_"
return $null
}
}

告警管理

最后,创建一个用于管理性能告警的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
function Manage-PerformanceAlerts {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$AlertID,

[Parameter()]
[string[]]$AlertTypes,

[Parameter()]
[ValidateSet("Threshold", "Trend", "Anomaly")]
[string]$AlertMode = "Threshold",

[Parameter()]
[hashtable]$AlertConfig,

[Parameter()]
[string]$ReportPath
)

try {
$manager = [PSCustomObject]@{
AlertID = $AlertID
StartTime = Get-Date
AlertStatus = @{}
Alerts = @{}
Actions = @()
}

# 获取告警配置
$config = Get-AlertConfig -AlertID $AlertID

# 管理告警
foreach ($type in $AlertTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Alerts = @{}
Actions = @()
}

# 应用告警配置
$typeConfig = Apply-AlertConfig `
-Config $config `
-Type $type `
-Mode $AlertMode `
-Settings $AlertConfig

$status.Config = $typeConfig

# 检测性能告警
$alerts = Detect-PerformanceAlerts `
-Type $type `
-Config $typeConfig

$status.Alerts = $alerts
$manager.Alerts[$type] = $alerts

# 执行告警动作
$actions = Execute-AlertActions `
-Alerts $alerts `
-Config $typeConfig

$status.Actions = $actions
$manager.Actions += $actions

# 更新告警状态
if ($alerts.Count -gt 0) {
$status.Status = "Active"
}
else {
$status.Status = "Inactive"
}

$manager.AlertStatus[$type] = $status
}

# 生成报告
if ($ReportPath) {
$report = Generate-AlertReport `
-Manager $manager `
-Config $config

$report | ConvertTo-Json -Depth 10 | Out-File -FilePath $ReportPath
}

# 更新管理器状态
$manager.EndTime = Get-Date

return $manager
}
catch {
Write-Error "告警管理失败:$_"
return $null
}
}

使用示例

以下是如何使用这些函数来管理性能监控的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# 监控系统资源
$monitor = Monitor-SystemResources -MonitorID "MONITOR001" `
-ResourceTypes @("CPU", "Memory", "Disk", "Network") `
-MonitorMode "RealTime" `
-MonitorConfig @{
"CPU" = @{
"Threshold" = 80
"Interval" = 60
"Alert" = $true
"Retention" = 7
}
"Memory" = @{
"Threshold" = 85
"Interval" = 60
"Alert" = $true
"Retention" = 7
}
"Disk" = @{
"Threshold" = 90
"Interval" = 300
"Alert" = $true
"Retention" = 7
}
"Network" = @{
"Threshold" = 70
"Interval" = 60
"Alert" = $true
"Retention" = 7
}
} `
-LogPath "C:\Logs\resource_monitoring.json"

# 分析系统性能
$analyzer = Analyze-SystemPerformance -AnalysisID "ANALYSIS001" `
-AnalysisTypes @("Application", "Database", "System") `
-AnalysisMode "Trend" `
-AnalysisConfig @{
"Application" = @{
"Period" = "7d"
"Metrics" = @("ResponseTime", "Throughput", "Errors")
"Threshold" = 0.95
"Report" = $true
}
"Database" = @{
"Period" = "7d"
"Metrics" = @("QueryTime", "Connections", "Cache")
"Threshold" = 0.95
"Report" = $true
}
"System" = @{
"Period" = "7d"
"Metrics" = @("Load", "IOPS", "Network")
"Threshold" = 0.95
"Report" = $true
}
} `
-ReportPath "C:\Reports\performance_analysis.json"

# 管理性能告警
$alerts = Manage-PerformanceAlerts -AlertID "ALERT001" `
-AlertTypes @("Critical", "Warning", "Info") `
-AlertMode "Threshold" `
-AlertConfig @{
"Critical" = @{
"Threshold" = 90
"Duration" = "5m"
"Actions" = @("Email", "SMS", "Webhook")
"Escalation" = $true
}
"Warning" = @{
"Threshold" = 80
"Duration" = "15m"
"Actions" = @("Email", "Webhook")
"Escalation" = $false
}
"Info" = @{
"Threshold" = 70
"Duration" = "30m"
"Actions" = @("Email")
"Escalation" = $false
}
} `
-ReportPath "C:\Reports\alert_management.json"

最佳实践

  1. 实施资源监控
  2. 分析性能趋势
  3. 管理性能告警
  4. 保持详细的监控记录
  5. 定期进行性能评估
  6. 实施优化策略
  7. 建立预警机制
  8. 保持系统文档更新

多云环境成本优化自动化实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function Get-CloudCostAnalysis {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[ValidateSet('Azure','AWS')]
[string]$CloudProvider
)

$threshold = 100 # 美元

switch ($CloudProvider) {
'Azure' {
$costData = Get-AzConsumptionUsageDetail -BillingPeriodName (Get-Date).ToString('yyyyMM') |
Group-Object ResourceGroup |
Select-Object Name,@{N='Cost';E={$_.Group.PretaxCost | Measure-Object -Sum | Select-Object -Expand Sum}}
}
'AWS' {
$costData = Get-CECostAndUsage -TimePeriod @{Start=(Get-Date).AddDays(-30).ToString('yyyy-MM-dd');End=(Get-Date).ToString('yyyy-MM-dd')} -Granularity MONTHLY |
Select-Object -Expand ResultsByTime |
Select-Object -Expand Groups |
Where-Object {$_.Metrics.UnblendedCost.Amount -gt $threshold}
}
}

$costData | Export-Csv -Path "${CloudProvider}_Cost_Report_$(Get-Date -Format yyyyMMdd).csv" -NoTypeInformation

if ($costData.Count -gt 5) {
Send-MailMessage -To 'finops@company.com' -Subject "[$CloudProvider] 成本异常警报" -Body "发现${threshold}美元以上资源:$($costData.Count)项"
}
}

核心功能:

  1. 支持Azure/AWS多云平台成本分析
  2. 自动识别异常支出资源
  3. 生成CSV报告并邮件告警
  4. 可配置成本阈值参数

扩展方向:

  • 集成Power BI可视化
  • 添加自动关闭闲置资源功能
  • 实现跨云平台成本对比分析

PowerShell 技能连载 - 正则表达式处理技巧

在 PowerShell 中,正则表达式(Regex)是一个强大的文本处理工具。本文将介绍一些实用的正则表达式技巧,帮助您更有效地处理文本数据。

首先,让我们看看基本的正则表达式匹配:

1
2
3
4
5
6
7
8
9
10
11
12
# 基本匹配
$text = "我的邮箱是 example@domain.com,电话是 123-456-7890"
$emailPattern = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
$phonePattern = "\d{3}-\d{3}-\d{4}"

# 提取邮箱
$email = [regex]::Match($text, $emailPattern).Value
Write-Host "邮箱地址:$email"

# 提取电话号码
$phone = [regex]::Match($text, $phonePattern).Value
Write-Host "电话号码:$phone"

使用正则表达式进行文本替换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 替换敏感信息
$logContent = @"
用户登录信息:
用户名:admin
密码:123456
IP地址:192.168.1.100
"@

# 替换密码和IP地址
$maskedContent = $logContent -replace "密码:.*", "密码:******"
$maskedContent = $maskedContent -replace "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", "***.***.***.***"

Write-Host "`n处理后的日志内容:"
Write-Host $maskedContent

使用正则表达式验证数据格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Test-DataFormat {
param(
[string]$InputString,
[string]$Pattern
)

if ($InputString -match $Pattern) {
return $true
}
return $false
}

# 验证中文姓名(2-4个汉字)
$namePattern = "^[\u4e00-\u9fa5]{2,4}$"
$testNames = @("张三", "李四", "王小明", "赵", "John")

foreach ($name in $testNames) {
$isValid = Test-DataFormat -InputString $name -Pattern $namePattern
Write-Host "姓名 '$name' 是否有效:$isValid"
}

使用正则表达式提取结构化数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 解析日志文件
$logEntry = "2024-03-27 10:30:45 [ERROR] 用户登录失败 - IP: 192.168.1.100, 用户名: admin"
$logPattern = "(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(\w+)\] (.+) - IP: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}), 用户名: (\w+)"

$matches = [regex]::Match($logEntry, $logPattern)
if ($matches.Success) {
$timestamp = $matches.Groups[1].Value
$level = $matches.Groups[2].Value
$message = $matches.Groups[3].Value
$ip = $matches.Groups[4].Value
$username = $matches.Groups[5].Value

Write-Host "`n解析结果:"
Write-Host "时间:$timestamp"
Write-Host "级别:$level"
Write-Host "消息:$message"
Write-Host "IP:$ip"
Write-Host "用户名:$username"
}

一些实用的正则表达式技巧:

  1. 使用命名捕获组:

    1
    2
    3
    4
    $pattern = "(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})"
    $date = "2024-03-27"
    $matches = [regex]::Match($date, $pattern)
    Write-Host "年份:$($matches.Groups['year'].Value)"
  2. 使用正向预查和负向预查:

    1
    2
    3
    4
    5
    # 匹配后面跟着"元"的数字
    $pricePattern = "\d+(?=元)"
    $text = "商品价格:100元,运费:20元"
    $prices = [regex]::Matches($text, $pricePattern) | ForEach-Object { $_.Value }
    Write-Host "`n价格:$($prices -join ', ')"
  3. 使用正则表达式进行文本清理:

    1
    2
    3
    $dirtyText = "Hello   World!   This   has   extra   spaces."
    $cleanText = $dirtyText -replace "\s+", " "
    Write-Host "清理后的文本:$cleanText"

这些技巧将帮助您更有效地处理文本数据。记住,正则表达式虽然强大,但也要注意性能影响,特别是在处理大量数据时。对于简单的字符串操作,使用基本的字符串方法可能更高效。

PowerShell 技能连载 - 高级错误处理技术

在PowerShell脚本开发中,有效的错误处理是确保脚本健壮性和可靠性的关键。本文将介绍一系列高级错误处理技术,帮助您编写更专业的PowerShell脚本。

基础错误处理

首先,让我们回顾PowerShell中的基本错误处理机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用try/catch/finally块处理错误
try {
# 尝试执行的代码
Get-Content -Path "C:\NonExistentFile.txt" -ErrorAction Stop
}
catch {
# 错误处理代码
Write-Host "发生错误: $($_.Exception.Message)" -ForegroundColor Red
}
finally {
# 无论是否发生错误都会执行的代码
Write-Host "操作完成" -ForegroundColor Yellow
}

使用$ErrorActionPreference

PowerShell的$ErrorActionPreference变量控制脚本遇到错误时的默认行为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 设置全局错误处理行为
$ErrorActionPreference = 'Stop' # 遇到错误时停止执行
# 其他选项: Continue(默认),SilentlyContinue,Ignore,Inquire

# 代码块中临时改变错误处理行为
$originalEAP = $ErrorActionPreference
$ErrorActionPreference = 'SilentlyContinue'
try {
# 尝试执行的代码,错误会被忽略
Get-Process -Name "NonExistentProcess"
}
finally {
# 恢复原始错误处理行为
$ErrorActionPreference = $originalEAP
}

创建自定义错误记录器

下面是一个自定义错误记录函数,可帮助您以统一格式记录错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
function Write-ErrorLog {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[System.Management.Automation.ErrorRecord]$ErrorRecord,

[Parameter()]
[string]$LogPath = "C:\Logs\PowerShell_Errors.log",

[Parameter()]
[switch]$PassThru
)

# 确保日志目录存在
$logDir = Split-Path -Path $LogPath -Parent
if (-not (Test-Path -Path $logDir)) {
New-Item -Path $logDir -ItemType Directory -Force | Out-Null
}

# 格式化错误信息
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$errorMessage = $ErrorRecord.Exception.Message
$errorLine = $ErrorRecord.InvocationInfo.Line.Trim()
$errorPosition = $ErrorRecord.InvocationInfo.PositionMessage
$errorCategory = $ErrorRecord.CategoryInfo.Category
$errorType = $ErrorRecord.Exception.GetType().FullName

# 构建详细错误信息
$logEntry = @"
[${timestamp}]
ERROR TYPE: $errorType
CATEGORY: $errorCategory
MESSAGE: $errorMessage
LINE: $errorLine
POSITION: $errorPosition
STACK TRACE:
$($ErrorRecord.ScriptStackTrace)
====================
"@

# 记录到文件
Add-Content -Path $LogPath -Value $logEntry

# 输出给调用者
if ($PassThru) {
return $ErrorRecord
}
}

# 使用示例
try {
# 故意触发错误
1/0
}
catch {
# 记录错误
Write-ErrorLog -ErrorRecord $_
# 输出友好的错误消息
Write-Host "发生计算错误,详情已记录到日志文件" -ForegroundColor Red
}

使用trap语句进行错误处理

trap语句是另一种捕获和处理错误的机制,特别适用于需要统一处理整个脚本中错误的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 在脚本开始处设置trap
trap {
Write-Host "捕获到错误: $($_.Exception.Message)" -ForegroundColor Red
# 继续执行(如果可能)
continue

# 或者终止当前执行范围并移至调用者
# break
}

# 现在脚本中的任何未经处理的错误都会被trap捕获
Get-Process -Name "NonExistentProcess"
Write-Host "这行仍会执行,因为我们在trap中使用了continue"

不同作用域的trap

您可以在不同的作用域中设置多个trap来处理不同类型的错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 默认trap(捕获所有错误)
trap {
Write-Host "默认trap: $($_.Exception.Message)" -ForegroundColor Red
continue
}

# 特定异常类型的trap
trap [System.DivideByZeroException] {
Write-Host "除零错误trap: $($_.Exception.Message)" -ForegroundColor Yellow
continue
}

# 特定命令产生的错误
trap [System.Management.Automation.CommandNotFoundException] {
Write-Host "命令未找到trap: $($_.Exception.Message)" -ForegroundColor Cyan
continue
}

# 测试不同类型的错误
1/0 # 触发除零错误
Get-NonExistentCommand # 触发命令未找到错误
[System.IO.File]::ReadAllText("C:\NonExistentFile.txt") # 触发文件未找到错误

创建高级错误处理函数

下面是一个更全面的错误处理函数,它结合了记录、通知和重试功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
function Invoke-WithErrorHandling {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[scriptblock]$ScriptBlock,

[Parameter()]
[string]$ErrorMessage = "执行脚本块时发生错误",

[Parameter()]
[string]$LogPath,

[Parameter()]
[switch]$SuppressOutput,

[Parameter()]
[int]$RetryCount = 0,

[Parameter()]
[int]$RetryDelaySeconds = 5,

[Parameter()]
[scriptblock]$OnErrorAction,

[Parameter()]
[scriptblock]$FinallyAction
)

$attempt = 0
$maxAttempts = $RetryCount + 1 # 初始尝试 + 重试次数
$success = $false
$result = $null

do {
$attempt++
try {
Write-Verbose "执行脚本块 (尝试 $attempt/$maxAttempts)"

# 执行脚本块
$result = & $ScriptBlock
$success = $true

# 成功完成,退出循环
break
}
catch {
$currentError = $_

# 构建详细错误信息
$detailedError = @{
Message = $currentError.Exception.Message
Type = $currentError.Exception.GetType().FullName
ScriptStackTrace = $currentError.ScriptStackTrace
PositionMessage = $currentError.InvocationInfo.PositionMessage
Line = $currentError.InvocationInfo.Line.Trim()
Time = Get-Date
Attempt = $attempt
}

# 记录错误
if ($LogPath) {
$logEntry = "[$($detailedError.Time.ToString('yyyy-MM-dd HH:mm:ss'))] 尝试 $($detailedError.Attempt)/$maxAttempts`n"
$logEntry += "错误: $($detailedError.Message)`n"
$logEntry += "类型: $($detailedError.Type)`n"
$logEntry += "位置: $($detailedError.PositionMessage)`n"
$logEntry += "堆栈跟踪: $($detailedError.ScriptStackTrace)`n"
$logEntry += "====================`n"

# 确保日志目录存在
$logDir = Split-Path -Path $LogPath -Parent
if (-not (Test-Path -Path $logDir)) {
New-Item -Path $logDir -ItemType Directory -Force | Out-Null
}

Add-Content -Path $LogPath -Value $logEntry
}

# 执行自定义错误处理动作
if ($OnErrorAction) {
& $OnErrorAction -ErrorInfo $detailedError
}

# 检查是否需要重试
if ($attempt -lt $maxAttempts) {
Write-Verbose "将在 $RetryDelaySeconds 秒后重试..."
Start-Sleep -Seconds $RetryDelaySeconds
}
else {
# 已达到最大尝试次数,重新抛出错误
if (-not $SuppressOutput) {
Write-Error "$ErrorMessage`n$($detailedError.Message)"
}
}
}
finally {
# 执行finally代码块
if ($FinallyAction) {
& $FinallyAction
}
}
} while ($attempt -lt $maxAttempts)

if ($success) {
return $result
}
}

# 使用示例
$result = Invoke-WithErrorHandling -ScriptBlock {
# 模拟一个可能失败的操作
if ((Get-Random -Minimum 1 -Maximum 4) -eq 1) {
# 操作成功
return "操作成功"
}
else {
# 操作失败
throw "随机故障发生"
}
} -ErrorMessage "执行关键操作时失败" -RetryCount 3 -RetryDelaySeconds 2 -LogPath "C:\Logs\Retry.log" -Verbose -OnErrorAction {
param($ErrorInfo)
Write-Host "发生错误,尝试 $($ErrorInfo.Attempt),错误消息: $($ErrorInfo.Message)" -ForegroundColor Yellow
}

if ($result) {
Write-Host "最终结果: $result" -ForegroundColor Green
}

在函数中处理管道输入错误

当编写接受管道输入的函数时,错误处理需要特别注意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
function Process-Items {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true, Mandatory = $true)]
[object]$InputObject
)

begin {
Write-Verbose "开始处理项目..."
$errorCount = 0
$successCount = 0
}

process {
try {
# 处理每个项目
Write-Verbose "正在处理: $InputObject"

# 模拟处理
if ($InputObject -eq "bad") {
throw "发现坏项目!"
}

# 处理成功
$successCount++
Write-Host "成功处理: $InputObject" -ForegroundColor Green
}
catch {
$errorCount++
Write-Host "处理项目 '$InputObject' 时出错: $($_.Exception.Message)" -ForegroundColor Red

# 可以选择如何处理单个项目的错误:
# 1. 继续处理下一个项目 (如本例)
# 2. 通过 throw 停止所有处理
# 3. 将错误写入错误流但继续处理
# $PSCmdlet.WriteError($_)
}
}

end {
Write-Verbose "处理完成。成功: $successCount, 失败: $errorCount"

# 返回摘要对象
[PSCustomObject]@{
SuccessCount = $successCount
ErrorCount = $errorCount
TotalCount = $successCount + $errorCount
}
}
}

# 使用示例
"item1", "bad", "item3" | Process-Items -Verbose

错误过滤器和自定义错误类

您可以创建自定义错误类型和错误过滤器来更好地组织错误处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 定义自定义错误类
class CustomValidationError : System.Exception {
[string]$Reason
[object]$Value

CustomValidationError([string]$message, [string]$reason, [object]$value) : base($message) {
$this.Reason = $reason
$this.Value = $value
}
}

# 验证函数
function Test-PositiveNumber {
param(
[Parameter(Mandatory = $true)]
[object]$Value
)

if (-not [double]::TryParse($Value, [ref]$null)) {
throw [CustomValidationError]::new(
"值 '$Value' 不是有效的数字",
"InvalidFormat",
$Value
)
}

if ([double]$Value -le 0) {
throw [CustomValidationError]::new(
"值 '$Value' 不是正数",
"NotPositive",
$Value
)
}

return $true
}

# 使用示例
try {
$number = "-5"
Test-PositiveNumber -Value $number
}
catch [CustomValidationError] {
# 处理自定义验证错误
$error = $_
Write-Host "验证错误: $($error.Exception.Message)" -ForegroundColor Red
Write-Host "原因: $($error.Exception.Reason)" -ForegroundColor Yellow
Write-Host "提供的值: $($error.Exception.Value)" -ForegroundColor Yellow
}
catch {
# 处理其他错误
Write-Host "其他错误: $($_.Exception.Message)" -ForegroundColor Red
}

创建一个完整的错误处理框架

最后,让我们创建一个全面的错误处理框架,可以在多个脚本中重用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# ErrorHandling.psm1
function Initialize-ErrorHandling {
[CmdletBinding()]
param(
[Parameter()]
[string]$LogPath = "$env:TEMP\PowerShell_Errors.log",

[Parameter()]
[ValidateSet('Continue', 'Stop', 'SilentlyContinue', 'Inquire', 'Ignore')]
[string]$DefaultAction = 'Continue',

[Parameter()]
[switch]$EnableGlobalErrorLogging,

[Parameter()]
[switch]$EnableGlobalErrorTrapping,

[Parameter()]
[scriptblock]$GlobalErrorAction
)

# 设置默认错误操作
$script:OriginalErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = $DefaultAction

# 确保日志目录存在
if (-not [string]::IsNullOrWhiteSpace($LogPath)) {
$logDir = Split-Path -Path $LogPath -Parent
if (-not (Test-Path -Path $logDir)) {
New-Item -Path $logDir -ItemType Directory -Force | Out-Null
}
$script:ErrorLogPath = $LogPath
}

# 设置全局错误日志记录
if ($EnableGlobalErrorLogging) {
# 覆盖$Error.Clear()方法以记录错误
$ExecutionContext.SessionState.PSVariable.Set('ErrorClearOriginal', ${function:Clear-Error})

function global:Clear-Error {
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
foreach ($err in $global:Error) {
$errorEntry = "[$timestamp] ERROR: $($err.Exception.Message)`nCATEGORY: $($err.CategoryInfo.Category)`nFULL: $($err | Out-String)"
Add-Content -Path $script:ErrorLogPath -Value $errorEntry
}
& $function:ErrorClearOriginal
}
}

# 设置全局错误捕获
if ($EnableGlobalErrorTrapping) {
trap {
# 记录错误
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$errorEntry = @"
[$timestamp] TRAPPED ERROR
MESSAGE: $($_.Exception.Message)
TYPE: $($_.Exception.GetType().FullName)
SCRIPT: $($_.InvocationInfo.ScriptName)
LINE NUMBER: $($_.InvocationInfo.ScriptLineNumber)
LINE: $($_.InvocationInfo.Line.Trim())
POSITION: $($_.InvocationInfo.PositionMessage)
STACK TRACE:
$($_.ScriptStackTrace)
====================
"@
Add-Content -Path $script:ErrorLogPath -Value $errorEntry

# 执行自定义错误处理
if ($GlobalErrorAction) {
& $GlobalErrorAction -ErrorRecord $_
}

# 继续执行
continue
}
}

Write-Verbose "已初始化错误处理框架 (日志路径: $script:ErrorLogPath)"
}

function Reset-ErrorHandling {
[CmdletBinding()]
param()

# 恢复原始错误操作首选项
if ($script:OriginalErrorActionPreference) {
$ErrorActionPreference = $script:OriginalErrorActionPreference
}

# 移除全局trap(不可能直接实现,需要重新启动会话)

Write-Verbose "已重置错误处理配置"
}

function Write-DetailedError {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 0)]
[System.Management.Automation.ErrorRecord]$ErrorRecord,

[Parameter()]
[string]$LogPath = $script:ErrorLogPath,

[Parameter()]
[switch]$PassThru,

[Parameter()]
[ValidateSet('Verbose', 'Warning', 'Error', 'Host', 'None')]
[string]$OutputType = 'Host'
)

# 格式化详细错误信息
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$formattedError = @"
[$timestamp] ERROR DETAILS
MESSAGE: $($ErrorRecord.Exception.Message)
TYPE: $($ErrorRecord.Exception.GetType().FullName)
SCRIPT: $($ErrorRecord.InvocationInfo.ScriptName)
LINE NUMBER: $($ErrorRecord.InvocationInfo.ScriptLineNumber)
LINE: $($ErrorRecord.InvocationInfo.Line.Trim())
POSITION: $($ErrorRecord.InvocationInfo.PositionMessage)
STACK TRACE:
$($ErrorRecord.ScriptStackTrace)
CATEGORY: $($ErrorRecord.CategoryInfo.Category)
REASON: $($ErrorRecord.CategoryInfo.Reason)
TARGET: $($ErrorRecord.CategoryInfo.TargetName)
FULL ERROR:
$($ErrorRecord | Out-String)
====================
"@

# 记录到文件
if (-not [string]::IsNullOrWhiteSpace($LogPath)) {
Add-Content -Path $LogPath -Value $formattedError
}

# 输出错误
switch ($OutputType) {
'Verbose' { Write-Verbose $formattedError }
'Warning' { Write-Warning $ErrorRecord.Exception.Message }
'Error' { Write-Error $ErrorRecord.Exception.Message }
'Host' {
Write-Host "ERROR: $($ErrorRecord.Exception.Message)" -ForegroundColor Red
Write-Host "DETAILS: Type=$($ErrorRecord.Exception.GetType().Name), Script=$($ErrorRecord.InvocationInfo.ScriptName)" -ForegroundColor DarkRed
}
'None' { }
}

# 返回错误
if ($PassThru) {
return $ErrorRecord
}
}

function Invoke-WithRetry {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[scriptblock]$ScriptBlock,

[Parameter()]
[int]$RetryCount = 3,

[Parameter()]
[int]$RetryIntervalSeconds = 5,

[Parameter()]
[scriptblock]$RetryCondition = { $true },

[Parameter()]
[string]$LogPath = $script:ErrorLogPath,

[Parameter()]
[scriptblock]$OnRetry
)

$attempt = 0
$maxAttempts = $RetryCount + 1 # 初始尝试 + 重试次数

do {
$attempt++
$lastError = $null

try {
Write-Verbose "执行代码块 (尝试 $attempt/$maxAttempts)"
# 执行脚本块并返回结果
return & $ScriptBlock
}
catch {
$lastError = $_

# 记录错误
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$retryLog = @"
[$timestamp] RETRY ATTEMPT $attempt/$maxAttempts
ERROR: $($lastError.Exception.Message)
TYPE: $($lastError.Exception.GetType().FullName)
====================
"@
if (-not [string]::IsNullOrWhiteSpace($LogPath)) {
Add-Content -Path $LogPath -Value $retryLog
}

# 执行OnRetry动作
if ($OnRetry) {
& $OnRetry -ErrorRecord $lastError -Attempt $attempt -MaxAttempts $maxAttempts
}

# 检查是否满足重试条件
$shouldRetry = & $RetryCondition -ErrorRecord $lastError

if ($shouldRetry -and $attempt -lt $maxAttempts) {
Write-Verbose "在 $RetryIntervalSeconds 秒后重试..."
Start-Sleep -Seconds $RetryIntervalSeconds
}
else {
# 已达到最大重试次数或不满足重试条件
throw $lastError
}
}
} while ($attempt -lt $maxAttempts)
}

# 导出模块函数
Export-ModuleMember -Function Initialize-ErrorHandling, Reset-ErrorHandling, Write-DetailedError, Invoke-WithRetry

使用错误处理框架的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 导入错误处理模块
Import-Module ErrorHandling.psm1

# 初始化错误处理
Initialize-ErrorHandling -LogPath "C:\Logs\MyScript.log" -DefaultAction "Stop" -EnableGlobalErrorLogging -Verbose

try {
# 使用重试机制执行不稳定操作
$result = Invoke-WithRetry -ScriptBlock {
# 模拟不稳定操作
if ((Get-Random -Minimum 1 -Maximum 5) -lt 3) {
throw "临时错误,可重试"
}
return "操作成功"
} -RetryCount 5 -RetryIntervalSeconds 2 -OnRetry {
param($ErrorRecord, $Attempt, $MaxAttempts)
Write-Host "重试 $Attempt/$MaxAttempts..." -ForegroundColor Yellow
} -Verbose

Write-Host "最终结果: $result" -ForegroundColor Green
}
catch {
# 详细记录错误
Write-DetailedError -ErrorRecord $_ -OutputType "Host"

# 执行清理操作
Write-Host "执行错误后清理..." -ForegroundColor Cyan
}
finally {
# 重置错误处理设置
Reset-ErrorHandling
}

最佳实践总结

  1. 预见错误:识别脚本中可能发生错误的区域,并相应地进行处理。
  2. 使用try/catch/finally:对于可能失败的关键操作,始终使用try/catch块。
  3. 使用-ErrorAction参数:在单个命令级别控制错误行为。
  4. 记录错误:将错误详细信息记录到日志文件,以便后续分析。
  5. 实现重试逻辑:对于网络或其他间歇性操作,实现自动重试。
  6. 提供有意义的错误消息:确保错误消息清晰、具有描述性,并包含足够的上下文信息。
  7. 使用自定义错误类型:对于复杂应用程序,考虑创建自定义错误类型。
  8. 测试错误处理:专门测试错误路径,确保它们按预期工作。

通过实施这些高级错误处理技术,您的PowerShell脚本将更加健壮,更易于调试和维护。良好的错误处理不仅能提高脚本质量,还能降低运营风险,特别是在自动化关键业务流程时。