PowerShell 技能连载 - 智能图像分类系统

在数字化转型浪潮中,智能图像处理技术日益重要。本文演示如何通过PowerShell调用云端AI服务实现自动化图像分类,提升海量图像资产管理效率。

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
function Invoke-ImageClassification {
param(
[string]$ImagePath,
[string]$ApiKey,
[ValidateRange(1,100)]
[int]$MaxResults = 5
)

try {
$base64Image = [Convert]::ToBase64String((Get-Content $ImagePath -Encoding Byte))
$headers = @{ "Ocp-Apim-Subscription-Key" = $ApiKey }
$body = @{ url = "data:image/jpeg;base64,$base64Image" } | ConvertTo-Json

$response = Invoke-RestMethod -Uri "https://eastus.api.cognitive.microsoft.com/vision/v3.1/analyze?visualFeatures=Categories"
-Method Post
-Headers $headers
-Body $body

$results = $response.categories | Select-Object name, score -First $MaxResults
return $results | Format-Table -AutoSize
}
catch {
Write-Error "分类失败:$($_.Exception.Message)"
}
}

实现原理分析:

  1. 将本地图像转换为Base64编码格式进行传输
  2. 通过Microsoft Cognitive Services视觉API实现智能分类
  3. 参数验证机制确保返回结果数量在合理范围
  4. 结构化返回结果便于后续处理分析
  5. 异常处理机制捕获网络请求和API调用错误

该脚本将传统图像管理升级为智能分类系统,特别适合需要处理大量用户生成内容的内容管理平台。

PowerShell 技能连载 - AI 辅助脚本生成

随着AI技术的进步,PowerShell现在可以通过集成AI模型实现智能代码建议功能。本方案通过封装OpenAI API实现脚本自动生成:

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
function Get-AIScriptSuggestion {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$TaskDescription,

[ValidateRange(0.1,1.0)]
[double]$Creativity = 0.7
)

try {
$apiKey = $env:OPENAI_KEY
$headers = @{
'Authorization' = "Bearer $apiKey"
'Content-Type' = 'application/json'
}

$body = @{
model = "gpt-4-turbo"
messages = @(
@{
role = "system"
content = "你是一个PowerShell专家,用简洁规范的代码解决问题。输出格式:\n```powershell\n<代码>\n```\n\n代码说明:"
},
@{
role = "user"
content = $TaskDescription
}
)
temperature = $Creativity
} | ConvertTo-Json -Depth 5

$response = Invoke-RestMethod -Uri 'https://api.openai.com/v1/chat/completions' \
-Method Post \
-Headers $headers \
-Body $body

$response.choices[0].message.content
}
catch {
Write-Error "AI请求失败: $_"
}
}

工作原理:

  1. 函数接收任务描述和创意系数参数,通过环境变量获取API密钥
  2. 构建符合OpenAI要求的请求结构,包含系统角色提示词
  3. 使用Invoke-RestMethod发起API调用
  4. 返回格式化的PowerShell代码建议
  5. 错误处理模块捕获网络异常和API限制错误

使用示例:

1
2
$env:OPENAI_KEY = 'your-api-key'
Get-AIScriptSuggestion -TaskDescription "需要批量重命名目录中所有.jpg文件,添加日期前缀"

最佳实践:

  1. 通过环境变量管理敏感信息
  2. 限制temperature参数控制输出稳定性
  3. 添加请求重试逻辑应对速率限制
  4. 缓存常见查询结果减少API调用

注意事项:
• 需注册OpenAI账户获取API密钥
• 建议添加使用量监控
• 重要脚本需人工审核后执行

PowerShell 技能连载 - 硬件监控技巧

