Creating powershell modules from multiple files, module link
I am creating a PowerShell script module using separate source files. What is the canonical way of referencing source functions embedded in a module from other internal source files?
For example, if my module is built from PS source in files "foo" and "bar"; and the function in "foo" should call the function in "bar", what's the best way to do this?
It doesn't look like dot-search would be a good idea. Also, the component files ("foo" and "bar") of psm1 files are not created. Is this idea the "ScriptsToProcess" field in the psd1 file?
Am I thinking about this the wrong way (not "PowerShelly")? Should I just dump everything into one psm1?
source to share
I personally followed the practice outlined by RamblingCookieMonster on his blog here: http://rabingcookiemonster.github.io/Building-A-PowerShell-Module/
Which should organize your functions into separate .ps1 files in subfolders \Public
and \Private
. Public contains functions that the user should be able to call directly, Private contains functions internal to PowerShell.
Then in the .psm1 file, you load the functions through a loop and dot search like this:
#Get public and private function definition files.
$Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue )
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue )
#Dot source the files
Foreach($import in @($Public + $Private))
{
Try
{
. $import.fullname
}
Catch
{
Write-Error -Message "Failed to import function $($import.fullname): $_"
}
}
# Here I might...
# Read in or create an initial config file and variable
# Export Public functions ($Public.BaseName) for WIP modules
# Set variables visible to the module and its functions only
Export-ModuleMember -Function $Public.Basename
- Source of this example: https://github.com/RamblingCookieMonster/PSStackExchange/blob/db1277453374cb16684b35cf93a8f5c97288c41f/PSStackExchange/PSStackExchange.psm1
Then you must also explicitly list the names of your public functions in the module manifest file .psd1 in the setup FunctionsToExport
. This allows these functions to be detected and automatically loaded when the module is used.
source to share
Since I recently had to do this myself, I am sharing my solution. I recently started to group functions in PSM1 files. They can be collected into one module with one manifest.
This allows me to have groups of functions that can be packaged with multiple modules.
Write-BarFunctions.psm1
Function Write-Bar {
return "Bar"
}
Function Write-Baz {
return "Baz"
}
Write-FooFunctions.psm1
Function Write-Foo {
return "Foo"
}
Function Write-FooBar {
$foo = Write-Foo
$bar = Write-Bar
return ("{0}{1}" -f $foo, $bar)
}
Function Write-FooBarBaz {
$foobar = Write-FooBar
$baz = Write-Baz
return ("{0}{1}" -f $foobar, $baz)
}
Which are combined into one module like this: (formatted for readability)
New-ModuleManifest
-Path .\Write-FooBarBazCombos
-NestedModules @('.\FooFunctions\Write-FooFunctions.psm1', '.\BarFunctions\Write-BarFunctions.psm1')
-Guid (New-Guid)
-ModuleVersion '1.0.0.0'
-Description 'demonstrate multiple psm1 files as 1 powershell module with 1 powershell module manifest'
-PowerShellVersion $PSVersionTable.PSVersion.ToString()
-FunctionsToExport @('Write-Foo', 'Write-Bar','Write-FooBar', 'Write-FooBarBaz')
PowerShell output:
PS C:\LWC\scripting-misc\module-manifest-multiple-files-example> New-ModuleManifest -Path .\Write-FooBarBazCombos.psd1
-NestedModules @('.\Write-FooFunctions.psm1', '.\Write-BarFunctions.psm1') -Guid (New-Guid) -ModuleVersion '1.0.0.0' -D
escription 'demonstrate multiple psm1 files as 1 powershell module with 1 powershell module manifest' -PowerShellVersio
n $PSVersionTable.PSVersion.ToString() -FunctionsToExport @('Write-Foo', 'Write-Bar','Write-FooBar', 'Write-FooBarBaz')
PS C:\LWC\scripting-misc\module-manifest-multiple-files-example> Import-Module .\Write-FooBarBazCombos.psd1
PS C:\LWC\scripting-misc\module-manifest-multiple-files-example> Get-Command -Module Write-FooBarBazCombos
CommandType Name Version Source
----------- ---- ------- ------
Function Write-Bar 1.0.0.0 Write-FooBarBazCombos
Function Write-Foo 1.0.0.0 Write-FooBarBazCombos
Function Write-FooBar 1.0.0.0 Write-FooBarBazCombos
Function Write-FooBarBaz 1.0.0.0 Write-FooBarBazCombos
- note that Write-Baz does not appear in the imported module because it is excluded from the FunctionsToExport parameter, so Write-FooBarBaz will throw an error (intentionally to display behavior).
PS C:\LWC\scripting-misc\module-manifest-multiple-files-example> Write-FooBar
FooBar
What you left in the directory:
PS C:\LWC\scripting-misc\module-manifest-multiple-files-example> Get-ChildItem | Select-Object Name
Name
----
Write-BarFunctions.psm1
Write-FooBarBazCombos.psd1
Write-FooFunctions.psm1
Appendix - I've expanded on this answer in another question - here:
source to share
@Ryan I also assumed that point search was not the best choice, but I'm not sure anymore. I also used the NestedModules approach but ran into a specific problem. I asked a question here: PowerShell module, call a function in a NestedModule from another NestedModule
I ended up finding that PrimaryModule can call any function in any NestedModule. But one NestedModule cannot call a function in another NestedModule.
Dividing your code into many logical files is the basics of Developer 101. So I am very surprised that there is no standard way to handle this.
Any help here is greatly appreciated. Please read the linked question, it gives a lot of details. Do you have to agree to use a point source? Because I find the manifest module way of splitting code very limiting.
source to share