Setting Default Display Properties to your SMO Functions


if you type GET-PROCESS what will be the output ?

   1: Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName                                                       

   2: -------  ------    -----      ----- -----   ------     -- -----------                                                       

   3:      32       5     1004       2908    29     1.11   2620 conhost                                                           

   4:     734      13     2448       4176    51     6.88    416 csrss                                                             

   5:     660      14     3044       7376    63   123.70    480 csrss      

                                                    

As we can see the  properties displayed are Handles,NPM(K),PM(K),WS(K),VM(K),CPU(s),Id and ProcessName.

Ok..now type GET-PROCESS | SELECT * : (LIST1 – All properties from Get-Process)

   1:  

   2: __NounName                 : Process

   3: Name                       : WmiPrvSE

   4: Handles                    : 343

   5: VM                         : 200318976

   6: WS                         : 29708288

   7: PM                         : 18628608

   8: NPM                        : 22536

   9: Path                       : C:\Windows\system32\wbem\wmiprvse.exe

  10: Company                    : Microsoft Corporation

  11: CPU                        : 7694.421875

  12: FileVersion                : 6.1.7601.17514 (win7sp1_rtm.101119-1850)

  13: ProductVersion             : 6.1.7601.17514

  14: Description                : WMI Provider Host

  15: Product                    : Microsoft® Windows® Operating System

  16: Id                         : 3060

  17: PriorityClass              : Normal

  18: HandleCount                : 343

  19: WorkingSet                 : 29708288

  20: PagedMemorySize            : 18628608

  21: PrivateMemorySize          : 18628608

  22: VirtualMemorySize          : 200318976

  23: TotalProcessorTime         : 02:08:14.4218750

  24: BasePriority               : 8

  25: ExitCode                   : 

  26: HasExited                  : False

  27: ExitTime                   : 

  28: Handle                     : 3636

  29: MachineName                : .

  30: MainWindowHandle           : 0

  31: MainWindowTitle            : 

  32: MainModule                 : System.Diagnostics.ProcessModule (wmiprvse.exe)

  33: MaxWorkingSet              : 1413120

  34: MinWorkingSet              : 204800

  35: Modules                    : {System.Diagnostics.ProcessModule (wmiprvse.exe), System.Diagnostics.ProcessModule (ntdll.dll),

  36:                               System.Diagnostics.ProcessModule (kernel32.dll), System.Diagnostics.ProcessModule (KERNELBASE.

  37:                              dll)...}

  38: NonpagedSystemMemorySize   : 22536

  39: NonpagedSystemMemorySize64 : 22536

  40: PagedMemorySize64          : 18628608

  41: PagedSystemMemorySize      : 164304

  42: PagedSystemMemorySize64    : 164304

  43: PeakPagedMemorySize        : 101957632

  44: PeakPagedMemorySize64      : 101957632

  45: PeakWorkingSet             : 108654592

  46: PeakWorkingSet64           : 108654592

  47: PeakVirtualMemorySize      : -1339703296

  48: PeakVirtualMemorySize64    : 2955264000

  49: PriorityBoostEnabled       : True

  50: PrivateMemorySize64        : 18628608

  51: PrivilegedProcessorTime    : 00:53:47.2968750

  52: ProcessName                : WmiPrvSE

  53: ProcessorAffinity          : 3

  54: Responding                 : True

  55: SessionId                  : 0

  56: StartInfo                  : System.Diagnostics.ProcessStartInfo

  57: StartTime                  : 8/8/2012 8:42:06 PM

  58: SynchronizingObject        : 

  59: Threads                    : {2844, 2512, 2584, 680...}

  60: UserProcessorTime          : 01:14:27.1250000

  61: VirtualMemorySize64        : 200318976

  62: EnableRaisingEvents        : False

  63: StandardInput              : 

  64: StandardOutput             : 

  65: StandardError              : 

  66: WorkingSet64               : 29708288

  67: Site                       : 

  68: Container                  : 

WOHOOOO !!!!  Why if I type GET-PROCESS  the output is different from GET-PROCESS | Select * ?

Because the default properties set up in a Windows PowerShell Formatting File, or a file with extension FORMAT.PS1XML, that are stored , IN THE CASE OF GET-PROCESS, on the PowerShell install folder.

How it works ? Generally speaking, because there is a LOT of configuration that you can do in a  formatting file, PowerShell uses a LOT of formatting files to format the default display for a .NET Framework Objects. This means that you can choose what default  properties to display, how to display, where (position)to display and you can create formulas too, using a node in the XML called <scriptblock>. In the case of GET-PROCESS the property PM(K) , is first displayed with a label PM(K) – You  can see in the list above that does not exist any property called PM(K) -That  is a formula in the DotNetTypes.format.ps1xml:

<ScriptBlock>[int]($_.PM / 1024)</ScriptBlock>

Now if you take a look on the LIST1 above we have a property called PM 

__NounName : Process
Name : WmiPrvSE
Handles : 258
VM : 94494720
WS : 31690752
PM : 25993216
NPM : 18128
Path : C:\Windows\system32\wbem\wmiprvse.exe

and this property is part of the formula in the DotNetTypes.format.ps1xml

How do I know this ? The output type from GET-PROCESS is a System.Diagnostics.Process (GET-PROCESS | GM), and if you search on DotNetTypes.format.ps1xml for this type you will find out all the information:

<View>

       <Name>process</Name>

       <ViewSelectedBy>

           <TypeName>System.Diagnostics.Process</TypeName>

       </ViewSelectedBy>

       <TableControl>

           <TableHeaders>

               <TableColumnHeader>

                   <Label>Handles</Label>

                   <Width>7</Width>

                   <Alignment>right</Alignment>

               </TableColumnHeader>

               <TableColumnHeader>

                   <Label>NPM(K)</Label>

                   <Width>7</Width>

                   <Alignment>right</Alignment>

               </TableColumnHeader>

               <TableColumnHeader>

                   <Label>PM(K)</Label>

                   <Width>8</Width>

                   <Alignment>right</Alignment>

               </TableColumnHeader>

               <TableColumnHeader>

                   <Label>WS(K)</Label>

                   <Width>10</Width>

                   <Alignment>right</Alignment>

               </TableColumnHeader>

               <TableColumnHeader>

                   <Label>VM(M)</Label>

                   <Width>5</Width>

                   <Alignment>right</Alignment>

               </TableColumnHeader>

               <TableColumnHeader>

                   <Label>CPU(s)</Label>

                   <Width>8</Width>

                   <Alignment>right</Alignment>

               </TableColumnHeader>

               <TableColumnHeader>

                   <Width>6</Width>

                   <Alignment>right</Alignment>

               </TableColumnHeader>

               <TableColumnHeader />

           </TableHeaders>

           <TableRowEntries>

               <TableRowEntry>

                   <TableColumnItems>

                       <TableColumnItem>

                           <PropertyName>HandleCount</PropertyName>

                       </TableColumnItem>

                       <TableColumnItem>

                           <ScriptBlock>[int]($_.NPM / 1024)</ScriptBlock>

                       </TableColumnItem>

                       <TableColumnItem>

                           <ScriptBlock>[int]($_.PM / 1024)</ScriptBlock>

                       </TableColumnItem>

                       <TableColumnItem>

                           <ScriptBlock>[int]($_.WS / 1024)</ScriptBlock>

                       </TableColumnItem>

                       <TableColumnItem>

                           <ScriptBlock>[int]($_.VM / 1048576)</ScriptBlock>

                       </TableColumnItem>

                       <TableColumnItem>

                           <ScriptBlock>

_.CPU -ne $()) 

{ 

_.CPU.ToString("N") 

}

           </ScriptBlock>

                       </TableColumnItem>

                       <TableColumnItem>

                           <PropertyName>Id</PropertyName>

                       </TableColumnItem>

                       <TableColumnItem>

                           <PropertyName>ProcessName</PropertyName>

                       </TableColumnItem>

                   </TableColumnItems>

               </TableRowEntry>

           </TableRowEntries>

       </TableControl>

   </View>

   <View>

 

You can find a complete list of the Formatting Files in Windows PowerShell Formatting Files. In this guide it says :

Windows PowerShell provides several formatting files (.format.ps1xml) that are located in the installation directory ($pshome). Each of these files defines the default display for a specific set of .NET Framework objects. These files should never be changed. However, you can use them as a reference for creating your own custom formatting files.

 

Hummmmm..Ok..then..I can create formatting files to my functionsAlegre

I have a function called GET-SQLServerInfo. The code is pretty simple and it is to display all information about SQL Server using SMO :

 

Function Get-SqlServerInfo {

 

    [CmdletBinding()]

    

    

    param(

        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline = $true)] [string[]]$SQLServer

    )

    begin {

        [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") > $null 

    }

    process {

        foreach ($SQL in $SQLServer) {

            $server = new-object ('Microsoft.SqlServer.Management.Smo.Server') $SQL

            write-output $server

        }

    }

}

 

The problem it is exactly what I said. It display ALL information about an SQL Server Instance. Besides it is slowly, sometimes I just want some basic properties.

