NewRelicPS.Configuration.SyntheticMonitor.psm1
Using module '.\NewRelicPS.SyntheticMonitors.psm1' <# .Synopsis Idempotently applies New Relic synthetic monitor configurations .Description Idempotently applies New Relic synthetic monitor configurations. The monitor configuration determines what sites are being monitored and from which locations. .Example Set-SyntheticConditionMonitor -AdminAPIKey $AdminAPIKey -DefinedSytheticMonitors $Config.SyntheticMonitors Uses New Relic APIs to update synthetic monitors to match the configuration defined in $Config.SyntheticMonitors. Any existing monitors that are not defined will be removed. .Parameter AdminAPIAPIKey Must be an admin user's API Key, not an account-level REST API Key. See more here: https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys .Parameter DefinedSyntheticMonitors An array of monitor objects which define the desired configuration state for New Relic synthetic monitors #> Function Set-NRSyntheticLocationMonitorConfiguration { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", '', Justification = "All CMDLets being called have ShouldProcess in place and the preference is passed to them." )] [CMDLetBinding(SupportsShouldProcess = $true)] Param ( [Parameter (Mandatory = $true)] [string] $AdminAPIKey, [array] $DefinedSyntheticMonitors ) # Iterate over each defined monitor [System.Collections.ArrayList]$existingMonitors = @(Get-NRSyntheticMonitor -APIKey $AdminAPIKey) Write-Verbose "There are currently $($DefinedSyntheticMonitors.count) defined Synthetic monitors and $($existingMonitors.count) existing Synthetic monitors." Foreach ($monitor in $DefinedSyntheticMonitors) { [array]$existingMonitor = $existingMonitors | Where-Object {$_.name -eq $monitor.name} # Items are declared by name and are later given an ID by New Relic, therefore resources with the same name will cause issues and are unsupported. If ($existingMonitor.count -gt 1) { Write-Error "Multiple monitors found with the name $($existingMonitor.name[0])! Ids: $($existingMonitor.id -join (',')) This must be resolved manually before continuing." -ErrorAction 'Stop' } # Update existing condition if needed If ($existingMonitor) { $monitorRequiresUpdate = Compare-NRSyntheticMonitorState -DefinedMonitor $monitor -ExistingMonitor $existingMonitor -Verbose:$PSCMDLet.GetVariableValue('VerbosePreference') If ($monitorRequiresUpdate) { Write-Verbose "Updating monitor $($monitor.name)" # Remove type property from monitor and pipe all other properties into the CMDLet $monitorParams = [pscustomobject] ($monitor | Select-Object -ExcludeProperty 'type') $monitorParams | Update-NRSyntheticMonitor -APIKey $AdminAPIKey -ID $existingMonitor.Id -Whatif:$WhatIfPreference | Out-Null } # Any extra existing monitors that are not defined will be removed later $existingMonitors.Remove($existingMonitor[0]) } # Otherwise, create monitor Else { Write-Verbose "Creating monitor $($monitor.name)" New-NRSyntheticMonitor @monitor -APIKey $AdminAPIKey -Whatif:$WhatIfPreference | Out-Null } } # Check for existing monitors not in the definition and remove them # Note that the Synthetic API returns an object with empty properties rather than null when no monitors exist so check using the id property If ($existingMonitors.id) { Write-Verbose "Removing monitor(s) $($existingMonitors.Name -join (','))" $existingMonitors.Id | Remove-NRSyntheticMonitor $AdminAPIKey -Whatif:$WhatIfPreference | Out-Null } } ########################## # Internal Functions ########################## Function Compare-NRSyntheticMonitorState { [CMDLetBinding()] Param ( $DefinedMonitor, $ExistingMonitor ) [boolean]$returnValue = $false $KeysExcludedFromComparison = @('Type', 'ScriptVariables') Foreach ($property in ($DefinedMonitor.Keys | Where-Object {$_ -notin $KeysExcludedFromComparison})) { # Options Requires special handling $optionsProperties = @('validatioString','verifySSL','bypassHEADRequest','treatRedirectAsFailure') If ($property -in $optionsProperties) { If ($DefinedMonitor.$property -ne $ExistingMonitor.options.$property) { Write-Verbose "Monitor $($DefinedMonitor.Name) has options property $property defined as $($DefinedMonitor.$property) but it is currently set to $($ExistingMonitor.options.$property)" $returnValue = $true } } # Locations also require special handling since this is an array of items ElseIf ($property -eq 'locations') { $locationsDiff = Compare-Object -ReferenceObject $DefinedMonitor.$property -DifferenceObject $ExistingMonitor.$property -PassThru If ($locationsDiff) { Write-Verbose "Monitor $($DefinedMonitor.Name) has an locations list of $($DefinedMonitor.$property) but it is currently set to $($ExistingMonitor.$property)" $returnValue = $true } } # Script path requires special handling to evaluate if update is needed ElseIf ($property -eq 'scriptPath') { If (Test-Path $DefinedMonitor.$property) { # Replace variables on script and convert to base64 then compare against existing script content $newScriptContent = Get-NRScriptContent -ScriptPath $DefinedMonitor.$property -ScriptVariables $DefinedMonitor.ScriptVariables $existingScriptContent = (Get-NRSyntheticMonitorScript -APIKey $AdminAPIKey -Id $ExistingMonitor.id).scriptText If ($newScriptContent -ne $existingScriptContent) { Write-Verbose "Monitor $($DefinedMonitor.Name) script's content has changed" $returnValue = $true } } Else { Write-Error "Cannot find script for $($DefinedMonitor.Name) at $($DefinedMonitor.$property)" } } # Compare top-level properties ElseIf ($DefinedMonitor.$property -ne $ExistingMonitor.$property) { Write-Verbose "Monitor $($DefinedMonitor.Name) has property $property defined as $($DefinedMonitor.$property) but it is currently set to $($ExistingMonitor.$property)" $returnValue = $true } } Return $returnValue } |