public/New-VSACustomField.ps1

function New-VSACustomField {
    <#
    .Synopsis
       Creates a custom field.
    .DESCRIPTION
       Creates a custom field of given type.
       Takes either persistent or non-persistent connection information.
    .PARAMETER VSAConnection
        Specifies existing non-persistent VSAConnection.
    .PARAMETER URISuffix
        Specifies URI suffix if it differs from the default.
    .PARAMETER FieldName
        Custom field's name.
    .PARAMETER FieldType
        New Field Type: "string", "number", "datetime", "date", "time".
    .EXAMPLE
       New-VSACustomField -FieldName 'MyField'
    .EXAMPLE
       New-VSACustomField -FieldName 'MyField' -FieldType datetime
    .INPUTS
       Accepts piped non-persistent VSAConnection
    .OUTPUTS
       True if creation was successful
    .NOTES
        Version 1.0.0
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param (
        [parameter(Mandatory = $false, 
            ValueFromPipelineByPropertyName = $true)]
        [VSAConnection] $VSAConnection,

        [parameter(DontShow, Mandatory=$false)]
        [ValidateNotNullOrEmpty()]
        [string] $URISuffix = 'api/v1.0/assetmgmt/assets/customfields',

        [Alias("Name")]
        [parameter(Mandatory=$true,
            ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()] 
        [string] $FieldName,

        [Alias("Type")]
        [parameter(Mandatory=$false,
            ValueFromPipelineByPropertyName=$true)]
        [ValidateSet("string", "number", "datetime", "date", "time")]
        [string]$FieldType = 'string'
        )
    process {

    # The previous body was a hand-rolled here-string with unescaped {0}/{1} substitutions and a
    # trailing comma before the closing ']' (invalid JSON per RFC 8259) (F-40). ConvertTo-Json
    # produces valid, correctly escaped JSON.
    $Body = ConvertTo-Json @(
        @{ key = 'FieldName'; value = $FieldName }
        @{ key = 'FieldType'; value = $FieldType }
    ) -Compress

    [hashtable]$Params = @{
        VSAConnection  = $VSAConnection
        URISuffix      = $URISuffix
        Method         = 'POST'
        Body           = $Body
    }

    #Remove empty keys
    foreach ( $key in @($Params.Keys) ) {
        if ( -not $Params[$key] )  { $Params.Remove($key) }
    }

    # No collection-wide existence pre-check (F-38): a duplicate FieldName now surfaces as the
    # API's own 4xx error (via the transport's improved error handling) instead of a second,
    # wasteful GET-the-whole-collection call before every creation.
    return Invoke-VSARestMethod @Params
    }
}
New-Alias -Name Add-VSACustomField -Value New-VSACustomField
Export-ModuleMember -Function New-VSACustomField -Alias Add-VSACustomField