Creating powershell modules from multiple files, referencing with module

后端 未结 3 670
轻奢々
轻奢々 2021-02-19 16:04

I creating a PowerShell script module using separate source files. What is the canonical way to reference source functions internal to the module from other internal source fil

相关标签:
3条回答
  • 2021-02-19 16:17

    @Ryan I similarly assumed that dot sourcing wasn't the best choice here, but I'm not so sure anymore. I've used the NestedModules approach as well, but have run up against a specific problem. I've asked the question here: PowerShell module, call function in NestedModule from another NestedModule

    In summary I find that the PrimaryModule can call any function in any NestedModule. But one NestedModule is not able to call a function in another NestedModule.

    Splitting your code out into many logical files is Developer 101 basics. So I'm really surprised there isn't a standard way of handling this.

    Any help here much appreciated. Please read the linked question, it gives plenty of detail. Is the consensus that dot sourcing has to be used? Because I'm finding the module manifest way of splitting out the code very limiting.

    0 讨论(0)
  • 2021-02-19 16:25

    Since I recently had to do this myself, I am sharing my solution. I have recently started grouping functions in psm1 files. These can be compiled into a single module with a single 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 a single 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 is not exposed in the imported module as it is excluded from the FunctionsToExport parameter so Write-FooBarBaz will error (intentional to show behavior).
    PS C:\LWC\scripting-misc\module-manifest-multiple-files-example> Write-FooBar
    FooBar
    

    What you're left with 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
    

    Addendum - I expanded on this answer in another question - here:

    https://stackoverflow.com/a/56171985/7710456

    0 讨论(0)
  • 2021-02-19 16:40

    I've personally followed the practice laid out by RamblingCookieMonster in his blog here: http://ramblingcookiemonster.github.io/Building-A-PowerShell-Module/

    Which is to organise your functions in to separate .ps1 files under sub-folders \Public and \Private. Public contains the functions the user should be able to call directly, Private is the functions internal to PowerShell.

    Then in the .psm1 file you load the functions via a loop and dot sourcing as follows:

    #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

    You should then also explicitly list your Public function names in your .psd1 module manifest file under the FunctionsToExport setting. Doing this allows these functions to be discoverable and the module to be auto-loaded when they are used.

    0 讨论(0)
提交回复
热议问题