Public/New-DevStructure.ps1

function New-DevStructure {
    <#
    .SYNOPSIS
    Creates a complete folder/file layout under a root directory.

    .DESCRIPTION
    Creates -Root, then every entry in -Directories and every (empty) file
    in -Files relative to it, creating missing parent directories for files
    automatically. Each path is rejected if it is rooted or escapes -Root
    via a '..' segment. Existing files are preserved unless -Force is used;
    existing directories are always left untouched.

    .PARAMETER Root
    Root directory to create the structure under.

    .PARAMETER Directories
    Relative directory paths to create under -Root.

    .PARAMETER Files
    Relative file paths to create (empty) under -Root.

    .PARAMETER Force
    Overwrites files in -Files that already exist.

    .EXAMPLE
    mkstruct -Root MyProject -Directories src/core, src/adapters, tests/unit, docs -Files README.md, src/app.ps1, tests/app.Tests.ps1
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    [Alias('mkstruct')]
    [OutputType([System.IO.FileSystemInfo[]])]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Root,

        [Parameter()]
        [string[]]$Directories = @(),

        [Parameter()]
        [string[]]$Files = @(),

        [switch]$Force
    )

    $resolvedRoot = Resolve-DtFullPath -Path $Root

    $resolvedDirectories = foreach ($directory in $Directories) {
        Resolve-DtContainedPath -BasePath $resolvedRoot -ChildName $directory
    }
    $resolvedFiles = foreach ($file in $Files) {
        Resolve-DtContainedPath -BasePath $resolvedRoot -ChildName $file
    }

    if (-not $PSCmdlet.ShouldProcess($resolvedRoot, 'Create structure')) {
        return
    }

    New-DtDirectory -Path $resolvedRoot -Force -Confirm:$false | Out-Null

    foreach ($resolvedDirectory in $resolvedDirectories) {
        New-DtDirectory -Path $resolvedDirectory -Force -Confirm:$false | Out-Null
        Get-Item -LiteralPath $resolvedDirectory
    }

    foreach ($resolvedFile in $resolvedFiles) {
        Set-DtFileContent -Path $resolvedFile -Content '' -Force:$Force -Confirm:$false | Out-Null
        if (Test-Path -LiteralPath $resolvedFile) {
            Get-Item -LiteralPath $resolvedFile
        }
    }
}