KiZAN has a lab of 26 Raspberry Pi 2 boards running Windows 10 IoT core. On a regular basis, we need to re-flash, provision, and configure the boards. When we perform the re-flash and provisioning process, it is manual, and consumes more time than we want to spend (up to 2 days). Truth be told, we don't have 2 days of free time, so we decided to invest in automation.
Once the entire re-flash and provisioning process was automated, we hoped to reduce the time spent to under 2 hours. Yeah, from 2 days to 2 hours. You do the math. This post is one of a series of posts describing our automation efforts for provisioning Windows 10 IoT Core on the Raspberry Pi 2.
In this post, you'll learn how to find the IP address of a Windows 10 IoT Core device after initial flash with PowerShell.
26 devices all named minwinpc
After a newly flashed Windows 10 IoT Core device boots, it has a default name of minwinpc. Now imagine you have 26 devices, all booting up with the name minwinpc and want 26 named kizan-pi-XX, where XX is 01 through 26. We also want specific physical boards tied to each name, so we can accurately inventory and track units (for asset purposes). It turns out there are a number of obstacles in our way. First, the only way to identify one from another, at this point, is from the IP address. But how do I know which physical unit belongs to which IP address? Until we rename the device to its unique name, we cannot reference a device by name. Second, we cannot reference a device by its IP address (at first) because we don’t know the IP address, and it could change depending on the network connection (Ethernet vs. Wireless).
As we were brainstorming a solution, we thought through several scenarios. It finally hit us: each device has its own MAC Address, that never changes. Finally! We have found a way to uniquely identify each of the devices. One problem, how do we get the device's IP address via the MAC address? As it turns out, the answer is always a little bit more complicated than you'd expect, but we found a working (and reliable solution) by using arp -a inside a PowerShell script.
Using Address Resolution Protocol (ARP) to find a device's IP address
Address Resolution Protocol (ARP) is used to map IP addresses to their corresponding hardware (MAC) addresses. Windows has a convenient command line tool, arp, that can query the network using ARP. When the command arp -a is used, it accesses a local ARP table (this stores all of the recently seen IP addresses and corresponding MAC addresses). Every time you talk to a device on your network, your computer caches the other device Mac and IP address. This information is cached in the ARP table, but only for a short period of time. Let's take a look at some PowerShell code that uses the arp command to find a device by its MAC address:
In the code above, we are setting the variable $ip to the output of the arp -a call. I pipe the results of the command to the Select-String command. This command will receive the output of the arp -a command line by line. Select-String then checks to see if the given MAC address (the $macAddress variable) is present in the string. If it is present, it gets piped to the third and final command. The final command parses the corresponding entry that the MAC address has found and converts it to a string, splitting the columns based off of a space (" "), and choosing the first column (the IP address). The command $_.ToString is similar to saying "for each". And it's that simple! Right? Not so fast.
What if the ARP table is empty
What if the device isn't listed in the ARP table? After all, the devices just appeared on the network and I haven't actually communicated with the device, so it's IP and MAC addresses wouldn’t be in my ARP table. No problem! Loop through all IP addresses in the current subnet, broadcasting a ping for each IP address in the network. This will eventually load every visible device into the ARP table.
I will explain in greater detail with code:
I start with a for loop, with a range of 1 to 254. There are 256 available addresses, but .0 is reserved for the network address identifier and .255 is reserved for the broadcast address. In each iteration I ping the network and use the arp command just like above to see if the IP address is now visible. The variable $networkSegment is the network that I'm working with. When you ping for a device, it does not give an immediate response (and it takes time for the local machine to update its ARP table), so I put a wait of 500 ms after the ping to make sure the ping request has time to get a response and update the ARP table.
Great! Our team now has a solution and we can find the IP address of a Windows 10 IoT Core device after initial flash via PowerShell. I ended up wrapping the code into a function, which I've included below.
The Working Code
In my next post, I'll show you how we renamed each of our devices.
Interested in learning more?
View the rest of our IoT blogs!
Posted by Mike Branstein
Developer and leader. Passionate about systems architecture, domain driven design, application lifecycle management, and technology.