PowerShell 技能连载 - 理解文本转换
有许多方法能将对象转换为文本。如果您在某些情况下弄糊涂了,这篇文章能帮您快速搞清。请看:
有三个基础的将对象转换为文本的方法。
1 | $a = 4.5 |
对于简单对象,三个方法的结果不会有差别。然而,对于更复杂的对象,结果差异可能很大。请看一下数组:
1 | $a = 1,2,3 |
并且看看复杂对象如何转换为文本:
1 | $a = Get-Process |
有许多方法能将对象转换为文本。如果您在某些情况下弄糊涂了,这篇文章能帮您快速搞清。请看:
有三个基础的将对象转换为文本的方法。
1 | $a = 4.5 |
对于简单对象,三个方法的结果不会有差别。然而,对于更复杂的对象,结果差异可能很大。请看一下数组:
1 | $a = 1,2,3 |
并且看看复杂对象如何转换为文本:
1 | $a = Get-Process |
执行策略 (Execution Policy) 可以禁止脚本执行。它被设计成一个用户的首选项,所以您总是可以改变有关的执行策略。不过,在一些环境下,组策略可以强制改变设置,并且禁止运行脚本。
在这种情况下,您可以考虑重置内部的 PowerShell 授权管理。将它替换为一个缺省的实例以后,您可以忽略之前的执行策略设置,执行 PowerShell 脚本:
1 | $context = $executioncontext.gettype().getfield('_context','nonpublic,instance').getvalue($executioncontext); $field = $context.gettype().getfield('_authorizationManager','nonpublic,instance'); $field.setvalue($context,(New-Object management.automation.authorizationmanager 'Microsoft.PowerShell')) |
请注意,这不是一个安全问题。执行策略的控制权在用户。这并不是一个安全边界。
在前一个例子中我们使用 HashSet 来对比数字列表,并查找哪些元素在两个列表中都出现,或只在一个列表中出现。
字符串列表也可以做相同的事。假设您有两个名字清单,并且希望知道哪些名字在两个名单中都出现,或只在一个名单中出现,请试试以下代码:
1 | $set1 = New-Object System.Collections.Generic.HashSet[string] (,[string[]]@('Harry','Mary','Terri')) |
以下是执行结果:
Original Sets:
Harry Mary Terri
Tom Tim Terri Tobias
In Both
Terri
All Combined
Harry Mary Terri Tom Tim Tobias
Exclusive in Set 1
Harry Mary
Exclusive in both (no duplicates)
Harry Mary Tobias Tom Tim
一个脚本常常需要对比两个列表是否相等,或者某个列表是否缺失了某个元素。这种情况下,您可以使用 HashSet
,而不用手动写代码。请看:
1 | $set1 = New-Object System.Collections.Generic.HashSet[int32] (,[int[]]@(1,2,5,7,9,12)) |
这个例子演示了如何创建两个初始的集合:$set1
和 $set2
。
要计算一个列表和另一个列表的差别,首先创建一个列表的工作拷贝,然后可以运用各种比较方法,将工作拷贝和另一个列表做比较。
结果可以在工作拷贝中直接查看。这是以上代码的执行结果:
Original Sets:
1 2 5 7 9 12
1 2 5 12 111
In Both
1 2 5 12
All Combined
1 2 5 7 9 12 111
Exclusive in Set 1
7 9
Exclusive in both (no duplicates)
7 9 111
有时候您会见到用 Select-Object
向已有对象增加信息的脚本,类似以下代码:
1 | Get-Process | |
这段代码可以工作,但是 Select-Object
创建了一个全新的对象拷贝,所以这种方法速度比较慢并且改变了对象的类型。因为这个原因,您会注意到 PowerrShell 不再像正常的那样以表格的方式输出。
Add-Member
是首选的增加额外信息到已有对象的 cmdlet,因为它不会拷贝对象并且不会改变对象类型。请比较输出结果:
1 | Get-Process | |
对象类型没有改变,并且 PowerShell 继续使用进程查看缺省的输出布局。这是因为新的 “Sender” 属性初始是不可见的。不过它事实上存在:
1 | Get-Process | |
多数时候,大部分新对象都是静态数据,以属性的方式表示。一个特别有效的创建新的包含新属性的对象是将哈希表转换为对象——我们早些时候转换过:
1 | $conf = [PSCustomObject]@{ |
输出的结果是一个简单的对象,没有任何特别的方法:
1 | PS C:\> $conf |
要增加方法,请在随后使用 Add-Member
修饰该对象。这行代码增加一个新的 Register()
方法:
1 | $object | |
请注意脚本块代码如何通过 Register()
方法来存取 $this
:$this
变量代表对象自身,所以即便您晚些时候才决定改变 “Url
“ 属性,Register()
方法将仍然可以工作。
当您运行 Register()
方法,该对象打开 “Url
“ 属性指定的 URL:
1 | PS C:\> $conf.Register() |
在前一个技能中,我们学习了针对 PowerShell ISE 的命令扩展。以下是另一个例子,增加 CTRL
+K
键盘快捷键,在选中的每一行尾部添加注释 (#
)。
1 | function Invoke-Comment |
PowerShell ISE 暴露了一些可扩展的组件。例如,如果您希望按下 CTRL
+K
切换选中文本的注释状态,请试试这段代码:
1 | function Toggle-Comment |
它基本上是使用 $psise
来操作 ISE 对象模型,然后安装一个快捷键为 CTRL
+K
的新的菜单命令来调用 Toggle-Comment
函数。
在位于 $profile
的用户配置文件脚本中(这个路径可能还不存在)增加这段代码,PowerShell ISE 每次启动的时候就会自动运行这段代码。
在前一个技能中我们大量操作了哈希表,甚至从 .psd1 文件中读取。如果您需要不同格式的数据,例如 JSON,那么转换工作很简单。需要做的只是先将哈希表转换为一个对象:
1 | $hash = @{ |
当哈希表转换为一个对象以后,您可以将它用管道传递给 ConvertTo-Json
,或其它的 ConvertTo-*
指令。
在前一个技能中我们介绍了通过 Import-LocalizedData
读取存储在 .psd1 文件中的数据。
从 PowerShell 5 开始,有一个新的cmdlet名为 Import-PowerShellDataFile
。您可以用它安全地从 .psd1 文件中读取数据。类似 Import-LocalizedData
,这个cmdlet只接受没有活动内容(没有命令和变量)的 .psd1 文件。
以下是您需要的脚本:
1 | $path = "$PSScriptRoot\data.psd1" |
将数据文件存放在相同文件夹下,将它命名为 data.psd1,然后设为如下内容:
1 | @{ |
当您运行这段脚本时,它将 .psd1 文件中的数据以哈希表的形式返回。