Public/Hide-HDTShellWindow.ps1

function Hide-HDTShellWindow {
    <#
        .SYNOPSIS
            Hides or restores the WinPE console window behind the wizard.
 
        .DESCRIPTION
            WinPE boots into cmd.exe running startnet.cmd, and that black
            X:\Windows\System32> window sits behind everything for the whole
            deployment. -WindowStyle Hidden on the PowerShell launch does not
            touch it: that hides the POWERSHELL host, not the shell that
            started it. The only way to move it is the Win32 ShowWindow API
            against the console's own handle, which is what MDT and PSD do.
 
            THE CONSOLE IS RESTORED ON FAILURE, AND THAT IS NOT OPTIONAL. A
            hidden console plus a wizard that then throws leaves a technician
            staring at a BLANK SCREEN with no way to read what went wrong and
            nothing to type into. Every caller that hides it must restore it on
            its failure path - hidden is a presentation choice, not a place to
            get stuck.
 
            AN ADAPTER, AND THEREFORE BRANCH-FREE. It wraps
            two Win32 calls and has nothing to decide; whether to hide at all is
            the payload's decision. It is also SAFE OUTSIDE WinPE: a process
            with no console gets a null handle and this does nothing, so the
            desktop preview tool is unaffected.
 
        .PARAMETER Restore
            Show the console again instead of hiding it.
 
        .OUTPUTS
            System.Boolean - whether a console window was found to act on.
 
        .EXAMPLE
            Hide-HDTShellWindow
 
            What the payload calls once the wizard is about to appear.
 
        .EXAMPLE
            try { Hide-HDTShellWindow; ... } finally { Hide-HDTShellWindow -Restore }
 
            The only correct shape: hidden for the happy path, back for every
            other one.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',
        Justification = 'Changes only the visibility of this process own console window; it alters no system state.')]
    [CmdletBinding()]
    [OutputType([bool])]
    param(
        [Parameter()]
        [switch] $Restore
    )

    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'

    # The type is added ONCE per session; Add-Type throws if the name already
    # exists, and the payload may show more than one page.
    if (-not ([System.Management.Automation.PSTypeName]'HDT.NativeWindow').Type) {
        Add-Type -Namespace 'HDT' -Name 'NativeWindow' -MemberDefinition @'
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
 
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
'@

    }

    $handle = [HDT.NativeWindow]::GetConsoleWindow()

    # No console - a windowed host, or the desktop preview tool. Nothing to do,
    # and not an error: this must never be the reason a wizard fails to open.
    if ($handle -eq [System.IntPtr]::Zero) {
        return $false
    }

    # 0 = SW_HIDE, 5 = SW_SHOW.
    $command = 0
    if ($Restore) { $command = 5 }

    [void] [HDT.NativeWindow]::ShowWindow($handle, $command)

    return $true
}