Module Builder

This module is used to build, update and publish modules.

I have switched my workflow for making modules a few times now, from creating a module from the ground up to having a script put the scaffolding together for the PSD1 and PSM1 files.

Currently I am using a method of compiling separate functions into a module along with creating all of the necessary files, this is by far my favorite way of doing it as it is much easier to work on when the modules get larger and more complicated as everything can be separated at the function level. It can also allow you to separate Public and Private functions, I do not currently do this as I have yet to find a need for it in my environment.

Here is an example of how I currently have my code structured. You don’t necessarily have to follow the same structure but the build module may need some adjusting to work with a different structure.

function Build {
    <#
.DESCRIPTION
    Developer:  Mike Polselli
    PSVersion:  5.0
    Language:   PowerShell
    Purpose:    This script will compile scripts into a module. Its purpose is to create a module while leaving the "Functions" as individual scripts for easy management and updating.
.PARAMETER Help
    Displays helpful information about the script.
.PARAMETER Identity
    Identifies the module you wish to build.
.PARAMETER NewModule
    Used when you are building a new module, this will create the necessary files and prompt for a description.
.PARAMETER Publish
    Publishes the module to the CompanyName Repository.
.PARAMETER Update
    Updates the module manifest, uses the Microsoft versioning standard.
.EXAMPLE
    Build -Help
.EXAMPLE
    Build -Identity Logging
.EXAMPLE
    Build -Identity Logging -Publish -Update Revision
.EXAMPLE
    Build -Identity SomeModule -NewModule

    Enter a description for SomeModule.: This is a description of the module.
#>
    [cmdletbinding(DefaultParameterSetName = "Primary")]
    param (
        [Parameter(ParameterSetName = "NewModule", Position = 0, Mandatory = $true)]
        [Parameter(ParameterSetName = "Publish", Position = 0, Mandatory = $true)]
        [Parameter(ParameterSetName = "Primary", Position = 0, Mandatory = $true)]
        [string]$Identity,

        [Parameter(ParameterSetName = "NewModule", Position = 1)]
        [switch]$NewModule,

        [Parameter(ParameterSetName = "Publish", Position = 2)]
        [switch]$Publish,

        [Parameter(ParameterSetName = "Publish", Position = 3)]
        [ValidateSet('Major', 'Minor', 'Build', 'Revision')]
        [string]$Update,

        [Parameter(ParameterSetName = "Help")][switch]$Help
    )
    if ($Help) {
        Get-Help $MyInvocation.MyCommand.Name -Full | more
        break
    }
    
    $Path = "\\$env:USERDNSDOMAIN\Path\To\Module\Scripts"
    $NewPath = $Path | Split-Path -Parent
    if ($NewModule) {
        # Creates required files and folders for the new module.
        try {
            # This will stop existing modules from being overwritten.
            New-Item -Path $NewPath\$Identity -ItemType Directory -ErrorAction Stop
            New-Item -Path $NewPath\$Identity\$Identity'.psm1' -ItemType File
            $Properties = @{
                Path          = "$NewPath\$Identity\$Identity.psd1"
                Author        = 'YourName'
                CompanyName   = 'CompanyName'
                Description   = Read-Host -Prompt "Enter a description for $Identity."
                ModuleVersion = '1.0.0.0'
                RootModule    = $Identity
            }
            New-ModuleManifest @Properties
        }
        catch {
            Write-Warning "The module $Identity already exists!"
            break
        }
    }

    $Scripts = Get-ChildItem $Path\$Identity -Include *.ps1 -Recurse
    $Module = Get-ChildItem $NewPath\$Identity -Include *.psm1 -Recurse
    $Manifest = Get-ChildItem $NewPath\$Identity -Include *.psd1 -Recurse

    $Functions = @()
    Set-Content -Path $Module -Value $null

    foreach ($Script in $Scripts) {
        # Adds Functions to the module.
        # Adds the Function names to an array to export.
        $Code = Get-Content -Path $Script.FullName
        Add-Content -Path $Module -Value $Code -Force
        Add-Content -Path $Module -Value "`n" -Force
        $Functions += $Script.Name.Split('.')[0]
    }
    Update-ModuleManifest -Path $Manifest -FunctionsToExport $Functions

    $GetFile = Get-ChildItem -Path $NewPath\$Identity *.psd1
    Test-ModuleManifest -Path $GetFile.FullName

    if ($Publish) {
        # Publishes the module.
        $GetCurrentVersion = Get-Content -Path $GetFile.FullName | Select-String -Pattern '^ModuleVersion = (.*)'
        [version]$CurrentVersion = $GetCurrentVersion.Matches.Groups[1].Value.Replace("'", '')
        switch ($Update) {
            Major { $UpdatedVersion = "{0}.{1}.{2}.{3}" -f ($CurrentVersion.Major + 1), $CurrentVersion.Minor, $CurrentVersion.Build, $CurrentVersion.Revision }
            Minor { $UpdatedVersion = "{0}.{1}.{2}.{3}" -f $CurrentVersion.Major, ($CurrentVersion.Minor + 1 ), $CurrentVersion.Build, $CurrentVersion.Revision }
            Build { $UpdatedVersion = "{0}.{1}.{2}.{3}" -f $CurrentVersion.Major, $CurrentVersion.Minor, ($CurrentVersion.Build + 1), $CurrentVersion.Revision }
            Revision { $UpdatedVersion = "{0}.{1}.{2}.{3}" -f $CurrentVersion.Major, $CurrentVersion.Minor, $CurrentVersion.Build, ($CurrentVersion.Revision + 1) }
        }
        (Get-Content -Path $GetFile.FullName -Raw) -replace $GetCurrentVersion.Matches.Groups[1].Value, $UpdatedVersion.Insert($UpdatedVersion.Length, "'").Insert(0, "'") | Set-Content -Path $GetFile.FullName

        Publish-Module -Path $NewPath\$Identity -Repository RepositoryName
    }
}

$IdentityBlock = {
    param($CommandName, $ParameterName, $WordToComplete, $CommandAst, $FakeBoundParameter)
    $Path = "\\$env:USERDNSDOMAIN\Path\To\Module\Scripts"
    (Get-ChildItem $Path).Name | Where-Object {
        $PSItem -like "$WordToComplete*"
    } | ForEach-Object {
        "$PSItem"
    }
}

Register-ArgumentCompleter -CommandName Build -ParameterName Identity -ScriptBlock $IdentityBlock

As with all code you find on the internet, look it over, tinker with it, test it, and so on before you use it in any production environments!