Using Powershell to Change Microphone Defaults

This is my first experience with powershell that is in-depth. There was a lot of hassle to get my script to work too.

The Goal is to be able to find the microphone that has the name “Internal Mic” and to be able to change the defaults of microphones as you could by going to the Recording tab in the Sound menu from Control Panel and right-clicking your mic and “Set as default device” or “Set as default communication device”. The reason that my choice for using powershell is that it has the ability to find variable names and return that value.

As far as settings for Microphones in Windows goes they’re stored in registry at HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture . Here is where it would be easy to just say if you know the path then you can just use Group Policy to do the work for you but I couldn’t. The Microphones on every laptop that I could look at had different values for names even though they were for the same devices on the same model of computer. Here is a photo of those “names” aka key.

reg_microphone_capture

 

As you can see is that there are a few devices with no name that you can follow after \Capture\ because it is no longer the same from one computer to the next but is a good starting point on where to look for the settings.

After a bit of wading through registry I noticed that the devices that had been set to default also had Role’s in there key.

reg_microphone_role

 

So here you can see that Role:1 and Role:2 are already set. Role:1 is the Role that is set when you would “Set as default device” and Role:2 is for “Set as default communication device”. Here you can also set whether the device is disabled or not with DeviceState key. As the microphone that I want is already the default device but not the default communication device it is a bit easier to look for and set that second role.

So with that little background the goal with code is to find the key containing Role:1 and set a Role:2 by passing the variable named microphone.

  1. #ignore most commented out data like below
  2. #only way to easily input reg-binary is to use an array to set to convert to hex
  3. [int[]]$data = 221,07,12,00,05,00,27,00,17,00,55,00,58,00,143,03
  4. #[hex]$data2 = dd070c0005001200140011002d0015007b00
  5. #bytes = [Text.Encoding]::Unicode.GetBytes($data)
  6.  
  7. cd HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture
  8. #recursive search starts in the directory cd'ed to
  9. gci . -rec -ea SilentlyContinue | % {
  10. if((get-itemproperty -Path $_.PsPath) -match “Role:1)
  11. { $_.PsPath}
  12.  
  13. #$_.PsPath | Out-File C:\scripts\test2.txt -width 120
  14. #get rid of unneeded formatting in front
  15. $_pathMin = $_.PsPath.Substring(54)
  16. #get rid of unneeded formatting off end
  17. $_pathMin = $_pathMin.Substring(0, $_pathMin.Length-11)
  18. #put into correct path format
  19. $intMicParent = "HKLM:" + $_pathMin
  20. #$_pathMin + $bytes | Out-File C:\scripts\test3.txt -width 120
  21. }
  22.  
  23. #this next part is needed to take
  24. $acl = Get-Acl $intMicParent
  25.  
  26. # Admins may do everything:
  27. $person = [System.Security.Principal.NTAccount]”Administrators”
  28. $access = [System.Security.AccessControl.RegistryRights]"FullControl"
  29. $inheritance = [System.Security.AccessControl.InheritanceFlags]"None"
  30. $propagation = [System.Security.AccessControl.PropagationFlags]"None"
  31. $type = [System.Security.AccessControl.AccessControlType]"Allow"
  32. $rule = New-Object System.Security.AccessControl.RegistryAccessRule(`
  33. $person,$access,$inheritance,$propagation,$type)
  34. $acl.ResetAccessRule($rule)</code>
  35.  
  36. # Everyone may only read and create subkeys:
  37. $person = [System.Security.Principal.NTAccount]"Everyone"
  38. $access = [System.Security.AccessControl.RegistryRights]"ReadKey"
  39. $inheritance = [System.Security.AccessControl.InheritanceFlags]"None"
  40. $propagation = [System.Security.AccessControl.PropagationFlags]"None"
  41. $type = [System.Security.AccessControl.AccessControlType]"Allow"
  42. $rule = New-Object System.Security.AccessControl.RegistryAccessRule(`
  43. $person,$access,$inheritance,$propagation,$type)
  44. $acl.ResetAccessRule($rule)</code>
  45.  
  46. icacls $intMicParent /setowner "Administrator" /t
  47.  
  48. <code>Set-itemproperty -path $intMicParent -name "Role:2" -value ([byte[]]$data)
#ignore most commented out data like below
#only way to easily input reg-binary is to use an array to set to convert to hex
[int[]]$data = 221,07,12,00,05,00,27,00,17,00,55,00,58,00,143,03
#[hex]$data2 = dd070c0005001200140011002d0015007b00
#bytes = [Text.Encoding]::Unicode.GetBytes($data)

