I was finding the MIB update process painful when in closed environment since MIB database update has to be applied to every Orion server (including HA & APE). Since I had no hope that this feature request would be treated shortly, I made a Power Shell script to address the issue. I hope other Thwacksters will find this helpful 
Please go vote so we don't have to rely on home cooked scripts for this kind of feature that could / should be either embedded into the Orion software, or the MIB installer...
The script will validate that all or your servers are running the same MIB database version, and offers a way to remediate. You have the choice to validate all servers MIB database version against:
- The first server in the list;
- a manually downloaded MIBs.msi file;
- or download the latest file directly from internet if you are allowed to access from your workstation running the script.
Once the check is made, you are presented with a list similar to:

If any discrepancies are found, you can then correct this:

Once file is copied and installation is succeeded, you are then prompted to recheck:


# MIB DB ditribution
# v0.3 / 2020-11-02
# By P Langlois
#Remember to run this script as admin if you are running them directly on one of your Orion Server (otherwise, registry access might no work and throw an error)
#Define the list of Servers you want to connect to, starting by your Main Poller which should have the reference version. Each entry must be
#separated by a coma. Ensure the last entry does not have a coma at the end.
$SwiServers =
"1.1.1.1",
"2.2.2.2",
"3.3.3.3",
"4.4.4.4",
"5.5.5.5",
"6.6.6.6"
$LocalTempFolder = "c:\Windows\Temp\" #Used to extract MSI for validation purposes
$DestinationTempFolder = "c:\Windows\Temp\" #Used to copy the MSI on destination target before installation
$Data = $null #init
$output = $null #init
$WrongCheck = $false #init
$recheck = $null #init
#Asking for validation process:
$title = 'Confirmation Needed'
$question = "How do you want to validate version reference?"
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Usign first server in list')) #0
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Provide file')) #1
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Download')) #2
$validation = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($validation -eq 1) {
#Browsing for file
Add-Type -AssemblyName System.Windows.Forms
$MIBInstaller = New-Object System.Windows.Forms.OpenFileDialog
$MIBInstaller.filter = "Windows installer (*.msi)|*.msi"
$MIBInstaller.Title = "Provide the location of the MIB installer."
[void]$MIBInstaller.ShowDialog()
if ($MIBInstaller.FileName -eq "") {
Write-Host "[WARNING] No file provided. Exiting"
exit
}
else {
$MIBfile = $MIBInstaller.FileName
write-host "[INFO] Analyzing $MIBfile"
}
}
if ($validation -eq 2) {
#Downloading file
$MIBVersionURL = "https://downloads.solarwinds.com/solarwinds/Release/MIB-Database/MIBsVersion.json" #To obtain current online version
$MIBversion = ConvertFrom-Json(Invoke-WebRequest -Uri $MIBVersionURL)
$OnlineVersion = $version.version
if ($null -eq $MIBversion) {
# If unable to fetch:
$ButtonType = [System.Windows.Forms.MessageBoxButtons]::OK
$MessageIcon = [System.Windows.Forms.MessageBoxIcon]::ERROR
$MessageBody = "Unable to obtain current online version of Database. `rDo you have internet access?`r`rCancelling!"
$MessageTitle = "Eror"
$Result = [System.Windows.Forms.MessageBox]::Show($MessageBody, $MessageTitle, $ButtonType, $MessageIcon)
}
else {
$title = 'Confirmation Needed'
$question = "MIBs Database version $OnlineVersion is available. Do you want to download? "
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes')) #0
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No')) #1
$download = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($download -eq 0) {
$Source = "https://downloads.solarwinds.com/solarwinds/Release/MIB-Database/MIBs.msi"
Start-BitsTransfer -Source $source -Destination $LocalTempFolder
$MIBfile = "$LocalTempFolder\MIBs.msi"
write-host "[INFO] Analyzing $MIBfile"
}
else {
break
}
}
}
if ($validation -eq 1 -Or $validation -eq 2) {
#extracting MSI metadata to obtain file version poorly encoded by Solarwinds.
#inspired by https://evotec.xyz/getting-file-metadata-with-powershell-similar-to-what-windows-explorer-provides/
$MetaDataObject = [ordered] @{} #init
$FileInformation = Get-ItemProperty -Path $MIBfile
$ShellApplication = New-Object -ComObject Shell.Application
$ShellFolder = $ShellApplication.Namespace($FileInformation.Directory.FullName)
$ShellFile = $ShellFolder.ParseName($FileInformation.Name)
$MetaDataProperties = [ordered] @{}
0..400 | ForEach-Object -Process {
$DataValue = $ShellFolder.GetDetailsOf($null, $_)
$PropertyValue = (Get-Culture).TextInfo.ToTitleCase($DataValue.Trim()).Replace(' ', '')
if ($PropertyValue -ne '') {
$MetaDataProperties["$_"] = $PropertyValue
}
}
foreach ($Key in $MetaDataProperties.Keys) {
$Property = $MetaDataProperties[$Key]
$Value = $ShellFolder.GetDetailsOf($ShellFile, [int] $Key)
if ($Property -in 'Attributes', 'Folder', 'Type', 'SpaceFree', 'TotalSize', 'SpaceUsed') {
continue
}
If (($null -ne $Value) -and ($Value -ne '')) {
$MetaDataObject["$Property"] = $Value
}
}
$MSIversion = ($MetaDataObject.Subject).Replace("SolarWinds MIBs v", "")
#extracting MSI to obtain database size once deflated :
Start-Process "MSIEXEC" -ArgumentList "/a $MIBFile /qn TARGETDIR=$LocalTempFolder" -Wait -NoNewWindow #extracting MIB file
$MIBFile = $LocalTempFolder + "SolarWinds\MIBs.cfg"
$MIBSize = (get-item $MIBFile).Length
}
#Asking for Hash validation or not:
$title = 'Confirmation Needed'
$question = "Do you want to calculate the hash of MIB file for each server? `rThis might take a few minutes per server to execute..."
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes')) #0
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No!')) #1
$checkhash = $Host.UI.PromptForChoice($title, $question, $choices, 1)
function get-MIBDBStatus {
$Script:MIBFiles = @() #init
$index = 0 #init
$Hash = $null #init
$result = $null #init
$destination = $Server.source
$RegistryKeyPath = 'SOFTWARE\WOW6432Node\SolarWinds\Orion\MIBs' #Where MIB version is stored in remote server
$MIBFileLocation = "\\$server\c$\ProgramData\SolarWinds\MIBs.cfg" #Location of MIB database.
$ValueName = 'Version'
if ($validation -eq 1 -OR $validation -eq 2) {
if ($checkhash -eq 0) {
$hash = (Get-FileHash $MIBFileLocation).hash
}
else {
$hash = "n/a"
}
$result = [pscustomobject]@{
index = $index
source = "MSI FILE"
file = $MIBFile
hash = $Hash
size = $MIBSize
Version = $MSIversion
VersionCheck = "Reference"
SizeCheck = "Reference"
HashCheck = "Reference"
}
$Script:MIBFiles += $result
$index++
}
foreach ($Server in $SwiServers) {
Write-Output "[INFO] Connecting to $Server"
if (-not (Test-Connection -BufferSize 32 -Count 1 -ComputerName $Server -Quiet)) {
#Checking with a ping if the server is reachable
Write-Host "[ERROR] Unable to connect to $Server" -ForegroundColor Red
}
else {
if (-not (Test-Path -Path $MIBFileLocation)) {
#Checking if file is available on the PC.
Write-Host "[WARNING] Path is unavailable on $Server" -ForegroundColor Red
}
else {
Write-Output "[INFO] Please wait, collecting MIB file information on $Server"
if ($checkhash -eq 0) {
$hash = (Get-FileHash $MIBFileLocation).hash
}
else {
$hash = "n/a"
}
$MIBSize = (get-item $MIBFileLocation).Length
#Connecting to remote registry to grab version information:
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server)
$key = $reg.OpenSubKey($RegistryKeyPath)
$Data = $key.GetValue($ValueName)
$result = [pscustomobject]@{
index = $index
source = $Server
file = $MIBFileLocation
hash = $Hash
size = $MIBSize
Version = $Data
VersionCheck = $null
SizeCheck = $null
HashCheck = $null
}
$Script:MIBFiles += $result
}
}
$index++
}
#Grabbing reference from first server (index #1)
$targetHash = ($MIBFiles | Where-Object { $_.index -eq 0 }).hash
$targetRegistry = ($MIBFiles | Where-Object { $_.index -eq 0 }).Version
$targetSize = ($MIBFiles | Where-Object { $_.index -eq 0 }).Size
#Adding validation to table
foreach ($m in $MIBFiles) {
if ($m.index -eq 0) {
$m.VersionCheck = "Reference"
$m.SizeCheck = "Reference"
if ($checkhash -eq 0) {
$m.HashCheck = "Reference"
}
}
else {
if ($m.Version -eq $targetRegistry) {
$m.VersionCheck = 'OK'
}
else {
$m.VersionCheck = 'WRONG'
}
if ($checkhash -eq 0) {
if ($m.hash -eq $targethash) {
$m.HashCheck = 'OK'
}
else {
$m.HashCheck = 'WRONG'
}
}
if ($m.size -eq $targetSize) {
$m.SizeCheck = 'OK'
}
else {
$m.SizeCheck = 'WRONG'
}
}
}
#Display the results:
if ($checkhash -eq 0) {
$Script:output = $MIBFiles | Select-Object * -ExcludeProperty file | Format-Table
}
else {
$Script:output = $mibfiles | Select-Object * -ExcludeProperty file, hash, HashCheck | Format-Table
}
$output | Out-String -Stream | ForEach-Object {
$fgArg = if ($_ -match 'WRONG') { @{ 'ForegroundColor' = 'Red' } } else { @{} }
Write-Host @fgArg $_
}
}
get-MIBDBStatus
if ($MIBFiles.VersionCheck -contains 'WRONG' -Or $MIBFiles.SizeCheck -contains 'WRONG' -Or $MIBFiles.HashCheck -contains 'WRONG') {
$WrongCheck = $true
#Asking if we should attempt to fix the issue:
$title = 'Confirmation Needed'
$question = "There are failed validations. Do you want to copy the file to the affected server(s) and recheck? Requires WINRM"
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No!'))
$fixOrNot = $Host.UI.PromptForChoice($title, $question, $choices, 1)
IF ($fixOrNot -eq 0) {
#building a list of servers to deploy to:
$toFix = $MIBFiles | Where-Object { $_.VersionCheck -eq 'WRONG' }
$TargetCreds = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME")
foreach ($server in $toFix) {
$tempfolder = $DestinationTempFolder
$destination = $tempfolder + $MIBInstaller.SafeFileName
$log = $tempfolder + 'MIB_deploy.txt'
$servername = $server.source
write-host "[INFO]Attempting connection on $Servername"
$session = New-PSSession -ComputerName $servername -Credential $TargetCreds
Copy-Item -Path $MIBInstaller.FileName -ToSession $session -Destination $destination
$command = {
param($destination, $log)
Start-Process -FilePath msiexec -ArgumentList "/i $destination /quiet /log $log" -Wait
}
Invoke-Command -Session $session -ScriptBlock $command -ArgumentList $destination, $log
}
Remove-PSSession $session
$session = $null
}
}
if ($WrongCheck -eq $true) {
#Asking if we should recheck MIB information:
$title = 'Confirmation Needed'
$question = "There were failed validations. Do you want to recheck if servers were properly fixed?"
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No!'))
$recheck = $Host.UI.PromptForChoice($title, $question, $choices, 1)
IF ($recheck -eq 0) {
get-MIBDBStatus
}
else {
exit
}
}
I do not have the pretension of being a developer. Please review code before using it. Any comments are welcome!