Search code examples
powershellenumstypeconverter

How to create a Converter for an Enum


How to create (preferably in PowerShell) a type converter for a custom PowerShell [enum]?

Related PowerShell issue: enum <enum-name> should ConvertFrom [string]

Based on the specific [Access] example in question How to define a type of a bit-combination?:

[Flags()] enum Access {
    Execute = 1
    Write = 2
    Read = 4
}

I am trying to build an [Access] ConvertFrom converter:

class AccessConverter : System.Management.Automation.PSTypeConverter
{
    [bool] CanConvertFrom([object]$sourceValue, [Type]$destinationType) {
        return $sourceValue -eq [string]
    }
    [object] ConvertFrom([object]$sourceValue, [Type]$destinationType, [IFormatProvider]$formatProvider, [bool]$ignoreCase) {
        if     ($sourceValue -eq [string]) { return [Access]$SourceValue }
        else { throw [NotImplementedException]::new() }
    }
    [bool] CanConvertTo([object]$sourceValue, [Type]$destinationType) {
        return $false
    }
    [object] ConvertTo([object]$sourceValue, [Type]$destinationType, [IFormatProvider]$formatProvider, [bool]$ignoreCase) {
        throw [NotImplementedException]::new() 
    }
}

Update-TypeData -TypeName Access -TypeConverter AccessConverter

But that doesn't work as expected:

$Access.HasFlag('read, write')

MethodException: Cannot convert argument "flag", with value: "read, write", for "HasFlag" to type "System.Enum": "Cannot convert value "read, write" to type "System.Enum". Error: "Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.""

Or is that because HasFlag expects a general enumType type rather then the specific custom ("access") enum?


Solution

  • Not sure if this would work with a PSTypeConverter or if it even relates, what you're looking to accomplish, as I see it, can be achieved by overriding the .HasFlag method from your enum with a script method that casts your type:

    [Flags()] enum Access {
        Execute = 1
        Write = 2
        Read = 4
    }
    
    $updateTypeDataSplat = @{
        TypeName   = 'Access'
        MemberType = 'ScriptMethod'
        MemberName = 'HasFlag'
        Value      = {
            param([Access] $flag)
    
            $this.PSBase.HasFlag($flag)
        }
    }
    
    Update-TypeData @updateTypeDataSplat
    
    $access = [Access] 'Execute, Read'
    $access.HasFlag('Execute, Read')         # true
    $access.HasFlag('Execute, Write, Read')  # false