2014-09-04 2 views
0

모두에게 안녕하세요! 나는 이번 주에이 대본을 작업 해왔다. 그것은 정상적으로 작동하지만 우리 네트워크에서 물리적으로 (예 : 유타에서 플로리다/알래스카에 이르기까지) 실질적으로 멀리 떨어져있는 PC를 쿼리 할 때 매우 오랜 시간이 걸립니다.Powershell WMI 스크립트 속도가 느림

사무실에있는 PC를 쿼리하는 데 약 15 초 밖에 걸리지 않습니다. ~ 3000 마일 떨어진 곳에있는 PC를 쿼리하는 데 때때로 5 분 이상 걸립니다.

대기 시간이 상당히 길어질 것으로 예상되지만 누군가이 스크립트를 사용하여 시간을 절약하는 데 도움이되는지 궁금합니다.

PowerShell 초보자를위한 모든 지침을 주시면 감사하겠습니다.

감사합니다.

## Ping Test to prevent errors when no PC is found 
function PingTest { 

$outputBox.text="Testing PC Connection. Please wait..." 
$pingresults = Test-Connection $InputBox.text -count 2 

if($pingresults.Count -gt 0) 
{ 
GetComputerInfo 
} 
Else 
{ 
$outputBox.text="**ERROR!** 

The PC may either be off the network or the PC hostname you've entered is incorrect. Please try again." 
} 

} 

## After successful ping, grabs PC info from ComputerInfoScript function and sents to the output box 
function GetComputerInfo { 
$outputBox.text = "Ping test successful. Gathering PC info. Please wait..." 
$computerhostname = $InputBox.text; 
$computerinfo = ComputerInfoScript | out-string; 
$outputBox.text=$computerinfo #sends gathered computer information to output box 
if ($Checkbox_AutoCopy.checked -eq $True) { # auto-copy 
$outputBox.text | clip 
} 
} 

## Commands to grab PC information 
function ComputerInfoScript { 
################################## Variables 
$date = Get-Date 
$computerSystem = get-wmiobject Win32_ComputerSystem -ComputerName $computerhostname 
$computerBIOS = get-wmiobject Win32_BIOS -ComputerName $computerhostname 
$computerOS = get-wmiobject Win32_OperatingSystem -ComputerName $computerhostname 
$computerCPU = get-wmiobject Win32_Processor -ComputerName $computerhostname 
$computerHDD = Get-WmiObject Win32_LogicalDisk -Filter drivetype=3 -ComputerName $computerhostname 
$computerDefaultPrint = get-wmiobject win32_printer | %{if ($_.default) {$_}} 
$computerPrint = Get-WmiObject Win32_Printer -ComputerName $computerhostname 
$computerMonitors = Get-WMIObject Win32_DesktopMonitor -ComputerName $computerhostname 
$computerOpticalDrive = Get-WmiObject Win32_CDROMDrive -ComputerName $computerhostname 
$computerMappedDrives = Get-WmiObject -ComputerName $computerhostname -Class Win32_MappedLogicalDisk | select name,providername 
$computerEventErrorsApp = Get-EventLog -ComputerName $computerhostname -LogName Application -EntryType Error -Newest 5 | select timegenerated,source,message 
$computerEventErrorsSys = Get-EventLog -ComputerName $computerhostname -LogName System -EntryType Error -Newest 5 | select timegenerated,source,message 


################################# System Info 
"System Information for: " + $computerSystem.Name 
"Captured on " + $date 
"-------------------------------------" 
"Distinguished Name: " + $computerOu.DistinguishedName 
"Manufacturer: " + $computerSystem.Manufacturer 
"Model: " + $computerSystem.Model 
"Serial Number: " + $computerBIOS.SerialNumber 
"CPU: " + $computerCPU.Name 
"HDD Capacity: " + "{0:N2}" -f ($computerHDD.Size/1GB) + "GB" 
"HDD Space: " + "{0:P2}" -f ($computerHDD.FreeSpace/$computerHDD.Size) + " Free (" + "{0:N2}" -f ($computerHDD.FreeSpace/1GB) + "GB)" 
"RAM: " + "{0:N2}" -f ($computerSystem.TotalPhysicalMemory/1GB) + "GB" 
"Operating System: " + $computerOS.caption + ", Service Pack: " + $computerOS.ServicePackMajorVersion 
"User logged In: " + $computerSystem.UserName 
"Last Reboot: " + $computerOS.ConvertToDateTime($computerOS.LastBootUpTime) 


################################# Share Drives 
"" 
if ($Checkbox_MappedDrives.Checked -eq $true) { 
"-------------------------------------" 
"User's Mapped Network Drives" 
"-------------------------------------" 
foreach ($orca in $computerMappedDrives) { 
$orca.name + " " + $orca.providername 
} 
} 
################################# Printers 
if ($Checkbox_InstalledPrinters.checked -eq $True) #checkbox for Installed Printers 
{ 
"" 
"-------------------------------------" 
"Installed Printers:" 
"-------------------------------------" 
"Default Printer: " + $computerDefaultPrint.name 
"" 
foreach ($orca in $computerPrint) { 
" " + $orca.name 
} 
} 


################################# Errors 
if ($Checkbox_Errors.Checked -eq $true) { 
"" 
"-------------------------------------" 
"Application Event Errors:" 
"-------------------------------------" 
foreach ($orca in $computerEventErrorsApp) { 

"Date: " + $orca.timegenerated 
"Source: " + $orca.source 
"Message: " 
" " + $orca.message 
"" 
"" 
} 
"" 
"-------------------------------------" 
"System Event Errors:" 
"-------------------------------------" 
foreach ($orca in $computerEventErrorsSys) { 
"Date: " + $orca.timegenerated 
"Source: " + $orca.source 
"Message: " 
" " + $orca.message 
"" 
"" 
} 
} 
} 


