about_Enum

简短说明

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

详细说明

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

枚举在内部表示为整数值类型,起始值为零。 默认情况下,PowerShell 枚举使用 System.Int32[int]) 作为基础类型。 默认情况下,PowerShell 在列表中分配值零的第一个标签。 默认情况下,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的基础值。 显式赋值后的标签将立即获得下一个整数值。 可以通过将相同的值分配给另一个标签来创建同义词;请参阅以下对象的构造值:oggogamoggjpgjpegmpgmpeg

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() 的输出仅显示 oggjpgjpegmpg也发生了同样的事情,mpeg。 同义词值的名称 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

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

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

还可以使用 HasFlag() 方法测试是否设置了特定标志。 此示例测试 设备隐藏 属性的值 $file1

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. 定义一个名为 <type>Enum的枚举,如 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() 静态方法返回给定枚举类型、枚举值和格式字符串的格式化字符串输出。 输出与对具有指定格式字符串的值调用 ToString 方法相同。

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

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

有效的格式字符串 GgDdXx,以及 Ff。 有关详细信息,请参阅 枚举格式字符串

以下示例使用每个受支持的枚举格式字符串将 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() 静态方法返回 $true,否则 $false。 使用此方法检查某个值是否对枚举有效,而无需处理无效的参数错误。

可以在 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>])

以下示例将 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

枚举值同义词

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

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

以下代码块将 着色 枚举定义为同义词 GreyGray

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 系统
  • ushort - System.UInt16
  • int - System.Int32 系统
  • uint - System.UInt32 系统
  • long - System.Int64 系统
  • ulong - System.UInt64 系统

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

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

设置枚举值的格式

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

以下示例使用每个受支持的枚举格式字符串(GgDdXx,以及 Ff)将 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

请注意,对于标志枚举,GF 格式字符串显示用逗号分隔的值的设置标志列表。 最后一个值(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

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

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

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

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

局限性

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

    解决方法:无

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

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