Sunday, June 9, 2013

How to delete Open or Insecure Wi-Fi HotSpots from Windows 8: Wifi.exe Command Line Utility with Source

How to delete Open or Insecure Wi-Fi HotSpots from Windows 8: Wifi.exe Command Line Utility with Source:
image
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.
UPDATE: I've put Wifi-Manager up on Chocolately so you can now "cinst wifi-manager." Thanks to Brendan Forster for the heavy lifting! Learn more about the Chocolatey package manager here!

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.
UPDATE: Lee Holmes went and wrote it in PowerShell! Amazing.

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 mind 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.



     

DIGITAL JUICE

No comments:

Post a Comment

Thank's!