I want to toggle airplane mode in Windows programmatically using PowerShell. After some research, I found that this can be done through COM interfaces and native Windows APIs. Below is a script I’ve written that successfully toggles airplane mode using P/Invoke.
Below is a PowerShell script that toggles airplane mode in Windows using COM interfaces and native Windows APIs.
# script for toggling the airplane mode in Windows
# carsten.giese@googlemail.com
cls
remove-variable * -ea 0
$ErrorActionPreference = 'stop'
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public static class NativeMethods {
[DllImport("ole32.dll")]
public static extern int CoInitialize(IntPtr pv);
[DllImport("ole32.dll")]
public static extern void CoUninitialize();
[DllImport("ole32.dll")]
public static extern uint CoCreateInstance(Guid clsid, IntPtr pv, uint ctx, Guid iid, out IntPtr ppv);
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int GetSystemRadioStateDelegate(IntPtr cg, out int ie, out int se, out int p3);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int SetSystemRadioStateDelegate(IntPtr ptr, int state);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int ReleaseDelegate(IntPtr ptr);
'@
$CLSID = '581333F6-28DB-41BE-BC7A-FF201F12F3F6'
$IID = 'DB3AFBFB-08E6-46C6-AA70-BF9A34C30AB7'
$CRID = '73726163-6574-676e-6965-736531333131'
$mrs = [System.Runtime.InteropServices.Marshal]
try {
$irm = 0
$null = [NativeMethods]::CoInitialize(0)
$null = [NativeMethods]::CoCreateInstance($CLSID, 0, 4, $IID, [ref]$irm)
$comPtr = $mrs::ReadIntPtr($irm)
$methodPtr = [IntPtr[]]::new(8)
$mrs::Copy($comPtr, $methodPtr, 0, $methodPtr.Length)
$getState = $mrs::GetDelegateForFunctionPointer($methodPtr[5], [GetSystemRadioStateDelegate])
$setState = $mrs::GetDelegateForFunctionPointer($methodPtr[6], [SetSystemRadioStateDelegate])
$release = $mrs::GetDelegateForFunctionPointer($methodPtr[2], [ReleaseDelegate])
# get the current airplane mode:
$oldState, $p2, $p3 = (0,0,0)
$null = $getState.Invoke($irm, [ref]$oldState, [ref]$p2, [ref]$p3)
# toggle the state of the airplane mode (# 0=airplane_mode, 1=normal_mode):
$newState = !$oldState
$null = $setState.Invoke($irm, $newState)
$null = $release.Invoke($irm)
}
finally {
$null = [NativeMethods]::CoUninitialize()
}
This PowerShell script toggles airplane mode in Windows by interacting directly with COM interfaces and native Windows APIs using P/Invoke. Below is a breakdown of how the script works and why specific elements are necessary.
Initialization and Setup:
Add-Type
to include C# code. It initializes the COM library using CoInitialize
and creates an instance of the COM object with CoCreateInstance
.Method Resolution with $methodPtr
:
$methodPtr
is an array of pointers extracted from the COM object’s virtual function table (vtable). This table contains the memory addresses of the object’s methods.Marshal.Copy
, the function pointers are copied into $methodPtr
, making individual methods accessible by their index.Using $methodPtr
Methods:
$methodPtr[5]
: Calls GetSystemRadioState
to get the current airplane mode status.$methodPtr[6]
: Calls SetSystemRadioState
to set (or toggle) the airplane mode.$methodPtr[2]
: Calls Release
to release the COM object after use.List of Methods in the vtable:
The COM object exposes the following methods via $methodPtr
:
Method 0
: QueryInterface
(internal for COM object communication).Method 1
: AddRef
(increments reference count).Method 2
: Release
(decrements reference count, frees resources).Method 5
: GetSystemRadioState
(fetches current airplane mode state).Method 6
: SetSystemRadioState
(toggles or sets airplane mode).Toggling Airplane Mode:
0
for enabled, 1
for disabled) using the GetSystemRadioState
delegate.SetSystemRadioState
delegate.Cleanup:
Release
method, and CoUninitialize
is called to clean up the COM environment.[UnmanagedFunctionPointer]
Required?The [UnmanagedFunctionPointer]
attribute is critical because it allows the script to define managed delegates that represent unmanaged function pointers. These are necessary to call methods from the COM object’s vtable.
Interfacing with Native Code:
[UnmanagedFunctionPointer]
act as a bridge, enabling managed code to interact with unmanaged function pointers.Specifying Calling Conventions:
CallingConvention.StdCall
ensures the method calls follow the correct calling convention used by the COM object.Mapping Method Signatures:
This script demonstrates how PowerShell can interact with COM interfaces for advanced Windows functionality, such as toggling airplane mode, without relying on external tools or GUIs.