Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of the *.psm1 files in a Powershell module?

So I implemented my first Powershell module with a bunch of .ps1 files (one per function) and the .psd1 manifest file.

I am trying to understand what is the purpose of the .psm1 files - do I need them at all in my module?

What is their added value?

EDIT 1

Here is my .psd1 file:

@{
    ModuleVersion = "0.0.19106.59054"
    GUID = "59bc8fa6-b480-4226-9bcc-ec243102f3cc"
    Author = "..."
    CompanyName = "..."
    Copyright = "..."
    Description = "..."
    ScriptsToProcess = "vsts\config.ps1"
    VariablesToExport = @(
        "TfsInstanceUrl",
        "TfsApiVersion",
        "QANuGetRepoUrl"
    )
    NestedModules = @(
        "db\Backup-Database.ps1",
        ...
        "vsts\work\Get-WorkItems.ps1"
    )
    FunctionsToExport = @(
        "Assert-ExtractionDestFolder",
        ...
        "Write-HostIfNotVerbose"
    )
    PrivateData = @{
        PSData = @{
            ExternalModuleDependencies = "SqlServer"
        }
    }
}

Like I said, each function is in its own file.

like image 690
mark Avatar asked Apr 27 '19 02:04

mark


2 Answers

what is the purpose of the .psm1 files - do I need them at all in my module?

  • In script modules, i.e., modules authored in PowerShell (as opposed to compiled binary cmdlets), it is only *.psm1 files that provide the module-specific behaviors distinct from regular *.ps1 script files (separate, isolated scope, private commands, control over exported commands).

    • Typically, a script module manifest has a RootModule entry pointing to (the main) *.psm1 file; for smaller modules it is not uncommon for all of the module's functionality to be implemented in this one *.psm1 file.

      • In fact, a stand-alone *.psm1 file can also act as a module, though it doesn't integrate with PowerShell's module auto-discovery and auto-loading feature.

      • Note that if you were to use a regular *.ps1 script directly in RootModule, its definitions would be loaded into the caller's scope, not the module's; that is, you would lose the benefits of a module.

  • Even though you're listing regular *.ps1 scripts in your NestedModules manifest entry, by virtue of using that specific entry these scripts are dot-sourced in the module's context and thereby become part of the module:

    • This is conceptually equivalent to creating and referencing a root *.psm1 script in RootModule, and - instead of defining a NestedModules entry - explicitly dot-sourcing your *.ps1 scripts from there - see bottom section.

    • Note that if you were to reference *.psm1 files in NestedModules, they would truly become nested modules, with their own scopes; a nested module is usable from the enclosing module, but not visible to the outside world (though you can list it among the loaded modules with Get-Module -All).


Listing *.ps1 files in NesteModules vs. dot-sourcing them from the RootModule

While there should be no difference in functionality, using a *.psm1 RootModule to dot-source the *.ps1 files containing your module's functions can potentially simplify things, if you simply need to dot-source all *.ps1 files located in your module directory's subtree:

# Add this to the *.psm1 file specified in 'RootModule'

# Find all *.ps1 files in the module's subtree and dot-source them
foreach ($script in 
  (Get-ChildItem -File -Recurse -LiteralPath $PSScriptRoot -Filter *.ps1)
) { 
  . $script 
}

If you need to load the scripts in a specific order, need only a subset of the scripts, or want to speed things up slightly (though I doubt that the speed difference will be noticeable), you can dot-source the files individually from a RootModule *.psm1 file, as an alternative to listing them in the NestedModules entry:

# Add this to the *.psm1 file specified in 'RootModule'

# Dot-source the *.ps1 files individually.
. "$PSScriptRoot/db/Backup-Database.ps1"
# ...
. "$PSScriptRoot/vsts/work/Get-WorkItems.ps1"

Again, all of the above approaches are functionally equivalent. Given that you explicitly export functions via the ExportedFunctions entry (as is advisable), the use of *.ps1 files that must be dot-sourced is ultimately an implementation detail that is not relevant for the purposes of command discovery and module auto-loading - it only matters at actual import time.

like image 62
mklement0 Avatar answered Oct 05 '22 13:10

mklement0


.psm1 file is powershellmodule file. When we create script module we write all the functions of a module in a .psm1 file then we export the functions and then we can use those functions by importing module. .psm1 is basically refers the powershellmodule. Powershell directly identifies anything which is written in this file will be a part of module.

like image 40
Dharmesh Purohit Avatar answered Oct 05 '22 13:10

Dharmesh Purohit