How do I create a custom type in PowerShell for my scripts to use?

后端 未结 8 1229
遥遥无期
遥遥无期 2020-12-22 18:29

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 struc

相关标签:
8条回答
  • 2020-12-22 18:52

    This is the shortcut method:

    $myPerson = "" | Select-Object First,Last,Phone
    
    0 讨论(0)
  • 2020-12-22 18:56

    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
    
    0 讨论(0)
  • 2020-12-22 19:00

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

    [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.

    0 讨论(0)
  • 2020-12-22 19:01

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

    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
    }
    
    0 讨论(0)
  • 2020-12-22 19:08

    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.

    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:

    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:

    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...

    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.

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

    $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:

    [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:

    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):

    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):

    class Contact
    {
        # Optionally, add attributes to prevent invalid values
        [ValidateNotNullOrEmpty()][string]$First
        [ValidateNotNullOrEmpty()][string]$Last
        [ValidateNotNullOrEmpty()][string]$Phone
    }
    
    $C = [Contact]@{
       First = "Joel"
       Last = "Bennett"
    }
    
    0 讨论(0)
  • 2020-12-22 19:16

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

    $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.

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

    0 讨论(0)
提交回复
热议问题