PowerShell 技能连载 - 语音之周:更改讲述人的语音

在前一个技能中我们演示了如何使用语音转换器来念出文本。以下是查找您系统中安装的语言的方法:

1
2
3
4
5
6
#requires -Version 2.0
Add-Type -AssemblyName System.Speech
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
$speak.GetInstalledVoices() |
Select-Object -ExpandProperty VoiceInfo |
Select-Object -Property Culture, Name, Gender, Age

结果类似如下:

1
2
3
4
5
Culture Name                    Gender   Age
------- ---- ------ ---
en-US Microsoft Zira Desktop Female Adult
en-US Microsoft David Desktop Male Adult
de-DE Microsoft Hedda Desktop Female Adult

用这行代码可以返回缺省的语音:

1
$speak.Voice

假设您的系统安装了多个语音,以下是选择一个不同语音的方法。只需要传入您想使用的语音名字。这个例子在德文 Windows 10 系统上使用德语语音引擎:

1
2
3
4
5
#requires -Version 2.0
Add-Type -AssemblyName System.speech
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
$speak.SelectVoice('Microsoft Hedda Desktop')
$speak.Speak('Jetzt spreche ich deutsch.')

PowerShell 技能连载 - 语音之周:使用语音讲述人

当您将 “System.Speech“ 程序集添加到 PowerShell 中后,就可以使用新增的 “SpeechSynthesizer“ 类将文字转成语音:

1
2
3
Add-Type -AssemblyName System.Speech
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
$speak.Speak('Hello I am PowerShell!')

请注意语音讲述人用的是您系统的缺省语音。您的讲述人缺省情况下可能说的不是英文。我们将在接下来的技能当中介绍如何使用不同的语音。

PowerShell 技能连载 - 增加和删除反斜杠

我们处理路径时,常常需要使路径“标准化”。例如确保所有的路径都以反斜杠结尾。一种尝试如下:

1
2
3
4
5
6
$path = 'c:\temp'
if ($path -notmatch '\\$')
{
$path += '\'
}
$path

这段代码用正则表达式来查找一段文本尾部的反斜杠。如果不存在,则添加一个反斜杠。

如果您想删除路径尾部的反斜杠,您可以直接使用 -replace 运算符:

1
2
$path = 'c:\temp\' -replace '\\$'
$path

PowerShell 技能连载 - 检查整数的位数

有些时候您可能会需要检查一个整数的位数,例如验证用户的输入。以下是一个非常简单的使用正则表达式的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# check the number of digits in an integer
$integer = 5721567

# is it between 4 and 6 digits?
$is4to6 = $integer -match '^\d{4,6}$'

# is it exactly 7 digits?
$is7 = $integer -match '^\d{7}$'

# is it at least 4 digits?
$isatleast4 = $integer -match '^\d{4,}$'

"4-6 digits? $is4to6"
"exactly 7 digits? $is7"
"at least 4 digits? $isatleast4"

这个例子演示了如何检查是否是恰好的位数,或者位数处于某个范围。请注意 “^” 代表表达式的起始,”$” 代表表达式的结尾。”\d” 表示一位数字,大括号确定位数。

PowerShell 技能连载 - 在资源管理器中打开 PowerShell

一个在文件资源管理器中快速启动 PowerShell 的办法是导航到您数据的文件夹,然后点击导航条。这时导航面包屑控件变成了文件夹路径。将它改为 “powershell”,并按下回车键。

这时会打开 PowerShell,并且当前文件夹会设置为您导航到的文件夹。

不过,当前路径下有一个名为 “powershell” 的子文件夹时,这个技巧会失效。在这个例子中,文件资源管理器只会导航到该目录中。

PowerShell 技能连载 - 隐藏进度条

有些 cmdlet 和脚本使用进度条来指示进度。如您在前一个技能中所学的,进度条可能会导致延迟,所以如果您如果不想指示进度,您可能会希望隐藏进度条。以下是实现方法:

以下代码从互联网下载一张图片。Invoke-WebRequest 处理耗时的操作并且在下载时显示一个进度条:

1
2
3
4
5
6
7
8
#requires -Version 3.0


$path = "$home\Pictures\psconf15.jpg"
$url = 'http://www.powertheshell.com/wp-content/uploads/groupWPK2015.jpg'
Invoke-WebRequest -Uri $url -OutFile $path

Invoke-Item -Path $path

如果您不想显示进度条,请使用 $ProgressPreference 变量,临时隐藏进度条。请注意代码是如何用大括号包裹起来,并且用 ”&“ 号执行的。通过这种方法,当代码执行完毕后,所有在大括号中改变的变量都会被忽略,所以您不需要将 $ProgressPreference 变量重置为原来的值。

