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

时间:2020-03-05 18:52:29  来源:igfitidea点击:

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

Contact
{
    string First
    string Last
    string Phone
}

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

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

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

解决方案

回答

我们可以使用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"

输出如下:

[8] ? $contact

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

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

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

回答

可以在PowerShell中创建自定义类型。
柯克·蒙罗(Kirk Munro)实际上有两个很棒的帖子,对过程进行了详尽的详细介绍。

  • 命名自定义对象
  • 定义自定义对象的默认属性

Manning撰写的《 Windows PowerShell In Action》一书还提供了一个代码示例,用于创建特定于域的语言来创建自定义类型。这本书在各个方面都很出色,所以我真的推荐它。

如果我们只是在寻找一种快速的方法来执行上述操作,则可以创建一个函数来创建自定义对象,例如

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
}

回答

这是快捷方式:

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

回答

在PowerShell 3之前

PowerShell的可扩展类型系统最初不让我们创建可以针对参数进行测试的具体类型。如果我们不需要该测试,则可以使用上面提到的任何其他方法。

如果我们想要一个可以转换为或者进行类型检查的实际类型,例如在示例脚本中……除非将其写入Cor VB.net并进行编译,否则无法完成。在PowerShell 2中,我们可以使用" Add-Type"命令来简化它:

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

历史记录:在PowerShell 1中,它甚至更难。我们必须手动使用CodeDom,PoshCode.org上有一个非常老的函数new-struct脚本,可以。示例变为:

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

使用Add-Type或者New-Struct可以让我们实际在param([Contact] $ contact)中测试该类,并使用$ contact = new-object Contact来创建新类。 。

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

从PowerShell 2开始,我们可以将-Property参数用于New-Object:

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

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

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

我们仍然只能得到一个对象,因此我们应该执行" New-Contact"函数以确保每个对象都相同,但是现在我们可以通过修饰一个PSTypeName属性的参数:

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

在PowerShell 5中,一切都发生了变化,我们最终获得了" class"和" enum"作为用于定义类型的语言关键字(没有" struct"但可以):

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

我们还提供了一种无需使用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"
}