PowerShell Add-Type : Cannot add type. already exist
Asked Answered
F

7

14

I'm using PowerShell script to run C# code directly in the script. I've run in to an error a particular error a few times. If I make any changes to the C# code in the PowerShell ISE and try to run it again I get the following error.

Add-Type : Cannot add type. The type name 'AlertsOnOff10.onOff' already exists.
At C:\Users\testUser\Desktop\test.ps1:80 char:1
+ Add-Type -TypeDefinition $Source -ReferencedAssemblies $Assem
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (AlertsOnOff10.onOff:String) [Add-Type], Exception
    + FullyQualifiedErrorId : TYPE_ALREADY_EXISTS,Microsoft.PowerShell.Commands.AddTypeCommand

The way I have been resolving this error is by changing the namespace and the command to call the C# method [AlertsOnOff10.onOff]::Main("off"). I there a way I can prevent this error from happening without having to change namespace and method call?

Fenella answered 8/9, 2014 at 18:42 Comment(2)
I would suggest using VS and ex. a console application to develop and debug assemblies. PowerShell can use managed code, but it's not designed to be used as a replacement for VS(althought it's a great supplement)Equitable
Could this help? Of course if your type definition changes it won't help, but it might be a workaround if you are not planning to redefine the type: #16553301Cleodal
B
11

To my knowledge there is no way to remove a type from a PowerShell session once it has been added.

The (annoying) workaround I would suggest is to write your code in one ISE session, and execute it in a completely different session (separate console window or separate ISE if you want to be able to debug).

This only matters if you're changing $Source though (actively developing the type definition). If that's not the part that's changing, then ignore the errors, or if it's a terminating error use -ErrorAction to change it.

Brachio answered 8/9, 2014 at 18:52 Comment(4)
From my understanding, if I close my ISE session I won't run into this error. Is that correct?Fenella
While running ISE changes are not lost. So a variable $wazzup will persist after running a particular piece of code or script.Hemangioma
You can use Remove-Variable to get rid of a defiend variable, and you can clear other run-time objects. But this is not true of types.Brachio
This issue isn't a PowerShell limitation so much as it is a .NET limitation. There's no supported way to remove assemblies once they have been loaded.Barometry
B
17

For those who want to avoid the error or avoid loading the type if it's already been loaded use the following check:

if ("TrustAllCertsPolicy" -as [type]) {} else {
        Add-Type "using System.Net;using System.Security.Cryptography.X509Certificates;public class TrustAllCertsPolicy : ICertificatePolicy {public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) {return true;}}"
        [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
}

I post this because you get the error OP posted if you make even superficial (e.g. formatting) changes to the C# code.

Banville answered 15/1, 2019 at 8:14 Comment(1)
I found a general solution. If you add "-namespace system" at the end of the add-type statement then you can always check the existence of the type via "[type]myTypeName". Even if the added type has no class. Without this the new type ends up as [Microsoft.PowerShell.Commands.AddType.AutoGeneratedTypes.myTypeName].Stratton
B
11

To my knowledge there is no way to remove a type from a PowerShell session once it has been added.

The (annoying) workaround I would suggest is to write your code in one ISE session, and execute it in a completely different session (separate console window or separate ISE if you want to be able to debug).

This only matters if you're changing $Source though (actively developing the type definition). If that's not the part that's changing, then ignore the errors, or if it's a terminating error use -ErrorAction to change it.

Brachio answered 8/9, 2014 at 18:52 Comment(4)
From my understanding, if I close my ISE session I won't run into this error. Is that correct?Fenella
While running ISE changes are not lost. So a variable $wazzup will persist after running a particular piece of code or script.Hemangioma
You can use Remove-Variable to get rid of a defiend variable, and you can clear other run-time objects. But this is not true of types.Brachio
This issue isn't a PowerShell limitation so much as it is a .NET limitation. There's no supported way to remove assemblies once they have been loaded.Barometry
M
4

You can execute it as a job:

$cmd = {    

    $code = @'
        using System;

        namespace MyCode
        {
            public class Helper
            {
                public static string FormatText(string message)
                {
                    return "Version 1: " + message;
                }
            }
        }
'@

    Add-Type -TypeDefinition $code -PassThru | Out-Null

    Write-Output $( [MyCode.Helper]::FormatText("It Works!") )
}

$j = Start-Job -ScriptBlock $cmd

do 
{
    Receive-Job -Job $j

} while ( $j.State -eq "Running" )
Mutism answered 10/12, 2016 at 20:9 Comment(0)
F
3

Adam Furmanek's blog has the simplest and best work around. This goes something like this below. If you want to see how to pass in parameters for that, you can see that https://samtran.me/2020/02/09/execute-c-code-with-parameters-using-powershell/

$id = get-random
$code = @"
using System;
namespace HelloWorld
{
    public class Program$id
    {
        public static void Main(){
            Console.WriteLine("Hello world again!");
        }
    }
}
"@

Add-Type -TypeDefinition $code -Language CSharp 
Invoke-Expression "[HelloWorld.Program$id]::Main()"
Fandango answered 9/2, 2020 at 3:24 Comment(1)
This will lead to your code unnecessarily recompiling every time with the old results piling up in memory.Warnock
D
1

The simple solution is close Powershell and reopen it. Types you've added with Add-Type will be removed on closing, then run code again.

Diathermic answered 26/7, 2022 at 18:41 Comment(0)
S
1

Instead of

./YourScript.ps1

use this command

powershell.exe -ExecutionPolicy ByPass -Command "./YourScript.ps1"
Sibeal answered 3/12, 2022 at 22:11 Comment(1)
Might you please edit your answer and explain a little how it resolves the problem in the question? As discussed in Explaining entirely code-based answers, it's a lot more helpful to people if your answer also explain why its code works. Thanks!Burkett
C
0

No sure if this meets your requirements but here goes anyway. You can check to see if an assembly is loaded or not and then take action, in the example below I am checking to see if WinSCPnet.dll is already loaded or not:

If ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object Location -Match 'WinSCPnet.dll$')
{
  Write-Host 'Loaded'
} Else {
  Write-Host 'Not Loaded'
}

Bonus:

If you want to list the types available in the assembly:

([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object Location -Match 'WinSCPnet.dll$').GetTypes()

If you want to list members of a specific type in the assembly:

(([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object Location -Match 'WinSCPnet.dll$').GetTypes() | Where-Object Name -EQ 'SessionOptions').GetMembers() #| Format-Table Name, MemberType
Chinua answered 1/8, 2024 at 11:17 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.