public/Invoke-OSDeployHydration.ps1

#Requires -PSEdition Core
#Requires -Version 7.4

<#
.SYNOPSIS
    Runs the complete OSDeploy hydration workflow end-to-end.
 
.DESCRIPTION
    Automates the full OSDeploy setup sequence on a supported Windows 11 machine:
 
      1. Detects the running OS version and processor architecture.
      2. Installs the matching Windows ADK, Git, VS Code, and VS Code Insiders.
      3. Downloads WinPE drivers for the detected architecture.
      4. Builds a WinPE boot image named 'Hydra', using the newest available WinRE
         source when present, or falling back to the ADK WinPE when none is found.
 
    Requires Windows 11 25H2 or 26H1, PowerShell 7.6+, and Administrator rights.
 
.PARAMETER Force
    Runs all steps non-interactively. WinPE driver downloads skip the Out-GridView
    picker and all matching sources are processed automatically. If no WinRE source
    is found the ADK WinPE is used without prompting.
 
.EXAMPLE
    Invoke-OSDeployHydration
 
    Runs the full hydration workflow with interactive pickers at each step.
 
.EXAMPLE
    Invoke-OSDeployHydration -Force
 
    Runs the full hydration workflow non-interactively end-to-end.
 
.INPUTS
    None. This function does not accept pipeline input.
 
.OUTPUTS
    None.
 
.NOTES
    Author: David Segura
    Company: Recast Software
    Requires: Windows 11 25H2 or 26H1, PowerShell 7.6, Windows ADK, Run as Administrator
#>

function Invoke-OSDeployHydration {
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    [Alias('Invoke-OSDeployHydra')]
    param (
        [Parameter()]
        [switch]$Force
    )

    Write-OSDeployBanner
    if (-not $IsWindows) {
        throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Invoke-OSDeployHydration is supported only on Windows."
    }

    $currentPrincipal = [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
    if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Invoke-OSDeployHydration requires Administrator rights. Re-run PowerShell as Administrator and try again."
    }

    # Detect processor architecture — default to amd64, override only for arm64
    $arch = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { 'arm64' } else { 'amd64' }
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Architecture: $arch"

    # Detect OS version and resolve the matching ADK component name
    $displayVersion = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'DisplayVersion' -ErrorAction Stop).DisplayVersion
    $adkName = switch ($displayVersion) {
        '25H2'  { 'adk-25h2' }
        '26H1'  { 'adk-26h1' }
        default {
            throw "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] Invoke-OSDeployHydration requires Windows 11 25H2 or 26H1. Detected: $displayVersion"
        }
    }
    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] OS: Windows 11 $displayVersion — ADK: $adkName"

    #region Step 1 — Install software
    if ($PSCmdlet.ShouldProcess("git, code, code-insiders, $adkName", 'Install software components')) {
        # Always install git non-interactively to suppress identity change prompts
        # when user.email and user.name are already configured.
        Install-GitForWindows -NonInteractive
        Install-OSDeploySoftware -Name @('code', 'code-insiders', $adkName, '7zip') -Force
    }
    #endregion

    #region Step 2 — Update WinPE drivers for the detected architecture
    Initialize-OSDeployWinPEDrivers

    $filteredDriverNames = [string[]]($global:OSDeployModule.WinPEDrivers.PSObject.Properties |
        Where-Object { $_.Value.Architecture -eq $arch -and ($null -eq $_.Value.PSObject.Properties['Disabled'] -or $_.Value.PSObject.Properties['Disabled'].Value -ne $true) } |
        Select-Object -ExpandProperty Name)

    Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] WinPE driver sources ($arch): $($filteredDriverNames -join ', ')"

    if ($filteredDriverNames) {
        $driverParams = @{ Name = $filteredDriverNames }
        if ($Force) { $driverParams['NonInteractive'] = $true }
        Update-OSDeployWinPEDrivers @driverParams
    }
    else {
        Write-Warning "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No WinPE driver sources found for architecture '$arch'."
    }
    #endregion

    #region Step 3 — Build boot image (prefer WinRE, fall back to ADK WinPE)
    $winRESources = Get-OSDeployCoreWinRESource -Architecture $arch

    $buildParams = @{
        Name         = 'Hydra'
        Architecture = $arch
    }

    if ($winRESources) {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] WinRE source(s) found for $arch — using WinRE."
    }
    else {
        Write-Verbose "[$(Get-Date -format s)] [$($MyInvocation.MyCommand.Name)] No WinRE sources found for $arch — falling back to ADK WinPE."
        $buildParams['UseAdkWinPE'] = $true
    }

    Build-OSDeployBootMedia @buildParams
    #endregion
}