Friday Fun What’s My Variable

I use scriptblocks quite a bit in my PowerShell work, often saved as variables. These are handy for commands you want to run again, but don’t necessarily need to turn into permanent functions.


$freec={(get-wmiobject win32_logicaldisk -filter "deviceid='c:'" -property Freespace).FreeSpace/1mb}

Now in PowerShell I can invoke the scriptblock.


PS S:\> &$freec
94079.72265625

Ok then. I have a number of these defined. I decided I wanted an easy way to identify them when I run Get-Variable. For example, if I remembered all the variable names I could just do this:


PS S:\> get-variable freec,dirt

Name Value
---- -----
freec (gwmi win32_logicaldisk -filter "deviceid='c:...
dirt Param([string]$Path=$env:temp) Get-ChildItem ...

But needless to say that’s asking too much. When I first looked at this problem I went down the path of trying to parse values I saw with Get-Variable to identify potential script blocks. Then I realized this was a rookie mistake. PowerShell is all about the objects. Now a variable is also an object with a value property. This value could be a string, and integer or a pscredential. So my task then was to identify each value type.

Every object in PowerShell has a built in method called GetType().


PS S:\> $s=get-service spooler
PS S:\> $s.GetType()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ServiceController System.ComponentM...

This is actually another object with a Name property.


PS S:\> $s.GetType().name
ServiceController

Aha! Let’s look at this with my variable.


PS S:\> (get-variable freec).value.GetType().Name
ScriptBlock

This is a one-line shortcut that gets the Value property of the Freec variable and then runs the GetType() method followed by retrieving just the Name property. This is promising. Here’s one way I can use this:


get-variable | Where {$_.value.GetType().Name -eq "ScriptBlock"}

As you can see there is still an issue with variables with no values.

I’ll just add another condition to my Where expression.


get-variable | Where {$_.value -AND $_.value.GetType().Name -eq "ScriptBlock"}

Success!

These are in fact all of the scriptblocks in my current session. But now I can take this a step further and look at my other variables and their type.


get-variable | select Name,@{Name="Type";Expression={$_.value.GetType().Name}}

Or I might try grouping.


get-variable | select Name,@{Name="Type";Expression={$_.value.GetType().Name}} | where {$_.type} | Group Type | Sort Count -Descending

I wanted to filter out empty values so I’m only keeping objects that have a defined type in my grouped output.

The bottom line is never forget about the object!

Friday Fun – A Christmas Prompt

Over the last few weeks I’ve read about other people’s PowerShell prompts and offered a few suggestions of my own. This week’s Friday Fun creates colorful holiday prompt that counts down the number of days until Christmas. Continue reading

Friday Fun – Get Number Object

You most likely know that I’m all about the object and the PowerShell pipeline. Everything in PowerShell is an object. Pipe something to Get-Member and you can discover all of the object’s properties and methods (ie its members). Some objects, like strings, have many methods but very few properties. Some objects, like numbers have very little of either. I mean, what can you really do with a number? Well, I can have a bit of fun with one and maybe teach a few PowerShell concepts along the way. Continue reading

Friday Fun What a CHAR!

Last week I posted a PowerShell snippet on Twitter. My original post piped an array of integers as [CHAR] type using an OFS. Don’t worry about that. As many people reminded me, it is much easier to use the -Join operator.

I’ll let you try that on your own. The [CHAR] type is used to represent a character as an integer value, like this:

For this week’s Friday Fun I thought it would be nice to translate a string of text into corresponding character values. It looks like a secret code! Or we could use the translation in a join scriptblock. So I put together a little script I call Translate-ToChar.ps1. The script takes a string of text and writes an array of [CHAR] objects.

The script begins by defining a map hash table for what I think are all characters you are likely to find on a US keyboard. These should be character values 33 through 125 which I get using the range (..) operator.

Each number is piped to ForEach object where I add it to the hash table. In order to get the hash table key to work properly I cast the number as a string and the hash table value is the same number cast as a [CHAR]. Now we can begin breaking the string apart and “translating” it.

The script splits the string into a character array using the default delimiter of a space. Because I’m going to be using a pipelined expression, I save the current letter as a variable. It will keep things straight in a moment.

The next step is to find the character in the hash table values. I found the best way to accomplish this was to call the hash table’s GetEnumerator() method. This way I can pipe it to Where-Object and find the corresponding key.

Notice I’m using the case sensitive -ceq operator. The Name property of the hash table enumerator is the key value, or in other words the corresponding [CHAR] integer. With me still? This value is added to an array for the final result. In fact the default isĀ to simply write $values to the pipeline. But, I’ve included a -Scriptblock parameter to have the script write a scriptblock to the pipeline using the -Join operator I mentioned earlier. Now for the interesting part.

I have an array variable which needs to be expanded into the scriptblock. This won’t work:

I’ll end up with a scriptblock but have no way of resolving $values once the script ends. So instead I create a string with $values knowing that PowerShell will expand it. And because I want the array to be expanded as a comma separated string, I’ll specify the $ofs variable as a comma. The default is a space.

The variable $t is now a string with all of the integer values from $values as a comma separated list. I can turn this into scriptblock like this:

The scriptblock gets written to the pipeline. So, I could run the script like this:

Now I can use $a however I want. Or I could create a scriptblock.

I can invoke $b anytime I want to see the message.

While I don’t expect you to be running this in production I hope you picked up some tips on using hash tables, arrays, scriptblocks and casting variable types.

Download Translate-ToChar

Friday Fun Add A Print Menu to the PowerShell ISE

I spend a fair amount of time in the PowerShell ISE. One task that I find myself needing, especially lately, is the ability to print a script file. I’m sure you noticed there is no Print menu choice. So I decided to add my own to the ISE. Continue reading