如何在PowerShell中创建自定义类型以供我的脚本使用?

时间:2022-07-14 07:15:27

I would like to be able to define and use a custom type in some of my PowerShell scripts. For example, let's pretend I had a need for an object that had the following structure:

我希望能够在我的一些PowerShell脚本中定义和使用自定义类型。例如,让我假装我需要一个具有以下结构的对象:

Contact
{
    string First
    string Last
    string Phone
}

How would I go about creating this so that I could use it in function like the following:

我将如何创建它,以便我可以在以下功能中使用它:

function PrintContact
{
    param( [Contact]$contact )
    "Customer Name is " + $contact.First + " " + $contact.Last
    "Customer Phone is " + $contact.Phone 
}

Is something like this possible, or even recommended in PowerShell?

这样的事情是可能的,甚至在PowerShell中推荐?

7 个解决方案

#1


53  

Creating custom types can be done in PowerShell.
Kirk Munro actually has two great posts that detail the process thoroughly.

可以在PowerShell中创建自定义类型。 Kirk Munro实际上有两个很好的帖子,详细介绍了这个过程。

The book Windows PowerShell In Action by Manning also has a code sample for creating a domain specific language to create custom types. The book is excellent all around, so I really recommend it.

Manning的Windows PowerShell In Action一书还提供了一个代码示例,用于创建特定于域的语言来创建自定义类型。这本书很好,所以我真的推荐它。

If you are just looking for a quick way to do the above, you could create a function to create the custom object like

如果您只是想快速完成上述操作,可以创建一个函数来创建自定义对象

function New-Person()
{
  param ($FirstName, $LastName, $Phone)

  $person = new-object PSObject

  $person | add-member -type NoteProperty -Name First -Value $FirstName
  $person | add-member -type NoteProperty -Name Last -Value $LastName
  $person | add-member -type NoteProperty -Name Phone -Value $Phone

  return $person
}

#2


84  

Prior to PowerShell 3

PowerShell's Extensible Type System didn't originally let you create concrete types you can test against the way you did in your parameter. If you don't need that test, you're fine with any of the other methods mentioned above.

PowerShell的可扩展类型系统最初并不允许您创建具体类型,您可以根据参数的方式进行测试。如果您不需要该测试,则可以使用上述任何其他方法。

If you want an actual type that you can cast to or type-check with, as in your example script ... it cannot be done without writing it in C# or VB.net and compiling. In PowerShell 2, you can use the "Add-Type" command to do it quite simmple:

如果你想要一个你可以强制转换或使用类型检查的实际类型,就像在你的示例脚本中那样......如果没有在C#或VB.net中编写并编译它就无法完成。在PowerShell 2中,您可以使用“Add-Type”命令来完成它:

add-type @"
public struct contact {
   public string First;
   public string Last;
   public string Phone;
}
"@

Historical Note: In PowerShell 1 it was even harder. You had to manually use CodeDom, there is a very old function new-struct script on PoshCode.org which will help. Your example becomes:

历史记录:在PowerShell 1中,它更难。你必须手动使用CodeDom,PoshCode.org上有一个非常古老的函数new-struct脚本,这将有所帮助。你的例子变成:

New-Struct Contact @{
    First=[string];
    Last=[string];
    Phone=[string];
}

Using Add-Type or New-Struct will let you actually test the class in your param([Contact]$contact) and make new ones using $contact = new-object Contact and so on...

使用Add-Type或New-Struct将允许您实际测试param中的类([Contact] $ contact)并使用$ contact = new-object Contact等来创建新类...

In PowerShell 3

If you don't need a "real" class that you can cast to, you don't have to use the Add-Member way that Steven and others have demonstrated above.

如果您不需要可以强制转换的“真实”类,则不必使用Steven和其他人在上面演示过的Add-Member方法。

Since PowerShell 2 you could use the -Property parameter for New-Object:

从PowerShell 2开始,您可以为New-Object使用-Property参数:

$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }

