This is the part 2 of a multi-part blog.

Part 1Part 2Part 3

Previously on C#4PS:

We installed Visual Studio and a couple of extensions, we set up a new project in a new solution, and we changed the theme to Dark because we are dark and moody.

Code window ready:


That’s all we did in Part 1, which is why you feel so restless.

Write code and import it into PowerShell

We add a static property, Two, and a static method, GetCritique():


Note that I’ve added “public” in front of the class definition. Otherwise, the class will load in PowerShell but it will be invisible and you won’t be able to call it, like God during a bout of existential angst.

We build it and run it in the usual way, by hitting Start in the tool bar, or pressing F5.


Oh, we can’t. We’re building a class library, and that won’t run itself.


So we instead use Ctrl-Shift-B, or Build > Build Solution. This puts the binary in StupidClass\bin\Debug, since I have the Debug build configuration selected, along with a .pdb file which helps a debugger provide readable output. We open PowerShell and run:

Import-Module ".\PSUGUK-Compiled-PSModule\StupidClass\bin\Debug\StupidClass.dll"

We can now use this class like any other .NET class:


Tab completion works, we can access the static members with the double-colon syntax, we even get our nice typo - neough said.

If that didn’t work, did you remember to add “public” before “class StupidClass”?

Let’s add an instance method, GetInstanceCritique:


This time, when we build again, it balks, because we have a file lock open on the output file. That’s because we’re trying to overwrite the .dll file that we just loaded in PowerShell.


I know what you’re thinking. “Aha,” you nod, “we need to run Remove-Module in our PowerShell window.”

Won’t work. When you import that module, you load the StupidClass type into the AppDomain. You can never unload a class from an AppDomain in .NET, not even with -Force. Not even with sudo –force. You have to close the PowerShell host.

So go ahead and do that.

Now it builds when you press Ctrl-Shift-B, and if you open a new PowerShell host and import it again, you can instantiate the object with New-Object and call that instance method:


I’m sure you are using tab completion here. This stuff practically writes itself, it’s so low-effort. What can we do about that annoying close-and-reopen malarkey? Well, you could write a script that uses System.IO.FileSystemWatcher and Register-ObjectEvent to pick up on file changes, but we are actually going to use Visual Studio’s Build Events.

Build Events

You access these from the Project Properties window:


As a reminder, you can get to that either through Project > StupidClass Properties, or by right-clicking on the StupidClass project in Solution Explorer:


We need a pre-build event to close the PowerShell window from the last run, and a post-build event to open PowerShell and import the module. You can paste the events straight in here or, if you don’t like this nice script I’ve cooked for you and want to do something different, you can click on the Edit buttons and access the Macros. Macros will embed variables related to the project or solution you are building, such as output paths.


start powershell -NoProfile -Command "Get-Process powershell | where {$_.MainWindowTitle -eq '$(TargetName)'} | Stop-Process"

Post-Build (see note about cmdow):

C:\dev\cmdow\bin\Release\cmdow.exe /run powershell -NoExit -Command "sl $(ProjectDir); $host.UI.RawUI.WindowTitle ='$(TargetName)'; Import-Module $(TargetPath)"

Build Events are janky batch script and you’ll need to escape anything that looks like a macro.

What will annoy you quickly is how stubborn Visual Studio is about waiting for you to close the just-opened PowerShell host before it returns. StackOverflow pointed me to a little app called cmdow, which you will need to download from [here](”>. Update the build event script above to reflect where you save it. This allows you to code while you still have the class loaded in PowerShell.

Next up: write code that isn’t stupid!