```powershell
<#
.SYNOPSIS
    Creates and validates Hyper-V virtual switches with optional VLAN configuration.

.DESCRIPTION
    This script is designed to support practical Hyper-V switch provisioning.
    It can:
      - Inventory host adapters and existing VMSwitch objects
      - Validate that the selected physical adapter exists
      - Create external, internal, or private switches
      - Preserve host access by default when creating an external switch
      - Optionally configure VLAN access or trunk settings for VM or management OS adapters
      - Run non-destructive validation checks after creation

    By default, the script performs safe checks and will not make changes unless -CreateSwitch is specified.
    Review parameters carefully before running against production hosts.

.NOTES
    Requires:
      - Windows Server with Hyper-V module installed
      - Administrative privileges

    Safe defaults:
      - No credentials
      - No destructive actions
      - No automatic NIC selection

.EXAMPLE
    .\New-HyperVSwitch.ps1 -InventoryOnly

.EXAMPLE
    .\New-HyperVSwitch.ps1 -SwitchName "Prod-External" -SwitchType External -NetAdapterName "Ethernet1" -AllowManagementOS

.EXAMPLE
    .\New-HyperVSwitch.ps1 -SwitchName "Lab-Internal" -SwitchType Internal -CreateSwitch

.EXAMPLE
    .\New-HyperVSwitch.ps1 -SwitchName "App01" -ApplyVlan -VlanId 120 -VlanMode Access
#>

[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
param(
    [switch]$InventoryOnly,

    [switch]$CreateSwitch,

    [ValidateNotNullOrEmpty()]
    [string]$SwitchName,

    [ValidateSet('External', 'Internal', 'Private')]
    [string]$SwitchType = 'External',

    [ValidateNotNullOrEmpty()]
    [string]$NetAdapterName,

    [switch]$AllowManagementOS,

    [switch]$ApplyVlan,

    [ValidateRange(1, 4094)]
    [int]$VlanId,

    [ValidateSet('Access', 'Trunk')]
    [string]$VlanMode = 'Access',

    [ValidateNotNullOrEmpty()]
    [string]$TargetVMName,

    [ValidateNotNullOrEmpty()]
    [string]$ManagementAdapterName
)

function Test-AdminContext {
    $currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentIdentity)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Write-Section {
    param([string]$Text)
    Write-Host "`n=== $Text ===" -ForegroundColor Cyan
}

if (-not (Test-AdminContext)) {
    throw "This script must be run from an elevated PowerShell session."
}

if (-not (Get-Command Get-VMSwitch -ErrorAction SilentlyContinue)) {
    throw "The Hyper-V PowerShell module is not available on this host."
}

Write-Section "Host inventory"
Get-NetAdapter | Select-Object Name, InterfaceDescription, Status, LinkSpeed | Format-Table -AutoSize

Write-Section "Existing Hyper-V switches"
Get-VMSwitch | Select-Object Name, SwitchType, NetAdapterInterfaceDescription, AllowManagementOS | Format-Table -AutoSize

if ($InventoryOnly) {
    Write-Host "Inventory complete. No changes were made." -ForegroundColor Green
    return
}

if ($CreateSwitch) {
    if ([string]::IsNullOrWhiteSpace($SwitchName)) {
        throw "-SwitchName is required when using -CreateSwitch."
    }

    if ($SwitchType -eq 'External' -and [string]::IsNullOrWhiteSpace($NetAdapterName)) {
        throw "-NetAdapterName is required for External switches."
    }

    $existingSwitch = Get-VMSwitch -Name $SwitchName -ErrorAction SilentlyContinue
    if ($existingSwitch) {
        Write-Host "Switch '$SwitchName' already exists. Skipping creation." -ForegroundColor Yellow
    }
    else {
        switch ($SwitchType) {
            'External' {
                $adapter = Get-NetAdapter -Name $NetAdapterName -ErrorAction Stop
                if ($PSCmdlet.ShouldProcess("VMSwitch '$SwitchName' on adapter '$NetAdapterName'", "Create External switch")) {
                    New-VMSwitch -Name $SwitchName -NetAdapterName $adapter.Name -AllowManagementOS:$AllowManagementOS.IsPresent | Out-Null
                }
            }
            'Internal' {
                if ($PSCmdlet.ShouldProcess("VMSwitch '$SwitchName'", "Create Internal switch")) {
                    New-VMSwitch -Name $SwitchName -SwitchType Internal | Out-Null
                }
            }
            'Private' {
                if ($PSCmdlet.ShouldProcess("VMSwitch '$SwitchName'", "Create Private switch")) {
                    New-VMSwitch -Name $SwitchName -SwitchType Private | Out-Null
                }
            }
        }

        Write-Host "Switch creation request completed for '$SwitchName'." -ForegroundColor Green
    }
}

if ($ApplyVlan) {
    if ([string]::IsNullOrWhiteSpace($TargetVMName) -and [string]::IsNullOrWhiteSpace($ManagementAdapterName)) {
        throw "Specify either -TargetVMName or -ManagementAdapterName when using -ApplyVlan."
    }

    if ($VlanMode -eq 'Access') {
        if ($TargetVMName) {
            if ($PSCmdlet.ShouldProcess("VM '$TargetVMName'", "Set access VLAN $VlanId")) {
                Set-VMNetworkAdapterVlan -VMName $TargetVMName -Access -VlanId $VlanId
            }
        }

        if ($ManagementAdapterName) {
            if ($PSCmdlet.ShouldProcess("Management OS adapter '$ManagementAdapterName'", "Set access VLAN $VlanId")) {
                Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $ManagementAdapterName -Access -VlanId $VlanId
            }
        }
    }
    else {
        Write-Warning "Trunk mode is enabled only when your uplink design explicitly requires multiple VLANs and upstream switching supports it."
        if ($TargetVMName) {
            if ($PSCmdlet.ShouldProcess("VM '$TargetVMName'", "Set trunk VLAN $VlanId")) {
                Set-VMNetworkAdapterVlan -VMName $TargetVMName -Trunk -NativeVlanId $VlanId -AllowedVlanIdList $VlanId
            }
        }

        if ($ManagementAdapterName) {
            if ($PSCmdlet.ShouldProcess("Management OS adapter '$ManagementAdapterName'", "Set trunk VLAN $VlanId")) {
                Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $ManagementAdapterName -Trunk -NativeVlanId $VlanId -AllowedVlanIdList $VlanId
            }
        }
    }

    Write-Host "VLAN configuration completed." -ForegroundColor Green
}

Write-Section "Post-change validation"
if ($SwitchName) {
    Get-VMSwitch -Name $SwitchName | Select-Object Name, SwitchType, NetAdapterInterfaceDescription, AllowManagementOS | Format-List
}

if ($TargetVMName) {
    Get-VMNetworkAdapterVlan -VMName $TargetVMName | Format-List
}

if ($ManagementAdapterName) {
    Get-VMNetworkAdapter -ManagementOS -Name $ManagementAdapterName -ErrorAction SilentlyContinue | Format-List Name, SwitchName, Status
    Get-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $ManagementAdapterName | Format-List
}

Write-Host "Validation complete. Review output before moving the configuration into production." -ForegroundColor Green
```