Windows IoT Core has a nice web-based device management interface. This app can configure many aspects of the device, such as connecting the device to a WiFi network. Because the web-based device management was just a web app, I thought it shouldn’t be difficult to write a remote app to do the same.
I ended up with a remote app that could query WiFi networks visible to a Windows IoT Core device and connect or disconnect that device to those networks.
To get started, I connected my browser to the web-based device management app for one of my Windows IoT Core devices (minwinpc2).
Then I opened the F12 Developer Tools of my browser to see what was going on underneath the hood. Because I’m interested in getting access to the WiFi of my device, I went to the Networking page of the app.
In the WiFi adapters section, the first items are the WiFi devices. In my case, I only have one (although it appears multiple devices are supported), “Broadcom WiFi Dongle Driver”. Looking through the F12 Developer Tools -> Networks page I found a get request to
http://minwinpc2:8080/api/wifi/interfaces
that returned the following Json result:
{"Interfaces" : [ {"Description" : "Broadcom Wifi Dongle Driver", "GUID" : "{MY_BROADCOM_GUID}", "Index" : 0, "ProfilesList" : [ {"GroupPolicyProfile" : false, "Name" : "Bighands", "PerUserProfile" : false} ]} ]}
Looking further I found a get request to
http://minwinpc2:8080/api/wifi/networks?interface=MINE_BROADCOM_GUID
that returned a list of WiFi networks:
{"AvailableNetworks" : [ {"AlreadyConnected" : true, "AuthenticationAlgorithm" : "WPA2_PSK", "CipherAlgorithm" : "AES", "Connectable" : 1, "InfrastructureType" : "Infrastructure", "ProfileAvailable" : true, "ProfileName" : "Bighands", "SSID" : "Bighands", "SecurityEnabled" : 1, "SignalQuality" : 80, "PhysicalTypes" : ["802.11n"]}, ……. ]}
That’s fairly straight forward. Query the interfaces (WiFi adapters) and get the interface GUID. Then use that GUID in the network query to get the list of WiFi networks that interface (WiFi adapter) can see.
Going further, I used the web-based device management app to disconnect from my WiFi (make sure you have a hardwired network connection at this point) and found a post request to
http://minwinpc2:8080/api/wifi/network?interface=MY_BROADCOM_GUID&op=disconnect
Connecting back to my WiFi network (Bighands) with a key, generated a post request to
http://minwinpc2:8080/api/wifi/network?interface=MY_BROADCOM_GUID&ssid=Bighands&op=connect&createprofile=yes&key=HASHEDPASSWORD
With these calls deciphered I started coding with a Universal Windows project. I came up with a simple example that demonstrates how an app can remotely scan, connect, and disconnect a Windows IoT Core device using authenticated web requests.
You can download my project here
The Code:
The first step was to create the credentials for logging into the device. Hopefully you’ve changed the default password on your Windows IoT Device.
public static AuthenticationHeaderValue CreateBasicCredentials(string userName, string password) { string toEncode = userName + ":" + password; Encoding encoding = Encoding.GetEncoding("iso-8859-1"); byte[] toBase64 = encoding.GetBytes(toEncode); string parameter = Convert.ToBase64String(toBase64); return new AuthenticationHeaderValue("Basic", parameter); }
In order to easily decode the returned interfaces and WiFi networks, I needed some classes to handle the responses. These classes were crafted to match the response data structures we previously discovered.
class AvailableInterfaces { public IEnumerable<WifiInterface> Interfaces { get; set; } } class WifiInterface { public String Description { get; set; } public String GUID { get; set; } public int Index { get; set; } } public class AvailableNetworksObject { public IEnumerable<WifiNetwork> AvailableNetworks { get; set; } } public class WifiNetwork { public bool AlreadyConnected { get; set; } public String AuthenticationAlgorithm { get; set; } public String CipherAlgorithm { get; set; } public int Connectable { get; set; } public String InfrastructureType { get; set; } public bool ProfileAvailable { get; set; } public String ProfileName { get; set; } public String SSID { get; set; } public int SecurityEnabled { get; set; } public int SignalQuality { get; set; } public IEnumerable<String> PhysicalTypes { get; set; } }
Now we can make the call to get the interfaces. Note that I’m assuming only one interface (WiFi adapter) in this case. If you have more, you’ll need to allow for a way to select the one you’re interested in querying.
using (HttpClient client = new HttpClient()) { using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("http://{0}:8080/api/wifi/interfaces", this.DeviceName))) { request.Headers.Authorization = CreateBasicCredentials("Administrator", "mypassword"); using (HttpResponseMessage response = await client.SendAsync(request)) { var data = await response.Content.ReadAsStringAsync(); var interfaces = JsonConvert.DeserializeObject<AvailableInterfaces>(data); var ourInterface = interfaces.Interfaces.First(); this.InterfaceDescription = ourInterface.Description; this.InterfaceGUID = ourInterface.GUID.Replace('{', ' ').Replace('}', ' ').Trim(); this.Status = "Getting Interfaces Succeeded"; } } }
Now that we’ve got the GUID from the previous call, we can scan our interface (WiFi adapter) for available networks.
using (HttpClient client = new HttpClient()) { using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("http://{0}:8080/api/wifi/networks?interface={1}", this.DeviceName, this.InterfaceGUID))) { request.Headers.Authorization = MainViewModel.CreateBasicCredentials("Administrator", "mypassword"); using (HttpResponseMessage response = await client.SendAsync(request)) { var data = await response.Content.ReadAsStringAsync(); var networks = JsonConvert.DeserializeObject<AvailableNetworksObject>(data); this.Networks = networks.AvailableNetworks; this.Status = "Refresh Wifi Succeeded"; } } }
To disconnect, the post request is simple.
using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = MainViewModel.CreateBasicCredentials("Administrator", "mypassword"); using (HttpResponseMessage response = await client.PostAsync(string.Format("http://{0}:8080/api/wifi/network?interface={1}&op=disconnect", this.DeviceName, this.InterfaceGUID), null)) { this.Status = "Disconnecting Wifi Succeeded"; } }
To connect, you need to first encode the WiFi password.
static public string EncodeTo64(string toEncode) { byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode); string returnValue = System.Convert.ToBase64String(toEncodeAsBytes); return returnValue; }
Now you can make the connect post request.
using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = MainViewModel.CreateBasicCredentials("Administrator", "mypassword"); using (HttpResponseMessage response = await client.PostAsync(string.Format("http://{0}:8080/api/wifi/network?interface={1}&ssid={2}&op=connect&createprofile=yes&key={3}", this.DeviceName, this.InterfaceGUID, this.SelectedWifi.SSID, EncodeTo64(this.WifiKey)), null)) { this.Status = "Connecting Wifi Succeeded"; } }
Conclusion:
This app opens the door for you to decipher other calls that are made with the web-based device management app to control all manner of Windows IoT Core settings. Go ahead and get hacking.
The post Windows IoT Core Remote Wifi Scanner appeared first on Falafel Software Blog.