For the most part I'm happy with Windows 8 but one feature was removed that makes no sense to me - the wireless networks dialog.
Sure, you can "Forget this network" by right clicking on a Wi-Fi Connection, but only when that network is in range. The old Wireless Networks dialog where you could add and remove networks is gone. Who knows how many saved Wi-Fi hotspot profile I have littering my system?
So, The Problem: I want to remove saved Wi-Fi Profiles whenever I feel like it. I wrote a command line util that will work in Windows 7 and Windows 8.
TL;DR Version
There's a build zipped up of Wifi.exe available here and the source is on GitHub.
Caveats and "Ya I know."
First, let me be clear that I have written a command line utility to replace another command line utility. I get it. I knew it when I did it. Others smarter than I have done similar things and written utilities that match their way of thinking rather than learning an unintuitive syntax. Don't hate the playa, hate the Regular Expression.
Aside: This is also a problem with my iPhone. I likely have 50+ saved Wi-Fi spots on my phone and no way to delete them without jail-breaking.
You can access Wi-Fi profiles with the netsh.exe that comes with Windows, so you could list out profiles like this:
c:\>netsh wlan show profiles
Profiles on interface Wi-Fi:
User profiles
-------------
All User Profile : Wayport_Access
All User Profile : HANSELMAN
All User Profile : HANSELMAN-N
All User Profile : HanselSpot
All User Profile : EliteWifi
All User Profile : Qdoba Free Wifi
Then, for each one, call
c:\>netsh wlan show profile "Qdoba Free Wifi"
Profile Qdoba Free Wifi on interface Wi-Fi:
=======================================================================
Profile information
-------------------
Version : 1
Type : Wireless LAN
Name : Qdoba Free Wifi
Control options :
Connection mode : Connect manually
Connectivity settings
---------------------
Number of SSIDs : 1
SSID name : "Qdoba Free Wifi"
Network type : Infrastructure
For each of these profiles, check if they are secure or open, and if you are connecting manually or automatically. Then, if you wanted, you could netsh wlan delete profile name="Qdoba Free Wifi" and remove a profile, even when it's not near you.
In my recent podcast with security expert Troy Hunt, he pointed out that it's easy to create a fake honeypot Wi-Fi spot that has the same name as a common open network, like Starbucks, for example.
- Given: If my PC or phone is set up to automatically connect to any open hotspot named "Starbucks" then it will just connect to one...even an evil hotspot.
- Therefore: it would be nice to automatically delete profiles for Wi-Fi spots that are both open (no security) and set to automatically connect.
I was tired, so I thought I'd bang out a little utility to do this. I could have used PowerShell or something but I felt like using C#. It's exercise.
Wifi.exe and it's Usage
Tired of reading? There's a build zipped up of Wifi.exe available here and the source is on GitHub. You may need to Right Click | Properties | Unblock the zip.
There's no warranty. The code sucks and I'm a horrible person and you're running a util you found on my blog. However, it works awesome on my machine. Issues appreciated, tidy PRs appreciated more, running Resharper and doing a PR, less so. I'll update the build if good bugs require it.
If you run Wifi.exe (I put it in my path) you'll see something like this:
c:\>wifi
AP-guest manual WPA2PSK
HANSELMAN-N auto WPA2PSK
HANSELMAN auto WPA2PSK
HanselSpot auto WPA2PSK
Qdoba Free Wifi manual open
Wayport_Access auto open Warning: AUTO connect to OPEN WiFi
Delete WiFi profiles that are OPEN *and* AUTO connect? [y/n]
n
Notice the columns, and the prompt. There's a warning when a hotspot is both open and set to auto-connect. If you answer Y to the prompt, the utility will delete that profile. You can also type 'wifi /deleteautoopen' to bypass the prompt and auto-delete just profiles that are auto and open.
A pull request a few minutes after I pushed this code also added the ability to
wifi delete "HOTSPOTNAME"
which is nice also. Thanks!
The Code
One of the great things about writing command line apps like this is that there's literally a dozen ways to do everything. They are trivial and silly but also useful and used daily. In this case I've got command line argument processing to think about, parsing output from a spawned process, doing the parsing in a clean way, making sure it works on a non-English machine (which I thought about but didn't test), as well as cleaning up of generated temp files.
It's hardly impressive code, but some of it was fun or interesting. Here's a few bits I liked.
Making Columns with Console.WriteLine and String.Format
Did you know that you can right- and left-align columns within a fixed with using String.Format? Few people know about this and I've seen whole libraries written custom to do the work that's built right in.
Console.WriteLine(String.Format("{0,-20} {1,10} {2,10} {3,30} ", a.Name, a.ConnectionMode, a.Authentication, warning));
Note the {0,-20} (left aligned) and the {1,10} (right aligned). Those are just like {0} and {1} in a String.Format but they include alignment and width.
Gratuitous use of Linq
It wouldn't be a silly utility without in crazy LINQ, eh? Who needs Regular Expressions when you can when you can do a SQL query over your string? ;) Actually, I don't know if this is a good thing or not. It was fun, though, and it works. Your thoughts?
This takes the output from wlan show profiles (seen above) and parses it into a list of just the AP Names. I think it should work in any language, assuming the : colons are there.
string result = ExecuteNetSh("wlan show profiles");
var listOfProfiles = from line in result.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
where line.Contains(":")
let l = line
where l.Last() != ':'
select l.Split(':')[1].Trim();
foreach (string profile in listOfProfiles)
ExecuteNetSh(String.Format("wlan export profile \"{0}\" folder=\"{1}\"", profile, Environment.CurrentDirectory));
Cleaning up the temp XML files
I export a bunch of very specific XML files with a VERY non-specific extension. I can't control their file name and I don't want guess what their name is because I would need to recreate their AP Name encoding scheme. Instead, I look for any XML files in the current folder (given the rare chance that YOU, the utility runner, have XML files in the same folder already) and only delete the ones with the namespace that I know to be present in Wi-Fi profiles. I patted myself on the back for this one, but just lightly.
static XNamespace ns = "http://www.microsoft.com/networking/WLAN/profile/v1";
//Delete the exported profiles we made, making sure they are what we think they are!
foreach (string file in Directory.EnumerateFiles(Environment.CurrentDirectory, "*.xml"))
if (XElement.Load(file).Name.Namespace == ns)
File.Delete(file);
Capturing Command Line Output
Finally, here's how you get the output of a command line process you started:
Process p = new Process();
p.StartInfo.FileName = "netsh.exe";
p.StartInfo.Arguments = arguments ?? String.Empty;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
return output;
Pretty basic, but useful to bookmark.
Alternatives
After I wrote this I noticed there are some WinForms utilities to do this. That's great. I wouldn't might making may own, except I'd want it to look exactly like the Windows 7 dialog. It'd be fun just to see if I could get it pixel perfect.
Feel free to go check out the code, play with it and make fun of me. https://github.com/shanselman/Windows-Wifi-Manager
Get Involved! Check out my latest production with TekPub. A meticulously edited TWO HOURS of video content where we cover everything we think a developer should know to "Get Involved" in the developer community.
© 2013 Scott Hanselman. All rights reserved.