Private/Get-HDTConsoleWindowIcon.ps1

function Get-HDTConsoleWindowIcon {
    <#
        .SYNOPSIS
            The icon every console window wears, in its title bar and in the
            taskbar button: Hephaestus' anvil on the banner blue.
 
        .DESCRIPTION
            THIS IS AN ADAPTER OVER WPF AND IS DELIBERATELY BRANCH-FREE. It
            decides nothing and reads nothing: two colours and one path, drawn
            once. tests/unit/ConsoleWindowIcon.Tests.ps1 asserts the size, that
            it is an ImageSource, and that it is frozen - the three things that
            can be wrong without looking at it.
 
            WHY THERE IS ONE AT ALL. A WPF window that declares no Icon falls
            back to the icon of the process that hosts it, and that process is
            powershell.exe - so the console, the task sequence editor and every
            dialog came up wearing the PowerShell feather. An administrator
            alt-tabbing between the console and the shell that started it had
            two identical buttons, and pinning the console to the taskbar pinned
            something indistinguishable from a shell.
 
            IT IS DRAWN, NOT SHIPPED AS A .ico. A binary asset is a file nobody
            can review in a diff, and it would have to be found at run time at a
            path that differs between a source tree, a generated bundle and an
            installed module - three ways for a window to come up with no icon
            because a file move was missed. Geometry is text and lives in this
            file, and RenderTargetBitmap turns it into what Window.Icon takes.
 
            256 SQUARE IS THE LARGEST SIZE A SHELL ASKS FOR - the jumbo icon in
            an Alt+Tab switcher and in the taskbar at 200% scaling. WPF
            downsamples for the 16- and 32-pixel uses, which is why the anvil is
            a solid silhouette with no detail small enough to disappear when it
            is a sixteenth of this size.
 
            IT IS FROZEN because the boot image build opens its progress window
            on a second thread, and an unfrozen Freezable belongs to the thread
            that made it. Freezing also lets all thirteen windows share the one
            bitmap instead of rendering their own.
 
        .INPUTS
            None. This command does not accept pipeline input.
 
        .OUTPUTS
            A frozen System.Windows.Media.Imaging.RenderTargetBitmap, 256x256.
 
        .EXAMPLE
            $window.Icon = Get-HDTConsoleWindowIcon
    #>

    # OutputType IS [object] AND NOT THE REAL TYPE. An attribute is bound before
    # a single line of the body runs, so naming ImageSource here would demand
    # PresentationCore from a session that has not loaded it yet - and this
    # function is what loads it. The Add-Type calls below are the reason the
    # attribute cannot say what they make available.
    [CmdletBinding()]
    [OutputType([object])]
    param()

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

    Add-Type -AssemblyName PresentationCore
    Add-Type -AssemblyName PresentationFramework
    Add-Type -AssemblyName WindowsBase

    # THE BADGE IS THE BANNER'S BLUE, #0E639C, the one colour that is the same
    # in both palettes (Get-HDTConsoleTheme). The icon does not follow the theme:
    # a taskbar button that changed colour when somebody switched the console to
    # dark would stop being the thing they learned to look for.
    $badge = New-Object -TypeName System.Windows.Media.SolidColorBrush -ArgumentList (
        [System.Windows.Media.ColorConverter]::ConvertFromString('#FF0E639C'))
    $metal = New-Object -TypeName System.Windows.Media.SolidColorBrush -ArgumentList (
        [System.Windows.Media.ColorConverter]::ConvertFromString('#FFFFFFFF'))

    # THE ANVIL, ON A 256 GRID: horn on the left tapering to a point, top face,
    # waist, splayed foot. It is a silhouette rather than an outline because an
    # outline of this at 16 pixels is a grey smudge.
    $anvil = [System.Windows.Media.Geometry]::Parse((
        'M 22,98 L 104,80 L 216,80 L 216,114 ' +
        'L 176,114 L 176,166 L 222,166 L 234,202 ' +
        'L 80,202 L 92,166 L 144,166 L 144,114 L 96,114 ' +
        'C 70,112 44,108 22,98 Z'))

    $visual = New-Object -TypeName System.Windows.Media.DrawingVisual
    $context = $visual.RenderOpen()
    $context.DrawRoundedRectangle($badge, $null,
        (New-Object -TypeName System.Windows.Rect -ArgumentList 0, 0, 256, 256), 48, 48)
    $context.DrawGeometry($metal, $null, $anvil)
    $context.Close()

    $bitmap = New-Object -TypeName System.Windows.Media.Imaging.RenderTargetBitmap -ArgumentList (
        256, 256, 96, 96, [System.Windows.Media.PixelFormats]::Pbgra32)
    $bitmap.Render($visual)
    $bitmap.Freeze()

    $bitmap
}