Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
You can’t perform that action at this time.