Learn about Windows PowerShell
Summary: Microsoft Scripting Guy, Ed Wilson, shows how easy it is to create custom Windows PowerShell type accelerators and incorporate them into scripts.
Microsoft Scripting Guy, Ed Wilson, is here. Windows PowerShell is cool. In fact, it should come with a disclaimer something like this:
Warning! Windows PowerShell can be addictive. Symptoms of Windows PowerShell addiction include talking in verb-noun pairs; writing Windows PowerShell psudo-code on Facebook, Twitter, and in email. Advanced cases typically manifest themselves as dreaming of creating the perfect Windows PowerShell profile, and customizing your Windows PowerShell prompt to include current weather and stock information.
Am I the only person who thinks that Windows PowerShell would be a great Twitter client? Oh well…
When I was playing around with listing all type accelerators yesterday in my post, Use PowerShell to Find PowerShell Type Accelerators, I noticed that there is an Add static method available.
This means that it should be possible to create and to add a custom type accelerator. To test this, I began playing around with different syntaxes until I came up with something that worked. Using the Get-Member cmdlet was enough to get me started in the right direction. This is shown here:
PS C:\> [accelerators] | get-member -Static -MemberType method -Name add | fl -Force
TypeName : System.Management.Automation.TypeAccelerators
Name : Add
MemberType : Method
Definition : static void Add(string typeName, type type)
I need to supply a string for TypeName, and a type as a type. Hmmmm…
After a few tries, I came up with this syntax:
The first parameter becomes the name of the newly created type accelerator. The second string is the type that will be “accelerated” by the command. I now check to see if it works by simply placing the name in square brackets. As shown here, this appears to work:
PS C:\> [mydate]
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True DateTime System.ValueType
Now I want to see if I can get the current date and time. I do this by calling the static Now method. As shown here, it works:
PS C:\> [mydate]::now
Tuesday, July 2, 2013 1:44:00 PM
Granted, all this is somewhat bogus because there is already the [datetime] type accelerator, but I was just taking the first step to see if I could make it work.
Inside the Microsoft.VisualBasic assembly are equivalents to many of the old VBScript functions. The Microsoft.VisualBasic assembly is not loaded by default. To use any of these classes, first load the assembly by using the Add-Type command. This command is shown here:
Add-Type -AssemblyName Microsoft.VisualBasic
Now, I can add a type accelerator for the Microsoft.VisualBasic.VBMath .NET Framework class. I decide to call the accelerator VBMath. The script is shown here:
Now, I test out the newly created type accelerator:
PS C:\> [vbmath]
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False VBMath System.Object
It returns, so that is good. Now I decide to pipe the object to the Get-Member cmdlet to see what it provides.
PS C:\> [vbmath] | Get-Member -Static
Name MemberType Definition
---- ---------- ----------
Equals Method static bool Equals(System.Object objA, System.Object o...
Randomize Method static void Randomize(), static void Randomize(double ...
ReferenceEquals Method static bool ReferenceEquals(System.Object objA, System...
Rnd Method static float Rnd(), static float Rnd(float Number)
It looks like there are two interesting methods. (These methods are documented on MSDN). The first is Randomize. I use it here:
Nothing comes back because Randomize uses the system timer to obtain a seed value for the RND method. RND returns a value that is less than 1 but greater than or equal to 0. If I do not use the Randomize method, the RND method always returns the same numbers in the same order. Now I use the RND method to create a few random numbers as shown here:
PS C:\> [vbmath]::Randomize()
PS C:\> [vbmath]::Rnd()
The point to all of this is that I can create a nice shortcut to a .NET Framework class, and thereby permit my code to be simpler and easier to read. Certainly [vbmath] is easier to read and type than [Microsoft.VisualBasic.VBMath].
If I add the type and the type accelerator at the beginning of a script, my code is easier to read, and possibly easier to write. If I add the commands to my profile, I have access to them via the script and the Windows PowerShell command line. This is more flexible and offers more options.
Of course, I would not create the [vbmath] type accelerator in real life. I have Get-Random, which is easier to use and is already built into Windows PowerShell (beginning with Windows PowerShell 2.0). So there is no need to create an instance of this class. I am simply using it as an example of adding a type accelerator for something that does not already exist.
There are lots of useful .NET Framework classes that you might want to harvest for your scripts. MSDN documents them all. Between MSDN and Bing you have all you need. If you find something cool, please share it with us.
That is all there is to creating and to using type accelerators. 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 firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
On one hand you recommend against using custom (even standard) aliases in scripts, yet now you are for custom type accelerators?
@X You are right. The thing to always keep in mind, is what am I going to do with the script once it is written? Am I going to share it with someone? Am I going to upload it to Script Center? Am I going to keep it for my own? What I am doing here, is creating a type accelerator inside of my script. It becomes a shortcut and can reduce typing. I used to do this (especially when automating office) to make the code more readable. There is no difference between using this technique, and using -astype with a variable to create a custom type. However, you have pointed out something that is vital -- I found out that the [accelerators] type is only available when the PowerShell Community Extensions are installed -- and they are not standard install. So there is an external dependency here ... Again goes back to how do I intend to use the script.
Understood, just thought you had a change of heart ;)
How can I get this to work if I don't have PowerShell Community Extension Project installed? The previous post mentioned here, blogs.technet.com/.../use-powershell-to-find-powershell-type-accelerators.aspx, suggests that this extension project is necessary for this post to work.
Here is a quick example to create an accelerator for [tcpclient]
$accelerators = [PSObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')