
说明:
随着 window11 不停发布新版23H2, 25H2,26H1,都要搞上共享文件和打印 的麻烦
为不想设置这么 只能用这个方法来搞好一部:
控制面板-》编辑凭据管理器-》添加 Windows 凭据-》填入:对方计算名|用户:guest 密码:空
把这个操作写成程序方便那些 不会操作人员操作下!!! 记得打包成exe
局域网凭据一键添加工具
自动扫描局域网计算机,智能识别主机名,快速添加 Windows 网络凭据。
告别手动输入,3 秒完成全部扫描。
< 3s
扫描速度
254
最大扫描主机
30
并发 Ping
0
依赖安装
SCROLL
// 问题背景
为什么需要这个工具?
在日常局域网运维中,添加网络凭据是一件繁琐但高频的操作。
⌨️
手动输入易出错
需要记住每台计算机的名称或 IP 地址,手动逐个输入,容易拼写错误导致连接失败。
🔍
查找计算机名困难
面对几十台甚至上百台机器,不知道哪些在线、哪些关机,需要逐一排查。
⏳
命令行操作繁琐
使用 cmdkey 命令需要打开 CMD,手动输入完整参数,对非技术人员不友好。
// 核心功能
六大核心能力
从扫描到添加,全流程自动化,一键搞定。
🌐
智能局域网扫描
自动检测本机子网,通过 net view + Ping 扫描双重机制,确保不遗漏任何在线计算机。
⚡
30 路并发加速
使用线程池 30 路并发 Ping,254 个地址 2-3 秒内完成扫描,极速不等待。
🏷️
智能主机名解析
三重解析策略:DNS 反查 → NetBIOS → IP 直显,0.3 秒超时自动跳过,绝不卡顿。
📊
实时进度反馈
三阶段进度条(Net View → Ping 扫描 → 名称解析),每阶段独立显示进度与状态。
🎯
下拉选择 + 手动输入
扫描结果自动填充下拉列表,点击即选;查不到的机器也可以手动输入计算机名或 IP。
🔒
凭据一键添加
封装 cmdkey 命令,填写用户名密码即可添加,支持密码遮蔽显示,操作安全直观。
代码:
python
import subprocess
import threading
import tkinter as tk
from tkinter import ttk, messagebox
import ipaddress
import socket
import re
from concurrent.futures import ThreadPoolExecutor, as_completed
def get_local_subnet():
"""获取本机所在子网"""
try:
result = subprocess.run("ipconfig", shell=True, capture_output=True,
text=True, encoding="gbk", errors="ignore")
ip_pattern = r'IPv4 地址[^\d]*(\d+\.\d+\.\d+\.\d+)'
mask_pattern = r'子网掩码[^\d]*(\d+\.\d+\.\d+\.\d+)'
ip_match = re.search(ip_pattern, result.stdout)
mask_match = re.search(mask_pattern, result.stdout)
if ip_match and mask_match:
ip = ip_match.group(1)
mask = mask_match.group(1)
network = ipaddress.IPv4Network(f"{ip}/{mask}", strict=False)
return str(network), ip
except Exception:
pass
return None, None
def ping_host(ip):
"""Ping 单个主机,返回 IP 或 None"""
try:
r = subprocess.run(
f"ping -n 1 -w 200 {ip}",
shell=True, capture_output=True, timeout=1
)
if r.returncode == 0:
return str(ip)
except Exception:
pass
return None
def resolve_hostname(ip, timeout=0.5):
"""
快速反查主机名
- 使用 socket 设置超时,超时就直接返回 IP
- 不会卡住
"""
old_timeout = socket.getdefaulttimeout()
try:
socket.setdefaulttimeout(timeout) # 0.5秒超时,查不到就放弃
hostname = socket.gethostbyaddr(ip)[0]
short_name = hostname.split(".")[0]
return short_name
except (socket.herror, socket.gaierror, socket.timeout, OSError):
return ip # 解析失败,直接用 IP
finally:
socket.setdefaulttimeout(old_timeout)
def resolve_hostname_fast(ip, timeout=0.3):
"""
多种方式快速解析,任何一种成功就返回
优先级: gethostbyaddr → nslookup → 直接返回 IP
"""
# 方法1: socket 反查(极短超时)
old_timeout = socket.getdefaulttimeout()
try:
socket.setdefaulttimeout(timeout)
hostname = socket.gethostbyaddr(ip)[0]
name = hostname.split(".")[0]
if name and name != ip:
return name
except Exception:
pass
finally:
socket.setdefaulttimeout(old_timeout)
# 方法2: nbtstat 查 NetBIOS 名(局域网最常用,速度很快)
try:
result = subprocess.run(
f"nbtstat -A {ip}",
shell=True, capture_output=True, text=True,
timeout=0.5, encoding="gbk", errors="ignore"
)
# 找 <00> UNIQUE 那一行的名称
for line in result.stdout.splitlines():
if "<00>" in line and "UNIQUE" in line:
name = line.split()[0].strip()
if name and len(name) > 1:
return name
except Exception:
pass
# 方法3: 都失败了,直接返回 IP
return ip
def scan_lan(progress_callback=None):
"""
扫描局域网中的计算机
"""
computers = []
# ======== 阶段1: net view ========
if progress_callback:
progress_callback(0, 1, 0, "正在执行 net view ...")
try:
result = subprocess.run(
"net view", shell=True, capture_output=True,
text=True, encoding="gbk", errors="ignore", timeout=15
)
if result.returncode == 0:
for line in result.stdout.splitlines():
match = re.match(r'\\\\(\S+)', line.strip())
if match:
name = match.group(1)
if name not in computers:
computers.append(name)
except Exception:
pass
net_view_count = len(computers)
# ======== 阶段2: Ping 扫描 ========
network, local_ip = get_local_subnet()
if not network or not local_ip:
if progress_callback:
progress_callback(1, 1, net_view_count, "net view 完成,无法获取子网信息")
computers.sort()
return computers
base = ".".join(local_ip.split(".")[:3]) + ".0/24"
net = ipaddress.IPv4Network(base, strict=False)
hosts = [str(ip) for ip in net.hosts() if str(ip) != local_ip]
total = len(hosts)
if progress_callback:
progress_callback(0, total, net_view_count,
f"net view 发现 {net_view_count} 台,开始 ping 扫描...")
# --- 2a: 多线程 Ping ---
found_ips = []
completed = 0
with ThreadPoolExecutor(max_workers=30) as executor:
future_to_ip = {executor.submit(ping_host, ip): ip for ip in hosts}
for future in as_completed(future_to_ip):
completed += 1
result = future.result()
if result:
found_ips.append(result)
if completed % 10 == 0 or completed == total:
if progress_callback:
progress_callback(
completed, total, net_view_count + len(found_ips),
f"Ping 扫描 {completed}/{total} | 存活 {len(found_ips)} 个"
)
# --- 2b: 多线程并行反查主机名(关键加速点)---
if progress_callback:
progress_callback(total, total, net_view_count + len(found_ips),
f"Ping 完成,并行解析 {len(found_ips)} 个主机名...")
names_found = []
resolve_total = len(found_ips)
resolve_done = 0
if resolve_total > 0:
with ThreadPoolExecutor(max_workers=20) as executor:
future_to_ip = {
executor.submit(resolve_hostname_fast, ip, 0.3): ip
for ip in found_ips
}
for future in as_completed(future_to_ip):
resolve_done += 1
name = future.result()
if name not in names_found:
names_found.append(name)
if resolve_done % 5 == 0 or resolve_done == resolve_total:
if progress_callback:
progress_callback(
total, total, net_view_count + resolve_done,
f"解析主机名 {resolve_done}/{resolve_total} | "
f"已识别 {len(names_found)} 台"
)
# 合并结果
for name in names_found:
if name not in computers:
computers.append(name)
if progress_callback:
progress_callback(total, total, len(computers),
f"扫描完成,共发现 {len(computers)} 台计算机")
computers.sort()
return computers
def add_windows_credential(target_name, username="guest", password=""):
"""使用 cmdkey 命令添加 Windows 凭据"""
try:
cmd = f'cmdkey /add:{target_name} /user:{username}'
if password:
cmd += f' /pass:{password}'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode == 0:
messagebox.showinfo("成功", f"成功添加凭据!\n目标计算机: {target_name}")
return True
else:
messagebox.showerror("错误", f"添加凭据失败: {result.stderr}")
return False
except Exception as e:
messagebox.showerror("错误", f"添加凭据时发生错误: {str(e)}")
return False
class CredentialApp:
def __init__(self, root):
self.root = root
self.root.title("Windows 局域网凭据添加工具")
self.root.geometry("500x480")
self.root.resizable(False, False)
style = ttk.Style()
style.theme_use("clam")
style.configure("Info.TLabel", font=("Microsoft YaHei UI", 9))
style.configure("Scan.TButton", font=("Microsoft YaHei UI", 10), padding=6)
style.configure("Action.TButton", font=("Microsoft YaHei UI", 10, "bold"), padding=6)
# ---------- 顶部标题 ----------
header = tk.Frame(root, bg="#0078D4", height=50)
header.pack(fill="x")
header.pack_propagate(False)
tk.Label(header, text="局域网凭据添加工具", bg="#0078D4", fg="white",
font=("Microsoft YaHei UI", 15, "bold")).pack(expand=True)
# ---------- 主内容区 ----------
main_frame = tk.Frame(root, padx=20, pady=15)
main_frame.pack(fill="both", expand=True)
# ---- 计算机选择区 ----
select_frame = tk.LabelFrame(main_frame, text=" 选择或输入目标计算机 ",
font=("Microsoft YaHei UI", 10), padx=10, pady=8)
select_frame.pack(fill="x", pady=(0, 8))
combo_row = tk.Frame(select_frame)
combo_row.pack(fill="x")
self.computer_var = tk.StringVar()
self.computer_combo = ttk.Combobox(
combo_row, textvariable=self.computer_var,
font=("Consolas", 11), width=35
)
self.computer_combo.pack(side="left", fill="x", expand=True, padx=(0, 10))
self.scan_btn = ttk.Button(combo_row, text="扫描局域网", style="Scan.TButton",
command=self.start_scan)
self.scan_btn.pack(side="right")
# ---- 进度条区域 ----
self.progress_frame = tk.Frame(select_frame)
self.progress_bar = ttk.Progressbar(self.progress_frame, mode="indeterminate", length=380)
self.progress_bar.pack(fill="x")
# 阶段指示器
self.phase_label = tk.Label(self.progress_frame, text="",
font=("Microsoft YaHei UI", 9, "bold"),
fg="#0078D4", anchor="w")
self.phase_label.pack(fill="x", pady=(3, 0))
self.progress_label = tk.Label(self.progress_frame, text="",
font=("Microsoft YaHei UI", 9), fg="#555555", anchor="w")
self.progress_label.pack(fill="x")
# 状态提示
self.status_var = tk.StringVar(value="点击「扫描局域网」自动发现计算机,也可直接输入计算机名或 IP")
self.status_label = ttk.Label(select_frame, textvariable=self.status_var,
style="Info.TLabel", foreground="gray")
self.status_label.pack(anchor="w", pady=(5, 0))
# ---- 凭据设置区 ----
cred_frame = tk.LabelFrame(main_frame, text=" 凭据设置 ",
font=("Microsoft YaHei UI", 10), padx=10, pady=8)
cred_frame.pack(fill="x", pady=(0, 8))
user_row = tk.Frame(cred_frame)
user_row.pack(fill="x", pady=3)
tk.Label(user_row, text="用户名:", font=("Microsoft YaHei UI", 10),
width=8, anchor="e").pack(side="left")
self.username_var = tk.StringVar(value="guest")
tk.Entry(user_row, textvariable=self.username_var,
font=("Consolas", 11), width=30).pack(side="left", padx=5)
pass_row = tk.Frame(cred_frame)
pass_row.pack(fill="x", pady=3)
tk.Label(pass_row, text="密 码:", font=("Microsoft YaHei UI", 10),
width=8, anchor="e").pack(side="left")
self.password_var = tk.StringVar()
self.pass_entry = tk.Entry(pass_row, textvariable=self.password_var,
font=("Consolas", 11), width=30, show="•")
self.pass_entry.pack(side="left", padx=5)
self.show_pass_var = tk.BooleanVar(value=False)
tk.Checkbutton(pass_row, text="显示", variable=self.show_pass_var,
command=self.toggle_password).pack(side="left")
# ---- 按钮区 ----
btn_frame = tk.Frame(main_frame)
btn_frame.pack(pady=10)
ttk.Button(btn_frame, text="添加凭据", style="Action.TButton",
command=self.add_credential).pack(side="left", padx=10)
ttk.Button(btn_frame, text="清除", style="Scan.TButton",
command=self.clear_fields).pack(side="left", padx=10)
ttk.Button(btn_frame, text="退出", style="Scan.TButton",
command=self.root.quit).pack(side="left", padx=10)
def toggle_password(self):
self.pass_entry.config(show="" if self.show_pass_var.get() else "•")
def show_progress(self):
self.progress_frame.pack(fill="x", pady=(6, 0))
self.progress_bar.configure(mode="indeterminate", value=0, maximum=100)
self.progress_bar.start(15)
self.phase_label.config(text="")
self.progress_label.config(text="准备中...")
def switch_progress_to_determinate(self, total):
self.progress_bar.stop()
self.progress_bar.configure(mode="determinate", maximum=total, value=0)
def update_progress(self, current, total, found_count, status_text):
def _update():
if self.progress_bar.cget("mode") == "indeterminate" and total > 0:
self.switch_progress_to_determinate(total)
if total > 0:
pct = int(current / total * 100)
self.progress_bar.configure(value=current)
self.progress_label.config(text=f"{status_text} ({pct}%)")
# 自动识别阶段
if "net view" in status_text.lower():
self.phase_label.config(text="Phase 1/3: Net View", fg="#0078D4")
elif "ping" in status_text.lower():
self.phase_label.config(text="Phase 2/3: Ping 扫描", fg="#E67E22")
elif "解析" in status_text.lower() or "识别" in status_text.lower():
self.phase_label.config(text="Phase 3/3: 解析主机名", fg="#27AE60")
elif "完成" in status_text.lower():
self.phase_label.config(text="扫描完成!", fg="#27AE60")
self.root.after(0, _update)
def hide_progress(self):
self.progress_bar.stop()
self.progress_frame.pack_forget()
def start_scan(self):
self.scan_btn.config(state="disabled", text="扫描中...")
self.computer_combo["values"] = []
self.status_var.set("")
self.show_progress()
def do_scan():
computers = scan_lan(
progress_callback=lambda *args: self.root.after(0, self.update_progress, *args)
)
self.root.after(0, lambda: self.on_scan_done(computers))
threading.Thread(target=do_scan, daemon=True).start()
def on_scan_done(self, computers):
self.scan_btn.config(state="normal", text="扫描局域网")
self.root.after(1000, self.hide_progress)
if computers:
self.computer_combo["values"] = computers
self.computer_var.set(computers[0])
self.status_var.set(f"扫描完成,共发现 {len(computers)} 台计算机 --- 可下拉选择或手动输入")
else:
self.status_var.set("未扫描到计算机,请手动输入计算机名或 IP 地址")
def add_credential(self):
computer_name = self.computer_var.get().strip()
if not computer_name:
messagebox.showwarning("警告", "请输入或选择目标计算机!")
return
username = self.username_var.get().strip()
password = self.password_var.get()
if not username:
messagebox.showwarning("警告", "请输入用户名!")
return
if add_windows_credential(computer_name, username, password):
self.computer_var.set("")
def clear_fields(self):
self.computer_var.set("")
self.username_var.set("guest")
self.password_var.set("")
def main():
root = tk.Tk()
CredentialApp(root)
root.mainloop()
if __name__ == "__main__":
main()