April 15th, 2015

Create Custom Type Data in PowerShell to Format WMI Display

Doctor Scripto
Scripter

Summary: Microsoft Scripting Guy, Ed Wilson, talks about creating custom type data to control the way a WMI class displays.

Hey, Scripting Guy! Question Hey, Scripting Guy! Yesterday, you said you could create custom type data to control the way the Win32_Volume WMI class reports back. How would one go about doing that? I looked on the Internet, and to be honest, it looks like it is basically impossible.

—AT

Hey, Scripting Guy! Answer Hello AT,

Microsoft Scripting Guy, Ed Wilson, is here. I love this time of the year. All the windows are open, the azaleas are in bloom, and I am upstairs with my Surface Pro 3, a cup of orange-cream green tea, and a slice of artisan cheese. I also scored some organic grapes, and they are so sweet that I needed to add nothing to my tea this morning.

AT, you are right. Yesterday in Comparing CIM and WMI in PowerShell, I began talking about comparing the results of Get-Volume with the Win32_Volume WMI class.

Obviously, if all of my systems are running Windows 8.1, there is no reason to mess around with using the WMI class. But if that is not the case, it makes sense to make things a bit easier to use.

Create custom type data

I want to be able to update the type data for the Win32_Volume WMI class. There is no custom type data, so I need to create something. Luckily, beginning with Windows PowerShell 3.0, this is super easy. I simply use the Update-TypeData cmdlet. The hard parts are figuring out the type name that I am going to use and figuring out how to accomplish the task.

From yesterday’s article, we know that the Win32_Volume WMI class does not have any custom type data. However, the Win32_Bios WMI class does. So I need to see how the Win32_Bios WMI class type data is named:

PS C:\> gcim Win32_BIOS | Get-TypeName

CimInstance#root/cimv2/Win32_BIOS

PS C:\> gwmi win32_bios | Get-TypeName

ManagementObject#root\cimv2\Win32_BIOS

But I want the full name, so I use a wildcard character to retrieve it. This is shown here:

PS C:\> "*win32_bios*" | Get-TypeData | select typename

TypeName

——–

System.Management.ManagementObject#root\cimv2\Win32_BIOS

Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_BIOS

It appears that all I need to do is change the name of the WMI class on the end of the string. I decide my new type data name will be the following:

Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Volume

This type data will control the way data returns from the Get-CimInstance cmdlet. I am not going to bother to create type data for the Get-WmiObject cmdlet, because this methodology requires Windows PowerShell 3.0 or later; therefore, the Get-CimInstance cmdlet would be available anyway.

As a test, I decide to create default properties. I use the Update-TypeData cmdlet, and I specify the type name and the default properties. I store the type name in a variable named $dataType. The second command is one long command. The command is shown here:

$dataType = "Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Volume"

Update-TypeData -TypeName $DataType `

 -DefaultDisplayPropertySet DriveLetter, DriveType, Label, FileSystem, FreeSpace, ` Capacity

As shown here, when I use Get-CimInstance to query Win32_Volume, only the selected properties return:

PS C:\> Get-CimInstance win32_volume

DriveLetter : C:

DriveType   : 3

Label       : SSD

FileSystem  : NTFS

FreeSpace   : 53269737472

Capacity    : 159486308352

DriveLetter : E:

DriveType   : 3

Label       : HybridTerrabyte

FileSystem  : NTFS

FreeSpace   : 392849973248

Capacity    : 1000068870144

DriveLetter :

DriveType   : 3

Label       : Recovery

FileSystem  : NTFS

FreeSpace   : 24080384

Capacity    : 314568704

If I attempt to update the type data, an error occurs. Here is the error message I receive:

PS C:\> E:\Data\ScriptingGuys\2015\HSG_4_13_15\CreateTypeDataForVolumeClass.ps1

Update-TypeData : Error in TypeData

"Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Volume": The member DefaultDisplayPropertySet is already present.

At E:\Data\ScriptingGuys\2015\HSG_4_13_15\CreateTypeDataForVolumeClass.ps1:11 char:1

