25

尝试编写一个 PowerShell cmdlet,它将在开始时静音,除非已经静音,并在最后取消静音(只有在开始时没有静音)。找不到我可以使用的任何 PoweShell 或 WMI 对象。我正在玩弄使用auxGetVolumeauxSetVolume 之类的 Win32 函数,但不能完全让它工作(如何从 IntPtr 读取值?)。

我正在使用 V2 CTP2。有什么想法吗?

谢谢!

4

11 回答 11

35

从 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。

PS Diogo 的答案似乎很聪明,但对我不起作用。

于 2013-10-13T17:40:00.600 回答
22

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

$obj = new-object -com wscript.shell 
$obj.SendKeys([char]173)
于 2012-09-13T00:12:58.590 回答
10

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:\>
于 2016-10-07T16:18:20.207 回答
7

您可以通过简单地管理 Windows 音频服务以另一种方式给猫剥皮。停止静音,启动取消静音。

于 2008-11-01T05:29:05.910 回答
7

似乎没有一种快速简便的方法来调整音量。如果您有 c++ 经验,您可以使用这篇博文做一些事情,Larry Osterman 描述了如何从平台 api 调用 IAudioEndpointVolume 接口(对于 Vista,从我在几次搜索中发现的内容来看,XP 可能更难)。

V2 确实允许您编译内联代码(通过 Add-Type),因此这可能是一种选择。

于 2008-11-01T19:25:32.010 回答
4

我知道这不是 PowerShell,但结合 Michael 和 Diogo 的答案给出了一个单行 VBScript 解决方案:

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

把它拍进去mute.vbs,你可以双击来切换静音

  • 仍然适用于 Windows 10 (10586.104)
  • 无需Set-ExecutionPolicy像使用 PowerShell 那样
于 2016-02-18T22:44:52.313 回答
2

我没有找到如何在 PowerShell 中执行此操作,但是有一个名为 NirCmd 的命令行实用程序可以通过运行以下命令来解决问题:

C:\utils\nircmd.exe mutesysvolume 2

NirCmd 可在此处免费获得:http: //www.nirsoft.net/utils/nircmd.html

于 2009-11-03T23:33:19.223 回答
2

vbscript中的解决方案:

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

按键每次将音量降低 2。

于 2013-01-31T00:43:05.310 回答
1

查看我对从 powershell 更改音频级别的回答?

Set-DefaultAudioDeviceMute
于 2014-07-29T12:48:37.243 回答
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,然后保存所有音频设备的列表,过滤到录音设备中。您获取所有录音设备的索引,然后遍历每个设备,首先将设备设置为主音频设备,然后将该设备设置为静音(这 2 步过程是 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

PS 我真的很喜欢一些单线解决方案,例如从 powershell 更改音频级别?

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

于 2020-12-23T16:49:25.100 回答
0

在上面的第二个脚本中,要在 PowerShell 7 或 PowerShell Core 中的第一行更改:

-Language CsharpVersion3

到...

-Language Csharp

在 W10 上工作

于 2020-07-29T14:46:28.787 回答