Here, I will show my mini project where I built a desktop app with Python customtkinter and pyinstaller.
Introduction:
We often need to retrieve a Wi-Fi password from a device we’ve used in the past, usually because we’ve forgotten it or someone else needs to connect their new device. However, sharing a QR code isn't always an option. For example, the connected device might be nowhere near the router.
Imagine my Device A was previously connected to Wi-Fi 'XYZ' in Indonesia, but I am currently in Japan with that device. My friend in Indonesia wants to connect their Device B to that same 'XYZ' network. Since my device isn't currently within range of the signal, I can't simply generate a 'Share Wi-Fi' QR code. Need a way to view the saved password.
Problem:
See, the troubles start when we need to share the access. Modern smartphones have made sharing Wi-Fi easy via QR codes, BUT the catch is as what have been discussed on the introduction.
Solve:
And that's why I came up with this idea. I want to make it as an app. A one tap solution without entering manual script to cmd.
DISCLAIMER:
Please use this guide as intended for personal use or for helping friends or family to access networks you already have permission to use. And always be cautious when sharing Wi-Fi passwords.
1. First step (getting familiar with batch command)
If you run this command on Windows cmd:
netsh wlan show profiles
This will list all the device's connected Wi-Fi profiles 👇.
2. Show the passwords
To display the password, simply add this:
netsh wlan show profiles name="<profile_name>" key=clear | findstr Key
3. Automating
Now we know how to retrieve the password, but only for single profile. Easily, we just need to loop the given list of profiles. In Python, we need to use import subprocess library.
import subprocess
from subprocess import CalledProcessError
def get_all_connected_wifi_profile() -> list[str]:
command = f"netsh wlan show profiles"
try:
all_wifis = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT).decode("utf-8")
except UnicodeDecodeError:
all_wifis = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, encoding="latin-1")
except CalledProcessError as e:
print(f"Error: {e}")
print(f"Command output: {e.output.decode('utf-8').strip()}")
profiles = [
line.split(":")[1].strip()
for line in all_wifis.split("\n")
if "All User Profile" in line
]
return profiles
def get_password(name: str) -> str:
try:
command = f'netsh wlan show profiles name="{name}" key=clear | findstr Key'
try:
output = (subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT).decode("utf-8").strip())
except UnicodeDecodeError:
output = (subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, encoding="latin-1").strip())
if "Key Content" in output:
password = output.split(":")[1].strip()
return password
else:
return None
except CalledProcessError as e:
print(f"Error: {e}")
print(f"Command output: {e.output.decode('utf-8').strip()}")
Then iterate them like this
if __name__ == "__main__":
all_profiles = get_all_connected_wifi_profile()
for i, network in enumerate(all_profiles):
password = get_password(network)
print(f'{i+1}. {network} --> "{password}"')
Congratulations, now we get all the data we need. Just one thing, enhance it and put is a one tap solutions (as an app .exe).
4. The Tkinter things (UI)
Here, I use customtkinter library, why? Because it looks more modern than normal tkinter.
CustomTkinter is a python desktop UI-library based on Tkinter, which provides modern looking and fully customizable widgets. With CustomTkinter you'll get a consistent look across all desktop platforms (Windows, macOS, Linux).
Source: CustomTkinter Documentation
It's too much to explain the UI. Hopefully, you can get familiar with customtkinter by yourself by reading the documentations.
Let's go back and..., here is the full code:
# main.py
import subprocess
import customtkinter as ctk
from subprocess import CalledProcessError
class RetriveConnectedWifiPasswordApp:
def __init__(self) -> None:
self.root = ctk.CTk()
self.app_width = 700
self.app_height = 680
self.color1 = "#D2DE32"
self.color2 = "#FFFFDD"
self.bgcolor = "#61A3BA"
# icon_path = "icons8-wifi-96.ico"
# self.root.iconbitmap(icon_path)
self.screenwidth = self.root.winfo_screenwidth()
self.screenheight = self.root.winfo_screenheight()
self.x = (self.screenwidth // 2) - (self.app_width // 2) + 120
self.y = (self.screenheight // 2) - (self.app_height // 2) - 38
self.root.title("Get Connected Wi-Fi Password")
self.root.geometry(f"{self.app_width}x{self.app_height}+{self.x}+{self.y}")
self.root.resizable(False, False)
self.root.configure(bg=self.bgcolor)
self.header = None
self.scrollable = None
self.letsGoButton = None
self.resultLabel = None
self.data = {}
@staticmethod
def get_password(name: str) -> str:
try:
command = f'netsh wlan show profiles name="{name}" key=clear | findstr Key'
try:
output = (subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT).decode("utf-8").strip())
except UnicodeDecodeError:
output = (subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, encoding="latin-1").strip())
if "Key Content" in output:
password = output.split(":")[1].strip()
return password
else:
return None
except CalledProcessError as e:
print(f"Error: {e}")
print(f"Command output: {e.output.decode('utf-8').strip()}")
@staticmethod
def get_all_connected_wifi_profile() -> list[str]:
command = f"netsh wlan show profiles"
try:
all_wifis = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT).decode("utf-8")
except UnicodeDecodeError:
all_wifis = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, encoding="latin-1")
except CalledProcessError as e:
print(f"Error: {e}")
print(f"Command output: {e.output.decode('utf-8').strip()}")
"""
# all_wifis looks like this
Profiles on interface Wi-Fi:
Group policy profiles (read only)
---------------------------------
<None>
User profiles
-------------
All User Profile : cencored1
All User Profile : cencored2
All User Profile : cencored3
All User Profile : cencored4
All User Profile : TP-Link_3E16
All User Profile : Redmi Note 9 Pro
All User Profile : TP-LINK_C32E7E
"""
profiles = [
line.split(":")[1].strip()
for line in all_wifis.split("\n")
if "All User Profile" in line
]
return profiles
def letsGoButtonEvent(self):
self.letsGoButton.configure(state="disabled")
all_profiles = self.get_all_connected_wifi_profile()
labelHeader = ctk.CTkLabel(
self.scrollable,
text="Connected Networks",
font=("Arial", 18, "bold"),
# bg_color="#555555",
# text_color="#FFFFFF",
width=200,
)
labelHeader.pack(side="top", pady=(8, 10))
for i, network in enumerate(all_profiles):
password = self.get_password(network)
# write data
self.data[network] = password
if password == None:
password = str(password).lower()
else:
password = "[" + password + "]"
text = network.rjust(40, " ") + " --> " + password.ljust(40, " ")
container = ctk.CTkFrame(self.scrollable)
if i + 1 == len(all_profiles):
container.pack(side="top", pady=(0, 16))
else:
container.pack(side="top")
number = ctk.CTkLabel(
container,
text=f"{(str(i+1) + ' ').rjust(5, ' ')}",
font=("Consolas", 11, "bold"),
# bg_color="#555555",
)
number.pack(side="left", pady=(0, 2), padx=(0, 2))
label = ctk.CTkLabel(
container,
text=text,
font=("Consolas", 11),
# bg_color="#555555",
width=200,
)
label.pack(side="left", pady=(0, 2))
self.root.update()
def initialize(self):
self.header = ctk.CTkLabel(
self.root,
text="Get Connected Wi-Fi Password",
font=("Arial", 26, "bold"),
# bg_color=self.color1,
# text_color="#000000",
width=self.screenwidth,
height=30,
)
self.header.pack(pady=(24, 0))
self.scrollable = ctk.CTkScrollableFrame(
self.root, width=self.app_width - 100, height=500
)
self.scrollable.pack(pady=(24, 0))
self.letsGoButton = ctk.CTkButton(
self.root,
text="Let's go",
command=self.letsGoButtonEvent,
font=("Arial", 12, "bold"),
width=150,
height=34,
corner_radius=18,
)
self.letsGoButton.pack(side="top", pady=(24, 0))
def run(self):
self.initialize()
self.root.mainloop()
if __name__ == "__main__":
app = RetriveConnectedWifiPasswordApp()
app.run()
Run it:
python main.py
You will get something like this:
5. Compile it to .exe file
Why we need to compile it to .exe file? Because, not every PC has python environment installed. And it also make things easier for us when we need to get previously connected networks.
- Install
pyinstaller:
pip install pyinstaller
- Run this command to complie
pyinstaller main.py --onefile --windowed --icon="assets/icons8-wifi-96.ico" --name="Connected Networks"
The --icon="..." tag is optional, you can remove it. It's for the application icon.
After that, it will create new 2 directories dist/ and build/. Locate the Connected Networks.exe, should be in dist/. You can safely delete the build/ folder. There maybe also a Connected Networks.spec file. You can delete it also safely.
- Check the result
Check if it works fine and as expected by open the compiled file (.exe) located on dist/.
6. Finish
And congrats, we made it. Hopefully this is useful.
Here's the link to the my repository for more details:
GitHub Repository



Top comments (0)