在多次挣扎之后,我们的新项目最终决定放弃在watchdog上缝缝补补,在Windows平台上改回成用USN日志的方式监控文件变动。随之带来一个问题:拥有管理员权限的进程才能读取USN日志。
旧项目的方案是额外注册一个系统服务,读取usn日志,并通过管道与主进程通讯。但上线之后发现,系统服务很容易被各种电脑管家误删除,导致程序工作异常。新项目打算在主进程中直接读取usn日志。这就要求使用管理员权限运行主进程。而我们又不想让用户每次启动程序时都弹出一个UAC提示框。最后决定借助计划任务来实现我们的需求。
原理
运行等级(Principal.RunLevel)为TASK_RUNLEVEL_HIGHEST的计划任务,在执行时,被调用的进程会以管理员权限运行。
这种计划任务仅在添加时需要管理员权限。在被触发时,不需要管理员权限,也就不会弹出UAC提示。
实现
创建计划任务
通过com组件ITaskService添加计划任务
重点是把Principal.RunLevel设为TASK_RUNLEVEL_HIGHEST
下列代码展示了如何用Python创建最高权限的计划任务。
注意:运行下列代码时需要管理员权限
1 | import sys |
执行计划任务
同样的,通过com组件ITaskService启动计划任务。此时就不需要管理员权限了。
1 | exist_task = root_folder.GetTask(f'{task_name}') # 如果任务不存在,此处会抛出异常 |
最终流程
启动时检查当前进程是否拥有管理员权限
- 如果没有管理员权限,则检查系统的计划任务服务中有没有注册对应的计划任务。
- 如果没有,则使用ShellExecute/ShellExecuteEx的方式,启动带管理员权限的进程(会弹出UAC对话框),并退出当前进程。
- 如果有,则启动对应的计划任务,并退出当前进程
- 如果有管理员权限,则检查系统的计划任务服务中有没有注册对应的计划任务。
如果不存在,则需要创建/修复计划任务。因为此时程序已经拥有管理员权限,可以直接创建对应的计划任务
其他
方案还需要实现一些辅助的功能,这边也一并列出对应的Python实现
检查当前进程是否有管理员权限
1 | def check_privileges() -> bool |
使用ShellExecuteEx启动带管理员权限的进程
1 | start_args = ['banana', 'kuma~'] |