本文由 简悦 SimpRead转码, 原文地址 scriptingosx.com
MacOS 上的 AppleScript 对于专业用户和管理员来说都是非常有用的工具。尽管它可能......
对于专业用户和管理员来说,macOS 上的 AppleScript 都是非常有用的工具。尽管它可能不是(也不应该是)许多任务的首选工具,但 AppleScript 能让某些任务变得非常简单。因此,它应该成为 "MacAdmin 工具带 "的一部分。
AppleScript 的优势在于应用程序间的通信。通过 AppleEvents(或 AppleScript 命令),你往往可以从其他应用程序中获取有价值的信息,而这些信息是很难甚至不可能通过其他方式获取的。通过 AppleScript,你甚至可以在目标应用程序中创建和更改数据。
如果你有任何安全和隐私方面的考虑,这应该会让你兴奋不已。在 macOS 10.13 High Sierra 之前,任何非沙盒应用程序都可以使用 AppleScript 和 AppleEvents 从各种支持脚本的应用程序和服务中收集各种个人隐私数据。它甚至可以使用 Mail 等支持脚本的应用程序,以你的名义创建和发送电子邮件。
自 macOS Mojave 以来,安全和隐私控件限制了 AppleEvents 的发送和接收。特定进程只能在获得用户批准后才能向不同进程发送事件。用户可以在 "安全与隐私 "偏好窗格的 "隐私 "选项卡中管理应用程序间的审批。
MacAdmin 可以选择使用从 DEP 注册或用户批准的 MDM 推送的 PPPC(隐私偏好策略控制)配置文件,预先批准应用程序间事件。
隐私批准
使用 osascript 从 shell 向另一个进程发送事件时,可以从终端触发安全审批:
> osascript -e 'tell application "Finder" to get POSIX path of ((target of Finder window 1) as alias)'
从终端运行此命令时,可能会出现以下提示:
如果您之前已批准或拒绝终端应用程序向该特定目标应用程序发送事件,则不会收到此提示。您可以在 "系统偏好设置 "的 "安全与隐私 "窗格中的 "隐私 "选项卡的 "自动化 "部分检查用户授予的权限。
对于任何给定的源/目标应用程序组合,提示只会显示 一次。当用户批准该权限("OK "按钮)时,未来的事件将被允许。
当用户拒绝连接("不允许 "按钮)时,该事件和未来的事件都将被拒绝 而不会有进一步的提示。osascript 将失败,AppleScript 将返回错误 -1743。
> osascript -e 'tell application "Finder" to get POSIX path of ((target of Finder window 1) as alias)'
79:84: execution error: Not authorized to send Apple events to Finder. (-1743)
如果想重新获得批准对话框,可以使用 tccutil 命令重置源程序(终端)的状态:
> tccutil reset AppleEvents com.apple.Terminal
这将从 "隐私 "窗格中的 "自动化"("AppleEvents")区域移除 "终端 "应用程序及其所有目标应用程序,并为今后的每个新请求显示对话框。这在测试过程中非常有用。
处理拒绝
在这种情况下,osascript 将返回错误信息:
if ! osascript -e ' tell app "Finder" to return POSIX path of ((target of Finder window 1) as alias)'
then
echo "osascript encountered an error"
exit 1
fi
然而,osascript 会对所有类型的失败返回错误,而且没有简单的方法来区分它们。例如,当没有打开 Finder 窗口时,上述操作也会失败。
如果要区分 AppleScript 错误,需要在 AppleScript 代码中进行区分:
if ! osascript -s o <<EndOfScript
tell application "Finder"
try
set c to (count of Finder windows)
on error message number -1743
error "Privacy settings prevent access to Finder"
end try
if c is 0 then
return POSIX path of (desktop as alias)
else
return POSIX path of ((target of Finder window 1) as alias)
end if
end tell
EndOfScript
then
echo "osascript failed"
fi
注意:"osascript "的"-s o "选项可使其将 AppleScript 错误打印到标准输出而不是标准错误,这对在管理系统日志中查找错误很有用。
注 2:当从管理和安装脚本(以 root 用户身份运行)运行
osascript时,需要 以当前用户身份运行 以避免出现问题。
避免隐私提示
因此,我们知道一种处理隐私提示的方法。理想情况下,你希望完全避免它们。虽然这并非总是可行,但有几种策略可以奏效。
不要发送到其他进程
在 Mac OS X 过去的版本中(我故意用这个名字,因为时间太久了),显示对话框的脚本可能不会显示在最高窗口层。换句话说,对话框会消失在当前活动窗口的后面。为了避免 "丢失 "对话框,最好的做法是将 "显示对话框 "命令(以及类似命令)发送给刚刚接收到 "激活 "命令的进程:
tell application "Finder"
activate
display dialog "Hello, World!"
end tell
作为 Finder 的替代方案,系统事件进程也经常被使用。Jamf MacAdmin 经常使用 "自助服务"。这样做的额外好处是,对话框看起来就像是来自 Finder 或 "自助服务",包括跳动的 dock 图标。
随着时间的推移,尽管隐藏对话框的根本问题已经解决,但这种做法依然存在。你甚至经常会看到 AppleScript 代码在用户交互以外的命令中使用这种做法,而这种做法本来就没有意义。由于 macOS Mojave 中的隐私限制,这种做法会给某些人带来麻烦,因为你会将 "显示对话框"(或其他)命令发送到一个单独的进程。运行此脚本的进程需要获得批准,才能向 "系统事件 "发送事件。
osascript <<EndOfScript
tell application "System Events"
activate
display dialog "Hello, World!"
end tell
EndOfScript
在当前版本的 macOS 中,你可以直接使用 display dialog 和其他命令,而无需使用外层的 tell 块。由于你的 AppleScript 代码不会向另一个进程发送事件,因此无需隐私许可。这段代码的效果与上述代码相同,但不会触发批准请求。
osascript <<EndOfScript
display dialog "Hello, World!"
EndOfScript
要确定一条 AppleScript 命令是否需要 "tell "代码块,必须检查它来自何处。许多对 MacAdmin 有用的 AppleScript 命令都包含在 "StandardAdditions "脚本扩展中。脚本扩展,顾名思义,就是扩展 AppleScript 的功能,而不需要自己的程序。
Standard Additions 扩展中的实用命令包括
- 用户交互:"choose file/folder/from list"、"display dialog/alert/notification"
- 文件命令:
mount volume - 剪贴板命令:
get the clipboard、set the clipboard to。 - 声音控制:
set volume、get volume settings。 system info
当脚本只使用这些命令时,请确保它们不包含在 tell 块中。这将避免不必要的访问审批提示。
豁免 AppleScript 命令
某些 AppleScript 命令会被区别对待,不会触发隐私审批:
activate: 启动应用程序和/或调到前台open:打开文件open location:打开 URLquit:退出应用程序
例如,这将无需批准即可工作:
osascript <<EndOfScript
tell application "Firefox"
open location "https://scriptingosx.com"
end
EndOfScript
使用非 AppleScript 替代方法
有时,可以通过其他方法实现与 AppleScript 类似的效果。这可能很难理解和实现。
举个例子,在 Mojave 之前,我经常使用这条 AppleScript 命令进行设置:
tell application "Finder" to set desktop picture to POSIX file "/Library/Desktop Pictures/BoringBlueDesktop.png"
Mojave 还处于测试阶段,还不清楚是否或如何管理 PPPC 豁免,因此我寻找了另一种方法。我发现了读取和更改桌面图片而不触发 PPPC 的 Cocoa 函数,并以此构建了一个小型命令行工具: desktoppr.
这种方法的缺点是,你必须在要使用它的客户端上安装和/或管理命令行工具。对此,有不同的策略,但与 "仅仅 "运行 AppleScript 相比,需要付出额外的努力。
建立 PPPC 配置文件以预先批准 AppleEvents
即使考虑了上述避免向其他进程发送 AppleEvents 的方案,在某些情况下仍有必要这样做。对于 MacAdmin 需要在几十台、几百台甚至几千台 Mac 上运行脚本的情况,用户批准根本不是一个可行的选择。
MacAdmin 可以使用隐私偏好策略控制 (PPPC) 配置文件在某些进程之间预先批准 AppleEvents(以及大多数其他隐私区域)。只有从用户批准或自动注册的 MDM 推送时,才能管理 PPPC 配置文件。
您可以手动建立这样的配置文件,但使用工具建立这些配置文件要容易得多:
您的 MDM 解决方案可能有专门的工具或 Web 界面,请查阅文档或询问供应商。
不过,这里有一个很大的要求:只有使用有效 Apple Developer ID 签名的应用程序和工具才能通过这种方式预先获得批准,因为签名是用来识别和验证二进制文件的。
确定需要批准的程序
虽然可以对 shell 脚本和其他脚本进行签名,但通常没有必要这样做。如前所述,当我们从终端运行脚本时,需要审批的不是脚本,而是终端应用程序。当你的脚本从管理系统或其他工具运行时,可能不容易确定到底哪个进程需要审批。
要确定这一点,最实用的方法是记录 "透明、同意和控制 "系统 (tcc) 的输出,并查看是哪个流程发出了请求。
首先,使用一个干净的测试系统,或重置你怀疑可能与 "tccutil "有关的进程的审批。
然后打开一个单独的终端窗口,运行此命令,它将显示 tcc 进程的日志条目流:
> log stream --debug --predicate 'subsystem == "com.apple.TCC" AND eventMessage BEGINSWITH "AttributionChain"'
输出结果中会有很多噪音。
然后按计划在部署过程中的运行方式运行相关脚本。如果计划从管理系统运行脚本,那么现在就运行。您将在上述数据流中获得大量输出。
即使不清楚父进程是什么,也可以过滤输出中的 osascript 条目,因为这通常是使用的中间工具。
在我的示例中,我发现了几个类似的条目:
0 tccd: [com.apple.TCC:access] AttributionChain: RESP:{ID: com.barebones.bbedit, PID[1179], auid: 501, euid: 501, responsible path: '/Applications/BBEdit.app/Contents/MacOS/BBEdit', binary path: '/Applications/BBEdit.app/Contents/MacOS/BBEdit'}, ACC:{ID: com.apple.osascript, PID[18756], auid: 501, euid: 501, binary path: '/usr/bin/osascript'}, REQ:{ID: com.apple.appleeventsd, PID[577], auid: 55, euid: 55, binary path: '/System/Library/CoreServices/appleeventsd'}
这里的重要信息是 "负责路径",它提供了二进制文件和 tcc 认为 "负责 "的外层应用程序。这就是你需要批准的应用程序。
在管理系统中运行脚本时,MDM 供应商/提供商应该已经提供了相关文档,可以省去这些麻烦。
有了所有这些信息,您就可以使用上述工具之一建立 PPPC 配置文件,将其上传到您的 MDM,并在部署脚本运行之前将其推送到客户端。
结论
虽然 AppleEvents 增加了隐私保护,但它确实给自动化管理工作流程增加了一些障碍。
您可以使用一些策略来避免 AppleScript 触发隐私控制。如果这些还不够,您必须建立一个 PPPC 配置文件来预先批准父进程。