Howto Write a PowerShell Module or Function in C# with Visual Studio 2012This is a post in a series of posts, you can read Step 2, 3, 4 and 5 also.
So you’ve probably more than stumbled upon Microsoft PowerShell at this point. Or you’ll have some really awesome couple of weeks ahead of yourself now that Windows Server 2012 is released. I won’t be getting into explaining PowerShell what it is and why to use it. You know that by now and if you don’t I’m sure that you will find really good resources by searching the web.
Over the last year I’ve been creating lots and lots of PowerShell scripts. Just take a look at my script (here) for downloading TechEd and MMS sessions or my hydration kit for System Center (here). One of the first things that you run into when creating scripts is the need for functions in order to create/do more with less (coding). I like to refer to or think of functions as loops such as do…while or foreach … loops. There isn’t really that much of object orientized programming that you need to know before creating PowerShell functions. They might not be optimal but they’ll work just fine… at least version 15 or 16
For me there were a little breakthrough when I learned howto create functions with CmdletBinding (feature like –Verbose or –Debug). Same with parameters and how to control them (like ValidateSet and so on). After that how to include comments/help for each parameter came pretty quick as well. And soon I were of creating modules with module manifest and stuff.
However I still wasn’t quite satisfied. I really wanted to compile those modules and be able to distribute them in a good fashion way. With the lack of knowledge how to do this I looked into signing and learned to and started to code sign my scripts. Which also is really nice, however users of my script still had to grant permission to run my scripts in PowerShell before the would execute without any issue (if Execution Policy was set to RemoteSigned or AllSigned). And that wasn’t always “good enough”. At least not for me
After searching the web for some time a found a handful of sites with some info here and other info there. This is my contribution.
So lets get going, but where are we going? Our goal with this post is to have a PowerShell module that we can load into PowerShell and get functions that we can run. All in a compiled .DLL file. Let’s really get going then. Oh, we’ll use Visual Studio 2012.
Create a class
First we’ll start by simply creating a project in Visual Studio 2012 containing a simple Class Library (DLL). There isn’t much to say here except – choose the right project template or you’ll get trouble following the rest of this guide.
Add reference to PowerShell
In order to connect into the PowerShell runspace inside the program language and create functions in PowerShell we must add a reference to the PowerShell library (DLL) which is called “System Management Automation” – guess why.
System Management Automation 6.1
Okey I admit – I’m coding on Windows 8. It’s great once you start coding in PowerShell and C# to easily transform this knowledge and start developing Windows 8 Apps (WinRT/Metro). Give it a try why don’t you! Anyhow, I still want my code to be able to run in Windows 7 without PowerShell 3.0 deployed so I’ve copied the System.Mangement.Automation.dll from Windows 7 (see second picture showing file version 6.1) into c:temp on my development machine. Foot note: I’m not 100% sure that this really is a requirement but I figured it didn’t hurt. We’ll also need System.Management framework imported as well.
Removing what we don’t need
It’s always good to have it nice and clean around you. This time around, we won’t be able to compile the code.
Remove the line containing “using System.Threading.Tasks;”. Soon we’ll start with that code. I promise!
Change to .Net Framework 3.5
Double click “Properties” in the “Solution Explorer” to the right and when you get the same view as above change “Target Framework” to “.NET Framework 3.5” instead and select “Yes” in the popup question. While at it, you can see in the Solution Explorer that “System.Management” and “System.Management.Automation” has been added under “References”.
Creation of first PowerShell function in c#
Just above the first class (which we will rename later) definition we add a line that starts with
or, if we go ahead and add a line after “using System.Text;” like
we can shorten the VerbsCommon-string like in the picture below.
As you can see in the first picture in the section there are lots of verbs to choose from. And this is a point where I spent some time figuring out myself since no one made it this visual or even commenting on it. Some verbs live within VerbsCommon such as “Get”, others like “Protect” live within “VerbsSecurity”. In PowerShell you can type “Get-Verbs” and you’ll get a neat list with the different verbs and where the live.
Note: It’s considered good practice to reuse these verbs and not make up some yourself when suitable. In other words, use the common verb “Get” instead of “Fetch” for getting information or something like that.
As I wrote above we rename the class to something that links it to the function, in this example “Get_OperatingSystemSKU” and we make it a “subset” (my own word) of the class System.Management.Automation.Cmdlet. Again, if we add the “using System.Management.Automation;” in the beginning we only add “Cmdlet” so we get
public class Get_OperatingSystemSKU : Cmdlet
At this point we could actually compile the code and execute it but why would we? It doesn’t produce anything, no output.
Get something done!
The moment we all have been waiting for. Time to actually add some code. At this time what we’ve done in PowerShell equivalent is
“Wow, that isn’t much.” you might think. Correct! But by using this method we’ll be able to c o m p i le it – and that is awesome
Back to business… coding.
Since this function doesn’t accept pipeline data/parameters (actually no parameters at all) we’ll use the EndProcessing instead of ProcessRecord which most blogs suggest. To actually get some output we write
WriteObject(“Hello world!”, true);
Don’t ask me about the true part, I’ve tried to find some logic to it but haven’t wasted enough time on it. It works – don’t break it (that much).
A “Hello World” in all glory but let’s get serious. WriteObject returns data to the console, try to always return objects instead of strings so that you’ll be able to reuse the data in the scripts that you’ll use this cmdlet in.
string ouput = “A string of output”;
Would be better, sadly in this example that is not more with less.
I’ve added some code to actually get that SKU back. At this link I found all different SKU’s there is in Microsoft Windows.
Run code, run
So we hit F6 and the code compiles.
If we would have changed the file name for the class file in Solution Explorer the output file’s name would be different. For this guide this will do fine.
We copy the dll to a different folder and import it just as any other module and viola we have a new cmdlet that we can execute…
Good luck with all coding!