Jarom
Jarom

Reputation: 51

Powershell WMI script slowness

Friendly hello to everyone! I've been working on this script this week. It works the way it should, but when querying the PCs in our network which are physically a substantial distance away from me (e.g., from Utah to Florida/Alaska) it's taking a VERY long time.

Querying PC's located in the office takes only ~15 seconds. Querying PC's located ~3000 miles away is taking sometimes more than 5 minutes.

I expect quite a bit of latency, but I was wondering if anyone had any advice on getting that time down at all using this script.

Any guidance for a PowerShell newbie would be appreciated.

Thanks!

## 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()  

Upvotes: 0

Views: 920

Answers (3)

Raf
Raf

Reputation: 10107

Two very good, knowledgeable answers but there is a much simpler solution which will speed up the entire operation significantly:

RDP to one of your IT workstations at the far end and run the script from there.

Upvotes: 0

mjolinor
mjolinor

Reputation: 68273

Absent "fan out" remoting, you should be able to speed that up quite a bit if you use CIM, creating a persistent CIM session first and then using that same session for repeated WMI queries rather than repeated Get-WMIObject calls which will result in repeated session set-up and tear-down per call.

Upvotes: 1

TheMadTechnician
TheMadTechnician

Reputation: 36297

My suggestion would be to have the remote system do the work once, and then respond with all of the results, instead of creating a connection, asking it for WMI info, closing the connection, creating a connection, asking it for WMI info, closing the connection, repeat, repeat, repeat...

To do that I changed one function. I converted all of the WMI and Eventlog calls to exclude the -ComputerName argument, and converted them to be properties of a custom object. Then I wrapped that all up as a ScriptBlock, and assigned it to $Command. Then I use Invoke-Command to run that command on the remote machine, and assign the results to $Data.

Then any reference to any of the various variables that you had before are changed to $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
""
""
}
}
}

Upvotes: 2

Related Questions