And in PowerShell 3, we got the ability to use the PSCustomObject accelerator to add a TypeName:

在PowerShell 3中,我们可以使用PSCustomObject加速器添加TypeName:

[PSCustomObject]@{
    PSTypeName = "Contact"
    First = $First
    Last = $Last
    Phone = $Phone
}

You're still only getting a single object, so you should make a New-Contact function to make sure that every object comes out the same, but you can now easily verify a parameter "is" one of those type by decorating a parameter with the PSTypeName attribute:

您仍然只获得一个对象,因此您应该创建一个New-Contact函数以确保每个对象都是相同的,但您现在可以通过使用装饰参数来轻松验证参数“is”之一PSTypeName属性:

function PrintContact
{
    param( [PSTypeName("Contact")]$contact )
    "Customer Name is " + $contact.First + " " + $contact.Last
    "Customer Phone is " + $contact.Phone 
}

In PowerShell 5

In PowerShell 5 everything changes, and we finally got class and enum as language keywords for defining types (there's no struct but that's ok):

在PowerShell 5中,一切都在变化,我们最终得到了class和enum作为定义类型的语言关键字(没有结构但是没关系):

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone

    # optionally, have a constructor to 
    # force properties to be set:
    Contact($First, $Last, $Phone) {
       $this.First = $First
       $this.Last = $Last
       $this.Phone = $Phone
    }
}

We also got a new way to create objects without using New-Object: [Contact]::new() -- in fact, if you kept your class simple and don't define a constructor, you can create objects by casting a hashtable (although without a constructor, there would be no way to enforce that all properties must be set):

我们还有一种新的方法来创建对象而不使用New-Object:[Contact] :: new() - 实际上,如果你保持你的类简单并且没有定义构造函数,你可以通过生成哈希表来创建对象(虽然没有构造函数,但是没有办法强制必须设置所有属性):

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone
}

$C = [Contact]@{
   First = "Joel"
   Last = "Bennett"
}

#3


16  

This is the shortcut method:

这是快捷方式:

$myPerson = "" | Select-Object First,Last,Phone

#4


9  

Steven Murawski's answer is great, however I like the shorter (or rather just the neater select-object instead of using add-member syntax):

Steven Murawski的答案很棒,但是我喜欢较短的(或者更简单的是更简洁的select-object而不是使用add-member语法):

function New-Person() {
  param ($FirstName, $LastName, $Phone)

  $person = new-object PSObject | select-object First, Last, Phone

  $person.First = $FirstName
  $person.Last = $LastName
  $person.Phone = $Phone

  return $person
}

#5


4  

There is the concept of PSObject and Add-Member that you could use.

您可以使用PSObject和Add-Member的概念。

$contact = New-Object PSObject

$contact | Add-Member -memberType NoteProperty -name "First" -value "John"
$contact | Add-Member -memberType NoteProperty -name "Last" -value "Doe"
$contact | Add-Member -memberType NoteProperty -name "Phone" -value "123-4567"

This outputs like:

输出如下:

[8] » $contact

First                                       Last                                       Phone
-----                                       ----                                       -----
John                                        Doe                                        123-4567

