pscustomobject.s are a great tool to add into your Powershell toolbelt. Let’s start with the basics and work our way into the more advanced features. The idea behind using a pscustomobject. is to have a very simple way to create structured data. Take a look at the first example and you will have a better idea of what that means.

指数

创建PSCustomObject.

I love using [PSCustomObject] in Powershell. Creating a usable object has never been easier. Because of that, I am going to skip over all the other ways you can create an object but I do need to mention that most of this is Powershell v3.0 and newer.

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

This works well for me because I use hashtables for just about everything. But there are times when I would like Powershell to treat hashtables more like an object and this does it. The first place you notice the difference is when you want to use Format-Table or Export-CSV 和 you realize that a hashtable is just a collection of key/value pairs.

然后,您可以访问并使用像普通对象一样的值。

$myObject.Name

转换一个哈希特

虽然我在这个主题上,你知道你可以做到这一点:

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

我更喜欢从一开始创建对象,但有时你必须先使用哈希特。这是作用,因为构造函数为对象属性进行了Hastable。一个重要的说明是,虽然这是有效的,但它并不是一个完全重要的。最大的区别是属性的顺序不保留。

遗产方法

You may have seen people use New-Object to create custom objects.

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

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

这种方式有点慢,但它可能是您对PowerShell的EARY版本的最佳选择。

保存到文件

我找到保存哈希表到文件的最佳方法是将其另存为JSON。您可以将其导入其中 [PSCusomObject]

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

我介绍了更多方法来将对象保存到我的文章中的文件 阅读和写入文件的许多方法.

添加属性

You can still add new properties to your pscustomobject. with Add-Member.

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

$myObject.ID

删除属性

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

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

psobject is a hidden property that gives you access to base object metadata.

枚举属性名称

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

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

We can get this same list off of the psobject property too.

$myobject.psobject.properties.name

动态访问属性

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

$myObject.Name

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

$myObject.'Name'

我们可以稍微拍摄这一步并为属性名称使用变量。

$property = 'Name'
$myObject.$property

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

将pscustomboject转换为哈希表

要从最后一个SECITON继续,您可以动态地行走属性并从中创建一个哈希表。

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

测试属性

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

if( $null -ne $myObject.ID )

But if the value could be $null 和 you still need to check for it, you can check the psobject.properties for it.

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

添加对象方法

If you need to add a script method to an object, you can do it with Add-Member 和 a ScriptBlock. You have to use the this automatic variable reference the current object. Here is a scriptblock to turn a object into a hashtable. (same code form the last example)

$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()

对象VS值类型

对象和值类型不会以相同的方式处理变量分配。如果为彼此分配值类型,则只有该值将被复制到新变量。

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

In this case, $first is 1 and $second is 2.

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

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

Because $third$fourth reference the same instance of an object, both $third.key$fourth.Key are 4.

psobject.copy()

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

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

Clone creates a shallow copy of the object. They have different instances now and $third.key is 3 and $fourth.Key is 4 in this example.

我称之为浅副本,因为如果您有嵌套对象。 (属性包含其他对象的位置)。只复制顶级值。子对象将相互引用。

自定义对象类型的pstypename

Now that we have an object, there are a few more things we can do with it that may not be nearly as obvious. First thing we need to do is give it a PSTypeName. This is the most common way I see people do it:

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

我最近发现了另一种方式来做这件事 由/ U / Markekraus发布。我做了一点挖掘和更多关于这个想法的帖子 亚当·贝尔特兰迈克谢泼德 他们谈论这种方法,允许您在内联定义它。

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

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

使用DefaultPropertyset(长路)

电源外壳默认确定我们要显示的属性是什么。很多原生命令都有一个 .ps1xml 形成文件 这是所有沉重的举重。由此 Boe Prox发布, there is another way for us to do this on our custom object using just Powershell. We can give it a MemberSet for it to use.

$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

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

使用defaultPropertyset更新 - typedata

这真的很好,但我最近在观看时看到了更好的方法 电源外壳与Jeffrey Snover拔掉了2016年& Don Jones。他正在使用 更新 - typedata. 指定默认属性。

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

这简单,如果我没有这篇文章,我几乎可以记住它,因为我没有作为快速参考。现在我可以轻松地创建具有大量属性的对象,并且在从shell看它时仍然会给它一个漂亮的清洁视图。如果我需要访问或查看其他属性,它们仍然存在。

$myObject | Format-List *

使用scriptproperty更新 - typedata

我离开该视频的其他东西正在为对象创建脚本属性。这将是一个好时机,指出这也适用于现有物体。

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

You can do this before your object is created or after and it will still work. This is what makes this different then using Add-Member with a script property. When you use Add-Member the way I referenced earlier, it only exists on that specific instance of the object. This one applies to all objects with this TypeName.

功能参数

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

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

然后,PowerShell将要求对象是您指定的类型。如果类型不匹配,则会抛出验证错误,以便在代码中为您节省测试步骤。让Powershell做到最好的一个很好的例子。

功能OutputType.

You can also define an OutputType. for your advanced functions.

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

OutputType. 属性值仅是文档说明。它不是从功能代码中导出或与实际功能输出相比。

这 main reason you would use an output type is so that meta information about your function reflects your intentions. Things like Get-Command,Get-Help 和 your development environment can take advantage of that. If you want more information then take a look at the help for it: about_functions_outputtypeattribute.

With that said, if you are utilizing Pester to unit test your functions then it would be a good idea to validate the output objects match your OutputType.. This could catch variables that just fall to the pipe when they shouldn’t.

结束思想

这 context of this was all about [PSCustomObject], but a lot of this information applies to objects in general.

I have seen most of these features in passing before but never saw them presented as a collection of information on pscustomobject.. Just this last week I stumbled upon another one and was surprised that I had not seen it before. I wanted to pull all these ideas together so you can hopefully see the bigger picture and be aware of them when you have an opportunity to use them. I hope you learned something and can find a way to work this into your scripts.