macOS企业部署需脚本化pkg/dmg/app分发与配置固化:用xattr清除隔离属性后installer静默安装;hdiutil挂载+cp -X拷贝保留签名;defaults写用户偏好、profiles管系统策略;每步校验+结构化日志+版本条件分支。

MacOS 企业级软件部署不能靠手动点安装包,必须用脚本驱动 pkg / dmg / app 分发 + 配置固化,否则无法批量、不可回滚、不满足审计要求。
用 installer 命令静默安装 pkg 包,但必须处理权限和信任链
macOS 12+ 默认阻止未签名或公证失败的 pkg,installer 报错 “package is untrusted” 是最常见卡点。不是加 -allowUntrusted 就能过——该参数仅绕过 Gatekeeper 检查,不解决系统级信任缺失。
- 真正要做的:提前用
xattr -d com.apple.quarantine <pkg_path>清除隔离属性,再执行installer -pkg <pkg_path> -target / -silent - 若 pkg 内含 LaunchDaemon 或需要 root 权限的配置,必须用
sudo installer,且目标卷需已启用全盘访问(TCC)授权,否则静默失败无提示 - 别依赖
-dumplog查错:它只输出安装器日志,不包含 postinstall 脚本崩溃信息;应配合console -u | grep installer实时捕获
从 dmg 挂载到应用拷贝,得用 hdiutil + cp -X 保留资源分支和扩展属性
直接拖拽复制.app在脚本里行不通——会丢掉 com.apple.FinderInfo 和代码签名资源分支,导致启动时报 “damaged and can’t be opened”。
- 挂载:用
hdiutil attach -nobrowse -quiet <dmg_path>获取设备路径(如/dev/disk2),再用ls /Volumes/找卷名,避免硬编码 - 拷贝:必须用
cp -X -R <source.app> /Applications/,-X关键,否则 ACL 和扩展属性丢失 - 卸载:别用
hdiutil detach /Volumes/xxx,而要用hdiutil detach <device_path>(即/dev/disk2),否则可能残留挂载点致下次挂载失败
配置固化必须分层:defaults 写 plist、profiles 管系统策略、脚本补业务逻辑
企业办公软件的“标准”不止是装上,还包括禁用自动更新、预设服务器地址、隐藏无关菜单项——这些不能混在同一层处理。
- 用户级偏好:用
defaults write <domain> <key> <value>,注意domain是 Bundle ID(如com.microsoft.Outlook),不是路径 - 系统级策略(如禁止修改 Dock、强制启用 FileVault):必须用
profiles install -path <mobileconfig>,且 mobileconfig 需由 MDM 签名,本地profiles命令不校验签名但系统策略引擎会拒收未签名文件 - 启动后首次运行配置(如 Outlook 配置 Exchange 账户):不能塞进 login item,要用
launchctl bootstrap gui/<uid> <plist_path>注册一次性 job,且 plist 中设RunAtLoad = false+StartCalendarInterval延迟 30 秒,避开 Finder 启动风暴
脚本退出码和日志必须映射到真实失败环节
很多自动化脚本用 set -e 就以为能捕获错误,实际 installer 即使失败也常返回 0,defaults write 对不存在 domain 也静默成功——结果是“看似跑完,实则漏配”。
- 每个关键步骤后加校验:比如装完 Zoom,立刻跑
codesign --verify --deep --strict /Applications/Zoom.us.app 2>/dev/null,失败才报错 - 日志写入
/var/log/company-deploy.log(而非 stdout),每行带$(date +%s)时间戳,方便和system.log对齐排查时序问题 - 最终退出码不要 return 0/1 简单区分,用不同数字代表不同失败类型:
exit 10表示 pkg 安装失败,exit 20表示配置写入失败,便于上游编排工具识别
真正的难点不在语法,而在于 macOS 每次大版本更新都会调整 TCC 权限模型、签名验证强度或 LaunchServices 行为——去年有效的 spctl --master-disable 在 Ventura 已被彻底移除,必须用配置描述文件替代。脚本里所有绕过机制,都要对应到具体系统版本号做条件分支,不能写死。

















