about_Enum

简短说明

enum 语句声明枚举。 枚举是一种非重复类型,由一组名为枚举器列表的命名标签组成。

长说明

使用 enum 语句可以创建强类型标签集。 可以在代码中使用该枚举,无需分析或检查拼写错误。

枚举在内部表示为整数值类型,起始值为零。 默认情况下,PowerShell 枚举使用 System.Int32[int]) 作为基础类型。 默认情况下,PowerShell 向列表中的第一个标签分配值“0”。 默认情况下,PowerShell 向剩余标签分配连续整数。

在定义中,可以为标签提供任何整数值。 没有分配值的标签采用下一个整数值。

语法

枚举使用以下语法:

整数枚举定义语法

[[<attribute>]...] enum <enum-name> {
    <label> [= <int-value>]
    ...
}

特定的基础类型枚举定义语法

[[<attribute>]...] enum <enum-name> : <underlying-type-name> {
    <label> [= <int-value>]
    ...
}

标志枚举定义语法

[[<attribute>]...] [Flag()] enum <enum-name>[ : <underlying-type-name>] {
    <label 0> [= 1]
    <label 1> [= 2]
    <label 2> [= 4]
    <label 3> [= 8]
    ...
    ...
}

枚举访问语法

[<enum-name>]::<label>

示例

示例 1 - 最小枚举

以下代码块使用三个 标签定义 MarkdownUnorderedListCharacter 枚举。 它不向任何标签分配显式值。

enum MarkdownUnorderedListCharacter {
    Asterisk
    Dash
    Plus
}

下一个代码块显示转换为枚举类型时整数值和字符串值的行为方式。

$ValuesToConvert = @(0, 'Asterisk', 1, 'Dash', 2, 'Plus')
foreach ($Value in $ValuesToConvert) {
    [MarkdownUnorderedListCharacter]$EnumValue = $Value

    [pscustomobject]@{
        AssignedValue = $Value
        Enumeration   = $EnumValue
        AreEqual      = $Value -eq $EnumValue
    }
}
AssignedValue Enumeration AreEqual
------------- ----------- --------
            0    Asterisk     True
     Asterisk    Asterisk     True
            1        Dash     True
         Dash        Dash     True
            2        Plus     True
         Plus        Plus     True

强制转换等于枚举值的整数将返回该枚举。 强制转换与枚举标签相同的字符串将返回该枚举。

示例 2 - 显式和同义词枚举值

以下示例演示与媒体文件相关的对象的枚举。 定义将显式值分配给 musicpicturevideo 的基础值。 紧跟在显式赋值后的标签将获得下一个整数值。 可通过将相同的值分配给另一个标签来创建同义词;请参阅以下对象的构造值:oggogamogg,或者 jpgjpeg,或者 mpgmpeg

enum MediaTypes {
    unknown
    music   = 10
    mp3
    aac
    ogg     = 15
    oga     = 15
    mogg    = 15
    picture = 20
    jpg
    jpeg    = 21
    png
    video   = 40
    mpg
    mpeg    = 41
    avi
    m4v
}

GetEnumNames() 方法返回枚举的标签列表。

[MediaTypes].GetEnumNames()
unknown
music
mp3
aac
ogg
oga
mogg
picture
jpg
jpeg
png
video
mpg
mpeg
avi
m4v

GetEnumValues() 方法返回枚举的值列表。

[MediaTypes].GetEnumValues()
unknown
music
mp3
aac
ogg
ogg
ogg
picture
jpg
jpg
png
video
mpg
mpg
avi
m4v

注意

GetEnumNames()GetEnumValues() 表面上会返回相同的结果:命名值的列表。 但是在内部,GetEnumValues() 会枚举这些值,然后将值映射到名称。 仔细阅读列表,你会注意到,oggogamogg 显示在 GetEnumNames() 的输出中,但 GetEnumValues() 的输出仅显示 oggjpgjpegmpgmpeg 也是这样。 同义词值的名称 PowerShell 返回不是确定性的。

可以使用 GetEnumName() 方法获取与特定值关联的名称。 如果有多个与值关联的名称,该方法将返回第一个定义的名称。

[MediaTypes].GetEnumName(15)
ogg

以下示例演示如何将每个名称映射到其值。

