PowerShell does not allow binary modules in form of an .EXE assembly file. We have a .NET .exe module that apart from other things contains a few powershell cmdlets. Sometimes I want to load this module into a standard PS host. Currently I cannot. I've tried 2 ways I'm aware of, and both do not work.
Is far as I know there are not technical reason that should prevent me from using .net .exe assembly as .dll assembly. If I rename the file to .dll it works.
Way 1: Bare module file
Import-Module .\MyModule.exe
Way 2: Manifest file
@{ RootModule = 'MyModule.exe'; ModuleVersion = '2.0' }
Import-Module .\MyModule.psd1
It works
Way 1:
Import-Module : The extension '.exe' is not a valid module extension. The supported module extensions are '.dll', '.ps1', '.psm1', '.psd1', '.cdxml' and '.xaml'. Correct the extension then try adding the
file 'C:\Users\User\Workplace\Project1\Debug\MyModule.exe' again.
At line:1 char:1
+ Import-Module .\MyModule.exe
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (:) [Import-Module], InvalidOperationException
+ FullyQualifiedErrorId : Modules_InvalidModuleExtension,Microsoft.PowerShell.Commands.ImportModuleCommand
Ways 2:
Import-Module : Object reference not set to an instance of an object.
At line:1 char:1
+ Import-Module .\MyModule.psd1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Import-Module], NullReferenceException
+ FullyQualifiedErrorId : System.NullReferenceException,Microsoft.PowerShell.Commands.ImportModuleCommand
The call stack:
Object reference not set to an instance of an object.
at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModuleNamedInManifest(PSModuleInfo parentModule, ModuleSpecification moduleSpecification, String moduleBase, Boolean searchModulePath, String prefix, SessionState ss, ImportModuleOptions options, ManifestProcessingFlags manifestProcessingFlags, Boolean loadTypesFiles, Boolean loadFormatFiles, Object privateData, Boolean& found, String shortModuleName)
at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModuleManifest(String moduleManifestPath, ExternalScriptInfo scriptInfo, Hashtable data, Hashtable localizedData, ManifestProcessingFlags manifestProcessingFlags, Version minimumVersion, Version maximumVersion, Version requiredVersion, Nullable`1 requiredModuleGuid, ImportModuleOptions& options, Boolean& containedErrors)
at Microsoft.PowerShell.Commands.ModuleCmdletBase.LoadModule(PSModuleInfo parentModule, String fileName, String moduleBase, String prefix, SessionState ss, Object privateData, ImportModuleOptions& options, ManifestProcessingFlags manifestProcessingFlags, Boolean& found, Boolean& moduleFileFound)
at Microsoft.PowerShell.Commands.ImportModuleCommand.ImportModule_LocallyViaName(ImportModuleOptions importModuleOptions, String name)
at Microsoft.PowerShell.Commands.ImportModuleCommand.ProcessRecord()
at System.Management.Automation.Cmdlet.DoProcessRecord()
at System.Management.Automation.CommandProcessor.ProcessRecord()
> $PSVersionTable
Name Value
---- -----
PSVersion 6.0.0
PSEdition Core
GitCommitId v6.0.0
OS Microsoft Windows 10.0.15063
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Does this module contain cmdlets? If not, then you should really use the AssembliesToProcess field. This will be faster since the module loader won't scan all the types in the assembly looking for cmdlets. Alternatively you can use Add-Type -AssemblyName ... to directly load the module. Hopefully these alternatives will unblock you.
Otherwise, the null pointer exception is definitely a bug that should be fixed. Restricting the set of extensions allowed as RootModule was deliberated and I vaguely recall that we specifically chose to exclude executables but I can't remember why. @khansen00 - do you remember?
@BrucePay Yes, this module contains cmdlets. Below is a minimal module to reproduce this issue
```c#
namespace Module6741
{
[Cmdlet(VerbsCommon.Get, "FooBar")]
public class GetFooBarCmdlet : PSCmdlet
{
protected override void ProcessRecord()
{
WriteObject("FooBar");
}
}
internal class EntryPoint
{
public static void Main(string[] args)
{
}
}
}
```
@BrucePay I see no AssembliesToProcess so I assume you meant RequiredAssemblies manifest field. If I add RequiredAssemblies instead of RootModule the import-module does not crash, but no cmdlets get exported either.
> ipmo .\MyModule.psd1
> Get-Module MyModule
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 1.0 MyModule
@BrucePay The Add-Type -AssemblyName didn't work for as well. Am I doing it wrong?
> Add-Type -AssemblyName "ExeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
> Get-FooBar
Get-FooBar : The term 'Get-FooBar' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is
correct and try again.
@kirillkovalenko Import-Module has an Assembly parameter that takes a System.Reflection.Assembly object. This works for me:
$assembly = [System.Reflection.Assembly]::LoadFrom('Path\To\Module.exe')
Import-Module -Assembly $assembly
Most helpful comment
@kirillkovalenko
Import-Modulehas anAssemblyparameter that takes aSystem.Reflection.Assemblyobject. This works for me: