param( [Parameter(Mandatory=$true)] [ValidateSet("list","set","next","current")] [string]$Action, [int]$Index = -1 ) $ErrorActionPreference = 'Stop' Add-Type -TypeDefinition @' using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace JarvisAudio { [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IMMDeviceEnumerator { [PreserveSig] int EnumAudioEndpoints(int dataFlow, int stateMask, out IMMDeviceCollection devices); [PreserveSig] int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice device); [PreserveSig] int GetDevice([MarshalAs(UnmanagedType.LPWStr)] string id, out IMMDevice device); } [Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IMMDeviceCollection { [PreserveSig] int GetCount(out int count); [PreserveSig] int Item(int idx, out IMMDevice device); } [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IMMDevice { [PreserveSig] int Activate(ref Guid iid, int clsCtx, IntPtr activationParams, [MarshalAs(UnmanagedType.IUnknown)] out object iface); [PreserveSig] int OpenPropertyStore(int access, out IPropertyStore store); [PreserveSig] int GetId([MarshalAs(UnmanagedType.LPWStr)] out string id); [PreserveSig] int GetState(out int state); } [Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IPropertyStore { [PreserveSig] int GetCount(out int count); [PreserveSig] int GetAt(int idx, out PROPERTYKEY key); [PreserveSig] int GetValue(ref PROPERTYKEY key, out PROPVARIANT value); } [StructLayout(LayoutKind.Sequential)] public struct PROPERTYKEY { public Guid formatId; public int propertyId; } [StructLayout(LayoutKind.Sequential)] public struct PROPVARIANT { public ushort vt; public ushort r1; public ushort r2; public ushort r3; public IntPtr p; public IntPtr p2; } [ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] public class MMDeviceEnumerator {} [Guid("F8679F50-850A-41CF-9C72-430F290290C8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IPolicyConfig { [PreserveSig] int GetMixFormat(); [PreserveSig] int GetDeviceFormat(); [PreserveSig] int ResetDeviceFormat(); [PreserveSig] int SetDeviceFormat(); [PreserveSig] int GetProcessingPeriod(); [PreserveSig] int SetProcessingPeriod(); [PreserveSig] int GetShareMode(); [PreserveSig] int SetShareMode(); [PreserveSig] int GetPropertyValue(); [PreserveSig] int SetPropertyValue(); [PreserveSig] int SetDefaultEndpoint([MarshalAs(UnmanagedType.LPWStr)] string deviceId, uint role); [PreserveSig] int SetEndpointVisibility(); } [ComImport, Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")] public class PolicyConfigClient {} public class Device { public string Id { get; set; } public string Name { get; set; } } public static class Manager { const int eRender = 0; const int DEVICE_STATE_ACTIVE = 1; static PROPERTYKEY PKEY_Device_FriendlyName = new PROPERTYKEY { formatId = new Guid("a45c254e-df1c-4efd-8020-67d146a850e0"), propertyId = 14 }; public static List ListRender() { var enumr = (IMMDeviceEnumerator)new MMDeviceEnumerator(); IMMDeviceCollection coll; int hr = enumr.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, out coll); if (hr != 0) throw new Exception("EnumAudioEndpoints failed: 0x" + hr.ToString("X")); int count; coll.GetCount(out count); var result = new List(); for (int i = 0; i < count; i++) { IMMDevice dev; coll.Item(i, out dev); string id; dev.GetId(out id); IPropertyStore store; dev.OpenPropertyStore(0, out store); PROPVARIANT v; store.GetValue(ref PKEY_Device_FriendlyName, out v); string name = v.p != IntPtr.Zero ? Marshal.PtrToStringUni(v.p) : "(unknown)"; result.Add(new Device { Id = id, Name = name }); } return result; } public static string GetDefaultRenderId() { var enumr = (IMMDeviceEnumerator)new MMDeviceEnumerator(); IMMDevice dev; int hr = enumr.GetDefaultAudioEndpoint(eRender, 0, out dev); // eConsole = 0 if (hr != 0) return null; string id; dev.GetId(out id); return id; } public static void SetDefault(string deviceId) { var cfg = (IPolicyConfig)new PolicyConfigClient(); cfg.SetDefaultEndpoint(deviceId, 0); // eConsole cfg.SetDefaultEndpoint(deviceId, 1); // eMultimedia cfg.SetDefaultEndpoint(deviceId, 2); // eCommunications } } } '@ -Language CSharp $devs = [JarvisAudio.Manager]::ListRender() switch ($Action) { "list" { for ($i = 0; $i -lt $devs.Count; $i++) { Write-Output ("{0}`t{1}" -f $i, $devs[$i].Name) } } "current" { $cur = [JarvisAudio.Manager]::GetDefaultRenderId() for ($i = 0; $i -lt $devs.Count; $i++) { if ($devs[$i].Id -eq $cur) { Write-Output ("{0}`t{1}" -f $i, $devs[$i].Name) return } } Write-Output "-1`t(unknown)" } "set" { if ($Index -lt 0 -or $Index -ge $devs.Count) { Write-Error "Index out of range: $Index (have $($devs.Count) devices)" exit 2 } [JarvisAudio.Manager]::SetDefault($devs[$Index].Id) Write-Output ("OK`t{0}" -f $devs[$Index].Name) } "next" { $cur = [JarvisAudio.Manager]::GetDefaultRenderId() $curIdx = -1 for ($i = 0; $i -lt $devs.Count; $i++) { if ($devs[$i].Id -eq $cur) { $curIdx = $i; break } } $nextIdx = ($curIdx + 1) % $devs.Count [JarvisAudio.Manager]::SetDefault($devs[$nextIdx].Id) Write-Output ("OK`t{0}" -f $devs[$nextIdx].Name) } }