在IT运维中,硬件监控是确保系统稳定运行的关键任务。本文将介绍如何使用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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 创建系统资源监控函数
function Get-SystemResourceInfo {
param(
[string]$ComputerName = $env:COMPUTERNAME,
[switch]$IncludeCPU,
[switch]$IncludeMemory,
[switch]$IncludeDisk,
[switch]$IncludeNetwork,
[switch]$All
)

if ($All) {
$IncludeCPU = $IncludeMemory = $IncludeDisk = $IncludeNetwork = $true
}

$results = [PSCustomObject]@{
ComputerName = $ComputerName
Timestamp = Get-Date
}

try {
# 获取CPU信息
if ($IncludeCPU) {
$cpuInfo = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_Processor
$cpuUsage = (Get-Counter -ComputerName $ComputerName -Counter "\Processor(_Total)\% Processor Time" -ErrorAction SilentlyContinue).CounterSamples.CookedValue

$cpuDetails = [PSCustomObject]@{
Name = $cpuInfo.Name
Cores = $cpuInfo.NumberOfCores
LogicalProcessors = $cpuInfo.NumberOfLogicalProcessors
MaxClockSpeed = "$($cpuInfo.MaxClockSpeed) MHz"
CurrentUsage = "$([Math]::Round($cpuUsage, 2))%"
LoadPercentage = $cpuInfo.LoadPercentage
Architecture = $cpuInfo.AddressWidth
L2CacheSize = "$($cpuInfo.L2CacheSize) KB"
L3CacheSize = "$($cpuInfo.L3CacheSize) KB"
}

$results | Add-Member -MemberType NoteProperty -Name "CPU" -Value $cpuDetails
}

# 获取内存信息
if ($IncludeMemory) {
$memoryInfo = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_OperatingSystem
$physicalMemory = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_PhysicalMemory

$totalMemory = ($physicalMemory | Measure-Object -Property Capacity -Sum).Sum / 1GB
$freeMemory = $memoryInfo.FreePhysicalMemory / 1MB
$usedMemory = $totalMemory - ($freeMemory / 1024)
$memoryUsagePercent = [Math]::Round(($usedMemory / $totalMemory) * 100, 2)

$memoryDetails = [PSCustomObject]@{
TotalGB = [Math]::Round($totalMemory, 2)
FreeGB = [Math]::Round($freeMemory / 1024, 2)
UsedGB = [Math]::Round($usedMemory, 2)
UsagePercent = "$memoryUsagePercent%"
Modules = $physicalMemory.Count
MemoryType = ($physicalMemory | Select-Object -First 1).MemoryType
Speed = "$($physicalMemory | Select-Object -First 1 -ExpandProperty Speed) MHz"
PagedPoolMB = [Math]::Round((Get-CimInstance -ComputerName $ComputerName -ClassName Win32_PerfFormattedData_PerfOS_Memory).PoolPagedBytes / 1MB, 2)
NonPagedPoolMB = [Math]::Round((Get-CimInstance -ComputerName $ComputerName -ClassName Win32_PerfFormattedData_PerfOS_Memory).PoolNonpagedBytes / 1MB, 2)
}

$results | Add-Member -MemberType NoteProperty -Name "Memory" -Value $memoryDetails
}

# 获取磁盘信息
if ($IncludeDisk) {
$diskInfo = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_LogicalDisk -Filter "DriveType=3"
$diskCounter = Get-Counter -ComputerName $ComputerName -Counter "\PhysicalDisk(_Total)\Disk Reads/sec", "\PhysicalDisk(_Total)\Disk Writes/sec", "\PhysicalDisk(_Total)\Avg. Disk Queue Length" -ErrorAction SilentlyContinue

$diskReadsSec = $diskCounter.CounterSamples[0].CookedValue
$diskWritesSec = $diskCounter.CounterSamples[1].CookedValue
$diskQueueLength = $diskCounter.CounterSamples[2].CookedValue

$diskDetails = $diskInfo | ForEach-Object {
$freeSpace = $_.FreeSpace / 1GB
$totalSpace = $_.Size / 1GB
$usedSpace = $totalSpace - $freeSpace
$percentFree = [Math]::Round(($freeSpace / $totalSpace) * 100, 2)

[PSCustomObject]@{
Drive = $_.DeviceID
VolumeLabel = $_.VolumeName
TotalGB = [Math]::Round($totalSpace, 2)
FreeGB = [Math]::Round($freeSpace, 2)
UsedGB = [Math]::Round($usedSpace, 2)
PercentFree = "$percentFree%"
FileSystem = $_.FileSystem
}
}

$diskMetrics = [PSCustomObject]@{
Drives = $diskDetails
ReadPerSec = [Math]::Round($diskReadsSec, 2)
WritesPerSec = [Math]::Round($diskWritesSec, 2)
QueueLength = [Math]::Round($diskQueueLength, 2)
AvgTransferTime = [Math]::Round((Get-Counter -ComputerName $ComputerName -Counter "\PhysicalDisk(_Total)\Avg. Disk sec/Transfer" -ErrorAction SilentlyContinue).CounterSamples.CookedValue * 1000, 2)
}

$results | Add-Member -MemberType NoteProperty -Name "Disk" -Value $diskMetrics
}

# 获取网络信息
if ($IncludeNetwork) {
$networkAdapters = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_NetworkAdapter | Where-Object { $_.PhysicalAdapter -eq $true -and $_.NetEnabled -eq $true }
$networkConfigs = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true }

$networkMetrics = $networkAdapters | ForEach-Object {
$adapterConfig = $networkConfigs | Where-Object { $_.Index -eq $_.Index }
$bytesReceivedSec = (Get-Counter -ComputerName $ComputerName -Counter "\Network Interface($($_.Name))\Bytes Received/sec" -ErrorAction SilentlyContinue).CounterSamples.CookedValue
$bytesSentSec = (Get-Counter -ComputerName $ComputerName -Counter "\Network Interface($($_.Name))\Bytes Sent/sec" -ErrorAction SilentlyContinue).CounterSamples.CookedValue

[PSCustomObject]@{
Name = $_.Name
ConnectionName = $_.NetConnectionID
Speed = if ($_.Speed) { "$([Math]::Round($_.Speed / 1000000, 0)) Mbps" } else { "Unknown" }
MACAddress = $_.MACAddress
IPAddresses = $adapterConfig.IPAddress
BytesReceivedSec = [Math]::Round($bytesReceivedSec / 1KB, 2)
BytesSentSec = [Math]::Round($bytesSentSec / 1KB, 2)
TotalBandwidthKBSec = [Math]::Round(($bytesReceivedSec + $bytesSentSec) / 1KB, 2)
}
}

$results | Add-Member -MemberType NoteProperty -Name "Network" -Value $networkMetrics
}

return $results
}
catch {
Write-Error "获取系统资源信息时出错: $_"
}
}

