1 Star 0 Fork 1

李永宏/AppXManager

forked from 火柴/AppXManager 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
WinAppsUninstaller.py 10.09 KB
一键复制 编辑 原始数据 按行查看 历史
火柴 提交于 2024-07-24 10:55 . 更改了版本号
import json
import os
import subprocess
import sys
import time
import PySimpleGUI as sg
import pyperclip
from concurrent.futures import ThreadPoolExecutor
rec_list = []
try:
with open('rec_uninstall.json', 'r', encoding='utf-8') as file:
rec_list = json.load(file)
except IOError:
print('无法加载rec_uninstall.json')
warn_list = []
try:
with open('warn_list.json', 'r', encoding='utf-8') as file:
warn_list = json.load(file)
except IOError:
print('无法加载warn_list.json')
name_dict = {}
try:
with open('cn_name.json', 'r', encoding='utf-8') as file:
name_dict = json.load(file)
except IOError:
print('无法加载cn_name.json')
# 修复高DPI感知
if sys.platform == 'win32':
try:
import ctypes
ctypes.OleDLL('shcore').SetProcessDpiAwareness(1)
except (ImportError, AttributeError, OSError):
pass
def uninstall(sel_app, threads=False):
try:
uninstall_command = f"Get-AppxPackage -Name '*{sel_app}*' | Remove-AppxPackage"
result = subprocess.run(["powershell", uninstall_command], capture_output=True, text=True)
if result.returncode == 0:
print(f"卸载命令执行成功!{sel_app}")
else:
print(f'命令执行失败{sel_app},参考:')
print(result.stderr)
if not threads:
print('已卸载!', sel_app)
window[sel_app].update(text_color='red')
# if notfoundAppx(sel_app):
# print('已卸载!', sel_app)
# window[sel_app].update(text_color='red')
# else:
# print('应用还存在,似乎未卸载成功')
except Exception as e:
print(f"卸载应用时出现错误: {e}")
def notfoundAppx(app_name): # 检查指定的应用程序是否不存在
command = f"Get-AppxPackage -Name '*{app_name}*'" # 定义一个命令,用于搜索指定应用程序
# print(command)
try:
# 使用PowerShell运行命令,并将输出捕获到check_result中
check_result = subprocess.run(["powershell", command], capture_output=True, text=True)
if check_result.stdout.strip() == "": # 如果输出为空,则表示应用程序不存在
return True
else:
return False
except Exception as e:
print(f"异常: {e}")
def getColor(curr_name):
if curr_name in warn_list:
return 'purple'
elif curr_name in rec_list:
return '#006600'
elif curr_name in dev_list:
return 'blue'
else:
return ''
def getName(name): # 获取推荐列表中的名字
# 判断name是否在recom_dict中
if name in name_dict.keys():
# 如果在,返回recom_dict中的值
return name_dict[name]
else:
# 如果不在,返回name
return name
def tidy(name_list):
recom = []
noml = []
dev = []
warn = []
for x in name_list:
if x in rec_list:
recom.append(x)
elif x in warn_list:
warn.append(x)
elif x in dev_list:
dev.append(x)
else:
noml.append(x)
recom.sort()
noml.sort()
dev.sort()
warn.sort()
print('推荐卸载', len(recom))
print('第三方', len(dev))
print('不建议卸载', len(warn))
return recom + noml + dev + warn
print("正在获取包信息,等待系统响应...")
getapp_pscmd = 'powershell "Get-AppxPackage | Select-Object -Property Name, IsFramework, NonRemovable, SignatureKind,PackageFullName"'
echo = ""
try:
echo = subprocess.check_output(getapp_pscmd).decode("utf-8")
except Exception as e:
print(f"获取包信息时出现错误: {e}\n请检查是否安装powershell")
echo_list = list(filter(None, echo.split("\r\n\r\n")))
num = len(echo_list)
if num > 0:
print(f"包数量: {num}")
else:
print("没有找到任何包,请检查是否以管理员权限运行")
# 创建一个空列表,用于存储包的信息
pkg_list = [] # 包列表
name_list = []
dev_list = []
# 遍历echo_list中的每个元素(即每个包的信息)
for echo_item in echo_list:
# 将字符串按照换行符进行分割,得到一个列表
lines = str(echo_item).split("\n")
# 创建一个空字典,用于存储当前包的信息
appinfdic = {}
# 遍历lines中的每个元素(即当前包的一行信息)
for x in lines:
# 如果当前行包含冒号,说明该行是一个键值对
if ":" in x:
# 使用split方法将字符串按照冒号进行分割,得到一个列表,其中第一个元素为键,第二个元素为值
k, v = x.split(":", 1)
# 将键和值去除首尾空格后存入字典
appinfdic[k.strip()] = v.strip()
# 只添加"NonRemovable"为"False"的包到包列表中
if appinfdic.get("NonRemovable") == "False" and appinfdic.get("IsFramework") == "False":
pkg_list.append(appinfdic) # 将一个包字典存入包列表
name_list.append(appinfdic.get('Name'))
if appinfdic.get("SignatureKind") == "Developer":
dev_list.append(appinfdic.get('Name'))
name_list = tidy(name_list)
print("可卸载的非框架应用", len(name_list))
# 界面布局
sg.set_options(font=('微软雅黑', 8))
sg.theme('Default1')
# sg.theme('GreenMono')
# sg.theme('LightBlue6')
# sg.theme('DarkAmber')
# sg.theme('BlueMono')
# sg.theme('LightBrown10')
# sg.theme('LightGrey')
row_cap = 4 if len(name_list) > 33 else 3
frame_layout = []
row_layout = []
for i, capp in enumerate(name_list):
if i % row_cap == 0: # 如果当前是新行的开始
row_layout = []
column_layout = [[ # 创建单个应用的Column布局
sg.Checkbox(getName(capp), size=(30, 1), key=capp, text_color=getColor(capp)),
sg.Button('详情', key=f'btinfo-{capp}'),
sg.Button('卸载', key=f'button-{capp}')
]]
row_layout.append(sg.Column(column_layout)) # 将该Column添加到当前行布局
# 当达到每行的最大元素数或者处理到最后一个应用时,将当前行布局添加到主布局中
if len(row_layout) == row_cap or i == len(name_list) - 1:
frame_layout.append(row_layout)
layout = [ # 创建一个表格布局,其中包含表格布局和提交和取消按钮
[sg.Frame('可卸载的非框架应用', frame_layout)],
[
sg.Button('全选'),
sg.Button('反选'),
sg.Button('全不选'),
sg.Button('复制名称', button_color=('WHITE', '#CA7508')),
# sg.Button('显示信息'),
sg.Button('推荐卸载', button_color=('white', 'springgreen4')),
sg.Button('一键卸载', button_color=('white', 'firebrick3')),
sg.Checkbox('多线程', key='threads', default=False),
# sg.Button('检查存在状态', button_color=('white', '#132843')),
sg.Button('退出'),
sg.Text('第三方', text_color='blue'),
sg.Text('不推荐卸载', text_color='purple'),
sg.Text('已卸载', text_color='red'),
]
]
# sg.theme('SystemDefaultForReal')
window = sg.Window('WinAppsUninstaller 240724', layout)
while True: # 添加事件循环
event, values = window.read()
if event in (sg.WIN_CLOSED, '退出'):
break
if event.startswith('button-'):
app_name = event.split('-')[1]
uninstall(app_name)
if event.startswith('btinfo-'):
app_name = event.split('-')[1]
powershell_command = f"Get-AppxPackage {app_name} | Select-Object Name, PackageFullName, Version, InstallLocation, Dependencies"
echo = subprocess.check_output(["powershell", powershell_command]).decode("utf-8")
print(echo)
if event == '全选':
for aapp in name_list:
window[aapp].update(value=True)
if event == '反选':
for app in name_list:
window[app].update(value=not window[app].get())
if event == '全不选':
for app in name_list:
window[app].update(value=False)
if event == '一键卸载':
selected_apps = [app for app in name_list if window[app].get()]
if sg.popup_yes_no(f'确定要卸载选中的{len(selected_apps)}个应用吗?') == 'Yes':
start_time = time.time()
# 如果key=threads的值为1,则使用单线程执行任务
if not values['threads']:
print('单线程模式')
for app in selected_apps:
uninstall(app)
else:
print('多线程模式')
with ThreadPoolExecutor() as executor:
futures = [executor.submit(uninstall, app, True) for app in selected_apps]
for future in futures: # 等待所有任务完成
future.result()
for x in selected_apps:
window[x].update(text_color='red')
print('默认线程数:', os.cpu_count())
end_time = time.time()
print(f'卸载时间: {end_time - start_time:.2f}秒')
sg.popup('卸载完成', f'已卸载{len(selected_apps)}个应用')
if event == '复制名称':
selected_apps = [app for app in name_list if window[app].get()]
pyperclip.copy('\n'.join(selected_apps))
print(selected_apps)
print('已复制到剪切板', len(selected_apps), '个应用')
if event == '推荐卸载':
for app in name_list:
if app in rec_list:
window[app].update(value=True)
if event == '检查存在状态':
uninstalled_apps = []
selected_apps = [app for app in name_list if window[app].get()]
for app in selected_apps:
if notfoundAppx(app):
uninstalled_apps.append(app)
print(app, '确认已卸载!')
else:
print(app, '存在!')
for app in uninstalled_apps:
window[app].update(text_color='red')
window.close()
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/sendbysend/appx_manager.git
[email protected]:sendbysend/appx_manager.git
sendbysend
appx_manager
AppXManager
master

搜索帮助