Last active
August 13, 2019 05:29
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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