PowerShell 技能连载 - 数据库操作技巧

在 PowerShell 中处理数据库操作是一项常见任务,特别是在数据管理和自动化过程中。本文将介绍一些实用的数据库操作技巧。

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

1
2
# 安装数据库操作模块
Install-Module -Name SqlServer -Force

连接数据库并执行查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 设置数据库连接参数
$server = "localhost"
$database = "TestDB"
$query = @"
SELECT
员工ID,
姓名,
部门,
职位,
入职日期
FROM 员工信息
WHERE 部门 = '技术部'
ORDER BY 入职日期 DESC
"@

# 执行查询
$results = Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query

# 显示结果
Write-Host "技术部员工列表:"
$results | Format-Table

执行参数化查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建参数化查询
$query = @"
SELECT
订单号,
客户名称,
订单金额,
下单日期
FROM 订单信息
WHERE 下单日期 BETWEEN @开始日期 AND @结束日期
AND 订单金额 > @最小金额
"@

# 设置参数
$params = @{
开始日期 = "2024-01-01"
结束日期 = "2024-03-31"
最小金额 = 10000
}

# 执行参数化查询
$results = Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query -Parameters $params

执行事务操作:

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
# 开始事务
$connection = New-Object System.Data.SqlClient.SqlConnection
$connection.ConnectionString = "Server=$server;Database=$database;Integrated Security=True"
$connection.Open()
$transaction = $connection.BeginTransaction()

try {
# 执行多个操作
$query1 = "UPDATE 库存 SET 数量 = 数量 - 1 WHERE 产品ID = 1"
$query2 = "INSERT INTO 订单明细 (订单号, 产品ID, 数量) VALUES ('ORD001', 1, 1)"

Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query1 -Transaction $transaction
Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $query2 -Transaction $transaction

# 提交事务
$transaction.Commit()
Write-Host "事务执行成功"
}
catch {
# 回滚事务
$transaction.Rollback()
Write-Host "事务执行失败:$_"
}
finally {
$connection.Close()
}

批量数据导入:

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
# 准备批量数据
$data = @(
@{
产品名称 = "笔记本电脑"
价格 = 5999
库存 = 10
},
@{
产品名称 = "无线鼠标"
价格 = 199
库存 = 50
}
)

# 创建数据表
$table = New-Object System.Data.DataTable
$table.Columns.Add("产品名称")
$table.Columns.Add("价格")
$table.Columns.Add("库存")

# 添加数据
foreach ($item in $data) {
$row = $table.NewRow()
$row["产品名称"] = $item.产品名称
$row["价格"] = $item.价格
$row["库存"] = $item.库存
$table.Rows.Add($row)
}

# 批量导入数据
Write-SqlTableData -ServerInstance $server -Database $database -TableName "产品信息" -InputData $table

一些实用的数据库操作技巧:

  1. 数据库备份:
1
2
3
4
5
6
7
8
9
# 创建数据库备份
$backupPath = "C:\Backups\TestDB_$(Get-Date -Format 'yyyyMMdd').bak"
$backupQuery = @"
BACKUP DATABASE TestDB
TO DISK = '$backupPath'
WITH FORMAT, MEDIANAME = 'TestDBBackup', NAME = 'TestDB-Full Database Backup'
"@

Invoke-Sqlcmd -ServerInstance $server -Query $backupQuery
  1. 数据库还原:
1
2
3
4
5
6
7
8
# 还原数据库
$restoreQuery = @"
RESTORE DATABASE TestDB
FROM DISK = '$backupPath'
WITH REPLACE
"@

Invoke-Sqlcmd -ServerInstance $server -Query $restoreQuery
  1. 数据库维护:
1
2
3
4
5
6
7
# 更新统计信息
$updateStatsQuery = @"
UPDATE STATISTICS 员工信息 WITH FULLSCAN
UPDATE STATISTICS 订单信息 WITH FULLSCAN
"@

Invoke-Sqlcmd -ServerInstance $server -Database $database -Query $updateStatsQuery

这些技巧将帮助您更有效地处理数据库操作。记住,在执行数据库操作时,始终要注意数据安全性和性能影响。同时,建议使用参数化查询来防止 SQL 注入攻击。

PowerShell 技能连载 - IoT边缘设备监控

在工业物联网场景中,边缘设备监控至关重要。以下脚本实现设备状态采集与异常预警:

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

[ValidateRange(1,100)]
[int]$SamplingInterval = 30
)

$report = [PSCustomObject]@{
Timestamp = Get-Date
OnlineDevices = @()
OfflineDevices = @()
HighTempDevices = @()
LowBatteryDevices = @()
}

try {
# 设备状态轮询
$DeviceIPs | ForEach-Object -Parallel {
$response = Test-NetConnection -ComputerName $_ -Port 502 -InformationLevel Quiet
$telemetry = Invoke-RestMethod -Uri "http://$_/metrics" -TimeoutSec 3

[PSCustomObject]@{
IP = $_
Online = $response
Temperature = $telemetry.temp
BatteryLevel = $telemetry.battery
LastSeen = Get-Date
}
} -ThrottleLimit 10

# 数据分析
$results | ForEach-Object {
if(-not $_.Online) {
$report.OfflineDevices += $_.IP
continue
}

$report.OnlineDevices += $_.IP

if($_.Temperature -gt 85) {
$report.HighTempDevices += $_.IP
}

if($_.BatteryLevel -lt 20) {
$report.LowBatteryDevices += $_.IP
}
}

# 触发预警
if($report.HighTempDevices.Count -gt 0) {
Send-Notification -Type "HighTemp" -Devices $report.HighTempDevices
}

if($report.LowBatteryDevices.Count -gt 0) {
Send-Notification -Type "LowBattery" -Devices $report.LowBatteryDevices
}
}
catch {
Write-Warning "设备监控异常: $_"
}

return $report
}

