Skip to content

Instantly share code, notes, and snippets.

@darrenjrobinson
Last active August 13, 2019 05:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darrenjrobinson/dfe3f20786334a950214e1f4b74a41dd to your computer and use it in GitHub Desktop.
Save darrenjrobinson/dfe3f20786334a950214e1f4b74a41dd to your computer and use it in GitHub Desktop.
Export and document MIM Configuration, generate Static WebPage with MIM Export and Config. Associated blogpost https://blog.darrenjrobinson.com/automated-microsoft-identity-manager-configuration-backups-documentation-to-azure/
# Import LithnetMIISAutomation for MIM Sync Server Config Exports
Import-Module lithnetmiisautomation
# Find the MA's
$managementagents = Get-ManagementAgent
write-host -ForegroundColor green "$($managementagents.Count) management agents found"
# Local Backup Path
$BackupPath = "G:\Backup"
$foldername = Get-Date -format dd-MM-yyyy-hh-mm
$outputfilepath = "$BackupPath\$foldername"
# Azure Storage Account
$AzureStorageURI = "YOURSTORAGEACCOUNT.blob.core.windows.net" # e.g mystorageaccount.blob.core.windows.net
# Azure Static Website Address
$AzureStaticWebURI = "YOURSTORAGEACCOUNT.z6.web.core.windows.net" # e.g mystorageaccount.z6.web.core.windows.net
# Create Backup Folders
if (!(Test-Path $outputfilepath)) {
$BackupFolder = New-Item -Path $outputfilepath -Type Directory
# MA Exports
$MAExports = New-Item -Path "$outputfilepath\MAExports" -Type Directory
# Extensions Exports
$MAExtensions = New-Item -Path "$outputfilepath\MAExtensions" -Type Directory
# SyncExport Exports
$SyncServer = New-Item -Path "$outputfilepath\ServerExport" -Type Directory
# Portal Config
$PortalExport = New-Item -Path "$outputfilepath\PortalExport" -Type Directory
}
# Export MA's
foreach ($ma in $managementagents.name) {
Export-ManagementAgent -File ($MAExports.FullName + "\$ma.xml") -MA $ma
}
# Export Sync Server
Export-MetaverseConfiguration -Path $SyncServer.FullName
# Copy Extensions
$extlocation = get-itemproperty "hklm:\software\microsoft\forefront identity manager\2010\synchronization service" -erroraction stop | Select-Object -expand location
$extensionsfolder = join-path $extlocation "Synchronization Service"
$extensionsfolder = join-path $extensionsfolder "Extensions"
Copy-Item "$extensionsfolder\*" $MAExtensions.fullname -recurse -Force
# Portal
add-pssnapin FIMAutomation
# Update if MIM Service isn't on the same host in your Dev environ
$portalConfig = Export-FIMConfig -uri http://localhost:5725/ResourceManagementService -portalConfig
$portalConfig | ConvertFrom-FIMResource -file ($PortalExport.FullName + "\PortalConfig.xml")
# Compress Backup
if (!(Test-Path "$($BackupPath)\Compressed")) {
New-Item -Path "$($BackupPath)\Compressed" -Type Directory
Compress-Archive -Path $outputfilepath -DestinationPath "$($BackupPath)\Compressed\$($foldername).zip"
}
else {
Compress-Archive -Path $outputfilepath -DestinationPath "$($BackupPath)\Compressed\$($foldername).zip"
}
# Copy to Azure Blob Storage
azcopy login --identity
$mimBackupCopyResult = (azcopy cp "$($BackupPath)\Compressed\$($foldername).zip" "https://$($AzureStorageURI)/`$web/Configs/$($foldername).zip" --output-type json) | convertfrom-json
$mimBackupCopyExitCode = $mimBackupCopyResult | Select-Object | Where-Object { $_.MessageType -eq "Exit" }
if (($mimBackupCopyExitCode.MessageContent | ConvertFrom-Json).JobStatus -ne "Completed") {
# try copy again
$mimBackupCopyResult = $null
$mimBackupCopyExitCode = $null
$mimBackupCopyResult = (azcopy cp "$($BackupPath)\Compressed\$($foldername).zip" "https://$($AzureStorageURI)/`$web/Configs/$($foldername).zip" --output-type json) | ConvertFrom-Json
$mimBackupCopyExitCode = $mimBackupCopyResult | Select-Object | Where-Object { $_.MessageType -eq "Exit" }
if (($mimBackupCopyExitCode.MessageContent | ConvertFrom-Json).JobStatus -ne "Completed") {
[boolean]$mimBackupCopySuccess = $false
}
else {
[boolean]$mimBackupCopySuccess = $true
}
}
else {
[boolean]$mimBackupCopySuccess = $true
}
# MIM Documentor
$MIMDocumenterPath = "C:\Customer\MIMDoco"
$MIMDocumenterScript = '\InvokeDocumenter-CustomerDev.ps1'
$MIMDocoFoldername = Get-Date -format dd-MM-yyyy;
$ReportPrefix = "$($MIMDocumenterPath)\Report\Customer_Dev_$($MIMDocoFoldername)"
$MIMDocoOutputfilepath = "$($MIMDocumenterPath)\Data\Customer\Dev\$($MIMDocoFoldername)"
$BackupFolder = New-Item -Path $MIMDocoOutputfilepath -Type Directory
# SyncServer Config Export
$MIMDocoSyncServer = New-Item -Path "$MIMDocoOutputfilepath\SyncConfig" -Type Directory
# Portal Config Exports
$MIMDocoPortalExport = New-Item -Path "$MIMDocoOutputfilepath\ServiceConfig" -Type Directory
# Portal Schema
# Update if MIM Service isn't on the same host in your Dev environ
$portalSchema = Export-FIMConfig -uri http://localhost:5725/ResourceManagementService -schemaConfig -customConfig "/SynchronizationFilter"
$portalSchema | ConvertFrom-FIMResource -file "$($MIMDocoPortalExport.Fullname)\Schema.xml"
# Portal Policy
# Update if MIM Service isn't on the same host in your Dev environ
$portalPolicy = Export-FIMConfig -uri http://localhost:5725/ResourceManagementService -policyConfig -portalConfig -MessageSize 9999999 ;
$portalPolicy | ConvertFrom-FIMResource -file "$($MIMDocoPortalExport.Fullname)\Policy.xml"
# Copy Sync Config previously exported for Doco Generation
Copy-item "$($SyncServer.FullName)\*.*" -Recurse "$MIMDocoOutputfilepath\SyncConfig"
# Generate the Report
invoke-expression -Command "$($MIMDocumenterPath)$($MIMDocumenterScript)"
# Create Report Directory
$Report = New-Item -Path "$MIMDocoOutputfilepath\Report" -Type Directory
# Copy the Report to the folder associated with the configs
Copy-Item "$($ReportPrefix)_AppliedTo_MIM-SP1-Base_4.4.1459.0_Consolidated_report.html" "$($MIMDocoOutputfilepath)\Report"
$ReportDetails = Get-Item "$($ReportPrefix)_AppliedTo_MIM-SP1-Base_4.4.1459.0_Consolidated_report.html"
$ReportSize = [math]::Round(($ReportDetails.Length / 1MB), 3)
# Copy Report to Azure Storage Static WebSite
azcopy cp "$($ReportPrefix)_AppliedTo_MIM-SP1-Base_4.4.1459.0_Consolidated_report.html" "https://$($AzureStorageURI)/`$web/Reports/$($ReportDetails.Name)"
$mimReportCopyResult = (azcopy cp "$($ReportPrefix)_AppliedTo_MIM-SP1-Base_4.4.1459.0_Consolidated_report.html" "https://$($AzureStorageURI)/`$web/Reports/$($ReportDetails.Name)" --output-type json) | convertfrom-json
$mimReportCopyExitCode = $mimReportCopyResult | Select-Object | Where-Object { $_.MessageType -eq "Exit" }
if (($mimReportCopyExitCode.MessageContent | ConvertFrom-Json).JobStatus -ne "Completed") {
# try copy again
$mimReportCopyResult = $null
$mimReportCopyExitCode = $null
$mimReportCopyResult = (azcopy cp "$($ReportPrefix)_AppliedTo_MIM-SP1-Base_4.4.1459.0_Consolidated_report.html" "https://$($AzureStorageURI)/`$web/Reports/$($ReportDetails.Name)" --output-type json) | convertfrom-json
$mimReportCopyExitCode = $mimBackupCopyResult | Select-Object | Where-Object { $_.MessageType -eq "Exit" }
if (($mimReportCopyExitCode.MessageContent | ConvertFrom-Json).JobStatus -ne "Completed") {
[boolean]$mimReportCopySuccess = $false
}
else {
[boolean]$mimReportCopySuccess = $true
}
}
else {
[boolean]$mimReportCopySuccess = $true
}
# Get a list of the Reports and Configs in Blob Storage
$listReports = (azcopy list "https://$($AzureStorageURI)/`$web/Reports" --output-type json) | convertfrom-json
$listConfigs = (azcopy list "https://$($AzureStorageURI)/`$web/Configs" --output-type json) | ConvertFrom-Json
# Generate Index.html Header
$tableHeader = @"
<html>
<body>
<style>
h1 {
text-align: center;
font-family: Segoe UI;
}
h2,
th {
text-align: center;
}
table {
margin: auto;
font-family: Segoe UI;
box-shadow: 10px 10px 5px #888;
border: thin ridge grey;
}
th {
background: #17a2e2;
color: #fff;
max-width: 400px;
padding: 5px 10px;
}
td {
font-size: 11px;
padding: 5px 20px;
color: #000;
}
tr {
background: #85d1f0;
}
tr:nth-child(even) {
background: #beebf7;
}
tr:nth-child(odd) {
background: #a0d7f7;
}
</style>
<H1>Microsoft Identity Manager Configuration Reports</H1>
<table>
<thead>
<tr>
<th>Report Date</th>
<th>Report</th>
<th>Size</th>
<th>Config</th>
<th>Size</th>
</tr>
</thead>
<tbody>
"@
$ReportTemplate = [pscustomobject][ordered]@{
ReportDate = $null
Report = $null
ReportSize = $null
Config = $null
ConfigSize = $null
}
# Generate index.html Body with content from Azure Static Website
$htmlTableBody = $null
if ($listReports.Count -eq $listConfigs.Count) {
[int]$configCount = $listReports.Count
[int]$row = 0
do {
$row++
# Config
if ($listConfigs[$row].MessageContent -ne "INFO: List is using OAuth token for authentication." -and $listConfigs[$row].MessageType -ne "Exit" -and $listReports[$row].MessageContent -ne "INFO: List is using OAuth token for authentication." -and $listReports[$row].MessageType -ne "Exit") {
$configContent = $null
$reportContent = $null
try {
$tEntry = $ReportTemplate.PsObject.Copy()
[array]$configContent = ($listConfigs[$row].MessageContent.Replace("INFO: ", $null).split(";") )
$configFilename = $configContent[0]
$configFileSize = $configContent[1].ToString().Replace("Content Size: ", $null)
$tEntry.ConfigSize = $configFileSize
$tEntry.Config = $configFilename
[array]$reportContent = ($listReports[$row].MessageContent.Replace("INFO: ", $null).split(";") )
$reportFilename = $reportContent[0]
$reportFileSize = $reportContent[1].ToString().Replace("Content Size: ", $null)
$tEntry.ReportSize = $reportFileSize
$tEntry.Report = $reportFilename
$arrExportsDate = ($configFilename.Replace(".zip", "")).Split("-")
$extractDate = [datetime]::parseexact("$($arrExportsDate[0])-$($arrExportsDate[1])-$($arrExportsDate[2])", 'dd-MM-yyyy', $null)
$tEntry.ReportDate = $extractDate
$indexContent += $tEntry
}
catch {
# bad data in Storage Account ?
}
}
} until ($row -eq $configCount)
# Sort by Date
$indexContent = $indexContent | Sort-Object -Property ReportDate -Descending
# Build Table Contents
$htmlTableBody = $null
foreach ($reportDetails in $indexContent) {
$reportDate = $reportDetails.ReportDate.ToString().Replace(" 12:00:00 AM","")
$htmlTableBody += "<tr><td>$($reportDate)</td><td><a target='_blank' href='https://$($AzureStaticWebURI)/Reports/$($reportDetails.Report)'>MIM Config Report</a></td><td>$($reportDetails.ReportSize)</td><td><a target='_blank' href='https://$($AzureStaticWebURI)/Configs/$($reportDetails.Config)'>MIM Config Backup</a></td><td>$($reportDetails.ConfigSize)</td></tr>"
}
# Close the html document
$htmlTableBody += "</tbody></table></body></html>"
# Join the HTML Fragments
$tableHeader + $htmlTableBody | Out-File "$($BackupFolder.FullName)\index.html"
# Copy new Index.html page to Blob Storage
azcopy cp "$($BackupFolder.FullName)\index.html" "https://$($AzureStorageURI)/`$web/index.html"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment