Reputation: 178
I'm working on a Quick Module CLI builder. The idea is you have my Module, which has commands like Add-QuickFunction, Add-QuickAlias, New-QuickModule, Remove-QuickCommand, etc.
As you build out the functions, your Modules continue to get built out. The plan is to create an Export-QuickModule and Export-QuickModule command, so that when you're ready to Export your module it's ready to be published, to your organization, or to a public gallery.
So the problem is two-fold.
PS C:\WINDOWS\system32> Get-Module -Name QuickModuleCLI
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.1.3 QuickModuleCLI {New-QuickModule, Update-QuickModule}
Notice how it only includes 2 Exported commands. This is after I manually added Export-ModuleMember to my local system. Without having Export-ModuleMember, only New-QuickModule appears as exported.
But compare it to the actual list of Commands:
PS C:\WINDOWS\system32> Get-Command -Module QuickModuleCLI
CommandType Name Version Source
----------- ---- ------- ------
Function Add-QuickAlias 0.1.3 QuickModuleCLI
Function Add-QuickFunction 0.1.3 QuickModuleCLI
Function ConvertTo-PowershellEncodedString 0.1.3 QuickModuleCLI
Function Edit-QuickCommand 0.1.3 QuickModuleCLI
Function New-QuickModule 0.1.3 QuickModuleCLI
Function Remove-QuickCommand 0.1.3 QuickModuleCLI
Function Rename-QuickCommand 0.1.3 QuickModuleCLI
Function Reset-QuickCommand 0.1.3 QuickModuleCLI
Function Set-Env 0.1.3 QuickModuleCLI
Function Update-QuickModule 0.1.3 QuickModuleCLI
What this means is, after opening a new session, I see the following:
PS C:\WINDOWS\system32> Write-Test
Write-Test : The term 'Write-Test' 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.
At line:1 char:1
+ Write-Test
+ ~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Write-Test:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\WINDOWS\system32> Import-Module QuickModuleCLI
PS C:\WINDOWS\system32> Write-Test
Hello
I use a dynamic self-rolled PowerShell generator to update the psd1 file and add to the FunctionsToExport. You can verify that when I Import-Module, it calls the NestedModules and imports it properly. However, on the computer I use to develop this Module in, I don't need to Import-Module in order for Write-Test to appear in my PowerShell Options. Is this an environmental thing that I have to just "deal with" or is this something you that can be fixed?
The code can be found here: https://github.com/EdLichtman/QuickModuleCLI And you can try it out yourself with Import-Module QuickModuleCLI
Upvotes: 2
Views: 1443
Reputation: 178
So to follow up on part 2, it turns out the reason why is related to, in fact it's exactly the same behavior described in this answer:
Invoking functions from nested modules in a script module do not always trigger a module to autoload
My workaround was to add to the FunctionsToExport list, the functions within the NestedModules. Initially I did not think I could export functions that were not directly part of the parent module.
Upvotes: 0
Reputation: 10125
Part 1 - ExportedCommands
Here's a minimal repro for your issue with the ExportedCommands
list not matching the result from Get-Command
. I distilled it down to this by progressively removing chunks of code from your repo at https://github.com/EdLichtman/QuickModuleCLI until there was nothing left to remove:
MyModule.psd1
@{
RootModule = "MyModule.psm1"
ModuleVersion = "0.1.4"
FunctionsToExport = @(
"Add-MyAlias",
"New-MyModule"
)
}
MyModule.psm1
function global:Add-MyAlias {
write-host "global:Add-MyAlias"
}
function New-MyModule {
write-host "New-MyModule"
}
Interactive
PS> Import-Module .\MyModule\MyModule.psd1 -Force
PS> Get-Module MyModule
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.1.4 MyModule New-MyModule
PS> Get-Command -Module MyModule
CommandType Name Version Source
----------- ---- ------- ------
Function Add-MyAlias 0.1.4 MyModule
Function New-MyModule 0.1.4 MyModule
I don't know what the exact implication is when you use global:
on an exported function (I'm assuming the function gets imported into the global
scope rather than the module scope), but if you remove global:
the function will suddenly appear in the ExportedCommands
list again:
Part 2 - Importing Modules
PowerShell has a feature that will cause it to search for unknown commands in a set of predefined folder locations. This is called "Module Auto-Loading" and you can enable or disable the feature using the $PSModuleAutoLoadingPreference
variable as per About Preference Variables (hint: it's enabled by default).
The locations it searches are defined in an environment variable PSModulePath
- see About PSModulePath.
If you want the commands in your module to be discoverable and auto-loaded on first invocation, either install your module in one of the paths already added to the PSModulePath
environment variable, or add your module's location to the path.
Upvotes: 2