PowerShell 技能连载 - 控制音量和静音状态
要调节音量以及静音、取消扬声器的静音,PowerShell 可以像这样用 C# 代码来操作 API:
1 | Add-Type -TypeDefinition @' |
要调节音量以及静音、取消扬声器的静音,PowerShell 可以像这样用 C# 代码来操作 API:
1 | Add-Type -TypeDefinition @' |
在前一个技能中我们解释了如何用 Web Service 来安全地检测密码并且查明它们是否已被泄漏。
信息安全有关的代码有时经过压缩后看起来是否“有趣”,所以在第一步分钟我们分享了优美的而且可读的代码。而以下是考虑“信息安全”的变体,它展示 PowerShell 代码可以被压缩到什么程度并且可以自动混淆。这段代码返回一个指定的密码被暴露了多少次(如果未曾发现被暴露过,返回 null
)。
1 | $p = 'P@ssw0rd'[Net.ServicePointManager]::SecurityProtocol = 'Tls12'$a,$b = (Get-FileHash -A 'SHA1' -I ([IO.MemoryStream]::new([Text.Encoding]::UTF8.GetBytes($p)))).Hash -split '(?<=^.{5})'(((irm "https://api.pwnedpasswords.com/range/$a" -UseB) -split '\r\n' -like "$b*") -split ':')[-1 |
复杂的密码不一定安全。例如,”P@ssw0rd” 是一个非常复杂的密码,但是非常不安全。这是为什么安全社区开始建议用更相关的测试取代复杂性标准,并防止使用以前黑客入侵中使用过的密码。这些密码——虽然它们可能很复杂——是字典攻击的一个常规部分并且非常不安全。
如何知道某个密码是否已被泄露?您可以使用类似 haveibeenpwnd.com 的网站或者它们的 API。这是它的工作原理:
以下是用 PowerShell 检查密码的方法:
1 | # enable all SSL protocols |
试着改变 $Password
中的密码来测试这段代码。您会很惊讶地发现许多密码已经泄漏:
Sunshine has been seen 13.524 times.
在前一个技能中我们学习了如何在 PowerShell 中启用所有的 SSL 安全协议来连接到 Web Service 和 网站:
1 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 |
有趣的是,可以用一行更短的代码来代替:
1 | [Net.ServicePointManager]::SecurityProtocol = 'Ssl3, Tls, Tls11, Tls12' |
以下是它的原因:
由于 SecurityProtocol
是 Net.SecurityProtocolType
类型的,所以当您传入字符串数据,它可以自动转换:
1 | PS> [Net.ServicePointManager]::SecurityProtocol.GetType().FullName |
与其用 SecurityProtocolType
枚举并且用 -bor 操作符来连接,您还可以用比特标志位的名称组成的逗号分隔的字符串。两者是相同的:
1 | $a = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 |
根据您的 PowerShell、.NET Framework 的版本和升级,WEB 连接的缺省安全协议可能仍然是 SSL3。您可以方便地查明它:
1 | [Net.ServicePointManager]::SecurityProtocol |
如果返回的协议不包含 Tls12,那么您可能无法用 PowerShell 连接到安全的 Web Service 和网站。我们只需要这样操作就可以启用更多的服务:
1 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Ssl3 -bor [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 |
假设您需要以固定宽度分割一段文本。例如,如果您需要一段文本的前 5 个字符,以及剩余的部分,如何实现它?
大多数 PowerShell 用户可能会用类似这样的方法:
1 | $text = 'ID12:Here is the text'$prefix = $text.Substring(0,5)$suffix = $text.Substring(5)$prefix$suffix |
当然,如果用分割字符,例如 “:”,可以这样操作:
1 | $prefix, $suffix = 'ID12:Here is the text' -split ':'$prefix$suffix |
然而,这将会吃掉分割字符,并且它会导致超过两个部分。这不是我们要的目标:用固定宽度分割一段文本。而您仍然可以使用 -split
操作符:
1 | $prefix, $suffix = 'ID12:Here is the text' -split '(?<=^.{5})'$prefix$suffix |
正则表达式结构 “(?<=XXX)
“ 称为“向后引用”。”^
“ 代表文本的开始,而 “.
“ 代表任何字符。如您猜测的那样,”{5}
“ 限定该占位符出现的次数,所以基本上这个正则表达式从剩下的文本中分割出前 5 个字符并且返回两部分(假设文本至少 6 个以上字符长度)。
在 PowerShell 5(以及 Get-FileHash
之前),要计算字符串和文件的哈希值,您需要借助原生的 .NET 方法。以下是一段为一个字符串创建 MD5 哈希的示例代码:
1 | $Text = 'this is the text that you want to convert into a hash' |
如果您需要计算一个文件内容的哈希值,要么使用 Get-Content
来读取文件,或者使用以下代码:
1 | $Path = "C:\somefile.txt" |
哈希是一种唯一确定一段文本而不用暴露原始文本的棒法。哈希被用来确定文本、查找重复的文件内容,以及验证密码。PowerShell 5 以及更高版本甚至提供了一个 cmdlet 来计算文件的哈希值:Get-FileHash
。
然而,Get-FileHash
不能计算字符串的哈希。没有必要只是为了计算哈希值而将字符串保存到文件。您可以使用所谓的内存流来代替。以下是一段从任何字符串计算哈希值的代码片段:
1 | $Text = 'this is the text that you want to convert into a hash' |
使用完成后别忘了关闭并释放内存流,防止内存泄漏并释放所有资源。
当您用管道将对象输出到 Out-GridView
,该 cmdlet 显示缺省的属性,所以当您用一个网格视图窗口当作选择框时,您可以控制用户可见的内容。以下代码将读取前 10 个 AD 用户输出到网格视图窗口,并且用户可以选择要返回的项。然而,网格视图窗口中显示的数据看起来很丑:
1 | Get-ADUser -ResultSetSize 10 -Filter * | |
如果您没有使用 AD 或没有安装 RSAT 工具,以下是使用进程的类似的例子:
1 | Get-Process | |
如果您使用 Select-Object
来限制显示的属性,这将改变对象的类型,所以当您继续用管道将改变过的对象传给下一级 cmdlet,它们将无法处理返回的对象。
解决方法是保持对象类型不变,而是改变缺省属性。以下是 AD 用户对象的解决方案,在选择对话框中只显示 Name 和 SID:
1 | [string[]]$visible = 'Name', 'SID' |
这是进程选择框的解决方案,显示进程的名称、公司、起始时间,和窗体标题:
1 | [string[]]$visible = 'Name', 'Company','StartTime','MainWindowTitle' |
结果发现,进程对象不接受新的 DefaultDisplayPropertySet
,所以在这个例子中需要一个完整的克隆,这样您可以用 Select-Object -Property *
将对象输出到管道。由于这不会改变对象类型,所以所有原始属性都被保留下来,下游管道命令能继续起作用,因为管道绑定仍然有效。
当在 PowerShell 中输出数据时,它会静默地通过管道输出到 Out-Default
并且最终以文本的方式输出到控制台。如果我们覆盖 Out-Default
,就可以改变它的行为,例如将所有 PowerShell 的输出改到一个网格视图窗口。实际中,您甚至可以区别对待正常的输出和错误信息,并且将两者显示在不同的窗口里。
以下是两个函数:Enable-GridOutput
和 Disable-GridOutput
。当您运行 Enable-GridOutput
时,它会覆盖 Out-Default
并将常规的输出显示在 “Output” 网格视图窗口,并且将错误信息转换为有用的文本,并将它输出到一个独立的 “Error” 网格视图窗口。
当运行 Disable-GridOutput
后,会去掉覆盖的效果,并且回到缺省的行为:
1 | function Enable-GridOutput |