Private/ConvertTo-TogglObject.ps1

function ConvertTo-TogglObject {
    [CmdletBinding()]
    param(
        # A PSCustomObject to convert
        [Parameter( Mandatory = $true, Position = 0, ValueFromPipeline = $true )]
        [PSObject[]]
        $InputObject, <#Alias?#>

        # The field configuration
        [Parameter(Mandatory = $true)]
        [System.Collections.Hashtable]
        $ObjectConfig
    )

    begin {
        New-Item function::local:Write-Verbose -Value (
            New-Module -ScriptBlock { param($verb, $fixedName, $verbose) } -ArgumentList @((Get-Command Write-Verbose), $PSCmdlet.MyInvocation.InvocationName, $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent)
        ).NewBoundScriptBlock{
            param($Message)
            if ($verbose) {
                & $verb -Message "=>$fixedName $Message" -Verbose
            }
            else {
                & $verb -Message "=>$fixedName $Message"
            }
        } | Write-Verbose
    }

    ##
    ## TODO TESTS
    ##
    process {
        foreach ($item in $InputObject) {
            Write-Verbose "Processing item: $($item | ConvertTo-Json -Compress)..."
            $item | Write-Verbose
            #todo if item is empty???
            $object = @{}
            if ($item.GetType().Name -eq "HashTable") {
                write-Verbose "`$item is of type HashTable"
                $element = New-Object -TypeName psobject -Property $item
            }
            else {
                Write-Verbose "`$item is of type $($item.GetType().Name)"
                $element = $item
            }

            foreach ($field in $ObjectConfig.Fields) {
                Write-Verbose "Processing field `"$($field.name)`""
                $inputField = $element.PSObject.Members[$field.name].Value
                if ($null -ne $inputField) {
                    $object[$field.name] = $inputField -as $field.type
                }
                else {
                    if ($null -ne $field.default) {
                        Write-Verbose "Defaulting null-valued field"
                        $object[$field.name] = $field.default -as $field.type
                    }
                    elseif ($field.required) {
                        throw "Property `"$($field.name)`" is required"
                    }
                }
                Write-Verbose "Value: `"$inputField`""
            }

            $result = New-Object -TypeName psobject -Property $object
            Write-Verbose "Inserting TypeName `"$($ObjectConfig.TypeName)`""
            $result.PSObject.TypeNames.Insert(0, $ObjectConfig.TypeName)
            <#
            IMHO this is a really great idea for dynamic configs. Unfortunately code in psd1 is not allowed.
            //TODO: Create an Issue and let's see if someone has an idea
            foreach ($validator in $objectConfig.Validators) {
                if (-not $validator.callback.invoke($result)) {
                    Write-Debug ($validator.name + " returned false. Throwing ArgumentException with message: " + $validator.message)
                    Throw [System.ArgumentException]::new("Error validating fields: " + $validator.message)
                }
            }
            #>

            Write-Output $result
        }
    }
}