In this mini-series, we are looking at the differences between Get-WmiObject and Get-CimInstance. Future PowerShell versions no longer support Get-WmiObject, so it is time to switch to Get-CimInstance if you haven’t already.
In the previous part you learned that both cmdlets return the same basic information for WMI classes, but the metadata properties added by both cmdlets differ considerably. Now let’s take a closer look at the basic information returned by them.
We refine the test script to also take into account the datatype, so we are not just looking at property names but also the type of data returned by these properties. For this, we are looking at the property “TypeNameOfValue”.
Since this is a string, type names are not always consistent. They can be displayed as “Bool” and “Boolean”, or “String” and “System.String”. To make results comparable, the code uses a calculated property in $typeName to omit the type namespace, and to apply manual adjustments in a switch statement. If you happen to find other type names that are displayed differently, simply extend the switch statement.
# we are comparing this WMI class (feel free to adjust) $wmiClass = 'Win32_OperatingSystem' # get information about the WMI class Win32_OperatingSystem with both cmdlets $a = Get-WmiObject -Class $wmiClass | Select-Object -First 1 $b = Get-CimInstance -ClassName $wmiClass | Select-Object -First 1 # create a calculated property that returns only the basic type name # and omits the namespace $typeName = @{ Name = 'Type' Expression = { $type = $_.TypeNameOfValue.Split('.')[-1].ToLower() switch ($type) { 'boolean' { 'bool' } default { $type } } } } # ignore the metadata properties which we already know are different $meta = '__CLASS','__DERIVATION','__DYNASTY','__GENUS','__NAMESPACE','__PATH','__PROPERTY_COUNT','__RELPATH','__SERVER','__SUPERCLASS','CimClass','CimInstanceProperties','CimSystemProperties','ClassPath','Container','Options','Properties','Qualifiers','Scope','Site','SystemProperties' # return the properties and their data type. Add the origin so we later know # which cmdlet emitted them $aDetail = $a.PSObject.Properties | # exclude the metadata we already know is different Where-Object { $_.Name -notin $meta } | # add the origin command as new property "Origin" Select-Object -Property Name, $typeName, @{N='Origin'={'Get-WmiObject'}} $bDetail = $b.PSObject.Properties | # exclude the metadata we already know is different Where-Object { $_.Name -notin $meta } | # add the origin command as new property "Origin" Select-Object -Property Name, $typeName, @{N='Origin'={'Get-CimInstance'}} # compare differences Compare-Object -ReferenceObject $aDetail -DifferenceObject $bDetail -Property Name, Type -PassThru | Select-Object -Property Name, Origin, Type | Sort-Object -Property Name
Here is the result:
Name Origin Type ---- ------ ---- InstallDate Get-CimInstance ciminstance#datetime InstallDate Get-WmiObject string LastBootUpTime Get-CimInstance ciminstance#datetime LastBootUpTime Get-WmiObject string LocalDateTime Get-CimInstance ciminstance#datetime LocalDateTime Get-WmiObject string Path Get-WmiObject managementpath
- Get-CimInstance returns date and time as DateTime objects whereas Get-WmiObject returns them as string, using its internal WMI format for it
- Get-WmiObject adds another metadata property called “Path”
Get-CimInstance makes dealing with dates and times much easier than Get-WmiObject:
PS> $a.InstallDate 20190903124241.000000+120 PS> $b.InstallDate Tuesday, September 3, 2019 12:42:41
With the code above, you now have an easy-to-use tool to test the WMI classes your scripts use, and identify properties that may return different data types when you move from Get-WmiObject to Get-CimInstance.