Get local WMI & Application data

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

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s