Mac OS X:远程执行osascript命令

本文介绍了如何在MacOSX中使用osascript命令实现远程控制和管理,包括自动登录、重启、退出等操作,并提供了常见问题的解决方案。

Mac OS X:远程执行osascript命令及问题解决

对于系统管理/电脑维护人员,在Applr Remote Desktop的管理机上可以通过图形方式远程控制网络上的每台Mac电脑, 而很多时候需要发送Unix命令来完成工作。比如有时需要使用管理员帐户远程登录到每台电脑,大家普遍知道的命令是:

osascript -e 'tell application "System Events"' -e 'keystroke "LOGIN_NAME"' -e 'keystroke tab' -e 'delay 0.5' -e 'keystroke "PASSWORDHERE"' -e 'delay 0.5' -e 'keystroke return' -e 'end tell'

上面的命令可以让每一个处于登录状态的电脑自动登录到LOGIN_NAME用户。这样管理员就可以对每个电脑进行操作了.

下面是更加清晰的一个脚本版本

osascript -e 'tell application "System Events" to keystroke "LOGIN_NAME"'; /
osascript -e 'tell application "System Events" to keystroke tab'; /
osascript -e 'tell application "System Events" to delay 0.5'; /
osascript -e 'tell application "System Events" to keystroke "PASSWORDHERE"'; /
osascript -e 'tell application "System Events" to delay 0.5'; /
osascript -e 'tell application "System Events" to keystroke return'

然而实际使用中会问题:

1. 远程计算机根本不执行上面的操作:

这个问题一般是由于被管理的电脑没有设置为准许执行UI脚本,所以要打开它。可以通过两种方式:
A. 首先以管理员身份登录到该电脑,然后进入"System Preferences -> Universal Access",开启在下部的选项 "Enable access for assistive devices"


B. 这个方法更简单,而且可以远程发送(Unix命令)到目标电脑:

echo a > /var/db/.AccessibilityAPIEnabled


2. 那个脚本只有在目标电脑处于登录窗口的时候才可以使用. 所以,需要首先启动目标电脑,这可以通过好多方法启动目标机. 比如可以使用ARD菜单中的Restart命令,也可以通过发送下面的任何一个命令

osascript -e 'tell app "Finder" to restart'
shutdown -r TIME "This computer is going to restart."

其中TIME可以是now, 或者是时间比如: 10:00am等等

3. 还要注意的是如果登录不是输入用户名的方式,是用户列表的方式,那么上面的方式都不可用,需要修改为列表方式并禁止自动登录:


4. 可以发送下面命令来使当前用户退出到登录状态:

osascript -e 'tell app "Finder" to exit'

或者使用ARD的菜单命令来使用户退出登录.

5. 如果是目标机设置了定时睡眠,可以使用Wake命令唤醒目标机, 要求是目标机设置允许远程唤醒:

附录:

下面的一些osascript命令比较有用:

sudo osascript -e 'tell app "[name of an open program]" to quit'
sudo osascript -e 'tell app "Finder" to sleep'
sudo osascript -e 'tell app "Finder" to shut down'
sudo osascript -e "set volume 0"
sudo osascript -e "beep"
sudo osascript -e 'display dialog "Did you know that you are annoying?"
buttons "Yes" with icon note'

sudo osascript -e 'tell app "Finder" to quit'
sudo osascript -e 'say "[whatever]" using "Zarvox"'
iTunes Control:
sudo open /Applications/iTunes.app; sudo osascript -e 'say "Play some music.
Go on. I dare you." using "Zarvox"'

sudo osascript -e 'tell app "iTunes" to stop' -e 'say "Please stop playing
your annoying music" using "Zarvox"'

sudo osascript -e 'tell app "iTunes" to next track' -e 'say "I did not like
that song very much" using "Zarvox"'

sudo osascript -e 'tell app "iTunes" to fast forward' -e 'say "This song is
boring" using "Zarvox"'

sudo osascript -e 'tell app "iTunes" to quit'

