Cole_McDonald
4 months agoProfessor
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