12

I've been strugling with this for a while now. I intend to create new PowerShell module for my project. Aim is to package several custom cmdlets into standalone unit, which I could deploy to other machines via our Nexus repository (or via anything else).

Problem: Everywhere I look, I see tutorials packaging all PowerShell functions/cmdlets into single *.psm1 file. File is stored inside equally named directory, which actually represents module itself.

Question: Is there a way, how to separate each cmdlet/function into standalone file? If I have a module consisting of several cmdlets, it's not very convenient to put them all in single *.psm1 file.

Thanks Matthew

Martinecko
  • 1,719
  • 4
  • 22
  • 35

3 Answers3

15

You could also use a manifest file. "A module manifest is a .psd1 file that contains a hash table. The keys and values in the hash table do the following things:

  • Describe the contents and attributes of the module.
  • Define the prerequisites
  • Determine how the components are processed.

Manifests are not required for a module. Modules can reference script files (.ps1), script module files (.psm1), manifest files (.psd1), formatting and type files (.ps1xml), cmdlet and provider assemblies (.dll), resource files, Help files, localization files, or any other type of file or resource that is bundled as part of the module. For an internationalized script, the module folder also contains a set of message catalog files. If you add a manifest file to the module folder, you can reference the multiple files as a single unit by referencing the manifest." (Source)

So you can use ps1 files instead of psm1 files directly from psd1 files:

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 
NestedModules = 'Get-WUList.ps1','Add-WUOfflineSync.ps1'

# Functions to export from this module 
FunctionsToExport = 'Get-WUList','Add-WUOfflineSync'
Johan de Haan
  • 1,010
  • 9
  • 13
  • When you are importing module via cmdlet Import-Module, it needs to be pointed to existing *.psm1 file. Although *.psd1 exists in my directory (it contains metainfo about developer and company) it only provides ability to include/exclude certain cmdlets/functions which exist in module. However, existence of cmdlets/functions in module is determined by their presence in *.psm1 file (whether directly, or via dot-sourcing). Or am I missing some point here? Can you perhaps provide some examples how cmdelets can be included in module via *.psd1 file? :-) – Martinecko Apr 15 '15 at 10:46
  • 2
    You can define `NestedModules ` with the ps1 files, without using a psm1 file: # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess NestedModules = 'Get-WUList.ps1','Add-WUOfflineSync.ps1' # Functions to export from this module FunctionsToExport = 'Get-WUList','Add-WUOfflineSync'` – Johan de Haan Apr 15 '15 at 11:10
  • 1
    I've added my last info to my answer, for future reference. – Johan de Haan Apr 15 '15 at 12:06
  • As an addendum you can use folders in the nested modules property: `NestedModules = 'Credentials\Set-ServiceCredential.ps1','Prod\Restart-ProdServices.ps1'` will load the ps1 files from the folders. You also cannot use wildcards to load the whole folder at once. – hsimah Jan 09 '17 at 01:59
3

Following up on @MatthewLowe - I've made my .psm1 a "one liner" as follows; this seems to work, provided that none of the scriptlets depend on one whose name is alphabetically after itself:

Get-ChildItem -Path $psScriptRoot\*.ps1 | ForEach-Object { . $_.fullname; Export-ModuleMember -Function ([IO.PATH]::GetFileNameWithoutExtension($_.fullname)) }

Jeff Zeitlin
  • 9,773
  • 2
  • 21
  • 33
1

Just posting this answer which I found as I was actually wrinting question itself :-). I downloaded few PowerShell modules from internet and looked inside, I found answer there. But since I got stuck on this for few hours (new to powershell ;-)), I decide to post this anyway, for future generations :-P.

You can put your cmdlets (*.ps1 files) EACH into separate file. Store them inside your module directory and create *.psm1 file. Then, dot-source your *.ps1 cmdlets/functions into this *.psm1.

However, reference to current module directory where your *.ps1 files are stored must be provided like this
". $psScriptRoot/moduleFunc1.ps1" AND NOT LIKE ". ./moduleFunc1.ps1"

Enjoy Matthew

Martinecko
  • 1,719
  • 4
  • 22
  • 35