The other alternative (that I'm aware of) is to define a type in C#/VB.NET and load that assembly into PowerShell for use directly.

另一个替代方案(我知道)是在C#/ VB.NET中定义一个类型,并将该程序集加载到PowerShell中以便直接使用。

This behavior is definitely encouraged because it allows other scripts or sections of your script work with an actual object.

绝对鼓励这种行为,因为它允许脚本的其他脚本或部分与实际对象一起使用。

#6


4  

Surprised no one mentioned this simple option (vs 3 or later) for creating custom objects:

惊讶没有人提到这个简单的选项(vs 3或更高版本)来创建自定义对象:

[PSCustomObject]@{
    First = $First
    Last = $Last
    Phone = $Phone
}

The type will be PSCustomObject, not an actual custom type though. But it is probably the easiest way to create a custom object.

类型将是PSCustomObject,但不是实际的自定义类型。但它可能是创建自定义对象的最简单方法。

#7


2  

Here is the hard path to create custom types and store them in a collection.

以下是创建自定义类型并将其存储在集合中的硬路径。

$Collection = @()

$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "John"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "123-4567"
$Collection += $Object

$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "Jeanne"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "765-4321"
$Collection += $Object

Write-Ouput -InputObject $Collection

#1


53  

Creating custom types can be done in PowerShell.
Kirk Munro actually has two great posts that detail the process thoroughly.

可以在PowerShell中创建自定义类型。 Kirk Munro实际上有两个很好的帖子,详细介绍了这个过程。

The book Windows PowerShell In Action by Manning also has a code sample for creating a domain specific language to create custom types. The book is excellent all around, so I really recommend it.

Manning的Windows PowerShell In Action一书还提供了一个代码示例,用于创建特定于域的语言来创建自定义类型。这本书很好,所以我真的推荐它。

If you are just looking for a quick way to do the above, you could create a function to create the custom object like

如果您只是想快速完成上述操作,可以创建一个函数来创建自定义对象

function New-Person()
{
  param ($FirstName, $LastName, $Phone)

  $person = new-object PSObject

  $person | add-member -type NoteProperty -Name First -Value $FirstName
  $person | add-member -type NoteProperty -Name Last -Value $LastName
  $person | add-member -type NoteProperty -Name Phone -Value $Phone

  return $person
}

#2


84  

Prior to PowerShell 3

PowerShell's Extensible Type System didn't originally let you create concrete types you can test against the way you did in your parameter. If you don't need that test, you're fine with any of the other methods mentioned above.

PowerShell的可扩展类型系统最初并不允许您创建具体类型,您可以根据参数的方式进行测试。如果您不需要该测试,则可以使用上述任何其他方法。

If you want an actual type that you can cast to or type-check with, as in your example script ... it cannot be done without writing it in C# or VB.net and compiling. In PowerShell 2, you can use the "Add-Type" command to do it quite simmple:

如果你想要一个你可以强制转换或使用类型检查的实际类型,就像在你的示例脚本中那样......如果没有在C#或VB.net中编写并编译它就无法完成。在PowerShell 2中,您可以使用“Add-Type”命令来完成它:

add-type @"
public struct contact {
   public string First;
   public string Last;
   public string Phone;
}
"@

Historical Note: In PowerShell 1 it was even harder. You had to manually use CodeDom, there is a very old function new-struct script on PoshCode.org which will help. Your example becomes:

历史记录:在PowerShell 1中,它更难。你必须手动使用CodeDom,PoshCode.org上有一个非常古老的函数new-struct脚本,这将有所帮助。你的例子变成:

New-Struct Contact @{
    First=[string];
    Last=[string];
    Phone=[string];
}

Using Add-Type or New-Struct will let you actually test the class in your param([Contact]$contact) and make new ones using $contact = new-object Contact and so on...

使用Add-Type或New-Struct将允许您实际测试param中的类([Contact] $ contact)并使用$ contact = new-object Contact等来创建新类...

In PowerShell 3

If you don't need a "real" class that you can cast to, you don't have to use the Add-Member way that Steven and others have demonstrated above.

如果您不需要可以强制转换的“真实”类,则不必使用Steven和其他人在上面演示过的Add-Member方法。

Since PowerShell 2 you could use the -Property parameter for New-Object:

从PowerShell 2开始,您可以为New-Object使用-Property参数:

$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }

And in PowerShell 3, we got the ability to use the PSCustomObject accelerator to add a TypeName:

在PowerShell 3中,我们可以使用PSCustomObject加速器添加TypeName:

[PSCustomObject]@{
    PSTypeName = "Contact"
    First = $First
    Last = $Last
    Phone = $Phone
}

You're still only getting a single object, so you should make a New-Contact function to make sure that every object comes out the same, but you can now easily verify a parameter "is" one of those type by decorating a parameter with the PSTypeName attribute:

您仍然只获得一个对象,因此您应该创建一个New-Contact函数以确保每个对象都是相同的,但您现在可以通过使用装饰参数来轻松验证参数“is”之一PSTypeName属性:

function PrintContact
{
    param( [PSTypeName("Contact")]$contact )
    "Customer Name is " + $contact.First + " " + $contact.Last
    "Customer Phone is " + $contact.Phone 
}

In PowerShell 5

In PowerShell 5 everything changes, and we finally got class and enum as language keywords for defining types (there's no struct but that's ok):

在PowerShell 5中,一切都在变化,我们最终得到了class和enum作为定义类型的语言关键字(没有结构但是没关系):

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone

    # optionally, have a constructor to 
    # force properties to be set:
    Contact($First, $Last, $Phone) {
       $this.First = $First
       $this.Last = $Last
       $this.Phone = $Phone
    }
}

We also got a new way to create objects without using New-Object: [Contact]::new() -- in fact, if you kept your class simple and don't define a constructor, you can create objects by casting a hashtable (although without a constructor, there would be no way to enforce that all properties must be set):

我们还有一种新的方法来创建对象而不使用New-Object:[Contact] :: new() - 实际上,如果你保持你的类简单并且没有定义构造函数,你可以通过生成哈希表来创建对象(虽然没有构造函数,但是没有办法强制必须设置所有属性):

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone
}

$C = [Contact]@{
   First = "Joel"
   Last = "Bennett"
}

#3


16  

This is the shortcut method:

这是快捷方式:

$myPerson = "" | Select-Object First,Last,Phone

#4


9  

Steven Murawski's answer is great, however I like the shorter (or rather just the neater select-object instead of using add-member syntax):

Steven Murawski的答案很棒,但是我喜欢较短的(或者更简单的是更简洁的select-object而不是使用add-member语法):

function New-Person() {
  param ($FirstName, $LastName, $Phone)

  $person = new-object PSObject | select-object First, Last, Phone

  $person.First = $FirstName
  $person.Last = $LastName
  $person.Phone = $Phone

  return $person
}

#5


4  

There is the concept of PSObject and Add-Member that you could use.

您可以使用PSObject和Add-Member的概念。

$contact = New-Object PSObject

$contact | Add-Member -memberType NoteProperty -name "First" -value "John"
$contact | Add-Member -memberType NoteProperty -name "Last" -value "Doe"
$contact | Add-Member -memberType NoteProperty -name "Phone" -value "123-4567"

This outputs like:

输出如下:

[8] » $contact

First                                       Last                                       Phone
-----                                       ----                                       -----
John                                        Doe                                        123-4567

The other alternative (that I'm aware of) is to define a type in C#/VB.NET and load that assembly into PowerShell for use directly.

另一个替代方案(我知道)是在C#/ VB.NET中定义一个类型,并将该程序集加载到PowerShell中以便直接使用。

This behavior is definitely encouraged because it allows other scripts or sections of your script work with an actual object.

绝对鼓励这种行为,因为它允许脚本的其他脚本或部分与实际对象一起使用。

#6


4  

Surprised no one mentioned this simple option (vs 3 or later) for creating custom objects:

惊讶没有人提到这个简单的选项(vs 3或更高版本)来创建自定义对象:

[PSCustomObject]@{
    First = $First
    Last = $Last
    Phone = $Phone
}

The type will be PSCustomObject, not an actual custom type though. But it is probably the easiest way to create a custom object.

类型将是PSCustomObject,但不是实际的自定义类型。但它可能是创建自定义对象的最简单方法。

#7


2  

Here is the hard path to create custom types and store them in a collection.

以下是创建自定义类型并将其存储在集合中的硬路径。

$Collection = @()

$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "John"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "123-4567"
$Collection += $Object

$Object = New-Object -TypeName PSObject
$Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail')
Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "Jeanne"
Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe"
Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "765-4321"
$Collection += $Object

Write-Ouput -InputObject $Collection