当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 关于 PSCustomObject 您想了解的所有信息

作者:精品下载站 日期:2024-12-14 03:04:26 浏览:14 分类:玩电脑

关于 PSCustomObject 您想了解的所有信息


PSCustomObject 是一个可以添加到 PowerShell 工具带中的出色工具。让我们从基础知识开始,逐步了解更高级的功能。使用 PSCustomObject 背后的想法是提供一种创建结构化数据的简单方法。看一下第一个示例,您就会更好地了解这意味着什么。

笔记

本文的原始版本出现在@KevinMarquette 撰写的博客上。 PowerShell 团队感谢 Kevin 与我们分享这些内容。请查看他的博客:PowerShellExplained.com。

创建 PSCustomObject

我喜欢在 PowerShell 中使用 [PSCustomObject]。创建可用的对象从未如此简单。因此,我将跳过创建对象的所有其他方法,但我需要提及的是,这些示例中的大多数都是 PowerShell v3.0 及更高版本。

$myObject = [PSCustomObject]@{
    Name     = 'Kevin'
    Language = 'PowerShell'
    State    = 'Texas'
}

这种方法对我来说很有效,因为我几乎所有事情都使用哈希表。但有时我希望 PowerShell 将哈希表更像一个对象。您首先注意到差异的地方是当您想要使用Format-TableExport-CSV 并且您意识到哈希表只是键/值对的集合时。

然后,您可以像访问普通对象一样访问和使用这些值。

$myObject.Name

转换哈希表

当我谈论这个话题时,你知道你可以这样做吗:

$myHashtable = @{
    Name     = 'Kevin'
    Language = 'PowerShell'
    State    = 'Texas'
}
$myObject = [pscustomobject]$myHashtable

我确实更喜欢从一开始就创建对象,但有时您必须首先使用哈希表。此示例之所以有效,是因为构造函数采用对象属性的哈希表。一个重要的注意事项是,虽然此方法有效,但它并不完全等效。最大的区别是不保留属性的顺序。

如果您想保留顺序,请参阅有序哈希表。

传统方法

您可能见过人们使用 New-Object 创建自定义对象。

$myHashtable = @{
    Name     = 'Kevin'
    Language = 'PowerShell'
    State    = 'Texas'
}

$myObject = New-Object -TypeName PSObject -Property $myHashtable

这种方式速度较慢,但对于早期版本的 PowerShell 来说,它可能是最佳选择。

保存到文件

我发现将哈希表保存到文件的最佳方法是将其保存为 JSON。您可以将其导入回 [PSCustomObject]

$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path
$myObject = Get-Content -Path $Path | ConvertFrom-Json

我在《读写文件的多种方法》一文中介绍了将对象保存到文件的更多方法。

使用属性

添加属性

您仍然可以使用 Add-Member 将新属性添加到您的 PSCustomObject

$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'

$myObject.ID

删除属性

您还可以删除对象的属性。

$myObject.psobject.properties.remove('ID')

.psobject 是一个内部成员,可让您访问基本对象元数据。有关内部成员的更多信息,请参阅 about_Intrinsic_Members。

枚举属性名称

有时您需要对象上所有属性名称的列表。

$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name

我们也可以从 psobject 属性中获取相同的列表。

$myobject.psobject.properties.name

笔记

Get-Member 按字母顺序返回属性。使用成员访问运算符枚举属性名称会按照属性在对象上定义的顺序返回属性。

动态访问属性

我已经提到过您可以直接访问属性值。

$myObject.Name

您可以使用字符串作为属性名称,它仍然有效。

$myObject.'Name'

我们可以再采取这一步骤,并使用变量作为属性名称。

$property = 'Name'
$myObject.$property

我知道这看起来很奇怪,但它确实有效。

将 PSCustomObject 转换为哈希表

要继续上一节,您可以动态遍历属性并根据它们创建哈希表。

$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
    $hashtable[$property] = $myObject.$property
}

性能测试

如果您需要知道某个属性是否存在,您只需检查该属性是否具有值即可。

if( $null -ne $myObject.ID )

但如果该值可能是 $null,您可以通过检查 psobject.properties 来检查它是否存在。

if( $myobject.psobject.properties.match('ID').Count )

添加对象方法

如果需要向对象添加脚本方法,可以使用 Add-MemberScriptBlock 来完成。您必须使用 this 自动变量引用当前对象。这是一个将对象转换为哈希表的scriptblock。 (与上一个示例相同的代码)

$ScriptBlock = {
    $hashtable = @{}
    foreach( $property in $this.psobject.properties.name )
    {
        $hashtable[$property] = $this.$property
    }
    return $hashtable
}

然后我们将它作为脚本属性添加到我们的对象中。

$memberParam = @{
    MemberType = "ScriptMethod"
    InputObject = $myobject
    Name = "ToHashtable"
    Value = $scriptBlock
}
Add-Member @memberParam

然后我们可以这样调用我们的函数:

$myObject.ToHashtable()

对象与值类型

对象和值类型处理变量赋值的方式不同。如果相互分配值类型,则只有值会复制到新变量。

