- Context
My son installed a sofware to change his voice.
Unfortunately, I don’t have this software in my profile but the default device is set to use this virtual device as microphone.
- Solution
I was looking for a way to change the default input and found the following promissing links:
https://github.com/frgnca/AudioDeviceCmdlets
https://github.com/SomeProgrammerGuy/Powershell-Default-Audio-Device-Changer/blob/master/Set-DefaultAudioDevice.ps1
Although it’s designed for Windows 7, I’ve decided to write a script that would set the default device based on the name of the device (using a dynamic paramter) on my Windows 10.
#Requires -RunAsAdministrator | |
#Requires -PSEdition Desktop | |
[CmdletBinding(SupportsShouldProcess)] | |
Param() | |
DynamicParam { | |
$Dictionary = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameterDictionary | |
#region helper function | |
Function New-ParameterAttributCollection { | |
[CmdletBinding()] | |
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] | |
Param( | |
[Switch]$Mandatory, | |
[Switch]$ValueFromPipeline, | |
[Switch]$ValueFromPipelineByPropertyName, | |
[String]$ParameterSetName, | |
[Parameter()] | |
[ValidateSet( | |
'Arguments','Count','Drive','EnumeratedArguments','Length','NotNull', | |
'NotNullOrEmpty','Pattern','Range','Script','Set','UserDrive' | |
)][string]$ValidateType, | |
[Parameter()] | |
$ValidationContent | |
) | |
Begin { | |
}Process { | |
$c = New-Object System.Collections.ObjectModel.Collection[System.Attribute] | |
$a = New-Object System.Management.Automation.ParameterAttribute | |
if ($Mandatory) { | |
$a.Mandatory = $true | |
} | |
if ($ValueFromPipeline) { | |
$a.ValueFromPipeline = $true | |
} | |
if ($ValueFromPipelineByPropertyName) { | |
$a.ValueFromPipelineByPropertyName=$true | |
} | |
if ($ParameterSetName) { | |
$a.ParameterSetName = $ParameterSetName | |
} | |
$c.Add($a) | |
if ($ValidateType -and $ValidationContent) { | |
try { | |
$c.Add((New-Object "System.Management.Automation.Validate$($ValidateType)Attribute"( | |
$ValidationContent | |
))) | |
} catch { | |
Throw $_ | |
} | |
} | |
$c | |
} | |
End {} | |
} | |
#endregion | |
try { | |
$audioDevices = Get-PnpDevice -ErrorAction Stop | | |
Where-Object {$_.Class -eq 'AudioEndpoint' } | | |
Select-Object -Property Caption,Status,DeviceID | | |
Foreach-Object { | |
[PSCustomObject]@{ | |
DeviceName = $_.Caption | |
Status = $_.Status | |
Id = ($_.DeviceID -split '\.')[4] | |
} | |
} | |
} catch { | |
Throw 'Failed to enumerate audio devices' | |
} | |
#region param DeviceName | |
$Dictionary.Add( | |
'DeviceName', | |
(New-Object System.Management.Automation.RuntimeDefinedParameter( | |
'DeviceName', | |
[string], | |
(New-ParameterAttributCollection -Mandatory -ValidateType Set -ValidationContent ( | |
$audioDevices | ForEach-Object { $_.DeviceName } | |
)) | |
)) | |
) | |
$Dictionary | |
} | |
Begin {} | |
Process {} | |
End { | |
#Source: https://github.com/SomeProgrammerGuy/Powershell-Default-Audio-Device-Changer/blob/master/Set-DefaultAudioDevice.ps1 | |
$cSharpSourceCode = @" | |
using System; | |
using System.Runtime.InteropServices; | |
// eConsole: Games, system notification sounds, and voice commands. // | |
// eMultimedia: Music, movies, narration, and live music recording. // | |
// eCommunications: Voice communications (talking to another person). // | |
// ERole_enum_count: The number of members in the ERole enumeration // | |
// (not counting the ERole_enum_count member). // | |
public enum ERole : uint | |
{ | |
eConsole = 0, | |
eMultimedia = 1, | |
eCommunications = 2, | |
ERole_enum_count = 3 | |
} | |
// Undocumented COM-interface IPolicyConfig. // | |
// Use to set default audio Capture / Render endpoint. // | |
[Guid("F8679F50-850A-41CF-9C72-430F290290C8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | |
internal interface IPolicyConfig | |
{ | |
// HRESULT GetMixFormat(PCWSTR, WAVEFORMATEX **); | |
[PreserveSig] | |
int GetMixFormat(); | |
// HRESULT STDMETHODCALLTYPE GetDeviceFormat(PCWSTR, INT, WAVEFORMATEX **); | |
[PreserveSig] | |
int GetDeviceFormat(); | |
// HRESULT STDMETHODCALLTYPE ResetDeviceFormat(PCWSTR); | |
[PreserveSig] | |
int ResetDeviceFormat(); | |
// HRESULT STDMETHODCALLTYPE SetDeviceFormat(PCWSTR, WAVEFORMATEX *, WAVEFORMATEX *); | |
[PreserveSig] | |
int SetDeviceFormat(); | |
// HRESULT STDMETHODCALLTYPE GetProcessingPeriod(PCWSTR, INT, PINT64, PINT64); | |
[PreserveSig] | |
int GetProcessingPeriod(); | |
// HRESULT STDMETHODCALLTYPE SetProcessingPeriod(PCWSTR, PINT64); | |
[PreserveSig] | |
int SetProcessingPeriod(); | |
// HRESULT STDMETHODCALLTYPE GetShareMode(PCWSTR, struct DeviceShareMode *); | |
[PreserveSig] | |
int GetShareMode(); | |
// HRESULT STDMETHODCALLTYPE SetShareMode(PCWSTR, struct DeviceShareMode *); | |
[PreserveSig] | |
int SetShareMode(); | |
// HRESULT STDMETHODCALLTYPE GetPropertyValue(PCWSTR, const PROPERTYKEY &, PROPVARIANT *); | |
[PreserveSig] | |
int GetPropertyValue(); | |
// HRESULT STDMETHODCALLTYPE SetPropertyValue(PCWSTR, const PROPERTYKEY &, PROPVARIANT *); | |
[PreserveSig] | |
int SetPropertyValue(); | |
// HRESULT STDMETHODCALLTYPE SetDefaultEndpoint(__in PCWSTR wszDeviceId, __in ERole role); | |
[PreserveSig] | |
int SetDefaultEndpoint( | |
[In] [MarshalAs(UnmanagedType.LPWStr)] string wszDeviceId, | |
[In] [MarshalAs(UnmanagedType.U4)] ERole role); | |
// HRESULT STDMETHODCALLTYPE SetEndpointVisibility(PCWSTR, INT); | |
[PreserveSig] | |
int SetEndpointVisibility(); | |
} | |
[ComImport, Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")] | |
internal class _CPolicyConfigClient | |
{ | |
} | |
public class PolicyConfigClient | |
{ | |
public static int SetDefaultDevice(string deviceID) | |
{ | |
IPolicyConfig _policyConfigClient = (new _CPolicyConfigClient() as IPolicyConfig); | |
try | |
{ | |
Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eConsole)); | |
Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eMultimedia)); | |
Marshal.ThrowExceptionForHR(_policyConfigClient.SetDefaultEndpoint(deviceID, ERole.eCommunications)); | |
return 0; | |
} | |
catch | |
{ | |
return 1; | |
} | |
} | |
} | |
"@ | |
try { | |
Add-Type -TypeDefinition $cSharpSourceCode -ErrorAction Stop | |
} catch { | |
Write-Error 'Failed to add cSharp Code' | |
} | |
Function Set-DefaultAudioDevice { | |
[CmdletBinding(SupportsShouldProcess)] | |
[OutputType([System.Int32])] | |
Param ( | |
[parameter(Mandatory)] | |
[string]$deviceId | |
) | |
Begin {} | |
Process {} | |
End { | |
try { | |
if ($pscmdlet.ShouldProcess("$($deviceId)", 'Set default audio device to:')) { | |
[PolicyConfigClient]::SetDefaultDevice("{0.0.0.00000000}.$($deviceId)") | |
} | |
} catch { | |
Write-Error "Failed to set $($DeviceName) as default because $($_.Exception.Message)" | |
} | |
} | |
} | |
$d = $audioDevices | Where-Object { $_.DeviceName -eq "$($PSBoundParameters['DeviceName'])" } | |
try { | |
if ($pscmdlet.ShouldProcess("$($d.DeviceName)", 'Set default audio device to:')) { | |
$r = Set-DefaultAudioDevice -deviceId $d.Id | |
If ($r -eq 0) { | |
Write-Verbose -Message "Successfully set $($d.DeviceName) as default audio device" | |
} else { | |
Write-Warning -Message "Failed to set $($DeviceName) as default audio device, return code was $($r)" | |
} | |
} | |
} catch { | |
Write-Error -Message "Failed to set $($DeviceName) as default" | |
} | |
} |
How do I use it?
./Set-DefaultAudioDevice.ps1 -DeviceName 'Headset Earphone (HyperX Virtual Surround Sound)' -Verbose
The script has a WhatIf parameter and the dynamic parameter supports tab completion to find out present audio device names.
Next step, fire up a scheduled tasks that executes this script at every logon of my account 😀
Pingback: Dew Drop – June 26, 2023 (#3971) – Morning Dew by Alvin Ashcraft