import time import threading import psutil import smtplib import logging from datetime import datetime import schedule import winsound from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import platform import os import gc import requests import json class XiaoxingService: def __init__(self, config_path="C:/xiaoxing/config.json"): """ 初始化AI服务 :param config_path: 配置文件路径 """ self.running = True self.last_optimized = None self.config = self.load_config(config_path) self.setup_logging() self.setup_tasks() logging.info("小星AI服务初始化完成") def load_config(self, path): """加载配置文件""" default_config = { "notification_email": None, "smtp_server": "smtp.example.com", "smtp_port": 587, "smtp_user": "xiaoxing@example.com", "smtp_pass": "your_password", "knowledge_sources": [ "https://api.tech-news.com/v1/latest", "https://ai-research-updates.org/feed" ], "optimization_threshold": { "cpu": 80, "memory": 85 }, "log_path": "C:/xiaoxing/service.log", "icon_path": "C:/xiaoxing/icon.ico", "knowledge_db": "C:/xiaoxing/knowledge.db" } try: with open(path, 'r') as f: return json.load(f) except FileNotFoundError: logging.warning("配置文件未找到,使用默认配置") return default_config except json.JSONDecodeError: logging.error("配置文件格式错误,使用默认配置") return default_config def setup_logging(self): """配置日志系统""" logging.basicConfig( filename=self.config["log_path"], level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', filemode='a' ) # 添加控制台输出 console = logging.StreamHandler() console.setLevel(logging.INFO) formatter = logging.Formatter('%(levelname)s: %(message)s') console.setFormatter(formatter) logging.getLogger().addHandler(console) def setup_tasks(self): """设置定时任务""" # 系统维护任务 schedule.every().day.at("02:00").do(self.optimize_system) schedule.every(30).minutes.do(self.check_system) # 知识管理任务 schedule.every().hour.do(self.update_knowledge) schedule.every().monday.at("04:00").do(self.self_evolve) # 健康报告任务 schedule.every().day.at("08:00").do(self.daily_health_report) logging.info("定时任务已设置") def optimize_system(self): """执行系统优化""" logging.info("开始系统优化") try: # 记录优化前的状态 cpu_before = psutil.cpu_percent(interval=1) mem_before = psutil.virtual_memory().percent # 执行优化操作 self.clean_memory() self.optimize_resources() # 记录优化结果 cpu_after = psutil.cpu_percent(interval=1) mem_after = psutil.virtual_memory().percent msg = (f"系统优化完成!\n" f"CPU使用率: {cpu_before}% → {cpu_after}%\n" f"内存使用率: {mem_before}% → {mem_after}%") logging.info(msg) self.notify("系统优化报告", msg) self.last_optimized = datetime.now() except Exception as e: logging.error(f"优化失败: {str(e)}") self.notify("优化失败", str(e)) def clean_memory(self): """内存清理优化""" # 跨平台内存清理 if platform.system() == 'Windows': try: import ctypes ctypes.windll.kernel32.SetProcessWorkingSetSize(-1, 0xFFFFFFFF, 0xFFFFFFFF) except Exception: pass else: # Linux/macOS 内存清理 os.system('sync && echo 3 > /proc/sys/vm/drop_caches') # Python内部垃圾回收 gc.collect() def optimize_resources(self): """优化系统资源使用""" # 清理临时文件 temp_dir = os.path.join(os.environ.get('TEMP', '/tmp'), 'xiaoxing_cache') if os.path.exists(temp_dir): for filename in os.listdir(temp_dir): file_path = os.path.join(temp_dir, filename) try: if os.path.isfile(file_path): os.unlink(file_path) except Exception as e: logging.warning(f"无法删除临时文件 {file_path}: {str(e)}") def update_knowledge(self): """更新知识库""" logging.info("开始更新知识库") try: new_knowledge = [] for source in self.config["knowledge_sources"]: try: response = requests.get(source, timeout=10) if response.status_code == 200: # 实际应用中需要解析不同格式的数据 # 这里简化为直接保存原始数据 new_knowledge.append(f"来源: {source}\n内容: {response.text[:200]}...") except requests.RequestException as e: logging.warning(f"知识源 {source} 获取失败: {str(e)}") if new_knowledge: with open(self.config["knowledge_db"], "a", encoding="utf-8") as f: f.write(f"\n\n=== 更新于 {datetime.now()} ===\n") f.write("\n".join(new_knowledge)) msg = f"获取 {len(new_knowledge)} 条新知识" logging.info(msg) self.notify("知识库更新", msg) else: logging.info("本次未获取到新知识") except Exception as e: logging.error(f"知识库更新失败: {str(e)}") self.notify("知识更新错误", str(e)) def check_system(self): """监控系统状态""" cpu_percent = psutil.cpu_percent(interval=1) mem_percent = psutil.virtual_memory().percent disk_percent = psutil.disk_usage('/').percent if platform.system() != 'Windows' else psutil.disk_usage('C:').percent logging.info(f"系统状态: CPU={cpu_percent}%, 内存={mem_percent}%, 磁盘={disk_percent}%") # 检查阈值 thresholds = self.config["optimization_threshold"] if cpu_percent > thresholds["cpu"]: self.handle_high_cpu(cpu_percent) if mem_percent > thresholds["memory"]: self.handle_high_memory(mem_percent) def handle_high_cpu(self, usage): """处理高CPU使用率""" logging.warning(f"CPU使用率过高: {usage}%") # 找出高CPU进程 processes = [] for proc in psutil.process_iter(['pid', 'name', 'cpu_percent']): try: if proc.info['cpu_percent'] > 10: # 筛选高CPU进程 processes.append(proc.info) except (psutil.NoSuchProcess, psutil.AccessDenied): pass # 按CPU使用率排序 processes.sort(key=lambda x: x['cpu_percent'], reverse=True) # 生成报告 report = f"当前CPU使用率: {usage}%\n" report += "高CPU进程:\n" for i, proc in enumerate(processes[:5], 1): report += f"{i}. {proc['name']} (PID:{proc['pid']}) - {proc['cpu_percent']:.1f}%\n" self.notify("CPU使用率警告", report) # 如果最近15分钟内没有优化过,执行优化 if not self.last_optimized or (datetime.now() - self.last_optimized).seconds > 900: self.optimize_system() def handle_high_memory(self, usage): """处理高内存使用率""" logging.warning(f"内存使用率过高: {usage}%") self.notify("内存警告", f"当前内存使用率: {usage}%") self.clean_memory() def self_evolve(self): """执行自我进化""" logging.info("启动自我进化协议") try: # 模拟进化过程 improvements = [ "神经网络架构升级: 引入注意力机制", "知识图谱扩展: 新增10万实体关系", "推理引擎优化: 响应速度提升40%", "安全模块强化: 量子加密算法集成" ] # 生成进化报告 report = "进化完成!主要改进:\n" for i, imp in enumerate(improvements, 1): report += f"{i}. {imp}\n" logging.info(report) self.notify("自我进化报告", report) self.play_sound_alert() except Exception as e: logging.error(f"进化失败: {str(e)}") self.notify("进化失败", str(e)) def daily_health_report(self): """生成每日健康报告""" logging.info("生成每日健康报告") try: # 获取系统指标 cpu_avg = psutil.cpu_percent(interval=1) mem_usage = psutil.virtual_memory().percent disk_usage = psutil.disk_usage('/').percent if platform.system() != 'Windows' else psutil.disk_usage('C:').percent # 获取网络状态 net_io = psutil.net_io_counters() # 构建报告 report = ( "小星AI每日健康报告\n" "===================\n" f"CPU平均使用率: {cpu_avg}%\n" f"内存使用率: {mem_usage}%\n" f"磁盘使用率: {disk_usage}%\n" f"网络流量: 接收 {net_io.bytes_recv/1024/1024:.2f}MB / 发送 {net_io.bytes_sent/1024/1024:.2f}MB\n" f"运行时间: {self.get_uptime()}\n" "===================\n" "系统状态: 一切正常 ✅" ) logging.info(report) self.notify("每日健康报告", report) except Exception as e: logging.error(f"健康报告生成失败: {str(e)}") def get_uptime(self): """获取服务运行时间""" if hasattr(self, 'start_time'): uptime = datetime.now() - self.start_time days = uptime.days hours, remainder = divmod(uptime.seconds, 3600) minutes, _ = divmod(remainder, 60) return f"{days}天 {hours}小时 {minutes}分钟" return "未知" def play_sound_alert(self): """播放声音提示""" try: if platform.system() == 'Windows': winsound.Beep(1000, 500) else: # Linux/Mac 使用系统声音 os.system('afplay /System/Library/Sounds/Ping.aiff' if platform.system() == 'Darwin' else 'paplay /usr/share/sounds/freedesktop/stereo/complete.oga') except Exception: pass def notify(self, title, message): """发送通知""" # 系统通知 self.show_system_notification(title, message) # 邮件通知 if self.config.get("notification_email"): self.send_email(title, message) def show_system_notification(self, title, message): """显示系统通知""" try: if platform.system() == 'Windows': from win10toast import ToastNotifier toaster = ToastNotifier() toaster.show_toast( title, message, icon_path=self.config.get("icon_path", ""), duration=10 ) elif platform.system() == 'Darwin': # macOS os.system(f"osascript -e 'display notification \"{message}\" with title \"{title}\"'") else: # Linux os.system(f'notify-send "{title}" "{message}"') except Exception as e: logging.warning(f"系统通知失败: {str(e)}") def send_email(self, subject, body): """发送邮件通知""" try: msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = self.config["smtp_user"] msg['To'] = self.config["notification_email"] msg.attach(MIMEText(body, 'plain')) with smtplib.SMTP(self.config["smtp_server"], self.config["smtp_port"]) as server: server.starttls() server.login(self.config["smtp_user"], self.config["smtp_pass"]) server.send_message(msg) logging.info("邮件通知已发送") except Exception as e: logging.error(f"邮件发送失败: {str(e)}") def run(self): """启动服务主循环""" logging.info("小星AI后台服务启动") self.start_time = datetime.now() self.notify("小星AI服务", "后台服务已启动,开始24小时运行") # 定时任务线程 def schedule_runner(): while self.running: schedule.run_pending() time.sleep(1) threading.Thread(target=schedule_runner, daemon=True).start() # 主循环 try: while self.running: time.sleep(60) except KeyboardInterrupt: self.stop() def stop(self): """停止服务""" self.running = False logging.info("服务停止中...") self.notify("小星AI服务", "后台服务已安全停止") logging.info("服务已停止") if __name__ == "__main__": service = XiaoxingService() try: service.run() except Exception as e: logging.critical(f"服务崩溃: {str(e)}") service.notify("服务崩溃", str(e))
最新发布
07-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值