## Clipboard Function 
function ClipClip { 

$outputBox.text | clip 

} 



################################### 
# GUI        # 
################################### 

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") #loading the necessary 


################################# Main Window 
$Form = New-Object System.Windows.Forms.Form #creating hte form (this will be the "Primary" window) 
$Form.Size = New-Object System.Drawing.Size(590,315) #the size in px of the window length, height 
$Form.Text = "Computer Info Tool v1.2" 
$Form.MaximizeBox = $False 

################################# INPUT; PC hostname/IP entry 
$InputBox = New-Object System.Windows.Forms.TextBox 
$InputBox.Location = New-Object System.Drawing.Size(5,250) 
$InputBox.Size = New-Object System.Drawing.Size(485,20) 
$Form.Controls.Add($InputBox) 

################################# Information Output Box 
$outputBox = New-Object System.Windows.Forms.TextBox #creating the text box 
$outputBox.Location = New-Object System.Drawing.Size(5,40) 
$outputBox.Size = New-Object System.Drawing.Size(565,200) 
$outputBox.MultiLine = $True 
$outputBox.AutoSize = $True 
$outputBox.ScrollBars = "Vertical" 

################################# COPY button 
$CopyButton = New-Object System.Windows.Forms.Button 
$CopyButton.Location = New-Object System.Drawing.Size (5,15) 
$CopyButton.Size = New-Object System.Drawing.Size (110,20) 
$CopyButton.Text = "Copy" 
$CopyButton.Add_Click({ClipClip}) 
$Form.Controls.Add($CopyButton) 

################################# Add'l Information Checkboxes 
$Checkbox_AutoCopy = New-Object System.Windows.Forms.CheckBox #create the radio button 
$Checkbox_AutoCopy.Location = new-object System.Drawing.Point(120,17) #location of the radio button(px) in relation to the group box's edges (length, height) 
$Checkbox_AutoCopy.size = New-Object System.Drawing.Size(110,20) #the size in px of the radio button (length, height) 
$Checkbox_AutoCopy.Checked = $false #is checked by default 
$Checkbox_AutoCopy.Text = "Auto-Copy" #labeling the radio button 
$Form.Controls.Add($Checkbox_AutoCopy) #activate the inside the group box 

################################# GO button 
$GoButton = New-Object System.Windows.Forms.Button 
$GoButton.Location = New-Object System.Drawing.Size (495,250) 
$GoButton.Size = New-Object System.Drawing.Size (60,20) 
$GoButton.Text = "Go" 
$GoButton.Add_Click({PingTest}) 
$Form.Controls.Add($GoButton) 
$Form.AcceptButton = $GoButton 

################################# Group Box 
$groupBox = New-Object System.Windows.Forms.GroupBox #create the group box 
$groupBox.Location = New-Object System.Drawing.Size(245,5) #location of the group box (px) in relation to the primary window's edges (length, height) 
$groupBox.size = New-Object System.Drawing.Size(325,35) #the size in px of the group box (length, height) 
$groupBox.text = "Additional Details" #labeling the box 
$Form.Controls.Add($groupBox) #activate the group box 

################################# Add'l Information Checkboxes 
$Checkbox_InstalledPrinters = New-Object System.Windows.Forms.CheckBox #create the radio button 
$Checkbox_InstalledPrinters.Location = new-object System.Drawing.Point(15,13) #location of the radio button(px) in relation to the group box's edges (length, height) 
$Checkbox_InstalledPrinters.size = New-Object System.Drawing.Size(110,20) #the size in px of the radio button (length, height) 
$Checkbox_InstalledPrinters.Checked = $false #is checked by default 
$Checkbox_InstalledPrinters.Text = "Installed Printers" #labeling the radio button 
$groupBox.Controls.Add($Checkbox_InstalledPrinters) #activate the inside the group box 

