Use of Wildcards in PowerShell Formating

MMS in San Diego was a great conference!  I met lots of customers that asked lots of great questions.  I was demonstrating PowerShell’s WMI support when a customer asked about controlling the output.  The problem was that PowerShell was showing all the WMI System properties as well as the Object properties and that this wasn’t what they wanted.  PowerShell makes WMI objects look like any other object so there is no “special” processing for WMI so the question is, can you do the equivalent of -EXCLUDE __*  (All WMI System Properties start with “__”).  Let me illustrate the problem:


PS> Get-WmiObject Win32_Processor



AddressWidth                : 32
Architecture                : 0
Availability                : 3
Caption                     : x86 Family 6 Model 13 Stepping 8
ConfigManagerErrorCode      :
ConfigManagerUserConfig     :
CpuStatus                   : 1
CreationClassName           : Win32_Processor
CurrentClockSpeed           : 786
CurrentVoltage              : 33
DataWidth                   : 32
Description                 : x86 Family 6 Model 13 Stepping 8
DeviceID                    : CPU0
ErrorCleared                :
ErrorDescription            :
ExtClock                    : 133
Family                      : 2
InstallDate                 :
L2CacheSize                 : 2048
L2CacheSpeed                :
LastErrorCode               :
Level                       : 6
LoadPercentage              : 0
Manufacturer                : GenuineIntel
MaxClockSpeed               : 2127
Name                        :         Intel(R) Pentium(R) M processor 2.13GHz
OtherFamilyDescription      :
PNPDeviceID                 :
PowerManagementCapabilities :
PowerManagementSupported    : False
ProcessorId                 : AFE9FBFF000006D8
ProcessorType               : 3
Revision                    : 3336
Role                        : CPU
SocketDesignation           : Microprocessor
Status                      : OK
StatusInfo                  : 3
Stepping                    : 8
SystemCreationClassName     : Win32_ComputerSystem
SystemName                  : JPSLAP04
UniqueId                    :
UpgradeMethod               : 6
Version                     : Model 13, Stepping 8
VoltageCaps                 : 2
__GENUS                     : 2
__CLASS                     : Win32_Processor
__SUPERCLASS                : CIM_Processor
__DYNASTY                   : CIM_ManagedSystemElement
__RELPATH                   : Win32_Processor.DeviceID=”CPU0″
__PROPERTY_COUNT            : 44
__DERIVATION                : {CIM_Processor, CIM_LogicalDevice, CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER                    : JPSLAP04
__NAMESPACE                 : root\cimv2
__PATH                      :
\\JPSLAP04\root\cimv2:Win32_Processor.DeviceID=”CPU0


The last 10 properties are all system properties.  In this example, it is annoying but not horrible to include the system properties but now consider this example:



PS> Get-WmiObject Win32_Processor -property Name



Name             :         Intel(R) Pentium(R) M processor 2.13GHz
__GENUS          : 2
__CLASS          : Win32_Processor
__SUPERCLASS     :
__DYNASTY        :
__RELPATH        :
__PROPERTY_COUNT : 1
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :


The system properties are always included, even if you just get a single property.  So the ability to say


Get-WmiObject Win32_Processor -property Name |fl -Exclude __*


would be great.  We LOVE -Exclude (applied LOTS of places) and the ony reason it isn’t more places in V1 is simply a “to ship is to choose” issue.  Soooo, it was with great sadness that I had to give this customer the world’s worse answer:  We plan to provide this in the next release, hang in there for a few years and things will get better.


I want to pull my hair out every time I have to say that.  One of the whole points of PowerShell was to avoid ever having this conversation.  The idea was that feature team would expose their mgmt via PowerShell and then delivers their “scenarios” on top of that (like Exchange 2007 has done).  Then when a customer says that the scenario doesn’t meet their needs, the feature team can say, “Great – we’ll fix that in our next release but in the meantime, you can get that using the following script”.  NIRVANA. 


So when I had to say this myself – it really hurt.  We’ve put quite a bit of energy into designing PowerShell to be dynamically extensible (e.g. our extensible type system and formatting system) but there will always be things that require changes to the engine.  


Back to the question – my full answer was that -Exclude would come in a future release but that the right way to do this was to define a custom formatting VIEW for this object.  We extend WMI objects in a way that allow you to register Views for them.



PS> @(get-wmiobject -class “Win32_Share”)[0].PSTypeNames
System.Management.ManagementObject#root\cimv2\Win32_Share
System.Management.ManagementObject
System.Management.ManagementBaseObject
System.ComponentModel.Component
System.MarshalByRefObject
System.Object


This is the data that is used for all of PowerShell’s type extensions and formatting decisions.  Notice the first entry.  In .NET, a single class (System.Management.ManagementObject) represents all WMI instances so it would be impossible to register meaningful extensions if we just had that.  This is why we add an entry extending the .NET hierarchy with a synthetic entry which uses the WMI ClassPath.  Now you can define a view like this:


<Configuration>
  <ViewDefinitions>
    <View>
      <Name>CustomView</Name>
      <ViewSelectedBy>
        <TypeName>System.Management.ManagementObject</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <TableHeaders>
          <TableColumnHeader>
            <Label>Name</Label>
            <Width>12</Width>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Description</Label>
            <Width>30</Width>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Path</Label>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Name</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Description</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Path</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>


Put this in a file like Win32_Share.Format.PS1xml and execute the command  Update-FormatData Win32_Share.Format.PS1xml and the then you can do this:


PS> Get-WmiObject -Class Win32_Share


Name         Description                    Path               
—-         ———–                    —-               
E$           Default share                  E:\                
IPC$         Remote IPC                                        
CCMSetup$    Microsoft IT SMS Troublesho… C:\WINDOWS\system…
VPCache$     Microsoft IT SMS Troublesho… C:\WINDOWS\system…
ps                                          C:\ps              
WMILogs$     Microsoft IT SMS Troublesho… C:\WINDOWS\system…
CCMLogs$     Microsoft IT SMS Troublesho… C:\WINDOWS\system…
ADMIN$       Remote Admin                   C:\WINDOWS         
C$           Default share                  C:\                


So we’ve got a reasonable answer but I still wanted to give the customer a way to get what he wanted.  On the flight back home, it hit me – you can use wildcards in formatting to solve this problem.  When you pipe objects to our formatters you can specify which properties you want to show.  e.g.


get-process |FT ID,Handles


Here I’ve specified that I want to properties whose Names are ID and Handles to be output.  But here is the BIG deal:  you are NOT limited to specifying property NAMES you can specify any or all of the following things:


PropertySets:  PropertySets are named sets of properties that you can define as part of our extended type system.  We’ve define a few for you.  Here is an example of that working:


PS> gps |gm -membertype PropertySet

   TypeName: System.Diagnostics.Process
Name            MemberType  Definition
—-            ———-  ———-
PSConfiguration PropertySet PSConfiguration {Name, Id, PriorityCla…
PSResources     PropertySet PSResources {Name, Id, Handlecount, Wo…

PS> gps |ft PSConfiguration
Name                             Id    PriorityClass FileVersion
—-                             —    ————- ———–
AcroRd32                       1360           Normal 7.0.5.2005092300
alg                            2356           Normal 5.1.2600.2180…
apdproxy                       1964           Normal 3.0.0.49815
ApntEx                         3996           Normal 5.5.1.19


Expressions – you can specify a scriptblock and the system will assign the current object to the variable $_ ,execute the scriptblock and use the result:


PS> gps i* |ft name,{$_.StartTime.dayofweek}


Name                               $_.StartTime.dayofweek
—-                               ———————-
Idle
iexplore                           Saturday
iexplore                           Saturday
iexplore                           Saturday
InoRpc                             Thursday
InoRT                              Thursday
InoTask                            Thursday


HashTables – you can specify a hashtable with the following Keys:  Label, Expression, Alignment, Width.  The formatter will use these to drive its processing:


PS> gps i* |ft name,@{Label=”WeekDay”;Expression={$_.StartTime.DayOfWeek};Width=60}


Name     WeekDay
—-     ——-
Idle
iexplore Saturday
iexplore Saturday
iexplore Saturday
InoRpc   Thursday
InoRT    Thursday
InoTask  Thursday


WildCards – you can specify a set of propertynames using wildcards!


PS> gps i* |ft name,pe*64
Name              PeakPagedMemorySi PeakWorkingSet64 PeakVirtualMemor
                               ze64                           ySize64
—-              —————– —————- —————-
Idle                              0                0                0
iexplore                  114106368        117862400        270757888
iexplore                  118153216        131960832        278261760
iexplore                  119189504        131948544        273432576
InoRpc                      5140480          8220672         75395072
InoRT                      17981440         20332544         76890112
InoTask                    11993088         15597568         72310784


you can specify a set of propertynames using wildcards! So now the question is, how do wildcards help with the WMI issue?  By specifying properties [a-z]* , you’ll get all properties which start with an A-Z but none of those that start with __ .


PS> Get-WmiObject Win32_Processor |fl [a-z]*



AddressWidth                : 32
Architecture                : 0
Availability                : 3
Caption                     : x86 Family 6 Model 13 Stepping 8
ConfigManagerErrorCode      :
ConfigManagerUserConfig     :
CpuStatus                   : 1
CreationClassName           : Win32_Processor
CurrentClockSpeed           : 786
CurrentVoltage              : 33
DataWidth                   : 32
Description                 : x86 Family 6 Model 13 Stepping 8
DeviceID                    : CPU0
ErrorCleared                :
ErrorDescription            :
ExtClock                    : 133
Family                      : 2
InstallDate                 :
L2CacheSize                 : 2048
L2CacheSpeed                :
LastErrorCode               :
Level                       : 6
LoadPercentage              : 0
Manufacturer                : GenuineIntel
MaxClockSpeed               : 2127
Name                        :         Intel(R) Pentium(R) M processor
                               2.13GHz
OtherFamilyDescription      :
PNPDeviceID                 :
PowerManagementCapabilities :
PowerManagementSupported    : False
ProcessorId                 : AFE9FBFF000006D8
ProcessorType               : 3
Revision                    : 3336
Role                        : CPU
SocketDesignation           : Microprocessor
Status                      : OK
StatusInfo                  : 3
Stepping                    : 8
SystemCreationClassName     : Win32_ComputerSystem
SystemName                  : JPSLAP04
UniqueId                    :
UpgradeMethod               : 6
Version                     : Model 13, Stepping 8
VoltageCaps                 : 2


So there, you don’t have to hang in there a few years before we get around to implementing this.  We still need to implement it because there are times when this will be the best way to think about the problem but at least for this scenario, you are not blocked.


Our formatting and outputing system is quite powerful and it will really pay off to spend a some time exploring it’s capabilities.  I think you’ll be quite surprised and pleased by the things you can do.  It is not as rich as we want it (and we are very interested in hearing what additional features you want from it) but it is still a pretty amazing V1.


Enjoy!
Jeffrey Snover
PowerShell Architect


PSMDTAG:TYPE:WMI  formatting, synthetic types
PSMDTAG:CMDLET:FORMAT propertysets, expressions, hashtables, wildcards
PSMDTAG:INTERNAL Type->Synthetic Type->Formatting
PSMDTAG:FORMATEXTENSION:ManagementObject