Advanced Template Module Generator Tool

<#
.SYNOPSIS
Advanced Template Module Generator Tool

.DESCRIPTION
This script provides an interactive tool to generate a comprehensive structure for a PowerShell module,
including advanced features like dependency management, script analyzer settings, and extensive testing setup.

.NOTES
File Name      : AdvancedTemplateModuleGenerator.ps1
Author         : [Your Name]
Prerequisite   : PowerShell V5.1 or later
Version        : 1.0
Date           : [Current Date]

.EXAMPLE
.\AdvancedTemplateModuleGenerator.ps1
#>

function Show-Menu {
    Clear-Host
    Write-Host "=== Advanced Template Module Generator Tool ===" -ForegroundColor Cyan
    Write-Host "1. Set Module Details"
    Write-Host "2. Add Public Function"
    Write-Host "3. Add Private Function"
    Write-Host "4. Add Module Dependencies"
    Write-Host "5. Configure Build Settings"
    Write-Host "6. Configure Test Settings"
    Write-Host "7. Generate Module Files"
    Write-Host "8. Exit"
}

function Set-ModuleDetails {
    $script:moduleName = Read-Host "Enter the name of the module"
    $script:moduleDescription = Read-Host "Enter a brief description of the module"
    $script:moduleAuthor = Read-Host "Enter the author's name"
    $script:moduleVersion = Read-Host "Enter the module version (e.g., 1.0.0)"
    $script:moduleLicense = Read-Host "Enter the module license (e.g., MIT)"
    $script:moduleProjectUri = Read-Host "Enter the project URI (optional)"
    Write-Host "Module details set successfully." -ForegroundColor Green
}

function Add-PublicFunction {
    $functionName = Read-Host "Enter the name of the public function"
    $script:publicFunctions += $functionName
    Write-Host "Public function '$functionName' added." -ForegroundColor Green
}

function Add-PrivateFunction {
    $functionName = Read-Host "Enter the name of the private function"
    $script:privateFunctions += $functionName
    Write-Host "Private function '$functionName' added." -ForegroundColor Green
}

function Add-ModuleDependencies {
    do {
        $dependencyName = Read-Host "Enter the name of the module dependency (or press Enter to finish)"
        if ($dependencyName -ne "") {
            $dependencyVersion = Read-Host "Enter the required version (leave blank for any version)"
            $script:moduleDependencies += [PSCustomObject]@{
                Name = $dependencyName
                Version = $dependencyVersion
            }
            Write-Host "Dependency added: $dependencyName $dependencyVersion" -ForegroundColor Green
        }
    } while ($dependencyName -ne "")
}

function Set-BuildSettings {
    $script:usePSScriptAnalyzer = (Read-Host "Use PSScriptAnalyzer for code analysis? (Y/N)") -eq 'Y'
    $script:useplatyPS = (Read-Host "Use platyPS for documentation generation? (Y/N)") -eq 'Y'
    Write-Host "Build settings configured." -ForegroundColor Green
}

function Set-TestSettings {
    $script:usePester = (Read-Host "Use Pester for testing? (Y/N)") -eq 'Y'
    $script:useCodeCoverage = (Read-Host "Include code coverage in tests? (Y/N)") -eq 'Y'
    Write-Host "Test settings configured." -ForegroundColor Green
}

function Generate-ModuleFiles {
    if ([string]::IsNullOrWhiteSpace($script:moduleName)) {
        Write-Host "Please set module details first." -ForegroundColor Yellow
        return
    }

    $modulePath = Join-Path -Path $PWD -ChildPath $script:moduleName
    New-Item -Path $modulePath -ItemType Directory -Force | Out-Null

    # Create module manifest
    $manifestPath = Join-Path -Path $modulePath -ChildPath "$($script:moduleName).psd1"
    $manifestParams = @{
        Path = $manifestPath
        RootModule = "$($script:moduleName).psm1"
        ModuleVersion = $script:moduleVersion
        Author = $script:moduleAuthor
        Description = $script:moduleDescription
        FunctionsToExport = $script:publicFunctions
        PowerShellVersion = '5.1'
    }
    if ($script:moduleLicense) { $manifestParams['LicenseUri'] = $script:moduleLicense }
    if ($script:moduleProjectUri) { $manifestParams['ProjectUri'] = $script:moduleProjectUri }
    if ($script:moduleDependencies) {
        $manifestParams['RequiredModules'] = $script:moduleDependencies | ForEach-Object {
            if ($_.Version) { @{ModuleName = $_.Name; ModuleVersion = $_.Version} } else { $_.Name }
        }
    }
    New-ModuleManifest @manifestParams

    # Create module script file
    $modulePSM1Path = Join-Path -Path $modulePath -ChildPath "$($script:moduleName).psm1"
    $modulePSM1Content = @"
# Dot source public/private functions
`$public = @(Get-ChildItem -Path `$PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue)
`$private = @(Get-ChildItem -Path `$PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue)

