I’ve been working on a System documentation script. Basically System Information = WMI 😉
WMI takes some getting use to. The data is there, getting to it can be a challenge. Depending on how the data is retrieved in could take some serious time, especially when queries are done remotely.
It’s better to select the properties you want in a query, than retrieving all the properties of a WMI class.
My objective was to have a simple script that is easy to maintain. I know the WMI Classes and Properties I want to query, rinse and repeat!!!
I also wanted to export the data to XML. Nothing fancy just the basics. My first attempt in the past was to use .NET XMLTextWriter. That was because at first I tried the export-clixml cmdlet… The horror… XMLTextWriter approach drawback is that I’m more busy with creating XML tags than the WMI Data. Found this link on TechNet, ConvertTo-XML will get you readable XML code. 🙂
I’ve created a function Get-WMIData that will return WMI data when the WMI Class and Properties are given as parameters… rinse and repeat!!!
function Get-WMIData { param( [string]$WMIClass, [string[]]$WMIProperties ) $queryProperties ='' foreach ($property in $WMIProperties){ $queryProperties += "$property," } #Remove last character from $queryProperties $queryProperties = $queryProperties -replace ".$" $results = Get-wmiObject -Query "SELECT $queryProperties FROM $WMIClass" return $results | Select-Object $WMIProperties }
The Select-Object $WMIProperties excludes those pesky system properties (__SystemProperty). That was a bonus using this approach! If anybody asks, it was by design… Hehe…
Next up: Define the WMI Class properties you want per WMI Class.
This is a collections of arrays you can expand on. The name of the array equals the WMI Class (I’ll show you why later on)
$Win32_ComputerSystem = @( 'DNSHostName' 'Model' 'Manufacturer' 'Domain' 'DomainRole' 'PartOfDomain' 'HypervisorPresent' 'SystemType' ) $Win32_OperatingSystem = @( 'Version' 'BuildNumber' 'BuildType' 'OSLanguage' 'OSType' 'OSArchitecture' 'MUILanguages' 'OperatingSystemSKU' 'Organization' 'ProductType' 'ServicePackMajorVersion' 'ServicePackMinorVersion' 'SizeStoredInPagingFiles' 'SystemDevice' 'SystemDirectory' 'WindowsDirectory' )
To enumerate the WMIClasses information I want, I have an array in place:
$WMIClasses = @( 'Win32_ComputerSystem' 'Win32_OperatingSystem' 'Win32_BIOS' 'Win32_Processor' 'Win32_DiskDrive' 'Win32_LogicalDisk' 'Win32_Volume' 'Win32_IP4RouteTable' 'Win32_NetworkAdapterConfiguration' )
This is the list I’ll go through to retrieve the WMI Classes data.
When calling the function Get-WMIData, I know the WMI Classes I want (See Array $WMIClasses). To get the property values from the corresponding WMIClass array I can do the following:
(Get-variable -name $WMIClass).Value
Now the foreach code is quite easy:
foreach($WMIClass in $WMIClasses) { #Get WMI version if($Export){ (Get-WMIData -WMIClass $WMIClass -WMIProperties (Get-variable -name $WMIClass).Value | convertto-xml -NoTypeInformation).save("$PSScriptRoot\$($env:COMPUTERNAME)\$($WMIClass).xml") } Else { "`n$WMIClass`n" Get-WMIData -WMIClass $WMIClass -WMIProperties (Get-variable -name $WMIClass).Value } }
I’ve added an export parameter switch to export to XML, otherwise the data is displayed in the console.
put it all together:
<# Author: ing. I.C.A. Strachan Version: 1.0.0 Version History: Purpose: Get WMI Information from System Syntax: Get-ComputerInformation.ps1 -APPS -WMI -Export This will export WMI & Application Data to a subfolder (Using the ComputerName as subfolder name) The subfolder data is zipped as well. #> [CmdletBinding()] Param( [switch]$WMI, [switch]$APPS, [switch]$Export ) if($Export) { if (!(Test-Path -Path "$PSScriptRoot\$env:ComputerName")) { New-Item "$PSScriptRoot\$env:ComputerName" -ItemType Directory > $null } } function Get-WMIData { param( [string]$WMIClass, [string[]]$WMIProperties ) $queryProperties ='' foreach ($property in $WMIProperties){ $queryProperties += "$property," } #Remove last character from $queryProperties $queryProperties = $queryProperties -replace ".$" $results = Get-wmiObject -Query "SELECT $queryProperties FROM $WMIClass" return $results | Select-Object $WMIProperties } #Function courtesy of Kris Powell #http://www.adminarsenal.com/admin-arsenal-blog/powershell-zip-up-files-using-.net-and-add-type function Compress-Folder { Param( [Parameter(Mandatory=$True)] [string]$DestinationFileName, [Parameter(Mandatory=$True)] [string]$SourceFolder, [Parameter(Mandatory=$False)] [ValidateSet('Optimal', 'Fastest', 'NoCompression')] [string]$CompressionLevel = 'Optimal', [Parameter(Mandatory=$False)] [switch]$IncludeParentDir ) Add-Type -AssemblyName System.IO.Compression.FileSystem $CompressionLevel = [System.IO.Compression.CompressionLevel]::$CompressionLevel [System.IO.Compression.ZipFile]::CreateFromDirectory($SourceFolder, $DestinationFileName, $CompressionLevel, $IncludeParentDir) } #region: HashTables with WMI Properties to query $Win32_NetworkAdapterConfiguration = @( 'IPEnabled' 'DHCPEnabled' 'IPAddress' 'DefaultIPGateway' 'DNSDomain' 'ServiceName' 'Description' 'Index' ) $Win32_ComputerSystem = @( 'DNSHostName' 'Model' 'Manufacturer' 'Domain' 'DomainRole' 'PartOfDomain' 'HypervisorPresent' 'SystemType' ) $Win32_OperatingSystem = @( 'Version' 'BuildNumber' 'BuildType' 'OSLanguage' 'OSType' 'OSArchitecture' 'MUILanguages' 'OperatingSystemSKU' 'Organization' 'ProductType' 'ServicePackMajorVersion' 'ServicePackMinorVersion' 'SizeStoredInPagingFiles' 'SystemDevice' 'SystemDirectory' 'WindowsDirectory' ) $Win32_BIOS = @( 'SMBIOSBIOSVersion' 'Manufacturer' 'Name' 'SerialNumber' 'Version' 'ReleaseDate' ) $Win32_Processor = @( 'Caption' 'Manufacturer' 'Name' 'DeviceID' 'MaxClockSpeed' 'SocketDesignation' ) $Win32_DiskDrive = @( 'Partitions' 'Model' 'Name' 'DeviceID' 'Size' 'Caption' 'MediaType' 'FirmwareRevision' 'SerialNumber' 'Signature' 'SCSIBus' 'SCSILogicalUnit' 'SCSIPort' 'SCSITargetId' ) $Win32_LogicalDisk = @( 'DriveType' 'FreeSpace' 'VolumeName' 'DeviceID' 'Size' ) $Win32_Volume = @( 'Name' 'Driveletter' 'DriveType' 'DeviceID' 'AutoMount' 'Capacity' 'FreeSpace' 'SystemVolume' 'Label' ) $Win32_IP4RouteTable = @( 'Name' 'Description' 'InterfaceIndex' 'Protocol' ) $WMIClasses = @( 'Win32_ComputerSystem' 'Win32_OperatingSystem' 'Win32_BIOS' 'Win32_Processor' 'Win32_DiskDrive' 'Win32_LogicalDisk' 'Win32_Volume' 'Win32_IP4RouteTable' 'Win32_NetworkAdapterConfiguration' ) #endregion #region: Main if($WMI) { foreach($WMIClass in $WMIClasses) { if($Export){ (Get-WMIData -WMIClass $WMIClass -WMIProperties (Get-variable -name $WMIClass).Value | convertto-xml -NoTypeInformation).save("$PSScriptRoot\$($env:COMPUTERNAME)\$($WMIClass).xml") } Else { "`n$WMIClass`n" Get-WMIData -WMIClass $WMIClass -WMIProperties (Get-variable -name $WMIClass).Value } } } if($APPS) { $SoftwareInstalled = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Where-Object {$_.DisplayName -ne $null} if($Export){ ($SoftwareInstalled | convertto-xml -NoTypeInformation).save("$PSScriptRoot\$($env:COMPUTERNAME)\Applications.xml") } Else{ "`nSoftware Installed`n" Write-Output $SoftwareInstalled } } #endregion #region Compress Folder with XML Files If($Export) { $DateStamp = $(get-date -uformat '%d%m%Y') $ZipParameters = @{ SourceFolder = "$PSScriptRoot\$($env:COMPUTERNAME)" DestinationFile = "$PSScriptRoot\$($env:COMPUTERNAME)-$DateStamp.zip" CompressionLevel = 'Optimal' } #Remove current zip file if (test-path $ZipParameters.DestinationFile) { Remove-Item -Path $ZipParameters.DestinationFile > out-null } Compress-Folder @ZipParameters } #endregion
If there’s a property you’d like to add to a WMIClass just add it to the WMIClass array! Want to query a new WMIClass? Add a new array with the properties you want and then add the WMIClass to the WMIClasses array!
Having to data zipped could enable you to send it by email 😉 Having the data in XML form could by used to import into Databases, generate HTML Reports… you get the idea…
Hope it’s worth something to you!
Ttyl,
Urv