[MediaTypes].GetEnumNames() | ForEach-Object {
  [pscustomobject]@{
    Name = $_
    Value = [int]([MediaTypes]::$_)
  }
}
Name    Value
----    -----
unknown     0
music      10
mp3        11
aac        12
ogg        15
oga        15
mogg       15
picture    20
jpg        21
jpeg       21
png        22
video      40
mpg        41
mpeg       41
avi        42
m4v        43

可以使用语法 [<enum-name>]::<label> 按标签指定单个枚举值。

[MediaTypes]::png
[MediaTypes]::png -eq 22
png
True

示例 3 - 枚举为标志

以下代码块将 FileAttributes 枚举创建为一组位标志。 每个标签的值是上一个标签的值的两倍。

[Flags()] enum FileAttributes {
    Archive    = 1
    Compressed = 2
    Device     = 4
    Directory  = 8
    Encrypted  = 16
    Hidden     = 32
}

[FileAttributes]$file1 =  [FileAttributes]::Archive
[FileAttributes]$file1 += [FileAttributes]::Compressed
[FileAttributes]$file1 += [FileAttributes]::Device
"file1 attributes are: $file1"

[FileAttributes]$file2 = [FileAttributes]28 ## => 16 + 8 + 4
"file2 attributes are: $file2"
file1 attributes are: Archive, Compressed, Device
file2 attributes are: Device, Directory, Encrypted

若要测试是否设置了特定标志,可使用二元比较运算符 -band。 此示例针对 $file2 的值中的 Device 和 Archive 属性进行测试。

PS > ($file2 -band [FileAttributes]::Device) -eq [FileAttributes]::Device
True

PS > ($file2 -band [FileAttributes]::Archive) -eq [FileAttributes]::Archive
False

还可以使用 HasFlag() 方法测试是否设置了特定标志。 此示例针对 $file1 的值中的 Device 和 Hidden 属性进行测试。

PS > $file1.HasFlag([FileAttributes]::Device)
True

PS > $file1.HasFlag([FileAttributes]::Hidden)
False

示例 4 - 枚举作为参数

在以下示例中,ConvertTo-LineEndingRegex 函数使用 EndOfLine 类型定义 InputObject 参数。

enum EndOfLine {
    CR   = 1
    LF   = 2
    CRLF = 3
}

function ConvertTo-LineEndingRegex {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline)]
        [EndOfLine[]]$InputObject
    )

    process {
        switch ($InputObject) {
            CR   {  '\r'  }
            LF   {  '\n'  }
            CRLF { '\r\n' }
        }
    }
}

[EndOfLine]::CR | ConvertTo-LineEndingRegex

'CRLF' | ConvertTo-LineEndingRegex

ConvertTo-LineEndingRegex 2
\r

\r\n

\n

在此示例中,调用 ConvertTo-LineEndingRegex 的第一个语句会传递 CR 的枚举值。 第二条语句传递字符串 'CRLF',该字符串被强制转换为 LineEnding。 第三个语句指定参数的值 2,该参数映射到 LF 标签。

可通过在 PowerShell 提示符中键入以下文本来查看参数补全选项:

ConvertTo-LineEndingRegex -InputObject <Tab>

为参数指定无效的标签名称或数值时,该函数会引发错误。

ConvertTo-LineEndingRegex -InputObject 0
ConvertTo-LineEndingRegex: Cannot process argument transformation on
parameter 'InputObject'. Cannot convert value "0" to type "EndOfLine" due
to enumeration values that are not valid. Specify one of the following
enumeration values and try again. The possible enumeration values are
"CR,LF,CRLF".

示例 5 - 具有特定基础类型的枚举

从 PowerShell 6.2 开始,可以使用特定的基础类型定义枚举。 此示例显示枚举的有效基础类型。

第一个代码块将两个变量初始化为数组。 $EnumTypes 是一个空数组,用于保存动态创建的类型。 $IntegralTypes 是一个数组,其中包含枚举的有效基础类型。

$EnumTypes     = @()
$IntegralTypes = @(
    'byte', 'sbyte', 'short', 'ushort', 'int', 'uint', 'long', 'ulong'
)

