Regardless of whether a server is for Exchange, for SQL, or for any other use; a key component of the server’s configuration is the set of IP addresses assigned to it.
Many organizations apply all addresses (even server addresses) using DHCP. For servers, this is often based on reservations of the MAC addresses on those servers. In most cases, this works well. However, if the DHCP server(s) should be unavailable (for whatever reason), the server will not receive the desired address, and instead will receive an APIPA address (that is, an IPv4 address starting with “169.” as the first octet of the IPv4 address).
Regardless of the result, for many servers it is important to know if the IP addresses should change. The first step in that process is to be able to enumerate (list) all of the IP addresses for all of the network interfaces on the server.
There are a number of mechanisms available for obtaining this information from Windows; including but not limited to “ipconfig.exe”, WMI, “wmic.exe”, “netsh.exe”, and others. The challenge for using most of the available interfaces is that they provide a significant amount of extraneous information. Extraneous information makes the output very difficult to parse and use within scripts.
This blog post provides a script that enumerates all of the network interfaces available on a particular computer and the associated IP addresses. The second script, which you could schedule to run every 15-30 minutes, compares and contrasts any changes in IP addresses on a server and reports the change via a SMTP server (such as Exchange Server).
The first script:
### ### IP-Address-Check.ps1 ### ### This script lists all Ethernet adapters supporting IP on a computer and ### the associated IP addresses - both IPv4 and IPv6. A simple object is ### output containing the name of the interface, an array containing the IPv4 ### addresses, and an array containing the IPv6 addresses. ### ### While this information is available from netsh.exe, the format of the ### output from netsh.exe is not conducive for easy re-use or parsing. ### ### Michael B. Smith ### michael at smithcons dot com ### http://essential.exchange ### February 28, 2012 ### Set-StrictMode -Version 2.0 $HKLM = 2147483650 $wmi = [wmiclass]"\root\default:StdRegProv" function RegRead { Param( [int64] $hive, [string]$keyName, [string]$valueName, [ref] $value, [string]$type = "REG_SZ" ) switch ( $type ) { 'reg_sz' { $r = $wmi.GetStringValue( $hive, $keyName, $valueName ) $value.Value = $r.sValue } 'reg_dword' { $r = $wmi.GetDWORDValue( $hive, $keyName, $valueName ) $value.Value = $r.uValue } 'reg_qword' { $r = $wmi.GetQWORDValue( $hive, $keyName, $valueName ) $value.Value = $r.uValue } 'reg_binary' { $r = $wmi.GetBinaryValue( $hive, $keyName, $valueName ) $value.Value = $r.uValue } default { write-error "ERROR: RegRead $hive $keyName $valueName" return 1 } } return $r.ReturnValue } function EnumerateAdapters { $nicSettings = gwmi Win32_NetworkAdapterSetting -EA 0 foreach( $nicSetting in $nicSettings ) { $nicElement = [wmi] $nicSetting.Element if( $nicElement.AdapterType -eq "Ethernet 802.3" ) { $nicConfig = [wmi] $nicSetting.Setting ## is of type Win32_NetworkAdapterConfiguration $nicGUID = $nicConfig.SettingID if( $nicConfig.IPEnabled -eq $true ) { $hive = $HKLM $keyName = "System\CurrentControlSet\Control\Network\" + "{4D36E972-E325-11CE-BFC1-08002BE10318}\" + $nicGUID + "\Connection" $valueName = "Name" $name = '' $result = RegRead $hive $keyName $valueName ( [ref] $name ) 'reg_sz' if( $result -ne 0 ) { $name = "" } $arrIPListPublic_v6 = @() $arrIPListPublic_v4 = @() foreach( $ip in $nicConfig.IPAddress ) { if( $ip.IndexOf( ':' ) -ge 0 ) { $arrIPListPublic_v6 += $ip } else { $arrIPListPublic_v4 += $ip } } $obj = "" | select Name, IPv4Addresses, IPv6Addresses $obj.Name = $name $obj.IPv4Addresses = $arrIPListPublic_v4 $obj.IPv6Addresses = $arrIPListPublic_v6 $obj ### output the object to the pipeline $arrIPListPublic_v4 = $null $arrIPListPublic_v6 = $null } $nicConfig = $null } $nicElement = $null } $nicSettings = $null } ### ### Main ### EnumerateAdapters
The second script:
### ### IP-Check-Controller.ps1 ### ### Check to see if any IP addresses on a computer have changed. This may ### be relevant in many configurations based on DHCP. ### ### Michael B. Smith ### michael at smithcons dot com ### http://essential.exchange ### February 28, 2012 ### Param( [string]$to = "ip-report@example.com", [string]$mx = "mx.example.com", [string]$sub = "The IP address information has changed at $($env:ComputerName)", [string]$fr = "ip-check-controller@example.local" ) [string]$nl = "`r`n" ### ### Main ### if( ( Test-Path "Addr-old.txt" -PathType Leaf ) ) { rm "Addr-old.txt" } if( ( Test-Path "Addr-new.txt" -PathType Leaf ) ) { mv "Addr-new.txt" "Addr-old.txt" } .\IP-Address-Check | out-file "Addr-new.txt" $result = Compare-Object -ReferenceObject $(gc "Addr-old.txt") -DifferenceObject $(gc "Addr-new.txt") -PassThru if( $result -eq $null ) { ## no changes to file exit } ### if we get here, the files are different $text = "A change has occurred in the IP addresses or active adapters.$nl$nl"+ "The changes found are:$nl" foreach( $line in $result ) { $text += "`t" + $line + $nl } $text += $nl + "The new full configuration is:$nl" $lines = gc "Addr-New.txt" foreach( $line in $lines ) { $text += "`t$line$nl" } $text += $nl + "The old full configuration is:$nl" $lines = gc "Addr-Old.txt" foreach( $line in $lines ) { $text += "`t$line$nl" } Send-MailMessage -To $to -Subject $sub -From $fr -Body $text -SmtpServer $mx -Priority High
Typically, instead of scheduling the second PowerShell script, you would schedule a BAT script, as shown below:
@echo off REM REM IP-Check-Controller.bat REM REM Michael B. Smith REM michael at smithcons dot com REM http://essential.exchange REM February 28, 2012 REM powershell.exe -command ".\IP-Check-Controller.ps1"
Until next time…
If there are things you would like to see written about, please let me know.
Follow me on twitter: @EssentialExch