接下来,让我们创建一个温度监控函数:

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
# 创建温度监控函数
function Get-SystemTemperature {
param(
[string]$ComputerName = $env:COMPUTERNAME
)

try {
# 使用 WMI 获取温度传感器数据
$temperatureData = @()

# 获取CPU温度 (使用MSAcpi_ThermalZoneTemperature类)
$cpuTemp = Get-CimInstance -ComputerName $ComputerName -Namespace "root\WMI" -ClassName MSAcpi_ThermalZoneTemperature -ErrorAction SilentlyContinue

if ($cpuTemp) {
foreach ($temp in $cpuTemp) {
# 温度以Kelvin为单位,转换为摄氏度
$tempC = [Math]::Round($temp.CurrentTemperature / 10 - 273.15, 1)

$temperatureData += [PSCustomObject]@{
SensorType = "CPU"
Name = $temp.InstanceName
TemperatureCelsius = $tempC
TemperatureFahrenheit = [Math]::Round(($tempC * 9/5) + 32, 1)
Status = if ($tempC -gt 80) { "Critical" } elseif ($tempC -gt 70) { "Warning" } else { "Normal" }
}
}
}

# 如果无法通过MSAcpi_ThermalZoneTemperature获取,尝试其他方法
if ($temperatureData.Count -eq 0) {
# 尝试通过Open Hardware Monitor获取(如果已安装)
$ohm = Get-CimInstance -ComputerName $ComputerName -Namespace "root\OpenHardwareMonitor" -ClassName Sensor -ErrorAction SilentlyContinue | Where-Object { $_.SensorType -eq "Temperature" }

if ($ohm) {
foreach ($sensor in $ohm) {
$temperatureData += [PSCustomObject]@{
SensorType = $sensor.Parent
Name = $sensor.Name
TemperatureCelsius = [Math]::Round($sensor.Value, 1)
TemperatureFahrenheit = [Math]::Round(($sensor.Value * 9/5) + 32, 1)
Status = if ($sensor.Value -gt 80) { "Critical" } elseif ($sensor.Value -gt 70) { "Warning" } else { "Normal" }
}
}
}
}

# 如果仍无法获取温度数据,使用Win32_TemperatureProbe类(较老的系统)
if ($temperatureData.Count -eq 0) {
$oldTemp = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_TemperatureProbe -ErrorAction SilentlyContinue

if ($oldTemp) {
foreach ($probe in $oldTemp) {
$tempC = $probe.CurrentReading

$temperatureData += [PSCustomObject]@{
SensorType = "System"
Name = $probe.Description
TemperatureCelsius = $tempC
TemperatureFahrenheit = [Math]::Round(($tempC * 9/5) + 32, 1)
Status = if ($tempC -gt 80) { "Critical" } elseif ($tempC -gt 70) { "Warning" } else { "Normal" }
}
}
}
}

# 如果所有方法都失败,返回一个消息
if ($temperatureData.Count -eq 0) {
Write-Warning "无法获取温度数据。可能需要安装适当的硬件监控工具,如Open Hardware Monitor。"
}

return $temperatureData
}
catch {
Write-Error "获取系统温度时出错: $_"
}
}