下一个代码块定义用于动态创建枚举定义的模板。 当 {0} 格式占位符替换为整型类型名称时,模板将创建一个脚本块,该脚本块:

  1. 定义名为 <a0/&0> 的枚举,例如byteEnum。 定义的枚举使用指定的整型类型作为基础值类型。

    枚举定义 Min 时,值设置为整型的最小值。 它定义 Max 值设置为整型的最大值。

  2. 返回新定义的类型。

$DefinitionTemplate = @"
enum {0}Enum : {0} {{
    Min = [{0}]::MinValue
    Max = [{0}]::MaxValue
}}

[{0}Enum]
"@

下一个代码块使用模板在当前范围内创建和调用脚本块。 它将返回的类型定义添加到数组中 $EnumTypes

foreach ($IntegralType in $IntegralTypes) {
    $Definition  = $DefinitionTemplate -f $IntegralType
    $ScriptBlock = [scriptblock]::Create($Definition)
    $EnumTypes  += . $ScriptBlock
}

最后一个代码块循环访问枚举类型,方法是使用 GetEnumValuesAsUnderlyingType() 该方法将值列为基础类型。 该循环为每个值创建新对象,其中显示了枚举类型、值类型、标签和实际值。

foreach ($EnumType in $EnumTypes) {
    $EnumType.GetEnumValuesAsUnderlyingType() | ForEach-Object {
        [pscustomobject]@{
            EnumType  = $EnumType.FullName
            ValueType = $_.GetType().FullName
            Label     = $EnumType.GetEnumName($_)
            Value     = $_
        }
    }
}
EnumType   ValueType     Label                Value
--------   ---------     -----                -----
byteEnum   System.Byte   Min                      0
byteEnum   System.Byte   Max                    255
sbyteEnum  System.SByte  Max                    127
sbyteEnum  System.SByte  Min                   -128
shortEnum  System.Int16  Max                  32767
shortEnum  System.Int16  Min                 -32768
ushortEnum System.UInt16 Min                      0
ushortEnum System.UInt16 Max                  65535
intEnum    System.Int32  Max             2147483647
intEnum    System.Int32  Min            -2147483648
uintEnum   System.UInt32 Min                      0
uintEnum   System.UInt32 Max             4294967295
longEnum   System.Int64  Max    9223372036854775807
longEnum   System.Int64  Min   -9223372036854775808
ulongEnum  System.UInt64 Min                      0
ulongEnum  System.UInt64 Max   18446744073709551615

枚举方法

以下列表包括可用于在 PowerShell 中枚举的有用方法,以及如何使用它们。

Format

Format()静态方法返回给定枚举类型、枚举值和格式字符串的格式化字符串输出。 输出与对具有指定格式字符串的值调用 ToString 方法相同。

可以在 System.Enum 基类类型或特定枚举类型上使用静态方法。

[System.Enum]::format([<enum-name>], <value>, <format-string>)
[<enum-name>]::format([<enum-name>], <value>, <format-string>)

有效的格式字符串为GgDdXxFf 有关详细信息,请参阅 枚举格式字符串

以下示例使用每个受支持的枚举格式字符串将 TaskState 枚举的每个值转换为其字符串表示形式。

enum TaskState {
    ToDo
    Doing
    Done
}

# String format template for the statements
$Statement = "[System.Enum]::Format([TaskState], {0}, '{1}')"

foreach ($Format in @('G', 'D', 'X', 'F')) {
    $StatementToDo  = $Statement -f 0, $Format
    $StatementDoing = $Statement -f "([TaskState]'Doing')", $Format
    $StatementDone  = $Statement -f '[TaskState]::Done', $Format
    $FormattedToDo  = [System.Enum]::Format(
      [TaskState], 0, $Format
    )
    $FormattedDoing = [System.Enum]::Format(
        [TaskState], ([TaskState]'Doing'), $Format
    )
    $FormattedDone  = [System.Enum]::Format(
      [TaskState], [TaskState]::Done, $Format
    )

    "{0,-62} => {1}" -f $StatementToDo,  $FormattedToDo
    "{0,-62} => {1}" -f $StatementDoing, $FormattedDoing
    "{0,-62} => {1}" -f $StatementDone,  $FormattedDone
}
[System.Enum]::Format([TaskState], 0, 'G')                     => ToDo
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'G')  => Doing
[System.Enum]::Format([TaskState], [TaskState]::Done, 'G')     => Done
[System.Enum]::Format([TaskState], 0, 'D')                     => 0
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'D')  => 1
[System.Enum]::Format([TaskState], [TaskState]::Done, 'D')     => 2
[System.Enum]::Format([TaskState], 0, 'X')                     => 00000000
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'X')  => 00000001
[System.Enum]::Format([TaskState], [TaskState]::Done, 'X')     => 00000002
[System.Enum]::Format([TaskState], 0, 'F')                     => ToDo
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'F')  => Doing
[System.Enum]::Format([TaskState], [TaskState]::Done, 'F')     => Done

