0
点赞
收藏
分享

微信扫一扫

极简远程桌面工具

影子喵喵喵 2023-08-17 阅读 57

工具由来

    自从升级win11操作系统后,本人使用的集中远程桌面管理工具,第一次打开和关闭远程桌面后,就会出现第二次连接不上的问题,需要不断的关闭和打开软件才能重新连接,因此给我造成了一些困扰,由于本人电脑一直远程着多台机器工作,因此想重新找个工具,找来找去发现很多都是收费或免费但受限软件,索性干脆写一个简易远程能够连接,方便工作就好。

工具需求

  1. 只远程管理windows机器
  2. 调用windows自带的RDP程序开启远程
  3. 保存连接的信息,如IP地址、用户名和密码,当然需要加密存储,同时可以在界面查看信息
  4. 添加、删除的机器量不受限制
  5. 选择开发语言:python
  6. 可作为windows exe程序运行

工具界面设计

极简远程桌面工具_远程桌面

完整代码

import os.path
import tkinter as tk
from tkinter import Menu, messagebox
import subprocess
from threading import Thread
from cryptography.fernet import Fernet
import base64
import re


def encode_to_32_byte_base64(input_string):
    # 将字符串填充到32字节长度
    padded_input = input_string.ljust(32)[:32]
    # 编码为URL安全的base64编码
    encoded_bytes = base64.urlsafe_b64encode(padded_input.encode())
    return encoded_bytes


def encryptpwdp_password(key, password):
    f = Fernet(key)
    encrypted_password = f.encrypt(password.encode())
    return encrypted_password


def decrypt_password(key, encrypted_password):
    f = Fernet(key)
    decrypted_password = f.decrypt(encrypted_password).decode()
    return decrypted_password


def encrypt_password(non_secure_string):
    # Run the PowerShell command and capture the output
    try:
        command = ['powershell.exe', '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command',
                   f'("{non_secure_string}" | ConvertTo-SecureString -AsPlainText -Force) | ConvertFrom-SecureString']

        print(command)
        output = subprocess.check_output(command, shell=True, text=True, encoding='utf-8')
        print(output)

        return output
    except subprocess.CalledProcessError as e:
        print(f"Error running PowerShell command:\n{e}")
        print("Error:", e)
        print("Output:", e.output)


def extract_values(filename):
    dir_path = 'config'
    file_path = os.path.join(dir_path, filename)
    try:
        with open(file_path, 'r') as file:
            content = file.read()
            # Define the pattern to match fields and values
            pattern = r'([a-zA-Z_]+):([sb]):([^\n]+)'

            # Find all matches using the pattern
            matches = re.findall(pattern, content)
            print(matches)

            # Create a dictionary to store the extracted data
            extracted_data = {}
            for match in matches:
                field_name, value_type, value = match
                extracted_data[field_name] = value.strip()

            return extracted_data
    except FileNotFoundError:
        print(f"File '{file_path}' not found.")
        return None

def generate_connect_config(w_remote_host, w_username, w_password, w_display_host, w_pwdp):
    try:
        rdp_file_content = f"""\
screen mode id:i:2
smart sizing:i:1
compression:i:1
displayconnectionbar:i:1
disable wallpaper:i:1
disable themes:i:0
autoreconnection enabled:i:0
redirectclipboard:i:1
full address:s:{w_remote_host}
username:s:{w_username}
password 51:b:{w_password}
pwdpp:s:{w_pwdp}
"""
        dir_path = 'config'
        w_display_host = os.path.join(dir_path, w_display_host)
        with open(f"{w_display_host}", "w") as rdp_file:
            rdp_file.write(rdp_file_content)
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred: {e}")


def connect_to_remote_desktop(w_display_host):
    try:
        # Run the RDP file using mstsc
        dir_path = 'config'
        w_display_host = os.path.join(dir_path, w_display_host)
        subprocess.run(["mstsc", f"{w_display_host}"], shell=True)
    except Exception as e:
        messagebox.showerror("Error", f"An error occurred: {e}")


def get_inputs():
    input_values = [
        entries[0].get(),
        entries[1].get(),
        entries[2].get(),
        entries[3].get()
    ]

    if any(not value for value in input_values):
        messagebox.showerror("Error", "All input fields must be filled.")
    else:
        print("Input values:", input_values)
        encrypted_password = encrypt_password(entries[3].get())
        print(encrypted_password)
        pwdp = encryptpwdp_password(key, entries[3].get()).decode('utf-8')
        generate_connect_config(entries[1].get(), entries[2].get(), encrypted_password, entries[0].get(), pwdp)
        refresh_buttons()
        messagebox.showinfo("信息", f"主机: {entries[1].get()},添加成功!")


def show_context_menu(event, button_name):
    selected_button.set(button_name)
    context_menu.post(event.x_root, event.y_root)


def modify_button():
    button_name = selected_button.get()
    # Implement the modify functionality here
    messagebox.showinfo("Modify", f"Modify {button_name}")


def delete_button():
    button_name = selected_button.get()
    dir_path = 'config'
    file_path = os.path.join(dir_path, button_name)
    try:
        os.remove(file_path)
        print(f"File '{file_path}' deleted successfully.")
        messagebox.showinfo("Delete", f"删除成功 {button_name}")
        refresh_buttons()
    except FileNotFoundError:
        print(f"File '{file_path}' not found.")
    except Exception as e:
        print(f"An error occurred: {e}")
        messagebox.showinfo("Delete", f"删除失败 {button_name}")


def view_button():
    button_name = selected_button.get()
    # Implement the view functionality here
    extracted_data = extract_values(button_name)
    if extracted_data:
        # 使用 get() 方法获取值,如果键不存在,则返回默认值
        s_address = extracted_data.get("address", "Unkown")
        s_user = extracted_data.get("username", "Unkown")
        s_pwdpp = extracted_data.get("pwdpp", "Unkown")
        # 解密密码
        s_password = decrypt_password(key, s_pwdpp.encode('utf-8'))
        message = f"IP地址:{s_address}\n用户名:{s_user}\n密码:{s_password} "
        messagebox.showinfo("View", message)
    else:
        print("Extraction failed.")


def on_button_click(button_name):
    # Run the execute_command function in a separate thread
    thread = Thread(target=connect_to_remote_desktop, args=(button_name,))
    thread.start()


def load_buttons(folder_path):
    for widget in buttons_frame.winfo_children():
        widget.destroy()  # Clear existing buttons
    row = 0
    col = 0

    for filename in os.listdir(folder_path):
        if os.path.isfile(os.path.join(folder_path, filename)):
            button = tk.Button(buttons_frame, text=filename)
            button.bind("<Button-3>", lambda event, name=filename: show_context_menu(event, name))
            button.configure(command=lambda name=filename: on_button_click(name))
            button.grid(row=row, column=col, padx=5, pady=5)
            col += 1

            if col >= 4:
                col = 0
                row += 1


def refresh_buttons():
    folder_path = "config"
    if not os.path.exists(folder_path):
        messagebox.showerror("Error", "Folder not found.")
        return

    load_buttons(folder_path)


def main():
    # 在这里替换为你自己的密钥
    org_key = 'Dxbdywzq@abcd2999@20202020@2023@'
    # 编码为32字节的URL安全的base64编码字节
    global key
    key = encode_to_32_byte_base64(org_key)

    folder_path = "config"
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)  # 自动创建文件夹

    if not os.path.exists(folder_path):
        messagebox.showerror("Error", "Folder not found.")
        # return

    # Create the main application window
    root = tk.Tk()
    root.title("Remote Desktop Manager")
    root.resizable(width=False, height=False)

    # Set the initial window size
    window_width = 550
    window_height = 220
    root.geometry(f"{window_width}x{window_height}+265+255")

    # Create a frame to hold input fields using grid layout
    input_frame = tk.Frame(root)
    input_frame.pack()
    # Create labels and entries using pack layout inside the grid frame
    label_texts = ["显示名:", "IP地址:", "用户名:", "密码:"]
    global entries  # Declare entries as global
    entries = []

    for i, label_text in enumerate(label_texts):
        label = tk.Label(input_frame, text=label_text)
        entry = tk.Entry(input_frame)
        if i == 0:
            label.grid(row=1, column=0, sticky="w")
            entry.grid(row=1, column=1, padx=5, pady=5, sticky="e")
        if i == 1:
            label.grid(row=1, column=2, sticky="w")
            entry.grid(row=1, column=3, padx=5, pady=5, sticky="e")
        if i == 2:
            label.grid(row=2, column=0, sticky="w")
            entry.grid(row=2, column=1, padx=5, pady=5, sticky="e")
        if i == 3:
            label.grid(row=2, column=2, sticky="w")
            entry.grid(row=2, column=3, padx=5, pady=5, sticky="e")
        entries.append(entry)

    # Create button to get inputs
    button = tk.Button(input_frame, text="添加远程", command=get_inputs)
    button.grid(row=3, column=0, padx=10, pady=10)

    global selected_button
    selected_button = tk.StringVar()

    global context_menu
    context_menu = Menu(root, tearoff=0)
    # context_menu.add_command(label="Modify", command=modify_button)
    context_menu.add_command(label="查看", command=view_button)
    context_menu.add_separator()
    context_menu.add_command(label="删除", command=delete_button)


    global buttons_frame
    buttons_frame = tk.Frame(root)
    buttons_frame.pack()
    refresh_button = tk.Button(root, text="重载配置", command=refresh_buttons, width=10)
    refresh_button.pack()
    refresh_buttons()
    root.mainloop()


if __name__ == "__main__":
    main()

打包exe程序运行

打包之前,您需要先安装pyinstaller模块,以编译为windows可以执行的exe程序

pyinstaller --onefile --noconsole --icon=alert12.ico --name=远程桌面 main.py

工具下载

下载地址:https://pan.baidu.com/s/1mzejYVV1ILosSr92VwEp2A

提取码:8j6i

运行环境要求:windowns10/11 或有安装powershell的windowns系统。

注:若有使用360,可能会误报,加入信任即可。

举报

相关推荐

0 条评论