+ Update-TypeData -TypeName $DataType `

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidOperation: (:) [Update-TypeData], RuntimeException

    + FullyQualifiedErrorId : TypesDynamicUpdateException,Microsoft.PowerShell.Commands.UpdateTypeDataCommand

I first need to remove the type data, and then I can update it. This command is shown here:

"Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Volume" |

Get-TypeData | Remove-TypeData

Add a script property

I see that the output from the drive type is coded. So, I look up the WMI class on MSDN, and add a script property to decode the numeric output. To do this, I use a simple Switch statement:

Switch ($this.psbase.CimInstanceProperties["DriveType"].value)

  {

   0 {"Unknown"}

   1 {"No Root"}

   2 {"Removable"}

   3 {"Local Disk"}

   4 {"Network Disk"}

   5 {"Compact Disk"}

   6 {"RAM Disk"}

  }

I keep my default property set, and I add a ScriptProperty named DriveType. The script block for the Switch statement and to translate the value goes in the –Value parameter. I use $this to gain access to the value from the WMI class property. The revised command is shown here:

$dataType = "Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Volume"

Update-TypeData -TypeName $DataType `

 -DefaultDisplayPropertySet DriveLetter, DriveType, Label, FileSystem, FreeSpace, Capacity `

 -MemberType ScriptProperty -MemberName DriveType -Value {

  Switch ($this.psbase.CimInstanceProperties["DriveType"].value)

  {

   0 {"Unknown"}

   1 {"No Root"}

   2 {"Removable"}

   3 {"Local Disk"}

   4 {"Network Disk"}

   5 {"Compact Disk"}

   6 {"RAM Disk"}

  }

 }

Now when I use Get-CimInstance to query the Win32_Volume WMI class, it comes back with nicely formatted output. This is shown in the following image:

Image of command output

But it gets better! Because the custom type system works on all instances of the data type, it even works on remote systems. So I update the type data on my local computer, and when I query a remote computer (that has not been updated), the data is properly formatted. It is way cool. This technique is shown here:

PS C:\> $dataType = "Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Volume"

PS C:\> Update-TypeData -TypeName $DataType `

>>  -DefaultDisplayPropertySet DriveLetter, DriveType, Label, FileSystem, FreeSpace, Capacity `

>>  -MemberType ScriptProperty -MemberName DriveType -Value {

>>   Switch ($this.psbase.CimInstanceProperties["DriveType"].value)

>>   {

>>    0 {"Unknown"}

>>    1 {"No Root"}

>>    2 {"Removable"}

>>    3 {"Local Disk"}

>>    4 {"Network Disk"}

>>    5 {"Compact Disk"}

>>    6 {"RAM Disk"}

>>   }

>>  }

>> 

PS C:\> gcim Win32_Volume

DriveLetter :

DriveType   : Local Disk

Label       : System Reserved

FileSystem  : NTFS

FreeSpace   : 331784192

Capacity    : 366997504

DriveLetter : C:

DriveType   : Local Disk

Label       :

FileSystem  : NTFS

FreeSpace   : 124714565632

Capacity    : 135996108800

DriveLetter : D:

DriveType   : Compact Disk

Label       :

FileSystem  :

FreeSpace   :

Capacity    :

PS C:\> gcim Win32_Volume -CimSession dc1

DriveLetter    : C:

DriveType      : Local Disk

Label          :

FileSystem     : NTFS

FreeSpace      : 125529444352

Capacity       : 135810510848

PSComputerName : dc1

DriveLetter    :

DriveType      : Local Disk

Label          : Recovery

FileSystem     : NTFS

FreeSpace      : 62734336

Capacity       : 314568704

PSComputerName : dc1

DriveLetter    : D:

DriveType      : Compact Disk

Label          :

FileSystem     :

FreeSpace      :

Capacity       :

PSComputerName : dc1

AT, that is all there is to using Windows PowerShell to create custom type data to control the display of a WMI class. CIM Week will continue tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.