46

Such a simple task, one would say, and I haven't found a satisfiable solution. What I've tried (with music playing through a Bluetooth-connected speaker to really know the state of the radio):

  • using devcon as admin: devcon disable USB\VID_8087&PID_07DC&REV_0001 (which is the HW ID of my Bluetooth adapter)... requires reboot to work...
  • using powershell as admin: Disable-NetAdapter "Bluetooth Network Connection 3" (which is translation of the name of my Bluetooth adapter)... it disables the PAN driver, but a Bluetooth speaker continues playing music...
  • using net as admin: net stop bthserv... doesn't actually turn off the radio (BT speaker continues playing music)
  • using .NET: The most relevant page on MSDN doesn't say a word about turning the adapter on/off.
  • using explorer: ms-settings:bluetooth or explorer.exe %LocalAppData%\Packages\windows.immersivecontrolpanel_cw5n1h2txyewy\LocalState\Indexed\Settings\cs-CZ\AAA_SettingsPagePCSystemBluetooth.settingcontent-ms... opens the Bluetooth settings panel, but I still have to click on the toggle

I can't believe Microsoft would be so ignorant to not provide such a command...

6
  • How are you playing the music?
    – harrymc
    Commented Feb 4, 2018 at 20:33
  • 1
    Using Winamp :) Commented Feb 4, 2018 at 21:04
  • Does killing Winamp stop the music?
    – harrymc
    Commented Feb 4, 2018 at 21:57
  • 1
    Of course, why it wouldn't? But the question is not about stopping music playback, it is about control of the BT radio. Commented Feb 4, 2018 at 23:20
  • 7
    @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. Commented Feb 5, 2018 at 9:31

10 Answers 10

52
+100

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 Tasks. 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.

