Summary: Microsoft Scripting Guy, Ed Wilson, talks about calculating properties in output.
Hey, Scripting Guy! Dude, I’ve got a question. I read your Hey, Scripting Guy! Blog every day. In fact, most times, I read it twice a day. One thing you do all the time, and I don’t understand, is that you send something to, like, Format-Table. I get it when you put in a property name—hey, that’s easy. What I don’t understand is when you add the curly braces, the ampersands, and all that, and then the output is magically changed into what you want. How does that work? I can’t seem to find where that is even documented. Is this secret Scripting Guy stuff, or can you share?
—TW
Hello TW,
Microsoft Scripting Guy, Ed Wilson, is here. Today is the Scripting Wife’s birthday (and she figured I would forget). If you are on Twitter, you might want to wish @ScriptingWife a happy birthday. This morning I decided to make a pot of Oolong tea to go with my breakfast. Normally, I drink green tea in the afternoon or late morning, but I decided to do something daring this morning. I am still drinking the very good Oolong tea I brought back from Germany, so I did not put much in it—a bit of jasmine flowers, a cinnamon stick, and a bit of lemon grass. The flavor is light and delicate, and it actually compliments my fresh kiwi quite well. I was reading over email sent to scripter@microsoft.com when I ran across this email from TW.
I know exactly what you mean. Calculating a value to display for a property is way cool, very powerful, and confusing as all get out…until you know what is going on. When you know the secret, it is quite easy. So, let’s get started.
It all begins with a hash table
Let me make this one thing perfectly clear—as someone once said. If you do Windows PowerShell, and if you want to get beyond the very basics, you need to understand about hash tables. This is because Windows PowerShell loves hash tables, and we use them everywhere.
So what is a hash table? I could say it is a lot like a dictionary object, and if you used VBScript or some other language in the past, you might say, “Oh, yeah.” Otherwise, that is sort of like saying an aardvark is kind of like a platypus (or not, as the case may be).
A hash table lets me create key/value pairs. I can have more than one of these pairs. Windows PowerShell uses hash tables as a way to quickly provide information about a variety of things. To create a hash table, I use an at sig ( @ ) and a pair of curly brackets (a script block). Inside this, I add my key/value pairs. Each of these pairs is separated by semicolons. Here is a basic example:
PS C:\> @{a=1;b=2;c=3}
Name Value
—- —–
c 3
b 2
a 1
You will notice that I do not even have to store it in a variable. When I type the hash table and press ENTER, it is sent to the default outputter, which in this case, is the console. If I had a pipeline, it would go on down the pipeline for additional processing. Here is an example:
PS C:\> @{a=1;b=2;c=3} | format-list *
Name : c
Key : c
Value : 3
Name : b
Key : b
Value : 2
Name : a
Key : a
Value : 1
So a hash table is made up of a series of key/value pairs that are enclosed inside a pair of curly brackets and preceded by an at sign.
A special hash table
The Format-List, Format-Table, and Select-Object cmdlets accept a hash table for the –Property parameter. (I cannot use this technique with Format-Wide.) The syntax for each shows that the –Property parameter accepts an object, and a hash table is an object:
PS C:\> Get-command format-list, Format-Table, Select-Object -Syntax
Format-List [[-Property] <Object[]>] [-GroupBy <Object>] [-View <string>]
[-ShowError] [-DisplayError] [-Force] [-Expand <string>] [-InputObject
<psobject>] [<CommonParameters>]
Format-Table [[-Property] <Object[]>] [-AutoSize] [-HideTableHeaders] [-Wrap]
[-GroupBy <Object>] [-View <string>] [-ShowError] [-DisplayError] [-Force]
[-Expand <string>] [-InputObject <psobject>] [<CommonParameters>]
Select-Object [[-Property] <Object[]>] [-InputObject <psobject>]
[-ExcludeProperty <string[]>] [-ExpandProperty <string>] [-Unique] [-Last
<int>] [-First <int>] [-Skip <int>] [-Wait] [<CommonParameters>]
An example
For me, one of the things that is a bit difficult to read is lots and lots of bytes. I much prefer that they display as kilobytes, megabytes, gigabytes, or even terrabytes, than simply bytes. Windows PowerShell has "administrative constants" (KB, MB, GB, TB) that I can use to do these calculations easily. Here is an example:
PS C:\> 1kb
1024
PS C:\> 1mb
1048576
PS C:\> 1gb
1073741824
PS C:\> 1tb
1099511627776
When the virtual memory property displays in bytes, I like to do something about it, and this is an excellent opportunity to use the calculated property value technique. Often, I do this interactively at the Windows PowerShell console because I have gotten pretty good at this technique. But for clarity, I am going to show it in the Windows PowerShell ISE because it is a bit easier to see what is going on.
All I am going to do is grab process information by using the Get-Process cmdlet, and send it down the pipeline. First up, I will use Format-Table to display the virtual memory in megabytes, instead of bytes. Here is how I do it:
get-process |
format-table @{
L='VM in Megs';
E={$_.vm/1MB}
}
Get-Process retrieves the process information and sends it down the pipeline. I send it to the Format-Table cmdlet. Now I open my hash table with the at sign and opening curly bracket as shown here:
get-process |
format-table @{
Now the L and the E in the command are abbreviations that stand for Label and for Expression. Because this is a special hash table, I can use the abbreviations if I wish. Remember, it is key name equals value. Each part is separated by a semicolon. So here, the Label is VM in Megs:
L='VM in Megs';
The Expression is a script block, and it is always a script block. Therefore, it has an opening and a closing curly brace. E is the abbreviation for Expression, and I set it equal to my script block value. Inside the script block, I use the $_ to represent the current item in the pipeline, and I divide it by the administrative constant, MB. I am using one megabyte to divide the current value in the pipeline. Here is that line:
E={$_.vm/1MB}
The last thing to do is close the curly brackets ( } ).
Here is what it would look like with Format-List:
get-process |
format-list @{
Label='VM in Megs';
Expression={$_.vm/1MB}
}
And here is what it would look like with Select-Object:
get-process |
Select-Object @{
Label='VM in Megs';
Expression={$_.vm/1MB}
}
If I want additional properties, I add them to the script, either before or after the calculated value. (I generally do it before because I think it is easier to read.) Here is an example:
get-process |
Select-Object Name, @{
Label='VM in Megs';
Expression={$_.vm/1MB}
}
Here is what that output looks like on my computer:
TW, that is all there is to using Windows PowerShell to calculate values for output. Join me tomorrow when I will talk about more cool Windows PowerShell 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
0 comments