如何通过PowerShell静音/取消静音我的声音

30

尝试编写一个PowerShell cmdlet,以在启动时静音(仅当未静音时),并在结束时解除静音(仅当开始时没有被静音)。

无法找到任何可用的PoweShell或WMI对象。我在玩Win32函数,如auxGetVolumeauxSetVolume,但无法完全使其工作(如何从IntPtr读取值?)。

我正在使用V2 CTP2。有什么建议吗?

谢谢!


你看过这个问题吗?(它涉及到蜂鸣声,但我不确定你所说的是哪种声音)?http://stackoverflow.com/questions/252799/turning-off-the-cmd-window-beep-sound - Ady
13个回答

40

从Vista版本开始,您必须使用Core Audio API来控制系统音量。它是一个不支持自动化的COM API,因此需要大量的样板代码来在.NET和PowerShell中使用。

无论如何,下面的代码可以让您从PowerShell访问[Audio]::Volume[Audio]::Mute属性。 这也适用于远程计算机,这可能很有用。只需将代码复制粘贴到PowerShell窗口中即可。

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)); }
  }
}
'@

使用示例:

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:\>

如果您需要更全面的Core Audio API的.NET包装器,那么还有其他选择,但我不知道是否有适用于PowerShell的友好cmdlet集合。

P.S. Diogo的回答似乎很聪明,但对我来说不起作用。


有机会能分享一下如何使用这种方法静音/取消静音麦克风吗? - JDH
1
我后来发现了更完整的 这个:https://github.com/frgnca/AudioDeviceCmdlets - Alex Jasmin
非常感谢您! - JDH

24

使用以下命令在ps1 powershell脚本上:

$obj = new-object -com wscript.shell 
$obj.SendKeys([char]173)

1
要在 .bat 中运行,请将此代码放入文件中并编写 **powershell.exe -file "C:\file.ps1"**。 - SneepS NinjA
谢谢。添加了键盘快捷键“F4”,效果非常好。 - Eddie Kumar
4
这是一个简单易用的静音方法,但它只是个切换键而不是一个明确的静音键。如果不知道音量的状态,它可能会产生相反的效果。 - Chuck Claunch

12

Alexandre的回答适合我的情况,但他的示例由于有关“var”名称空间的编译错误而无法使用。似乎较新/不同版本的.NET可能导致示例无法工作。如果您发现收到编译错误,则可以尝试以下替代版本:

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)); }
  }
}
'@

使用方法相同:

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:\>

不错。这个能扩展到覆盖麦克风/录音设备吗? - monojohnny
晚上尼克一样好!! - Bitcoin Murderous Maniac
@monojohnny 如果你将 enumerator.GetDefaultAudioEndpoint 的第一个参数从 0 (eRender) 改为 1 (eCapture),那么这个代码就可以静音/取消静音默认的麦克风/输入设备。 - sparrowt
还值得一提的是,这个答案和Alexandre在上面的答案(https://dev59.com/KnVC5IYBdhLWcg3wjx5d#19348221/)之间唯一的区别是增加了“-Language CsharpVersion3”。如果这个答案只是作为评论出现在那个问题中,可能会更少令人困惑。 - sparrowt

8

您可以通过简单地管理Windows音频服务来实现另一种方法。停止它以静音,启动它以取消静音。


1
这是我今天在搜索中找到的最简单的选项 +1。 "net stop "Windows Audio" - miltonb
1
在PowerShell中:Stop-Service -DisplayName“Windows Audio”&Start-Service -DisplayName“Windows Audio”。希望我早点想到那个。 - Bewc
简单易用(在我的Win10机器上可用),并且可以发送其他按键或使用其他shell方法等。不错的@Brian Adams https://stackoverflow.com/users/32992/brian-adams - HerbM
1
如果您在停止和重新启动服务时暂停了媒体文件,则可能会出现问题。视频播放器可能无法在稍后播放声音,除非您停止并重新启动播放。 - tomasz86
注意 - 这需要管理员权限,这对我来说是不能接受的。 - KERR

8
没有一种快速简单的方式来调整音量。如果你有c++经验,你可能可以通过this blog post实现一些东西,其中Larry Osterman描述了如何从平台api调用IAudioEndpointVolume接口(对于Vista来说是这样的,根据我在一些搜索中发现的情况,XP可能更加困难)。V2确实允许您编译内联代码(通过Add-Type),因此可能是一个选项。

6

虽然这不是PowerShell,但将Michael和Diogo的答案结合起来可以得到一个一行的VBScript解决方案:

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

将以下内容复制到mute.vbs文件中,双击即可切换静音状态:

  • 在Windows 10 (10586.104)中仍然有效
  • 无需像PowerShell那样执行Set-ExecutionPolicy

3

Vbscript解决方案:

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

这些按键每按一次就会将音量缩小2。


2

我在PowerShell中没有找到如何做到这一点,但是有一个命令行实用程序叫做NirCmd,可以通过运行以下命令来实现:

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

NirCmd免费提供下载,链接地址为:http://www.nirsoft.net/utils/nircmd.html

1

1

在得到一些反馈后,让我再试一次我的答案

这是基于@frgnca的AudioDeviceCmdlets,可以在此处找到:https://github.com/frgnca/AudioDeviceCmdlets

以下是将静音所有录音设备的代码。

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
}

您需要导入AudioDeviceCmdlets dll,然后保存所有音频设备的列表,筛选出录音设备。获取所有录音设备的索引,然后对每个设备进行迭代,首先将设备设置为主要音频设备,然后将该设备设置为静音(这是dll强制实施的两步过程)。
要取消静音,请将-RecordingMute 1更改为RecordingMute 0 同样地,要静音播放设备,可以使用以下代码:
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
}

要取消静音,您需要将-PlaybackMute 1更改为PlaybackMute 0
这段代码来自我正在进行的一个更大项目的一部分,该项目通过Arduino连接到物理按钮/LED静音状态显示器,以启用单个按钮按下以静音/取消静音所有系统麦克风(以帮助Zoom、Meet、Teams、Discord等),并帮助人们避免尴尬的热麦克风事件。

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

1

附言:我真的很喜欢一些单行解决方案,比如如何从powershell更改音频级别?

但是请注意,单行静音通常仅适用于当前设置为Windows默认值的单个设备。因此,如果您有能够使用不同音频设备(如Zoom和Meet)的软件,并且它们恰好正在使用非默认设备,则可能无法按预期工作。


1
发表一个自包含的解决方案而不是链接。 - Jean-François Fabre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接