PowerShell 技能连载 - 管理比特标志位(第三部分)
对十进制数设置比特标志位不是很难,但是不够直观。以下是一个快速的新方法,演示如何设置或取消一个数字中特定的比特:
1 | $decimal = 6254 |
结果演示了代码做了什么。ToString()
从右到左显示比特,所以第 0 比特是在最右边。在第二行和第三行,设置了两个独立的比特位,而并不影响其它位。在最后一行中,清除了一个比特位。
1 | 1100001101110 |
对十进制数设置比特标志位不是很难,但是不够直观。以下是一个快速的新方法,演示如何设置或取消一个数字中特定的比特:
1 | $decimal = 6254 |
结果演示了代码做了什么。ToString()
从右到左显示比特,所以第 0 比特是在最右边。在第二行和第三行,设置了两个独立的比特位,而并不影响其它位。在最后一行中,清除了一个比特位。
1 | 1100001101110 |
在前一个技能中我们演示了如何使用 PowerShell 5 新的枚举特性来解析bite标志位,甚至可以独立地检测每个标志位。
如果您无法使用 PowerShell 5,在早期的 PowerShell 版本中,仍然可以使用这个技术只需要通过 C# 代码来定义枚举即可:
1 | # this is the decimal we want to decipher |
如您所见,从十进制数转换到新的枚举类型使用正常而且非常简单:
1 | PS C:\> [BitFlags]6625 |
有时候您会需要处理比特标志位值。一个数字中的每个比特代表一个特定的设置,并且您的代码可能需要决定一个标志位是否置位,而不能影响别的比特。
这常常需要一系列位操作。然而在 PowerShell 5 中,有一个简单得多的办法——标志位枚举。
假设有一个值 56823,并且希望知道哪个比特是置位的。您需要将该数字转换成可视化的比特:
1 | PS C:\> [Convert]::ToString(56823, 2) |
如果您了解每个比特的意义,那么一个更强大的方法是定义一个枚举:
1 | #requires -Version 5 |
对每个比特提供一个友好的名字,并且记得添加属性 [Flags]
(这将允许设置多个值)。
现在要解析这个十进制值非常简单——只需要将它转换成新定义的枚举类型:
1 | $rawflags = 56823 |
这时得到的结果:
1 | PS C:\> $flags |
如果您只希望检测某个标志位是否置位,请使用 HasFlag()
方法:
1 | PS C:\> $flags.HasFlag([CustomBitFlags]::Option1) |
泛型可以作为实际类型的占位符,您可能会好奇为什么它会有意思。
有许多不同的数据类型没有 NULL 值。例如 Integer 和 Boolean 型,没有办法指出一个值是非法的还是未设置。您可以通过将一个 0(或者 -1)指定为某个 integer 变量的 “undefined” 值。但如果所有的数字都是合法的值呢?对于 Boolean,情况也是一样:虽然您可以定义 $false
值为 “undefined” 值,但许多情况下的确需要三种值:$true
、$flase
和 undefined
。
泛型是解决的办法,您可以使用 Nullable
类型根据任何合法的类型来创建自己的可空值类型。
1 | [Nullable[int]]$number = $null |
用常规数据类型来做数据转换:
1 | PS C:\> [int]$null |
以下是在 PowerShell 5 中使用新的类特性的另一个用例。在前一个例子中,我们演示了如何从 System.Diagnostics.Process
派生一个新类,从而获得代表进程的功能更强大的对象。
以下是一个从 WebClient
派生的类,WebClient
主要是用来连接网站。当您使用标准的 WebClient
对象是,它拒绝连接到证书错误的 HTTPS 网站。这是一件好事,但是有时候您仍需要连接这类网站。
1 | #requires -Version 5 |
这样,”“MyWebClient”
“ 类继承于 WebClient()
并改变了 ServerCertificateValidationCallBack
的行为。它只是返回 $true
,所以所有的连接都是成功的,而且证书检验变得无关紧要。
PowerShell 5 内置了类的支持。您可以使用这个新特性来增强已有的 .NET 类的功能。以下是一个例子:创建一个包含新功能的增强的进程类。
进程通常是由 System.Diagnostics.Process
对象代表。它们只有有限的功能,并且假设没有能直接使用的以友好方式关闭一个应用程序的方法。您可以杀除进程(会丢失未保存的数据),或关闭它(用户可以取消关闭)。
以下是一个新的 继承于 System.Diagnostics.Process
的名为 AppInstance
的类。所以它拥有 Process
类中所有已有的功能,您可以增加额外的属性和方法:
1 | #requires -Version 5 |
如您在这个例子中所见,当您从这个类创建一个新实例时,它启动了一个新的进程,而且这些进程照常暴露出相同的属性和方法。而且,有一些新的例如 SetPriority()
和 Close()
的新方法。
PowerShell 可以调用 Windows 内部的 API,在这个例子中,我们想向您展示如何改变一个应用程序窗口的显示状态。比如可以最大化、最小化、隐藏或显示窗口。
这个例子使用 PowerShell 5 最新的枚举特性对 showstate
数值赋予有意义的名字。在 PowerShell 的更早版本中,只需要移除枚举部分,并在代码中直接使用合适的 showstate
数字即可。
这里的学习要点是如何使用 Add-Type
来包装一个 C# 形式的 API 方法并在 PowerShell 代码中返回一个暴露这个方法的 type:
1 | #requires -Version 5 |
请注意这个例子将 PowerShell 窗口临时隐藏 2 秒钟。您可以对任何运行中的应用程序窗口做相同的事情。只需要用 Get-Process
来查找目标进程,并使用它的 “MainWindowHandle
“ 属性来发送 showstate 改变请求。
一些应用程序有多个窗口。在这种情况下,您只能针对主窗口操作,否则需要先靠其它 API 来获取子窗口的句柄集合。
Pester 是一个随 Windows 10 和 Windows Server 2016 发布的开源模块,可以通过 PowerShell Gallery 免费下载(需要事先安装最新版本的 PowerShellGet):
1 | PS C:\> Install-Module -Name Pester -Force -SkipPublisherCheck |
Pester 是一个主要用来测试 PowerShell 代码的测试框架。您不仅可以用它来测试代码,而且可以用它来测试任何东西。以下是一个测试 PowerShell 版本号和一些设置的小例子:
1 | Describe 'PowerShell Basic Check' { |
当您运行它时(当然,前提是已经安装了 Pester 模块),这是得到的输出结果:
1 | Describing PowerShell Basic Check |
当然,这只是一个例子。您可以把它做详细并且将测试扩展到更多的其它设置或依赖条件。
当您在 PowerShell 中读取环境变量时,您可能会使用 “env:
“ 驱动器。例如这行代码使用 %USERNAME%
环境变量,告知您执行这段代码的用户名:
1 | PS C:\> $env:USERNAME |
env:
驱动器总是存取环境变量的操作集合。所以大多数情况所有环境变量(例如 “UserName”)都定义在这个集合之中。基本上,环境变量的操作集合是当一个应用程序启动时所有环境变量的“快照”,加上一些额外的信息(例如 “UserName”)。
要从系统或用户集合中读取最新的环境变量,请使用类似如下的代码:
1 | $name = 'temp' |
例如您可以使用这个技术在两个进程间通信。实践方法是,打开两个 PowerShell 控制台。现在在第一个控制台中键入以下信息:
1 | [Environment]::SetEnvironmentVariable("PS_Info", "Hello", "user") |
在第二个 PowerShell 控制台中,键入这行代码来接收信息:
1 | [Environment]::GetEnvironmentVariable("PS_Info", "user") |
要清除环境变量,请在任意一个控制台中输入这行代码:
1 | [Environment]::SetEnvironmentVariable("PS_Info", "", "user") |
当通过 PowerShell 的 “env:
“ 驱动器来设置环境变量,您只需要操作其中的数据即可。它会应用到当前的 PowerShell 实例,和所有由它启动的应用程序。不过改变并不会保存。
要设置环境变量并使之持久化,请用这段代码代替:
1 | $name = 'Test' |
这个例子设置了一个名为 “test”,值为 “hello” 的用户级别新环境变量。请注意这个改变只会影响设置这个变量之后启动的应用程序。
要彻底删除一个环境变量,请将 $value
设置成一个空字符串。