下面创建一个硬件健康监控函数:

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
# 创建硬件健康监控函数
function Get-HardwareHealth {
param(
[string]$ComputerName = $env:COMPUTERNAME,
[switch]$IncludeSMARTData,
[int]$WarningDiskSpace = 10, # 磁盘空间警告阈值(百分比)
[int]$WarningMemory = 80, # 内存使用警告阈值(百分比)
[int]$WarningCPU = 90 # CPU使用警告阈值(百分比)
)

try {
$health = [PSCustomObject]@{
ComputerName = $ComputerName
Timestamp = Get-Date
Status = "Healthy"
Warnings = @()
Errors = @()
}

# 获取基本系统资源信息
$resources = Get-SystemResourceInfo -ComputerName $ComputerName -All

# 检查CPU健康状况
$cpuUsage = [double]($resources.CPU.CurrentUsage -replace '%', '')
if ($cpuUsage -ge $WarningCPU) {
$health.Warnings += "CPU使用率 ($cpuUsage%) 超过警告阈值 ($WarningCPU%)"
$health.Status = "Warning"
}

# 检查内存健康状况
$memoryUsage = [double]($resources.Memory.UsagePercent -replace '%', '')
if ($memoryUsage -ge $WarningMemory) {
$health.Warnings += "内存使用率 ($memoryUsage%) 超过警告阈值 ($WarningMemory%)"
$health.Status = "Warning"
}

# 检查磁盘健康状况
foreach ($drive in $resources.Disk.Drives) {
$freePercent = [double]($drive.PercentFree -replace '%', '')
if ($freePercent -le $WarningDiskSpace) {
$health.Warnings += "磁盘 $($drive.Drive) 可用空间 ($freePercent%) 低于警告阈值 ($WarningDiskSpace%)"
$health.Status = "Warning"
}
}

# 获取和检查温度数据
$temps = Get-SystemTemperature -ComputerName $ComputerName
foreach ($temp in $temps) {
if ($temp.Status -eq "Critical") {
$health.Errors += "$($temp.SensorType) 温度 ($($temp.TemperatureCelsius)°C) 处于临界状态"
$health.Status = "Critical"
}
elseif ($temp.Status -eq "Warning") {
$health.Warnings += "$($temp.SensorType) 温度 ($($temp.TemperatureCelsius)°C) 超过警告阈值"
if ($health.Status -ne "Critical") {
$health.Status = "Warning"
}
}
}

# 收集SMART数据(如果启用)
if ($IncludeSMARTData) {
# 这里使用CIM来获取SMART数据(需要WMIC)
$smartData = @()
$physicalDisks = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_DiskDrive

foreach ($disk in $physicalDisks) {
try {
# 尝试获取SMART状态
$smartStatus = Get-CimInstance -ComputerName $ComputerName -Namespace "root\WMI" -ClassName MSStorageDriver_FailurePredictStatus -ErrorAction SilentlyContinue |
Where-Object { $_.InstanceName -like "*$($disk.PNPDeviceID)*" }

# 获取SMART属性
$smartAttribs = Get-CimInstance -ComputerName $ComputerName -Namespace "root\WMI" -ClassName MSStorageDriver_FailurePredictData -ErrorAction SilentlyContinue |
Where-Object { $_.InstanceName -like "*$($disk.PNPDeviceID)*" }

$diskSmart = [PSCustomObject]@{
DiskName = $disk.Caption
Model = $disk.Model
SerialNumber = $disk.SerialNumber
FailurePredicted = if ($smartStatus) { $smartStatus.PredictFailure } else { "Unknown" }
SMARTDataAvailable = if ($smartAttribs) { $true } else { $false }
SMARTRawData = if ($smartAttribs) { $smartAttribs.VendorSpecific } else { $null }
}

$smartData += $diskSmart

# 如果预测硬盘将要故障,添加错误
if ($diskSmart.FailurePredicted) {
$health.Errors += "硬盘 $($diskSmart.DiskName) ($($diskSmart.Model)) 预测将故障"
$health.Status = "Critical"
}
}
catch {
Write-Warning "无法获取硬盘 $($disk.DeviceID) 的 SMART 数据: $_"
}
}

$health | Add-Member -MemberType NoteProperty -Name "SMARTData" -Value $smartData
}

# 添加基础指标
$health | Add-Member -MemberType NoteProperty -Name "ResourceMetrics" -Value $resources
$health | Add-Member -MemberType NoteProperty -Name "TemperatureMetrics" -Value $temps

return $health
}
catch {
Write-Error "获取硬件健康状态时出错: $_"
}
}

