The easiest way to find a remote server’s IP is probably nslookup
. But depending on how your environment is configured, not all IPs are automatically registered in the DNS. Servers with multiple network adapters that connect to different networks (an iSCSI SAN, for example) might only register the IPs used in the domain network.
Get-IPList#
Get-IPList
uses the good old ipconfig
command to query all IPs configured on all adapters, and it filters the output so you have a clean list with only the IPs. It also has parameters you can use to manually enter remote servers or import them from a file or OU.
I will be explaining the script in details, but feel free to just go ahead and download the final script.
ipconfig#
The reason I decided to go with ipconfig
instead of PowerShell’s Get-NetIPAddress
is that some servers might not have this comdlet available because of older PowerShell versions. I also prefer the way it sorts the IPs.
I started by removing all unnecessary lines from the output, keeping only the ones with IPv4 addresses. I used Select-String
with the -pattern
parameter to achieve that.
PS C:\Users\rsilva> ipconfig | Select-String -pattern "IPv4 Address"
IPv4 Address. . . . . . . . . . . : 172.25.247.1
IPv4 Address. . . . . . . . . . . : 192.168.86.59
IPv4 Address. . . . . . . . . . . : 172.28.112.1
To remove the redundant text and keep the IPs only, I used the -split
parameter in a foreach
loop so it goes through each line of the string.
$split = "IPv4 Address. . . . . . . . . . . : "
$IPs = ipconfig | select-string -pattern "IPv4 Address"
foreach ($IP in $IPs) {
($IP -split $split)[1]
}
Invoke-Command#
Now that we have a piece of code that can extract IPs from the ipconfig
output, let’s add Invoke-Command
to it so we can run the script against a remote server.
$split = "IPv4 Address. . . . . . . . . . . : "
$IPs = Invoke-Command -ScriptBlock {ipconfig | select-string -pattern "IPv4 Address"} -ComputerName server1
foreach ($IP in $IPs) {
($IP -split $split)[1]
}
You probably noticed the -ComputerName
parameter we used to specify the server is native to Invoke-Command
and we could technically add more servers (separated by comma) and run the script on all of them.
The problem with that approach, though, is that all IPs would be listed together and we wouldn’t be able to tell which IPs belong to each server. To avoid this inconvenience, we will be creating our own parameters.
ComputerName parameter#
I will be calling the parameter -ComputerName
because people are used to it from other PowerShell cmdlets, but you could name it “Server” or anything else you like.
To group the IPs by server, we only need to write the computer name before invoking the ipconfig
script block. I used Write-Output
for that and `n for a line break.
We will also need a new foreach
loop for for the servers that are specified within the new parameter.
param(
[Parameter()]
[string[]] $ComputerName
)
$split = "IPv4 Address. . . . . . . . . . . : "
foreach ($Computer in $ComputerName) {
Write-Output `n$Computer
$IPs = (Invoke-Command -ScriptBlock {ipconfig} -ComputerName $Computer) | select-string -pattern "IPv4 Address"
foreach ($IP in $IPs) {
($IP -split $split)[1]
}
}
You can see below an example of the script running with the new parameter.
PS C:\Users\rsilva> .\Get-IPList.ps1 -ComputerName server1,server2,server3
server1
192.168.86.9
192.168.86.31
192.168.86.36
server2
192.168.86.8
192.168.86.11
192.168.86.49
192.168.86.50
server3
192.168.86.14
192.168.86.131
This alone should get the job done. But if something doesn’t go exactly as expected, PowerShell will throw several lines of red errors and suddenly things aren’t looking nice anymore.
From this point on, I’ll be adding some extras that include better handling of errors, new parameters to get the list of servers from an Active Directory OU or from a file, adding some colors to the output and an option for IPv6.
Other parameters#
To add new parameters, we just need to declare them and specify what kind of data each one of them expect. Like -ComputerName
, both -File
and -OU
require a string. -IPv6
doesn’t expect any data, so we set it up as a switch.
param(
[Parameter()]
[string[]] $ComputerName,
[Parameter()]
[string[]] $OU,
[Parameter()]
[string[]] $File,
[Parameter()]
[switch] $IPv6
)
The -ComputerName
parameter saves its data (the server names) in the $ComputerName
variable that is used in the main part of the code. To avoid rewriting the same code for -File
and -OU
, we will use the same variable to store the servers we get from them.
File#
For this parameter we just need to get the content of the file. It’s as simple as Get-Content
.
if ($File) {
$ComputerName = Get-Content $File
}
OU#
For this parameter we need to query Active Directory and restrict the -SearchBase
to the specified OU. I also filtered the results to get only computers that are enabled, for obvious reasons.
if ($OU) {
$ComputerName = Get-ADComputer -SearchBase "$OU" -filter {enabled -eq $True} | Sort-Object -Property Name | Select-Object -ExpandProperty Name
}
IPv6#
Since this is a switch parameter, we will be using an if, else
statement. If it exists, $IPversion
and $split
variables get IPv6 related values. If not, IPv4.
if ($IPv6) {
$IPversion = "IPv6"
$split = "Link-local IPv6 Address . . . . . : "
}
else {
$IPversion = "IPv4"
$split = "IPv4 Address. . . . . . . . . . . : "
}
Before we had the $IPversion
variable, values for IPv4 were hardcoded, so we also have to make adjustments for the code to use the variable instead. You will see it in the code snippet when we talk about handling errors below.
Handling errors#
To better handle errors that the script might throw (a server not reachable, for example), we will be using Try, Catch
blocks.
If an error occurs within the Try block, the error is first saved to the $Error
variable. PowerShell then searches for a Catch block to handle the error, and that’s where we can make the error message look better.
try {
$IPs = (Invoke-Command -ScriptBlock {ipconfig} -ComputerName $Computer -ErrorAction Stop) | select-string -pattern $IPversion
foreach ($IP in $IPs) {
($IP -split $split)[1]
}
}
catch {
outputColor -fgcolor "Yellow"
Write-Output "Server is not reachable. Error details:"
outputColor -fgcolor "DarkGray"
Write-Output $_`n
outputColor -reset
}
outputColor function#
You probably noticed in the Catch
block above a function called outputColor with some color parameters. Unlike Write-Host
, Write-Output
doesn’t have parameters to change host colors.
To deal with this limitation, I decided to create this additional function to “prettify” the output in the console.
It has parameters for foreground and background colors, -fgcolor
and -bgcolor
respectively. It also saves the current colors in variables, so we can bring it back to what it was with the -reset
parameter.
$bgDefColor = $host.ui.RawUI.BackgroundColor
$fgDefColor = $host.ui.RawUI.ForegroundColor
function outputColor {
Param ([string]$bgcolor, [string]$fgcolor, [switch]$reset)
if ($bgcolor) {
$host.ui.RawUI.BackgroundColor = $bgcolor
}
if ($fgcolor) {
$host.ui.RawUI.ForegroundColor = $fgcolor
}
if ($reset) {
$host.ui.RawUI.BackgroundColor = $bgDefColor
$host.ui.RawUI.ForegroundColor = $fgDefColor
}
}
Install#
You can fork the final script on Github or install it from PowerShell Galery.