Get Server's OOBM IP (iLO, iDrac, iRMC etc.) remotely with PowerShell

So, there comes a time in every sysadmin's life when they need to make inventory of hardware servers and no one knows what the IP address for the OOBM devices is anymore. Their DNS records are rarely setup, and the major problem is of course, that you have 1000+ different servers from a variety of manufacturers, be it Dell, HP, IBM, Fujitsu etc.

Gotta love Mr. Happy Engineer :), night is long and coffee is cheap.


The OOBM systems  go by different proprietary names depending on the manufacturer, HP: iLO, Dell: iDRAC, Fujitsu: iRMC, IBM: IMM and so on.

Each manufacturer has their propietary tools and there's lots of complicated ways to get the OOBM's device IP address, usually by browsing the server's manufacturer management web tools, using modules requiring specific providers or using their MS-DOS tools (e.g. hpasmcli or racadm).

I tried many options, including RedFish and ipmi, but the clear winner is the method from Michael Albert's blog that reaches out to the  BMC (Baseboard Management Controller) from the OS, via good old WMI.

What's really sweet about it, is that the MICROSOFT_IPMI class is manufacturer agnostic, I was able to pull the IP and MAC addresses from all the HW Windows devices I reached, it worked against Windows Server 2003 up to 2012R2 OS servers, as well as HP, Dell, Fujitsu and IBM machines.

Michael's script is pretty neat and has done all the heavy lifting for us, he even mentions in his post that since it's a wmi cmdlet, we can just use "-computername" to run it against remote machines.

I've taken his advice and created a quick & dirty wrap, my version added the following features:

<#
Name: Get-OOBMIP.ps1
Date: June 15th, 2018
Created by: Michael Albert, modified by Erick Sevilla
            This is a mod of Michael Albert's genius: http://michlstechblog.info/blog/windows-read-the-ip-address-of-a-bmc-board/
Purpose:    Get IP, MAC and Subnet addresses from OOBM devices such as HP iLO's, Dell iDRAC's or Fujitsu's iRMC, 
            IBM's IMM etc.from a list of remote servers

Instructions:  1) From PowerShell as Admin, cd to script's path and run Get-OOBMIP.ps1 
               2) A .txt file will prompt, enter a list of hosts, IP's or FQDN's or remote machines
               3) Find results in console and csv file report
#>

 $ErrorActionPreference = "SilentlyContinue" # Don't use this, it's bad practice 🙂 -- Remove to debug
 $Timestamp = (Get-Date -f yyyy-MM-dd-hhmmss) # Current DateTime for logs
 $SourceFile = "$PSScriptRoot\Serverlist.txt" # Server list source, currently set as script's location
 $DestinationFile =  "$PSScriptRoot\Results_Get-OOBMIP_$Timestamp.csv" # Report file export name and location, currently set as script's location
 
 Write-Output "Replace this text with list of hosts you want to query, save and close..."| Out-File -FilePath $SourceFile -Encoding ASCII
 Start-Process $SourceFile -Wait # Propmts hosts.txt for user to populate with list of hosts
 Write-Host @("`r`nRunning Get-OOBMIP script...") -NoNewline -ForegroundColor Cyan -BackgroundColor Black

