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 Addstatic 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:
[accelerators]::add("mydate","System.datetime")
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 Nowmethod. 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.
Creating a type accelerator for a non-loaded assembly
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:
[accelerators]::Add('vbmath',"Microsoft.VisualBasic.vbmath")
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
TypeName: Microsoft.VisualBasic.VBMath
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:
[vbmath]::Randomize()
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()
0.3871228
PS C:\> [vbmath]::Rnd()
0.2059224
PS C:\> [vbmath]::Rnd()
0.847851
PS C:\> [vbmath]::Rnd()
0.3145823
The point to all this
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 scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy