NewRelicPS.Configuration.Dashboard.psm1

<#
.Synopsis
  Syncs dashboard configurations between accounts
.Description
  Syncs a dashboard configuration from a source account to one or more destination accounts
.Example
  Sync-NRDashboardConfiguration -APIKey $PersonalAPIKey -DefinedDashboards $MyDashboards
  Uses New Relic QraphQL APIs to sync an entire dashboard, including any subpages, to another New Relic account.
  Existing dashboards in destination accounts with names matching the source dashboard have their configuration updated to match the source dashboard.
.Parameter APIKey
  Must be a personal 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 DefinedDashboards
  An array of dashboard objects which define the source and destination parameters for syncing the configuration
#>

Function Sync-NRDashboardConfiguration {
  [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] $APIKey,
    [Parameter (Mandatory = $false)]
    [array] $DefinedDashboards
  )

  Write-Verbose "There are currently $($DefinedDashboards.count) source dashboards configured for sync."
  Foreach ($dashboard in $DefinedDashboards) {
    $shouldCopy = $false
    $destinationId = ''
    $destinationConfigJSON = ''
    $sourceConfig = Get-NRDashboard -APIKey $APIKey -DashboardId $dashboard.sourceDashboardId
    $sourceConfigJSON = $sourceConfig | ConvertTo-JSON -Depth 50

    # Multiple destination accounts can be defined in the configuration
    Foreach ($account in $dashboard.destinationAccounts) {

      # Find Dashboard in destination if available
      $destinationId = (Get-NRDashboardList -APIKey $APIKey | Where-Object { $_.name -eq $sourceConfig.name -and $_.accountId -eq $account.Id }).guid

      # If a single matching dashboard is found, compare configs between source and destination
      If ($destinationId.count -eq 1) {
        Write-Verbose "Found existing dashboard with name $($sourceConfig.name) in account $($account.id), comparing configs"
        $destinationConfigJSON = Get-NRDashboard -APIKey $APIKey -DashboardId $destinationId | ConvertTo-Json -Depth 50

        # If widget Ids have been updated at destination the compare will fail, so update source config account Ids to match destination before comparison.
        If ($dashboard.UpdateWidgetAccountIds) {
          $stringsToReplace = ($sourceConfigJSON | select-string -pattern '"AccountId": (.*),' -AllMatches).matches.value | Select-Object -unique
          Foreach ($string in $stringsToReplace) {
            $sourceConfigJson = $sourceConfigJSON -replace ($string, "`"accountId`": $($account.Id),")
          }
        }

        # Compare source and destination configs
        If ($sourceConfigJSON -ne $destinationConfigJSON) {
          Write-Verbose "Configuration differs for dashboard $($sourceConfig.name) between source and destination accounts"
          $shouldCopy = $true
        }
      }
      ElseIf ($destinationId.count -lt 1) {
        Write-Verbose "No matching dashboard found in account $($account.name) for dashboard $($sourceConfig.name))"
        $shouldCopy = $true
      }
      Else {
        Throw "More than one dashboard with name $($sourceConfig.name) found in account $($account.id). Multiple dashboards with the same name in the same account is unsupported."
      }

      # Only copy if required
      If ($shouldCopy) {
        Write-Verbose "Updating dashboard $($dashboard.sourceDashboardName) in account $($account.name)"
        Copy-NRDashboard -APIKey $APIKey -DashboardId $dashboard.sourceDashboardId -DestinationAccountId $account.id -UpdateWidgetAccountIds:$dashboard.updateWidgetAccountIds -Whatif:$WhatIfPreference | Out-Null
      }
    }
  }
}