I understand the difference between functions and cmdlets. This question is about the practical implications of when to declare a function in one or the other group of a powershell manifest file (psd1).
FunctionsToExport = @(
    'Get-BuildInformation'
)
CmdletsToExport @(
    'Get-BuildInformation'
)
One thing I noticed is that on importing a module, comment based help does not work if the cmdlet is only declared in CmdletsToExport - it has to be declared in FunctionsToExport. Should I be adding to both arrays? What am I getting by adding to CmdletsToExport?
Functions - i.e. units of functionality written in and executed by PowerShell - and (binary) cmdlets - i.e. units of functionality created by up-front compilation of (typically) C# code into .NET assemblies - are technically distinct command forms, and must be referenced separately in a module manifest.
When a caller imports a module - whether explicitly via Import-Module or implicitly via module auto-loading - that has a manifest, functions and cmdlets are only imported if they're referenced in the command form-appropriate manifest entry, i.e. FunctionsToExport and CmdletsToExport, respectively.
Mistakenly referencing a function in CmdletsToExport or vice versa is quietly ignored, though note that a module's functions / cmdlets may still be imported, namely if the FunctionsToExport / CmdletsToExport entry is either missing or set to * (neither is recommended, for performance reasons).
Use the -Verbose switch with Import-Module to see which functions and cmdlets (and possibly also aliases and variables) are in effect imported from a given module: look for the (final) block of lines that look like VERBOSE: Importing <command-form> <name>, e.g. VERBOSE: Importing function Get-BuildInformation
Note:
It is only the last or only block of verbose Importing ... lines that reflect what is actually imported, as detailed below.
Exporting ... lines alone do not guarantee import, because the module import process has two stages:
First, the set of candidate import elements is determined, as implied by the .psm1 module / a referenced assembly (.dll) containing cmdlets.
In a .psm1 (script) module, all functions and aliases are exported by default, unless constrained (or expanded to include variables)  by an explicit call to Export-ModuleMember.
Exporting ... lines (requested via -Verbose or via $VerbosePreference = 'Continue').In a .dll (binary) module, it is invariably all contained cmdlets that are candidate elements, i.e. all public classes that derive (ultimately) from the System.Management.Automation.Cmdlet base class.
In a hybrid module - one who combines a script module with binary modules - the resulting candidate cmdlets are - unfortunately and confusingly - reflected in verbose Importing ... lines, albeit in a separate block that precedes the Loading module from path '.../*.psm1' line, which is (eventually) followed by another block of Importing ... lines, which are the ones that matter - see below.
In a binary-only module, no verbose lines reflecting the candidate cmdlets are emitted.
Then, the set of candidate elements is typically constrained further for actual import, based on the relevant entries in the module manifest file (.psd1).
It is this constrained set of actual import elements that is reflected in the last or only block of verbose Importing ... lines.
As noted, referencing an element in the wrong entry (e.g. referencing a function in CmdletsToExport) is quietly ignored.
If you were to bypass a module's .psd1 file by importing a .psm1 or .dll file directly, it is the candidate elements that would directly become the effectively imported elements.
However, using a full-fledged module (one that lives in its own directory and includes a manifest file (.psd1)) is always advisable, for two reasons:
It allows you to associate metadata, notably a version number, with your module.
(Preferably) explicitly enumerating all exported elements in the manifest not only allows you to select the desired subset of candidate elements to export/import, but also helps speed up PowerShell's module discovery, which, notably, the module auto-loading feature is built on.
* is discouraged.As far as I can tell, none of this is related to comment-based help, which inherently only applies to functions and script files.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With