21
  • 2
    You cannot call a method on a null-valued expression. At C:\Users\chx\AppData\Local\Microsoft\WindowsApps\bluetooth.ps1:18 char:1 + Await ($bluetooth.SetStateAsync($BluetoothStatus)) ([Windows.Devices.
    – chx
    Commented Feb 9, 2018 at 3:45
  • @chx Are you sure your machine has a Bluetooth adapter? If there is no Bluetooth radio, the third-to-last line will set $bluetooth to null, which will cause the second-to-last line to produce that error.
    – Ben N
    Commented Feb 9, 2018 at 3:46
  • 3
    Clever, it works! I just couldn't get to compile a desktop app using this API, but loading it dynamically in a script seems to be the way to go. Now, compare to rfkill unblock bluetooth on Linux :-D Commented Feb 10, 2018 at 0:30
  • 2
    To adapt this script so that it itself checck if the bluetooth is on (or off) and the stop it (or start it) see superuser.com/q/1494499
    – MagTun
    Commented Oct 24, 2019 at 6:12
  • 1
    @Stabledog That suggests that no Bluetooth radios were returned by GetRadiosAsync. You can check the $radios variable to see if all radio information is missing or just Bluetooth. If no radios are returned, make sure to run in 64-bit PowerShell. If just Bluetooth is absent, double-check that the Bluetooth service(s) are still running.
    – Ben N
    Commented Jan 1 at 19:42
11

After giving up to seek for ready-made solutions, I've found out that the Universal Windows Platform apps have access to the radio control API.

So I merged a sample radio control app with a commandline-controlled app, and the result is here: https://github.com/peci1/RadioControl . It's published on Windows Store.

In general, it isn't possible to just let the app run in background, so you need to first launch the GUI, and then you can call it from the commandline like

radiocontrol.exe 0 on
radiocontrol.exe Bluetooth off

The core features that this app needs are:

using Windows.Devices.Radios;
await Radio.RequestAccessAsync();
var radios = await Radio.GetRadiosAsync();
await radios[0].SetStateAsync(RadioState.On);

Then you also need to add the Radios capability to the app manifest:

<DeviceCapability Name="radios" />

And to allow control from commandline, you need to override method protected override async void OnActivated(IActivatedEventArgs args) in App.xaml.cs and do the processing in a branch like this:

switch (args.Kind)
        {
            case ActivationKind.CommandLineLaunch:
2
  • This answer better fits StackOverflow.
    – harrymc
    Commented Feb 5, 2018 at 11:40
  • @MartinPecka By chance, do you know how to reconnect Bluetooth hardware that has been disconnected using Disable/Enable-NetAdapter? superuser.com/questions/1444278/…
    – JinSnow
    Commented Jun 3, 2019 at 11:29
5

This Autohotkey script seems to do the trick. I am bothered by the Sleep there but it seems the window becomes active before it is ready to receive my keystrokes.

SendMode Input
Run, ms-settings:bluetooth
WinWaitActive, Settings
Sleep 300
Send,{Tab}{Space}
WinClose, A

Crossposted to https://stackoverflow.com/q/48700268/308851 to figure out what that Sleep 300 could be replaced with.

1
  • This could also be a solution in most cases. I needed to also add a short sleep after sending the keystrokes. And this solution doesn't work if the screen is locked. The Universal Windows app I posted above does work even with locked screen. Commented Feb 9, 2018 at 15:00
4

Here's a partial solution: wmic path Win32_PNPEntity where "caption like '%bluetooth%' AND DeviceID like 'USB\\%'" call disable certainly makes the Bluetooth On/Off switch disappear and Device Manager reports This device is disabled. (Code 22). Whether that's enough to kill the radio, I am not sure.

I am unable to find documentation on what arguments call accepts. I think there should be some sort of rfkill here.

1
  • I'm sorry, doesn't work for me as you describe it. For me, the Bluetooth playback stops, but all the bluetooth switches in control panel remain on. And calling with enable doesn't resume the Bluetooth playback. The documentation on the PNPEntity class is here: msdn.microsoft.com/en-us/library/aa394353(v=vs.85).aspx , but no other useful methods seem to be there... Commented Feb 4, 2018 at 17:43
4

How about using pnputil?

pnputil /disable-device "<device instance ID>"
pnputil /enable-device "<device instance ID>"

Does not require reboot.

1
  • 1
    finding the device ID is part of the problem Commented Oct 1, 2023 at 14:33
2

Executing the following command from Command Prompt (as administrator) did the trick:

netsh interface set interface name="Bluetooth Network Connection" admin=disabled

I had previously used the same command to disable my Wi-Fi adapter, and found that it also worked with the other adapters in: Control Panel > Network and Internet > Network Connections. Just change the "name" argument to the name of your adapter. You can also enable it again by changing the last argument to admin=enabled.

5
  • 2
    This also seems to just disable the PAN drivers, but doesn't turn off the radio device itself (in control panel, Bluetooth is still being reported as "on"). Commented Jul 5, 2017 at 23:57
  • 1
    Verified now by the bluetooth repro test, doesn't turn off bluetooth. Commented Jul 6, 2017 at 21:43
  • I'm sorry @peci1 , I misunderstood your question. I had previously been looking at questions relating to disabling Bluetooth and interpreted your question as the same. So your goal is to turn off (cut power to) the Bluetooth device? I will research a bit and let you know if I find anything. Commented Jul 7, 2017 at 2:33
  • @peci1 would this link be helpful at all? Commented Jul 16, 2017 at 22:09
  • No, it does not. It's about USB, not Bluetooth devices. And the linked Device Management Cmdlet doesn't work, either. Commented Aug 30, 2017 at 1:18
2

You can use DevManView to enable/disable a device from the command line using this syntax:

devmanview /disable <Device Name>   
devmanview /enable <Device Name>    

It also allows the use of wildcards with the /use_wildcard argument.

3
  • Devmanview is indeed a useful tool, but it doesn't solve my problem. The problem is that there doesn't seem to be a device which you could disable in device manager to turn off the bluetooth radio. Commented Feb 10, 2018 at 0:03
  • @MartinPecka Do you not see any of these? i.sstatic.net/UrOuc.png If not, you might want to try and update drivers...
    – undo
    Commented Feb 10, 2018 at 8:52
  • I do see the Bluetooth device, but disabling it doesn't stop the playback - probably because the system needs to be restarted for it to really become disabled (as stated in the original question). Commented Feb 10, 2018 at 17:19
1

I made a batch script that checks a reg key value which would only be in place if your bluetooth radio was enabled. It then calls Ben N's powershell script above with the correct parameter to switch its current state. Turns it into a toggle shortcut, rather than having to use on and off separately.

@echo off
FOR /F "skip=2 tokens=2,*" %%A IN ('reg.exe query "HKLM\SYSTEM\CurrentControlSet\Services\bthserv\Parameters\BluetoothControlPanelTasks" /v "state"') DO set "VAR=%%B"

if %VAR%==0x1 (goto ON)

Powershell.exe -executionpolicy remotesigned -windowstyle hidden -File ".\bluetooth.ps1" -BluetoothStatus On
goto end

:ON
Powershell.exe -executionpolicy remotesigned -windowstyle hidden -File ".\bluetooth.ps1" -BluetoothStatus Off

:end
0

Powershell has cmdlets for doing exactly what you're seeking:

https://gallery.technet.microsoft.com/PowerShell-Device-60d73bb0

Use Get-Device to get a list of the devices. You can pipe that through where-object to pick your device and then pipe that to Disable-Device or Enable-Device.

Detailed Instructions...

Download and unzip the file.

Start a powershell as admin.

Change execution policy if necessary:

Set-ExecutionPolicy Unrestricted

Import the module:

Import-Module .\DeviceManagement.psd1

If you need to narrow down the list of devices you can use a -like compare:

Get-Device | Where-Object {$_.Name -like '*bluetooth*'}

If you know the exact name you can use an -eq (equals) compare:

Get-Device | Where-Object {$_.Name -eq 'Martin's Bluetooth Adapter'} | Disable-Device -Confirm:$False

Wipe hands on pants.

5
  • 2
    This will disable the USB device instead of just the radio. wmic can do this too, at least I think so.
    – chx
    Commented Feb 9, 2018 at 3:39
  • The question didn't ask how to disable to radio but not the adapter. Why the distinction? If you can give me a good reason I'll consider digging for you, but I answered the question that was asked "What I'm really interested in is really a way to disable/enable the Bluetooth adapter. – Martin Pecka Feb 5 at 9:31" Commented Feb 9, 2018 at 4:04
  • I'm sorry, what's the difference between adapter and radio? I consider these two terms equivalent. There's a ***load of software devices this HW thing provides, and you're right this question is not about them. Commented Feb 10, 2018 at 0:06
  • Moreover, both this and the 2012 PS script from Ricardo Mendes do not work at my Win 10 1709 64bit, as is mentioned in their comments. Both end up with error Disable-Device : Error calling SetupDiCallClassInstaller. I run them as admin and with unrestricted execution policy. Commented Feb 10, 2018 at 0:22
  • Here it is my solution to turn bluetooth on/off using cmd: Commented Dec 7, 2023 at 5:08
0

@martin-pecka I had a similar issue (wanted to prevent new connections while in s3 sleep mode) and the answer I have here for me works on windows 11.

Not sure why you say using net as admin: net stop bthserv... doesn't actually turn off the radio (BT speaker continues playing music). When I run it in an admin cmd window, it asks me to press Y to forcibly break all active bluetooth connections (and you can automate it with /Y). Perhaps it only works in windows 11?

https://superuser.com/a/1826747/63383

1
  • I guess it could be a 10/11 difference in behavior. Commented Jan 21 at 21:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .