欢迎各位兄弟 发布技术文章
这里的技术是共享的
我在 jamf 中 策略中执行 其它策略
本策略代码如下
#!/bin/bash
#
sudo -E jamf policy -id 251 # 251 是搜狗拼音策略的 id
在其它策略(id 为 251 和 -id 为 231 )中 ,,有 (/usr/bin/osascript) 这个代码,,,在251 和 231 的策略中,需要执行 (/usr/bin/osascript)
但是 本策略中 不需要执行 (/usr/bin/osascript)
策略id 为 251 的代码
#!/bin/bash
#
/bin/mkdir -p "${HOME}/Desktop/downloadfromjamf"
cd "${HOME}/Desktop/downloadfromjamf"
/usr/bin/curl -o "./sogou_pinyin_mac_intel_m1_615b.zip" http://aaaa.bbbb-ccc.com/util/software/sogou_pinyin_mac_intel_m1_615b.zip
unzip -o "./sogou_pinyin_mac_intel_m1_615b.zip"
chmod -R 777 "${HOME}/Desktop/downloadfromjamf"
sudo "./sogou_mac_615b.app/Contents/MacOS/SogouInstaller"
(/usr/bin/osascript -e 'display dialog "成功安装搜狗拼音,重启后生效,您可以删除桌面上的downloadfromjamf目录!" buttons {"OK"} default button "OK"')
#把文件夹权限置为 777 ,让所有人可以删
sudo chmod -R 777 "${HOME}/Desktop/downloadfromjamf/"
#cd ../
#rm -Rf "${HOME}/Desktop/downloadfromjamf"
sudo spctl --master-disable
exit 0
你的目标是:
在调用 jamf policy -id 251 时正常执行策略(包括 /usr/bin/osascript 弹窗)。
但在主脚本中(调用 251 的主策略)禁止运行 osascript。
以下是几种解决方法,从最推荐到最彻底:
直接修改 251 策略的脚本,使其仅在 SKIP_OSASCRIPT 未设置时运行弹窗:# OK OOK 有大用 有大大用
bash#!/bin/bash # ...(前面的代码不变) # 仅当未设置 SKIP_OSASCRIPT 时才弹窗 if [[ -z "$SKIP_OSASCRIPT" ]]; then /usr/bin/osascript -e 'display dialog "成功安装搜狗拼音,重启后生效,您可以删除桌面上的downloadfromjamf目录!" buttons {"OK"} default button "OK"' fi sudo chmod -R 777 "${HOME}/Desktop/downloadfromjamf/" sudo spctl --master-disable exit 0
然后在你的主脚本中: # OK OOK 有大用 有大大用
sudo 默认会清除环境变量
macOS 的 sudo 默认启用 env_reset 选项,会丢弃所有用户自定义的环境变量(除非明确配置允许继承)。
jamf policy 以 root 权限运行
即使不用 sudo,jamf policy 自身也会以 root 权限执行,继承的环境变量可能被过滤。
解决方案: 方法 1:通过 sudo 显式传递变量 # -E (environment ) 保留当前用户环境变量 # OK 有大用 有大大用
bash#!/bin/bashexport SKIP_OSASCRIPT=1 # 阻止 251 弹窗 sudo -E jamf policy -id 251
优点:
最干净、最可控的方式。
不影响其他系统功能。
osascript(仅限当前 shell)如果无法修改 251,可以临时替换 osascript:
bash#!/bin/bash # 临时伪造 osascript 函数 osascript() { echo "Skipping osascript (主策略拦截)" >&2 } export -f osascript # 执行 JAMF 策略(251/231 仍会正常弹窗) sudo -E jamf policy -id 251 sudo -E jamf policy -id 231
限制:
仅对 bash/zsh 有效,部分情况可能失效(如 sudo 环境)。
PATH 重定向(更强拦截)bash#!/bin/bash # 1. 创建假的 osascript mkdir -p /tmp/fakebin echo '#!/bin/sh' > /tmp/fakebin/osascript echo 'echo "Skipping osascript" >&2' >> /tmp/fakebin/osascript chmod +x /tmp/fakebin/osascript # 2. 优先使用假命令 export PATH="/tmp/fakebin:$PATH" # 3. 执行 JAMF 策略(251/231 不受影响) sudo -E jamf policy -id 251 sudo -E jamf policy -id 231 # 4. 恢复 PATH(可选) unset PATH
优点:
拦截更彻底,但仍不影响子进程。
osascript(不建议)bash#!/bin/bash # 1. 备份原版 osascript sudo mv /usr/bin/osascript /usr/bin/osascript.bak # 2. 替换成空命令 echo '#!/bin/sh' | sudo tee /usr/bin/osascript sudo chmod +x /usr/bin/osascript # 3. 执行策略(251/231 不会弹窗) sudo -E jamf policy -id 251 sudo -E jamf policy -id 231 # 4. 恢复原版 sudo mv /usr/bin/osascript.bak /usr/bin/osascript
⚠️ 风险:
可能破坏依赖 osascript 的系统功能。
恢复时可能因权限问题失败。
SIP 开启时可能无法修改。
| 方法 | 适用场景 | 风险 | 可控性 |
|---|---|---|---|
| 修改子策略 (方法1) | 最佳长期方案 | 无 | 100% |
| 环境变量拦截 (方法2) | 快速临时方案 | 可能失效 | 中 |
PATH 重定向 (方法3) | 强拦截,兼容性好 | 极小 | 高 |
| 替换二进制 (方法4) | 终极手段 | 高 | 低 |
bash#!/bin/bash # 方法1(需修改251策略) export SKIP_OSASCRIPT=1 sudo -E jamf policy -id 251 sudo -E jamf policy -id 231 # 或方法3(不需修改251) mkdir -p /tmp/fakebin echo '#!/bin/sh' > /tmp/fakebin/osascript echo 'exit 0' >> /tmp/fakebin/osascript chmod +x /tmp/fakebin/osascript export PATH="/tmp/fakebin:$PATH" sudo -E jamf policy -id 251 sudo -E jamf policy -id 231
采用 方法1 或 方法3 可稳定解决,同时避免系统风险!
#!/bin/bash
export SKIP_OSASCRIPT=1 # 阻止 251 弹窗
sudo -E jamf policy -id 251
sudo -E jamf policy -id 231
这段代码后面 我还想执行 /usr/bin/osascript
如果你想在 执行完 sudo -E jamf policy -id 251 后 恢复 osascript 功能,以便后续可以正常调用 /usr/bin/osascript,以下是几种解决方案:
SKIP_OSASCRIPT(推荐) # OK OOK 有大用 有大大用bash#!/bin/bash # 阻止 251/231 弹窗 export SKIP_OSASCRIPT=1 sudo -E jamf policy -id 251 sudo -E jamf policy -id 231 # 恢复 osascript 功能 unset SKIP_OSASCRIPT # 后续正常执行 osascript /usr/bin/osascript -e 'display dialog "This will now run normally!" buttons {"OK"}'
工作原理:
export SKIP_OSASCRIPT=1 让 251/231 跳过弹窗。
unset SKIP_OSASCRIPT 恢复 osascript 功能。
此后所有的 /usr/bin/osascript 调用都不会被拦截。
前提:需要修改 251 策略(增加 if [[ -z "$SKIP_OSASCRIPT" ]] 判断)。
下面的所有的其实已经可以不看了
PATH 重定向(无需修改 251)bash#!/bin/bash # 创建假的 osascript(临时跳过) mkdir -p /tmp/fakebin echo '#!/bin/sh' > /tmp/fakebin/osascript echo 'echo "Skipping osascript" >&2' >> /tmp/fakebin/osascript chmod +x /tmp/fakebin/osascript # 仅当前脚本优先用假 osascript export PATH="/tmp/fakebin:$PATH" # 执行策略(251/231 不会触发弹窗) sudo -E jamf policy -id 251 sudo -E jamf policy -id 231 # 恢复原本的 PATH(使 osascript 恢复正常) export PATH="${PATH#/tmp/fakebin:}" # 现在可以正常执行 osascript /usr/bin/osascript -e 'display dialog "Now working normally!" buttons {"OK"}' # 清理假的 osascript(可选) rm -rf /tmp/fakebin
优点:
不需要修改 251 策略。
仅临时拦截,不影响全局。
function 临时覆盖bash#!/bin/bash # 备份原版 osascript original_osascript="$(which osascript)" # 定义临时替代函数 osascript() { echo "Skipping osascript for jamf policies" >&2 return 0 } export -f osascript # 251/231 不会弹窗 sudo -E jamf policy -id 251 sudo -E jamf policy -id 231 # 恢复原版 osascript osascript() { "$original_osascript" "$@" } export -f osascript # 现在可以正常调用 /usr/bin/osascript -e 'display dialog "Back to normal!" buttons {"OK"}'
限制:仅对 bash/zsh 有效,若有子 shell 可能失效。
exec 恢复如果是在 jamf 策略执行后 完全恢复系统 osascript(例如之前修改过 /usr/bin/osascript):
bash#!/bin/bash # 如果是方法4(替换了二进制),恢复原版: if [ -f /usr/bin/osascript.bak ]; then sudo mv /usr/bin/osascript.bak /usr/bin/osascript fi # 现在 osascript 完全恢复 /usr/bin/osascript -e 'display dialog "System osascript is back!" buttons {"OK"}'
⚠️ 仅用于极端情况(避免替换系统二进制文件)。
✅ 如果 251 可修改 → 方法1(最干净可控):# OK 有大用
✅ 如果 251 不可修改 → 方法2(PATH 临时伪冒):
✅ 如果运行环境可控(非 sudo) → 方法3(临时 function 覆盖):
⛔ 避免直接修改 /usr/bin/osascript → 方法4(风险高)。
你更倾向于哪一种?我可以提供更具体的实现。
export SKIP_OSASCRIPT=1 是什么 意思
export SKIP_OSASCRIPT=1 是一条 Bash 环境变量设置命令,意思是:
定义一个名为 SKIP_OSASCRIPT 的环境变量,并赋值为 1(相当于 true/启用),之后所有子进程都会继承这个变量。
定义规则SKIP_OSASCRIPT=1 本质上是一个 标志位(类似开关),可以被脚本检测到。
后续影响
通过 export 导出后,所有从这个 shell 启动的子进程(包括 sudo -E jamf policy)都能读取这个变量。
bashexport SKIP_OSASCRIPT=1 # 临时启用 "跳过osascript" 模式 sudo -E jamf policy -id 251 # 251策略会检测这个变量,决定是否弹窗 sudo -E jamf policy -id 231 # 同上 unset SKIP_OSASCRIPT # 关闭跳过模式 /usr/bin/osascript ... # 现在可以正常执行osascript
关键前提:251 和 231 的脚本需要 主动检查这个变量(见下文说明)。
SKIP_OSASCRIPT?在你的 251 策略脚本中,需要添加判断逻辑:
bash#!/bin/bash # ...原有的安装代码... # 只有 SKIP_OSASCRIPT 未设置时才会弹窗 if [[ -z "${SKIP_OSASCRIPT}" ]]; then /usr/bin/osascript -e 'display dialog "安装成功!" buttons {"OK"}' fi
-z "$SKIP_OSASCRIPT" 表示:如果变量不存在或为空,才执行弹窗。
当主脚本设置了 export SKIP_OSASCRIPT=1,子脚本会跳过弹窗。
| 命令 | 类比现实场景 |
|---|---|
SKIP_OSASCRIPT=1 | 告诉所有人:"今天静音,不要播放声音" |
export | 用广播宣布这条规则(让所有房间生效) |
if [[ -z "$SKIP_OSASCRIPT" ]] | 每个房间检查:"如果没听到静音广播,就正常播放声音" |
作用范围
只对 显式检查该变量的脚本 有效(如果子策略不检查,则无效)。
进程结束后,变量自动失效(除非写入 ~/.bashrc 等配置文件)。
变量名自定义
你可以改用其他名字(如 DISABLE_DIALOGS=1),只需保持父子脚本一致。
与 sudo 的关系
sudo 默认会重置环境变量,但 jamf 通常能继承变量(建议测试验证)。
类似的环境变量模式还用于:
bashexport DEBUG=1 # 启用调试模式 export CI=true # 告诉脚本当前是自动化环境 export NO_COLOR=1 # 禁用彩色输出
如果需要更强制性的拦截,建议结合我之前提到的 PATH 重定向或函数覆盖方案。
unset SKIP_OSASCRIPT 是什么意思
unset SKIP_OSASCRIPT 是 删除/取消 之前定义的 SKIP_OSASCRIPT 环境变量,使其不再影响后续进程。相当于 关闭 这个开关。
撤销定义
移除当前 shell 中名为 SKIP_OSASCRIPT 的变量,此后任何读取该变量的操作都会返回空值。
作用域
仅影响 当前终端会话,不会持久化到系统配置。
bashexport SKIP_OSASCRIPT=1 # 设置变量(开启跳过模式) sudo -E jamf policy -id 251 # 子策略检测到变量,跳过弹窗 sudo -E jamf policy -id 231 # 同上 unset SKIP_OSASCRIPT # 删除变量(关闭跳过模式) /usr/bin/osascript -e '...' # 现在会正常执行弹窗
| 命令 | 作用 | 类比 |
|---|---|---|
SKIP_OSASCRIPT=1 | 定义变量(仅当前 shell) | 临时写个便签 |
export SKIP_OSASCRIPT=1 | 导出变量(子进程可见) | 用广播通知所有人 |
unset SKIP_OSASCRIPT | 删除变量 | 撕掉便签 / 关闭广播 |
bash# 设置变量 export SKIP_OSASCRIPT=1 echo $SKIP_OSASCRIPT # 输出: 1 # 删除变量 unset SKIP_OSASCRIPT echo $SKIP_OSASCRIPT # 输出: (空)
Q: 如果忘记 unset 会怎样?
A: 变量会一直存在,直到关闭终端或启动新的 shell 会话。可能导致后续脚本误判。
Q: 和 export SKIP_OSASCRIPT=(赋空值)有什么区别?
A: 赋空值后变量仍存在(值为空),而 unset 是完全删除变量。测试时需注意:
bashexport SKIP_OSASCRIPT= [[ -v SKIP_OSASCRIPT ]] && echo "存在" # 输出: 存在(变量未删除) unset SKIP_OSASCRIPT [[ -v SKIP_OSASCRIPT ]] && echo "存在" # 无输出(变量已删除)
对称操作
像开关一样成对使用:
bashexport SKIP_OSASCRIPT=1 # 开启 # ...执行需要跳过的代码... unset SKIP_OSASCRIPT # 关闭
脚本安全性
在脚本结束时主动清理变量:
bash#!/bin/bash export SKIP_OSASCRIPT=1 trap 'unset SKIP_OSASCRIPT' EXIT # 确保脚本退出时删除变量
调试技巧
检查变量状态:
bashif [[ -v SKIP_OSASCRIPT ]]; then echo "变量存在" else echo "变量不存在" fi
如果需要更复杂的变量管理(如跨终端持久化),可考虑写入临时文件或使用 envchain 等工具。
[[ -v SKIP_OSASCRIPT ]] 与 [[ -z "$SKIP_OSASCRIPT" ]] 区别
[[ -v SKIP_OSASCRIPT ]] 和 [[ -z "$SKIP_OSASCRIPT" ]] 是 两种完全不同的变量检查逻辑,区别如下:
[[ -v SKIP_OSASCRIPT ]]检查变量 SKIP_OSASCRIPT 是否被定义(存在),不关心变量的值。
返回 true:只要变量被定义过(即使值为空 "" 或 0)。
返回 false:变量完全未被定义(从未 export 或赋值过)。
bashunset SKIP_OSASCRIPT # 确保变量未定义 [[ -v SKIP_OSASCRIPT ]] && echo "定义" || echo "未定义" # 输出:未定义 export SKIP_OSASCRIPT="" # 定义为空值 [[ -v SKIP_OSASCRIPT ]] && echo "定义" || echo "未定义" # 输出:定义
[[ -z "$SKIP_OSASCRIPT" ]]检查变量 SKIP_OSASCRIPT 的值是否为空(或未定义)。
返回 true:变量值为空 "" 或 变量未定义。
返回 false:变量有非空值(如 1、true、hello)。
bashunset SKIP_OSASCRIPT # 变量未定义 [[ -z "$SKIP_OSASCRIPT" ]] && echo "空或未定义" || echo "有值" # 输出:空或未定义 export SKIP_OSASCRIPT="" [[ -z "$SKIP_OSASCRIPT" ]] && echo "空或未定义" || echo "有值" # 输出:空或未定义 export SKIP_OSASCRIPT=1 [[ -z "$SKIP_OSASCRIPT" ]] && echo "空或未定义" || echo "有值" # 输出:有值
| 检查方式 | 关注点 | true 条件 | 典型用途 |
|---|---|---|---|
[[ -v VAR ]] | 变量是否定义 | 变量存在(即使值为空) | 检查可选配置是否被设置 |
[[ -z "$VAR" ]] | 变量值是否为空 | 变量未定义 或 值为空 | 检查用户是否提供了有效输入 |
bash# 只有当 SKIP_OSASCRIPT 完全未定义时才弹窗 if [[ ! -v SKIP_OSASCRIPT ]]; then /usr/bin/osascript -e 'display dialog "弹窗"' fi
bash# 如果 SKIP_OSASCRIPT 非空(如值为1),则跳过弹窗 if [[ -z "$SKIP_OSASCRIPT" ]]; then /usr/bin/osascript -e 'display dialog "弹窗"' fi
混淆定义与值
[[ -v SKIP_OSASCRIPT ]] → true(变量存在)
[[ -z "$SKIP_OSASCRIPT" ]] → true(值为空)
-v 检测的是变量是否存在,而 -z 检测的是值是否为空。
例如:export SKIP_OSASCRIPT=""
未定义 vs 空值
bashunset SKIP_OSASCRIPT [[ -v SKIP_OSASCRIPT ]] # false(未定义) [[ -z "$SKIP_OSASCRIPT" ]] # true(未定义视为空)
需要严格区分“未设置”和“空值” → 用 -v
只关心“是否有有效值” → 用 -z
防御性脚本:结合两者:
bashif [[ ! -v SKIP_OSASCRIPT ]] || [[ -z "$SKIP_OSASCRIPT" ]]; then echo "变量未定义或值为空" fi
export SKIP_OSASCRIPT=1 # 设置变量(开启跳过模式)
sudo -E jamf policy -id 251 # 子策略检测到变量,跳过弹窗
sudo -E jamf policy -id 231 # 同上
为什么此时的变量 SKIP_OSASCRIPT 并没有传到 策略 251 里面
你是对的:通过 sudo -E jamf policy -id 251 调用子策略时,SKIP_OSASCRIPT 变量默认不会传递,因为 sudo 会重置环境变量(出于安全考虑)。以下是详细解释和解决方案:
sudo 默认会清除环境变量
macOS 的 sudo 默认启用 env_reset 选项,会丢弃所有用户自定义的环境变量(除非明确配置允许继承)。
jamf policy 以 root 权限运行
即使不用 sudo,jamf policy 自身也会以 root 权限执行,继承的环境变量可能被过滤。
sudo 显式传递变量 # -E (environment ) 保留当前用户环境变量 # OK 有大用 有大大用bashexport SKIP_OSASCRIPT=1 sudo -E jamf policy -id 251 # -E 保留当前用户环境变量
-E 参数:让 sudo 继承调用者的所有环境变量。
限制:需在 /etc/sudoers 中允许该选项(默认通常允许)。
env 直接传递bashexport SKIP_OSASCRIPT=1 sudo env SKIP_OSASCRIPT="$SKIP_OSASCRIPT" jamf policy -id 251
env VAR=value command:临时为命令设置变量,绕过 sudo 的限制。
/etc/sudoers(不推荐)bash# 允许所有变量通过 sudo(安全性降低) sudo visudo
添加以下行:
Defaults env_keep += "SKIP_OSASCRIPT"
风险:降低系统安全性,仅建议在受控环境使用。
如果能够修改 251 和 231 策略的脚本,可以通过参数传递:
bashsudo -E jamf policy -id 251 -skipDialogs # 假设子策略支持参数
然后在子策略脚本中:
bashif [[ "$1" == "-skipDialogs" ]]; then echo "跳过弹窗" fi
在 251 策略的脚本中临时添加调试代码:
bash#!/bin/bash echo "SKIP_OSASCRIPT 的值是: [${SKIP_OSASCRIPT}]" # 检查变量是否传递
运行后查看日志:
bashtail -f /var/log/jamf.log
bash#!/bin/bash export SKIP_OSASCRIPT=1 # 方法1(需 sudoers 允许) sudo -E jamf policy -id 251 # 或方法2(兼容性更好) sudo env SKIP_OSASCRIPT="$SKIP_OSASCRIPT" jamf policy -id 251 # 后续可正常使用 osascript unset SKIP_OSASCRIPT /usr/bin/osascript -e 'display dialog "Now working!"'
export 仅对当前 Shell 及其子进程有效,而 sudo 会创建新环境。
Jamf 策略执行上下文:子策略可能运行在不同的 Shell 或 Root 环境下。
通过以上方法,可确保变量正确传递到子策略。如果仍有问题,可能是策略脚本未正确检测变量(需检查 251 的脚本逻辑)。