Can you remove an Add-ed Type in PowerShell again?

DllPowershellAdd Type

Dll Problem Overview


I'm currently writing a library in C# and was using PowerShell to quickly test it on some occasions. However, this prevents me from re-building the project as PowerShell obviously still has the DLL open.

Is there a way of unloading the DLL again after adding it with Add-Type? The documentation doesn't seem to have clues on that and the obvious candidate would be Remove-Type (which doesn't exist – there is only one command anyway with Type as its noun). It gets cumbersome to close PowerShell and do all the stuff of navigating to the build directory and adding the type again each time I want to rebuild.

Dll Solutions


Solution 1 - Dll

Like the others say, this is a .NET behavior. Assemblies loaded into an AppDomain cannot be unloaded. Only the AppDomain can be unloaded, and powershell uses a single appdomain. I blogged a bit about this some years ago:

https://web.archive.org/web/20170707034334/http://www.nivot.org/blog/post/2007/12/07/WhyAppDomainsAreNotAMagicBullet

When I test like this, I usually keep a shell open and use a nested shell to do tests. start powershell, cd to bin location then run "powershell" to start nested shell (new process.) "exit" to start over, and run "powershell" again.

Solution 2 - Dll

I find the simplest way to get around this problem is to wrap the Add-Type and the test code inside of a Start-Job. Start-Job will create a background process, and the type will be loaded there. Once you are done, the process goes away and you're free to retry.

Here's an example of how it looks:

$job = Start-Job -ScriptBlock {

    Add-Type -path 'my.dll'
    $myObj = new-object My.MyTestClassName

    $result = $myObj.TestMethod
    $result
}
Wait-Job $job
Receive-Job $job

The output from the test method will be echoed to the console.

Solution 3 - Dll

If your assembly doesn't require a binding context you can do this:

$bytes = [System.IO.File]::ReadAllBytes("Path_To_Your_Dll.dll")
[System.Reflection.Assembly]::Load($bytes)

Solution 4 - Dll

Here is a complete example that allows to run the Add-Type command as a background job so that the assembly is unloaded once it finishes:

# Start-Job will not preserve the working directory, so do it manually
# Other arguments can also be passed to the job this way
$cd = Split-Path $MyInvocation.MyCommand.Path
$jobParams = @{
	'cd' = $cd
}

Start-Job -InputObject $jobParams -ScriptBlock {
	cd $Input.cd
	Add-Type -Path assembly.dll
} | Receive-Job -Wait -AutoRemoveJob

Receive-Job -Wait will make sure that the output of the job is received since otherwise it will be lost.

Solution 5 - Dll

I have been facing to similar problem. It is not possible to unload a type/assembly (that's because it applies to .NET framework).

In .NET you can solve it if you crate a new application domain (System.AppDomain) and load the assembly into that domain. It is possible to unload the app domain and that unloads all the dlls as well.

I haven't tried it yet, because for me it is much simpler to close a tab in Console and open new one.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoeyView Question on Stackoverflow
Solution 1 - Dllx0nView Answer on Stackoverflow
Solution 2 - DllStart-AutomatingView Answer on Stackoverflow
Solution 3 - DllGeorge HowarthView Answer on Stackoverflow
Solution 4 - DllKnaģisView Answer on Stackoverflow
Solution 5 - DllstejView Answer on Stackoverflow