Public/Invoke-LocalPilot.ps1

function Invoke-LocalPilot {
    <#
    .SYNOPSIS
        Local zero-cloud workstation provisioner and Machine-as-Code engine.
    .DESCRIPTION
        Configures, debloats, hardens, tunes, and installs software stacks on fresh
        Windows installations, hypervisor lab VMs, or personal gaming rigs without
        requiring Entra ID join or cloud Intune licenses.
    .PARAMETER Persona
        Predefined persona blueprint. Options: DevWorkstation, HomelabVM, GamingMinimal, FamilyClean.
    .PARAMETER RecipePath
        Path to a custom JSON recipe file.
    .PARAMETER Debloat
        Removes pre-installed consumer AppX bloat while preserving essential system apps.
    .PARAMETER HardenPrivacy
        Hardens telemetry, disables Bing start menu search, and disables silent app suggestions.
    .PARAMETER ConfigurePerformance
        Enables high performance power plans and tunes responsiveness.
    .PARAMETER InstallWingetPackages
        Additional or override Winget package IDs to install unattended.
    .PARAMETER EnableFeatures
        Windows optional features to enable (e.g. WSL, Hyper-V).
    .PARAMETER BirthCertificate
        Generates a post-provision hardware manifest & Markdown birth certificate.
    .PARAMETER BirthCertificatePath
        Path to save the generated birth certificate markdown file.
    .EXAMPLE
        Invoke-LocalPilot -Persona DevWorkstation -BirthCertificate
    .EXAMPLE
        Start-LocalPilot -Persona GamingMinimal -Debloat -HardenPrivacy -ConfigurePerformance
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Position = 0)]
        [ValidateSet('DevWorkstation', 'HomelabVM', 'GamingMinimal', 'FamilyClean')]
        [string]$Persona = 'DevWorkstation',

        [Parameter()]
        [string]$RecipePath,

        [Parameter()]
        [switch]$Debloat,

        [Parameter()]
        [switch]$HardenPrivacy,

        [Parameter()]
        [switch]$ConfigurePerformance,

        [Parameter()]
        [string[]]$InstallWingetPackages,

        [Parameter()]
        [string[]]$EnableFeatures,

        [Parameter()]
        [switch]$BirthCertificate,

        [Parameter()]
        [string]$BirthCertificatePath = ".\Workstation-BirthCertificate-$($env:COMPUTERNAME).md"
    )

    Write-Host ""
    Write-Host "==========================================================" -ForegroundColor Cyan
    Write-Host " 🚀 LocalPilot v1.0.0 - Local Workstation Provisioner " -ForegroundColor Cyan
    Write-Host "==========================================================" -ForegroundColor Cyan
    Write-Host ""

    # Load recipe
    $recipe = if ($RecipePath) {
        Write-Host " [LocalPilot] Loading custom recipe from: $RecipePath" -ForegroundColor Gray
        Get-LocalPilotRecipe -Path $RecipePath
    }
    else {
        Write-Host " [LocalPilot] Applying persona blueprint: $Persona" -ForegroundColor Gray
        Get-LocalPilotRecipe -Persona $Persona
    }

    $shouldDebloat = $Debloat.IsPresent -or $recipe.Debloat
    $shouldHarden = $HardenPrivacy.IsPresent -or $recipe.HardenPrivacy
    $shouldPerf = $ConfigurePerformance.IsPresent -or $recipe.ConfigurePerformance
    $packagesToInstall = if ($InstallWingetPackages) { $InstallWingetPackages } else { $recipe.WingetPackages }
    $featuresToEnable = if ($EnableFeatures) { $EnableFeatures } else { $recipe.WindowsFeatures }

    # 1. Debloat
    if ($shouldDebloat) {
        if ($PSCmdlet.ShouldProcess("System", "Remove consumer bloatware AppX packages")) {
            Write-Host " [LocalPilot] Debloating consumer AppX packages..." -ForegroundColor Yellow
            $bloatPatterns = @(
                '*Clipchamp*',
                '*BingNews*',
                '*BingWeather*',
                '*MicrosoftSolitaireCollection*',
                '*Xbox*',
                '*GamingApp*',
                '*YourPhone*',
                '*People*',
                '*FeedbackHub*',
                '*GetHelp*',
                '*Getstarted*',
                '*OfficeHub*',
                '*SkypeApp*',
                '*ZuneMusic*',
                '*ZuneVideo*',
                '*SpotifyAB.SpotifyMusic*',
                '*TikTok*',
                '*Disney*',
                '*Instagram*',
                '*Facebook*'
            )

            foreach ($pattern in $bloatPatterns) {
                $apps = Get-AppxPackage -Name $pattern -ErrorAction SilentlyContinue
                foreach ($app in $apps) {
                    Write-Host " [-] Removing AppX: $($app.Name)" -ForegroundColor DarkGray
                    Remove-AppxPackage -Package $app.PackageFullName -ErrorAction SilentlyContinue
                }

                # If running elevated, remove provisioned package
                $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
                if ($isAdmin) {
                    Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like $pattern } | ForEach-Object {
                        Write-Host " [-] De-provisioning: $($_.DisplayName)" -ForegroundColor DarkGray
                        Remove-AppxProvisionedPackage -Online -PackageName $_.PackageName -ErrorAction SilentlyContinue | Out-Null
                    }
                }
            }
        }
    }

    # 2. Privacy & Registry Hardening
    if ($shouldHarden) {
        if ($PSCmdlet.ShouldProcess("Registry", "Harden telemetry and disable Start search web injection")) {
            Write-Host " [LocalPilot] Hardening privacy and explorer registry settings..." -ForegroundColor Yellow

            # Disable Bing web search in Start Menu
            $searchPolicyPath = 'HKCU:\Software\Policies\Microsoft\Windows\Explorer'
            if (-not (Test-Path $searchPolicyPath)) { New-Item -Path $searchPolicyPath -Force | Out-Null }
            Set-ItemProperty -Path $searchPolicyPath -Name 'DisableSearchBoxSuggestions' -Value 1 -Type DWord -Force

            # Show known file extensions
            $explorerAdv = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'
            if (Test-Path $explorerAdv) {
                Set-ItemProperty -Path $explorerAdv -Name 'HideFileExt' -Value 0 -Type DWord -Force
            }

            # Disable Consumer Cloud Content & Silent Installs
            $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
            if ($isAdmin) {
                $cloudContentPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent'
                if (-not (Test-Path $cloudContentPath)) { New-Item -Path $cloudContentPath -Force | Out-Null }
                Set-ItemProperty -Path $cloudContentPath -Name 'DisableWindowsConsumerFeatures' -Value 1 -Type DWord -Force

                # Restrict Telemetry to Security / Minimum
                $dataCollectionPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection'
                if (-not (Test-Path $dataCollectionPath)) { New-Item -Path $dataCollectionPath -Force | Out-Null }
                Set-ItemProperty -Path $dataCollectionPath -Name 'AllowTelemetry' -Value 0 -Type DWord -Force
            }

            Write-Host " [+] Privacy and Explorer tweaks applied." -ForegroundColor DarkGray
        }
    }

    # 3. Performance Tuning
    if ($shouldPerf) {
        if ($PSCmdlet.ShouldProcess("System", "Configure high performance power plan & responsiveness")) {
            Write-Host " [LocalPilot] Configuring performance optimizations..." -ForegroundColor Yellow
            try {
                # High Performance power scheme GUID
                & powercfg -setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c 2>$null
                Write-Host " [+] Power scheme set to High Performance." -ForegroundColor DarkGray
            }
            catch {
                Write-Verbose "Could not switch power scheme: $_"
            }
        }
    }

    # 4. Windows Features
    if ($featuresToEnable -and $featuresToEnable.Count -gt 0) {
        $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
        if ($isAdmin) {
            foreach ($feature in $featuresToEnable) {
                if ($PSCmdlet.ShouldProcess("Feature: $feature", "Enable Windows Optional Feature")) {
                    Write-Host " [LocalPilot] Enabling feature: $feature" -ForegroundColor Cyan
                    Enable-WindowsOptionalFeature -Online -FeatureName $feature -All -NoRestart -ErrorAction SilentlyContinue | Out-Null
                }
            }
        }
        else {
            Write-Warning " [LocalPilot] Administrator privileges required to enable Windows Features ($($featuresToEnable -join ', ')). Skipping."
        }
    }

    # 5. Winget Packages
    if ($packagesToInstall -and $packagesToInstall.Count -gt 0) {
        $wingetCmd = Get-Command -Name 'winget' -ErrorAction SilentlyContinue
        if ($wingetCmd) {
            Write-Host " [LocalPilot] Installing Winget software stack ($($packagesToInstall.Count) packages)..." -ForegroundColor Cyan
            foreach ($pkgId in $packagesToInstall) {
                if ($PSCmdlet.ShouldProcess("Package: $pkgId", "Install via Winget")) {
                    Write-Host " --> Installing $pkgId..." -ForegroundColor White
                    & winget install --id $pkgId --exact --silent --accept-source-agreements --accept-package-agreements 2>&1 | Out-Null
                }
            }
        }
        else {
            Write-Warning " [LocalPilot] Winget CLI not detected in current path. Skipping software installs."
        }
    }

    # 6. Birth Certificate
    if ($BirthCertificate.IsPresent) {
        Write-Host " [LocalPilot] Generating Workstation Birth Certificate..." -ForegroundColor Green
        New-WorkstationBirthCertificate -OutputPath $BirthCertificatePath
    }

    Write-Host ""
    Write-Host "==========================================================" -ForegroundColor Green
    Write-Host " ✨ LocalPilot Provisioning Complete! " -ForegroundColor Green
    Write-Host "==========================================================" -ForegroundColor Green
    Write-Host ""
}