$first = 1
$second = $first
$second = 2

在本例中,$first 为 1,$second 为 2。

对象变量保存对实际对象的引用。当您将一个对象分配给新变量时,它们仍然引用同一个对象。

$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4

由于 $third$fourth 引用对象的同一实例,因此 $third.key$fourth.Key代码>是4。

psobject.copy()

如果您需要对象的真实副本,可以克隆它。

$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4

克隆创建对象的浅表副本。他们现在有不同的实例,在此示例中,$third.key 为 3,$fourth.Key 为 4。

我将其称为浅复制,因为如果您有嵌套对象(具有属性的对象包含其他对象),则仅复制顶级值。子对象将相互引用。

自定义对象类型的 PSTypeName

现在我们有了一个对象,我们还可以用它做一些可能不那么明显的事情。我们需要做的第一件事是给它一个PSTypeName。这是我看到人们最常见的做法:

$myObject.PSObject.TypeNames.Insert(0,"My.Object")

我最近从 Redditor u/markekraus 发现了另一种方法。他谈到了这种允许您内联定义它的方法。

$myObject = [PSCustomObject]@{
    PSTypeName = 'My.Object'
    Name       = 'Kevin'
    Language   = 'PowerShell'
    State      = 'Texas'
}

我喜欢这与语言的完美契合。现在我们有了一个具有正确类型名称的对象,我们可以做更多的事情。

笔记

您还可以使用 PowerShell 类创建自定义 PowerShell 类型。有关详细信息,请参阅 PowerShell 类概述。

使用 DefaultPropertySet(漫长的道路)

PowerShell 为我们决定默认显示哪些属性。许多本机命令都有一个 .ps1xml 格式化文件来完成所有繁重的工作。根据 Boe Prox 的这篇文章,我们还有另一种方法可以仅使用 PowerShell 在自定义对象上执行此操作。我们可以给它一个 MemberSet 供它使用。

$defaultDisplaySet = 'Name','Language'
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultDisplaySet)
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
$MyObject | Add-Member MemberSet PSStandardMembers $PSStandardMembers

现在,当我的对象刚刚落入外壳时,默认情况下它只会显示这些属性。

使用 DefaultPropertySet 更新类型数据

这很好,但我最近看到了一种更好的方法,使用 Update-TypeData 来指定默认属性。

$TypeData = @{
    TypeName = 'My.Object'
    DefaultDisplayPropertySet = 'Name','Language'
}
Update-TypeData @TypeData

这很简单,如果我没有这篇文章作为快速参考,我几乎可以记住它。现在,我可以轻松创建具有大量属性的对象,并且在从 shell 中查看它时仍然可以提供清晰的视图。如果我需要访问或查看其他属性,它们仍然在那里。

$myObject | Format-List *

使用 ScriptProperty 更新类型数据

我从该视频中得到的其他内容是为您的对象创建脚本属性。现在是指出这也适用于现有对象的好时机。

$TypeData = @{
    TypeName = 'My.Object'
    MemberType = 'ScriptProperty'
    MemberName = 'UpperCaseName'
    Value = {$this.Name.toUpper()}
}
Update-TypeData @TypeData

您可以在创建对象之前或之后执行此操作,它仍然可以工作。这就是它与使用 Add-Member 与脚本属性不同的原因。当您按照我之前引用的方式使用 Add-Member 时,它仅存在于该对象的特定实例上。这适用于具有此 TypeName 的所有对象。

功能参数

您现在可以在函数和脚本中使用这些自定义类型作为参数。您可以让一个函数创建这些自定义对象,然后将它们传递给其他函数。

param( [PSTypeName('My.Object')]$Data )

PowerShell 要求对象是您指定的类型。如果类型不自动匹配,它会抛出验证错误,以节省您在代码中测试它的步骤。这是让 PowerShell 做它最擅长的事情的一个很好的例子。

函数输出类型

您还可以为高级函数定义一个OutputType

function Get-MyObject
{
    [OutputType('My.Object')]
    [CmdletBinding()]
        param
        (
            ...

OutputType 属性值只是文档注释。它不是从函数代码派生出来的,也不是与实际函数输出进行比较的。

使用输出类型的主要原因是有关函数的元信息反映了您的意图。您的开发环境可以利用诸如 Get-CommandGet-Help 之类的东西。如果您想了解更多信息,请查看它的帮助:about_Functions_OutputTypeAttribute。

话虽如此,如果您使用 Pester 对函数进行单元测试,那么最好验证输出对象是否与您的 OutputType 相匹配。这可以捕获不应该落入管道的变量。

结束语

此内容的上下文都是关于 [PSCustomObject],但其中很多信息通常适用于对象。

我以前见过其中大部分功能,但从未见过它们在 PSCustomObject 上以信息集合的形式呈现。就在上周,我偶然发现了另一个,令我惊讶的是我以前没有见过它。我想将所有这些想法整合在一起,以便您能够看到更大的图景,并在有机会使用它们时意识到它们。我希望您学到了一些东西,并能找到一种方法将其应用到您的脚本中。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