Get-wmiobject wrapper

From Svendsen Tech Powershell Wiki

Jump to: navigation, search

Contents




General Information

Get-WmiObject-Wrapper.ps1, available for download below, is a "wrapper" around Get-WmiObject. It is designed to retrieve and collect data from a list of computers, and I built in support for a WMI timeout parameter, which is missing from Get-WmiObject. However, during testing it appears that the timeout is not in effect on certain computers that "get stuck", which is really the problem I set out to solve with the timeout parameter. See the aforementioned article for further details.

I decided to store the retrieved data using XML since PowerShell v2 has decent support for it.

It took a lot of experimentation to get this right and I had to make a few compromises in the code to get it working. You can look at the source code by clicking the text file download links in the downloads section below.


How It Works

You specify a list of computers (use "(gc computers.txt)" to use computer names from a file) and the WMI class or classes and the property or properties you want to retrieve from each class, from these computers. This will be stored in an XML structure that supports this type of data. I demonstrate how to parse the XML with a ready-made script in the examples below.

You specify WMI classes and the properties you want from each class with a special string in this format:

"wmi_class1:prop1,prop2|wmi_class2:prop1|wmi_class3:prop1,prop2,prop3"

Rules:

  • First you specify the class, followed by a colon, then a property or properties separated by commas.
  • Multiple class/property groups are separated by pipes.

In the example below, the string in this format that I use is "win32_operatingsystem:version|win32_computersystem:totalphysicalmemory,model"

The resulting XML looks like this, and you can now use the report generator to extract data and produce CSV reports:

Image:Get-WmiObject-Wrapper-example-run.png

Parameters

  • -ComputerName: Required. Array of strings with computer names. Use "(gc .\computers.txt)" to use a file.
  • -OutputFile: Required. Output file. You will be prompted to overwrite it unless you specify -Clobber. The XML save method requires a full path, so I do some tests to see if a full path was specified and if it looks like a relative path, you will be asked if you want to use the current working directory.
  • -MultiClassProperty: Required. You specify WMI classes and the properties you want from each class with a special string in this format: "wmi_class1:prop1,prop2|wmi_class2:prop1|wmi_class3:prop1,prop2,prop3".
  • -Timeout: Optional. A time span object. The default is "0:0:10", which is 10 seconds.
  • -NoPingTest: Optional. Specify this if you do NOT want to skip computers that do not respond to ICMP echo (ping).
  • -Clobber: Optional. Overwrite the specified output file without prompting if it already exists.
  • -Scope: Optional. The WMI management scope. Usually not necessary. By default "\\${Computer}\root\cimv2" will be used, while this lets you replace the part "root\cimv2" with what you specify instead.


Access The Data In The XML From The Command Line

I figure if anyone's going to use this, you need a convenient way of retrieving data from the XML. Of course, you could write your own parser and extract what you need, but that might be quite a bit of work, especially if you haven't done it before and need to learn how. So I wrote a simple, but, I dare say, highly flexible, report generator for you.

With Gwmi-Wrapper-Report.ps1 you can dump the entire XML to "CSV strings" (the default delimiter is " | ") in the format "computer name | class name | property name | property value". This is useful for visual inspection or making reports in some desired format.

Let me repeat this clearly: You can produce CSV reports from the XML data easily. Just use the -Headers and -CsvDelimiter parameters and redirect to a file with Out-File (if the output lines don't exceed the console window width), Add-Content or Set-Content. To process data properly with Import-Csv you need a single-character delimiter. If there are no commas in the data - you can use -CsvDelimiter ',' - and have the default behaviour with Import-Csv. Also see the example about exporting to CSV. It's easy!

You might want to read more about text processing with regular expressions here.

Gwmi-Wrapper-Report Parameters

The parameters are:

  • -XmlFile: Required. The XML file to parse.
  • -ComputerName: Optional. Default "all". Specify computer or computers to filter on. Only computer names matching those you specify here will be displayed.
  • -Class: Optional. Default "all". Specify WMI class or classes to filter on. Only classes matching those names you specify here will be displayed.
  • -Property: Optional. Default "all". Specify property or properties to filter on. Only properties matching those names you specify here will be displayed.
  • -CsvDelimiter: Optional. Specify a custom CSV delimiter string. Use a single-char value, such as "," or ";" if you redirect to a file and later want to use Import-Csv on it.
  • -Headers: Optional. Print the headers "Computer, Class, Property, Value". For use when using -CsvDelimiter and redirecting to a CSV file for later use with Import-Csv.

Example Use

These reports are based on the XML from the above screenshot (notice the command).

Dumping All Data

To dump everything, you can use the command:

> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml

And in my case I get this output:

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml
2008r2esxi | win32_computersystem | model | VMware Virtual Platform
2008r2esxi | win32_computersystem | totalphysicalmemory | 2147016704
2008r2esxi | win32_operatingsystem | version | 6.1.7601
server2008 | win32_computersystem | model | VMware Virtual Platform
server2008 | win32_computersystem | totalphysicalmemory | 2146136064
server2008 | win32_operatingsystem | version | 6.0.6002
silverstone | win32_computersystem | Error | Exception calling "Get" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
silverstone | win32_operatingsystem | Error | Exception calling "Get" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
ubuntu64esxi | win32_computersystem | Error | Exception calling "Get" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
ubuntu64esxi | win32_operatingsystem | Error | Exception calling "Get" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
win7esxi | win32_computersystem | model | VMware Virtual Platform
win7esxi | win32_computersystem | totalphysicalmemory | 2147016704
win7esxi | win32_operatingsystem | version | 6.1.7601
winxpesxi | win32_computersystem | model | VMware Virtual Platform
winxpesxi | win32_computersystem | totalphysicalmemory | 536330240
winxpesxi | win32_operatingsystem | version | 5.1.2600

You can of course process this with Select-String, but I built in some filtering options which I will now demonstrate.

Dumping Data With A Different CSV Delimiter

Use the -Headers and -CsvDelimiter parameters if you want to redirect to a file.

# Dump all hardware models.
PS C:\PS> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Property model -CsvDelimiter ','
2008r2esxi,win32_computersystem,model,VMware Virtual Platform
server2008,win32_computersystem,model,VMware Virtual Platform
win7esxi,win32_computersystem,model,VMware Virtual Platform
winxpesxi,win32_computersystem,model,VMware Virtual Platform

# Redirect to a file. Don't forget "-Headers"!
PS C:\PS> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Property model -CsvDelimiter ',' -Headers | Set-Content model.csv

# Process it with Import-Csv.
PS C:\PS> Import-Csv .\model.csv | ft -auto

Computer   Class                Property Value
--------   -----                -------- -----
2008r2esxi win32_computersystem model    VMware Virtual Platform
server2008 win32_computersystem model    VMware Virtual Platform
win7esxi   win32_computersystem model    VMware Virtual Platform
winxpesxi  win32_computersystem model    VMware Virtual Platform

Filtering On A Computer Name

Let's filter on the computer name "server2008":

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -ComputerName server2008
server2008 | win32_computersystem | model | VMware Virtual Platform
server2008 | win32_computersystem | totalphysicalmemory | 2146136064
server2008 | win32_operatingsystem | version | 6.0.6002

Filtering On A Property

Why not retrieve only the model for all computers:

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Property model
2008r2esxi | win32_computersystem | model | VMware Virtual Platform
server2008 | win32_computersystem | model | VMware Virtual Platform
win7esxi | win32_computersystem | model | VMware Virtual Platform
winxpesxi | win32_computersystem | model | VMware Virtual Platform

A side-effect here is that the computers with errors and no ping reply are filtered out, because the properties are named "Error" and "NoPing". There's only one Error or NoPing entry per class. To list errors, use:

> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Property error

To list computers that did not respond to ping, use:

> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Property NoPing


Filtering On A Class

Or just get the Win32_Operatingsystem class stuff (in this case the property "version"):

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Class Win32_OperatingSystem
2008r2esxi | win32_operatingsystem | version | 6.1.7601
server2008 | win32_operatingsystem | version | 6.0.6002
silverstone | win32_operatingsystem | Error | Exception calling "Get" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
ubuntu64esxi | win32_operatingsystem | Error | Exception calling "Get" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
win7esxi | win32_operatingsystem | version | 6.1.7601
winxpesxi | win32_operatingsystem | version | 5.1.2600

Notice how you get the errors as well. We can pull out the trick from example three with -Property version. In which case the class specification is useless since the property name doesn't exist in any other class, but that's specific to the example data.

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Class Win32_OperatingSystem -Property version
2008r2esxi | win32_operatingsystem | version | 6.1.7601
server2008 | win32_operatingsystem | version | 6.0.6002
win7esxi | win32_operatingsystem | version | 6.1.7601
winxpesxi | win32_operatingsystem | version | 5.1.2600

You could also have used Select-String like this (you need to escape the pipes which have a special meaning in regular expressions):

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml
-Class Win32_OperatingSystem | Select-String -NotMatch '\| Error \|'

2008r2esxi | win32_operatingsystem | version | 6.1.7601
server2008 | win32_operatingsystem | version | 6.0.6002
win7esxi | win32_operatingsystem | version | 6.1.7601
winxpesxi | win32_operatingsystem | version | 5.1.2600

Technically, if you wanted to be painfully precise, you would have to use a regular expression like "^(?:[^|]+(?: \| )?){2}Error \|" or maybe "^(?:[^|]+\|){2} Error \|".

Combined Filtering

You can also specify multiple parameters and they'll filter accordingly (they will basically be inclusively combined):

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml
-Class win32_computersystem,win32_operatingsystem
-Property model,version -ComputerName server2008,winxpesxi

server2008 | win32_computersystem | model | VMware Virtual Platform
server2008 | win32_operatingsystem | version | 6.0.6002
winxpesxi | win32_computersystem | model | VMware Virtual Platform
winxpesxi | win32_operatingsystem | version | 5.1.2600

Practical Example

To generate a simple report of memory in MB for all computers, you can use something like this one-liner:

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Property TotalPhysicalMemory |
%{ $Computer, $Mem = ($_ -split ' \| ')[0,3]; $Computer + ': ' + ($Mem/1MB).ToString('N') }
2008r2esxi: 2,047.55
server2008: 2,046.71
win7esxi: 2,047.55
winxpesxi: 511.48

Another Practical Example

For some reason you might want to find out how much memory computers running Windows 7 or Windows 2008 R2 have. This can be done in a two-step process with Gwmi-Wrapper-Report. First get the computers that have Windows 6.1:

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml
-Property version -Class Win32_OperatingSystem |
Where { ($_ -split ' \| ')[3] -match '^6\.1\.' }

2008r2esxi | win32_operatingsystem | version | 6.1.7601
win7esxi | win32_operatingsystem | version | 6.1.7601

Then get only the computer names and save them to a file:

# Verify output
PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Property version
-Class Win32_OperatingSystem |
Where { ($_ -split ' \| ')[3] -match '^6\.1\.' } | %{ ($_ -split ' \| ')[0]  }

2008r2esxi
win7esxi

# Then save the computer names to a file (win61.txt)

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml
-Property version -Class Win32_OperatingSystem |
Where { ($_ -split ' \| ')[3] -match '^6\.1\.' } |
%{ ($_ -split ' \| ')[0]  } | Out-File win61.txt

Then you can feed this file to the -ComputerName parameter and otherwise use the same command as in example six:

PS C:\prog\Powershell> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml
-Property TotalPhysicalMemory -ComputerName (gc .\win61.txt) |
%{ $Computer, $Mem = ($_ -split ' \| ')[0,3]; $Computer + ': ' + ($Mem/1MB).ToString('N') }

2008r2esxi: 2,047.55
win7esxi: 2,047.55

Exporting to a CSV File

Now this is useful. Let's demonstrate how to export to a CSV file. I use the -Headers parameter for adding default headers so I don't have to make some up and add them with the -Header parameter for the Import-Csv cmdlet afterwards. I also set a single-char CSV delimiter with -CsvDelimiter ';'. This is then redirected to a file with " > report.csv". If there are no commas in the data, you can of course use the default delimiter (a comma).

PS C:\> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml
-Headers -ComputerName server2008 -CsvDelimiter ';' > report.csv
PS C:\> Import-Csv .\report.csv -Delimiter ';'

Computer                      Class                         Property                      Value
--------                      -----                         --------                      -----
server2008                    win32_bios                    manufacturer                  Phoenix Technologies LTD
server2008                    win32_computersystem          model                         VMware Virtual Platform
server2008                    win32_computersystem          totalphysicalmemory           2146136064
server2008                    win32_operatingsystem         version                       6.0.6002

To make a CSV report with just the models for all computers, you can use something like this:

PS C:\> .\Gwmi-Wrapper-Report.ps1 -XmlFile .\wmi.xml -Headers
-Property Model -CsvDelimiter ',' | Set-Content model.csv

PS C:\prog\Powershell> Import-Csv .\model.csv |
Select Computer, @{n='Hardware Model';e={$_.Value}} | # you can also just use "Select Computer,Value"...
Format-Table -AutoSize

Computer   Hardware Model
--------   --------------
2008r2esxi VMware Virtual Platform
server2008 VMware Virtual Platform
win7esxi   VMware Virtual Platform
winxpesxi  VMware Virtual Platform

Downloads

Personal tools