现在,让我们创建一个持续监控和报警函数:

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
# 创建持续监控和报警功能
function Start-HardwareMonitoring {
param(
[string[]]$ComputerNames = @($env:COMPUTERNAME),
[int]$Interval = 300, # 间隔时间(秒)
[string]$LogPath, # 日志保存路径
[int]$Duration = 3600, # 持续时间(秒)
[scriptblock]$AlertAction, # 警报触发时执行的操作
[switch]$EnableEmailAlerts, # 是否启用电子邮件警报
[string]$SmtpServer,
[string]$FromAddress,
[string[]]$ToAddresses
)

try {
$startTime = Get-Date
$endTime = $startTime.AddSeconds($Duration)
$currentTime = $startTime

Write-Host "开始硬件监控,将持续到 $($endTime.ToString('yyyy-MM-dd HH:mm:ss'))"

# 创建日志文件
if ($LogPath) {
$logFile = Join-Path -Path $LogPath -ChildPath "HardwareMonitoring_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
$logHeaders = "Timestamp,ComputerName,Status,CPUUsage,MemoryUsage,FreeDiskSpace,Temperature,Warnings,Errors"
$logHeaders | Out-File -FilePath $logFile
}

while ($currentTime -lt $endTime) {
foreach ($computer in $ComputerNames) {
# 获取硬件健康信息
$healthInfo = Get-HardwareHealth -ComputerName $computer -IncludeSMARTData

# 将结果保存到日志文件
if ($LogPath) {
$cpuUsage = $healthInfo.ResourceMetrics.CPU.CurrentUsage -replace '%', ''
$memoryUsage = $healthInfo.ResourceMetrics.Memory.UsagePercent -replace '%', ''
$freeDiskSpace = ($healthInfo.ResourceMetrics.Disk.Drives | ForEach-Object { $_.PercentFree -replace '%', '' }) -join '|'
$temperature = ($healthInfo.TemperatureMetrics | ForEach-Object { "$($_.SensorType):$($_.TemperatureCelsius)" }) -join '|'
$warnings = ($healthInfo.Warnings -join '|').Replace(',', ';')
$errors = ($healthInfo.Errors -join '|').Replace(',', ';')

$logLine = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'),$computer,$($healthInfo.Status),$cpuUsage,$memoryUsage,$freeDiskSpace,$temperature,`"$warnings`",`"$errors`""
$logLine | Out-File -FilePath $logFile -Append
}

# 显示状态
$statusColor = switch ($healthInfo.Status) {
"Healthy" { "Green" }
"Warning" { "Yellow" }
"Critical" { "Red" }
default { "White" }
}

Write-Host "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $computer - 状态: " -NoNewline
Write-Host $healthInfo.Status -ForegroundColor $statusColor

# 显示警告和错误
foreach ($warning in $healthInfo.Warnings) {
Write-Host " 警告: $warning" -ForegroundColor Yellow
}

foreach ($error in $healthInfo.Errors) {
Write-Host " 错误: $error" -ForegroundColor Red
}

# 如果状态不是健康,执行警报操作
if ($healthInfo.Status -ne "Healthy") {
# 执行自定义警报动作
if ($AlertAction) {
& $AlertAction -HealthInfo $healthInfo
}

# 发送电子邮件警报
if ($EnableEmailAlerts -and $SmtpServer -and $FromAddress -and $ToAddresses) {
$subject = "硬件监控警报 - $computer - $($healthInfo.Status)"
$body = @"
计算机: $computer
状态: $($healthInfo.Status)
时间: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')

警告:
$($healthInfo.Warnings | ForEach-Object { "- $_" } | Out-String)

错误:
$($healthInfo.Errors | ForEach-Object { "- $_" } | Out-String)

系统指标:
- CPU使用率: $($healthInfo.ResourceMetrics.CPU.CurrentUsage)
- 内存使用率: $($healthInfo.ResourceMetrics.Memory.UsagePercent)
- 磁盘使用情况:
$($healthInfo.ResourceMetrics.Disk.Drives | ForEach-Object { " $($_.Drive): 可用空间 $($_.PercentFree)" } | Out-String)
"@

$emailParams = @{
SmtpServer = $SmtpServer
From = $FromAddress
To = $ToAddresses
Subject = $subject
Body = $body
}

try {
Send-MailMessage @emailParams
Write-Host " 已发送电子邮件警报" -ForegroundColor Cyan
}
catch {
Write-Host " 发送电子邮件警报失败: $_" -ForegroundColor Red
}
}
}
}

# 更新当前时间
$currentTime = Get-Date

# 如果还没有到结束时间,等待到下一个间隔
if ($currentTime -lt $endTime) {
$nextCheckTime = $currentTime.AddSeconds($Interval)
$waitTime = ($nextCheckTime - $currentTime).TotalSeconds

Write-Host "下一次检查将在 $($nextCheckTime.ToString('HH:mm:ss')) 进行 (等待 $([Math]::Round($waitTime, 0)) 秒)" -ForegroundColor Cyan
Start-Sleep -Seconds ([Math]::Round($waitTime, 0))
}
}

Write-Host "硬件监控已完成。监控持续了 $([Math]::Round(((Get-Date) - $startTime).TotalMinutes, 0)) 分钟。"

if ($LogPath) {
Write-Host "监控日志已保存至: $logFile"
}
}
catch {
Write-Error "硬件监控过程中出错: $_"
}
}

使用示例:

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
# 获取单次系统资源信息
Get-SystemResourceInfo -All

# 获取系统温度信息
Get-SystemTemperature

# 获取完整的硬件健康状态
Get-HardwareHealth -IncludeSMARTData

# 启动持续监控(每5分钟一次,持续1小时,保存日志到指定路径)
Start-HardwareMonitoring -Interval 300 -Duration 3600 -LogPath "C:\Logs"

# 带邮件警报的持续监控
Start-HardwareMonitoring -Interval 300 -Duration 3600 -LogPath "C:\Logs" -EnableEmailAlerts -SmtpServer "smtp.company.com" -FromAddress "monitoring@company.com" -ToAddresses "admin@company.com"

