For those of you who don't already know, Windows PowerShell is a command shell that pipes .NET objects between commands instead of text. You can use it to directly create and manipulate full-fledged .NET objects with the entire .NET Framework at your disposal. It's sort of like a live .NET programming language where your statements are executed line by line as you type them.
So I was writing a class library and got to a point where I wanted to test it. I could have written a small test application or a unit testing project, but it occurred to me: What if I just used PowerShell?
Working with your class library in PowerShell
As far as I know, PowerShell doesn't have any Cmdlets or other mechanism specifically for loading external libraries. But, it doesn't need one! Remember, you have the entire .NET Framework at your disposal. A simple call to the System.Reflection.Assembly class will do the trick.
[Reflection.Assembly]::LoadFrom("MyLibrary.dll")
You could capture the resulting Assembly object in a PowerShell variable if you want, but all that is needed is to load it into the application domain of PowerShell, which is exactly what this method does. Now that it's loaded, you can access your types the same way you otherwise would in PowerShell:
[MyNamespace.MyClass]::MyStaticMethod()
$obj = New-Object "MyNamespace.MyClass"
Setting up Visual Studio
Of course we want to easily start debugging by pressing the "Play" button, and we want Visual Studio to be able to pick up breakpoints and detect exceptions. Also, we want some PowerShell commands to be executed automatically every time, such as the one that loads the library and possibly some that instantiate some test objects for you. I opted to create a PowerShell script file in the project folder called "Debug.ps1". Setting the project's properties in Visual Studio to get it to work, though, was tricky.
Under the Debug tab in the properties for the class library project, select the "Start external program" option. Browse for powershell.exe.
Now for the command line arguments. Here's what I used:
-noexit -command . ..\..\debug.ps1
First, "-noexit" specifies that PowerShell is not to exit after the command is executed. We want this so that we can type our own commands after the initial script is executed. Second, "-command" specifies that the rest of the command line arguments is actually a command to be executed. The command is ". ..\..\debug.ps1". However, if you use quotes, it will think the quotes are part of the command which will make it simply think it's a string, not code to execute. The initial dot is there so that the script is "dot-sourced". "Dot-sourcing" a script means that it executes in the current runspace instead of a new one. This way, any variables set by the script will be preserved so they can be used afterward. Finally, if you don't specify a working directory, Visual Studio defaults to the output directory for the project. I kept it this way in case the project is copied to a different directory; for example, if it were added to source control and someone downloaded it to a different local directory. So to reference the script that exists in the project directory, I used "..\..\" since the current directory is in \bin\Debug inside the project directory.
Here's an example of what your debug.ps1 script might look like:
# Since the current directory is the output directory for the project, simply pass in the name of the DLL file:
$assembly = [Reflection.Assembly]::LoadFrom("MyLibrary.dll")
# Here's how to create an object using a constructor with two arguments:
$testObj = New-Object "MyNamespace.MyClass" -arguments "First argument.", "Second argument."
And as I mentioned before, since the script is "dot-sourced", the variables $assembly and $testObj will remain after the script is done executing. Also, if you haven't tried to run scripts in PowerShell yet, you might run into a security issue. Simply type "set-executionpolicy RemoteSigned" into PowerShell to allow unsigned local scripts to execute.