Public/Invoke-LMDeviceDedupe.ps1
<# .SYNOPSIS List and/or remove duplicte devices from a portal based on a specified device group and set of exclusion criteria. .DESCRIPTION List and/or remove duplicte devices from a portal based on a specified device group and set of exclusion criteria. .EXAMPLE Invoke-LMDeviceDedupe -ListDuplicates -DeviceGroupId 8 .NOTES Additional arrays can be specified to exclude certain IPs, sysname and devicetypes from being used for duplicate comparison .INPUTS None. Does not accept pipeline input. #> function Invoke-LMDeviceDedupe { [CmdletBinding()] param ( [Parameter(ParameterSetName = 'List', Mandatory)] [Switch]$ListDuplicates, [Parameter(ParameterSetName = 'Remove', Mandatory)] [Switch]$RemoveDuplicates, [String]$DeviceGroupId, [String[]]$IpExclusionList, [String[]]$SysNameExclusionList, [String[]]$ExcludeDeviceType = @(8) #Exclude K8s resources by default ) #Check if we are logged in and have valid api creds begin {} process { if ($Script:LMAuth.Valid) { $DeviceList = @() $IpExclusionList += @("127.0.0.1", "::1") $SysNameExclusionList += @("(none)", "N/A", "none", "blank", "empty", "") if ($DeviceGroupId) { $DeviceList = Get-LMDeviceGroupDevice -Id $DeviceGroupId } else { $DeviceList = Get-LMDevice } #Remove excluded device types $DeviceList = $DeviceList | Where-Object { $ExcludeDeviceType -notcontains $_.deviceType } if ($DeviceList) { $OrganizedDevicesList = @() $DuplicateSysNameList = @() $RemainingDeviceList = @() $OutputList = @() #Loop through list and compare sysname, hostname and ips foreach ($Device in $DeviceList) { $IpList = $null $IpListIndex = $Device.systemProperties.name.IndexOf("system.ips") if ($IpListIndex -ne -1) { $IpList = $Device.systemProperties[$IpListIndex].value } $SysName = $null $SysNameIndex = $Device.systemProperties.name.IndexOf("system.sysname") if ($SysNameIndex -ne -1) { $SysName = $Device.systemProperties[$SysNameIndex].value.tolower() } $HostName = $null $HostNameIndex = $Device.systemProperties.name.IndexOf("system.hostname") if ($HostNameIndex -ne -1) { $HostName = $Device.systemProperties[$HostNameIndex].value.tolower() } $OrganizedDevicesList += [PSCustomObject]@{ ipList = $IpList sysName = $SysName hostName = $HostName displayName = $Device.displayName deviceId = $Device.id currentCollectorId = $Device.currentCollectorId createdOnEpoch = $Device.createdOn createdOnDate = (Get-Date 01.01.1970) + ([System.TimeSpan]::fromseconds($($Device.createdOn))) } } #Remove items that are missing system.ips and system.sysname $OrganizedDevicesList = $OrganizedDevicesList | Where-Object { -not [string]::IsNullOrWhiteSpace($_.ipList) -or -not [string]::IsNullOrWhiteSpace($_.sysName) } #group devices with matching sysname values $DuplicateSysNameList = $OrganizedDevicesList | Group-Object -Property sysname | Sort-Object Count -Unique -Descending | Where-Object { $_.Count -gt 1 -and $SysNameExclusionList -notcontains $_.Name } #Group remaining devices into array so we can process for duplicate ips $RemainingDeviceList = ($OrganizedDevicesList | Group-Object -Property sysname | Sort-Object Count -Unique -Descending | Where-Object { $_.Count -eq 1 -or $SysNameExclusionList -contains $_.Name }).Group #Loop through each group and add duplicates to our list foreach ($Group in $DuplicateSysNameList) { #Get the oldest device out of the group and mark as original device to keep around $OriginalDeviceEpochIndex = $Group.Group.createdOnEpoch.IndexOf($($Group.Group.createdOnEpoch | Sort-Object -Descending | Select-Object -Last 1)) $OriginalDevice = $Group.Group[$OriginalDeviceEpochIndex] foreach ($Device in $Group.Group) { if ($Device.deviceId -ne $OriginalDevice.deviceId) { $OutputList += [PSCustomObject]@{ duplicate_deviceId = $Device.deviceId duplicate_sysName = $Device.sysName duplicate_hostName = $Device.hostName duplicate_displayName = $Device.displayName duplicate_currentCollectorId = $Device.currentCollectorId duplicate_createdOnEpoch = $Device.createdOnEpoch duplicate_createdOnDate = $Device.createdOnDate duplicate_ipList = $Device.ipList original_deviceId = $OriginalDevice.deviceId original_sysName = $OriginalDevice.sysName original_hostName = $OriginalDevice.hostName original_displayName = $OriginalDevice.displayName original_currentCollectorId = $OriginalDevice.currentCollectorId original_createdOnEpoch = $OriginalDevice.createdOnEpoch original_createdOnDate = $OriginalDevice.createdOnDate original_ipList = $OriginalDevice.ipList duplicate_reason = "device is considered a duplicate for having a matching sysname value of $($Device.sysName) with $($Group.Count) devices" } } } } $DuplicateIPDeviceList = @() $DuplicateIPDeviceGroupList = @() #Find duplicate ips for use to locate $DuplicateIPList = @() $DuplicateIPList = ($RemainingDeviceList.iplist.split(",") | Group-Object | Where-Object { $_.Count -gt 1 -and $IpExclusionList -notcontains $_.Name }).Group | Select-Object -Unique if ($DuplicateIPList) { foreach ($Device in $RemainingDeviceList) { #TODO process system.ips list for dupes if assigned to same collector id $DuplicateCheckResult = @() $DuplicateCheckResult = Compare-Object -ReferenceObject $DuplicateIpList -DifferenceObject $($Device.ipList).split(",") -IncludeEqual -ExcludeDifferent -PassThru if ($DuplicateCheckResult) { $DuplicateIPDeviceList += [PSCustomObject]@{ deviceId = $Device.deviceId ipList = $Device.ipList sysName = $Device.sysName hostName = $Device.hostName displayName = $Device.displayName currentCollectorId = $Device.currentCollectorId createdOnEpoch = $Device.createdOnEpoch createdOnDate = $Device.createdOnDate duplicate_ips = $DuplicateCheckResult -join "," } } } } #Group devices with the same duplicate IPs so we can add them to our group $DuplicateIPDeviceGroupList = $DuplicateIPDeviceList | Group-Object -Property duplicate_ips | Sort-Object Count -Unique -Descending | Where-Object { $_.count -gt 1 } foreach ($Group in $DuplicateIPDeviceGroupList) { #Get the oldest device out of the group and mark as original device to keep around $OriginalDeviceEpochIndex = $Group.Group.createdOnEpoch.IndexOf($($Group.Group.createdOnEpoch | Sort-Object -Descending | Select-Object -Last 1)) $OriginalDevice = $Group.Group[$OriginalDeviceEpochIndex] foreach ($Device in $Group.Group) { if ($Device.deviceId -ne $OriginalDevice.deviceId) { $OutputList += [PSCustomObject]@{ duplicate_deviceId = $Device.deviceId duplicate_sysName = $Device.sysName duplicate_hostName = $Device.hostName duplicate_displayName = $Device.displayName duplicate_currentCollectorId = $Device.currentCollectorId duplicate_createdOnEpoch = $Device.createdOnEpoch duplicate_createdOnDate = $Device.createdOnDate duplicate_ipList = $Device.ipList original_deviceId = $OriginalDevice.deviceId original_sysName = $OriginalDevice.sysName original_hostName = $OriginalDevice.hostName original_displayName = $OriginalDevice.displayName original_currentCollectorId = $OriginalDevice.currentCollectorId original_createdOnEpoch = $OriginalDevice.createdOnEpoch original_createdOnDate = $OriginalDevice.createdOnDate original_ipList = $OriginalDevice.ipList duplicate_reason = "device is considered a duplicate for having a matching system.ips value of $($Device.duplicate_ips) with $($Group.Count) devices" } } } } if ($OutputList) { if ($ListDuplicates) { return (Add-ObjectTypeInfo -InputObject $OutputList -TypeName "LogicMonitor.DedupeList" ) } elseif ($RemoveDuplicates) { foreach ($Device in $OutputList) { #Remove duplicate devices Write-Information "[INFO]: Removing device ($($Device.duplicate_deviceId)) $($Device.duplicate_displayName) for reason: $($Device.duplicate_reason)" Remove-LMDevice -Id $Device.duplicate_deviceId } } } else { Write-Information "[INFO]: No duplicates detected based on set parameters." } } } else { Write-Error "Please ensure you are logged in before running any commands, use Connect-LMAccount to login and try again." } } end {} } |