cd HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture
#recursive search starts in the directory cd'ed to
gci . -rec -ea SilentlyContinue | % {
if((get-itemproperty -Path $_.PsPath) -match “Role:1”)
{ $_.PsPath}

#$_.PsPath | Out-File C:\scripts\test2.txt -width 120
#get rid of unneeded formatting in front
$_pathMin = $_.PsPath.Substring(54)
#get rid of unneeded formatting off end
$_pathMin = $_pathMin.Substring(0, $_pathMin.Length-11)
#put into correct path format
$intMicParent = "HKLM:" + $_pathMin
#$_pathMin + $bytes | Out-File C:\scripts\test3.txt -width 120
}

#this next part is needed to take
$acl = Get-Acl $intMicParent

# Admins may do everything:
$person = [System.Security.Principal.NTAccount]”Administrators”
$access = [System.Security.AccessControl.RegistryRights]"FullControl"
$inheritance = [System.Security.AccessControl.InheritanceFlags]"None"
$propagation = [System.Security.AccessControl.PropagationFlags]"None"
$type = [System.Security.AccessControl.AccessControlType]"Allow"
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(`
$person,$access,$inheritance,$propagation,$type)
$acl.ResetAccessRule($rule)</code>

# Everyone may only read and create subkeys:
$person = [System.Security.Principal.NTAccount]"Everyone"
$access = [System.Security.AccessControl.RegistryRights]"ReadKey"
$inheritance = [System.Security.AccessControl.InheritanceFlags]"None"
$propagation = [System.Security.AccessControl.PropagationFlags]"None"
$type = [System.Security.AccessControl.AccessControlType]"Allow"
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(`
$person,$access,$inheritance,$propagation,$type)
$acl.ResetAccessRule($rule)</code>

icacls $intMicParent /setowner "Administrator" /t

<code>Set-itemproperty -path $intMicParent -name "Role:2" -value ([byte[]]$data)

Some of that may or may not be needed and as you can see I did set up some outputs to see exactly what was going on.
I did have several different iterations of the script but it was not till later that I learned that the denial of access wasnt a joke. The way our environment is set up(not my choice) I also had to get rights and run it with some other code with group policy. So yes I have Group Policy running a script to run a script (basically). First up is the ability to run a powershell script which when in a command prompt can be entered as

powershell -ExecutionPolicy ByPass -File \\path\to$\powershell.ps1

but at that point I found out that if this is being run at the level of just any plain user that logs in it will throw another access error. This time, after a little more research, is about registry access and that the easy way to allow changes is to make the current user the owner of the HKLM:\..\Capture\ . So in another file named owner.cmd we have the code to change ownership to current user.

  1. @echo off
  2.  
  3. if exist %windir%\system32\subinacl.exe (
  4. takeown /F %windir%\system32\subinacl.exe >nul
  5. icacls %windir%\system32\subinacl.exe /GRANT *S-1-1-0:F >nul
  6. subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /setowner=%username% >nul
  7. subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /grant=%username%=F >nul
  8. powershell -executionpolicy bypass -file \\path\to$\powershell.ps1
  9. )
  10. else (
  11. copy \\gmmsrv\msi$\Mic\subinacl.exe C:\Windows\System32
  12. takeown /F %windir%\system32\subinacl.exe >nul
  13. icacls %windir%\system32\subinacl.exe /GRANT *S-1-1-0:F >nul
  14. subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /setowner=%username% >nul
  15. subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /grant=%username%=F >nul
  16. powershell -executionpolicy bypass -file \\path\to$\powershell.ps1
  17. )
  18. exit
@echo off

if exist %windir%\system32\subinacl.exe (
takeown /F %windir%\system32\subinacl.exe >nul
icacls %windir%\system32\subinacl.exe /GRANT *S-1-1-0:F >nul
subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /setowner=%username% >nul
subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /grant=%username%=F >nul
powershell -executionpolicy bypass -file \\path\to$\powershell.ps1
)
else (
copy \\gmmsrv\msi$\Mic\subinacl.exe C:\Windows\System32
takeown /F %windir%\system32\subinacl.exe >nul
icacls %windir%\system32\subinacl.exe /GRANT *S-1-1-0:F >nul
subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /setowner=%username% >nul
subinacl /subkeyreg HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture /grant=%username%=F >nul
powershell -executionpolicy bypass -file \\path\to$\powershell.ps1
)
exit

With that you can see the powershell executionpolicy was used along with the ownership changed.

When all is said and done the script is run, it searches for role:1, and adds role:2. This worked for me and I hope this helps someone else. If you have a question or comment add one down below

You may also like...