2

I would like to use a .NET Framework class inside a PowerShell script. I've searched and read that it should be possible. What I have tried is the following:

Add-Type -AssemblyName System.Resources
$resx = New-Object [System.Resources.ResXResourceWriter];

But doing so throws an exception:

New-Object : Cannot find type [[System.Resources.ResXResourceWriter]]: verify
that the assembly containing this type is loaded.
At C:\temp\Translation\import_translation.ps1:41 char:25
+ ...             $resx = New-Object [System.Resources.ResXResourceWriter];
+                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

The assembly does not appear to be found, even though I'm loading it using the Add-Type command above. How can I use .NET Framework classes in PowerShell?

2
  • Aside from the primary problem of including the enclosing [...] in the New-Object call, there are two additional problems: (a) The type of interest is in the System.Windows.Forms assembly (Add-Type -AssemblyName System.Windows.Forms), and (b) the type of interest doesn't have a parameter-less constructor. Commented Sep 24, 2019 at 13:28
  • I'm also curious why Add-Type -AssemblyName System.Resources didn't result in an error, given that no such assembly is normally in the GAC. Commented Sep 24, 2019 at 13:41

1 Answer 1

1

tl;dr:

Note: In addition to the primary problem shown below, there are two additional problems:
* It is the System.Windows.Forms.dll assembly that contains the type of interest, so the Add-Type command should be: Add-Type -AssemblyName System.Windows.Forms; add -Passthru to see what types are being loaded.
* Type [System.Resources.ResXResourceWriter] does not have a parameter-less constructor; run [System.Resources.ResXResourceWriter]::new (without ()) to see the available constructor overloads; see bottom section.

Your primary problem:

Instead of:

$resx = New-Object [System.Resources.ResXResourceWriter] # WRONG, due to [...]

use:

$resx = New-Object System.Resources.ResXResourceWriter  # OK - no [...]

Alternatively, in PSv5+:

$resx = [System.Resources.ResXResourceWriter]::new() # OK

When you pass [System.Resources.ResXResourceWriter] as an argument to a command, it is treated verbatim, not as a type literal - and a type whose full name is literally [System.Resources.ResXResourceWriter], with the enclosing [ and ], doesn't exist.

The reason is that command arguments are parsed in argument mode, where [ has no special meaning as the 1st char. of an argument.

See this answer for an overview of how (unquoted) tokens are parsed in argument mode.

While you can force a token to be interpreted as an expression by enclosing it in (...) - ([System.Resources.ResXResourceWriter]), in this case - that just creates extra work, because the type literal is converted back to a string when the value is bound to the New-Object's -TypeName parameter.

PowerShell v5 introduced the static ::new() method that you can call on type literals in expression mode in order to invoke constructors with the method syntax, analogous to how you call methods in C#, as shown above.

Calling ::new without () is also a convenient way to list the available constructor overloads, i.e. to see what constructor variants with what parameters the type supports; e.g.:

Add-Type -AssemblyName System.Windows.Forms
[System.Resources.ResXResourceWriter]::new

yields:

OverloadDefinitions
-------------------
System.Resources.ResXResourceWriter new(string fileName)
System.Resources.ResXResourceWriter new(string fileName, System.Func[type,string] typeNameConverter)
System.Resources.ResXResourceWriter new(System.IO.Stream stream)
System.Resources.ResXResourceWriter new(System.IO.Stream stream, System.Func[type,string] typeNameConverter)
System.Resources.ResXResourceWriter new(System.IO.TextWriter textWriter)
System.Resources.ResXResourceWriter new(System.IO.TextWriter textWriter, System.Func[type,string] typeNameConverter)

For instance, to call the 2nd overload from the list above, you'd using something like (using bogus arguments):

[System.Resources.ResXResourceWriter]::new('c:\tmp\foo', {})
Sign up to request clarification or add additional context in comments.

3 Comments

@developer82: Using the usual method syntax, similar to C#; please see my update.
Do that returns a null object while using New-Object returns an object
@developer82: No, both New-Object and ::new() return the newly constructed instance; try Add-Type -AssemblyName System.Windows.Forms; [System.Resources.ResXResourceWriter]::new('c:\tmp\foo', {}).GetType().FullName

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.