1
2
3
4
5
6
7
8
9
10
11
#requires -Version 3.0


& {
$ProgressPreference = 'SilentlyContinue'

$path = "$home\Pictures\psconf15.jpg"
$url = 'http://www.powertheshell.com/wp-content/uploads/groupWPK2015.jpg'
Invoke-WebRequest -Uri $url -OutFile $path
}
Invoke-Item -Path $path

PowerShell 技能连载 - 明智地使用进度条

PowerShell 支持使用进度条。这是一个很简单的例子:

1
2
3
4
1..100 | ForEach-Object {
Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $_
Start-Sleep -Milliseconds 100
}

如果您没有过度使用 Write-Progress,那么使用进度条是很有价值的。特别在一个长时间的循环中,在循环的每一圈中调用一次 Write-Progress 并没有意义。如果那么做,脚本会变得非常慢。

假设您的循环运行 10000 次。显示一个进度条会显著地拖慢脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
$min = 1
$max = 10000

$start = Get-Date

$min..$max | ForEach-Object {
$percent = $_ * 100 / $max
Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $percent
}

$end = Get-Date

($end-$start).TotalMilliseconds

延迟的时间和 Write-Progress 的调用次数直接相关,所以如果您将 $max 的值改为 100000,该脚本会运行 10 倍的时间,只因为 Write-Progress 调用的次数达到 10 倍。

所以您需要使用一种智能的机制来限制 Write-Progress 的次数。以下例子每增加 0.1% 时跟新一次进度条:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$min = 1
$max = 10000

$start = Get-Date

# update progress bar every 0.1 %
$interval = $max / 1000

$min..$max | ForEach-Object {
$percent = $_ * 100 / $max

if ($_ % $interval -eq 0)
{
Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $percent
}
}

$end = Get-Date

($end-$start).TotalMilliseconds

当您增加 $max 的数值,您会注意到脚本并不会增加多少时间,因为调用 Write-Progress 的次数仍然没变。

PowerShell 技能连载 - 批量重命名照片

以下是一个快速批量重命名文件的方法,可以用于照片或其它文件。请看:

1
2
3
4
5
6
#requires -Version 1.0
$Path = "$home\Pictures"
$Filter = '*.jpg'

Get-ChildItem -Path $Path -Filter $Filter |
Rename-Item -NewName {$_.name -replace 'DSC','TEST'}

只需要调整路径和过滤器,使之指向所需的文件即可。在这个例子中,照片文件夹中的所有 *.jpg 文件中,关键字 “DSC” 将被替换成 “TEST”。请在使用前将脚本的参数改为您想要的。

要递归地重命名文件,请向 Get-ChildItem 命令添加 -Recurse 参数。但是,请小心。这一小段代码可能会导致一不小心对无数文件重命名。

PowerShell 技能连载 - 定位锁定的 AD 账户

在搜索指定的 AD 账户时,您可能曾经用过 Get-ADUser 命令,并且用 filter 参数来过滤结果。不过这样的过滤器可能会变得非常复杂。

这就是为什么针对最常见的 AD 搜索有一个快捷方式。只需要用 Search-ADAccount 命令即可:

1
2
3
4
5
6
#requires -Modules ActiveDirectory


Search-ADAccount -AccountDisabled
Search-ADAccount -AccountExpired
Search-ADAccount -AccountInactive

Search-ADAccount 暴露一系列参数来搜索最常见的条件。

PowerShell 技能连载 - 探索本地账户管理 cmdlet

PowerShell 5.1(随着 Windows 10 和 Server 2016 发布)现在原生支持管理本地账户。在前一个技能中您学习了如何使用 Get-LocalUser 命令。

要探索本地账户管理的其它 cmdlet,以下是如何识别暴露 Get-LocalUser 命令的模块的方法,然后列出该模块的其它 cmdlet:

1
2
3
4
5
6
7
8
#requires -Modules Microsoft.PowerShell.LocalAccounts


# find module that defines this cmdlet
$module = Get-Command -Name Get-LocalUser | Select-Object -ExpandProperty Source

# list all cmdlets defined by this module
Get-Command -Module $module

最终,列出所有新的管理 cmdlet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CommandType Name                    Version Source
----------- ---- ------- ------
Cmdlet Add-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Disable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Enable-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Get-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet New-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet New-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Remove-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Rename-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Rename-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Set-LocalGroup 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet Set-LocalUser 1.0.0.0 Microsoft.PowerShell.LocalAccounts