Public/Variables/New-RMMVariable.ps1
|
<#
Copyright (c) 2025-2026 Robert Faddes SPDX-License-Identifier: MPL-2.0 #> function New-RMMVariable { <# .SYNOPSIS Creates a new variable in the Datto RMM account or site. .DESCRIPTION The New-RMMVariable function creates a new variable at either the account (global) level or at a specific site level. Variables can store configuration data that can be referenced in scripts and automation. Variables can optionally be masked to hide sensitive values in the Datto RMM UI. .PARAMETER Site A DRMMSite object to create the variable in. Accepts pipeline input from Get-RMMSite. .PARAMETER SiteUid The unique identifier (GUID) of a site to create the variable in. .PARAMETER Name The name of the variable to create. .PARAMETER Value The value to assign to the variable. Accepts both string and SecureString. When a SecureString is provided: - The value is securely converted for the API call - Plaintext is cleared from memory immediately after use - The variable is NOT automatically masked (use -Masked if desired) .PARAMETER Masked Whether the variable value should be masked (hidden) in the Datto RMM UI. Use this for sensitive values like passwords or API keys. This must be explicitly specified and is independent of whether you use SecureString. .PARAMETER Force Bypasses the confirmation prompt. .EXAMPLE New-RMMVariable -Name "CompanyName" -Value "Contoso Ltd" Creates an account-level variable named "CompanyName". .EXAMPLE New-RMMVariable -Name "APIKey" -Value "secret123" -Masked Creates a masked account-level variable for sensitive data. .EXAMPLE $Secret = Read-Host -AsSecureString -Prompt "Enter API Key" PS > New-RMMVariable -Name "APIKey" -Value $Secret -Masked Creates a masked variable using SecureString for secure input and transport. .EXAMPLE Get-RMMSite -SiteName "Main Office" | New-RMMVariable -Name "SiteCode" -Value "MO001" Creates a site-level variable via pipeline. .EXAMPLE New-RMMVariable -SiteUid "a1b2c3d4-e5f6-7890-abcd-ef1234567890" -Name "BackupPath" -Value "\\server\backup" Creates a site-level variable by specifying the site UID. .INPUTS DRMMSite. You can pipe site objects from Get-RMMSite. You can also pipe objects with SiteUid or Uid properties. .OUTPUTS DRMMVariable. Returns the newly created variable object (fetched via Get-RMMVariable). .NOTES This function requires an active connection to the Datto RMM API. Use Connect-DattoRMM to authenticate before calling this function. Variable names must be unique within their scope (account or site). The Masked property can only be set during creation and cannot be changed later. API Behaviour: The Datto API does not return the created variable object, so this function fetches it using Get-RMMVariable by name. .LINK https://github.com/TheShadowTek/DattoRMM.Core/blob/main/docs/commands/Variables/New-RMMVariable.md .LINK Connect-DattoRMM .LINK Get-RMMVariable .LINK Set-RMMVariable .LINK Remove-RMMVariable .LINK Get-RMMSite #> [CmdletBinding(DefaultParameterSetName = 'Global', SupportsShouldProcess, ConfirmImpact = 'High')] param ( [Parameter( ParameterSetName = 'BySiteObject', Mandatory = $true, ValueFromPipeline = $true )] [DRMMSite] $Site, [Parameter( ParameterSetName = 'BySiteUid', Mandatory = $true )] [Alias('Uid')] [guid] $SiteUid, [Parameter(Mandatory = $true)] [string] $Name, [Parameter()] [object] $Value, [Parameter()] [switch] $Masked, [Parameter()] [switch] $Force ) process { if ($Site) { $SiteUid = $Site.Uid } $Scope = if ($PSCmdlet.ParameterSetName -match 'Site') {'Site'} else {'Global'} $Target = if ($Scope -eq 'Site') {"site $SiteUid"} else {"account"} if (-not $PSCmdlet.ShouldProcess($Target, "Create variable '$Name'") -and -not $Force) { return } Write-Debug "Creating new RMM variable '$Name' at $Scope scope" # Handle SecureString value conversion $PlainValue = $null if ($PSBoundParameters.ContainsKey('Value')) { if ($Value -is [SecureString]) { $PlainValue = ConvertFrom-SecureStringToPlaintext -SecureString $Value Write-Verbose "SecureString detected - converting securely for API call" } else { $PlainValue = $Value } } # Build request body $Body = @{} switch ($PSBoundParameters.Keys) { 'Name' { $Body.name = $Name } 'Value' { $Body.value = $PlainValue } 'Masked' { $Body.masked = $true } } # Determine API path based on scope $Path = if ($Scope -eq 'Site') { "site/$SiteUid/variable" } else { 'account/variable' } $APIMethod = @{ Path = $Path Method = 'Put' Body = $Body } # Invoke-ApiMethod does not throw on 400 errors by default, so use try/catch, throw on warnings try { Invoke-ApiMethod @APIMethod -WarningAction Stop | Out-Null } catch { Write-Warning "Failed to create variable '$Name' at $Scope scope.$(if ($Scope -eq 'Site') {" Site UID: $SiteUid."})" return } # API doesn't return the created variable, so fetch it by name $GetParams = @{ Name = $Name } if ($Scope -eq 'Site') { $GetParams.SiteUid = $SiteUid } Get-RMMVariable @GetParams } end { # Clear plaintext value from memory $PlainValue = $null } } # SIG # Begin signature block # MIIF+wYJKoZIhvcNAQcCoIIF7DCCBegCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDY/h92wmxY8Phv # Hf9Fh24M9KScAvJXWocEZFIwwHyCz6CCA04wggNKMIICMqADAgECAhB464iXHfI6 # 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 # CisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIM4ODiT+9cixV3cvMG7INEgkfSII # seOnCVhVydRKgo39MA0GCSqGSIb3DQEBAQUABIIBACmWNfKuCGQComF4iyLpcbGs # cYwziHc7dyFVSF0Fe5hSXMdjZWMoxz5qTj2LfJT1qtPmHjL9eEE0AaJFI5la4hRy # dqzobJhdgeuhQAOEYlkGM67EZe8ctn/aIUPQbTTPggE7BgvCpndk8fxK7ej4V+qN # FZa/cuNBAWfJ7CaT5cyncZ9xzrDQFrftkZzdhiIoMdoX82Fw2UfGxXj9mEtWScKs # iEW2PD5zmj7W3Z6o4ocHxLny1E87xvZEyD85DxUS/L8yZNgaBUDABUB5kc8Nz62E # e8W3qQDkz50HUDat6euk5kaE+hm6DZNt0Oi/Gfhgnqzm8f7+q84gqhkiu8UQ8BE= # SIG # End signature block |