实现原理:

  1. 使用并行处理加速多设备状态采集
  2. 通过Test-NetConnection验证设备在线状态
  3. 调用REST API获取设备遥测数据
  4. 设置温度(85°C)和电量(20%)双重预警阈值
  5. 自动触发邮件/短信通知机制

使用示例:

1
2
$devices = '192.168.1.100','192.168.1.101','192.168.1.102'
Get-IoTDeviceStatus -DeviceIPs $devices -SamplingInterval 60

最佳实践:

  1. 与TSDB时序数据库集成存储历史数据
  2. 配置指数退避策略应对网络波动
  3. 添加设备白名单安全机制
  4. 实现预警静默时段功能

注意事项:
• 需要设备开放502端口和/metrics端点
• 建议使用硬件加密模块保护通信安全
• 监控间隔不宜小于30秒

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
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
function Monitor-AgricultureEnvironment {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$FieldID,

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

[Parameter()]
[int]$SamplingInterval = 300,

[Parameter()]
[string]$DataPath,

[Parameter()]
[hashtable]$Thresholds
)

try {
$monitor = [PSCustomObject]@{
FieldID = $FieldID
StartTime = Get-Date
Zones = @{}
Alerts = @()
Statistics = @{}
}

while ($true) {
$sampleTime = Get-Date

foreach ($zone in $Zones) {
$zoneData = [PSCustomObject]@{
ZoneID = $zone
SampleTime = $sampleTime
Temperature = 0
Humidity = 0
SoilMoisture = 0
LightIntensity = 0
CO2Level = 0
Status = "Normal"
Alerts = @()
}

# 获取环境传感器数据
$sensors = Get-EnvironmentSensors -FieldID $FieldID -Zone $zone
foreach ($sensor in $sensors) {
$zoneData.$($sensor.Type) = $sensor.Value
}

# 检查阈值
if ($Thresholds) {
# 检查温度
if ($Thresholds.ContainsKey("Temperature")) {
$threshold = $Thresholds.Temperature
if ($zoneData.Temperature -gt $threshold.Max) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "HighTemperature"
Value = $zoneData.Temperature
Threshold = $threshold.Max
}
}
if ($zoneData.Temperature -lt $threshold.Min) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "LowTemperature"
Value = $zoneData.Temperature
Threshold = $threshold.Min
}
}
}

# 检查湿度
if ($Thresholds.ContainsKey("Humidity")) {
$threshold = $Thresholds.Humidity
if ($zoneData.Humidity -gt $threshold.Max) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "HighHumidity"
Value = $zoneData.Humidity
Threshold = $threshold.Max
}
}
if ($zoneData.Humidity -lt $threshold.Min) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "LowHumidity"
Value = $zoneData.Humidity
Threshold = $threshold.Min
}
}
}

# 检查土壤湿度
if ($Thresholds.ContainsKey("SoilMoisture")) {
$threshold = $Thresholds.SoilMoisture
if ($zoneData.SoilMoisture -gt $threshold.Max) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "HighSoilMoisture"
Value = $zoneData.SoilMoisture
Threshold = $threshold.Max
}
}
if ($zoneData.SoilMoisture -lt $threshold.Min) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "LowSoilMoisture"
Value = $zoneData.SoilMoisture
Threshold = $threshold.Min
}
}
}

# 检查光照强度
if ($Thresholds.ContainsKey("LightIntensity")) {
$threshold = $Thresholds.LightIntensity
if ($zoneData.LightIntensity -lt $threshold.Min) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "LowLight"
Value = $zoneData.LightIntensity
Threshold = $threshold.Min
}
}
}

# 检查CO2浓度
if ($Thresholds.ContainsKey("CO2Level")) {
$threshold = $Thresholds.CO2Level
if ($zoneData.CO2Level -gt $threshold.Max) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = $sampleTime
Type = "HighCO2"
Value = $zoneData.CO2Level
Threshold = $threshold.Max
}
}
}
}

$monitor.Zones[$zone] = $zoneData

# 处理告警
foreach ($alert in $zoneData.Alerts) {
$monitor.Alerts += $alert

# 记录数据
if ($DataPath) {
$zoneData | ConvertTo-Json | Out-File -FilePath $DataPath -Append
}

# 发送告警通知
Send-EnvironmentAlert -Alert $alert
}

# 更新统计信息
if (-not $monitor.Statistics.ContainsKey($zone)) {
$monitor.Statistics[$zone] = [PSCustomObject]@{
TemperatureHistory = @()
HumidityHistory = @()
SoilMoistureHistory = @()
LightHistory = @()
CO2History = @()
}
}

$stats = $monitor.Statistics[$zone]
$stats.TemperatureHistory += $zoneData.Temperature
$stats.HumidityHistory += $zoneData.Humidity
$stats.SoilMoistureHistory += $zoneData.SoilMoisture
$stats.LightHistory += $zoneData.LightIntensity
$stats.CO2History += $zoneData.CO2Level

# 保持历史数据在合理范围内
$maxHistoryLength = 1000
if ($stats.TemperatureHistory.Count -gt $maxHistoryLength) {
$stats.TemperatureHistory = $stats.TemperatureHistory | Select-Object -Last $maxHistoryLength
$stats.HumidityHistory = $stats.HumidityHistory | Select-Object -Last $maxHistoryLength
$stats.SoilMoistureHistory = $stats.SoilMoistureHistory | Select-Object -Last $maxHistoryLength
$stats.LightHistory = $stats.LightHistory | Select-Object -Last $maxHistoryLength
$stats.CO2History = $stats.CO2History | Select-Object -Last $maxHistoryLength
}
}

Start-Sleep -Seconds $SamplingInterval
}

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
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
function Manage-IrrigationSystem {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$FieldID,

[Parameter()]
[hashtable]$Schedule,

[Parameter()]
[hashtable]$SoilData,

[Parameter()]
[switch]$AutoAdjust,

[Parameter()]
[string]$WeatherForecast,

[Parameter()]
[string]$LogPath
)

try {
$controller = [PSCustomObject]@{
FieldID = $FieldID
StartTime = Get-Date
Zones = @{}
Status = "Normal"
Actions = @()
}

# 获取灌溉系统状态
$irrigationZones = Get-IrrigationZones -FieldID $FieldID
foreach ($zone in $irrigationZones) {
$controller.Zones[$zone.ID] = [PSCustomObject]@{
ZoneID = $zone.ID
CurrentState = $zone.State
WaterFlow = $zone.WaterFlow
Duration = $zone.Duration
NextSchedule = $zone.NextSchedule
Status = "Active"
}
}

# 处理天气预测
if ($WeatherForecast) {
$forecast = Get-WeatherForecast -Location $FieldID -Days 3
if ($forecast.RainProbability -gt 0.7) {
$controller.Status = "WeatherAdjusted"
foreach ($zone in $controller.Zones.Values) {
if ($zone.NextSchedule -lt (Get-Date).AddHours(24)) {
$action = Adjust-IrrigationSchedule `
-ZoneID $zone.ZoneID `
-DelayHours 24 `
-Reason "High Rain Probability"
$controller.Actions += $action

# 记录调整
if ($LogPath) {
$adjustmentLog = [PSCustomObject]@{
Time = Get-Date
Type = "ScheduleAdjustment"
ZoneID = $zone.ZoneID
Action = $action
Reason = "High Rain Probability"
}
$adjustmentLog | ConvertTo-Json | Out-File -FilePath $LogPath -Append
}
}
}
}
}

# 自适应控制
if ($AutoAdjust -and $SoilData) {
foreach ($zone in $controller.Zones.Values) {
$zoneSoilData = $SoilData[$zone.ZoneID]
if ($zoneSoilData) {
# 计算最优灌溉量
$optimalIrrigation = Calculate-OptimalIrrigation -SoilData $zoneSoilData

# 更新灌溉计划
if ($optimalIrrigation.WaterFlow -ne $zone.WaterFlow) {
$action = Update-IrrigationPlan `
-ZoneID $zone.ZoneID `
-WaterFlow $optimalIrrigation.WaterFlow `
-Duration $optimalIrrigation.Duration `
-Reason "Soil Moisture Based"
$controller.Actions += $action

# 记录调整
if ($LogPath) {
$adjustmentLog = [PSCustomObject]@{
Time = Get-Date
Type = "IrrigationAdjustment"
ZoneID = $zone.ZoneID
OldFlow = $zone.WaterFlow
NewFlow = $optimalIrrigation.WaterFlow
Duration = $optimalIrrigation.Duration
Reason = "Soil Moisture Based"
}
$adjustmentLog | ConvertTo-Json | Out-File -FilePath $LogPath -Append
}
}
}
}
}

# 应用固定计划
elseif ($Schedule) {
foreach ($zoneID in $Schedule.Keys) {
$zoneSchedule = $Schedule[$zoneID]
if ($controller.Zones.ContainsKey($zoneID)) {
$zone = $controller.Zones[$zoneID]

# 更新灌溉计划
if ($zoneSchedule.WaterFlow -ne $zone.WaterFlow) {
$action = Update-IrrigationPlan `
-ZoneID $zoneID `
-WaterFlow $zoneSchedule.WaterFlow `
-Duration $zoneSchedule.Duration `
-Reason "Fixed Schedule"
$controller.Actions += $action

# 记录调整
if ($LogPath) {
$adjustmentLog = [PSCustomObject]@{
Time = Get-Date
Type = "IrrigationAdjustment"
ZoneID = $zoneID
OldFlow = $zone.WaterFlow
NewFlow = $zoneSchedule.WaterFlow
Duration = $zoneSchedule.Duration
Reason = "Fixed Schedule"
}
$adjustmentLog | ConvertTo-Json | Out-File -FilePath $LogPath -Append
}
}
}
}
}

# 更新控制器状态
$controller.EndTime = Get-Date

return $controller
}
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
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
function Manage-PestControl {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$FieldID,

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

[Parameter()]
[string]$CropType,

[Parameter()]
[hashtable]$Thresholds,

[Parameter()]
[string]$TreatmentMethod,

[Parameter()]
[string]$LogPath
)

try {
$manager = [PSCustomObject]@{
FieldID = $FieldID
StartTime = Get-Date
Zones = @{}
Alerts = @()
Treatments = @()
}

foreach ($zone in $Zones) {
$zoneData = [PSCustomObject]@{
ZoneID = $zone
CropType = $CropType
PestLevel = 0
DiseaseLevel = 0
Status = "Normal"
Alerts = @()
TreatmentHistory = @()
}

# 获取病虫害数据
$pestData = Get-PestData -FieldID $FieldID -Zone $zone
$zoneData.PestLevel = $pestData.PestLevel
$zoneData.DiseaseLevel = $pestData.DiseaseLevel

# 检查阈值
if ($Thresholds) {
# 检查害虫水平
if ($Thresholds.ContainsKey("PestLevel")) {
$threshold = $Thresholds.PestLevel
if ($zoneData.PestLevel -gt $threshold.Max) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = Get-Date
Type = "HighPestLevel"
Value = $zoneData.PestLevel
Threshold = $threshold.Max
}
}
}

# 检查病害水平
if ($Thresholds.ContainsKey("DiseaseLevel")) {
$threshold = $Thresholds.DiseaseLevel
if ($zoneData.DiseaseLevel -gt $threshold.Max) {
$zoneData.Status = "Warning"
$zoneData.Alerts += [PSCustomObject]@{
Time = Get-Date
Type = "HighDiseaseLevel"
Value = $zoneData.DiseaseLevel
Threshold = $threshold.Max
}
}
}
}

$manager.Zones[$zone] = $zoneData

# 处理告警
foreach ($alert in $zoneData.Alerts) {
$manager.Alerts += $alert

# 记录告警
if ($LogPath) {
$alert | ConvertTo-Json | Out-File -FilePath $LogPath -Append
}

# 发送告警通知
Send-PestAlert -Alert $alert

# 执行防治措施
if ($TreatmentMethod) {
$treatment = Start-PestTreatment `
-ZoneID $zone `
-CropType $CropType `
-Method $TreatmentMethod `
-Level $alert.Value

$zoneData.TreatmentHistory += [PSCustomObject]@{
Time = Get-Date
Method = $TreatmentMethod
Level = $alert.Value
Result = $treatment.Result
}

$manager.Treatments += $treatment

# 记录防治措施
if ($LogPath) {
$treatmentLog = [PSCustomObject]@{
Time = Get-Date
Type = "Treatment"
ZoneID = $zone
Method = $TreatmentMethod
Level = $alert.Value
Result = $treatment.Result
}
$treatmentLog | ConvertTo-Json | Out-File -FilePath $LogPath -Append
}
}
}
}

# 更新管理器状态
$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
# 配置环境监控
$monitorConfig = @{
FieldID = "FLD001"
Zones = @("Zone1", "Zone2", "Zone3")
SamplingInterval = 300
DataPath = "C:\Data\environment_monitor.json"
Thresholds = @{
"Temperature" = @{
Min = 15
Max = 30
}
"Humidity" = @{
Min = 40
Max = 80
}
"SoilMoisture" = @{
Min = 20
Max = 60
}
"LightIntensity" = @{
Min = 1000
}
"CO2Level" = @{
Max = 1000
}
}
}

# 启动环境监控
$monitor = Start-Job -ScriptBlock {
param($config)
Monitor-AgricultureEnvironment -FieldID $config.FieldID `
-Zones $config.Zones `
-SamplingInterval $config.SamplingInterval `
-DataPath $config.DataPath `
-Thresholds $config.Thresholds
} -ArgumentList $monitorConfig

# 配置灌溉系统
$irrigationConfig = @{
FieldID = "FLD001"
Schedule = @{
"Zone1" = @{
WaterFlow = 2.5
Duration = 30
}
"Zone2" = @{
WaterFlow = 2.0
Duration = 25
}
"Zone3" = @{
WaterFlow = 2.8
Duration = 35
}
}
AutoAdjust = $true
LogPath = "C:\Logs\irrigation_control.json"
}

# 管理灌溉系统
$controller = Manage-IrrigationSystem -FieldID $irrigationConfig.FieldID `
-Schedule $irrigationConfig.Schedule `
-AutoAdjust:$irrigationConfig.AutoAdjust `
-LogPath $irrigationConfig.LogPath

# 配置病虫害防治
$pestConfig = @{
FieldID = "FLD001"
Zones = @("Zone1", "Zone2", "Zone3")
CropType = "Tomato"
Thresholds = @{
"PestLevel" = @{
Max = 0.7
}
"DiseaseLevel" = @{
Max = 0.5
}
}
TreatmentMethod = "Biological"
LogPath = "C:\Logs\pest_control.json"
}

# 管理病虫害防治
$manager = Manage-PestControl -FieldID $pestConfig.FieldID `
-Zones $pestConfig.Zones `
-CropType $pestConfig.CropType `
-Thresholds $pestConfig.Thresholds `
-TreatmentMethod $pestConfig.TreatmentMethod `
-LogPath $pestConfig.LogPath

最佳实践

  1. 实施实时环境监控
  2. 优化灌溉方案
  3. 建立病虫害预警机制
  4. 保持详细的运行记录
  5. 定期进行系统评估
  6. 实施防治措施
  7. 建立数据分析体系
  8. 保持系统文档更新

PowerShell 技能连载 - PowerShell 过滤器:使用 Where-Object 和 Select-Object

概述:Where-object 和 Select-object

在学习如何使用 Where-Object 和 Select-Object 命令之前,理解前几节讨论的概念是至关重要的。首先,PowerShell 是一种面向对象的编程语言。几乎每个命令都会返回一个具有多个特征的对象,这些特征可以独立检查和过滤。

例如,Get-Process 命令将返回有关当前运行中的 Windows 进程的各种信息,如启动时间和当前内存使用情况。每个信息都保存为 Process 对象的属性。通过管道字符 | ,PowerShell 命令也可以链接在一起。当您这样做时,在管道左侧命令的结果将发送到右侧命令中。如果您将 Get-Process 管道到 Stop-Process(即 Get-Process | Stop-Process),则由 Get-Process 命令识别出来的进程将被停止。如果没有设置筛选条件,则此操作会尝试停止系统上所有正在运行中的进程。

Where-object:语法、工作原理和示例

Where-object 命令可用于根据它们拥有任何属性来过滤对象。

1
2
3
4
5
6
7
PS C:\Users\dhrub> get-command Where-Object -Syntax

Where-Object [-Property] <string> [[-Value] <Object>] [-InputObject <psobject>] [-EQ] [<CommonParameters>]

Where-Object [-FilterScript] <scriptblock> [-InputObject <psobject>] [<CommonParameters>]

Where-Object [-Property] <string> [[-Value] <Object>] -Match [-InputObject <psobject>] [<CommonParameters>]

最常用的语法是:

1
Where-Object {$_.PropertyName -ComparisonType FilterValue}

“PropertyName”属性是您正在过滤其属性的对象的名称。ComparisonType是描述您执行比较类型的简短关键字。“eq”代表等于,“gt”代表大于,“lt”代表小于,“like”代表通配符搜索。最后,FilterValue是与对象属性进行比较的值。Get-Process命令示例如下所示,并附有输出。

1
2
3
4
5
PS C:\Users\dhrub> get-process| Where-Object {$_.processname -eq "armsvc"}

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
124 8 1588 2800 4956 0 armsvc

Select-object: 语法、工作原理和示例

Select-Object 命令是另一个需要熟悉的命令。该命令用于限制或修改其他命令的输出。它有许多应用程序,但其中最常见的一种是选择另一个命令的前 N 个结果。

1
2
3
4
5
6
7
8
PS C:\Users\dhrub> Get-Command Select-Object -Syntax

Select-Object [[-Property] <Object[]>] [-InputObject <psobject>] [-ExcludeProperty <string[]>] [-ExpandProperty <string>] [-Unique] [-Last <int>] [-First <int>] [-Skip <int>] [-Wait]
[<CommonParameters>]

Select-Object [[-Property] <Object[]>] [-InputObject <psobject>] [-ExcludeProperty <string[]>] [-ExpandProperty <string>] [-Unique] [-SkipLast <int>] [<CommonParameters>]

Select-Object [-InputObject <psobject>] [-Unique] [-Wait] [-Index <int[]>] [<CommonParameters>]

以下是我们可以过滤进程的一种方式。

1
2
3
4
5
6
7
8
PS C:\Users\dhrub> get-process |select Name

Name
----
AdobeIPCBroker
amdfendrsr
AppHelperCap
ApplicationFrameHost

以下示例显示系统中正在运行的前五个进程。

1
2
3
4
5
6
7
8
9
PS C:\Users\dhrub> get-process |Select-Object -First 5

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
206 13 2428 10492 0.09 836 6 AdobeIPCBroker
110 8 2012 4612 3368 0 amdfendrsr
334 15 5692 9724 2284 0 AppHelperCap
394 22 15564 32088 0.30 13260 6 ApplicationFrameHost
124 8 1588 2800 4956 0 armsvc

以下示例显示系统中正在运行的最后五个进程。

1
2
3
4
5
6
7
8
9
PS C:\Users\dhrub> get-process |Select-Object -last 5

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1064 75 55192 2556 10.11 14596 6 WinStore.App
186 13 3380 8544 3856 0 WmiPrvSE
189 12 3900 11268 7532 0 WmiPrvSE
462 16 4900 8100 1288 0 WUDFHost
767 51 30048 17588 1.89 14588 6 YourPhone

结论

在PowerShell中,您可以通过使用Where-Object和Select-Object命令轻松控制正在处理的项目。 您可以使用这些命令来过滤您查看的数据或将操作限制为与您设置的筛选器匹配的操作(例如停止服务或删除文件)。 这个系列将在下一篇文章中结束。 我们将研究如何循环遍历对象组以对一组项目执行更复杂的任务。

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 Manage-ProcessControl {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ProcessID,

[Parameter()]
[hashtable]$Parameters,

[Parameter()]
[string]$Mode,

[Parameter()]
[switch]$AutoStart,

[Parameter()]
[int]$Timeout = 300
)

try {
$control = [PSCustomObject]@{
ProcessID = $ProcessID
StartTime = Get-Date
Mode = $Mode
Parameters = $Parameters
Status = "Initializing"
Steps = @()
}

# 检查过程状态
$processStatus = Get-ProcessStatus -ProcessID $ProcessID
if ($processStatus.IsRunning) {
throw "过程 $ProcessID 已经在运行中"
}

# 验证参数
$validationResult = Test-ProcessParameters -ProcessID $ProcessID -Parameters $Parameters
if (-not $validationResult.IsValid) {
throw "参数验证失败:$($validationResult.Message)"
}

# 获取控制步骤
$steps = Get-ProcessSteps -ProcessID $ProcessID -Mode $Mode

foreach ($step in $steps) {
$stepResult = [PSCustomObject]@{
StepID = $step.ID
Description = $step.Description
StartTime = Get-Date
Status = "InProgress"
}

try {
# 执行控制步骤
$result = Invoke-ProcessStep -ProcessID $ProcessID `
-StepID $step.ID `
-Parameters $step.Parameters

$stepResult.Status = "Success"
$stepResult.Result = $result

# 检查步骤结果
if (-not $result.Success) {
throw "步骤 $($step.ID) 执行失败:$($result.Message)"
}
}
catch {
$stepResult.Status = "Failed"
$stepResult.Error = $_.Exception.Message
throw
}
finally {
$stepResult.EndTime = Get-Date
$control.Steps += $stepResult
}
}

# 更新控制状态
$control.Status = "Running"
$control.EndTime = Get-Date

# 如果启用自动启动,开始监控过程
if ($AutoStart) {
Start-ProcessMonitoring -ProcessID $ProcessID -Timeout $Timeout
}

return $control
}
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
98
99
100
101
function Collect-ProcessData {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ProcessID,

[Parameter(Mandatory = $true)]
[DateTime]$StartTime,

[Parameter(Mandatory = $true)]
[DateTime]$EndTime,

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

[Parameter()]
[int]$SamplingRate = 1,

[Parameter()]
[string]$StoragePath,

[Parameter()]
[ValidateSet("Raw", "Aggregated", "Both")]
[string]$DataFormat = "Both"
)

try {
$collection = [PSCustomObject]@{
ProcessID = $ProcessID
StartTime = $StartTime
EndTime = $EndTime
Tags = $Tags
SamplingRate = $SamplingRate
RawData = @()
AggregatedData = @{}
Quality = @{}
}

# 获取过程数据
$data = Get-ProcessData -ProcessID $ProcessID `
-StartTime $StartTime `
-EndTime $EndTime `
-Tags $Tags `
-SamplingRate $SamplingRate

foreach ($record in $data) {
# 存储原始数据
if ($DataFormat -in @("Raw", "Both")) {
$collection.RawData += [PSCustomObject]@{
Timestamp = $record.Timestamp
Values = $record.Values
Quality = $record.Quality
}
}

# 计算聚合数据
if ($DataFormat -in @("Aggregated", "Both")) {
foreach ($tag in $Tags) {
if (-not $collection.AggregatedData.ContainsKey($tag)) {
$collection.AggregatedData[$tag] = @{
Min = [double]::MaxValue
Max = [double]::MinValue
Sum = 0
Count = 0
Quality = 0
}
}

$value = $record.Values[$tag]
$quality = $record.Quality[$tag]

$collection.AggregatedData[$tag].Min = [Math]::Min($collection.AggregatedData[$tag].Min, $value)
$collection.AggregatedData[$tag].Max = [Math]::Max($collection.AggregatedData[$tag].Max, $value)
$collection.AggregatedData[$tag].Sum += $value
$collection.AggregatedData[$tag].Count++
$collection.AggregatedData[$tag].Quality += $quality
}
}
}

# 计算统计数据
foreach ($tag in $Tags) {
if ($collection.AggregatedData.ContainsKey($tag)) {
$stats = $collection.AggregatedData[$tag]
$stats.Average = $stats.Sum / $stats.Count
$stats.Quality = $stats.Quality / $stats.Count
}
}

# 存储数据
if ($StoragePath) {
$collection | ConvertTo-Json -Depth 10 | Out-File -FilePath $StoragePath
}

return $collection
}
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
98
99
100
101
102
103
104
105
function Manage-ProcessAlarms {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ProcessID,

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

[Parameter()]
[ValidateSet("High", "Medium", "Low")]
[string]$Priority,

[Parameter()]
[string]$Operator,

[Parameter()]
[string]$Notes,

[Parameter()]
[switch]$Acknowledge
)

try {
$alarmManager = [PSCustomObject]@{
ProcessID = $ProcessID
StartTime = Get-Date
Alarms = @()
Actions = @()
}

# 获取活动报警
$activeAlarms = Get-ActiveAlarms -ProcessID $ProcessID `
-Types $AlarmTypes `
-Priority $Priority

foreach ($alarm in $activeAlarms) {
$alarmInfo = [PSCustomObject]@{
AlarmID = $alarm.ID
Type = $alarm.Type
Priority = $alarm.Priority
Description = $alarm.Description
Timestamp = $alarm.Timestamp
Status = $alarm.Status
Values = $alarm.Values
Actions = @()
}

# 处理报警
if ($Acknowledge) {
$acknowledgeResult = Acknowledge-Alarm -AlarmID $alarm.ID `
-Operator $Operator `
-Notes $Notes

$alarmInfo.Status = "Acknowledged"
$alarmInfo.Actions += [PSCustomObject]@{
Time = Get-Date
Action = "Acknowledge"
Operator = $Operator
Notes = $Notes
}
}

# 执行报警动作
$actions = Get-AlarmActions -AlarmID $alarm.ID

foreach ($action in $actions) {
$actionResult = [PSCustomObject]@{
ActionID = $action.ID
Description = $action.Description
StartTime = Get-Date
Status = "InProgress"
}

try {
$result = Invoke-AlarmAction -AlarmID $alarm.ID `
-ActionID $action.ID `
-Parameters $action.Parameters

$actionResult.Status = "Success"
$actionResult.Result = $result
}
catch {
$actionResult.Status = "Failed"
$actionResult.Error = $_.Exception.Message
}
finally {
$actionResult.EndTime = Get-Date
$alarmInfo.Actions += $actionResult
}
}

$alarmManager.Alarms += $alarmInfo
}

# 更新报警状态
$alarmManager.EndTime = Get-Date

return $alarmManager
}
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
# 配置过程控制参数
$processConfig = @{
ProcessID = "REACTOR001"
Mode = "Normal"
Parameters = @{
Temperature = 150
Pressure = 10
FlowRate = 100
}
AutoStart = $true
Timeout = 600
}

# 启动过程控制
$control = Manage-ProcessControl -ProcessID $processConfig.ProcessID `
-Mode $processConfig.Mode `
-Parameters $processConfig.Parameters `
-AutoStart:$processConfig.AutoStart `
-Timeout $processConfig.Timeout

# 采集过程数据
$data = Collect-ProcessData -ProcessID "REACTOR001" `
-StartTime (Get-Date).AddHours(-1) `
-EndTime (Get-Date) `
-Tags @("Temperature", "Pressure", "FlowRate") `
-SamplingRate 1 `
-StoragePath "C:\Data\reactor001_data.json" `
-DataFormat "Both"

# 管理过程报警
$alarms = Manage-ProcessAlarms -ProcessID "REACTOR001" `
-AlarmTypes @("Temperature", "Pressure") `
-Priority "High" `
-Operator "John Smith" `
-Notes "系统维护" `
-Acknowledge

最佳实践

  1. 实施严格的过程控制
  2. 建立完整的数据采集系统
  3. 实现多级报警机制
  4. 保持详细的运行记录
  5. 定期进行系统校准
  6. 实施访问控制策略
  7. 建立应急响应机制
  8. 保持系统文档更新

PowerShell 技能连载 - DevOps 集成

在DevOps时代,PowerShell可以帮助我们更好地实现持续集成和持续部署。本文将介绍如何使用PowerShell构建一个DevOps自动化系统,包括CI/CD流程管理、基础设施即代码和制品管理等功能。

CI/CD流程管理

首先,让我们创建一个用于管理CI/CD流程的函数:

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 Manage-DevOpsPipeline {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$PipelineID,

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

[Parameter()]
[ValidateSet("Build", "Test", "Deploy")]
[string]$OperationMode = "Build",

[Parameter()]
[hashtable]$PipelineConfig,

[Parameter()]
[string]$LogPath
)

try {
$manager = [PSCustomObject]@{
PipelineID = $PipelineID
StartTime = Get-Date
PipelineStatus = @{}
Operations = @{}
Issues = @()
}

# 获取流程配置
$config = Get-PipelineConfig -PipelineID $PipelineID

# 管理流程
foreach ($type in $PipelineTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Operations = @{}
Issues = @()
}

# 应用流程配置
$typeConfig = Apply-PipelineConfig `
-Config $config `
-Type $type `
-Mode $OperationMode `
-Settings $PipelineConfig

$status.Config = $typeConfig

# 执行流程操作
$operations = Execute-PipelineOperations `
-Type $type `
-Config $typeConfig

$status.Operations = $operations
$manager.Operations[$type] = $operations

# 检查流程问题
$issues = Check-PipelineIssues `
-Operations $operations `
-Config $typeConfig

$status.Issues = $issues
$manager.Issues += $issues

# 更新流程状态
if ($issues.Count -gt 0) {
$status.Status = "Failed"
}
else {
$status.Status = "Success"
}

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

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

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

return $manager
}
catch {
Write-Error "DevOps流程管理失败:$_"
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-InfrastructureAsCode {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$InfraID,

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

[Parameter()]
[ValidateSet("Terraform", "DSC", "ARM")]
[string]$InfraMode = "Terraform",

[Parameter()]
[hashtable]$InfraConfig,

[Parameter()]
[string]$ReportPath
)

try {
$manager = [PSCustomObject]@{
InfraID = $InfraID
StartTime = Get-Date
InfraStatus = @{}
Configurations = @{}
Issues = @()
}

# 获取基础设施配置
$config = Get-InfraConfig -InfraID $InfraID

# 管理基础设施
foreach ($type in $InfraTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Configurations = @{}
Issues = @()
}

# 应用基础设施配置
$typeConfig = Apply-InfraConfig `
-Config $config `
-Type $type `
-Mode $InfraMode `
-Settings $InfraConfig

$status.Config = $typeConfig

# 配置基础设施
$configurations = Configure-InfraResources `
-Type $type `
-Config $typeConfig

$status.Configurations = $configurations
$manager.Configurations[$type] = $configurations

# 检查基础设施问题
$issues = Check-InfraIssues `
-Configurations $configurations `
-Config $typeConfig

$status.Issues = $issues
$manager.Issues += $issues

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

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

# 生成报告
if ($ReportPath) {
$report = Generate-InfraReport `
-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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
function Manage-Artifacts {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ArtifactID,

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

[Parameter()]
[ValidateSet("Package", "Container", "Binary")]
[string]$ArtifactMode = "Package",

[Parameter()]
[hashtable]$ArtifactConfig,

[Parameter()]
[string]$ReportPath
)

try {
$manager = [PSCustomObject]@{
ArtifactID = $ArtifactID
StartTime = Get-Date
ArtifactStatus = @{}
Operations = @{}
Issues = @()
}

# 获取制品配置
$config = Get-ArtifactConfig -ArtifactID $ArtifactID

# 管理制品
foreach ($type in $ArtifactTypes) {
$status = [PSCustomObject]@{
Type = $type
Status = "Unknown"
Config = @{}
Operations = @{}
Issues = @()
}

# 应用制品配置
$typeConfig = Apply-ArtifactConfig `
-Config $config `
-Type $type `
-Mode $ArtifactMode `
-Settings $ArtifactConfig

$status.Config = $typeConfig

# 执行制品操作
$operations = Execute-ArtifactOperations `
-Type $type `
-Config $typeConfig

$status.Operations = $operations
$manager.Operations[$type] = $operations

# 检查制品问题
$issues = Check-ArtifactIssues `
-Operations $operations `
-Config $typeConfig

$status.Issues = $issues
$manager.Issues += $issues

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

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

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

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

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

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

使用示例

以下是如何使用这些函数来管理DevOps环境的示例:

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
# 管理CI/CD流程
$manager = Manage-DevOpsPipeline -PipelineID "PIPELINE001" `
-PipelineTypes @("Build", "Test", "Deploy") `
-OperationMode "Build" `
-PipelineConfig @{
"Build" = @{
"Source" = @{
"Repository" = "https://github.com/org/repo"
"Branch" = "main"
"Trigger" = "push"
}
"Steps" = @{
"Restore" = @{
"Command" = "dotnet restore"
"WorkingDirectory" = "src"
}
"Build" = @{
"Command" = "dotnet build"
"WorkingDirectory" = "src"
}
"Publish" = @{
"Command" = "dotnet publish"
"WorkingDirectory" = "src"
}
}
"Artifacts" = @{
"Path" = "src/bin/Release/net6.0/publish"
"Type" = "zip"
}
}
"Test" = @{
"Framework" = "xunit"
"Projects" = @("tests/UnitTests", "tests/IntegrationTests")
"Coverage" = @{
"Enabled" = $true
"Threshold" = 80
}
}
"Deploy" = @{
"Environment" = "Production"
"Strategy" = "BlueGreen"
"Targets" = @{
"Web" = @{
"Type" = "AppService"
"ResourceGroup" = "rg-prod"
"Name" = "app-prod"
}
"Database" = @{
"Type" = "SqlServer"
"ResourceGroup" = "rg-prod"
"Name" = "sql-prod"
}
}
}
} `
-LogPath "C:\Logs\pipeline_management.json"

# 管理基础设施即代码
$manager = Manage-InfrastructureAsCode -InfraID "INFRA001" `
-InfraTypes @("Network", "Compute", "Storage") `
-InfraMode "Terraform" `
-InfraConfig @{
"Network" = @{
"Provider" = "azurerm"
"Resources" = @{
"VNet" = @{
"Name" = "vnet-prod"
"AddressSpace" = "10.0.0.0/16"
"Subnets" = @{
"Web" = "10.0.1.0/24"
"App" = "10.0.2.0/24"
"Data" = "10.0.3.0/24"
}
}
"NSG" = @{
"Name" = "nsg-prod"
"Rules" = @{
"HTTP" = @{
"Priority" = 100
"Protocol" = "Tcp"
"Port" = 80
"Source" = "Internet"
"Destination" = "Web"
}
}
}
}
}
"Compute" = @{
"Provider" = "azurerm"
"Resources" = @{
"VMSS" = @{
"Name" = "vmss-web"
"Capacity" = 3
"Size" = "Standard_D2s_v3"
"Image" = "UbuntuLTS"
}
"AppService" = @{
"Name" = "app-prod"
"Plan" = "PremiumV2"
"Runtime" = "dotnet:6.0"
}
}
}
"Storage" = @{
"Provider" = "azurerm"
"Resources" = @{
"StorageAccount" = @{
"Name" = "stprod"
"Type" = "Standard_LRS"
"Replication" = "GRS"
}
"Container" = @{
"Name" = "data"
"Access" = "private"
}
}
}
} `
-ReportPath "C:\Reports\infrastructure_management.json"

# 管理制品
$manager = Manage-Artifacts -ArtifactID "ARTIFACT001" `
-ArtifactTypes @("Package", "Container", "Binary") `
-ArtifactMode "Package" `
-ArtifactConfig @{
"Package" = @{
"Type" = "NuGet"
"Name" = "MyApp"
"Version" = "1.0.0"
"Source" = "src/MyApp"
"Target" = @{
"Feed" = "https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json"
"ApiKey" = "env:NUGET_API_KEY"
}
}
"Container" = @{
"Type" = "Docker"
"Name" = "myapp"
"Tag" = "1.0.0"
"Source" = "Dockerfile"
"Target" = @{
"Registry" = "myregistry.azurecr.io"
"Username" = "env:ACR_USERNAME"
"Password" = "env:ACR_PASSWORD"
}
}
"Binary" = @{
"Type" = "Zip"
"Name" = "myapp-release"
"Version" = "1.0.0"
"Source" = "src/MyApp/bin/Release"
"Target" = @{
"Storage" = "stprod"
"Container" = "releases"
}
}
} `
-ReportPath "C:\Reports\artifact_management.json"

最佳实践

  1. 实施CI/CD流程
  2. 配置基础设施即代码
  3. 管理制品版本
  4. 保持详细的部署记录
  5. 定期进行健康检查
  6. 实施监控策略
  7. 建立告警机制
  8. 保持系统文档更新

PowerShell 技能连载 - CSV 数据处理技巧

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

首先,让我们看看如何创建和读取 CSV 数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建示例 CSV 数据
$csvData = @"
姓名,年龄,部门,职位,入职日期
张三,30,技术部,高级工程师,2020-01-15
李四,28,市场部,市场经理,2019-06-20
王五,35,财务部,财务主管,2018-03-10
赵六,32,人力资源部,HR专员,2021-09-05
"@

# 将 CSV 字符串保存到文件
$csvData | Out-File -FilePath "employees.csv" -Encoding UTF8

# 读取 CSV 文件
$employees = Import-Csv -Path "employees.csv" -Encoding UTF8

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

处理带有特殊字符的 CSV:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建包含特殊字符的 CSV
$specialCsv = @"
产品名称,价格,描述,备注
"笔记本电脑",5999,"高性能,轻薄便携","支持""快速充电"""
"无线鼠标",199,"人体工学,静音","包含""电池"""
"机械键盘",899,"RGB背光,青轴","支持""宏编程"""
"@

# 使用引号处理特殊字符
$specialCsv | Out-File -FilePath "products.csv" -Encoding UTF8

# 读取并处理特殊字符
$products = Import-Csv -Path "products.csv" -Encoding UTF8
Write-Host "`n产品列表:"
$products | Format-Table

使用自定义分隔符:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建使用分号分隔的 CSV
$semicolonCsv = @"
姓名;年龄;部门;职位
张三;30;技术部;高级工程师
李四;28;市场部;市场经理
王五;35;财务部;财务主管
"@

$semicolonCsv | Out-File -FilePath "employees_semicolon.csv" -Encoding UTF8

# 使用自定义分隔符读取
$employees = Import-Csv -Path "employees_semicolon.csv" -Delimiter ";" -Encoding UTF8
Write-Host "`n使用分号分隔的员工列表:"
$employees | Format-Table

数据过滤和转换:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 读取 CSV 并进行数据过滤
$employees = Import-Csv -Path "employees.csv" -Encoding UTF8

# 过滤特定部门的员工
$techDept = $employees | Where-Object { $_.部门 -eq "技术部" }
Write-Host "`n技术部员工:"
$techDept | Format-Table

# 转换数据格式
$employees | ForEach-Object {
[PSCustomObject]@{
姓名 = $_.姓名
年龄 = [int]$_.年龄
部门 = $_.部门
职位 = $_.职位
入职日期 = [datetime]$_.入职日期
工作年限 = ((Get-Date) - [datetime]$_.入职日期).Days / 365
}
} | Export-Csv -Path "employees_processed.csv" -NoTypeInformation -Encoding UTF8

一些实用的 CSV 处理技巧:

  1. 处理大文件:
1
2
3
4
5
6
7
8
9
10
11
12
# 使用流式处理大型 CSV 文件
$reader = [System.IO.StreamReader]::new("large-data.csv")
$header = $reader.ReadLine().Split(",")
while (-not $reader.EndOfStream) {
$line = $reader.ReadLine().Split(",")
$record = @{}
for ($i = 0; $i -lt $header.Count; $i++) {
$record[$header[$i]] = $line[$i]
}
[PSCustomObject]$record
}
$reader.Close()
  1. 数据验证:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Test-CsvFormat {
param(
[string]$CsvPath,
[string[]]$RequiredColumns
)

$csv = Import-Csv -Path $CsvPath -Encoding UTF8
$headers = $csv[0].PSObject.Properties.Name

foreach ($column in $RequiredColumns) {
if ($column -notin $headers) {
return $false
}
}
return $true
}
  1. 合并多个 CSV 文件:
1
2
3
4
5
6
7
# 合并多个 CSV 文件
$csvFiles = Get-ChildItem -Path "*.csv" -Filter "employees_*.csv"
$allEmployees = @()
foreach ($file in $csvFiles) {
$allEmployees += Import-Csv -Path $file.FullName -Encoding UTF8
}
$allEmployees | Export-Csv -Path "all_employees.csv" -NoTypeInformation -Encoding UTF8

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

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
  1. 数据筛选和过滤:
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
  1. 创建数据透视表:
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 技术 QQ 群