Public/Export-LMDeviceGroupCustomProperties.ps1
|
<# .SYNOPSIS Exports device group custom properties with inheritance tracking to CSV or returns objects. .DESCRIPTION The Export-LMDeviceGroupCustomProperties function extracts specific custom properties from device groups, checking both direct properties and inherited properties from parent groups. It can export results to CSV or return objects for further processing. .PARAMETER PropertyKeys Array of custom property keys to extract from device groups. Each property will be checked for both direct and inherited values. .PARAMETER DeviceGroupId Optional device group ID to filter results to a specific group and its subgroups. .PARAMETER DeviceGroupFilter Optional filter object to apply when retrieving device groups. Can include multiple conditions combined as AND operations. .PARAMETER IncludeNumOfProperties Switch to include all numOf* properties (numOfHosts, numOfAWSDevices, etc.) in the output. .PARAMETER ExportPath Optional file path to export results to CSV. If not specified, results are returned as objects. .PARAMETER PassThru If specified, returns the results as objects even when ExportPath is provided. .EXAMPLE Export-LMDeviceGroupCustomProperties -PropertyKeys @("nre_filter.application-delivery.gslb.CPU.dataPointName", "nre_filter.application-delivery.gslb.CPU.datasource_name") Extracts the specified custom properties from all device groups and displays the results. .EXAMPLE Export-LMDeviceGroupCustomProperties -PropertyKeys "environment" -DeviceGroupId 1 -ExportPath "C:\reports\properties.csv" Extracts the "environment" property from device group 1 and its subgroups, exporting to CSV. .EXAMPLE Export-LMDeviceGroupCustomProperties -PropertyKeys @("location", "team") -IncludeNumOfProperties -PassThru Extracts "location" and "team" properties from all device groups, includes numOf* properties, and returns objects. .NOTES You must run Connect-LMAccount before running this command. The function checks parent groups by traversing the parentId chain to determine if properties are inherited. .INPUTS None. Does not accept pipeline input. .LINK Module repo: https://github.com/logicmonitor/Logic.Monitor.SE .LINK PSGallery: https://www.powershellgallery.com/packages/Logic.Monitor.SE #> Function Export-LMDeviceGroupCustomProperties { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [String[]]$PropertyKeys, [Parameter(Mandatory = $false)] [Int]$DeviceGroupId, [Parameter(Mandatory = $false)] [Object]$DeviceGroupFilter, [Parameter(Mandatory = $false)] [Switch]$IncludeNumOfProperties, [Parameter(Mandatory = $false)] [String]$ExportPath, [Parameter(Mandatory = $false)] [Switch]$PassThru ) # Check if we are logged in and have valid api creds If ($(Get-LMAccountStatus).Valid) { Write-Host "[INFO]: Retrieving device groups..." # Get device groups based on parameters If ($DeviceGroupId) { $deviceGroups = @() $startingGroup = Get-LMDeviceGroup -Id $DeviceGroupId $deviceGroups += $startingGroup # Get all parent groups up to root for proper inheritance checking $parentGroups = [System.Collections.ArrayList]@() $currentParentId = $startingGroup.parentId while ($currentParentId -ne 0) { try { $parentGroup = Get-LMDeviceGroup -Id $currentParentId If ($parentGroup) { $parentGroups.Add($parentGroup) | Out-Null $currentParentId = $parentGroup.parentId } else { break } } catch { break } } $deviceGroups += $parentGroups # Recursively get all subgroups $allGroups = [System.Collections.ArrayList]@() $allGroups.AddRange($deviceGroups) | Out-Null function Get-AllSubGroups { param([Int]$ParentId, [System.Collections.ArrayList]$GroupsList) $subGroups = Get-LMDeviceGroupGroup -Id $ParentId If ($subGroups) { foreach ($subGroup in $subGroups) { $GroupsList.Add($subGroup) | Out-Null Get-AllSubGroups -ParentId $subGroup.id -GroupsList $GroupsList } } } Get-AllSubGroups -ParentId $DeviceGroupId -GroupsList $allGroups $deviceGroups = $allGroups } ElseIf ($DeviceGroupFilter) { $deviceGroups = Get-LMDeviceGroup -Filter $DeviceGroupFilter } Else { $deviceGroups = Get-LMDeviceGroup } If (-not $deviceGroups) { Write-Warning "No device groups found matching the specified criteria." Return } Write-Host "[INFO]: Found $(($deviceGroups | Measure-Object).Count) device group(s). Creating lookup dictionary..." # Create a lookup dictionary for quick parent group access $groupLookup = @{} foreach ($group in $deviceGroups) { $groupLookup[$group.id] = $group } # Function to check parent chain for a custom property function Get-InheritedProperty { param( [Object]$CurrentGroup, [Hashtable]$GroupLookup, [String]$PropertyKey ) # Check current group's customProperties first if ($CurrentGroup.customProperties) { $prop = $CurrentGroup.customProperties | Where-Object { $_.name -eq $PropertyKey } if ($prop) { return @{ Value = $prop.value; Source = "Direct" } } } # Traverse up the parent chain $parentId = $CurrentGroup.parentId while ($parentId -ne 0 -and $GroupLookup.ContainsKey($parentId)) { $parentGroup = $GroupLookup[$parentId] if ($parentGroup.customProperties) { $prop = $parentGroup.customProperties | Where-Object { $_.name -eq $PropertyKey } if ($prop) { return @{ Value = $prop.value; Source = "Inherited" } } } $parentId = $parentGroup.parentId } return @{ Value = "N/A"; Source = "N/A" } } Write-Host "[INFO]: Processing $(($deviceGroups | Measure-Object).Count) device group(s) and extracting $(($PropertyKeys | Measure-Object).Count) custom property(ies)..." # Process each device group $results = $deviceGroups | ForEach-Object { $group = $_ # Get properties (checking direct first, then parent chain) $propertyResults = @{} foreach ($propertyKey in $PropertyKeys) { $result = Get-InheritedProperty -CurrentGroup $group -GroupLookup $groupLookup -PropertyKey $propertyKey $propertyResults[$propertyKey] = $result.Value $propertyResults["$propertyKey`Source"] = $result.Source } # Build output object $outputObject = [PSCustomObject]@{ id = $group.id name = $group.name parentId = $group.parentId } # Add property values and sources foreach ($key in $propertyResults.Keys) { $outputObject | Add-Member -MemberType NoteProperty -Name $key -Value $propertyResults[$key] } # Add numOf* properties if requested If ($IncludeNumOfProperties) { $outputObject | Add-Member -MemberType NoteProperty -Name "numOfHosts" -Value $group.numOfHosts $outputObject | Add-Member -MemberType NoteProperty -Name "numOfAWSDevices" -Value $group.numOfAWSDevices $outputObject | Add-Member -MemberType NoteProperty -Name "numOfAzureDevices" -Value $group.numOfAzureDevices $outputObject | Add-Member -MemberType NoteProperty -Name "numOfGcpDevices" -Value $group.numOfGcpDevices $outputObject | Add-Member -MemberType NoteProperty -Name "numOfOciDevices" -Value $group.numOfOciDevices $outputObject | Add-Member -MemberType NoteProperty -Name "numOfKubernetesDevices" -Value $group.numOfKubernetesDevices $outputObject | Add-Member -MemberType NoteProperty -Name "numOfDirectDevices" -Value $group.numOfDirectDevices $outputObject | Add-Member -MemberType NoteProperty -Name "numOfDirectSubGroups" -Value $group.numOfDirectSubGroups } $outputObject } # Export to CSV if path specified If ($ExportPath) { Write-Host "[INFO]: Exporting results to CSV: $ExportPath" $results | Export-Csv -Path $ExportPath -NoTypeInformation Write-Host "[INFO]: Successfully exported $(($results | Measure-Object).Count) record(s) to $ExportPath" } # Return results if PassThru is specified or no ExportPath If ($PassThru -or -not $ExportPath) { Return $results } } Else { Write-Error "Please ensure you are logged in before running any commands, use Connect-LMAccount to login and try again." } } |