Public/Devices/Set-RMMDeviceUDF.ps1
|
<#
Copyright (c) 2025-2026 Robert Faddes SPDX-License-Identifier: MPL-2.0 #> function Set-RMMDeviceUdf { <# .SYNOPSIS Sets user-defined fields on a device in Datto RMM. .DESCRIPTION The Set-RMMDeviceUdf function updates one or more user-defined fields (Udf1-Udf300) on a device in the Datto RMM system. UDFs are custom fields that can store additional metadata about devices for organisational and reporting purposes. The function supports two modes of operation: - Hashtable mode: Use -UdfFields to update multiple UDFs at once with a hashtable of key-value pairs (e.g., @{udf1='Value1'; udf50='Value50'}). - Single mode: Use -UdfNumber and -UdfValue to update a single UDF by number. Important behaviours: - Fields included in the request with empty values will be cleared (set to null) - Fields not included in the request will retain their current values - You only need to specify the fields you want to update - UDF values are limited to 255 characters .PARAMETER Device A DRMMDevice object to update. Accepts pipeline input from Get-RMMDevice. .PARAMETER DeviceUid The unique identifier (GUID) of the device to update. .PARAMETER UdfFields A hashtable of UDF fields to update. Keys should be in the format 'udf1', 'udf2', etc. Values are limited to 255 characters each. Example: @{udf1='Value1'; udf5='Value5'; udf10=''} Cannot be used with -UdfNumber/-UdfValue parameters. .PARAMETER UdfNumber The UDF number (1-300) to update. Must be used with -UdfValue. Cannot be used with -UdfFields parameter. .PARAMETER UdfValue The value to set for the specified UDF. Limited to 255 characters. Set to empty string to clear the field. Must be used with -UdfNumber. Cannot be used with -UdfFields parameter. .PARAMETER Force Bypasses the confirmation prompt. .EXAMPLE Set-RMMDeviceUdf -DeviceUid "a1b2c3d4-e5f6-7890-abcd-ef1234567890" -UdfNumber 1 -UdfValue "Department: IT" Sets Udf1 on a device, leaving other UDFs unchanged. .EXAMPLE Set-RMMDeviceUdf -DeviceUid $DeviceUid -UdfFields @{udf1='IT Department'; udf2='John Smith'; udf5=''} Updates multiple UDF fields using a hashtable. Udf5 is cleared. .EXAMPLE Set-RMMDeviceUdf -DeviceUid $DeviceUid -UdfNumber 1 -UdfValue '' -Force Clears Udf1 (sets to null) without confirmation. .EXAMPLE Get-RMMDevice -FilterId 100 | Set-RMMDeviceUdf -UdfNumber 3 -UdfValue "Datacenter: East" Updates Udf3 for all devices in filter 100. .EXAMPLE $UDFs = @{udf10='Production'; udf15='Critical'; udf200='Datacenter: West'} PS > Get-RMMDevice -Hostname "SERVER*" | Set-RMMDeviceUdf -UdfFields $UDFs -Force Updates multiple UDF fields on all servers matching the hostname pattern without confirmation. .EXAMPLE Set-RMMDeviceUdf -DeviceUid $DeviceUid -UdfFields @{udf150='Custom Data'; udf275='Extended'} Sets high-numbered UDFs (available since Datto RMM 14.9.0). .INPUTS DRMMDevice. You can pipe device objects from Get-RMMDevice. You can also pipe objects with DeviceUid or Uid properties. .OUTPUTS None. This function does not return any output. .NOTES This function requires an active connection to the Datto RMM API. Use Connect-DattoRMM to authenticate before calling this function. Best practices for UDF usage: - Establish consistent naming conventions across your organisation - Document which UDFs are used for what purpose - Use UDFs for data that doesn't fit standard device properties - Consider using UDFs for: location, department, owner, cost center, project codes, etc. .LINK https://github.com/TheShadowTek/DattoRMM.Core/blob/main/docs/commands/Devices/Set-RMMDeviceUdf.md .LINK Connect-DattoRMM .LINK about_DRMMDevice .LINK Get-RMMDevice .LINK about_DRMMDeviceUdfs #> [CmdletBinding(DefaultParameterSetName = 'ByDeviceUidHashtable', SupportsShouldProcess, ConfirmImpact = 'Medium')] param ( [Parameter( ParameterSetName = 'ByDeviceObjectHashtable', Mandatory = $true, ValueFromPipeline = $true )] [Parameter( ParameterSetName = 'ByDeviceObjectSingle', Mandatory = $true, ValueFromPipeline = $true )] [DRMMDevice] $Device, [Parameter( ParameterSetName = 'ByDeviceUidHashtable', Mandatory = $true )] [Parameter( ParameterSetName = 'ByDeviceUidSingle', Mandatory = $true )] [guid] $DeviceUid, [Parameter( ParameterSetName = 'ByDeviceObjectHashtable', Mandatory = $true )] [Parameter( ParameterSetName = 'ByDeviceUidHashtable', Mandatory = $true )] [hashtable] $UdfFields, [Parameter( ParameterSetName = 'ByDeviceObjectSingle', Mandatory = $true )] [Parameter( ParameterSetName = 'ByDeviceUidSingle', Mandatory = $true )] [ValidateRange(1, 300)] [int] $UdfNumber, [Parameter( ParameterSetName = 'ByDeviceObjectSingle', Mandatory = $true )] [Parameter( ParameterSetName = 'ByDeviceUidSingle', Mandatory = $true )] [ValidateLength(0, 255)] [AllowEmptyString()] [string] $UdfValue, [Parameter()] [switch] $Force ) process { if ($Device) { $DeviceUid = $Device.Uid $DeviceName = $Device.Hostname } else { $DeviceName = "device $DeviceUid" } $Target = "device '$DeviceName' (UID: $DeviceUid)" if (-not $Force -and -not $PSCmdlet.ShouldProcess($Target, "Update user-defined fields")) { return } Write-Debug "Updating UDF fields for device $DeviceUid" # Build request body based on parameter set $Body = @{} if ($PSCmdlet.ParameterSetName -match 'Hashtable') { foreach ($Key in $UdfFields.Keys) { if ($Key -notmatch '^udf(\d{1,3})$') { Write-Error "Invalid UDF key: '$Key'. Keys must be in the format 'udf1' through 'udf300'." return } $Number = [int]$Matches[1] if ($Number -lt 1 -or $Number -gt [DRMMDeviceUdfs]::MaxUdfCount) { Write-Error "Invalid UDF key: '$Key'. UDF number must be between 1 and $([DRMMDeviceUdfs]::MaxUdfCount)." return } $Value = $UdfFields[$Key] if ($null -ne $Value -and $Value.Length -gt 255) { Write-Error "UDF value for '$Key' exceeds 255 characters ($($Value.Length) characters)." return } $Body[$Key.ToLower()] = $Value } } else { $Body["udf$UdfNumber"] = $UdfValue } if ($Body.Count -eq 0) { Write-Warning "No UDF fields were specified for update." return } Write-Verbose "Setting $($Body.Count) UDF field(s) on $Target" $ApiMethodParams = @{ Path = "device/$DeviceUid/udf" Method = 'Post' Body = $Body } Invoke-ApiMethod @ApiMethodParams | Out-Null } } # SIG # Begin signature block # MIIF+wYJKoZIhvcNAQcCoIIF7DCCBegCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAGF5FdsUEdtaSC # hMV3p9+zo1K7/F8+X2kZSRDPd6jBdKCCA04wggNKMIICMqADAgECAhB464iXHfI6 # gksEkDDTyrNsMA0GCSqGSIb3DQEBCwUAMD0xFjAUBgNVBAoMDVJvYmVydCBGYWRk # ZXMxIzAhBgNVBAMMGkRhdHRvUk1NLkNvcmUgQ29kZSBTaWduaW5nMB4XDTI2MDMz # MTAwMTMzMFoXDTI4MDMzMTAwMjMzMFowPTEWMBQGA1UECgwNUm9iZXJ0IEZhZGRl # czEjMCEGA1UEAwwaRGF0dG9STU0uQ29yZSBDb2RlIFNpZ25pbmcwggEiMA0GCSqG # SIb3DQEBAQUAA4IBDwAwggEKAoIBAQChn1EpMYQgl1RgWzQj2+wp2mvdfb3UsaBS # nxEVGoQ0gj96tJ2MHAF7zsITdUjwaflKS1vE6wAlOg5EI1V79tJCMxzM0bFpOdR1 # L5F2HE/ovIAKNkHxFUF5qWU8vVeAsOViFQ4yhHpzLen0WLF6vhmc9eH23dLQy5fy # tELZQEc2WbQFa4HMAitP/P9kHAu6CUx5s4woLIOyyR06jkr3l9vk0sxcbCxx7+dF # RrsSLyPYPH+bUAB8+a0hs+6qCeteBuUfLvGzpMhpzKAsY82WZ3Rd9X38i32dYj+y # dYx+nx+UEMDLjDJrZgnVa8as4RojqVLcEns5yb/XTjLxDc58VatdAgMBAAGjRjBE # MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU # H+B0vf97dYXqdUX1YMcWhFsY6fcwDQYJKoZIhvcNAQELBQADggEBAJmD4EEGNmcD # 1JtFoRGxuLJaTHxDwBsjqcRQRE1VPZNGaiwIm8oSQdHVjQg0oIyK7SEb02cs6n6Y # NZbwf7B7WZJ4aKYbcoLug1k1x9SoqwBmfElECeJTKXf6dkRRNmrAodpGCixR4wMH # KXqwqP5F+5j7bdnQPiIVXuMesxc4tktz362ysph1bqKjDQSCBpwi0glEIH7bv5Ms # Ey9Gl3fe+vYC5W06d2LYVebEfm9+7766hsOgpdDVgdtnN+e6uwIJjG/6PTG6TMDP # y+pr5K6LyUVYJYcWWUTZRBqqwBHiLGekPbxrjEVfxUY32Pq4QfLzUH5hhUCAk4HN # XpF9pOzFLMUxggIDMIIB/wIBATBRMD0xFjAUBgNVBAoMDVJvYmVydCBGYWRkZXMx # IzAhBgNVBAMMGkRhdHRvUk1NLkNvcmUgQ29kZSBTaWduaW5nAhB464iXHfI6gksE # kDDTyrNsMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKEC # gAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwG # CisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOLIPg52JXrH9P8AENxe+IB1NPQN # uU5olWnSrldEaufaMA0GCSqGSIb3DQEBAQUABIIBAKEN+pkF3jDVj33rxCBDZZpb # XV/v3fyEXNcoRZy0dPlwRyDVywIzpF1ZZCb4KljgaIKD4FXay0hxfyvlR2jLdRqM # d2u6ng1cw8+S2U/EhB7ZAIkXax9EtNyxhxN5r4AhB4Yna9ZaK419w7fSzbWLYRDo # jBCEKNQjKmpdQW1C7cyf8RqbxgkHuiMbe0Pu7MrAy6m/anja/OBFEZ/yUve7SFGX # D+mwhq+fbYFZmsHAp2DYU+lI0iP3+BdojCK0WMvHtkHI0O60Fu5pGjBm1wjgM+ir # rZhrTr+vcwW4VpXvsL4DDNovMynyxW4miI+uZ0cW6Ft4fXNpMQwrMIhh8XOxJIM= # SIG # End signature block |