GetEnumName

GetEnumName()反射方法返回特定枚举值的名称。 输入值必须是枚举的有效基础类型,例如整数或枚举值。 如果有多个与值关联的名称,该方法将返回第一个定义的名称。

[<enum-name>].GetEnumName(<value>)
enum GateState {
    Unknown
    Open
    Opening
    Closing
    Closed
}

foreach ($Value in 0..4) {
    [pscustomobject]@{
      IntegerValue = $Value
      EnumName     = [GateState].GetEnumName($Value)
    }
}
IntegerValue EnumName
------------ --------
           0 Unknown
           1 Open
           2 Opening
           3 Closing
           4 Closed

GetEnumNames

GetEnumNames()反射方法将每个枚举值的名称作为字符串返回。 输出包括同义词。

[<enum-name>].GetEnumNames()
enum Season {
    Unknown
    Spring
    Summer
    Autumn
    Winter
    Fall   = 3
}

[Season].GetEnumNames()
Unknown
Spring
Summer
Fall
Autumn
Winter

GetEnumUnderlyingType

反射 GetEnumUnderlyingType() 方法返回枚举值的基础类型。

[<enum-name>].GetEnumUnderlyingType()
enum IntBasedEnum {
    Zero
    One
    Two
}
enum ShortBasedEnum : short {
    Zero
    One
    Two
}

foreach ($EnumType in @([IntBasedEnum], [ShortBasedEnum])) {
    [pscustomobject]@{
        EnumType = $EnumType
        ValueType = $EnumType.GetEnumUnderlyingType()
    }
}
EnumType       ValueType
--------       ---------
IntBasedEnum   System.Int32
ShortBasedEnum System.Int16

GetEnumValues

GetEnumValues()反射方法返回枚举的每个已定义值。

[<enum-name>].GetEnumValues()
enum Season {
    Unknown
    Spring
    Summer
    Autumn
    Winter
    Fall   = 3
}

[Season].GetEnumValues()
Unknown
Spring
Summer
Fall
Fall
Winter

GetEnumValuesAsUnderlyingType

反射 GetEnumValuesAsUnderlyingType() 方法将枚举的每个已定义值作为基础类型返回。

[<enum-name>].GetEnumValuesAsUnderlyingType()
enum IntBasedEnum {
    Zero
    One
    Two
}
enum ShortBasedEnum : short {
    Zero
    One
    Two
}

foreach ($EnumType in @([IntBasedEnum], [ShortBasedEnum])) {
    [pscustomobject]@{
        EnumType = $EnumType
        ValueType = $EnumType.GetEnumValuesAsUnderlyingType()[0].GetType()
    }
}
EnumType       ValueType
--------       ---------
IntBasedEnum   System.Int32
ShortBasedEnum System.Int16

HasFlag

实例 HasFlag 方法确定是否为标志枚举值设置位标志。 使用此方法比执行二进制比较和等效检查更短、更易于读取。

<enum-value>.HasFlag(<enum-flag-value>)

以下示例定义 ModuleFeatures 标志枚举,并显示值 39 具有哪些标志。

[Flags()] enum ModuleFeatures {
    Commands  = 1
    Classes   = 2
    Enums     = 4
    Types     = 8
    Formats   = 16
    Variables = 32
}

$Features = [ModuleFeatures]39

foreach ($Feature in [ModuleFeatures].GetEnumValues()) {
    "Has flag {0,-12}: {1}" -f "'$Feature'", ($Features.HasFlag($Feature))
}
Has flag 'Commands'  : True
Has flag 'Classes'   : True
Has flag 'Enums'     : True
Has flag 'Types'     : False
Has flag 'Formats'   : False
Has flag 'Variables' : True

IsDefined

IsDefined()如果为枚举定义了输入值,则静态方法将返回。否则$false,静态方法将返回$true。 使用此方法检查值是否对枚举有效,而无需处理无效的参数错误。

可以在 System.Enum 基类类型或特定枚举类型上使用静态方法。

[System.Enum]::IsDefined([<enum-name>], <value>)
[<enum-name>]::IsDefined([<enum-name>], <value>)
enum Season {
    Unknown
    Spring
    Summer
    Autumn
    Winter
    Fall   = 3
}

foreach ($Value in 0..5) {
    $IsValid   = [Season]::IsDefined([Season], $Value)
    $EnumValue = if ($IsValid) { [Season]$Value }

    [pscustomobject] @{
        InputValue = $Value
        IsValid    = $IsValid
        EnumValue  = $EnumValue
    }
}
InputValue IsValid EnumValue
---------- ------- ---------
         0    True   Unknown
         1    True    Spring
         2    True    Summer
         3    True      Fall
         4    True    Winter
         5   False

ToString

ToString()实例方法返回枚举值的标签。 此方法也是枚举值如何显示为输出的默认视图。 (可选)可以指定格式字符串来控制值显示方式。 有关格式设置的详细信息,请参阅 格式化枚举值

注意

对于定义特定值的同义词的枚举,请勿编写依赖于其输出 ToString()的代码。 该方法可以返回值的任何有效名称。

<enum-value>.ToString([<format-string>])

以下示例将 Shade 枚举 Gray 定义为同 Grey义词。 然后,它会输出显示实际枚举值、枚举作为字符串的对象,并将枚举作为整数显示。

enum Shade {
    White
    Grey
    Gray = 1
    Black
}

[Shade].GetEnumValues() | Foreach-Object -Process {
    [pscustomobject]@{
        EnumValue    = $_
        StringValue  = $_.ToString()
        IntegerValue = [int]$_
    }
}
numValue StringValue IntegerValue
--------- ----------- ------------
    White White                  0
     Grey Grey                   1
     Grey Grey                   1
    Black Black                  2

枚举值同义词

可以定义为同一整数值提供不同名称的枚举。 执行此操作时,指向相同基础值的名称称为 同义词。 使用同义词的枚举使用户能够为同一值指定不同的名称。

使用同义词定义枚举时,不要编写依赖于转换为特定名称的同义词值的代码。 可以可靠地编写将同义词字符串转换为枚举值的代码。 使用枚举值本身时,请始终将其作为枚举值或其基础类型而不是字符串进行比较。

以下代码块定义带Grey同义词和Gray同义词的 Shade 枚举。

enum Shade {
    White
    Grey
    Gray = 1
    Black
}

[Shade]'Grey' -eq [Shade]::Gray
[Shade]::Grey -eq 1
[Shade]'Gray' -eq 1
True
True
True

枚举用作标志

枚举的一个常见用途是表示一组互斥值。 例如, ArrivalStatus 实例的值为 Early、OnTime 或 Late。 对于一个 ArrivalStatus 实例的值来反映多个枚举常量毫无意义。

但是,在其他情况下,枚举对象的值可以包含多个枚举成员,并且每个成员表示枚举值中的位字段。 可以使用 FlagsAttribute 来指示枚举包含位字段作为用户可以组合的标志。

要使枚举作为标志正常工作,必须将每个标签的整数值设置为 2 的幂。 如果未为标签指定值,PowerShell 会将该值设置为高于上一个标签的值。

可以定义常用标志组合的值,以便用户更轻松地同时指定一组标志。 该值的名称应为标志的组合名称。 整数值应为标志值的总和。

若要确定是否为值设置了特定标志,请使用 HasFlag() 该值上的方法或使用二进制比较运算符 -band

有关演示如何使用标志枚举和检查是否设置标志的示例,请参阅示例 3

枚举用作参数

可以定义使用枚举作为其类型的 cmdlet 参数。 将枚举指定为参数的类型时,用户可实现参数值的自动补全和验证。 参数补全会建议枚举的有效标签列表。

当参数将枚举用作其类型时,可指定以下任一项:

  • 枚举,例如 [<EnumType>]::<Label>
  • 用作字符串的枚举的标签
  • 枚举的数值

有关显示枚举类型参数行为的示例,请参阅 示例 4

具有特定基础类型的枚举

从 PowerShell 6.2 开始,可以使用特定的基础类型定义枚举。 在没有特定基础类型的情况下定义枚举时,PowerShell 会创建枚举([int]System.Int32)作为基础类型。

枚举的基础类型必须是 整型数值类型。 以下列表包括具有其短名称和完整类型名称的有效类型:

  • byte - System.Byte
  • sbyte - System.SByte
  • short - System.Int16
  • System.UInt16ushort -
  • int - System.Int32
  • System.UInt32uint -
  • long - System.Int64
  • System.UInt64ulong -

可以将枚举的特定基础类型定义为短名称或完整类型名称。 以下定义在功能上是相同的。 只有用于基础类型的名称是不同的。

enum LongValueEnum : long {
    Zero
    One
    Two
}
enum LongValueEnum : System.Int64 {
    Zero
    One
    Two
}

设置枚举值的格式

可以通过调用静态 Format 方法以及实例 ToString 方法的重载将枚举值转换为其字符串表示形式。 可以使用格式字符串来控制枚举值表示为字符串的精确方式。 有关详细信息,请参阅 枚举格式字符串

以下示例使用每个受支持的枚举格式字符串(GgDdX或,或xF或)f将 TaskState 枚举的每个成员转换为其字符串表示形式。

enum TaskState {
    ToDo
    Doing
    Done
}

[TaskState].GetEnumValues() | ForEach-Object {
    [pscustomobject]@{
        "ToString('G')" = $_.ToString('G')
        "ToString('D')" = $_.ToString('D')
        "ToString('X')" = $_.ToString('X')
        "ToString('F')" = $_.ToString('F')
    }
}
ToString('G') ToString('D') ToString('X') ToString('F')
------------- ------------- ------------- -------------
ToDo          0             00000000      ToDo
Doing         1             00000001      Doing
Done          2             00000002      Done

以下示例对标志枚举的值使用格式字符串。

[Flags()] enum FlagEnum {
    A = 1
    B = 2
    C = 4
}

$FlagValues = @(
    [FlagEnum]::A                                 # 1
    [FlagEnum]::B                                 # 2
    [FlagEnum]::A + [FlagEnum]::B                 # 3
    [FlagEnum]::C                                 # 4
    [FlagEnum]::C + [FlagEnum]::A                 # 5
    [FlagEnum]::C + [FlagEnum]::B                 # 6
    [FlagEnum]::C + [FlagEnum]::A + [FlagEnum]::B # 7
    [FlagEnum]::C + [FlagEnum]::C                 # 8
)

foreach ($Value in $FlagValues) {
    [pscustomobject]@{
        "ToString('G')" = $Value.ToString('G')
        "ToString('D')" = $Value.ToString('D')
        "ToString('X')" = $Value.ToString('X')
        "ToString('F')" = $Value.ToString('F')
    }
}
ToString('G') ToString('D') ToString('X') ToString('F')
------------- ------------- ------------- -------------
A             1             00000001      A
B             2             00000002      B
A, B          3             00000003      A, B
C             4             00000004      C
A, C          5             00000005      A, C
B, C          6             00000006      B, C
A, B, C       7             00000007      A, B, C
8             8             00000008      8

请注意,对于标志枚举, G 字符串和 F 格式字符串显示用逗号分隔的值的集标志列表。 最后一个值 8不会列出任何标志,因为它实际上不是有效的标志集。 不能合并枚举标志以获取总和 8 ,而无需复制至少一个标志。

使用 Update-TypeData 定义扩展方法

不能在枚举的声明中定义方法。 若要扩展枚举的功能,可以使用 Update-TypeData cmdlet 定义 ScriptMethod 枚举的成员。

以下示例使用 Update-TypeData cmdlet 将方法添加到 GetFlags()FileAttributes 标志枚举。 它返回为值设置的标志的数组。

[Flags()] enum FileAttributes {
    Archive    = 1
    Compressed = 2
    Device     = 4
    Directory  = 8
    Encrypted  = 16
    Hidden     = 32
}

$MemberDefinition = @{
    TypeName   = 'FileAttributes'
    MemberName = 'GetFlags'
    MemberType = 'ScriptMethod'
    Value      = {
        foreach ($Flag in $this.GetType().GetEnumValues()) {
          if ($this.HasFlag($Flag)) { $Flag }
        }
    }
}

Update-TypeData @MemberDefinition