There is some ways to do this:

  1. I can create a PSCustomObject and output only what I want.
  2. I can pipe to Select-Object and show only what I want.

Problems :

Solution 1 – If I want the other properties….I do need to create other function (That would be out of the question.)

Solution 2 – I can do that. But Would not it be nice to have formatted the output with only a few basic properties and if I want to show the rest I just pipe to Select-Object * ?

Then, there is  a 3 solution. Create a Formatting File to that.  A formatting file is associated to the type of the object , not to an specific function, as we saw to GEt-PROCESS and the type System.Diagnostics.Process. If you type Get-FormatData you will see the object types and its formats :

 

image

 

How Can I Find the relationship between a formatting file and the object type ?  I found in this blog a cool function to do that. In this case he is using only to Get-EventLog and Get-WinEvent, but you can change to the function that you want  Alegre

Powershell Objects and .PS1XML Files

Now, Lets back to our example : My function GET-SQLServerInfo output a object type Microsoft.SqlServer.Management.Smo.Server,  then it is just to start to create the formatting file, in my case,Functions.Format.ps1xml.   to display by default the properties and its label and width :

 

Description Label Width Property
SQL Server Instance  Name Name 15 Name
SQL Server Edition Edition 30 Edition
SQL Server Product Level Product Level 15 ProductLevel
SQL Server Version Version 22 Scriptblock : $_.Version.ToString()
SQL Server Collation Collation 40 Collation

 

The  Functions.Format.ps1xml is :

<Configuration>
<ViewDefinitions>

<View>
<Name>Table</Name>
<ViewSelectedBy>
<TypeName>Microsoft.SqlServer.Management.Smo.Server</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>

<TableColumnHeader>
<Label>Name</Label>
<Width>15</Width>
<Alignment>left</Alignment>
</TableColumnHeader>

<TableColumnHeader>
<Label>Edition</Label>
<Width>30</Width>
<Alignment>left</Alignment>
</TableColumnHeader>

<TableColumnHeader>
<Label>Product Level</Label>
<Width>15</Width>
<Alignment>left</Alignment>
</TableColumnHeader>

<TableColumnHeader>
<Label>Version</Label>
<Width>22</Width>
<Alignment>left</Alignment>
</TableColumnHeader>

<TableColumnHeader>
<Label>Collation</Label>
<Width>40</Width>
<Alignment>left</Alignment>
</TableColumnHeader>

</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<Wrap/>
<TableColumnItems>

<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>

<TableColumnItem>
<PropertyName>Edition</PropertyName>
</TableColumnItem>

<TableColumnItem>
<PropertyName>ProductLevel</PropertyName>
</TableColumnItem>

<TableColumnItem>
<ScriptBlock>$_.Version.ToString()</ScriptBlock>
</TableColumnItem>

<TableColumnItem>
<PropertyName>Collation</PropertyName>
</TableColumnItem>

</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>

</ViewDefinitions>
</Configuration>

 

I save the formatting file in the $PSHOME folder . To load the file I can do it in the current session using  Update-Formatdata cmdlet :

Update-formatdata –prependpath "$($PSHOME)\Functions.Format.ps1xml"

or , an better, create or add in my module manifest from this module and in the FormatsToProcess option associate with Functions.Format.ps1xml .  This way I moved the file to the Functions Folder and in this folder now I have 3 files. Functions.psm1, Functions.psd1 and Functions.Format.ps1xml

Then when I start a PowerShell session my module will be loaded with its formatting file . If I type GET-SQLServerInfo :

Get-SqlServerInfo r2d2 

 

 

 

Name            Edition                        Product Level   Version                Collation                             

----            -------                        -------------   -------                ---------                             

r2d2            Enterprise Edition (64-bit)    RTM             11.0.2100              SQL_Latin1_General_CP1_CI_AS   

image

 

It is faster because I am only loading  5 properties and if I want to show all properties , it is just pipe to SELECT-OBJECT * :

Get-SqlServerInfo r2d2 | select *

image

 

Cool !!! uh ? To read :

Writing a Windows PowerShell Formatting File

How to Write a Module Manifest

 

#PowerShellLifeStyle

About Laerte Junior

Laerte Junior Laerte Junior is a SQL Server specialist and an active member of WW SQL Server and the Windows PowerShell community. He also is a huge Star Wars fan (yes, he has the Darth Vader´s Helmet with the voice changer). He has a passion for DC comics and living the simple life. "May The Force be with all of us"
This entry was posted in Powershell, SQL SERVER EM GERAL, Virtual Pass BR. Bookmark the permalink.

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