powershell - 多线程 PowerShell 脚本
问题描述
我有一个 PowerShell 脚本,用于检查文件夹中是否存在文件。问题是:这个脚本可以正常工作,但是速度很慢。我必须每天检查 10K Pcs 的统计数据。我想使用Invoke-Command
,但我不能使用它,因为并非所有客户端都启用了 WinRM。是否可以在没有 WinRM 的情况下使此脚本成为多线程?
这是我的代码:
function Show-Menu {
param (
[string]$Title = 'Debug'
)
cls
Write-Host "================ $Title ================"
Write-Host "Ziel Clients werden in der Datei C:\temp\srv.txt angegeben!" -ForegroundColor Red
Write-Host "1: Detailansicht alle Clients" -ForegroundColor Green
Write-Host "2: Today Crash" -ForegroundColor Green
Write-Host "3: Detailansich einzelner Client" -ForegroundColor Green
Write-Host "Q: 'Q' zum beenden."
Write-Host "Script wird ausgefuehrt als:"
whoami
}
do {
Show-Menu
$input = Read-Host "Nummer angeben"
switch ($input) {
'1' {
cls
Write-Host "Detailansicht alle Clients"
$computers = Get-Content C:\temp\srv.txt
foreach ($computer in $computers) {
Write-Host -foregroundcolor "green" "Verarbeite $computer..."
if ( ! (Test-Connection $computer -Count 1 -Quiet)) {
Write-Host -foregroundcolor "red" "$computer ist offline"
continue
}
$path = Test-Path "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*" -Include *dump*
Get-Item "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
If ($path -eq $true ) { Write-Host $computer 'Dumps are present' }
Else { Write-Host $computer 'Dumps are not present' }
pause
}
}
'2' {
cls
Write-Host "Today Crash"
$computers = Get-Content C:\temp\srv.txt
foreach ($computer in $computers) {
Write-Host -foregroundcolor "green" "Verarbeite $computer..."
if ( ! (Test-Connection $computer -Count 1 -Quiet)) {
Write-Host -foregroundcolor "red" "$computer ist offline"
continue
}
$result = Get-ChildItem -Path "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*" | Where-Object { $_.LastWriteTime -ge (Get-Date).Date }
}
$result | Out-GridView
}
'3' {
cls
Write-Host "Detailansich einzelner Client"
$computer = Read-Host -Prompt 'Client angeben'
$result = Get-ChildItem -Path "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
$result | Out-GridView
}
}
}
until ($input -eq 'q')
解决方案
虽然后台作业(通过方式启动Start-Job
)确实允许并行运行,但它们在子进程中运行,因此资源密集且速度慢;此外,您不能限制它们的使用,即您不能(直接)控制最多允许同时运行多少个子进程
相比之下,线程作业作为进程内线程运行,因此需要更少的资源,并且比基于子进程的后台作业快得多;此外,还支持节流(限制允许同时运行的线程数)。
线程作业通过PowerShell [Core] v6+Start-ThreadJob
附带的 cmdlet启动,在Windows PowerShell中可以按需安装,例如.Install-Module ThreadJob -Scope CurrentUser
您只需调用Start-ThreadJob
而不是Start-Job
,并使用标准*-Job
cmdlet 来管理此类线程作业 - 与管理Start-Job
-launched 后台作业的方式相同。
在最简单的情况下,您可以简单地等待所有线程完成:
# PowerShell [Core] 6+
# Windows PowerShell with the ThreadJob module installed.
Get-Content C:\temp\srv.txt | ForEach-Object {
$computer = $_
Start-ThreadJob { # create a thread job and output an object representing it
Write-Host -ForegroundColor Green "Processing $using:computer..."
# ...
Get-Item "\\$using:computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
# ...
}
} | Receive-Job -Wait -AutoRemoveJob
注意
$using:
范围说明符的使用,它是访问调用者$computer
值所必需的;此要求同样适用于后台作业、线程作业和远程处理。默认最多允许5个线程同时运行;您可以使用该
-ThrottleLimit
参数来修改此值,但请注意,将此值增加到超出硬件可以支持的范围实际上会减慢速度。不能保证输出排序;也就是说,不能保证输出与指定计算机名称的顺序相对应。
在PowerShell 7+中,有一种更简单的方法可以通过的参数并行运行线程:ForEach-Object
-Parallel
# PowerShell 7+
Get-Content C:\temp\srv.txt | ForEach-Object -Parallel {
Write-Host -foregroundcolor Green "Processing $_..."
# ...
Get-Item "\\$_\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
# ...
}
上面关于输出排序和限制的评论在这里同样适用,但请注意,计算机名称现在通过管道作为输入提供,因此可以在线程脚本块内使用通常的自动$_
变量。
推荐阅读
- amazon-web-services - 使用自定义资源访问 cloudformation 中的 API 网关端点
- javascript - 使用 Mongoose 查询一系列日期之间的项目
- r - 如何按年改变两个人口的比率
- python - 如何将多个文件夹中的相同文件合并为一个文件s3
- ios - 当状态更改时,如何防止 SceneKit 场景重新渲染不佳?
- excel - 如何在 FILTERXML 中连接 XML 子项
- javascript - 尝试对本地存储的输出进行分类
- java - CloseableHttpClient (Apache HTTPComponents) 的意外行为
- python - 亚马逊动态更改其 CSS 选择器和 HTML 对象的名称?
- r - R中data.table中的回归,id by id(例如,逐行)