This is challenging because of the necessary interoperation with WinRT, but it is possible in pure PowerShell:
[CmdletBinding()] Param (
[Parameter(Mandatory=$true)][ValidateSet('Off', 'On')][string]$BluetoothStatus
)
If ((Get-Service bthserv).Status -eq 'Stopped') { Start-Service bthserv }
Add-Type -AssemblyName System.Runtime.WindowsRuntime
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[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
Await ([Windows.Devices.Radios.Radio]::RequestAccessAsync()) ([Windows.Devices.Radios.RadioAccessStatus]) | Out-Null
$radios = Await ([Windows.Devices.Radios.Radio]::GetRadiosAsync()) ([System.Collections.Generic.IReadOnlyList[Windows.Devices.Radios.Radio]])
$bluetooth = $radios | ? { $_.Kind -eq 'Bluetooth' }
[Windows.Devices.Radios.RadioState,Windows.System.Devices,ContentType=WindowsRuntime] | Out-Null
Await ($bluetooth.SetStateAsync($BluetoothStatus)) ([Windows.Devices.Radios.RadioAccessStatus]) | Out-Null
To use it, save it is a PS1 file, e.g. bluetooth.ps1
. If you haven't already, follow the instructions in the Enabling Scripts section of the PowerShell tag wiki to enable the execution of scripts on your system. Then you can run it from a PowerShell prompt like this:
.\bluetooth.ps1 -BluetoothStatus On
To turn Bluetooth off, pass Off
instead.
To run it from a batch file:
powershell -command .\bluetooth.ps1 -BluetoothStatus On
Caveat: If the Bluetooth Support Service is not running, the script attempts to start it because otherwise, WinRT will not see Bluetooth radios. Alas, the service cannot be started if the script is not running as administrator. To make that unnecessary, you can change the startup type of that service to automatic.
Now for some explanation. The first three lines establish the parameters the script takes. Before beginning in earnest, we make sure the Bluetooth Support Service is running and start it if not. We then load the System.Runtime.WindowsRuntime
assembly so that we can use the WindowsRuntimeSystemExtensions.AsTask
method to convert WinRT-style tasks (which .NET/PowerShell doesn't understand) to .NET Task
s. That particular method has a boatload of different parameter sets which seem to trip up PowerShell's overload resolution, so in the next line we get the specific one that takes only a resultful WinRT task. Then we define a function that we'll use several times to extract a result of the appropriate type from an asynchronous WinRT task. Following that function's declaration, we load two necessary types from WinRT metadata. The remainder of the script is pretty much just a PowerShell translation of the C# code you wrote in your answer; it uses the Radio
WinRT class to find and configure the Bluetooth radio.
How are you playing the music? – harrymc – 2018-02-04T20:33:00.943
Using Winamp :) – Martin Pecka – 2018-02-04T21:04:15.353
Does killing Winamp stop the music? – harrymc – 2018-02-04T21:57:21.067
Of course, why it wouldn't? But the question is not about stopping music playback, it is about control of the BT radio. – Martin Pecka – 2018-02-04T23:20:01.210
You can't stop the music by disabling the device. You don't want to stop the play by the program. So all you have left is to mute the device. Would that be a solution? – harrymc – 2018-02-05T08:39:03.377
2@harrymc Read the question, please. Music playback is just a way how I detect if the Bluetooth connection is alive or not. What I'm really interested in is really a way to disable/enable the Bluetooth adapter. – Martin Pecka – 2018-02-05T09:31:42.913