Private/Scripts/Invoke-BluetoothState.ps1

param(
    [Parameter(Mandatory)]
    [ValidateSet('Get', 'Set')]
    [string]$Action,

    [Parameter()]
    [ValidateSet('On', 'Off')]
    [string]$BluetoothState
)

$ErrorActionPreference = 'Stop'

if ((Get-Service bthserv).Status -eq 'Stopped') { Start-Service bthserv }

Add-Type -AssemblyName System.Runtime.WindowsRuntime

$asTaskMethods = [System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object {
    $_.Name -eq 'AsTask' -and
    $_.GetParameters().Count -eq 1 -and
    $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1'
}

if (-not $asTaskMethods) {
    throw 'Unable to locate WinRT AsTask method. WinRT Bluetooth API may not be available on this system.'
}

$asTaskGeneric = $asTaskMethods[0]

function Await($WinRtTask, $ResultType) {
    $asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
    $netTask = $asTask.Invoke($null, @($WinRtTask))
    $netTask.Wait(-1) | Out-Null
    $netTask.Result
}

[Windows.Devices.Radios.Radio,Windows.System.Devices,ContentType=WindowsRuntime] | Out-Null
[Windows.Devices.Radios.RadioAccessStatus,Windows.System.Devices,ContentType=WindowsRuntime] | Out-Null
[Windows.Devices.Radios.RadioState,Windows.System.Devices,ContentType=WindowsRuntime] | Out-Null

$accessStatus = Await ([Windows.Devices.Radios.Radio]::RequestAccessAsync()) ([Windows.Devices.Radios.RadioAccessStatus])
if ($accessStatus -ne [Windows.Devices.Radios.RadioAccessStatus]::Allowed) {
    throw "Bluetooth access was denied. Status: $accessStatus"
}

$radios = Await ([Windows.Devices.Radios.Radio]::GetRadiosAsync()) ([System.Collections.Generic.IReadOnlyList[Windows.Devices.Radios.Radio]])
$bluetooth = $radios | Where-Object { $_.Kind -eq 'Bluetooth' } | Select-Object -First 1
if (-not $bluetooth) {
    throw 'No Bluetooth radio was found on this system.'
}

if ($Action -eq 'Set') {
    if (-not $BluetoothState) {
        $BluetoothState = if ($bluetooth.State -eq [Windows.Devices.Radios.RadioState]::On) { 'Off' } else { 'On' }
    }

    $setStatus = Await ($bluetooth.SetStateAsync($BluetoothState)) ([Windows.Devices.Radios.RadioAccessStatus])
    if ($setStatus -ne [Windows.Devices.Radios.RadioAccessStatus]::Allowed) {
        throw "Bluetooth state change failed. Status: $setStatus"
    }

    $refreshedRadios = Await ([Windows.Devices.Radios.Radio]::GetRadiosAsync()) ([System.Collections.Generic.IReadOnlyList[Windows.Devices.Radios.Radio]])
    $bluetooth = $refreshedRadios | Where-Object { $_.Kind -eq 'Bluetooth' } | Select-Object -First 1
}

[pscustomobject]@{ State = [string]$bluetooth.State } | ConvertTo-Json -Compress