Using .NET Framework Assemblies in Windows PowerShell

Doctor Scripto

Dr Scripto

Summary: Guest bloggers Microsoft PFEs Adam Haynes and Shubert Somer continue their .NET Framework Essentials post by talking about assemblies.

Microsoft Scripting Guy, Ed Wilson, is here. Today is part 4 of a 5-part series written by guest blogger Adam Haynes with help from his friend Shubert Somer. You will want to go back and read part 1, part 2, and part 3 (if you have not already done so) before you read today’s blog.  

Here’s Adam …

Shubert warned me about this “simple” blog post on .NET Framework Essentials. I am paraphrasing here, but it’s like getting too close to a black hole. Black holes are cool as is mixing .NET Framework and Windows PowerShell, but if you get close enough to have a peek over the edge, it’s too late and you’re getting sucked in. We tried to keep it simple, and so far, we have talked about: type/class, object, method, constructor, property, and members. While this is not an all-encompassing list of .NET terminology, we actually glossed over a rather important topic.

Remember when I said that in order for the script in the previous post to work you needed to have the Active Directory module available/installed? There is a very specific reason for this. The script did use several cmdlets that are part of the Active Directory module (installed with RSAT), but the part we glossed over was the System.DirectoryServices.ActiveDirectory assembly. Loading the Active Directory module into the Windows PowerShell console, loads the assembly for us.

I don’t want you to have to click back and forth between posts, so we are going to continue this post with a new sample to introduce this new concept and reiterate the previous learning. This script gives us access to Windows Forms objects. I know what you’re thinking. We spent all this time talking about how cool Windows PowerShell is and now I want you to go back to a GUI!? Well, not exactly, and here is why: while I love PowerShell, some users of the scripts I produce and assist with are a little gun shy when it comes to the blinking cursor in the deep blue box.

This little snippet pops open the dialog box we are all used to in the GUI when opening a file for input. It can be a nice thing to have if you are asking for files from the user, and they are not comfortable in the Shell (or if you are lazy like me).  

<SCRIPT >

 [reflection.assembly]::loadwithpartialname(“System.Windows.Forms”) | Out-Null
$openFile = New-Object System.Windows.Forms.OpenFileDialog
$openFile.Filter = “txt files (*.txt)|*.txt|All files (*.*)|*.*”
If($openFile.ShowDialog() -eq “OK”
{get-content $openFile.FileName} 

</SCRIPT >

Image of script

Most of this should be familiar to you, but line 1 looks oddly familiar—odd in that I have no idea what reflection.assembly means, and familiar because it looks like a static method. Why is it important or necessary, you ask? Because this is what the script returns when we don’t use it.

Image of command output

It seems that Windows PowerShell doesn’t know about the OpenFileDialog constructor, for some reason. I thought PowerShell was all knowing and all seeing? I want to turn it back over to Shubert, because that one line of the script will consume most of this post. That one line will also allow you to reach into .NET Framework and access whatever Microsoft technology you are working with. 

Shubert: There is a lot going on with that one line, so naturally I want to give some background to put it in to context. The way we deliver modular code, that is, code that has a chunk of functionality that can be reused, is to package stuff into DLLs (DLL stands for Dynamic Link Library, which is code that can be loaded into memory and executed on-demand). Back in the pre-.NET days, I liked to compare Windows programs to a bucket of marbles, with each marble representing a DLL. Installing a program was like emptying the bucket into your basement, and uninstalling was like telling one of your kids to go down in the basement and pick up all the green marbles. Keeping track of all the marbles was something known as DLL Hell.

Enter .NET … instead of a bucket of marbles, .NET Framework is more like having a bag of marbles with a little “contents” label. Installing a .NET program is more like putting the bag of marbles in a bag of marbles shelf in your basement, where you keep everything in alphabetical order. Mostly.

“Gee, that doesn’t sound much better,” you may think, but actually it is. It’s easier to find the bag of marbles you are looking for, and the label tells you which marbles are inside and what they do. The bags of marbles are like .NET assemblies, and the label on the bag is what reflection is for .NET Framework.

Like all things in .NET, reflection is actually just another set of .NET objects, and so they have their own sets of properties and methods. Because they are mostly utility-like things, many of these are static. The .NET technical term for reflection is a namespace, and it is very important to understand the difference between a namespace, an assembly, and a class.

Namespaces are just labels that are used to allow classes from different assemblies to have the same name and not interfere with each other. Much like classes form a container, or boundary, for their members (so many different classes can have an “Open()” method, for example), namespaces form a container for classes with the same name. Native .NET namespaces start with “System” (this is the root of the .NET namespace universe). The convention for application-specific namespaces is to start them with {CompanyName}.{ProductName}. So, for example, you may see Microsoft.Office.{some more stuff} for Office-related classes.

An assembly is a packaged chunk of functionality (the .NET equivalent of a DLL). Almost universally an assembly will consist of exactly one file (either a DLL or an EXE). To make things confusing, the naming convention for assemblies is very similar to the naming convention for namespaces. Be warned: they are not the same thing! An assembly may contain classes from many namespaces, and a namespace may cover many assemblies. Although not strictly correct, you can think of the assembly as the physical file containing the executable code and a namespace as a category to organize all the code that relates to a particular area.

So now, this line might start to make sense. Reflection is the namespace that tells Windows PowerShell exactly which assembly class to use (the full namespace is “System.Reflection”, but the left-most parts of the namespace can be dropped as long as it does not lead to any ambiguity—if it does, then Windows PowerShell should complain with some kind of “unable to resolve object path” message). The assembly class has a bunch of static methods for handling assemblies. We are using the method that will load the desired assembly (some file on disk) into memory so that it can be accessed by Windows PowerShell. To use the marbles analogy, you are telling one of your kids to go in the basement and bring back the “System.Windows.Forms” bag of marbles so that you can play marbles with them.

You will see later in the code that System.Windows.Forms is also a namespace, and that can make things a little confusing. If you are looking in MSDN for how to load the assembly that you need to access that cool class you found, check for the assembly name—it may be different (sometimes much different) from the class namespace!

Image of SPFarm class content

MSDN Reference: http://msdn.microsoft.com/en-us/library/ms973231.aspx

Adam: Well, I have to say that after listening to that in person, I was less smart than before we talked. After reading that a few times, I think it has sunk in. In the example from part 1 of the series, we didn’t need any if this because the Import-Module cmdlet did this work for us. The developers that wrote the module knew they needed the DirectoryServices namespace, so the Active Directory module has this type of code in it, and we don’t have to deal with it as administrators.

Now that we know why line 1 is so important, you might ask why we talked about it at the end? Well, if we started with that, do you know many admins that would have read this far? J I know that when Shubert tried to start out teaching me that one, I was reaching for the fake phone call to bail. We are almost done. In the final post, we will take this new-found knowledge and apply it line by line to the script we introduced in this post. 

~Adam

Thank you, Adam and Shubert. 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 

Doctor Scripto
Dr Scripto

Scripter, PowerShell, vbScript, BAT, CMD

Follow Dr Scripto   

0 comments

    Leave a comment