Let's look for scenarios that this code could cover.
Next 143296.ps1 script, using Get-Type
function - Get exported types in the current session
- Exports all types from all namespaces in the current session to
$allTypes
, then
- Selects those with non-empty (pseudo)enumeration to auxiliary Hashtable
$ppp
and $subTypes
.
Script 143296.ps1:
Import-Module -Name Reflection -Force
$allTypes = Get-Type -Force -Namespace * -ErrorAction SilentlyContinue
$allTypes.Count
$ppp=@{} ### auxiliary Hashtable object, could be useful though
$allTypes |
ForEach-Object {
$aux = $_ | Get-EnumValue -AsFlags
if ( $aux.Count -ne 0 ) { $ppp.add( $_.FullName, $_.BaseType) }
}
$ppp.Count
$subTypes = $allTypes | Where-Object { $ppp.ContainsKey($_.FullName)}
$subTypes.Count
$subGrups = $subtypes | Group-Object -Property BaseType
$subGrups.Count
### make public the most frequent items:
$subGrups | Sort-Object -Property Count -Descending | Select-Object -First 15
<# ### another approach to make public results:
$allBases = $ppp.Keys | %{ "{0,15} {1}" -f ($ppp[$_] | Select -ExpandProperty name), $_ } | sort
$allBases.Count
$subBases = $ppp.Keys | %{ ($ppp[$_] | Select -ExpandProperty name)} | sort -Unique
$subBases.Count
#>
Output:
PS D:\PShell> D:\PShell\CR\143296.ps1
12413
2490
2490
182
Count Name Group
----- ---- -----
1710 System.Enum {System.StringSplitOptions, System.StringComparison, System....
201 System.Object {System.String, System.EventArgs, System.BitConverter, Syste...
58 System.ValueType {System.DateTime, System.DateTimeOffset, System.Boolean, Sys...
53 System.Attribute {System.ComponentModel.BindableAttribute, System.ComponentMo...
28 System.Windows.Freezable {System.Windows.Media.Animation.ThicknessKeyFrame, System.Wi...
24 System.Windows.Framewo... {System.Windows.Shapes.Shape, System.Windows.Controls.Panel,...
22 System.Windows.Control... {Microsoft.VisualStudio.Text.Editor.OutliningMarginHeaderCon...
15 System.Windows.Media.A... {System.Windows.TextDecoration, System.Windows.Media.Animati...
11 System.Windows.Control... {System.Windows.Window, System.Windows.Controls.Primitives.B...
9 System.Windows.Depende... {System.Windows.Navigation.JournalEntry, System.Windows.Cont...
8 System.Globalization.C... {System.Globalization.GregorianCalendar, System.Globalizatio...
8 System.Windows.Control... {System.Windows.Controls.Canvas, System.Windows.Controls.Vir...
7 System.Windows.Media.P... {System.Windows.Media.ArcSegment, System.Windows.Media.Bezie...
7 System.Windows.Control... {System.Windows.Controls.Border, System.Windows.Controls.Ink...
7 System.Windows.Media.G... {System.Windows.Media.CombinedGeometry, System.Windows.Media...
The Get-EnumValue
function is explained using Comment-Based Help (CBH):
Set-StrictMode -Version latest
function Get-EnumValue {
<#
.SYNOPSIS
Return names (and values) for an enumeration or enumeration-like object.
.DESCRIPTION
With -AsFlags or no switch: return Ordered Dictionary of names and values
for an enumeration (or enumeration-like) object.
With -NoValues switch: return an array of names for such object.
.PARAMETER Type
Pass in an actual type, or a string for the type name.
.PARAMETER NoValues
If True, then output would be [string[]] array of names;
otherwise, [OrderedDictionary] type type.
If True, then -AsFlags parameter is ignored.
.PARAMETER AsFlags
If True *and* specified <type> is attributed 'FlagsAttribute' (some [Enum] types)
then output values would be hexadecimal-like strings (8+ hexadecimal ciphers);
otherwise, output values would follow <type> type.
Applies only if -NoValues parameter evaluates to False.
.INPUTS
Valid [type], or a string for the type name.
.OUTPUTS
Always returns [OrderedDictionary] or [system.array] object (see switches).
Never outputs Null; returns an empty (.Count -eq 0) object instead.
.NOTES
If -NoValues evaluates to True, then -AsFlags is ignored.
.EXAMPLE
# Enum, flag enumeration (FlagsAttribute present on object supplied)
[System.AttributeTargets]|Get-EnumValue -AsFlags -Verbose
.EXAMPLE
# Enum, value enumeration (no FlagsAttribute on object supplied)
[System.Runtime.InteropServices.VarEnum]|Get-EnumValue -AsFlags -Verbose
.EXAMPLE
# Struct (not Enum)
[System.Double]|Get-EnumValue -Verbose
.EXAMPLE
# Class (not Enum): useful or at least interesting output
[System.Security.Claims.ClaimValueTypes]|Get-EnumValue -AsFlags | ft -a -Wrap
.REMARKS
Based on 'Get-EnumValues' function and used in answer to:
http://codereview.stackexchange.com/questions/143296/getting-enum-values-of-pseudo-enum-classes
Useful related article: 'Get-Type' - Get exported types in the current session
https://gallery.technet.microsoft.com/scriptcenter/Get-Type-Get-exported-fee19cf7
.FUNCTIONALITY
Tested: Windows 8.1/64bit, Powershell 4
#>
[CmdletBinding(PositionalBinding=$false)]
param (
[Parameter(Mandatory,ValueFromPipeline,Position=0)]$Type,
[parameter(Mandatory=$false)][Switch][bool]$NoValues,
[parameter(Mandatory=$false)][Switch][bool]$AsFlags
)
begin {
Function EnumNoEnum ([type]$noEnumClass) {
$enumFlagsHash = [ordered]@{}
$noEnumClass.GetFields() |
Where-Object {$_.IsStatic -and $_.IsPublic} |
Select-Object -ExpandProperty Name |
ForEach-Object {
$enumFlagsHash.ADD( $_, $noEnumClass::$_)
}
return $enumFlagsHash
}
Function EnumFlags ([type]$enumClass, [bool]$enumFlags) {
$enumFlagsHash = [ordered]@{}
[System.Enum]::GetNames($enumClass) |
ForEach-Object {
if ($enumFlags) {
$enumFlagsHash.ADD( $_, "0x{0:x8}" -F $($enumClass::$_.value__))
} else {
$enumFlagsHash.ADD( $_, $($enumClass::$_.value__))
}
}
return $enumFlagsHash
}
}
process {
Try { $Type = [type]$Type} Catch { $Type = $null }
if ( $Type) {
Write-Verbose ("Type: {0}" -f $Type.ToString())
### ToDo: find out $enumFlagsAttribute in a more efficient way
$enumFlagsAttribute = ''
if ($Type.CustomAttributes |
Where-Object {$_.AttributeType.Name -eq 'FlagsAttribute'})
{ $enumFlagsAttribute = 'FlagsAttribute'}
Write-Verbose ("IsEnum? {0,-20} {1}" -f
$Type.IsEnum.ToString(), $enumFlagsAttribute)
if ($Type.IsEnum) {
if (-not $NoValues) {
if ( $AsFlags -and $enumFlagsAttribute) {
# flags enumeration
$TypeOut = . EnumFlags $Type $AsFlags
} else {
# value enumeration
$TypeOut = . EnumFlags $Type $False
}
} else {
$TypeOut = [System.Enum]::GetNames($Type)
}
} else {
# handle pseudo-enums i.e. for cases where this trick's been used
# http://stackoverflow.com/a/15713789/361842
if (-not $NoValues) {
$TypeOut = . EnumNoEnum $Type
} else {
$TypeOut = $Type.GetFields() |
Where-Object {$_.IsStatic -and $_.IsPublic} |
Select-Object -ExpandProperty Name
}
}
if ( $TypeOut ) { $TypeOut } else { ,@() }
} else {
Write-Verbose ("Null or invalid TypeName")
if ( $NoValues ) { ,@() } else { [ordered]@{} }
}
}
}
I think that information about FlagsAttribute
on a particular enum
type could matter (added to verbosed output), see FlagsAttribute
class.
See also the AsFlags
parameter in the above function: it causes that values of the FlagsAttribute
enum have a hexadecimal look (fake, however sometimes useful).