Public/Copy-LMDevicePropertyToDevice.ps1

<#
.SYNOPSIS
    Copies device properties from a source device to target devices. Sensitive properties cannot be copied as their values are not available via API.

.DESCRIPTION
    The Copy-LMDevicePropertyToDevice function copies specified properties from a source device to one or more target devices.
    The source device can be randomly selected from a group or explicitly specified. Properties are copied to the targets while
    preserving other existing device properties.

.PARAMETER SourceDeviceId
    The ID of the source device to copy properties from. This parameter is part of the "SourceDevice" parameter set.

.PARAMETER SourceGroupId
    The ID of the source group to randomly select a device from. This parameter is part of the "SourceGroup" parameter set.

.PARAMETER TargetDeviceId
    The ID of the target device(s) to copy properties to. Multiple device IDs can be specified.

.PARAMETER PropertyNames
    Array of property names to copy. These can be only be custom properties directly assigned to the device.

.PARAMETER PassThru
    If specified, returns the updated device objects.

.EXAMPLE
    Copy-LMDevicePropertyToDevice -SourceDeviceId 123 -TargetDeviceId 456 -PropertyNames "location","department"
    Copies the location and department properties from device 123 to device 456.

.EXAMPLE
    Copy-LMDevicePropertyToDevice -SourceGroupId 789 -TargetDeviceId 456,457 -PropertyNames "location" -PassThru
    Randomly selects a device from group 789 and copies its location property to devices 456 and 457, returning the updated devices.

.NOTES
    Requires an active Logic Monitor session. Use Connect-LMAccount to log in before running this function.
#>

Function Copy-LMDevicePropertyToDevice {
    [CmdletBinding(DefaultParameterSetName="SourceDevice")]
    Param(
        [Parameter(Mandatory,ParameterSetName="SourceDevice",ValueFromPipelineByPropertyName)]
        [String]$SourceDeviceId,

        [Parameter(Mandatory,ParameterSetName="SourceGroup")]
        [String]$SourceGroupId,

        [Parameter(Mandatory)]
        [String[]]$TargetDeviceId,

        [Parameter(Mandatory)]
        [String[]]$PropertyNames,

        [Switch]$PassThru
    )

    Begin {
        If($Script:LMAuth.Valid){}
        Else{
            Write-Error "Please ensure you are logged in before running any commands, use Connect-LMAccount to login and try again."
            return
        }
    }

    Process {
        Try {
            # Get source device either directly or from group
            If($PSCmdlet.ParameterSetName -eq "SourceDevice") {
                $sourceDevice = Get-LMDevice -Id $SourceDeviceId
                If(!$sourceDevice) {
                    Write-Error "Source device with ID $SourceDeviceId not found"
                    return
                }
            }
            Else {
                $devices = Get-LMDeviceGroupDevices -Id $SourceGroupId
                If(!$devices) {
                    Write-Error "No devices found in source group with ID $SourceGroupId"
                    return
                }
                $sourceDevice = $devices | Get-Random
            }

            # Initialize results array if PassThru specified
            $results = New-Object System.Collections.ArrayList

            # Define sensitive patterns
            $sensitivePatterns = @(
                'credential$',
                'password$',
                '\S+\.pass$',
                '\S+\.auth$',
                '\S+\.key$',
                '\S+\.privtoken$',
                '\S+\.authtoken$',
                '\S+\.community$',
                '\S+\.accesskey$',
                '\S+\.secretkey$',
                '\S+\.privatekey$',
                '\S+\.serviceaccountkey$',
                '\S+\.awsaccesskey$',
                '\S+\.awssecretkey$',
                '\S+\.refreshtoken$',
                '\S+\.accesstoken$',
                '\d+\.snmptrap\.community$',
                '\d+\.snmptrap\.privtoken$',
                '\d+\.snmptrap\.authtoken$'
            )

            # Process each target group
            Foreach($deviceId in $TargetDeviceId) {
                $device = Get-LMDevice -Id $deviceId
                If(!$device) {
                    Write-Warning "Target device with ID $deviceId not found, skipping..."
                    continue
                }

                # Build properties hashtable
                $propertiesToCopy = @{}
                Foreach($propName in $PropertyNames) {
                    if ($propName -like 'system.*' -or $propName -like 'auto.*') {
                        Write-Warning "Property $propName is a system or auto property and cannot be set on device groups. Skipping copy."
                        continue
                    }
                    $isSensitive = $false
                    foreach ($pattern in $sensitivePatterns) {
                        if ($propName -match $pattern) {
                            $isSensitive = $true
                            break
                        }
                    }
                    if ($isSensitive) {
                        Write-Warning "Property $propName is a sensitive credential property and its value is masked by the API. Skipping copy."
                        continue
                    }
                    # Check custom properties
                    $propValue = $null
                    If($sourceDevice.customProperties.name -contains $propName) {
                        $propValue = $sourceDevice.customProperties[$sourceDevice.customProperties.name.IndexOf($propName)].value
                    }
                    If($propValue) {
                        $propertiesToCopy[$propName] = $propValue
                    }
                    Else {
                        Write-Warning "Property $propName not found on source device $($sourceDevice.id), skipping..."
                    }
                }

                If($propertiesToCopy.Count -gt 0) {
                    Write-Information "[INFO]: Copying properties to group $($device.name) (ID: $deviceId)"
                    $updatedGroup = Set-LMDevice -Id $deviceId -Properties $propertiesToCopy

                    Write-Information "[INFO]: Added properties to $($device.displayName):"
                    $propertiesToCopy.GetEnumerator() | ForEach-Object {
                        Write-Information (" {0} = {1}" -f $_.Key, $_.Value)
                    }

                    If($PassThru) {
                        $results.Add($updatedGroup) | Out-Null
                    }
                }
            }
        }
        Catch {
            Write-Error "Error copying properties: $_"
        }
    }

    End {
        If($PassThru) {
            Return $results
        }
    }
}