Nov 23, 2009

System Center Operations Manager: Version Control


The current version of System Center Operations Manager 2007 doesn’t use version control for management packs. If you manage complex environments and use lot of custom monitoring, it would be nice to see when there is something changed and even better: easily fall back to your previous version in case an error slipped in. Another benefit of version control is you have exported management packs ready to import in other environments: i.e. between acceptance and production or between customers in case you are managing multiple customers like we do.

I’ve written some scripts to automatically export all your unsealed management packs if there is something changed, write a version number and email the new managementpack with a summary of all differences.
Another script will import your version controlled management packs (if there is something changed).
Scripts are updated on 12-11-2009

To setup version control for Management Packs, you need the following:
- ExportUnsealedMPs.ps1
- ExportUnsealedMPs_Simple.ps1
- ImportMPs.ps1
- SCOMSettings.xml
- A folder structure to save management packs
- SVN and TortoiseSVN
Folder Structure
SVN\SCOM
Scripts
SVNControlledMPs
UnsealedMPs
– diff
– temp
– test1
– test2
SVN
SVN is needed to do commits directly from within the script. TortoiseSVN helps you to commit, update and compare files within the Explorer.
Setup
After you setup SVN and Tortoise SVN and created the folder structure. You can create scheduled tasks to run the import and export jobs. It is a good idea to run the export at the end of the day to capture all changes of that day, I export them at 19:00.
Best time to import the management packs is 13:30, you don’t want to get suprised at night if some import causes pages.
First run ExportUnsealedMPs_Simple.ps1 to get all unsealed management packs without version control.
Commit your Unsealed Folder in SVN (before you do that, make sure you have marked xml files as text:
Edit Tortoise Settings file, add the following lines
Under [miscellany]:
enable-auto-props = yes
Under [auto-props]:
*.xml = svn:mime-type=text/xml;svn:eol-style=native;svn:keywords=Rev Date
Run the export job, it should not export anything, since you are up-to-date.
Change something in a management pack, update a description will do.
Run the export job again, you should see it is updated, committed and an email is sent to the address mentioned in your settings file..
ExportUnsealedMPs.ps1
#########################################################################################
# #
# Author: Jan Jacob Bos #
# Date: 17-01-2009 #
# Version: 1.5 #
# #
# Usage: ExportUnsealedMPs #
# #
# Purpose: Script to export unsealed management packs with version control #
# Only if something is changed the version number is increased and #
# management pack is saved, committed in SVN and emailed #
# #
#########################################################################################
# initialize settings from config file
$xmlSettings=[xml](get-content “.\SCOMSettings.xml”)
$ServerName = $xmlSettings.SCOMSettings.General | %{$_.RootMS} | select-object -unique
$targetFilePath = $xmlSettings.SCOMSettings.General | %{$_.ExportFolder} | select-object -unique
$SMTPServer = $xmlSettings.SCOMSettings.Mail | %{$_.SMTPServer} | select-object -unique
$From = $xmlSettings.SCOMSettings.Mail | %{$_.From} | select-object -unique
$To = $xmlSettings.SCOMSettings.Mail | %{$_.To} | select-object -unique
#Initializing the Ops Mgr 2007 Powershell provider
add-pssnapin “Microsoft.EnterpriseManagement.OperationsManager.Client” -ErrorVariable errSnapin ;
set-location “OperationsManagerMonitoring::” -ErrorVariable errSnapin ;
new-managementGroupConnection -ConnectionString:$Servername -ErrorVariable errSnapin ;
set-location $Servername -ErrorVariable errSnapin ;
# initializing variables
$Differences1 = “”
$Differences2 = “”
$VersionFirstpartCurrent = 0
$RevisionCurrent = 0
$VersionFirstpartFile = 0
$RevisionFile = 0
# Defining Functions
function ExternalCommand([string]$Command, [string]$Parameter)
{ $StartInfo = new-object System.Diagnostics.ProcessStartInfo
$StartInfo.FileName = $Command
$StartInfo.Arguments = $Parameter
$StartInfo.LoadUserProfile = $true
$StartInfo.UseShellExecute = $false
# Execute command
$proc = [System.Diagnostics.Process]::Start($StartInfo)
# Wait for command to finish
$proc.WaitForExit()
}
function GetRevision {param ([string]$VersionNo, [REF]$VersionFirstpartOUT, [REF]$RevisionOUT)
# look for last dot in version number (is always in format: 1.0.0.0) we only change last number (revision)
[int]$count = $VersionNo.length – ($VersionNo.LastIndexOf(”.”) + 1)
[int]$LastDot = $VersionNo.length – $count
$VersionFirstpartOUT.Value = $versionNo.substring(0, $LastDot)
[int]$RevisionOUT.Value = $VersionNo.substring($LastDot , $count)
}
function SendMail {param ([string]$Subject, [string]$Message, $Attachment)
# send mail
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = $From
$msg.To.Add($To)
$msg.Subject = $Subject
$msg.Body = $Message
if ($Attachment -ne “”)
{ $att = new-object Net.Mail.Attachment($Attachment)
$msg.Attachments.Add($att)
}
$smtp.Send($msg)
if ($Attachment -ne “”) {$att.Dispose()}
}
# get all unsealed management packs
$mps = get-managementpack | where-object {$_.Sealed -eq $false -and $_.ContentReadable -eq $true}
foreach($mp in $mps)
{ $ID = $mp.Name
$FileName = $ID + “.xml”
# Determine Revision Number from current MP
GetRevision $mp.version ([REF]$VersionFirstpartCurrent) ([REF]$RevisionCurrent)
# Retrieve the MP currently stored
# trap {”File not found ” -f $_.Exception.Message}
# $fileExists = [system.IO.File]::Exists($targetFilePath + “\” + $Filename)
# If File doesn’t exist, it is a new management pack
# write-host “Filename: $fileExists ”
if (-not [system.IO.File]::Exists($targetFilePath + “\” + $Filename))
{ # write-host “Filename (within IF) $ID Version: $VersionFirstpartCurrent$RevisionCurrent”
$NewFileName = $targetFilePath + “\” + $FileName
export-managementpack -managementpack $mp -path $targetFilePath
ExternalCommand (”"”C:\Program Files\SVN\bin\svn.exe”"”) (” add “”$NewFilename”"”)
ExternalCommand (”"”C:\Program Files\SVN\bin\svn.exe”"”) (” commit -m “”$ID Version: $VersionFirstpartCurrent$revisionCurrent”" “”$NewFilename”"”)
# Send mail a new managementpack has been exported
write-host “a new managementpack has been exported”
$MailContent = “A new Management Pack: $Filename with Version $VersionFirstpartCurrent$revisionCurrent has been exported”
SendMail “New managementpack $Filename on $Servername in repository” $MailContent “”
}
else
{
$FileSavedMP = [system.IO.Directory]::GetFiles($targetFilePath, $Filename)
# write-host “Filename: $FileSavedMP”
# we need the file in xml format to get version info
$xmlSavedMP=[xml](get-content $FileSavedMP)
# we need the the file in text format to compare it with the current version
$txtSavedMP=(get-content $FileSavedMP)
# get version number from xml file
$xmlSavedMP.selectnodes(”/ManagementPack/Manifest/Identity”)|foreach {
$_.selectnodes(”Version”) | foreach {
$versionFile = $_.get_InnerText()
write-host $ID $versionFile
# Determine Revision Number from file
GetRevision $versionfile ([REF]$VersionFirstpartFile) ([REF]$RevisionFile)
# check to see if version number is greater than the saved file
write-host “Revision Current version ” $RevisionCurrent
write-host “Revision Saved Version ” $RevisionFile
# if ($mp.version -gt $versionFile)
if ($RevisionCurrent -gt $RevisionFile)
# Current version number is higher, probably imported from another customer
{ $NewFileName = $targetFilePath + “\” + $FileName
export-managementpack -managementpack $mp -path $targetFilePath
ExternalCommand (”"”C:\Program Files\SVN\bin\svn.exe”"”) (” commit -m “”$ID Version: $VersionFirstpartFile$revisionFile”" “”$NewFilename”"”)
# Send mail a newer version is exported
write-host “a newer version is exported”
$MailContent = “Management Pack: $Filename with Version $VersionFirstpartCurrent$revisionCurrent has been updated in the repository”
SendMail “Updated $Filename on $Servername in repository” $MailContent “”
}
if ($RevisionCurrent -lt $RevisionFile)
{ # Send mail could not export because saved file has higher revision number
write-host “could not export because saved file has higher revision number”
$MailContent = “Management Pack: $Filename with Version $VersionFirstpartFile$revisionFile could not be exported”
SendMail “coud not export because saved file has higher revision number on $Servername” $MailContent “”
}
# if version number is equal then we need to check if mgmt pack is changed
if ($RevisionCurrent -eq $RevisionFile)
{ write-host “check if MP is changed”
$TargetFilePathTemp = $targetFilePath + “\temp”
export-managementpack -managementpack $mp -path $targetFilePathTemp
$FileCurrentMP = [system.IO.Directory]::GetFiles($targetFilePathTemp, $Filename)
$xmlCurrentMP = [xml](get-content $FileCurrentMP)
$txtCurrentMP = (get-content $FileCurrentMP)
# Check if MP is changed
# write-host “Current MP Size” $FileCurrentMP.Size
# Write-host “Saved Mp Size” $FileSavedMP.Size
$TargetFilePathTest1 = $targetFilePath + “\test1\”
$TargetFilePathTest2 = $targetFilePath + “\test2\”
set-content -Encoding “Unicode” -Path $TargetFilePathTest1$Filename $txtCurrentMP
set-content -Encoding “Unicode” -Path $TargetFilePathTest2$Filename $txtSavedMP
# set-content -Path $TargetFilePathTest1$Filename $txtCurrentMP
# set-content -Path $TargetFilePathTest2$Filename $txtSavedMP
compare-object $txtCurrentMP $txtSavedMP |foreach{
if ($_.SideIndicator -eq “< =") {[string]$Differences1 = $Differences1 + $($_.InputObject)}
if ($_.SideIndicator -eq "=>“) {[string]$Differences2 = $Differences2 + $($_.InputObject)}
}
# if difference is empty, there are no changes
if ($Differences1 -ine “” -or $Differences2 -ine “”)
{ # MP is changed, we need to increment the version number
write-host “Changes found”
# read information from management pack
$xmlCurrentMP.selectnodes(”/ManagementPack/Manifest/Identity”)|foreach {
$_.selectnodes(”Version”) | foreach {
[int]$revision = $revisionFile
$revision++
$NewVersion = $VersionFirstpartFile + $revision
write-host “new version $NewVersion”
# write new version number to file
$_.set_InnerText($NewVersion)
$NewFileName = $targetFilePath + “\” + $FileName
$xmlCurrentMP.save($NewFileName)
# write new version number to managementpack
$mp.set_Version($NewVersion)
$mp.AcceptChanges()
# new-item -ItemType file -force $NewFileName -value $xmlCurrentMP
# $xmlCurrentMP | Export-Clixml $NewFileName
# set-content -Encoding “Unicode” -Path $NewFileName $xmlCurrentMP
# commit changes in SVN
ExternalCommand (”"”C:\Program Files\SVN\bin\svn.exe”"”) (” commit -m “”$ID Version: $VersionFirstpartFile$revision”" “”$NewFilename”"”)
[string]$DiffFile = $targetFilePath + “\diff\$ID.txt”
# Get differences from SVN
ExternalCommand (”cmd.exe”) (”/c “”C:\Program Files\SVN\bin\svn.exe”" diff $NewFilename -r PREV >$DiffFile”)
# get changes since last version stored in SVN
[string]$DiffContentent = (get-content $DiffFile)
# send mail
$MailContent = “Management Pack: $Filename Version MP: $NewVersion $DiffContentent”
SendMail “New updates available on $Servername” $MailContent $NewFileName
# clean up
$Differences1 = “”
$Differences2 = “”
}
}
}
}
}
}
}
}
ExportUnsealedMPs_Simple.ps1
param ($ServerName)
add-pssnapin “Microsoft.EnterpriseManagement.OperationsManager.Client”;
set-location “OperationsManagerMonitoring::”;
new-managementGroupConnection -ConnectionString:$ServerName;
set-location $ServerName;
$mps = get-managementpack | where-object {$_.Sealed -eq $false}
foreach($mp in $mps)
{
export-managementpack -managementpack $mp -path “E:\SVN\SCOM\UnsealedMPs”
}
ImportMPs.ps1
#########################################################################################
# Date: 17-01-2009        �
# Version: 1.0         �
#          �
# Usage:    ImportMPs         �
#         �
# Purpose:  Script to import management packs with version control  �
#     Only if a newer version is available the management pack is  �
#  imported and an email is sent     �
#           �
#########################################################################################
# initialize settings from config file
$xmlSettings=[xml](get-content “.\SCOMSettings.xml”)
$ServerName = $xmlSettings.SCOMSettings.General | %{$_.RootMS} | select-object -unique
$Folder = $xmlSettings.SCOMSettings.General | %{$_.SVNControlledFolder} | select-object -unique
$SMTPServer = $xmlSettings.SCOMSettings.Mail | %{$_.SMTPServer} | select-object -unique
$From = $xmlSettings.SCOMSettings.Mail | %{$_.From} | select-object -unique
$To = $xmlSettings.SCOMSettings.Mail | %{$_.To} | select-object -unique
add-pssnapin “Microsoft.EnterpriseManagement.OperationsManager.Client”;
set-location “OperationsManagerMonitoring::”;
new-managementGroupConnection -ConnectionString:$ServerName;
set-location $ServerName;
$SmtpClient = new-object system.net.mail.smtpClient
$SmtpClient.host =
$SmtpServer
$Files = [system.IO.Directory]::GetFiles($Folder, “*.xml”)
foreach($File in $Files) {
Write-host “Importing ” $File
$xml=[xml](get-content $File)
$xml.selectnodes(”/ManagementPack/Manifest”)|foreach {
$_.selectnodes(”Identity/Version”) | foreach {
# Check version number MP to import
$versionFile =  $_.get_InnerText()
[int]$countFile = $versionfile.length – ($versionFile.LastIndexOf(”.”) + 1)
[int]$LastDotFile = $versionfile.length – $countFile
[int]$revisionFile = $versionFile.substring($LastDotFile , $countFile)
}
$_.selectnodes(”Name”) | foreach {
$NameFile = $_.get_InnerText()
}
}
write-host “versionFile” $revisionFile
write-host “NameFile” $NameFile
$mps = get-managementpack | where-object {$_.displayname -like $NameFile}
foreach($mp in $mps) {
# Check version number current MP
[string]$VersionMP = $mp.version
[int]$countMP = $versionMP.length – ($versionMP.LastIndexOf(”.”) + 1)
[int]$LastDotMP = $versionMP.length – $countMP
[int]$revisionMP = $versionMP.substring($LastDotMP , $countMP)
write-host “versionMP” $revisionMP
if($revisionFile -gt $revisionMP){
# “File Newer, we can import”
# need to set trap, to determine if import is successful
trap {   ‘Error Category {0}, Error Type {1}, ID: {2}, Message: {3}’ -f
$_.CategoryInfo.Category, $_.Exception.GetType().FullName,
$_.FullyQualifiedErrorID, $_.Exception.Message;   continue }
install-managementpack $File
if ($error) {
$Title = “Something went wrong with import of $NameFile”
$Body = “Name File $NameFile revision $revisionFile The Error message is: $error[0].Exception.Message”
$SmtpClient.Send($from,$to,$title,$Body) �
}
else {  �
$Title = “New updates are imported on $ServerName”
$Body = “Name File ” + $NameFile + ” revision ” + $revisionFile
$SmtpClient.Send($from,$to,$title,$Body)
}
}
if($revisionFile -lt $revisionMP){
$Title = “Update of management pack failed, because of version conflict”
$Body =  “Name File $NameFile  revision saved file $revisionFile Revision current MP $revisionMP”
$SmtpClient.Send($from,$to,$title,$Body)
}
}
}
SCOMSettings.xml


SCOMSERVER
DRIVE:\SVN\SCOM\UnsealedMPs
<DRIVE>\SVN\SCOM\SVNControlledMPs


MAILSERVER
FROM
TO


No comments:

Post a Comment