# OOBM Query function
function GetOOBMData {
    [cmdletbinding()]
    Param($Server)

    $oIPMI=Get-WmiObject -Namespace root\WMI -Class MICROSOFT_IPMI -ComputerName $Server
    [byte]$BMCResponderAddress = 0x20
    [byte]$GetLANInfoCmd = 0x02
    [byte]$GetChannelInfoCmd = 0x42
    [byte]$SetSystemInfoCmd = 0x58
    [byte]$GetSystemInfoCmd = 0x59
    [byte]$DefaultLUN = 0x00
    [byte]$IPMBProtocolType = 0x01
    [byte]$8023LANMediumType = 0x04
    [byte]$MaxChannel = 0x0b
    [byte]$EncodingAscii = 0x00
    [byte]$MaxSysInfoDataSize = 19

    [byte[]]$RequestData=@(0)
    $oMethodParameter=$oIPMI.GetMethodParameters("RequestResponse")
    $oMethodParameter.Command=$GetChannelInfoCmd
    $oMethodParameter.Lun=$DefaultLUN
    $oMethodParameter.NetworkFunction=0x06
    $oMethodParameter.RequestData=$RequestData
    $oMethodParameter.RequestDataSize=$RequestData.length
    $oMethodParameter.ResponderAddress=$BMCResponderAddress
    # http://msdn.microsoft.com/en-us/library/windows/desktop/aa392344%28v=vs.85%29.aspx
    $RequestData=@(0)
    [Int16]$iLanChannel=0
    [bool]$bFoundLAN=$false

                                        for(;$iLanChannel -le $MaxChannel;$iLanChannel++){
	$RequestData=@($iLanChannel)
	$oMethodParameter.RequestData=$RequestData
	$oMethodParameter.RequestDataSize=$RequestData.length
	$oRet=$oIPMI.PSBase.InvokeMethod("RequestResponse",$oMethodParameter,(New-Object System.Management.InvokeMethodOptions))
	#$oRet
	if($oRet.ResponseData[2] -eq $8023LANMediumType){
		$bFoundLAN=$true
		break;
	}
    }


    $oMethodParameter.Command=$GetLANInfoCmd
    $oMethodParameter.NetworkFunction=0x0c
    if($bFoundLAN){
	    $RequestData=@($iLanChannel,3,0,0)
	    $oMethodParameter.RequestData=$RequestData
	    $oMethodParameter.RequestDataSize=$RequestData.length
	    $oRet=$oIPMI.PSBase.InvokeMethod("RequestResponse",$oMethodParameter,(New-Object System.Management.InvokeMethodOptions))

    $OOBIP = (""+$oRet.ResponseData[2]+"."+$oRet.ResponseData[3]+"."+$oRet.ResponseData[4]+"."+$oRet.ResponseData[5] )

	    $RequestData=@($iLanChannel,6,0,0)
	    $oMethodParameter.RequestData=$RequestData
	    $oMethodParameter.RequestDataSize=$RequestData.length
	    $oRet=$oIPMI.PSBase.InvokeMethod("RequestResponse",$oMethodParameter,(New-Object System.Management.InvokeMethodOptions))
    $OOBSubnet = (""+$oRet.ResponseData[2]+"."+$oRet.ResponseData[3]+"."+$oRet.ResponseData[4]+"."+$oRet.ResponseData[5] )
	    $RequestData=@($iLanChannel,5,0,0)
	    $oMethodParameter.RequestData=$RequestData
	    $oMethodParameter.RequestDataSize=$RequestData.length
	    $oRet=$oIPMI.PSBase.InvokeMethod("RequestResponse",$oMethodParameter,(New-Object System.Management.InvokeMethodOptions))
    $OOBMACAddress = (("{0:x2}:{1:x2}:{2:x2}:{3:x2}:{4:x2}:{5:x2}" -f $oRet.ResponseData[2],$oRet.ResponseData[3],$oRet.ResponseData[4],$oRet.ResponseData[5],$oRet.ResponseData[6],$oRet.ResponseData[7]))
    $Status='SUCCESS'
    $Message = ''
    New-Object PSObject -Property @{Hostname=$Server;Status=$Status;OOBIP=$OOBIP;OOBMACAddress=$OOBMACAddress;OOBSubnet=$OOBSubnet;Message=$Message}
}
     
     }

# Function processing: Loop, progress bar and try-catch, all in a tasty wrap     
$Wrapper = @(

     $Servers = Get-Content $SourceFile
     $i = 0;$CountDuckula = @($Servers).Count

     foreach ($Server in $Servers) {
     $i++;[int]$Percentage = (($i/$CountDuckula)*100)
     Write-Progress -Activity "Get-OOBM Tool: Querying $Server" -Status "Completed $i of $CountDuckula - $Percentage%" -PercentComplete $Percentage

     try { GetOOBMData -Server $Server -ErrorAction Stop } catch {
                                         $Message=$($PSItem.ToString())
                                         $Status='FAIL'
                                         New-Object PSObject -Property @{
                                         Hostname=$Server;
                                         Status=$Status;
                                         OOBIP=$OOBIP;
                                         OOBMACAddress=$OOBMACAddress;
                                         OOBSubnet=$OOBSubnet;
                                         Message=$Message                }
                                         $OOBIP='';$OOBMACAddress='';$OOBSubnet='';$Message=$($PSItem.ToString())}
         
                                        }
                )

# Processing wrapped results for output
$Wrapper | Select-Object Hostname,Status,OOBIP,OOBMACAddress,OOBSubnet,Message | 
Export-Csv -Path $DestinationFile -Append -NoTypeInformation -Force # Output to csv file

Write-Host " Done!" -ForegroundColor Green -BackgroundColor Black # One puppy a day keeps the questions away
Write-Host "Path to report: " -ForegroundColor Cyan -BackgroundColor Black -NoNewline # In case you are wondering the file's name and location
Write-Host "$DestinationFile" -BackgroundColor Black # More write-host 'cause we hate puppies
$Wrapper | Format-Table Hostname,Status,OOBIP,OOBMACAddress,OOBSubnet,Message # Output to console because we are Homo videns

start $PSScriptRoot # Opening folder where the report is located for your convenience

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.