$Checkbox_MappedDrives = New-Object System.Windows.Forms.CheckBox #create the radio button 
$Checkbox_MappedDrives.Location = new-object System.Drawing.Point(125,13) #location of the radio button(px) in relation to the group box's edges (length, height) 
$Checkbox_MappedDrives.size = New-Object System.Drawing.Size(100,20) #the size in px of the radio button (length, height) 
$Checkbox_MappedDrives.Checked = $false #is checked by default 
$Checkbox_MappedDrives.Text = "Mapped Drives" #labeling the radio button 
$groupBox.Controls.Add($Checkbox_MappedDrives) #activate the inside the group box 

$Checkbox_Errors = New-Object System.Windows.Forms.CheckBox #create the radio button 
$Checkbox_Errors.Location = new-object System.Drawing.Point(225,13) #location of the radio button(px) in relation to the group box's edges (length, height) 
$Checkbox_Errors.size = New-Object System.Drawing.Size(87,20) #the size in px of the radio button (length, height) 
$Checkbox_Errors.Checked = $false #is checked by default 
$Checkbox_Errors.Text = "Event Errors" #labeling the radio button 
$groupBox.Controls.Add($Checkbox_Errors) #activate the inside the group box 

$Form.Controls.Add($outputBox) 
$Form.Add_Shown({$Form.Activate()}) 

[void] $Form.ShowDialog() 
+0

인프라 구조는 어떻습니까? 그 원격 컴퓨터에는 어떤 OS 버전이 있습니까? 원격 회의 또는 CIM 세션을 지원합니까? – mjolinor

+0

우리의 환경은 거의 100 % Windows 7이며, PSremoting은 win 8.1에서 거의 IT 워크 스테이션없이 활성화되지 않았습니다. 알래스카에서 플로리다에 이르는 약 4 천 대의 워크 스테이션을 지원합니다. – Jarom

답변

2

나의 제안은 원격 시스템을 한 번 일을하고 대신 WMI 정보를 위해 그것을 묻는 연결을 만드는 연결을 종료, 연결을 만드는, 모든 결과에 응답하는 것입니다, WMI 정보를 요청하고, 연결을 닫고, 반복하고, 반복하고, 반복합니다.

이렇게하려면 하나의 기능을 변경했습니다. -ComputerName 인수를 제외시키기 위해 모든 WMI 및 Eventlog 호출을 변환하고이를 사용자 지정 개체의 속성으로 변환했습니다. 그런 다음 ScriptBlock으로 모든 것을 싸서 $Command에 할당했습니다. 그런 다음 Invoke-Command를 사용하여 원격 컴퓨터에서 해당 명령을 실행하고 결과를 $Data에 할당합니다.

그런 다음 이전에 가지고 있던 다양한 변수에 대한 참조가 $data.oldvariablename으로 변경되었습니다.