# 使用自定义警报动作(例如,向Teams发送消息)
$alertAction = {
param($HealthInfo)

$webhookUrl = "https://company.webhook.office.com/webhookb2/..."

$body = @{
"@type" = "MessageCard"
"@context" = "http://schema.org/extensions"
"themeColor" = if ($HealthInfo.Status -eq "Critical") { "FF0000" } else { "FFA500" }
"summary" = "硬件监控警报 - $($HealthInfo.ComputerName)"
"sections" = @(
@{
"activityTitle" = "硬件监控警报"
"activitySubtitle" = "状态: $($HealthInfo.Status)"
"facts" = @(
@{
"name" = "计算机"
"value" = $HealthInfo.ComputerName
},
@{
"name" = "时间"
"value" = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
},
@{
"name" = "问题"
"value" = ($HealthInfo.Warnings + $HealthInfo.Errors) -join "; "
}
)
}
)
} | ConvertTo-Json -Depth 4

Invoke-RestMethod -Uri $webhookUrl -Method Post -ContentType 'application/json' -Body $body
}

Start-HardwareMonitoring -AlertAction $alertAction -Interval 300 -Duration 3600 -LogPath "C:\Logs"

这些脚本提供了全面的硬件监控功能,可以帮助IT管理员密切关注系统健康状况。对于企业环境,可以考虑将这些功能集成到现有的监控系统中,如SCOM、Nagios或Zabbix。也可以使用Windows任务计划程序来定期运行这些脚本,实现持续监控和长期趋势分析。

PowerShell 技能连载 - Excel 文件处理技巧

在 PowerShell 中处理 Excel 文件是一项常见任务,特别是在处理报表、数据分析时。本文将介绍一些实用的 Excel 文件处理技巧。

首先,我们需要安装必要的模块:

1
2
# 安装 Excel 处理模块
Install-Module -Name ImportExcel -Force

创建和写入 Excel 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建示例数据
$data = @(
[PSCustomObject]@{
姓名 = "张三"
部门 = "技术部"
职位 = "高级工程师"
入职日期 = "2020-01-15"
薪资 = 15000
},
[PSCustomObject]@{
姓名 = "李四"
部门 = "市场部"
职位 = "市场经理"
入职日期 = "2019-06-20"
薪资 = 12000
}
)

# 导出到 Excel 文件
$data | Export-Excel -Path "employees.xlsx" -WorksheetName "员工信息" -AutoSize

读取 Excel 文件:

1
2
3
4
5
6
# 读取 Excel 文件
$employees = Import-Excel -Path "employees.xlsx" -WorksheetName "员工信息"

# 显示数据
Write-Host "员工列表:"
$employees | Format-Table

处理多个工作表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建包含多个工作表的 Excel 文件
$data1 = @(
[PSCustomObject]@{ 产品 = "笔记本电脑"; 价格 = 5999; 库存 = 10 }
[PSCustomObject]@{ 产品 = "无线鼠标"; 价格 = 199; 库存 = 50 }
)

$data2 = @(
[PSCustomObject]@{ 客户 = "公司A"; 订单号 = "ORD001"; 金额 = 10000 }
[PSCustomObject]@{ 客户 = "公司B"; 订单号 = "ORD002"; 金额 = 8000 }
)

# 导出到不同的工作表
$data1 | Export-Excel -Path "inventory.xlsx" -WorksheetName "库存" -AutoSize
$data2 | Export-Excel -Path "inventory.xlsx" -WorksheetName "订单" -AutoSize

格式化 Excel 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建带格式的 Excel 文件
$data = @(
[PSCustomObject]@{ 姓名 = "张三"; 销售额 = 15000; 完成率 = 0.85 }
[PSCustomObject]@{ 姓名 = "李四"; 销售额 = 12000; 完成率 = 0.75 }
[PSCustomObject]@{ 姓名 = "王五"; 销售额 = 18000; 完成率 = 0.95 }
)

# 导出并应用格式
$excel = $data | Export-Excel -Path "sales.xlsx" -WorksheetName "销售报表" -AutoSize -PassThru

# 设置列宽
$excel.Workbook.Worksheets["销售报表"].Column(1).Width = 15
$excel.Workbook.Worksheets["销售报表"].Column(2).Width = 15
$excel.Workbook.Worksheets["销售报表"].Column(3).Width = 15

# 设置数字格式
$excel.Workbook.Worksheets["销售报表"].Column(2).Style.Numberformat.Format = "#,##0"
$excel.Workbook.Worksheets["销售报表"].Column(3).Style.Numberformat.Format = "0.00%"

# 保存更改
Close-ExcelPackage $excel

