functions/Initialize-BicepTemplate.ps1

function Initialize-BicepTemplate {
    <#
    .SYNOPSIS
    Initializes a directory with files from a predefined template library.
 
    .DESCRIPTION
    Generates files based on a selected template from a library of templates into a directory.
     
    #>

    [Alias('bicep-init')]
    [CmdletBinding()]
    param (
        [Parameter()]
        [System.IO.DirectoryInfo]
        $Target = '.',

        [Parameter()]
        [ValidateSet('deployment', 'registry')]
        [System.String]
        $Template = 'deployment',

        [Parameter()]
        [System.Collections.Hashtable]
        $InitParameter
    )

    <#
 
        Helper script for copying files.
 
        This avoids problems with existing subdirectories on Copy-Item in the staging directory.
        By only creating subdirectories when they do not exist and then copying all files.
 
    #>

    function Copy-Helper {

        param(
            [System.IO.DirectoryInfo] $sourceDir,
            [System.IO.DirectoryInfo] $targetDir
        )
        
        $sourceDirs = Get-ChildItem -Recurse -Directory -Path $sourceDir
        foreach ($dir in $sourceDirs) {
            $relativePath = Resolve-Path -Relative -Path $dir.FullName -RelativeBasePath $sourceDir
            $templateDir = [System.IO.DirectoryInfo]::new("$targetDir/$relativePath")
    
            if (-NOT $templateDir.Exists) {
                $null = $templateDir.Create()
            }
        }

        $sourceFiles = Get-ChildItem -Recurse -File -Path $sourceDir
        foreach ($file in $sourceFiles) {
            $relativePath = Resolve-Path -Relative -Path $file.FullName -RelativeBasePath $sourceDir
            $templateFile = [System.IO.FileInfo]::new("$targetDir/$relativePath")
    
            if ($templateFile.Exists) {
                throw [System.InvalidOperationException]::new("$relativePath already exists!")
            }
            else {
                $null = $file.CopyTo($templateFile)
            }
        }

    }

    <#
 
        Initialize all relevant variables:
        - targetDir where to copy files
        - sourceDir for the template
        - commonDir for common files
        - initPs1 for the template initialization script
 
    #>

    $common = Get-Item -Path "$PSScriptRoot/libary/common"
    $initPs1 = Get-Item -Path "$PSScriptRoot/libary/$Template/init.ps1"
    $rootDir = Get-Item -Path "$PSScriptRoot/libary/$Template/root"

    if (-NOT [System.IO.Path]::IsPathFullyQualified($Target)) {
        $rootedPath = [System.IO.Path]::Join((Get-Location).Path, $Target)
        $Target = [System.IO.DirectoryInfo]::new($rootedPath)
    }


    try {
        <#
         
            All files are copied to the staging directory,
            where they are modified and then copied to the target directory.
 
        #>


        $tempDir = "{0}/bicep-staging/{1}" -f [System.IO.Path]::GetTempPath(), [System.Guid]::NewGuid()
        $tempDir = New-Item -ItemType Directory -Path $tempDir

        Copy-Helper -sourceDir $rootDir -targetDir $tempDir
        Copy-Helper -sourceDir $common -targetDir $tempDir

        . $initPs1 @InitParameter -StagingDir $tempDir

        <#
 
            This is the final copy operation from staging to the user directory
            Uses the copy dialog for Windows and the shell copy for Linux.
 
        #>


        if (-NOT $Target.Exists) {
            $Target.Create()
        }
        
        if ($IsWindows) {
            $destination = New-Object -ComObject "Shell.Application"
            $destination = $destination.NameSpace($Target.FullName)
            $destination.CopyHere("$tempDir/*")
            return
        }

        try {
            Copy-Item -Path "$tempDir/*" -Recurse -Destination $Target
            Get-ChildItem -Path $tempDir -Hidden | Copy-Item -Recurse -Destination $Target -ErrorAction SilentlyContinue
        }
        catch {
            Write-Host -ForegroundColor RED "`n`nTarget: $Target"
            Write-Host -ForegroundColor RED "`Files already exist in the target directory."
            $overwrite = Read-UtilsUserOption -Prompt "Overwrite?"

            if ($overwrite) {
                Copy-Item -Path "$tempDir/*" -Recurse -Force -Destination $Target
                Get-ChildItem -Path $tempDir -Hidden | Copy-Item -Recurse -Force -Destination $Target -ErrorAction SilentlyContinue
            }
            else {
                Write-Host -ForegroundColor RED "`n`nAborting the operation."
            }
        }
    }
    finally {

        Remove-Item -Path $tempDir -Recurse -Force -ErrorAction SilentlyContinue

        # This cleans up staging directory from directories older than 10 minutes.
        # In case of a crash, when the staging directory was not deleted.
        Get-ChildItem -Path $tempDir.Parent -Directory
        | Where-Object -Property CreationTime -LT (Get-Date).AddMinutes(-10)
        | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
    }
}