PowerShell如何为每个IP启动Start-Job并关联名称生成对应日志文件
批量改造方案
原写法异常的核心原因:Start-Job启动的是独立进程的异步任务,不会在调用时捕获外层遍历变量的瞬时值,等作业实际执行读取变量时,外层循环往往已经跑完,所有作业都会读到最后一次遍历的IP和文件名,导致逻辑异常。按下面的步骤改造即可实现IP+自定义名称绑定的批量采集:
第一步:定义全局配置与设备映射表
不要零散给变量追加动态属性,直接用结构化数组维护设备与IP的绑定关系,后续新增设备直接往数组中添加条目即可:
# 所有设备共用的固定配置 $LogDir = "C:\WeightLogs" # 替换为实际日志存放目录 $PlinkDir = "C:\Tools\Plink" # 替换为实际plink.exe所在目录 $SerialPort = 23 # 替换为实际telnet服务端口 # 设备清单:每项对应一台采集设备,自定义名称与IP一一绑定 $DeviceList = @( [PSCustomObject]@{ Name = "1号车间称重台" IP = "192.168.3.101" } [PSCustomObject]@{ Name = "2号车间称重台" IP = "192.168.3.102" } [PSCustomObject]@{ Name = "3号车间称重台" IP = "192.168.3.103" } # 新增设备按上述格式追加即可 )
第二步:改造批量作业启动函数
每个设备独有的名称、IP通过-ArgumentList传入作业独立作用域,从根源避免变量串值,同时修复原代码的潜在问题(作业重名、文件流覆盖风险、特殊字符导致日志创建失败等):
function Capture-WeightBatch { foreach ($device in $DeviceList) { # 作业名绑定设备名,避免重名方便后续运维 Start-Job -Name "WeightLog_$($device.Name)" -ScriptBlock { param( $DeviceName, $DeviceIP ) # 日志行加时间戳过滤器 filter Add-Timestamp { $sw.WriteLine("$(Get-Date -Format MM/dd/yyyy_HH:mm:ss) $_") } try { # 替换文件名非法字符,避免创建日志文件报错 $safeFileName = $DeviceName -replace '[\\/:*?"<>|]', '_' $logFullPath = Join-Path $using:LogDir "$safeFileName$(Get-Date -f MM-dd-yyyy).txt" # StreamWriter第二个参数传$true表示追加写入,避免重启作业覆盖历史日志 $sw = [System.IO.StreamWriter]::new($logFullPath, $true) # 启动plink连接对应设备,输出打时间戳写入日志 & (Join-Path $using:PlinkDir "plink.exe") -telnet $DeviceIP -P $using:SerialPort | Add-Timestamp } finally { # 释放文件流资源,避免日志句柄占用 $sw.ForEach('Flush') $sw.ForEach('Dispose') } } -ArgumentList $device.Name, $device.IP } }
使用方式
直接调用函数即可批量启动所有设备的重量采集作业:
Capture-WeightBatch
常用运维命令
- 查看所有采集作业的运行状态:
Get-Job -Name WeightLog_* - 查看指定作业的运行输出与报错:
Receive-Job -Name "WeightLog_1号车间称重台" - 停止所有运行中的采集作业:
Get-Job -Name WeightLog_* | Stop-Job - 清理已退出的作业记录释放资源:
Get-Job -Name WeightLog_* | Where-Object State -ne Running | Remove-Job
若使用PowerShell 7+版本,也可替换
Start-Job为ForEach-Object -Parallel实现更高的并行效率,核心传参逻辑不变:设备独有参数必须传入并行作用域内部,禁止直接引用外层遍历变量。
内容的提问来源于stack exchange,提问作者user18982890
相关产品推荐
相关产品推荐

