Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Building a PowerShell Module Inception-Style

Posted on December 17, 2021December 17, 2021

Over the course of the last week or so, I've been sharing PowerShell functions and scripts for working with PowerShell functions and scripts. I showed PowerShell functions to export functions to a script file and code to convert scripts to functions It has all been very Inception-like. To wrap this all up I thought I'd share a PowerShell script I wrote to convert all of the code I've been sharing into a new module. I will eventually publish PSFunctionTools to the PowerShell Gallery and I see no reason why it won't work in Windows PowerShell or PowerShell 7. Even cross-platform.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

The script might even be the basis for an additional function. Or I might include it as a reference sample in the new module. What is mind-bending to me is that I am using the functions in the code on themselves to create something new. I don't expect you to be able to run this script since it is written for my environment and files. I've posted all of the code over the last week, but my files may be different than yours.

This script is based on the one I posted as a proof-of-concept for converting scripts into a PowerShell module. My script will also initialize the new project in git and generate initial help documentation using the Platyps module.

#requires -version 5.1
#requires -module Platyps

#Export functions from files and create a new module

[cmdletbinding(SupportsShouldProcess)]
Param(
    [Parameter(position = 0,HelpMessage = "What is the name of the new module?")]
    [ValidateNotNullOrEmpty()]
    [string]$NewModuleName = "PSFunctionTools",

    [Parameter(Position = 1,HelpMessage = "What is the parent path for the new module?")]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Path $_})]
    [string]$ParentPath = "C:\Scripts",

    [Parameter(HelpMessage = "Enter an module description.")]
    [string]$Description = "A set of PowerShell commands for working with PowerShell scripts and functions.",

    [Parameter(HelpMessage ="PowerShell script files with functions to export.")]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Path $_})]
    [string[]]$Files = $(
        'C:\scripts\Convert-FunctionToFile.ps1',
        'C:\scripts\new-folderlayout.ps1',
        'C:\scripts\dev-scripttofunction.ps1'
        )
)

Write-Verbose "Starting $($MyInvocation.MyCommand)"

<#
dot source the conversion functions

C:\scripts\Convert-FunctionToFile.ps1
  Test-FunctionName
  Get-FunctionName
  Get-FunctionAlias
  Export-FunctionFromFile
C:\scripts\New-FolderLayout.ps1
  Import-ModuleLayout
  Export-ModuleLayout
#>
. C:\scripts\Convert-FunctionToFile.ps1
. C:\scripts\New-FolderLayout.ps1

#the new module location
$path = Join-path -Path $ParentPath -ChildPath $NewModuleName
$export = [System.Collections.Generic.list[object]]::New()
$aliases = @()
#the layout was created using Export-ModuleLayout
$layout = "C:\scripts\ModuleLayout.json"
Write-Verbose "Creating the module structure"
Import-ModuleLayout -Name $NewModuleName -ParentPath $ParentPath -Layout $layout

#I removed the parameter validation on the target path
$functionFiles = $files | ForEach-Object {
    Write-Verbose "Processing $_"
    Export-FunctionFromFile -Path $_ -OutputPath $Path\functions\public -All -Passthru
    #get aliases
    if ($pscmdlet.ShouldProcess($_,"Getting function aliases")) {
        $aliases += Get-FunctionAlias -path $_ | Select-Object -ExpandProperty alias
    }
}

if ($functionFiles) {
    $export.AddRange($functionFiles.baseName)
}

#create the root module
$psm1 = @"

Get-Childitem `$psscriptroot\functions\*.ps1 -recurse |
Foreach-Object {
. `$_.FullName
}

"@
Write-Verbose "Creating root module $path\$newmodulename.psm1"
$psm1 | Out-File "$path\$newmodulename.psm1"

#create the module manifest
$splat = @{
    Path                 = "$path\$newmodulename.psd1"
    RootModule           = "$newmodulename.psm1"
    ModuleVersion        = "0.1.0"
    Author               = "Jeff Hicks"
    CompanyName          = "JDH Information Technology Solutions, Inc."
    Copyright            = "(c) 2021 JDH Information Technology Solutions, Inc."
    Description          = $Description
    CmdletsToExport      = @()
    VariablesToExport    = @()
    FunctionsToExport    = $Export
    AliasesToExport      = $aliases
    PowerShellVersion    = "5.1"
    CompatiblePSEditions = "Desktop","Core"
}
Write-Verbose "Creating module manifest $($splat.path)"
New-ModuleManifest @splat

#this requires the Platyps module
Write-Verbose "Creating module help files"
if ($PSCmdlet.ShouldProcess("docs","create markdown help files")) {
    Import-Module $splat.path
    New-MarkdownHelp -Module $NewModuleName -OutputFolder $path\docs
    New-ExternalHelp -Path $path\docs -OutputPath $path\en-us
}

Write-Verbose "Initializing git"
if ($PSCmdlet.ShouldProcess($path, "git initialize")) {
    Set-Location $path
    git init
    git add .
    git commit -m "initial files"
    git checkout -b $splat.ModuleVersion
}

if (-not $WhatIfPreference) {
    Get-ChildItem $path -Recurse
    Try {
        [void](Get-Command -name code.cmd -ErrorAction stop)
        Write-Verbose "Opening module in VSCode"
        code $path
    }
    Catch {
        Write-Warning "VS Code not found."
    }
}

Write-Verbose "Ending $($MyInvocation.MyCommand)"

I've parameterized the script with the idea that I can turn this into a reusable tool. But for now, the parameter values are hard-coded to save me typing.

The script has several phases. First, it creates the module structure using the command I shared to export and import a model module directory structure. Second, the script takes the array of files and exports all of the functions to separate files. Third, it creates a root module, and the module manifest using information from the exported functions. Next, the script creates help documentation and finally initializes git. If I'm not running the script with -WhatIf, the new module will be opened in VSCode.

new-psfunctiontoolsmodule script with -Whatif

I've already run this script and started working on the module, but I wanted you to see the output so this is using a temporary folder and -Whatif.

new module in vs code

Here you can see the results in VSCode. The entire process took about 3 seconds. I definitely will be developing this idea and using it myself. I often start with standalone script files that eventually I decide to turn into modules. It will be nice to have a set of tools to accelerate that process.

In the meantime, feel free to use any of the code I've shared to build your own PowerShell tooling for building PowerShell tooling.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

1 thought on “Building a PowerShell Module Inception-Style”

  1. Pingback: Building a PowerShell Module Inception-Style - The Lonely Administrator - Syndicated Blogs - IDERA Community

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d