$File = [FileAttributes]28

$File.GetFlags()
Device
Directory
Encrypted

使用类型加速器导出枚举

默认情况下,PowerShell 模块不会自动导出 PowerShell 中定义的类和枚举。 自定义类型在模块外部不可用,无需调用 using module 语句。

但是,如果模块添加类型加速器,则用户导入模块后,这些类型加速器将在会话中立即可用。

注意

向会话添加类型加速器使用内部 API(非公共)API。 使用此 API 可能会导致冲突。 如果导入模块时已存在同名的类型加速器,则下面所述的模式将引发错误。 从会话中删除模块时,它还会删除类型加速器。

此模式可确保类型在会话中可用。 在 VS Code 中创作脚本文件时,它不会影响 IntelliSense 或完成。 若要获取 VS Code 中自定义类型的 IntelliSense 和完成建议,需要将语句添加到 using module 脚本顶部。

以下模式演示如何在模块中将 PowerShell 类和枚举注册为类型加速器。 将代码片段添加到任何类型定义之后的根脚本模块。 请确保变量 $ExportableTypes 包含导入模块时要提供给用户的各种类型。 其他代码不需要任何编辑。

# Define the types to export with type accelerators.
$ExportableTypes =@(
    [DefinedTypeName]
)
# Get the internal TypeAccelerators class to use its static methods.
$TypeAcceleratorsClass = [psobject].Assembly.GetType(
    'System.Management.Automation.TypeAccelerators'
)
# Ensure none of the types would clobber an existing type accelerator.
# If a type accelerator with the same name exists, throw an exception.
$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get
foreach ($Type in $ExportableTypes) {
    if ($Type.FullName -in $ExistingTypeAccelerators.Keys) {
        $Message = @(
            "Unable to register type accelerator '$($Type.FullName)'"
            'Accelerator already exists.'
        ) -join ' - '

        throw [System.Management.Automation.ErrorRecord]::new(
            [System.InvalidOperationException]::new($Message),
            'TypeAcceleratorAlreadyExists',
            [System.Management.Automation.ErrorCategory]::InvalidOperation,
            $Type.FullName
        )
    }
}
# Add type accelerators for every exportable type.
foreach ($Type in $ExportableTypes) {
    $TypeAcceleratorsClass::Add($Type.FullName, $Type)
}
# Remove type accelerators when the module is removed.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    foreach($Type in $ExportableTypes) {
        $TypeAcceleratorsClass::Remove($Type.FullName)
    }
}.GetNewClosure()

当用户导入模块时,添加到会话的类型加速器中的任何类型都立即可用于 IntelliSense 和完成。 删除模块时,类型加速器也是如此。

从 PowerShell 模块手动导入枚举

Import-Module#requires 语句仅导入模块定义的模块函数、别名和变量。 不会导入枚举。

如果模块定义类和枚举,但不为这些类型添加类型加速器,请使用 using module 语句导入它们。

using module 语句从脚本模块或二进制模块的根模块 (ModuleToProcess) 导入类和枚举。 它不会一致地将嵌套模块中定义的类或脚本中定义的类导入到根模块中。 直接在根模块中定义你希望模块外部用户可以使用的类。

有关 using 语句的详细信息,请参阅 about_Using

在开发过程中加载新更改的代码

在脚本模块的开发过程中,通常更改代码,然后使用 Force 参数和 Import-Module 加载新版本的模块。 这仅适用于根模块中函数的更改。 Import-Module 不会重新加载任何嵌套模块。 此外,无法加载任何更新的类。

为确保运行最新版本,必须启动新会话。 无法卸载在 PowerShell 中定义并使用 using 语句导入的类和枚举。

另一种常见的开发做法是将代码分成不同的文件。 如果在一个文件中有使用另一个模块中定义的枚举的函数,则应使用 using module 语句来确保函数具有所需的枚举定义。

限制

  • 不能使用属性修饰 PowerShell 中定义的枚举值。 只能修饰枚举声明本身,就像 使用 FlagsAttribute 将枚举定义为一组位标志一样。

    解决方法:无

  • 不能在枚举定义中定义方法,PowerShell 不支持定义 [扩展方法] 如 C# 。

    解决方法:使用 Update-TypeData cmdlet 定义 ScriptMethod 枚举的成员。