Performance Powershell脚本运行缓慢

Performance Powershell脚本运行缓慢,performance,powershell,powershell-3.0,remote-server,powershell-remoting,Performance,Powershell,Powershell 3.0,Remote Server,Powershell Remoting,我正在编写一个脚本来检查大约15台远程服务器上的版本,该脚本的执行时间比我预期的要长得多 $listServers = @("compName1", "compName2", "compName3", ... "compName15") "" | Out-File C:\temp\javaVersion.txt "" | Out-File C:\temp\javaVersionLog.txt $cred = Get-Credential ForEach ($server in $listSe

我正在编写一个脚本来检查大约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
 }
根据测量命令输出,完成此操作大约需要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')

有几种方法可以提高性能。PowerShell工作流并行支持ForEach,这将同时影响每台计算机。您还可以使用Get-WMIObject with-ComputerName查询计算机列表。Get-WMIObject还支持-AsJob开关,这也会有所帮助。

您不需要在循环中或串行地执行此操作
invoke命令
获取
ComputerName
s的集合,并可以并行运行请求

$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
Get-WMIObject Win32_Product  -Filter "Name like 'Java [0-9]%'" -computername $listServers -throttlelimit 4 -asjob |select -excludeproperty version
然而,正如Tim Ferrell所指出的,您可以使用Get-WMIOObject远程ping服务器,如果您将其作为作业来执行,它将并行运行多个请求

$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
Get-WMIObject Win32_Product  -Filter "Name like 'Java [0-9]%'" -computername $listServers -throttlelimit 4 -asjob |select -excludeproperty version

然后使用Job cmdlet来接收结果。

是的,我认为使用jobs是一种方法。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 }

作业对象还有其他值得研究的属性。

Win32\u产品
触发器a进行查询,这使得该过程非常耗时。它还进行此类查询,因为它可能会无意中重置配置参数

对于某些特定程序的版本检查,最好直接从(远程)注册表读取信息:

$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
原因是Win32_产品。)不,说真的。我猜这是一个巨大的类,这就是为什么它总是这么慢的查询。在PS3.0中,您可以使用来并行执行脚本块。或者(或者除此之外),如果您只需要版本号,您可以使用Get Item查询注册表。速度快得多。