一些实用的 Excel 处理技巧:

  1. 合并多个 Excel 文件:

    1
    2
    3
    4
    5
    6
    7
    # 合并多个 Excel 文件的工作表
    $excelFiles = Get-ChildItem -Path "*.xlsx" -Filter "sales_*.xlsx"
    $combinedData = @()
    foreach ($file in $excelFiles) {
    $combinedData += Import-Excel -Path $file.FullName
    }
    $combinedData | Export-Excel -Path "combined_sales.xlsx" -WorksheetName "合并数据" -AutoSize
  2. 数据筛选和过滤:

    1
    2
    3
    4
    # 读取 Excel 并过滤数据
    $data = Import-Excel -Path "employees.xlsx"
    $highSalary = $data | Where-Object { $_.薪资 -gt 12000 }
    $highSalary | Export-Excel -Path "high_salary.xlsx" -WorksheetName "高薪员工" -AutoSize
  3. 创建数据透视表:

    1
    2
    3
    4
    # 创建数据透视表
    $data = Import-Excel -Path "sales.xlsx"
    $pivotTable = $data | Pivot-Table -PivotRows 部门 -PivotValues 销售额 -PivotColumns 月份
    $pivotTable | Export-Excel -Path "sales_pivot.xlsx" -WorksheetName "数据透视表" -AutoSize

这些技巧将帮助您更有效地处理 Excel 文件。记住,在处理大型 Excel 文件时,考虑使用流式处理方法来优化内存使用。同时,始终注意数据的完整性和格式的正确性。

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
function Invoke-AIScriptGeneration {
param(
[Parameter(Mandatory=$true)]
[string]$Prompt,
[ValidateSet('AWS','Azure','Windows','Linux')]
[string]$Environment = 'Windows'
)

$apiKey = $env:OPENAI_API_KEY
$headers = @{
'Authorization' = "Bearer $apiKey"
'Content-Type' = 'application/json'
}

$body = @{
model = 'gpt-4-turbo'
messages = @(
@{
role = 'system'
content = "你是一名资深PowerShell专家,根据用户需求生成可直接执行的运维脚本。当前环境:$Environment"
},
@{
role = 'user'
content = $Prompt
}
)
temperature = 0.3
max_tokens = 1024
} | ConvertTo-Json -Depth 5

try {
$response = Invoke-RestMethod -Uri 'https://api.openai.com/v1/chat/completions' \
-Method Post \
-Headers $headers \
-Body $body

$scriptBlock = [scriptblock]::Create($response.choices[0].message.content)
Write-Host "生成脚本验证通过:" -ForegroundColor Green
$scriptBlock.Invoke()
}
catch {
Write-Error "AI脚本生成失败: $($_.Exception.Message)"
}
}

核心功能:

  1. 集成OpenAI API实现自然语言转PowerShell脚本
  2. 支持多环境脚本生成(AWS/Azure/Windows/Linux)
  3. 自动脚本验证与安全执行机制
  4. 温度参数控制脚本生成稳定性

应用场景:

  • 新手运维人员快速生成标准脚本
  • 跨平台环境下的自动化模板生成
  • 复杂运维任务的快速原型开发
  • 企业知识库的脚本标准化沉淀

PowerShell 变量作用域深度解析

作用域层级体系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$globalVar = 'Global'

function Show-Scope {
begin {
$beginVar = 'Begin块变量'
Write-Host "Begin块访问全局变量: $globalVar"
}
process {
$processVar = 'Process块变量'
Write-Host "Process块继承Begin变量: $beginVar"
Write-Host "无法访问Process后续块变量"
}
end {
Write-Host "End块访问Process变量: $processVar"
$global:newGlobalVar = '新建全局变量'
}
}

# 执行验证
1..3 | Show-Scope
Write-Host "全局访问新建变量: $newGlobalVar"

作用域穿透规则

  1. 自上而下继承:子作用域自动继承父作用域变量
  2. 块级隔离:begin块变量不能在process块外访问
  3. 全局修改:使用$global:前缀跨作用域修改变量
  4. 变量生命周期:process块变量在每个管道元素独立创建

