PowerShell 技能连载 - 在资源管理器中打开 PowerShell
一个在文件资源管理器中快速启动 PowerShell 的办法是导航到您数据的文件夹,然后点击导航条。这时导航面包屑控件变成了文件夹路径。将它改为 “powershell”,并按下回车键。
这时会打开 PowerShell,并且当前文件夹会设置为您导航到的文件夹。
不过,当前路径下有一个名为 “powershell” 的子文件夹时,这个技巧会失效。在这个例子中,文件资源管理器只会导航到该目录中。
一个在文件资源管理器中快速启动 PowerShell 的办法是导航到您数据的文件夹,然后点击导航条。这时导航面包屑控件变成了文件夹路径。将它改为 “powershell”,并按下回车键。
这时会打开 PowerShell,并且当前文件夹会设置为您导航到的文件夹。
不过,当前路径下有一个名为 “powershell” 的子文件夹时,这个技巧会失效。在这个例子中,文件资源管理器只会导航到该目录中。
有些 cmdlet 和脚本使用进度条来指示进度。如您在前一个技能中所学的,进度条可能会导致延迟,所以如果您如果不想指示进度,您可能会希望隐藏进度条。以下是实现方法:
以下代码从互联网下载一张图片。Invoke-WebRequest
处理耗时的操作并且在下载时显示一个进度条:
1 | #requires -Version 3.0 |
如果您不想显示进度条,请使用 $ProgressPreference
变量,临时隐藏进度条。请注意代码是如何用大括号包裹起来,并且用 ”&“ 号执行的。通过这种方法,当代码执行完毕后,所有在大括号中改变的变量都会被忽略,所以您不需要将 $ProgressPreference
变量重置为原来的值。
1 | #requires -Version 3.0 |
PowerShell 支持使用进度条。这是一个很简单的例子:
1 | 1..100 | ForEach-Object { |
如果您没有过度使用 Write-Progress
,那么使用进度条是很有价值的。特别在一个长时间的循环中,在循环的每一圈中调用一次 Write-Progress
并没有意义。如果那么做,脚本会变得非常慢。
假设您的循环运行 10000 次。显示一个进度条会显著地拖慢脚本:
1 | $min = 1 |
延迟的时间和 Write-Progress
的调用次数直接相关,所以如果您将 $max
的值改为 100000,该脚本会运行 10 倍的时间,只因为 Write-Progress
调用的次数达到 10 倍。
所以您需要使用一种智能的机制来限制 Write-Progress
的次数。以下例子每增加 0.1% 时跟新一次进度条:
1 | $min = 1 |
当您增加 $max
的数值,您会注意到脚本并不会增加多少时间,因为调用 Write-Progress
的次数仍然没变。
以下是一个快速批量重命名文件的方法,可以用于照片或其它文件。请看:
1 | #requires -Version 1.0 |
只需要调整路径和过滤器,使之指向所需的文件即可。在这个例子中,照片文件夹中的所有 *.jpg 文件中,关键字 “DSC” 将被替换成 “TEST”。请在使用前将脚本的参数改为您想要的。
要递归地重命名文件,请向 Get-ChildItem
命令添加 -Recurse
参数。但是,请小心。这一小段代码可能会导致一不小心对无数文件重命名。
在搜索指定的 AD 账户时,您可能曾经用过 Get-ADUser
命令,并且用 filter 参数来过滤结果。不过这样的过滤器可能会变得非常复杂。
这就是为什么针对最常见的 AD 搜索有一个快捷方式。只需要用 Search-ADAccount
命令即可:
1 | #requires -Modules ActiveDirectory |
Search-ADAccount
暴露一系列参数来搜索最常见的条件。
PowerShell 5.1(随着 Windows 10 和 Server 2016 发布)现在原生支持管理本地账户。在前一个技能中您学习了如何使用 Get-LocalUser
命令。
要探索本地账户管理的其它 cmdlet,以下是如何识别暴露 Get-LocalUser
命令的模块的方法,然后列出该模块的其它 cmdlet:
1 | #requires -Modules Microsoft.PowerShell.LocalAccounts |
最终,列出所有新的管理 cmdlet:
1 | CommandType Name Version Source |
PowerShell 5.1 终于发布了管理本地用户账户的 cmdlet。要获取本地用户账户的列表,请使用 Get-LocalUser
并将结果通过管道传给 Select-Object
命令来查看所有属性:
1 | PS C:\> Get-LocalUser | Select-Object -Property * |
缺省情况下,Get-ADUser
(由 ActiveDirectory 模块提供,该模块是免费的 Microsoft RSAT 工具的一部分)只获取一小部分缺省属性。要获取更多信息,请使用 -Properties
参数,并且指定您需要获取的属性。
要获取所有 AD 用户的列表,以及他们的备注和描述字段,请使用这段代码:
#requires -Modules ActiveDirectory
Get-ADUser -Filter * -Properties Description, Info
如果你不知道所有可用属性的名字,请使用“*”代替,来获取所有可用的属性。
有些时候,脚本以交互的方式询问凭据或密码。请时刻注意脚本的作者可以获取所有输入信息的明文。仅当您信任脚本和作者的时候才可以输入敏感信息。
请注意:这并不是一个 PowerShell 问题,这是所有软件的共同问题。
让我们看看一个脚本如何利用输入的密码。如果一个脚本需要完整的凭据,它可以检查凭据对象并解出密码明文:
1 | $credential = Get-Credential |
类似地,当提示您输入密码作为安全字符串时,脚本的作者也能获取到输入的明文:
1 | $password = Read-Host -AsSecureString -Prompt 'Enter Password' |
当 PowerShell 自动加密一个安全字符串时,它使用您的身份作为密钥。只有您可以解密该安全字符串。而如果您想用一个共享的密码来加密一段安全字符串,会怎么样呢?
以下是一个经典的做法,用密码来加密:
1 | # $secretKey MUST be of length 8 or 16 |
该密钥 ($secretKey
) 必须是 8 或 16 个字符的文本。任何知道密钥的人都可以解密(这就是为何 secretKey 不应该是脚本的一部分,而下面的脚本下方加入了硬编码的密钥是为了演示解密的过程。最好以交互的方式输入密钥):
1 | # this is the key to your secret |
结果是一个安全字符串,您可以用它来构建一个完整的凭据:
1 | $credential = New-Object -TypeName PSCredential('yourcompany\youruser', $SecureString) |
您也可以再次检查密码明文:
PS C:\Users\tobwe> $credential.GetNetworkCredential().Password
myPassword
请注意安全字符串的所有者(创建它的人)总是可以取回明文形式的密码。这并不是一个安全问题。创建安全字符串的人在过去的时刻已经知道了密码。安全字符串保护第三方的敏感数据,并将它以其他用户无法接触到的形式保存到内存中。
密钥和对称加密算法的问题是您需要分发密钥,而密钥需要被保护,它既可以用来加密也可以用来解密。
在 PowerShell 5 中有一个简单得多的方法:Protect-CMSMessage
和 Unprotect-CMSMessage
,它们使用数字证书和非对称加密。通过这种方法,加密安全信息的一方无需知道解密的密钥,反之亦然。加密的一方只需要制定谁(哪个证书)可用来解密保密信息。