function ComputerInfoScript { 
################################## Variables 
$date = Get-Date 
$Command = {[PSCustomObject]@{ 
    'computerSystem' = get-wmiobject Win32_ComputerSystem 
    'computerBIOS' = get-wmiobject Win32_BIOS 
    'computerOS' = get-wmiobject Win32_OperatingSystem 
    'computerCPU' = get-wmiobject Win32_Processor 
    'computerHDD' = Get-WmiObject Win32_LogicalDisk -Filter drivetype=3 
    'computerDefaultPrint' = get-wmiobject win32_printer | %{if ($_.default) {$_}} 
    'computerPrint' = Get-WmiObject Win32_Printer 
    'computerMonitors' = Get-WMIObject Win32_DesktopMonitor 
    'computerOpticalDrive' = Get-WmiObject Win32_CDROMDrive 
    'computerMappedDrives' = Get-WmiObject -Class Win32_MappedLogicalDisk | select name,providername 
    'computerEventErrorsApp' = Get-EventLog -LogName Application -EntryType Error -Newest 5 | select timegenerated,source,message 
    'computerEventErrorsSys' = Get-EventLog -LogName System -EntryType Error -Newest 5 | select timegenerated,source,message 
}} 
$Data = Invoke-Command -ComputerName $computerhostname -ScriptBlock $Command 

################################# System Info 
"System Information for: " + $Data.computerSystem.Name 
"Captured on " + $date 
"-------------------------------------" 
"Distinguished Name: " + $data.computerOu.DistinguishedName 
"Manufacturer: " + $data.computerSystem.Manufacturer 
"Model: " + $data.computerSystem.Model 
"Serial Number: " + $data.computerBIOS.SerialNumber 
"CPU: " + $data.computerCPU.Name 
"HDD Capacity: " + "{0:N2}" -f ($data.computerHDD.Size/1GB) + "GB" 
"HDD Space: " + "{0:P2}" -f ($computerHDD.FreeSpace/$computerHDD.Size) + " Free (" + "{0:N2}" -f ($data.computerHDD.FreeSpace/1GB) + "GB)" 
"RAM: " + "{0:N2}" -f ($data.computerSystem.TotalPhysicalMemory/1GB) + "GB" 
"Operating System: " + $data.computerOS.caption + ", Service Pack: " + $data.computerOS.ServicePackMajorVersion 
"User logged In: " + $data.computerSystem.UserName 
"Last Reboot: " + $data.computerOS.ConvertToDateTime($data.computerOS.LastBootUpTime) 


################################# Share Drives 
"" 
if ($Checkbox_MappedDrives.Checked -eq $true) { 
"-------------------------------------" 
"User's Mapped Network Drives" 
"-------------------------------------" 
foreach ($orca in $data.computerMappedDrives) { 
$orca.name + " " + $orca.providername 
} 
} 
################################# Printers 
if ($Checkbox_InstalledPrinters.checked -eq $True) #checkbox for Installed Printers 
{ 
"" 
"-------------------------------------" 
"Installed Printers:" 
"-------------------------------------" 
"Default Printer: " + $data.computerDefaultPrint.name 
"" 
foreach ($orca in $data.computerPrint) { 
" " + $orca.name 
} 
} 


################################# Errors 
if ($Checkbox_Errors.Checked -eq $true) { 
"" 
"-------------------------------------" 
"Application Event Errors:" 
"-------------------------------------" 
foreach ($orca in $data.computerEventErrorsApp) { 

"Date: " + $orca.timegenerated 
"Source: " + $orca.source 
"Message: " 
" " + $orca.message 
"" 
"" 
} 
"" 
"-------------------------------------" 
"System Event Errors:" 
"-------------------------------------" 
foreach ($orca in $data.computerEventErrorsSys) { 
"Date: " + $orca.timegenerated 
"Source: " + $orca.source 
"Message: " 
" " + $orca.message 
"" 
"" 
} 
} 
} 
+1

PowerShell Remoting이 필수 구성 요소로 구성되어야합니다. :) 나는 같은 대답을 게시하려하고 있었다. –

+0

답장을 보내 주셔서 감사합니다! 우리는 psremoting을 가능하게하려고합니다. – Jarom

1

결석 "팬 아웃"원격, 당신은 반복 WMI에 대한 동일한 세션이 오기를 반복하기보다는 쿼리하는 사용하여 먼저하고 지속적인 CIM 세션을 생성, 당신은 CIM을 사용하는 경우 꽤 그 속도를 할 수 있어야한다 -WMIObject 호출로 반복되는 세션 설정 및 호출 당 분리가 발생합니다.

+1

@Jarom 솔직히 말해서 이것에 대해 전혀 몰랐으며 내 솔루션보다 더 간단 할 수 있습니다. 내가 가서 봤 거든 좋은 정보를 원한다면 좋은 기사를 찾았 : http://blogs.msdn.com/b/powershell/archive/2012/08/24/introduction-to-cim-cmdlets.aspx – TheMadTechnician

+0

감사합니다 정보. PowerShell에서 CIM으로 약간의 연구를하고 놀았습니다. 지금까지 행운이 없다. 지속적 연결을 위해 New-CIMSession을 사용하는 것으로 추측하고 있지만 몇 대의 컴퓨터를 시험해 보았고 powershell이 ​​대상 컴퓨터의 WS-Management 서비스 로그를 확인하도록 요청하고 있습니다. '-credential'도 시도했다. 행운을 빈다 – Jarom

+1

해당 워크 스테이션에 WSMan이 구성되어 있지 않으면 DCOM 인증을 사용하여 해당 세션을 만들어야 할 수 있습니다. – mjolinor

0

두 아주 좋은, 지식 답변을하지만, 상당히 전체 작업 속도를 높일 것입니다 훨씬 더 간단한 해결책이있다 : 맨 마지막에 당신의 IT 워크 스테이션 중 하나

RDP하고 거기에서 스크립트를 실행은.

+0

필자는 분리 된 "원거리"가 있다고 생각하지 않습니다. 지리적으로 다양한 위치에 많은 끝점이 있습니다. – mjolinor

+0

@Jarom은 유타, 플로리다, 알래스카의 3 개 위치를 언급합니다. RDP를 각각의 컴퓨터에 연결하고 "로컬"워크 스테이션에 대해서만 스크립트를 실행하면 _이 프로세스로 인해 프로세스 속도가 빨라집니다. – Raf

+0

이것은 각 사이트에 상대적으로 "로컬"인 컴퓨터 목록과 함께 각 위치에 대해 별도의 스크립트를 유지하면서 잠재적으로 높은 유지 관리 제안 일 수 있습니다. – mjolinor