windows自动关机程序(python版)

小初seo 学习笔记357字数 4075阅读13分35秒阅读模式
摘要

医院环境的自动关机程序探索

医院科室的终端电脑没有关机的习惯,除了浪费能源,还容易诱发安全问题。很多黑客事件都是发生在夜里,长时间不关机的终端电脑容易成为肉鸡或跳板。夜间因值班人员疲惫,当出现异常时也许不会第一时间发觉,无人看管的主机很容易成为被攻击的对象。

所以打算写一个自动关机的程序,通过参数文件控制关机时刻,以及控制是否需要关机或重启。毕竟像收费窗口、手术室电脑是不允许突然关机的。异常的无准备关机可能会造成财务账页不平或手术过程被干扰。

为了观察自动关机程序的行为,在程序中加了日志开关。通过日志开关来控制程序心跳输出,通过日志输出可以得知程序是否还活着或按预期执行。

程序日志信息如下:

windows自动关机程序(python版)

程序代码如下:

#!python3

import sys
import time
import os
from configparser import ConfigParser  

class MyLog:
    def __init__(self, log_dir):
        self.is_off = True
        self.log_dir = log_dir
        self.log_prefix = 'x-'

        if not os.path.exists(log_dir):
            os.makedirs(log_dir)

        self.logfile = os.path.join(log_dir,
                                    self.log_prefix + 
                                    str(time.strftime('%Y-%m-%d', time.localtime())) +
                                    '.log')

        self.file = open(file=self.logfile, mode='a', encoding='utf-8')

    def on(self):
        self.is_off = False

    def off(self):
        self.is_off = True

    def write(self, log_content):
        if self.is_off:
            pass
        else:
            self.file.write(log_content)
            self.file.flush()

    def reload_log(self):
        self.file.close()
        self.logfile = os.path.join(self.log_dir, str(time.strftime('%Y-%m-%d', time.localtime()))+'.log')
        self.file = open(file=self.logfile, mode='a', encoding='utf-8')

    def __del__(self):
        self.file.close()


def shutdown(second):
    cmd = 'shutdown -s -t ' + second
    os.system(cmd)


def reboot(second):
    cmd = 'shutdown -r -t ' + second
    os.system(cmd)


def cancel():
    os.system('shutdown -a')


def shutdown_conf(f):
    conf = ConfigParser()  
    conf.read(f, encoding='utf-8')
    shutdown_time = conf['shutdown']['shutdown_time']
    is_shutdown = conf['shutdown'].getboolean('is_shutdown')
    is_reboot = conf['shutdown'].getboolean('is_reboot')
    wait_second = conf['shutdown']['wait_second']
    return [shutdown_time, is_shutdown, is_reboot, wait_second]


def logging_conf(f):
    conf = ConfigParser()  
    conf.read(f, encoding='utf-8')
    is_off = conf['logging'].getboolean('is_off')
    log_dir = conf['logging']['log_dir']
    frequency = conf['logging']['frequency']
    prefix = conf['logging']['prefix']
    return [is_off, log_dir, frequency, prefix]

def base_conf(f):
    conf = ConfigParser()  
    conf.read(f, encoding='utf-8')
    conf_file = conf['conf']['conf_file']
    return conf_file


def default_conf(conf_file):
    '''如果配置文件不存在,就写入默认配置'''
    content = r'''
[shutdown]
; 注释:自动关机配置文件

; 定义每天关机的触发时刻, 24小时制
; 格式:03:00
shutdown_time = 01:30

; 是否自动关机 True 或 False
is_shutdown = True

; 是否自动重启 True 或 False
; 优先判断是否关机,当不关机时,判断是否重启
is_reboot = False

; 关机或重启前的等待时长,单位为秒
; 在倒计时结束前可以取消
wait_second = 180

[logging]
; 注释:默认日志信息

; 是否写日志
is_off = False

; 日志位置
log_dir = c:\autox\logs

; 更新日志文件的频率,每 sleep 120 次重新加载一下日志文件
; 目的是切换日志文件名称,特别是跨天时
frequency = 120

; 日志前缀
prefix = x

[conf]
; 注释:默认配置文件信息

; 配置文件
conf_file = c:\autox\autox.ini

'''
    if os.path.exists(conf_file):
        return False
    conf_folder = os.path.dirname(os.path.abspath(conf_file))

    if not os.path.exists(conf_folder):
        os.makedirs(conf_folder)
    
    with open(file=conf_file, mode='w', encoding='utf-8') as f:
        f.write(content)


def wait(shutdown_time):
    '''等待关机时刻到来'''
    global log
    global conf
    log.write('\n\n\nLogging: 程序开始执行\n')
    log.write('Logging: 关机时刻 %s\n' % shutdown_time)
    logging_param = logging_conf(conf)
    n = 1
    # 每循环m次,重新加载一下log文件
    # logging_conf => frequency
    m = int(logging_param[2])
    while True:
        now = time.strftime('%H:%M')
        if now != shutdown_time:
            time.sleep(2)
            n += 1
            if n >= m:
                n = 1
                log.reload_log()
                log.write('Logging: 关机时刻 %s\n' % shutdown_time)
                # 检查配置文件是否有更新
                # 使用配置文件中的 logging 参数控制是否输出日志
                logging_param = logging_conf(conf)
                # logging_conf => is_off
                log.is_off = logging_param[0]
                # logging_conf => frequency
                m = int(logging_param[2])
            now = time.strftime('%H:%M')
            current = time.strftime('%H:%M:%S')
            log.write('Logging: 等待 %s\n' % current)
        else:
            break
    log.write('Logging: 准备关机!\n')


log = MyLog(r'c:\autox\logs')
conf = r'c:\autox\autox.ini'
# log 开关
# 配置文件中的开关会覆盖程序代码中的
# 程序执行以后需要通过配置文件来控制程序行为
log.is_off = False

def main():
    while True:
        global log
        global conf
        try:
            # 当配置文件不存在时,写入默认配置文件
            default_conf(conf)
            # 加载自动关机的参数
            # 当关机被手动取消时进入下一轮循环
            shutdown_time,is_shutdown,is_reboot,wait_second = shutdown_conf(conf)
            
            # 等到关机时刻到来
            wait(shutdown_time)

            if is_shutdown:
                shutdown(wait_second)
            if is_reboot:
                reboot(wait_second)
            
            # 等待系统重启倒计时
            # 在此期间如果关机动作被手工取消则进入下一轮循环
            time.sleep(int(wait_second))
            
        except Exception as e:
            log.write(f'Error: {e}\n')


if __name__ == '__main__':
    main()

后期准备将程序打包成 exe 格式,并让程序在后台执行。设计成死循环主要是为了保障关机程序可以一起正常执行。并且程序大部分时间处于sleep状态,并不消耗资源。

通过配置文件控制,后期可以增加扩展性功能。比如自动更新、程序自启动。自动关机只是v0.1版的一个功能点,既然准备让这个程序在医院的终端电脑上一直执行,就准备将其作为一个agent,通过更新配置文件和程序版本来提供更多功能。

这里是一个医院环境的自动化运维的初级设想,在医院的终端上埋一个可自动更新的程序。程序可以在后续版本更新中完成指定任务,比如自动安装其它程序,或一些自定义任务。

程序的第一次下发使用医院的HIS程序或天擎程序分发模块。后续将完善程序的自更新功能,让其脱离其它分发程序可以自动更新。

全文完。

  • 本文由 发表于 2023年1月4日 22:43:26
  • 转载请务必保留本文链接:https://www.pkak.cn/9244.html