Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Adding System Path to CIMInstance Objects

Posted on June 13, 2013

The other night when I presented for the Mississippi PowerShell Users' Group, one of the members showed some PowerShell 3.0 code using the CIM cmdlets. At issue is how the CIM cmdlets handle the WMI system properties like __SERVER and __RELPATH. By default, those properties aren't displayed, but they are captured in the CimSystemProperties property.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

gcim-systemproperties

The problem is that the __PATH property is not captured when using Get-CIMInstance as you can see in the screen shot. This is apparently a known issue. Using Get-WMIObject still works.

PS C:\> get-wmiobject win32_service -filter "name='bits'" | Select -expand __PATH
\\SERENITY\root\cimv2:Win32_Service.Name="BITS"

Most of the time this probably isn't a big deal. But perhaps there are situations where you need the __PATH property. I saw some code the other night that constructed the __PATH property. I was intrigued and decided to figure this out for myself. The path needs the computer name, the namespace-class path, the name of the class, the class key and the value of that key. I have most of this already from the

PS C:\> $c.CimSystemProperties.ServerName
SERENITY
PS C:\> $c.CimSystemProperties.Namespace.Replace("/","\")
root\cimv2
PS C:\> $c.CimSystemProperties.ClassName
Win32_Service

I switched the direction of the slash in the namespace. The only part I'm missing is the key property. But I can find it by looking at the qualifiers for the class properties. Think of a qualifier as a tag to denotes a special use. What is really cool about the CIMInstance, is that class information is included. This means I can look at the class from the object itself.

PS C:\> $c.cimclass.CimClassProperties | select name,qualifiers

get-ciminstance-classproperties

All I need to do is find the property with a KEY qualifier.

PS C:\> $c.cimclass.CimClassProperties | where {$_.qualifiers.name -contains 'key'}

Name               : Name
Value              :
CimType            : String
Flags              : Property, Key, ReadOnly, NullValue
Qualifiers         : {read, key}
ReferenceClassName :

Now that I know the Name property is the key, I can finish building my path.

PS C:\> $Key = $c[0].CimClass.CimClassProperties |
>> where {$_.qualifiers.name -contains "key"} |
>> select -ExpandProperty Name
>>
PS C:\> $c | Select @{Name="__PATH";Expression={
>>   '\\{0}\{1}:{2}{3}' -f $_.CimSystemProperties.ServerName,
>>   $_.CimSystemProperties.Namespace.Replace("/","\"),
>>   $_.CimSystemProperties.ClassName,
>>   ".$($key)=""$($_.$key)"""
>>   }}
>>

__PATH
------
\\SERENITY\root\cimv2:Win32_Service.Name="BITS"

And this is the exact path I would get using Get-WMIObject.

PS C:\> Get-WmiObject win32_service -filter "name='bits'" | select __Path

__PATH
------
\\SERENITY\root\cimv2:Win32_Service.Name="BITS"

Of course, I don't want to have to do all that typing so I created a function to do the work for me.

#requires -version 3.0

Function Add-CIMPath {
<#
.Synopsis
Add the __PATH property to a CIMInstance object
.Description
The Get-CIMInstance cmdlet by default doesn't display the WMI system properties
like __SERVER. The properties are available in the CimSystemProperties property
except for __PATH. This function will construct the __PATH property and add it
to a CIMInstance object.
.Example
PS C:\> get-ciminstance win32_memorydevice | add-cimpath | select __Path

__PATH
------
\\SERVER01\root\cimv2:Win32_MemoryDevice.DeviceID="Memory Device 0"
\\SERVER01\root\cimv2:Win32_MemoryDevice.DeviceID="Memory Device 1"
.Example
PS C:\> get-ciminstance win32_bios -computer netbk8 | add-cimpath | format-list __Path,PSComputername

__PATH         : \\NETBK8\root\cimv2:Win32_BIOS.Name="Rev 1.0
                 ",SoftwareElementID="Rev 1.0
                 ",SoftwareElementState="3",TargetOperatingSystem="0",Version="LENOVO - 6040000"
PSComputerName : netbk8
.Inputs
CIMInstance
.Outputs
CIMInstance
.Link
Get-CIMInstance
#>

[cmdletbinding()]
Param (
[Parameter(Position=0,ValueFromPipeline=$True)]
[ValidateNotNullorEmpty()]
[ciminstance]$Inputobject
)

Begin {
    Write-Verbose -Message "Starting $($MyInvocation.Mycommand)"  
} #begin

Process {
#get the key class property
Write-Verbose "Processing $($Inputobject.CimClass.CimClassName)"

$Key = $Inputobject.CimClass.CimClassProperties | 
where {$_.qualifiers.name -contains "key"} | 
select -ExpandProperty Name

Write-Verbose "Creating __PATH Using key property $key"

$Inputobject | Add-Member -PassThru -MemberType NoteProperty -Name __PATH -Value ( 
 '\\{0}\{1}:{2}{3}' -f $_.CimSystemProperties.ServerName.ToUpper(),
  $_.CimSystemProperties.Namespace.Replace("/","\"),
  $_.CimSystemProperties.ClassName,
  $(
   if ($key -is [array]) {
     #create a string with the array of key names and values
     [string]$s = ".$($key[0])=""$($_.($key[0]))"""
     #add each additional key separated by comma
     for ($i=1;$i -lt $key.count;$i++) {
       $s+= ",$($key[$i])=""$($_.($key[$i]))"""
     }
     $s
   }
   elseif ($Key) {
    #just a single key
    ".$($key)=""$($_.$key)"""
   }
   else {
    #no key
    '=@'
   })
 ) #value
} #process

End {
    Write-Verbose -Message "Ending $($MyInvocation.Mycommand)"
} #end

} #end Add-CIMPath

The main part of the function is essentially what I just demonstrated. However, there are some special cases where there is no key property or there are multiple keys, so I had to add some logic to take that into account. I wrote the function assuming you would pipe a CIMInstance object to it and you want to add __PATH.

PS C:\> get-ciminstance win32_logicaldisk | Add-CIMPath | select __Path

__PATH
------
\\SERENITY\root\cimv2:Win32_LogicalDisk.DeviceID="C:"
\\SERENITY\root\cimv2:Win32_LogicalDisk.DeviceID="D:"
\\SERENITY\root\cimv2:Win32_LogicalDisk.DeviceID="E:"
\\SERENITY\root\cimv2:Win32_LogicalDisk.DeviceID="F:"
\\SERENITY\root\cimv2:Win32_LogicalDisk.DeviceID="G:"
\\SERENITY\root\cimv2:Win32_LogicalDisk.DeviceID="Z:"

And here is what the special cases look like.
ciminstance-addpath

I'll be the first to admit this is a bit of a brute force hack and I can't guarantee I've covered every oddball use case. So if you try this and come across a class that doesn't give the correct __PATH, I hope you'll let me know.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d