PowerShell 技能连载 - 合成语音(第 2 部分)
在前一个技能中我们介绍了文字转语音引擎。这个引擎可以将文本转为一个 WAV 声音文件。这样我们可以利用它来生成语音信息:
1 | $Path = "$home\Desktop\clickme.wav" |
在前一个技能中我们介绍了文字转语音引擎。这个引擎可以将文本转为一个 WAV 声音文件。这样我们可以利用它来生成语音信息:
1 | $Path = "$home\Desktop\clickme.wav" |
在之前的技能中,我们演示了 PowerShell 如何通过播放系统声音或 WAV 声音文件来生成声音信号。PowerShell 也可以调用内置的语音合成器:
1 | Add-Type -AssemblyName System.speech |
请注意 Windows 10 自带了本地化的文字转语音引擎,所以如果您的 Windows 不是使用英语语言,您可能需要将以上文字转为您的语言。
可以用一系列属性来调整输出的效果。请试试这段代码:
1 | Add-Type -AssemblyName System.speech |
在前一个技能里我们演示了如何用 PowerShell 播放系统声音。对于更灵活一些的场景,PowerShell 也可以播放任意的 *.wav 声音文件:
1 | $soundPlayer = New-Object System.Media.SoundPlayer |
默认情况下,PowerShell 并不会等待声音播放完毕。如果您需要同步播放声音,请试试这段代码:
1 | $soundPlayer = New-Object System.Media.SoundPlayer |
要播放不同的声音文件,只需要将路径替换为声音文件即可:
sound player 也可以用后台线程循环播放一个文件:
1 | $soundPlayer = New-Object System.Media.SoundPlayer |
当后台正在播放声音时,请确保用这段代码停止播放声音:
1 | $soundPlayer.Stop() |
如果您只是需要蜂鸣,那么 PowerShell 可以很轻松地帮助您:
1 | $frequency = 800 |
如果您需要做一些更复杂的事,那么您可以让 PowerShell 播放一段系统声音:
1 | [System.Media.SystemSounds]::Asterisk.Play() |
以下是支持的系统声音列表:
1 | PS> [System.Media.SystemSounds] | Get-Member -Static -MemberType Property |
当您尝试使用 Sort-Object
对 IPv4 地址排序的时候,结果是错误的:
1 | PS> '10.1.2.3', '2.3.4.5', '1.2.3.4' | Sort-Object |
这并不令人意外,因为数据类型是字符串型,所以 Sort-Object
使用的是字母排序。在前一个技能中我们介绍了如何将数据转换未 [Version]
类型,并且假装在排序软件版本号:
1 | PS> '10.1.2.3', '2.3.4.5', '1.2.3.4' | Sort-Object -Property { $_ -as [Version] } |
然而,这种方法对 IPv6 地址行不通,因为它无法转换为版本号:
1 | PS> '10.1.2.3', 'fe80::532:c4e:c409:b987%13', '2.3.4.5', '2DAB:FFFF:0000:3EAE:01AA:00FF:DD72:2C4A', '1.2.3.4' | Sort-Object -Property { $_ -as [Version] } |
用 -as
操作符将 IPv6 地址转为 [Version]
返回的是 NULL,所以当用 Sort-Object
排序时,IPv6 地址会出现在列表的最顶部。
要对 IPv6 地址排序,缺省的字母排序是够用的。所以我们做一些改变,当遇到一个 IPv6 地址时,用它的字符串值来排序:
1 | $code = { |
现在结果看起来清爽多了:
10.1.2.3
2.3.4.5
1.2.3.4
2DAB:FFFF:0000:3EAE:01AA:00FF:DD72:2C4A
fe80::532:c4e:c409:b987%13
请注意代码中向 IPv6 的字符串开头加入字母 “z”。这是为了保证 IPv6 地址位于列表的底部。如果您希望它们位于列表的顶部,请试试这段代码:
1 | $code = { |
由于 “/“ 的 ASCII 值比 “0” 更小,所以 IPv6 地址位于列表的顶部:
2DAB:FFFF:0000:3EAE:01AA:00FF:DD72:2C4A
fe80::532:c4e:c409:b987%13
1.2.3.4
2.3.4.5
10.1.2.3
在前一个示例中我们发布了一个超快的名为 Test-OnlieFast
的函数,并且这个函数可以在短时间内 ping 整个 IP 段:
1 | PS> $iprange = 1..200 | ForEach-Object { "192.168.189.$_" } |
然而,IP 地址列并没有排序过。当然您可以使用 Sort-Object
来实现,但是由于地址中的数据是字符串格式,所以它会按字母排序。
以下是一个可以正确地对 IPv4 地址排序的简单技巧:
1 | PS> Test-OnlineFast -ComputerName $iprange | Sort-Object { $_.Address -as [Version]} |
基本上,您通过 Sort-Object
将数据转换为 Version
对象,它刚好像 IPv4 地址一样,也是由四位数字组成。由于如果数据无法转换时,操作符 -as
将返回 NULL
结果,任何 IPv6 地址将会出现在列表的顶部(未排序)。
如果您错过了之前的 Test-OnlineFast
代码,以下再次把它贴出来:
1 | function Test-OnlineFast |
在之前的技能系列中,我们开发了一个名为 Test-OnlineFast
的新函数,可以在短时间内 ping 多台计算机。出于某些原因,最终版本并没有包含我们承诺的管道功能。以下是再次带给您的完整函数:
1 | function Test-OnlineFast |
让我们首先来确认 Test-OnlineFast
是如何工作的。以下是一些示例。我们首先 ping 一系列计算机。您可以同时使用计算机名和 IP 地址:
1 | PS> Test-OnlineFast -ComputerName google.de, powershellmagazine.com, 10.10.10.200, 127.0.0.1 |
我们现在来 ping 一整个 IP 段。以下例子从我们公共的酒店 WLAN 中(请确保将 IP 段调整为您所在的网段):
1 | PS> $iprange = 1..200 | ForEach-Object { "192.168.189.$_" } |
神奇的是超快的速度。ping 整个子网只花费了几秒钟。
有一系列有用的 cmdlet 可以管理事件日志,然而缺失了这个功能:
1 | PS> Get-Command -Noun EventLog |
没有一个将事件日志被分到 *.evtx 文件的 cmdlet。让我们动手编一个吧:
1 | function Backup-Eventlog |
现在备份事件日志变得十分方便,以下是一个使用示例:
1 | PS> Backup-Eventlog -LogName Application -DestinationPath c:\test\backup.evtx |
当您在 PowerShell 中调用一个底层的函数时,您可能经常会得到一个数值型的返回值。如果这个返回值是来自一个 Windows API 函数,那么有一个非常简单的方法将它转换成有意义的文本:
例如,当一个 API 函数因为权限不足导致失败,它的返回值是 5。让我们将它翻译为一个有意义的文本:
1 | PS> New-Object -TypeName ComponentModel.Win32Exception(5) |
在 PowerShell 5 中,您还可以使用这种语法:
1 | PS> [ComponentModel.Win32Exception]::new(5) |
请试试这个例子:
1 | 1..200 | ForEach-Object { '{0} = {1}' -f $_, (New-Object -TypeName ComponentModel.Win32Exception($_)) } |
当您用 Write-EventLog 将日志写入日志记录时,您需要指定一个合法的事件源名称。然而,并没有一个很方便的办法能查出哪个事件源文件对应注册到某个事件日志。这在您用 New-EventLog
创建新的事件日志时可能会带来麻烦:您不能指定一个已经存在的事件源名称。
以下是一个查找所有事件源名称,并且显示它们注册的事件日志的简单方法:
1 | PS> Get-WmiObject -Class Win32_NTEventLOgFile | Select-Object FileName, Sources |
您还可以将这个列表转换为一个有用的哈希表:
1 | # find all registered sources |