How can I mute/unmute my sound from PowerShell
Asked Answered
R

13

30

Trying to write a PowerShell cmdlet that will mute the sound at start, unless already muted, and un-mute it at the end (only if it wasn't muted to begin with). Couldn't find any PoweShell or WMI object I could use. I was toying with using Win32 functions like auxGetVolume or auxSetVolume, but couldn't quite get it to work (how to read the values from an IntPtr?).

I'm using V2 CTP2. Any ideas folks?

Thanks!

Richard answered 1/11, 2008 at 2:11 Comment(1)
Have you seen this question (it reltes to beep, but I'm not sure what sounds you are talking about)? #253299Proem
G
8

There does not seem to be a quick and easy way to adjust the volume.. If you have c++ experience, you could do something with this blog post, where Larry Osterman describes how to call the IAudioEndpointVolume interface from the platform api(for Vista, XP might be more difficult from what I've found in a few searches).

V2 does allow you to compile inline code (via Add-Type), so that might be an option.

Grettagreuze answered 1/11, 2008 at 19:25 Comment(0)
K
41

Starting with Vista you have to use the Core Audio API to control the system volume. It's a COM API that doesn't support automation and thus requires a lot of boilerplate to use from .NET and PowerShell.

Anyways the code bellow let you access the [Audio]::Volume and [Audio]::Mute properties from PowerShell. This also work on a remote computer which could be useful. Just copy-paste the code in your PowerShell window.

Add-Type -TypeDefinition @'
using System.Runtime.InteropServices;

[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAudioEndpointVolume {
  // f(), g(), ... are unused COM method slots. Define these if you care
  int f(); int g(); int h(); int i();
  int SetMasterVolumeLevelScalar(float fLevel, System.Guid pguidEventContext);
  int j();
  int GetMasterVolumeLevelScalar(out float pfLevel);
  int k(); int l(); int m(); int n();
  int SetMute([MarshalAs(UnmanagedType.Bool)] bool bMute, System.Guid pguidEventContext);
  int GetMute(out bool pbMute);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDevice {
  int Activate(ref System.Guid id, int clsCtx, int activationParams, out IAudioEndpointVolume aev);
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDeviceEnumerator {
  int f(); // Unused
  int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint);
}
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] class MMDeviceEnumeratorComObject { }

public class Audio {
  static IAudioEndpointVolume Vol() {
    var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator;
    IMMDevice dev = null;
    Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(/*eRender*/ 0, /*eMultimedia*/ 1, out dev));
    IAudioEndpointVolume epv = null;
    var epvid = typeof(IAudioEndpointVolume).GUID;
    Marshal.ThrowExceptionForHR(dev.Activate(ref epvid, /*CLSCTX_ALL*/ 23, 0, out epv));
    return epv;
  }
  public static float Volume {
    get {float v = -1; Marshal.ThrowExceptionForHR(Vol().GetMasterVolumeLevelScalar(out v)); return v;}
    set {Marshal.ThrowExceptionForHR(Vol().SetMasterVolumeLevelScalar(value, System.Guid.Empty));}
  }
  public static bool Mute {
    get { bool mute; Marshal.ThrowExceptionForHR(Vol().GetMute(out mute)); return mute; }
    set { Marshal.ThrowExceptionForHR(Vol().SetMute(value, System.Guid.Empty)); }
  }
}
'@

Usage sample:

PS C:\> [Audio]::Volume         # Check current volume (now about 10%)
0,09999999
PS C:\> [Audio]::Mute           # See if speaker is muted
False
PS C:\> [Audio]::Mute = $true   # Mute speaker
PS C:\> [Audio]::Volume = 0.75  # Set volume to 75%
PS C:\> [Audio]::Volume         # Check that the changes are applied
0,75
PS C:\> [Audio]::Mute
True
PS C:\>

There are more comprehensive .NET wrappers out there for the Core Audio API if you need one but I'm not aware of a set of PowerShell friendly cmdlets.

P.S. Diogo answer seems clever but it doesn't work for me.

Kudos answered 1/11, 2008 at 2:11 Comment(3)
Any chance you could share how to mute/unmute the mic using this approach?Sandusky
I since found this which is more complete: github.com/frgnca/AudioDeviceCmdletsKudos
Thank you so much!Sandusky
A
25

Use the following commands on a ps1 powershell script:

$obj = new-object -com wscript.shell 
$obj.SendKeys([char]173)
Ashleeashleigh answered 13/9, 2012 at 0:12 Comment(3)
To run with .bat places this code inside the file and write powershell.exe -file "C: \ file.ps1"Electro
Thanks.. Added keyboard shortcut 'F4' working like a charm.Contemplative
This is a nice and simple method of hitting the mute key, however it's only a toggle and not a discrete mute. Without knowing the state of the volume it could do the opposite of what's intended.Anuska
B
12

Alexandre's answer fit my situation, but his example does not work due to compilation errors regarding the namespace of 'var'. It seems that newer/different versions of .net may cause the example not to work. If you found that you received compilation errors, this is an alternative version to try for those cases:

Add-Type -Language CsharpVersion3 -TypeDefinition @'
using System.Runtime.InteropServices;

[Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IAudioEndpointVolume {
  // f(), g(), ... are unused COM method slots. Define these if you care
  int f(); int g(); int h(); int i();
  int SetMasterVolumeLevelScalar(float fLevel, System.Guid pguidEventContext);
  int j();
  int GetMasterVolumeLevelScalar(out float pfLevel);
  int k(); int l(); int m(); int n();
  int SetMute([MarshalAs(UnmanagedType.Bool)] bool bMute, System.Guid pguidEventContext);
  int GetMute(out bool pbMute);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDevice {
  int Activate(ref System.Guid id, int clsCtx, int activationParams, out IAudioEndpointVolume aev);
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMDeviceEnumerator {
  int f(); // Unused
  int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint);
}
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] class MMDeviceEnumeratorComObject { }

public class Audio {
  static IAudioEndpointVolume Vol() {
    var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator;
    IMMDevice dev = null;
    Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(/*eRender*/ 0, /*eMultimedia*/ 1, out dev));
    IAudioEndpointVolume epv = null;
    var epvid = typeof(IAudioEndpointVolume).GUID;
    Marshal.ThrowExceptionForHR(dev.Activate(ref epvid, /*CLSCTX_ALL*/ 23, 0, out epv));
    return epv;
  }
  public static float Volume {
    get {float v = -1; Marshal.ThrowExceptionForHR(Vol().GetMasterVolumeLevelScalar(out v)); return v;}
    set {Marshal.ThrowExceptionForHR(Vol().SetMasterVolumeLevelScalar(value, System.Guid.Empty));}
  }
  public static bool Mute {
    get { bool mute; Marshal.ThrowExceptionForHR(Vol().GetMute(out mute)); return mute; }
    set { Marshal.ThrowExceptionForHR(Vol().SetMute(value, System.Guid.Empty)); }
  }
}
'@

Usage is the same:

PS C:\> [Audio]::Volume         # Check current volume (now about 10%)
0,09999999
PS C:\> [Audio]::Mute           # See if speaker is muted
False
PS C:\> [Audio]::Mute = $true   # Mute speaker
PS C:\> [Audio]::Volume = 0.75  # Set volume to 75%
PS C:\> [Audio]::Volume         # Check that the changes are applied
0,75
PS C:\> [Audio]::Mute
True
PS C:\>
Bassist answered 7/10, 2016 at 16:18 Comment(4)
Nice. Could this be extended to cover microphone/recording devices as well ?Gadhelic
Nice like Nick at Night!!Medick
@Gadhelic yes if you change the first argument to enumerator.GetDefaultAudioEndpoint to be 1 (eCapture) instead of 0 (eRender) then this works to mute/unmute the default microphone / input device.Brader
It's also worth pointing out what is the only difference between this and Alexandre's answer above (stackoverflow.com/a/19348221) which is the addition of -Language CsharpVersion3. It might be less confusing if this answer had just been a comment on that question instead.Brader
V
8

You could skin the cat another way by simply managing the Windows Audio Service. Stop it to mute, start it to unmute.

Venule answered 1/11, 2008 at 5:29 Comment(5)
This is the simplest option I found in my search today +1. "net stop "Windows Audio"Sculpsit
In powershell: Stop-Service -DisplayName "Windows Audio" & Start-Service -DisplayName "Windows Audio". Wishing I had thought of that sooner.Demiurge
Simple, works (on my Win10 machine), and leads to the possibility of sending other keys or using other shell methods etc. NICE @Brian Adams stackoverflow.com/users/32992/brian-adamsCharqui
This can be problematic if you have a media file on pause while stopping and restarting the service. The video player may not be able to play the sound later, unless you stop and restart the playback.Hoptoad
Note - this requires admin privileges which is a deal breaker for me.Rexfourd
G
8

There does not seem to be a quick and easy way to adjust the volume.. If you have c++ experience, you could do something with this blog post, where Larry Osterman describes how to call the IAudioEndpointVolume interface from the platform api(for Vista, XP might be more difficult from what I've found in a few searches).

V2 does allow you to compile inline code (via Add-Type), so that might be an option.

Grettagreuze answered 1/11, 2008 at 19:25 Comment(0)
M
6

I know it isn't PowerShell, but combining the answers from Michael and Diogo gives a one-line VBScript solution:

CreateObject("WScript.Shell").SendKeys(chr(173))

Slap this in mute.vbs, and you can just double-click to toggle mute

  • still works in Windows 10 (10586.104)
  • no need to Set-ExecutionPolicy as you might with PowerShell
Mcgill answered 18/2, 2016 at 22:44 Comment(0)
F
3

Solution in vbscript:

Set WshShell = CreateObject("WScript.Shell")
For i = 0 To 50
  WshShell.SendKeys(chr(174))
  WScript.Sleep 100
Next

The keys reduce the volume by 2 each time.

Fuselage answered 31/1, 2013 at 0:43 Comment(0)
B
2

I didn't find how to do this in PowerShell, but there is a command-line utility called NirCmd that will do the trick by running this command:

C:\utils\nircmd.exe mutesysvolume 0  # 1 to to unmute, 2 to toggle

NirCmd is available for free here: http://www.nirsoft.net/utils/nircmd.html

Belkisbelknap answered 3/11, 2009 at 23:33 Comment(0)
H
1

Check out my answer to Change audio level from powershell?

Set-DefaultAudioDeviceMute
Hols answered 29/7, 2014 at 12:48 Comment(0)
E
1

lemme try again, after getting some feedback on my answer

This is based on @frgnca's AudioDeviceCmdlets, found here: https://github.com/frgnca/AudioDeviceCmdlets

Here is code that will mute every recording device.

Import-Module .\AudioDeviceCmdlets
$audio_device_list = Get-AudioDevice -list
$recording_devices = $audio_device_list | ? {$_.Type -eq "Recording"}
$recording_devices 
$recording_device_index = $recording_devices.Index | Out-String -stream
foreach ($i in $recording_device_index) {
    $inti = [int]$i
    Set-AudioDevice $inti | out-null -erroraction SilentlyContinue
    Set-AudioDevice -RecordingMute 1 -erroraction SilentlyContinue
}

You import the AudioDeviceCmdlets dll, then save a list of all audio devices, filtered down into recording devices. You grab the index of all the recording devices and then iterate through each one, first setting the device to be your primary audio device, then setting that device to mute (this 2 step process is a limitation imposed by the dll).

To unmute everything, you change -RecordingMute 1 to RecordingMute 0

Similarly, to mute playback devices you can use this code:

Import-Module .\AudioDeviceCmdlets
$audio_device_list = Get-AudioDevice -list
$playback_devices = $audio_device_list | ? {$_.Type -eq "Playback"}
$playback_devices 
$playback_device_index = $playback_devices.Index | Out-String -stream
foreach ($i in $playback_device_index) {
$inti = [int]$i
    Set-AudioDevice $inti | out-null -erroraction SilentlyContinue
    Set-AudioDevice -PlaybackMute 1 -erroraction SilentlyContinue
}

To unmute everything, you change -PlaybackMute 1 to PlaybackMute 0

This code comes from part of a bigger project I have which hooks up to a physical button/LED mute status display via Arduino to enable single button press to Mute/Unmute all system microphones (to help with Zoom, Meet, Teams, Discord, etc.) and to help people avoid embarrassing hot-mic incidents.

https://github.com/dakota-mewt/mewt

1

P.S. I really like some of the one-line solutions like Change audio level from powershell?

However, note that a single-line muting typically applies only to the single device that's currently set as the windows default. So if you have software that's capable of addressing different audio devices (like Zoom and Meet), and they happen to be using a non-default device, it may not work as desired.

Egwin answered 23/12, 2020 at 16:49 Comment(1)
post a self-contained solution instead of a linkAmin
G
0

In the second script above, to work in PowerShell 7 or PowerShell Core in the 1st line change:

-Language CsharpVersion3

to...

-Language Csharp

Working on W10

Gasperoni answered 29/7, 2020 at 14:46 Comment(1)
Or just omit the -Language parameter entirely (CSharp is the only acceptable value in PowerShell 7, as well as being the default, see documentation) as was the case in Alexandre's original answer - i.e. this is not a new answer and might have been better as a comment on the answer above.Brader
S
0

Here's a simple timed mute script using autohotkey (from autohotkey dotcom).

mbutton:: ; Trigger this script with a click on the mouse wheel

SoundSet, +1,, Mute ; Mute the PC sound

sleep, 27000 ; Wait 27 seconds for the annoying advertisement to run

SoundSet, +1,, Mute ; Unmute the PC sound

Schermerhorn answered 27/6, 2022 at 1:10 Comment(0)
P
-1

Mute

Stop-Service -Name Audiosrv

Unmute

Start-Service -Name Audiosrv
Penitential answered 16/11, 2023 at 14:44 Comment(1)
Stopping the whole service just to mute...Seagraves

© 2022 - 2024 — McMap. All rights reserved.