Stroniax
Stroniax

Reputation: 860

PowerShell Types.ps1xml Can't Find Type When Importing Module

I'm having trouble importing a module that contains a manifest, binary (root module), and a type file that defines a type converter or code property that references a type identified in the binary.

When I try to import the module, I can see from verbose output that the types files are loaded before the binary module's classes are imported:

VERBOSE: Loading module from path '...\bin\Debug\Module\manifest.psd1'.
VERBOSE: Loading 'TypesToProcess' from path '...\bin\Debug\Module\Type.PS1XML'.

Before the root module is loaded, I get the following error:

Import-Module : The following error occurred while loading the extended type data file: , ...\bin\Debug\Module\Type.PS1XML(64) :
Error: Unable to find type [MyRootModule.MyItemConverter].
At line:1 char:128
+ ... odule\Manifest.psd1 | Import-Module -verbose ; $Debu ...
+                                            ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Import-Module], RuntimeException
    + FullyQualifiedErrorId : FormatXmlUpdateException,Microsoft.PowerShell.Commands.ImportModuleCommand

The question is, how can I load types after the root module is imported (without turning the entire module into a script that loads everything by calling Import-Module and Update-TypeData for every item in the module directory)? Or what other way would I have to get around this error and import the module and types at the same time?

Here's a quick example. This module (concocted on-the-spot as an example only) has the following items:

module\manifest.psd1

module\root.dll

module\type.ps1xml

This is the content of root.dll

namespace MyRootModule {
  public class MyTestItem {
    public string Name {get; set;}
    public int Id {get; set;}
  }
  public class MyItemConverter : PSTypeConverter {
    // code omitted for brevity
    // effectively creates a 'MyTestItem' with id '1' for string input 'one', and vice versa.
  }
}

This is the relevant content of manifest.psd1

@{
RootModule = 'root.dll'
TypesToProcess = 'type.ps1xml'
}

This is the content of type.ps1xml

<?xml version="1.0" encoding="utf-8" ?>
<Types>
  <Type>
    <Name>MyRootModule.MyTestItem</Name>
    <TypeConverter>
      <TypeName>MyRootModule.MyItemConverter</TypeName>
    <TypeConverter>
  </Type>
</Types>

If I load the binary module first, and then force-load the manifest or use update-typedata -PrependPath $pathToTypeFile, everything works and I can use the converter as I'd expect to be able to (i.e. [MyRootModule.MyTestItem]1 returns a new instance of [MyRootModule.MyTestItem]), which indicates that the problem has nothing to do with the converter itself.

TLDR; The powershell module is loading the types file before the binary, and since a type defined in the binary is not found at that time the import fails.

Upvotes: 2

Views: 671

Answers (1)

Stroniax
Stroniax

Reputation: 860

Took me some time but I'll mark the answer here in case anyone else runs into this problem. There's a member of the module manifest that I had forgotten about/never paid much attention to, RequiredAssemblies. You can mark your dll as a required assembly as well as the root module to import it before types files are loaded. (Note: it still needs listed as the root or a nested module to import cmdlets.)

As an example, updating the manifest listed above to the following fixes the issue:

@{
RootModule = 'root.dll'
TypesToProcess = 'type.ps1xml'
RequiredAssemblies = 'root.dll'
}

Upvotes: 3

Related Questions