Public/Set-SCOMMPAliases.ps1
|
Function Set-SCOMMPAliases { <# .Synopsis Will standardize all of the aliases in one or more unsealed (.xml) management pack files. .DESCRIPTION This script will inventory all of the MP reference IDs that can be found in the single file or set of .XML files specified by the InputPath. It will create a customized set of condensed alias acronyms to be standardized across all of the unsealed management packs. It will then replace the aliases in the Manifest as well as throughout the elements where the aliases are used. .Parameter InputPath This can be a directory or full path to an unsealed management pack .xml file. .EXAMPLE PS C:\> Set-SCOMMPAliases -InputPath 'C:\UnSealedMPs\' .EXAMPLE PS C:\> Set-SCOMMPAliases -InputPath 'C:\UnSealedMPs\MyCustom.Monitoring.xml' .NOTES Author: Tyson Paul Blog: https://monitoringguys.com/ Date: 2017/12/13 History: 2017/12/13: First version #> Param ( [Parameter(Mandatory=$true)] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path -Path $_})] [string]$InputPath #Either a folder or full file path ) ##### TESTING ###### #$InputPath = 'C:\Test\Test\TempTest' ##### TESTING ###### # This will be used to seed the reference catalog with some hardcoded values for some common aliases $seed = @' Microsoft.SystemCenter = SC Microsoft.SystemCenter.Apm.Infrastructure = APMInf Microsoft.SystemCenter.Apm.Infrastructure.Monitoring = APMInfMon Microsoft.SystemCenter.Apm.Library = APMLib Microsoft.SystemCenter.Apm.NTServices = APMNT Microsoft.SystemCenter.Apm.Wcf = APMWcf Microsoft.SystemCenter.Apm.Web = APMWeb Microsoft.SystemCenter.DataWarehouse.ApmReports.Library = APMReports Microsoft.SystemCenter.InstanceGroup.Library = SCIGL Microsoft.SystemCenter.Internal = SCInt Microsoft.SystemCenter.Library =SCLib Microsoft.SystemCenter.WebApplication.Library = WebAppLib Microsoft.SystemCenter.WebApplicationSolutions.Library = WebAppSolLib Microsoft.SystemCenter.WebApplicationSolutions.Library.Resources.ENU = WebAppLibRes Microsoft.SystemCenter.WebApplicationTest.External.Library = WebAppTestExtLib Microsoft.SystemCenter.WebApplicationTest.Library = WebAppTestLib Microsoft.Windows.InternetInformationServices.2003 = IIS2003 Microsoft.Windows.Library = Windows Microsoft.Windows.Server.Library = WinSrvLib System.Health.Library = Health System.Library = System System.NetworkManagement.Library = NetManLib System.NetworkManagement.Monitoring = NetManMon System.NetworkManagement.Reports = NetManRpt System.NetworkManagement.Templates = NetManTmp System.Performance.Library = Performance '@ # $seed -split "`r`n" | Sort-Object ############################################################## # Will replace common/popular namespaces with smaller, friendly acronym Function AcronymCommonNames { Param ( [Parameter(Mandatory=$true)] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [string]$thisString ) $acronyms = ConvertFrom-StringData -StringData @" Microsoft.SQLServer = MSQL Microsoft.Windows.Server = MWS Microsoft.Windows.InternetInformationServices = IIS "@ If ( $acronyms.ContainsKey($thisString) ) { $arrNames = $acronyms.GetEnumerator().Name $arrNames | ForEach-Object { #Write-Host $_.Name $_.value $thisString = $thisString.Replace(($_),($acronyms.$_) ) } } Return $thisString } ############################################################## Function Create-Alias { Param( [Parameter(Mandatory=$true)] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [string]$Seed, [Parameter(Mandatory=$true)] [ValidateNotNull()] [ValidateNotNullOrEmpty()] # array of existing values, to prevent duplicates [system.Object[]]$Existing ) $array = AcronymCommonNames -thisString $Seed $array = $array.Split('.') $newAlias = $array[0].Replace('Microsoft','').Replace('Windows','Win').Replace('HewlettPackard','HP') For($i = 1; $i -lt $array.Count; $i++) { $fragment = $array[$i] If ( $fragment -match '\d+' ) { $newAlias += $fragment } ElseIf ( $fragment -match '^ApplicationMonitoring.?' ) { $newAlias += 'AppMon' } ElseIf ( $fragment -match '^Dashboard.?' ) { $newAlias += 'Dash' } ElseIf ( $fragment -match '^Discovery.?' ) { $newAlias += 'Disc' } ElseIf ( $fragment -match '^Library.?' ) { $newAlias += 'Lib' } ElseIf ( $fragment -match '^Linux.?' ) { $newAlias += 'Linux' } ElseIf ( $fragment -match '^Monitor.?' ) { $newAlias += 'Mon' } ElseIf ( $fragment -match '^NetworkManagement.?' ) { $newAlias += 'NetMan' } ElseIf ( $fragment -match '^Network.?' ) { $newAlias += 'Net' } ElseIf ( $fragment -match '^Report.?' ) { $newAlias += 'Rpt' } ElseIf ( $fragment -match '^Server.?' ) { $newAlias += 'Ser' } ElseIf ( $fragment -match '^System.?' ) { $newAlias += 'Sys' } ElseIf ( $fragment -match '^Template.?' ) { $newAlias += 'Tmp' } ElseIf ( $fragment -match '^Unix.?' ) { $newAlias += 'Unix' } ElseIf ( $fragment -match '^Visual.?' ) { $newAlias += 'Vis' } ElseIf ( $fragment -match '^Windows.?' ) { $newAlias += 'Win' } Else { # Use capitalized letters in MP name to build the acronym $tempchar = '' [char[]]$fragment | ForEach-Object { If ([char]::IsUpper($_) ){$tempchar+=$_ } } # $newAlias += $fragment[0] $newAlias += $tempchar } } $i = 2 $tempAlias = $newAlias While ($Existing -contains ($tempAlias)) { $tempAlias = $newAlias +"$i" $i++ } Return $tempAlias } ############################################################## # This function will replace all instances of existing aliases with the newly customized aliases. Function Standardize-AllReferenceAliases { Param( [Parameter(Mandatory=$true)] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [System.Object[]]$MPPaths, [Parameter(Mandatory=$true)] [ValidateNotNull()] [ValidateNotNullOrEmpty()] [Hashtable]$Catalog ) ForEach ($MPPath in $MPPaths){ $mpxml = [xml](Get-Content $MPPath) $arrReferences = $mpxml.GetEnumerator().Manifest.references.reference [int]$i = 0 $content = (Get-Content $MPPath) # Replace aliases wherever used in xml ForEach ($ref in ($arrReferences) ) { <# Aliases typically appear in two scenarios... 1) Examples: referring to some element property: <Property>$MPElement[Name="Windows!Microsoft.Windows.Computer"]/PrincipalName$</Property> <MonitoringClass>$MPElement[Name="SCLib!Microsoft.SystemCenter.ManagedComputer"]$</MonitoringClass> <RelationshipClass>$MPElement[Name="SCIGL!Microsoft.SystemCenter.InstanceGroupContainsEntities"]$ #> $aliasrefbang = '="'+"$($ref.Alias)"+"!" $newAlias = ('="'+($Catalog.($ref.ID))+'!') $content = ($content -Replace ([regex]::Escape($aliasrefbang)), ([regex]::Escape($newAlias)) ) <# 2) Examples: referring to a workflow, type, datasource, etc.: <DataSource ID="GroupPopulationDataSource" TypeID="SCLib!Microsoft.SystemCenter.GroupPopulator"> <DiscoveryRelationship TypeID="SCIGL!Microsoft.SystemCenter.InstanceGroupContainsEntities" /> #> $aliasrefbang = '>'+"$($ref.Alias)"+"!" $newAlias = ('>'+($Catalog.($ref.ID))+'!') $content = ($content -Replace ([regex]::Escape($aliasrefbang)), ([regex]::Escape($newAlias)) ) #$content | Set-Content $MPPath -Force -Encoding UTF8 } # Reload the XML because it was just rewritten #$mpxml = [xml](Get-Content $MPPath) $mpxml = [xml]($content) $arrReferences = $mpxml.GetEnumerator().Manifest.references.reference [int]$i = 0 # Replace aliases in Manifest ForEach ($ref in ($arrReferences) ) { $ref.Alias = $Catalog.($ref.ID) $i++ } Write-Host "`t$i references updated! [ " -NoNewline -b Black -f Cyan Write-Host $(Split-Path -Path $MPPath -Leaf) -NoNewline Write-Host " ]" -b Black -f Cyan $mpxml.Save($MPPath) } } #endFunction ############################################################## <# This function is designed to append (or trim) a unique hash value to/from the aliases (in the Manifest as well as elsewhere in the management pack). This is necessary in the rare cases where existing aliases already match my customized new condensed acronyms in the $cat (catalog). "Windows!" is a good example of this. I've encountered random MPs which have the alias, "Windows" already assigned to a reference. This becomes problematic when I attempt to change references to the 'Microsoft.Windows.Library' after which the file ends up with multiple identical alias references (to different sealed MPs) using the exact same alias, "Windows". This is a clever way to make sure that all aliases are unique (no conflicts). This function should be run twice on the catalog; Once to append the unique string to aliases in the catalog (after the cat has been generated, of course), then modify the files. Then run again to set aliases to their final, desired values, then modify the files again to their final desired values. #> Function Modify-Aliases { Param( [Hashtable]$cat, [Switch]$Localized ) $hash = Get-StringHash $env:COMPUTERNAME If ($Localized){ @($cat.Keys) | ForEach-Object { $Cat[$_] = $cat[$_]+$hash } } Else{ @($cat.Keys) | ForEach-Object { $Cat[$_] = [string]$cat[$_] -Replace $hash, "" } } Return $cat } ############################################################## #http://jongurgul.com/blog/get-stringhash-get-filehash/ Function Get-StringHash { param ( [string] $String, [string] $HashName = "MD5" ) $StringBuilder = New-Object System.Text.StringBuilder [System.Security.Cryptography.HashAlgorithm]::Create($HashName).ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String))|ForEach-Object{ [Void]$StringBuilder.Append($_.ToString("x2")) } $StringBuilder.ToString() } #------------------------------------------------------------- #################### MAIN ################################ ############################################################## # Create catalog of all existing references/aliases # The idea here is to seed the catalog with common pack names. # For other MPs dynamically create aliases based on doted name structure ############################################################## $cat = ConvertFrom-StringData -StringData $seed If (Test-Path -Path $InputPath -PathType Container -ErrorAction SilentlyContinue) { $MPPaths = (Get-ChildItem $InputPath -Recurse -Include *.xml -File ).FullName | Sort-Object Write-Host "$($MPPaths.Count) files found..." -F Yellow -B Black } ElseIf ((Test-Path -Path $InputPath -PathType Leaf -ErrorAction SilentlyContinue) -and ($InputPath -like "*.xml") ) { $MPPaths = $InputPath } Else { Write-Host "Something is wrong with `$InputPath: [$($InputPath)]."; Exit} $refIDs = @() [int]$i=0 ForEach ($MPPath in $MPPaths) { Write-Host $MPPath -F Green $mpxml = [xml](Get-Content $MPPath) #$mpxml.SelectNodes("//Reference") | % { $mpxml.ManagementPack.Manifest.References.Reference | ForEach-Object { $refIDs += $_.ID $_ Write-Progress -Activity "Creating master catalog of known References" -Status $_.ID -PercentComplete ($i / $MPPaths.Count*100) } $i++ } # Create array of all unique IDs $AllRefIDs = ($refIDs | Group-Object ).Name | Sort-Object $AllRefIDs | ForEach-Object { #If ID not in catalog yet, add it with customized alias If ( -not($cat.ContainsKey($_.ToString())) ){ $cat.Add($_,(Create-Alias -Seed $_ -Existing $cat.Values) ) } } # Update all aliases to unique values to prevent naming conflicts when modifying files $cat = Modify-Aliases -Localized:$true -cat $cat Write-Host "Updating references...(first pass, randomized unique values)" -b Black -f Yellow Standardize-AllReferenceAliases -MPPaths $MPPaths -Catalog $cat # Update all aliases to final, correct values, and modify files $cat = Modify-Aliases -Localized:$false -cat $cat Write-Host "Updating references...(final pass)" -b Black -f Green Standardize-AllReferenceAliases -MPPaths $MPPaths -Catalog $cat # Display the reference/alias Catalog $arrCat = @() ForEach ($key in $cat.Keys ){ #Write-Host $key " = " $cat[$key] $arrCat += ("$key = $($cat[$key])" ) } Return ($arrCat | Sort-Object) } |