Change Auditing for Group Hierarchy
We had a couple of folders move on us (erroneous clicks by our users). Tracking down where they came from was difficult. I've written a solution using a configSource. AppliesTo() targets a collector we've set aside for doing RestAPI queries with longer timeouts for scripting:
$company = "<Your Company From the URL Here>"
$URLBase = "https://$company.logicmonitor.com/santaba/rest"
$accessID = "##ApiAccessID.key##"
$accessKey = "##ApiAccessKey.key##"
#region Initialization and Functions
#-------- The Functions ----------
function Send-Request {
param (
$cred ,
$URL ,
$accessid = $null,
$accesskey = $null,
$data = $null,
$version = '3' ,
$httpVerb = "GET"
)
if ( $accessId -eq $null) { exit 1 }
<# Use TLS 1.2 #>
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
<# Get current time in milliseconds #>
$epoch = [Math]::Round(
( New-TimeSpan `
-start (Get-Date -Date "1/1/1970") `
-end (Get-Date).ToUniversalTime()).TotalMilliseconds
)
<# Concatenate Request Details #>
$requestVars = $httpVerb + $epoch + $data + $resourcePath
<# Construct Signature #>
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes( $accessKey )
$signatureBytes = $hmac.ComputeHash( [Text.Encoding]::UTF8.GetBytes( $requestVars ) )
$signatureHex = [System.BitConverter]::ToString( $signatureBytes ) -replace '-'
$signature = [System.Convert]::ToBase64String( [System.Text.Encoding]::UTF8.GetBytes( $signatureHex.ToLower() ) )
<# Construct Headers #>
$auth = 'LMv1 ' + $accessId + ':' + $signature + ':' + $epoch
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add( "Authorization", $auth )
$headers.Add( "Content-Type" , 'application/json' )
# uses version 2 of the API
$headers.Add( "X-version" , $version )
<# Make Request #>
$response = Invoke-RestMethod `
-Uri $URL `
-Method $httpVerb `
-Body $data `
-Header $headers `
-erroraction SilentlyContinue `
-warningaction SilentlyContinue
Return $response
}
function Get-LMRestAPIObjectListing {
param (
$URLBase ,
$resourcePathRoot , # "/device/devices"
$size = 1000 ,
$accessKey ,
$accessId ,
$version = '2'
)
$output = @()
$looping = $true
$counter = 0
while ($looping) {
#re-calc offset based on iteration
$offset = $counter * $size
$resourcePath = $resourcePathRoot
$queryParam = "?size=$size&offset=$offset"
$url = $URLBase + $resourcePath + $queryParam
# Make Request
$response = Send-Request `
-accesskey $accessKey `
-accessid $accessId `
-URL $url `
-version $version
if ( $response.items.count -eq $size ) {
# Return set is full, more items to retrieve
$output += $response.items
$counter++
} elseif ( $response.items.count -gt 0 ) {
# Return set is not full, store date, end loop
$output += $response.items
$looping = $false
} else {
# Return set is empty, no data to store, end loop
$looping = $false
}
}
write-output $output
}
#endregion
#region Get Groups
$resourcePath = "/device/groups"
$Groups = Get-LMRestAPIObjectListing `
-resourcePathRoot $resourcePath `
-accessKey $accessKey `
-accessId $accessID `
-URLBase $URLBase
#endregion
$groups | sort id | select id, parentid, fullpath | format-table -autosize
Cole McDonald
Posted 2 years ago·Last reply 2 years ago
3 comments
Michael Raymond
·2 years agoThis is super dope! Thoughts on publishing to the Exchange?
Cole McDonald
OP2 years agoI don't generally interface with the Exchange much at all. Most of what I end up writing is part of our IP and I'm not allowed to share. So I come here with the neat little ones I think would be useful for others to have. I'm not averse to it, I just haven't really dug into the exchange much as it's traditionally had issues for us and how we have deployed/tuned things.
LM User
·2 years agoWe did something similar in Groovy except that we also output the non-obfuscated properties. That way we can also tell when someone makes a change to a group property breaking something.