
[英]Powershell script running more slowly in a runspace than in the shell
[英]Powershell Script Running Slowly
我正在编写一个脚本来检查大约15台远程服务器上的版本,并且该脚本的执行时间比我期望的要长得多。
$listServers = @("compName1", "compName2", "compName3", ... "compName15")
"" | Out-File C:\temp\javaVersion.txt
"" | Out-File C:\temp\javaVersionLog.txt
$cred = Get-Credential
ForEach ($server in $listServers)
{
Measure-Command {$javaVersion = Invoke-Command -ComputerName $server -Credential $cred -Authentication Kerberos -ScriptBlock {Get-WmiObject -Class Win32_Product -Filter "Name like 'Java [0-9]%'" | Select -ExcludeProperty Version}} -ErrorAction SilentlyContinue -ErrorVariable errorOutput
$errorOutput | Out-File C:\temp\javaVersionLog.txt -Append
$server + $javaVersion | Out-File C:\temp\javaVersion.txt -Append
}
根据Measure-Command输出,大约需要21秒才能完成。 我是否有原因想念该脚本需要很长时间才能完成?
编辑:
在被其他问题分散注意力之后,我终于完成了脚本。
Start-Transcript C:\temp\javaVersion.txt
$listServers = @("compName1", "compName2", "compName3", ... "compName15")
$javaVersVerbose = ""
Invoke-Command -ComputerName $listServers -ScriptBlock {
$registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $_);
$javaKey = $registry.OpenSubKey('SOFTWARE\JavaSoft\Java Runtime Environment');
$javaVers = $javaKey.GetValue('CurrentVersion');
$javaVersVerbose = $javaKey.GetValue('Java' + $javaVers.Substring(2, 1) + 'FamilyVersion');
$nameKey = $registry.OpenSubKey('SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName');
$name = $nameKey.GetValue('ComputerName');
$name + " " + $javaVersVerbose | echo
} -ErrorAction SilentlyContinue -ErrorVariable errorOutput
$errorOutput | echo
Write-Host -NoNewLine 'Press any key to continue...'
$null = $Host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
您无需循环执行,也无需串行执行。 invoke-command
接受ComputerName
的集合,并且可以并行运行请求。
$listServers = @("compName1", "compName2", "compName3", ... "compName15")
Invoke-Command -throttlelimit 4 -ComputerName $listServers -Credential $cred -Authentication Kerberos -ScriptBlock {Get-WmiObject -Class Win32_Product -Filter "Name like 'Java [0-9]%'" | Select -ExcludeProperty Version}} -ErrorAction SilentlyContinue -ErrorVariable errorOutput
但是,正如Tim Ferrell所指出的那样,您可以使用Get-WMIObject远程ping服务器,如果您将其作为作业进行,它将并行运行多个请求。
Get-WMIObject Win32_Product -Filter "Name like 'Java [0-9]%'" -computername $listServers -throttlelimit 4 -asjob |select -excludeproperty version
然后使用Job cmdlet接收结果。
有两种方法可以改善性能。 PowerShell WorkFlow并行支持ForEach,这将同时击中每台计算机。 您还可以将Get-WMIObject与-ComputerName一起使用来查询计算机列表。 Get-WMIObject还支持-AsJob开关,这也可能有所帮助。
是的,我认为使用工作是必经之路。 WMI调用可能会花费很长时间,尤其是当您遇到一两个没有响应的主机时。
也许考虑这样的事情:
$listServers = @((1..15 | % {"compName$_"}))
$jobList = @()
$JavaBlock = {
function checkServer ($serverName) {
$returnValue = Get-WmiObject -computerName $serverName -Class Win32_Product -Credential $cred -Filter "Name like 'Java [0-9]%'" | Select -ExcludeProperty Version
return $returnValue
}
}
foreach ($server in $listServer) {
$job = start-job -InitializationScript $JavaBlock -ScriptBlock { checkServer $args } -argumentList $hostname
$jobList += $job
while (($jobList | where { $_.state -eq "Running" }).count -ge 30) { start-sleep -s 1 }
}
while (($jobList | | where { $_.state -eq "Running" }).count -ge 1) { start-sleep -ms 500 }
这两个while语句控制作业流程。 foreach语句中的一个限制了作业,因此一次仅运行30个。 最后一个只是等待所有作业完成,然后再结束。
要收集结果,可以使用以下方法:
$jobList | % { $jobResults = Receive-Job $_; write-host $jobResults.result }
Job对象还具有其他可能值得探索的属性。
对Win32_Product
查询触发了已安装软件包的重新配置 ,这使该过程非常耗时。 这还会使此类查询潜在地有害 ,因为它可能会无意中重置配置参数。
对于特定程序的版本检查,最好直接从(远程)注册表中读取信息:
$listServers | % {
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $_)
$key = $reg.OpenSubKey('SOFTWARE\JavaSoft\Java Runtime Environment')
New-Object -Type PSObject -Property @{
'Server' = $_
'JavaVersion' = $key.GetValue('CurrentVersion')
}
} | Export-Csv 'C:\temp\javaVersion.csv' -NoType
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.