最佳实践

  • 使用param块显式声明函数参数
  • 避免在process块修改全局变量
  • 通过$script:作用域访问脚本级变量
  • 使用Write-Verbose代替临时变量调试

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
function Invoke-HybridIaC {
[CmdletBinding(SupportsShouldProcess=$true)]
param(
[Parameter(Mandatory=$true)]
[ValidateSet('Azure','AWS','OnPrem')]
[string[]]$Environments,

[string]$DscConfigPath = '$PSScriptRoot/dsc'
)

$deploymentReport = [PSCustomObject]@{
Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
AppliedConfigs = @()
ComplianceStatus = @{}
CrossPlatformIssues = @()
}

try {
# 应用Terraform基础设施
$Environments | ForEach-Object {
if ($PSCmdlet.ShouldProcess("Deploy $_ resources")) {
terraform -chdir="$DscConfigPath/terraform/$_" apply -auto-approve
}
}

# 执行DSC配置
$Environments | ForEach-Object {
$dscConfig = Get-ChildItem "$DscConfigPath/$_" -Filter *.ps1
$dscConfig | ForEach-Object {
$job = Start-Job -ScriptBlock {
param($config)
& $config.FullName
} -ArgumentList $_
$deploymentReport.AppliedConfigs += $job | Wait-Job | Receive-Job
}
}

# 验证混合云合规性
$deploymentReport.ComplianceStatus = $Environments | ForEach-Object {
$status = Test-DscConfiguration -CimSession (New-CimSession -ComputerName $_)
@{$_ = $status.InDesiredState ? 'Compliant' : 'Non-Compliant'}
}
}
catch {
Write-Error "混合云部署失败: $_"
terraform -chdir="$DscConfigPath/terraform" destroy -auto-approve
}

# 生成统一部署报告
$deploymentReport | Export-Clixml -Path "$env:TEMP/HybridIaC_Report_$(Get-Date -Format yyyyMMdd).xml"
return $deploymentReport
}

核心功能

  1. 多环境Terraform编排
  2. DSC配置跨平台应用
  3. 混合云合规性验证
  4. 原子化作业执行

应用场景

  • 混合云环境统一管理
  • 配置漂移自动修复
  • 跨云平台灾备部署
  • 基础设施合规审计

PowerShell与Terraform实现基础设施即代码

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
function Invoke-TerraformDeployment {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Environment
)

# 生成Terraform变量文件
$tfVars = @{
environment = $Environment
location = 'eastus'
vm_count = 3
} | ConvertTo-Json
$tfVars | Out-File -FilePath "./terraform.tfvars.json"

# 初始化并应用配置
terraform init -input=false
terraform apply -auto-approve -var-file="./terraform.tfvars.json"

# 获取输出变量
$output = terraform output -json | ConvertFrom-Json
[PSCustomObject]@{
PublicIP = $output.public_ip.value
StorageEndpoint = $output.storage_endpoint.value
}
}

# 执行多环境部署
'dev','staging','prod' | ForEach-Object {
Invoke-TerraformDeployment -Environment $_ -Verbose
}

核心功能:

  1. 自动化生成Terraform变量文件
  2. 集成Terraform CLI实现无人值守部署
  3. 解析基础设施输出参数

扩展方向:

  • 添加Azure Key Vault集成管理敏感信息
  • 实现漂移检测与自动修复
  • 与监控系统集成进行健康检查

PowerSwitch 模式匹配实战指南

通配符模式匹配

1
2
3
4
5
6
7
8
9
10
11
12
$process = 'powershell_ise'

switch -Wildcard ($process)
{
'*sql*' { '数据库相关进程' }
'power*' {
if($_.Length -gt 10) {
'长进程名PowerShell组件'
}
}
default { '未识别进程类型' }
}

正则表达式模式

1
2
3
4
5
6
7
8
9
10
11
$logEntry = 'ERROR [2024-07-15] : File not found: config.json'

switch -Regex ($logEntry)
{
'^WARN' { Write-Host '警告级别日志' -ForegroundColor Yellow }
'^ERROR' {
$matches = $_ -match '\d{4}-\d{2}-\d{2}'
Write-Host "严重错误于$($matches[0])" -ForegroundColor Red
}
'config' { Send-Alert -Type '配置缺失' }
}

脚本块条件

1
2
3
4
5
6
7
8
$num = 42

switch ($num)
{
{ $_ -is [string] } { '字符串类型' }
{ $_ % 2 -eq 0 } { '偶数数字' }
{ $_ -gt [math]::PI } { '大于圆周率' }
}

最佳实践

  1. 优先使用-exact参数避免意外匹配
  2. 通过fallthrough关键词控制执行流
  3. 结合break/continue控制循环上下文
  4. 使用parallel参数加速大数据处理

PowerShell字符串操作完全指南

基础字符串操作

1
2
3
4
5
6
7
8
9
10
11
# 多行字符串处理
$text = @"
系统日志条目:
时间: $(Get-Date)
事件: 用户登录
"@
$text -replace '\s+',' ' -split '
'

# 字符串格式化演示
"{0}的存款利率为{1:P}" -f '工商银行', 0.035

高级处理技巧

1
2
3
4
5
6
7
8
# 正则表达式分割
$csvData = '姓名,年龄,职业;张三,30,工程师'
$csvData -split '[;,]' | Group-Object { $_ -match '\d+' }

# 字符串构建优化
$sb = [System.Text.StringBuilder]::new()
1..100 | ForEach-Object { $null = $sb.Append("条目$_") }
$sb.ToString()

实用场景建议

  1. 使用Trim系列方法处理首尾空白
  2. 通过PadLeft/PadRight实现对齐格式
  3. 优先使用-f格式化运算符代替字符串拼接
  4. 处理大文本时使用StringBuilder