Public/Export-SCOMOverrides.ps1

Function Export-SCOMOverrides {
  <#
      .Synopsis
      This script will export all SCOM overrides to various file formats.
 
      .DESCRIPTION
      Will export a generous amount of information about overrides. Output may be filtered by management pack and exported to html, csv, xml, and json file formats.
 
 
      .PARAMETER OutDir
      Directory where output files will be created. Folder will get created if it doesn't already exist.
 
      .PARAMETER ExportFormats
      File format. TypeInformation is excluded. "CSV","JSON","HTML","XML"
 
      .PARAMETER CSS
      Any custom CSS for the HTML report. This will be inserted into the <Head> tag of the document. See examples.
 
      .PARAMETER FilterMPNames
      This can be a comma-separated string of management pack names or it can be an array of single names or a combination of both. See examples. The report(s) will only include overrides that exist in these MPs.
 
      .PARAMETER SortBy
      Sort rows by column name.
 
      .PARAMETER SortOrder
      Ascending or descending based on SortBy parameter.
 
      .PARAMETER DateStampFile
      By default the output files will include a datestamp in the name. Specify $false to produce a consistent filename. See examples.
 
 
      .PARAMETER WriteToEventLog
      Will write debugging info to Opsman event log.
 
      .EXAMPLE
      Export-SCOMOverrides -OutDir C:\Reports -ExportFormats HTML -FilterMPNames 'URLGenie.OVERRIDES,OpsMgr.Self.Maintenance.Overrides','PortGenie.OVERRIDES','WindowsService.OVERRIDES' -Verbose
 
      This example demonstrates that you can supply a comma-separated list of MP Names or an array of names or both.
 
      .EXAMPLE
      Export-SCOMOverrides -SortBy ORMPName -SortOrder Ascending -DateStampFile:$false -Verbose
 
 
      .EXAMPLE
      #Example
      PS C:\> [string]$CSS = @'
      <style>
      table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      }
 
      th, td {
      padding: 5px;
      }
 
      td {
      text-align: center;
      }
      </style>
      '@
 
      PS C:\> Export-SCOMOverrides -SortBy ORMPName -ExportFormats HTML -CSS $CSS -OutDir "C:\Reports"
 
      .NOTES
      Author: Tyson Paul
      Blog: https://monitoringguys.com/2019/11/12/scomhelper/
      History:
      2020.05.13 - First version
 
      .INPUTS
      Inputs to this cmdlet (if any)
 
      .OUTPUTS
      Will output to std output or up to 4 different output file formats.
 
  #>



  [CmdletBinding(DefaultParameterSetName='Parameter Set 1',
      SupportsShouldProcess=$true,
      PositionalBinding=$false,
      HelpUri = 'https://monitoringguys.com/',
  ConfirmImpact='Medium')]

  Param (

    # Folder for exported files (HTML and CSV)
    [Parameter(Mandatory=$true, ParameterSetName='FileExport',
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=0)]
    [string]$OutDir,



    # Export Formats: <html | csv | xml | json | all>
    [Parameter(Mandatory=$false, ParameterSetName='FileExport',
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=1)]
    [ValidateSet(
        "All",
        "CSV",
        "JSON",
        "HTML",
    "XML")]
    $ExportFormats ,


    # Optional CSS for HTML file export. Will appear in <Head> section of output file.
    [Parameter(Mandatory=$false, ParameterSetName='FileExport',
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=2)]
    [string]$CSS = @'
<style>
table, th, td {
  border: 1px solid black;
  border-collapse: collapse;
}
 
th, td {
  padding: 3px;
}
 
td {
  text-align: left;
}
</style>
'@

    ,

    # Comma-separated list of management pack Names or array of names (or both) for which to include overrides from only THESE MPs. Otherwise ALL ORs from ALL MPs will be exported.
    [Parameter(Mandatory=$false,
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=3)]
    [string[]]$FilterMPNames = '',


    #Report rows will be sorted by this Workflow property
    [Parameter(Mandatory=$false,
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=4)]
    [ValidateSet("ContextDN",
        "ContextInstanceDN",
        "ContextIsGroup",
        "Enforced",
        "ORMPName",
        "ORName",
        "Parameter",
        "Property",
        "Value",
        "Workflow",
        "WorkflowDN",
        "WorkflowMPName",
    "WorkflowType")]
    [string]$SortBy = "WorkflowDN",

    #Formatting of HTML export
    [Parameter(Mandatory=$false,
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=5)]
    [ValidateNotNull()]
    [ValidateNotNullOrEmpty()]
    [ValidateSet("Ascending", "Descending")]
    [string]$SortOrder = 'Ascending',


    # Will export files with unique datestamp name. <true|false>
    [Parameter(Mandatory=$false, ParameterSetName='FileExport',
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=6)]
    [switch]$DateStampFile = $true,


    [Parameter(Mandatory=$false,
        ValueFromPipeline=$false,
        ValueFromPipelineByPropertyName=$false,
        ValueFromRemainingArguments=$false,
    Position=7)]
    [switch]$WriteToEventLog
  )


  [int]$maxLogLength = 31000 #max chars to allow for event log messages
  [string]$ScriptName = 'Export-Overrides.ps1'
  $ScriptNameInstanceGUID = (New-Guid).Guid.Substring(((New-Guid).Guid.Length ) -6).ToUpper()
  [string]$whoami = whoami.exe

  ########################################################
  Function LogIt {
    Param(
      [switch]$Display,
      [int]$EventID,
      [int]$Line,
      $maxLogLength=31000,
      [string]$msg = '<No message provided>',
      [bool]$Proceed,
      [int]$Type = 2
    )

    $output = @"
 
 
Message: $msg
 
ThisScriptInstanceGUID: $ScriptNameInstanceGUID
ScriptLine: $Line
Running As: $whoami
This script: $ScriptName
 
 
Any Errors: $Error
 
"@


    If ($Proceed)
    {
      $oEvent = New-Object -ComObject 'MOM.ScriptAPI'
      If ($output.Length -gt $maxLogLength){
        $output = ($output.Substring(0,([math]::Min($output.Length,$maxLogLength) )) + '...TRUNCATED...')
      }
      $oEvent.LogScriptEvent($ScriptName,$EventID,$Type,$output )
      #Display output, appropriate for an agent task.

    }
    If ($Display ) {
      Write-Verbose $msg
    }
  }
  ###############################################################################
  Function Load-Cache {

    LogIt -msg "Building cache..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display

    # Cache all classes
    LogIt -msg "Getting all Classes..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $AllClasses = Get-SCOMClass
    LogIt -msg "$($AllClasses.Count) found." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $hashAllClasses = @{}
    $hashAllClassesID = @{}
    ForEach ($Class in $AllClasses) {
      $hashAllClasses.Add($Class.Name, $Class)
      $hashAllClassesID.Add($Class.ID.GUID,$Class)
    }

    # Cache all monitors
    LogIt -msg "Getting all Monitors..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $AllMonitors = Get-SCOMMonitor
    LogIt -msg "$($AllMonitors.Count) Monitors found." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $hashAllMonitors = @{}
    ForEach ($Mon in $AllMonitors) {
      $hashAllMonitors.Add($Mon.Id.Guid, $Mon)
    }

    # Cache all rules
    LogIt -msg "Getting all Rules..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $AllRules = Get-SCOMRule
    LogIt -msg "$($AllRules.Count) Rules found." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $hashAllRules = @{}

    ForEach ($Rule in $AllRules) {
      $hashAllRules.Add($Rule.Id.Guid, $Rule)
    }

    # Cache all discoveries
    LogIt -msg "Getting all Discoveries..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $AllDiscoveries = Get-SCOMDiscovery
    LogIt -msg "$($AllDiscoveries.Count) Discoveries found." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $hashAllDiscoveries = @{}
    ForEach ($Disc in $AllDiscoveries) {
      $hashAllDiscoveries.Add($Disc.Id.Guid, $Disc)
    }

    # Cache all groups
    LogIt -msg "Getting all Groups..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $AllGroups = Get-SCOMGroup
    LogIt -msg "$($AllGroups.Count) Groups found." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    $hashAllGroups = @{}
    ForEach ($Group in $AllGroups) {
      $hashAllGroups.Add($Group.FullName, $Group)
    }
  }

  ########################################################
  Function Load-MPs {
    Param(
      [ValidateSet("Sealed","Unsealed","All")]
      [string]$type="All"
    )

    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
    If ($Reload -eq $true ){ $type = 'All'}
    switch ($type)
    {
      'All' {
        LogIt -msg "Getting ALL MPs. This may take a minute..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        $AllMPs = Get-SCOMManagementPack | Where-Object {$_.Name -notin $ExcludedMPs.Values}
        $hashAllMPs = @{}
        $AllMPs | ForEach-Object {
          $hashAllMPs.Add($_.Name,$_)
        }
        $tmpmsg = "$($AllMPs.Count ) MPs found..."
      }

      {$_ -in 'All','Sealed' } {
        LogIt -msg "Getting Sealed MPs. This may take a minute..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        $SealedMPs = $AllMPs | Where-Object -FilterScript {$_.Sealed -eq $True } | Where-Object {$_.Name -notin $ExcludedMPs.Values}
        $hashSealedMPs = @{}
        $SealedMPs | ForEach-Object {
          $hashSealedMPs.Add($_.Name,$_)
        }
        $tmpmsg += " $($SealedMPs.Count ) Sealed MPs found..."
      }

      {$_ -in 'All','Unsealed' } {
        LogIt -msg "Getting unsealed MPs. This may take a minute..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        $UnsealedMPs = $AllMPs | Where-Object -FilterScript {$_.Sealed -eq $False } | Where-Object {$_.Name -notin $ExcludedMPs.Values}
        $hashUnsealedMPs = @{}
        $UnsealedMPs | ForEach-Object {
          $hashUnsealedMPs.Add($_.Name,$_)
        }
        $tmpmsg += " $($UnsealedMPs.Count ) unsealed MPs found..."
      }

      Default {Write-Host "Default switch. Problem." -F Yellow}
    }

    [double]$elapsed = $stopwatch.Elapsed.TotalSeconds
    $stopwatch.Stop()
    LogIt -msg "$tmpmsg Operation took $($elapsed) seconds." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display

  }
  ########################################################
  Function Select-Overrides {
    Param(
      [Parameter( Mandatory=$false,
      ParameterSetName='1')]
      [System.Object[]]$MPs,

      [System.Object[]]$Override,
      [Switch]$silent
    )

    [System.Collections.ArrayList]$arrayOR = @()

    If ([bool]$MPs) {
      LogIt -msg "`nGetting overrides from $($MPs.Count) unsealed MP(s). This may take a minute..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
      # Return only the overrides from the previously selected MPs
      ForEach ($MP in $MPs) {
        Try{
          $arrayOR += ( ($AllMPs | Where-Object { $_.Name -eq $MP.Name}).GetOverrides() )
        }Catch{
          Write-Host "No valid overrides found in MP: $($MP.Name)"
        }
      }
    }
    Else {
      LogIt -msg "`nGetting overrides from $($AllMPs.Count) Management Packs. This may take a minute..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
      $arrayOR = $AllMPs | ForEach-Object {$_.GetOverrides()}
    }

    If ($arrayOR.Count -eq 0){
      LogIt -msg "No valid overrides found in MP(s). To be valid for selection, ORs must not reference locally defined targets or workflows (in the same unsealed pack)." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    }

    # Just set variable here. Function should be dot-sourced when called.
    $ORs = $arrayOR
  }
  ########################################################
  Function Format-OR {
    Param(
      $ORs
    )
    [System.Collections.ArrayList]$arrObject = @()
    [int]$i=0

    LogIt -msg "Begin formatting ORs..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    # 'MonitorPropertyOverride', 'RulePropertyOverride', 'DiscoveryPropertyOverride'
    # 'MonitorConfigurationOverride', 'RuleConfigurationOverride', 'DiscoveryConfigurationOverride'
    # I'm going to have to do this the old-fashioned way
    ForEach ($item in $ORs) {
      $i++
      #Write-Progress -Activity "Formatting Data" -status "$i of ($ORs.Count)" -percentComplete ($i / ($ORs.Count*100))
      $Object = New-Object PSObject

      # Will address Diagnostic and Recovery overrides at a later time. Maybe.
      If ($item.XMLTag -match 'Diagnostic|Recovery' ) { Continue; }

      $Object | add-member Noteproperty ORName ([string]$item.Name)
      $Object | add-member Noteproperty ORMPName ([string]$item.Identifier.Domain[0])

      # is Monitor
      If ([bool]$item.Monitor.Identifier.Path.Count) {
        $Object | add-member Noteproperty WorkflowMPName ($item.Monitor.Identifier.Domain[0].ToString())
        $Object | add-member Noteproperty WorkflowType "Monitor"
        $Object | add-member Noteproperty Workflow ($item.Monitor.Identifier.Path[0].ToString())
        #$Object | add-member Noteproperty WorkflowDN ((Get-SCOMMonitor -Id $item.Monitor.Id.Guid).DisplayName )
        $Object | add-member Noteproperty WorkflowDN (($hashAllMonitors[$item.Monitor.Id.Guid]).DisplayName )
        $Object | add-member Noteproperty WorkflowId ([string]$item.Monitor.Id.Guid)
      }
      # is Rule
      ElseIf (($item.Rule.Identifier.Path.Count)) {
        $Object | add-member Noteproperty WorkflowMPName ($item.Rule.Identifier.Domain[0].ToString())
        $Object | add-member Noteproperty WorkflowType "Rule"
        $Object | add-member Noteproperty Workflow ($item.Rule.Identifier.Path[0].ToString() )
        #$Object | add-member Noteproperty WorkflowDN ((Get-SCOMRule -Id $item.Rule.Id.Guid).DisplayName )
        $Object | add-member Noteproperty WorkflowDN (($hashAllRules[$item.Rule.Id.Guid]).DisplayName )
        $Object | add-member Noteproperty WorkflowId ([string]$item.Rule.Id.Guid)
      }
      # is Discovery
      ElseIf ([bool]($item.Discovery.Identifier.Path.Count)) {
        $Object | add-member Noteproperty WorkflowMPName ($item.Discovery.Identifier.Domain[0].ToString())
        $Object | add-member Noteproperty WorkflowType "Discovery"
        $Object | add-member Noteproperty Workflow ($item.Discovery.Identifier.Path[0].ToString())
        #$Object | add-member Noteproperty WorkflowDN ((Get-SCOMDiscovery -Id $item.Discovery.Id.Guid).DisplayName )
        $Object | add-member Noteproperty WorkflowDN (($hashAllDiscoveries[$item.Discovery.Id.Guid]).DisplayName )

        $Object | add-member Noteproperty WorkflowId ([string]$item.Discovery.Id.Guid)
      }
      Else {
        $Object | add-member Noteproperty Workflow "ERROR"
        $Object | add-member Noteproperty WorkflowDN "ERROR"
        $Object | add-member Noteproperty WorkflowType "ERROR"
      }


      # To be added at some point
      # Diagnostic Task
      # Recovery Task
      # Note: $item.Target.Identifier.Path[0]


      If ([bool]($item.Property.Count)) {
        $Object | add-member Noteproperty Property ($item.Property.ToString() )
        $Object | add-member Noteproperty Parameter ""
      }
      Else {
        $Object | add-member Noteproperty Property ""
        $Object | add-member Noteproperty Parameter $item.Parameter
      }

      $Object | add-member Noteproperty Value $item.Value

      If ([bool]($hashAllClassesID[$item.Context.Id.Guid])){
        $Object | add-member Noteproperty Context ( $hashAllClassesID[$item.Context.Id.Guid].Name )
        $Object | add-member Noteproperty ContextID ($item.Context.Id.Guid.ToString())
        $Object | add-member Noteproperty ContextDN ( $hashAllClassesID[$item.Context.Id.Guid].DisplayName )

        If ( $hashAllGroups.ContainsKey($hashAllClassesID[$item.Context.Id.Guid].Name) ) {
          $Object | add-member Noteproperty ContextIsGroup 'True'
        }
        Else {
          $Object | add-member Noteproperty ContextIsGroup 'False'
        }
      }
      #If the Context/Target does not exist, then add the ORName to a dirty list
      Else {
        Try{
          # Need to figure out what to do with this collection of duds.
          $StaleORNames.Add($item.Name,'Stale')
        }
        Catch { #typically it's a bad idea to have an empty Catch but it's fine in this situation
        }
        $Object | add-member Noteproperty Context "DOES NOT EXIST - STALE REFERENCE"
        $Object | add-member Noteproperty ContextID ""
        $Object | add-member Noteproperty ContextDN ""
      }

      If ([Bool]($item.ContextInstance.Count)) {
        $Object | add-member Noteproperty ContextInstanceID ($item.ContextInstance.Guid.ToString() )
        If ([bool]($DN = (Get-SCOMClassInstance -Id $item.ContextInstance.Guid).DisplayName) ) {
          # This might prove to be very time consuming
          $Object | add-member Noteproperty ContextInstanceDN $DN
        } Else{
          $Object | add-member Noteproperty ContextInstanceDN ""
        }

      }
      Else {
        $Object | add-member Noteproperty ContextInstanceID ""
        $Object | add-member Noteproperty ContextInstanceDN ""
      }

      $Object | add-member Noteproperty Enforced $item.Enforced
      $Object | add-member Noteproperty OR_MPVersion $item.Identifier.Version.ToString()
      $arrObject.Add($Object) | Out-Null
    }
    If ($Object) {
      Remove-Variable -Name Object -ErrorAction SilentlyContinue
    }
    LogIt -msg "Done formatting ORs." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display

    # Just set variable here. Function should be dot-sourced when called.
    $ORs_F = $arrObject
  }
  ########################################################

  Function Verify-OutDir {
    Param (
      [string]$OutDir
    )

    If (-NOT (Test-Path -Path $OutDir -PathType Container )) {
      Try {
        New-Item -Path $OutDir -ItemType Directory -Force -ErrorAction Stop
        Return $true
      }Catch{
        Write-Error "Unable to verify output directory."
        Return $false
      }
    }
    Else {
      Return (Test-Path -Path $OutDir -PathType Container )
    }
  }

  ########################################################
  Function __LINE__ {
    $MyInvocation.ScriptLineNumber
  }
  ########################################################


  #====================================================================================
  #====================================== MAIN ======================================

  [int]$info=0
  [int]$critical=1
  [int]$warn=2

  # This will help control output sort order command
  Switch ($SortOrder ) {
    'Ascending' {
      [BOOL]$SortOrder = $false
    }
    'Descending' {
      [BOOL]$SortOrder = $true
    }
    Default {
      [BOOL]$SortOrder = $false
    }
  }

  # These are MPs that shouldn't be tampered with or consulted.
  $ExcludedMPs =  @{
    1 = 'Microsoft.SystemCenter.SecureReferenceOverride'
    2 = 'Microsoft.SystemCenter.GlobalServiceMonitor.SecureReferenceOverride'
    3 = 'Microsoft.SystemCenter.Notifications.Internal'
    4 = 'Microsoft.SystemCenter.NetworkDiscovery.Internal'
    5 = 'Microsoft.SystemCenter.Advisor.SecureReferenceOverride'
  }


  If ($DateStampFile){
    [string]$FileName = "overrides_$(Get-Date -F yyyyMMdd_HHmmss)"
  }
  Else {
    [string]$FileName = "overrides"
  }

  If (-NOT (Verify-OutDir -OutDir $OutDir)) {
    LogIt -msg "Unable to verify export directory [$($OutDir)]. Please run this task with permissions to create the directory or specify a valid path. Exiting." -Type $critical -EventID 9995 -Proceed $true -Line $(__LINE__) -Display
    Exit
  }

  # Functions are dot-sourced (which is perfectly fine) because output statements in the functions are meant to be seen in agent task.
  # Output statements in functions will contaminate function return values.
  . Load-Cache

  . Load-MPs -type 'All'

  [System.Collections.ArrayList]$FilteredMPs = @()
  ForEach ($Item in $FilterMPNames) {
    ForEach ($Name in @($Item.Split(',').Split(';').Split(':')) )
    {
      $null = $FilteredMPs.Add($hashAllMPs[$Name])
    }
  }

  #. Load-MPs -type 'All'
  . Select-Overrides -MPs $FilteredMPs

  # Result will populate '$ORs_F'
  . Format-OR -ORs $ORs


  If ($ORs_F.Count) {
    $ORs_F = $ORs_F | Sort-Object -Property $SortBy -Descending:$SortOrder
  }

  If (-NOT $ExportFormats){
    LogIt -msg "Returning overrides to std out." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
    Return $ORs_F
  }
  Else {
    Switch ($ExportFormats) {
      {$_ -match 'all|csv'} {
        Try{
          $ORs_F | Export-Csv -Path (Join-Path $OutDir "$($FileName).csv") -NoTypeInformation -Force -Encoding UTF8
          LogIt -msg "Exporting overrides to: [$((Join-Path $OutDir "$($FileName).csv"))] ..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        } Catch {
          LogIt -msg "FAILED Exporting overrides to: [$((Join-Path $OutDir "$($FileName).csv"))] ..." -Type $warn -EventID 9995 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        }
      }

      {$_ -match 'all|html'} {
        Try{
          $ORs_F | ConvertTo-Html -Head $css | Set-Content -Path (Join-Path $OutDir "$($FileName).html") -Encoding UTF8 -Force
          LogIt -msg "Exporting overrides to: [$((Join-Path $OutDir "$($FileName).html"))] ..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        } Catch {
          LogIt -msg "FAILED Exporting overrides to: [$((Join-Path $OutDir "$($FileName).html"))] ..." -Type $warn -EventID 9995 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        }
      }

      {$_ -match 'all|json'} {
        Try{
          $ORs_F | ConvertTo-Json | Set-Content -Path (Join-Path $OutDir "$($FileName).json") -Force -Encoding UTF8
          LogIt -msg "Exporting overrides to: [$((Join-Path $OutDir "$($FileName).json"))] ..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        } Catch {
          LogIt -msg "FAILED Exporting overrides to: [$((Join-Path $OutDir "$($FileName).json"))] ..." -Type $warn -EventID 9995 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        }
      }

      {$_ -match 'all|xml'} {
        Try{
          $ORs_F | Export-Clixml -Path (Join-Path $OutDir "$($FileName).xml") -Force -Encoding UTF8
          LogIt -msg "Exporting overrides to: [$((Join-Path $OutDir "$($FileName).xml"))] ..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        } Catch {
          LogIt -msg "FAILED Exporting overrides to: [$((Join-Path $OutDir "$($FileName).xml"))] ..." -Type $warn -EventID 9995 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
        }
      }

      default      {
        LogIt -msg "FAILED Exporting overrides! Something is wrong with `$ExportFormats [$($ExportFormats)]" -Type $critical -EventID 9995 -Proceed $true -Line $(__LINE__) -Display
      }
    }#end switch
  }
  LogIt -msg "Script end ..." -Type $info -EventID 9990 -Proceed $WriteToEventLog -Line $(__LINE__) -Display
}