foreach (`$import in @(`$public + `$private)) {
    try {
        . `$import.FullName
    } catch {
        Write-Error -Message "Failed to import function `$(`$import.FullName): `$_"
    }
}

# Export public functions
Export-ModuleMember -Function `$public.BaseName
"@
    Set-Content -Path $modulePSM1Path -Value $modulePSM1Content

    # Create Public and Private folders
    New-Item -Path (Join-Path -Path $modulePath -ChildPath "Public") -ItemType Directory -Force | Out-Null
    New-Item -Path (Join-Path -Path $modulePath -ChildPath "Private") -ItemType Directory -Force | Out-Null

    # Create function files
    foreach ($function in $script:publicFunctions) {
        $functionPath = Join-Path -Path $modulePath -ChildPath "Public\$function.ps1"
        $functionContent = @"
function $function {
    <#
    .SYNOPSIS
    Brief description of $function

    .DESCRIPTION
    Detailed description of $function

    .PARAMETER Param1
    Description of Param1

    .EXAMPLE
    $function -Param1 Value
    Explanation of the example

    .NOTES
    Additional notes about the function
    #>
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=`$true)]
        [string]`$Param1
    )

    begin {
        # Initialize any prerequisites
    }

    process {
        # Main function logic
    }

    end {
        # Cleanup or final actions
    }
}
"@
        Set-Content -Path $functionPath -Value $functionContent
    }

    foreach ($function in $script:privateFunctions) {
        $functionPath = Join-Path -Path $modulePath -ChildPath "Private\$function.ps1"
        $functionContent = @"
function $function {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=`$true)]
        [string]`$Param1
    )

    # Function logic here
}
"@
        Set-Content -Path $functionPath -Value $functionContent
    }

    # Create tests folder and files
    $testsFolderPath = Join-Path -Path $modulePath -ChildPath "Tests"
    New-Item -Path $testsFolderPath -ItemType Directory -Force | Out-Null

    if ($script:usePester) {
        $testFilePath = Join-Path -Path $testsFolderPath -ChildPath "$($script:moduleName).Tests.ps1"
        $testFileContent = @"
`$ModuleName = '$($script:moduleName)'
`$ModuleManifestPath = "`$PSScriptRoot\..\`$ModuleName.psd1"

Describe "`$ModuleName Module Tests" {
    BeforeAll {
        `$Module = Import-Module `$ModuleManifestPath -PassThru -Force
    }

    It "Module manifest is valid" {
        Test-ModuleManifest -Path `$ModuleManifestPath | Should -Not -BeNullOrEmpty
        `$? | Should -Be `$true
    }

    It "Module can be imported" {
        `$Module | Should -Not -BeNullOrEmpty
    }

    Context "Function Tests" {
        # Add tests for each function
        $(foreach ($function in $script:publicFunctions) {
@"
        It "$function exists" {
            Get-Command $function -Module `$ModuleName | Should -Not -BeNullOrEmpty
        }

"@
        })
    }
}
"@
        Set-Content -Path $testFilePath -Value $testFileContent
    }

    # Create build configuration
    $buildFolderPath = Join-Path -Path $modulePath -ChildPath "Build"
    New-Item -Path $buildFolderPath -ItemType Directory -Force | Out-Null

    $buildFilePath = Join-Path -Path $buildFolderPath -ChildPath "build.ps1"
    $buildFileContent = @"
param (
    [switch]`$Test,
    [switch]`$Analyze,
    [switch]`$Documentation
)

`$ModuleName = '$($script:moduleName)'
`$ModuleRoot = "`$PSScriptRoot\.."
`$OutputPath = "`$ModuleRoot\Output"

# Clean and create output directory
if (Test-Path -Path `$OutputPath) {
    Remove-Item -Path `$OutputPath -Recurse -Force
}
New-Item -Path `$OutputPath -ItemType Directory -Force | Out-Null

# Copy module files to output directory
Copy-Item -Path "`$ModuleRoot\`$ModuleName.psd1" -Destination `$OutputPath
Copy-Item -Path "`$ModuleRoot\`$ModuleName.psm1" -Destination `$OutputPath
Copy-Item -Path "`$ModuleRoot\Public" -Destination `$OutputPath -Recurse
Copy-Item -Path "`$ModuleRoot\Private" -Destination `$OutputPath -Recurse

if (`$Test) {
    # Run Pester tests
    `$testResults = Invoke-Pester -Path "`$ModuleRoot\Tests" -PassThru
    if (`$testResults.FailedCount -gt 0) {
        throw "One or more tests failed."
    }
}

if (`$Analyze) {
    # Run PSScriptAnalyzer
    `$analysisResults = Invoke-ScriptAnalyzer -Path `$OutputPath -Recurse
    if (`$analysisResults) {
        `$analysisResults | Format-Table
        throw "PSScriptAnalyzer found one or more issues."
    }
}

if (`$Documentation) {
    # Generate documentation using platyPS
    Import-Module platyPS
    New-MarkdownHelp -Module `$ModuleName -OutputFolder "`$OutputPath\docs" -Force
}

Write-Host "Build completed successfully." -ForegroundColor Green
"@
    Set-Content -Path $buildFilePath -Value $buildFileContent

    # Create PSScriptAnalyzer settings file
    if ($script:usePSScriptAnalyzer) {
        $analyzerSettingsPath = Join-Path -Path $modulePath -ChildPath "PSScriptAnalyzerSettings.psd1"
        $analyzerSettingsContent = @"
@{
    Severity = @('Error', 'Warning')
    ExcludeRules = @('PSUseShouldProcessForStateChangingFunctions')
    Rules = @{
        PSAvoidUsingCmdletAliases = @{
            Whitelist = @('Where', 'Select')
        }
    }
}
"@
        Set-Content -Path $analyzerSettingsPath -Value $analyzerSettingsContent
    }

    Write-Host "Module files generated successfully at: $modulePath" -ForegroundColor Green
}

# Initialize variables
$script:moduleName = ""
$script:moduleDescription = ""
$script:moduleAuthor = ""
$script:moduleVersion = ""
$script:moduleLicense = ""
$script:moduleProjectUri = ""
$script:publicFunctions = @()
$script:privateFunctions = @()
$script:moduleDependencies = @()
$script:usePSScriptAnalyzer = $false
$script:useplatyPS = $false
$script:usePester = $false
$script:useCodeCoverage = $false

# Main program loop
do {
    Show-Menu
    $choice = Read-Host "`nEnter your choice (1-8)"

    switch ($choice) {
        "1" { Set-ModuleDetails }
        "2" { Add-PublicFunction }
        "3" { Add-PrivateFunction }
        "4" { Add-ModuleDependencies }
        "5" { Set-BuildSettings }
        "6" { Set-TestSettings }
        "7" { Generate-ModuleFiles }
        "8" { Write-Host "Exiting program..." -ForegroundColor Yellow; break }
        default { Write-Host "Invalid choice. Please try again." -ForegroundColor Red }
    }

    if ($choice -ne "8") {
        Read-Host "`nPress Enter to continue..."
    }
} while ($choice -ne "8")

This Advanced Template Module Generator Tool includes:

  1. A menu-driven interface for easy navigation.
  2. Enhanced functions to:
    • Set detailed module information (including license and project URI)
    • Add public and private functions
    • Specify module dependencies
    • Configure build and test settings

Key features:

  1. Advanced Module Manifest Generation:
    • Includes more detailed module information
    • Supports specifying module dependencies
  2. Comprehensive Module Structure:
    • Creates a more robust folder structure including build and test directories
  3. Enhanced Function File Generation:
    • Generates more detailed function templates
  4. Build Script Generation:
    • Creates a build.ps1 script for module building, testing, and documentation generation
  5. Test Configuration:
    • Sets up Pester tests with placeholders for each public function
    • Optionally includes code coverage settings
  6. PSScriptAnalyzer Integration:
    • Generates a PSScriptAnalyzer settings file
    • Includes PSScriptAnalyzer in the build process
  7. Documentation Support:
    • Optionally sets up platyPS for documentation generation
  8. Dependency Management:
    • Allows specifying module dependencies with version requirements

This tool is particularly useful for:

  • Experienced PowerShell module developers
  • Teams working on larger PowerShell projects
  • Developers who want to follow best practices in module development

To use this script effectively:

  1. Run the script in PowerShell
  2. Use the menu options to:
    • Set detailed module information
    • Add public and private functions
    • Specify dependencies and configure build/test settings
    • Generate the module files
  3. Review the generated module structure and customize as needed

This advanced script provides a more comprehensive starting point for PowerShell module development, incorporating best practices and tools commonly used in professional PowerShell module projects.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *