New-ADOField.ps1
function New-ADOField { <# .Synopsis Creates new fields in Azure DevOps .Description Creates new work item fields in Azure DevOps or Team Foundation Server. .Example New-ADOField -Name Verb -ReferenceName Cmdlet.Verb -Description "The PowerShell Verb" -ValidValue (Get-Verb | Select-Object -ExpandProperty Verb | Sort-Object) -Organization MyOrganization .Example New-ADOField -Name IsDCR -Type Boolean -Description "Is this a direct custom request?" -Organization MyOrganization .Notes .Link Invoke-ADORestAPI #> [CmdletBinding(SupportsShouldProcess=$true)] [OutputType('PSDevOps.Field')] param( # The friendly name of the field [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('FriendlyName', 'DisplayName')] [string] $Name, # The reference name of the field. This is the name used in queries. # If not provided, the ReferenceName will Custom. + -Name (stripped of whitespace) [Parameter(ValueFromPipelineByPropertyName)] [Alias('SystemName')] [string] $ReferenceName, <# The type of the field. This can be any of the following: * boolean * dateTime * double * guid * history * html * identity * integer * plainText * string * treePath #> [Parameter(ValueFromPipelineByPropertyName)] [Alias('FieldType')] [ValidateSet('boolean','dateTime', 'double','guid', 'history','html','identity','integer', 'picklistDouble','picklistInteger','picklistString', 'plainText','string','treePath')] [string] $Type = 'string', # A description for the field. [Parameter(ValueFromPipelineByPropertyName)] [string] $Description, # A list of valid values. # If provided, an associated picklist will be created with these values. [Parameter(ValueFromPipelineByPropertyName)] [Alias('ValidValues','Picklist')] [string[]] $ValidValue, # If set, the field can be used to sort. [Parameter(ValueFromPipelineByPropertyName)] [switch] $CanSortBy, # If set, the field can be used in queries. [Parameter(ValueFromPipelineByPropertyName)] [switch] $IsQueryable, # If set, the field will be read only. [Parameter(ValueFromPipelineByPropertyName)] [switch] $ReadOnly, # If set, custom values can be provided into the field. # This is ignored if not used with -ValidValue. [Parameter(ValueFromPipelineByPropertyName)] [Alias('IsPickListSuggestable','OpenEnded')] [switch] $AllowCustomValue, # The Organization [Parameter(Mandatory,ValueFromPipelineByPropertyName)] [Alias('Org')] [string] $Organization, # The Project [Parameter(ValueFromPipelineByPropertyName)] [string] $Project, # The server. By default https://dev.azure.com/. # To use against TFS, provide the tfs server URL (e.g. http://tfsserver:8080/tfs). [Parameter(ValueFromPipelineByPropertyName)] [uri] $Server = "https://dev.azure.com/", # The api version. By default, 5.1. # If targeting TFS, this will need to change to match your server version. # See: https://docs.microsoft.com/en-us/azure/devops/integrate/concepts/rest-api-versioning?view=azure-devops [string] $ApiVersion = "5.1-preview") dynamicParam { . $GetInvokeParameters -DynamicParameter } begin { #region Copy Invoke-ADORestAPI parameters $invokeParams = . $getInvokeParameters $PSBoundParameters #endregion Copy Invoke-ADORestAPI parameters $validFieldTypes = foreach ($_ in $MyInvocation.MyCommand.Parameters['Type'].Attributes) { if ($_.ValidValues) { $_.ValidValues;break } } } process { $uriBase = "$Server".TrimEnd('/'), $Organization, $Project -join '/' $uri = $uriBase, "_apis/wit/fields?" -join '/' if ($Server -ne 'https://dev.azure.com/' -and -not $PSBoundParameters.ApiVersion) { $ApiVersion = '2.0' } $uri += if ($ApiVersion) { "api-version=$ApiVersion" } $postContent = [Ordered]@{} $postContent.name = $Name $postContent.referenceName = if ($ReferenceName) { $ReferenceName } else { "Custom." + $Name -replace '\s','' } for ($i =0; $i -lt $validFieldTypes.Length; $i++) { if ($validFieldTypes[$i] -ieq $type) { $type = $validFieldTypes[$i] } } $postContent.type = $type $postContent.readOnly = $readOnly -as [bool] $postContent.canSortBy = $canSortBy -as [bool] $postContent.isQueryable = $isQueryable -as [bool] $postContent.isIdentity = $type -eq 'identity' $postContent.description = $Description if ($ValidValue) { if ($type -notlike 'picklist*' -and $Type -ne 'string' -and $type -ne 'integer' -and $type -ne 'double') { Write-Error "Can only provide a list of valid values fields of type string, integer, or double" return } $postContent.isPicklist = $true $pickListCreate = [Ordered]@{ id = $null name = "$($postContent.ReferenceName)_$([GUID]::NewGuid())" -replace '-','' -replace '\.','' type = if ($type -like 'picklist*') { $validFieldTypes[$validFieldTypes.IndexOf($Type)] } else { $validFieldTypes[$validFieldTypes.IndexOf($Type)] } } $pickListCreate.type= $pickListCreate.type.Substring(0,1).ToUpper() + $pickListCreate.type.Substring(1) $pickListCreate.items = @(if ($type -match 'string') { $ValidValue } else { $ValidValue -as [double[]] }) if (-not $pickListCreate.items) { $pickListCreate.items = @('') } $picklistCreateUri = "$Server".TrimEnd('/'), $Organization, '_apis/work/processes/lists?' -join '/' if ($ApiVersion) { $picklistCreateUri += "api-version=$ApiVersion" } if ($WhatIfPreference) { $whatIfOut = @{} + $invokeParams + @{ Uri = $picklistCreateUri Method = 'POST' Body = $pickListCreate } $whatIfOut } elseif ($PSCmdlet.ShouldProcess("Create Picklist with $ValidValue")) { $createdPickList = Invoke-ADORestAPI @invokeParams -Uri $picklistCreateUri -Method POST -Body $pickListCreate $postContent.picklistId = $createdPickList.id $postContent.isPicklistSuggest = $AllowCustomValue -as [bool] } } $invokeParams.Uri = $uri $invokeParams.Body = $postContent $invokeParams.Method = 'POST' if ($WhatIfPreference) { $invokeParams.Remove('PersonalAccesstoken') $invokeParams return } if (-not $PSCmdlet.ShouldProcess("POST $uri with $($invokeParams.body)")) { return } Invoke-ADORestAPI @invokeParams -PSTypeName @( if ($Project) { "$Organization.$project.Field" } "$Organization.Field" "PSDevOps.Field" ) -Property @{ Organization = $Organization Project = $Project Server = $Server } } } |