Search code examples
powershelldll.net-assemblygacpowershell-cmdlet

Exporting Powershell CMDlets from DLLs loaded by [Reflection.Assembly]::Load()


I have an environment where files cannot be written to disk, and so I usually load DLLs from memory in the GAC.

While loading is not a problem, exposing the DLL Commandlets is. The Assembly is loaded:

[appdomain]::currentdomain.getassemblies() | sort -property fullname | format-table fullname

FullName
--------
AudioDeviceCmdlets, Version=3.0.0.4, Culture=neutral, PublicKeyToken=null

fl *

CodeBase            : file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_64/mscorlib/v4.0_4.0.0.0__b77a5c561934e089/mscorlib.dll
FullName            : AudioDeviceCmdlets, Version=3.0.0.4, Culture=neutral, PublicKeyToken=null
EntryPoint          :
DefinedTypes        : {CoreAudioApi.AudioEndpointVolume, CoreAudioApi.AudioEndpointVolumeCallback, CoreAudioApi.AudioEndpointVolumeChannel, CoreAudioApi.AudioEndpointVolumeChannels...}
Evidence            : {<System.Security.Policy.Url version="1">
                      <Url>file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_64/mscorlib/v4.0_4.0.0.0__b77a5c561934e089/mscorlib.dll</Url>
                      </System.Security.Policy.Url>
                      , <System.Security.Policy.Zone version="1">
                      <Zone>MyComputer</Zone>
                      </System.Security.Policy.Zone>
                      }
PermissionSet       : {}
SecurityRuleSet     : Level2
ManifestModule      : AudioDeviceCmdlets.dll
ReflectionOnly      : False
Location            :
ImageRuntimeVersion : v4.0.30319
GlobalAssemblyCache : False
HostContext         : 0
IsDynamic           : False
EscapedCodeBase     : file:///C:/WINDOWS/Microsoft.Net/assembly/GAC_64/mscorlib/v4.0_4.0.0.0__b77a5c561934e089/mscorlib.dll
ExportedTypes       : {CoreAudioApi.AudioEndpointVolume, CoreAudioApi.AudioEndpointVolumeChannel, CoreAudioApi.AudioEndpointVolumeChannels, CoreAudioApi.AudioEndpointVolumeNotificationDelegate...}
IsFullyTrusted      : True
CustomAttributes    : {[System.Runtime.CompilerServices.CompilationRelaxationsAttribute((Int32)8)], [System.Runtime.CompilerServices.RuntimeCompatibilityAttribute(WrapNonExceptionThrows = True)],
                      [System.Diagnostics.DebuggableAttribute((System.Diagnostics.DebuggableAttribute+DebuggingModes)2)], [System.Reflection.AssemblyTitleAttribute("AudioDeviceCmdlets")]...}
Modules             : {<unknown>}

..but the CMDLets are not exported.. of course I'm surely missing something.

The same DLL, loaded in the 'regular' way:

load-module AudioDeviceCmdlets.dll

correctly exports several CmdLets, like Get-AudioDevice and Set-AudioDevice.

Any hint on what steps I'm missing to expose the Cmdlets in the dll?


Solution

  • while it seems very rude, (and I'm still open to better answers!) this works:

    1) Select the first instance of the available Assembly (as there could be more than one, or be more specific in finding the one you want to load):

    $Assembly=([System.AppDomain]::CurrentDomain.GetAssemblies()|? FullName -Match "AudioDeviceCmdlets")[0]
    

    2) Import the assembly using Import-Module but, instead of specifying the dll to load, reference the Assembly directly. Without a manifest, it will default to exporting all the variables and all the functions therein

    Import-Module -Assembly $Assembly
    

    Voila, now the Commandlets are correctly exported! :)