0

약 15 개의 원격 서버에서 버전을 확인하는 스크립트를 작성 중이며 스크립트가 예상보다 오래 실행됩니다.Powershell 스크립트가 느리게 실행 됨

$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') 
+0

이유는 Win32_Product와입니다.) 아니, 진지하게. 나는 그것이 거대한 클래스라고 생각합니다. 그래서 항상 쿼리하는 것이 너무 느립니다. PS 3.0에서는 [workflows] (http://blogs.technet.com/b/heyscriptingguy/archive/2012/12/26/powershell-workflows-the-basics.aspx)를 사용하여 스크립트 블록을 병렬로 실행할 수 있습니다. 또는 (또는 그 외에도) 버전 번호 만 필요한 경우 Get-Item을 사용하여 레지스트리를 쿼리 할 수 ​​있습니다. 훨씬 빠릅니다. –

답변

1

루프 나 연속적으로 수행 할 필요가 없습니다. invoke-commandComputerName 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 

그러나 팀 페럴에 의해 지적 된 바와 같이, 당신은 원격 서버에 ping은 Get-WMIObject에서 사용할 수 있습니다, 그리고 당신은 작업으로 그것을 할 경우, 병렬로 여러 요청을 실행합니다.

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

그런 다음 작업 cmdlet을 사용하여 결과를받습니다.

0

성능을 향상시킬 수있는 몇 가지 방법이 있습니다. PowerShell WorkFlow는 각 컴퓨터를 동시에 공격하는 ForEach를 병렬로 지원합니다. -ComputerName과 함께 Get-WMIObject를 사용하여 컴퓨터 목록을 쿼리 할 수도 있습니다. Get-WMIObject는 또한 도움이 될 수있는 -AsJob 스위치도 지원합니다.

0

그래, 일자리를 이용하는 것이 최선의 방법이라고 생각합니다. 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 } 

. foreach 문 내의 하나가 작업을 조절하여 한 번에 30 개만 실행합니다. 마지막 작업은 모든 작업이 완료 될 때까지 기다렸다가 종료합니다.

이 결과를 수집하려면, 당신은이를 사용할 수 있습니다

$jobList | % { $jobResults = Receive-Job $_; write-host $jobResults.result } 

작업 개체뿐만 아니라 탐구 가치가있을 수있는 다른 속성이 있습니다.

0

Win32_Product에 대한 쿼리는 reconfiguration of installed packages을 트리거하므로 프로세스에 많은 시간이 소요됩니다. 또한 실수로 구성 매개 변수를 재설정 할 수 있으므로 이러한 쿼리는 potentially harmful이됩니다. 특정 프로그램의 버전 확인 같은 것을 들어

당신이 (원격) 레지스트리에서 직접 정보를 읽는 것이 더 낫다 :

$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 
관련 문제