When a module is divided in this manner, the root module must contain everything required to load the module content. This is most often achieved by dot-sourcing each of the files in the sub-folders adjacent to the root module. One possible way to do this is to use Get-ChildItem to find all of the ps1 files beneath a certain point and dot-source those.
The following snippet uses this approach:
Get-ChildItem (Join-Path $psscriptroot 'private') {
. $_.FullName
}
$functionsToExport = Get-ChildItem (Join-Path $psscriptroot 'public') {
. $_.FullName
$_.BaseName
}
Export-ModuleMember -Function $functionsToExport
The snippet assumes Export-ModuleMember is to be used, and that the manifest has FunctionsToExport set to *. As the files are named after the functions, the BaseName property of each item is used to build an array of functions to pass to Export-ModuleMember.
The disadvantage of this approach is that it loads all ps1 files without further consideration. Any additional files dropped into the module will load as well. While a module is undergoing development, this behavior may be desirable, but it represents a small risk for anyone installing the module.
An alternative, but higher-maintenance, approach, is to name the files to import instead of allowing any file at all to load. For example:
$private = 'GetRegistryValueInfo'
$public = @(
'Get-ComputerDescription'
'Remove-ComputerDescription'
'Set-ComputerDescription'
)
foreach ($item in $private) {
. '{0}private{1}.ps1' -f $psscriptroot, $item
}
foreach ($item in $public) {
. '{0}public{1}.ps1' -f $psscriptroot, $item
}
Export-ModuleMember -Function $public
With this version, module content is loaded with an explicit name. Additional files that are erroneously placed in the module folder will not be processed.