Конфигурация как код: defaults, plist и профили

Рейтинг: 55.2% · 12 голосов
Подробный курс по macOS для разработчиков и админов: архитектура и Apple Silicon, терминал и zsh, Homebrew и пакеты, launchd и автоматизация, APFS и Time Machine, безопасность (SIP, Gatekeeper, TCC, FileVault), сеть, логи и диагностика, MDM и DDM, контейнеры и виртуализация, восстановление. По официальной документации Apple, актуально на 2026 (macOS 26 Tahoe).
Ответить
Аватара пользователя
Artem_MacAdmin
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Конфигурация как код: defaults, plist и профили

Сообщение Artem_MacAdmin »

Оглавление курса (47)
  1. Что такое macOS: Unix под капотом и место в 2026
  2. Архитектура macOS: XNU, тома и Signed System Volume
  3. Apple Silicon: ARM, Rosetta 2 и отличия от Intel
  4. Установка, обновление и восстановление macOS
  5. Finder, рабочий стол и продуктивность
  6. Системные настройки и их управление из CLI (defaults)
  7. Пользователи и группы: учётные записи и управление
  8. Терминал и zsh: командная строка macOS
  9. CLI на macOS: BSD-команды и отличия от Linux
  10. Настройка zsh: .zshrc, prompt, плагины
  11. Файловая система и права: POSIX, ACL, атрибуты, флаги
  12. Homebrew: пакетный менеджер для macOS
  13. Homebrew глубже: tap, Brewfile, services, обслуживание
  14. Другие пакеты: MacPorts, mas, Nix и App Store
  15. Установка приложений: .app, .dmg, .pkg и Gatekeeper
  16. Управление приложениями и их данные
  17. launchd и launchctl: система запуска macOS
  18. Свои службы и периодические задачи на launchd
  19. Автоматизация: Shortcuts, AppleScript и osascript
  20. Конфигурация как код: defaults, plist и профили (вы здесь)
  21. APFS: снапшоты, клоны, контейнеры и шифрование
  22. Управление дисками: diskutil, образы и форматирование
  23. Time Machine и резервное копирование
  24. Внешние диски, форматы и сетевые тома
  25. Модель безопасности macOS: SIP и целостность системы
  26. Gatekeeper, нотаризация и защита от вредоносов
  27. Приватность и TCC: разрешения на доступ
  28. FileVault: полнодисковое шифрование
  29. Связка ключей и управление секретами
  30. Сетевой экран и защита сети
  31. Сеть в macOS: настройка и инструменты
  32. Диагностика сети на Mac
  33. Общий доступ: SSH, экран, файлы, удалённое управление
  34. Процессы и ресурсы: мониторинг производительности
  35. Логи macOS: unified logging и диагностика
  36. Производительность и энергия: powermetrics, диагностика
  37. Энергия, сон и обслуживание системы
  38. Профили конфигурации и основы MDM
  39. Управление парком Mac: MDM, DDM и zero-touch (2026)
  40. Среда разработчика на Mac: Xcode CLT, git, версии
  41. Контейнеры на Mac: Docker Desktop, OrbStack, Apple container
  42. Виртуализация: Virtualization.framework, UTM, Linux и Windows
  43. Режимы загрузки и восстановление (Apple Silicon)
  44. Сброс, NVRAM, Safe Mode и сброс настроек
  45. Траблшутинг macOS: дерево решений по симптомам
  46. Место на диске и обслуживание системы
  47. Сквозной проект: настройка Mac как у профи + куда расти
Ты настроил новый Mac руками за час: пощёлкал галки в Системных настройках, развернул Dock, отключил естественную прокрутку, поставил скриншоты в PNG, выключил .DS_Store на сетевых дисках. А через полгода apple меняет тебе ноут по гарантии, или ты разворачиваешь второй Mac, или коллеге выдают такой же - и ты снова час щёлкаешь галки, половину забыв. Это не работа админа, это работа обезьяны.

Конфигурация macos бывает двух видов: повторяемая и неповторяемая. Неповторяемая живёт в твоей голове и в мышечной памяти. Повторяемая - это текст, который можно положить в git, прогнать на десяти машинах и получить одинаковый результат. Весь этот урок про то, как превратить настройки в код: где они физически лежат, как их читать и писать командой defaults write, как лезть в сложные структуры через PlistBuddy, и где проходит граница, за которой локальный скрипт уже не годится и нужен профиль конфигурации или MDM.

Где живут настройки: формат plist

Почти все настройки на mac хранятся в файлах property list, расширение .plist. Это структурированный формат: словари (dict, ключ-значение), массивы (array), строки, числа, булевы, даты, бинарные данные. По сути - JSON до того, как JSON стал модным. Лежат plist в трёх основных местах, и это надо держать в голове:
  • ~/Library/Preferences/ - настройки текущего пользователя. Здесь файлы вида com.apple.dock.plist, com.apple.finder.plist.
  • /Library/Preferences/ - настройки уровня всей системы (нужен root для записи).
  • ~/Library/Preferences/ByHost/ - настройки, привязанные к конкретному железу. К имени файла добавлен Hardware UUID машины.
Имя файла - это домен. Домен com.apple.dock - это reverse-DNS идентификатор приложения. Ключевой момент, на котором спотыкаются все новички: ты не правишь plist текстовым редактором напрямую. Во-первых, macOS чаще всего хранит их в бинарном виде, а не в XML. Во-вторых, за настройками следит демон cfprefsd, который кеширует значения в памяти - если ты подменишь файл руками в обход него, твою правку могут затереть кешем. Поэтому пишем через инструменты, которые ходят через систему: defaults и PlistBuddy.

Посмотрим, бинарный файл или XML, и переведём его в читаемый вид утилитой plutil:

Код: Выделить всё

$ file ~/Library/Preferences/com.apple.dock.plist
/Users/admin/Library/Preferences/com.apple.dock.plist: Apple binary property list

$ plutil -convert xml1 -o - ~/Library/Preferences/com.apple.dock.plist | head
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
    <key>autohide</key>
    <true/>
    <key>tilesize</key>
    <integer>48</integer>
</dict>
</plist>
Разбор: file говорит, что это Apple binary property list - значит в редакторе ты увидишь кашу. plutil -convert xml1 переводит в XML, а -o - выводит результат в stdout, не трогая сам файл. Если нужно физически сконвертировать файл на диске - убираешь -o и пишешь

Код: Выделить всё

plutil -convert xml1 file.plist
(или binary1 обратно). И первое, что нужно делать перед любым деплоем plist, - проверять синтаксис:

Код: Выделить всё

$ plutil -lint ~/Library/Preferences/com.apple.finder.plist
/Users/admin/Library/Preferences/com.apple.finder.plist: OK
Если plist битый, plutil -lint покажет строку и проблему. На этом ловится 90 процентов ошибок, когда .mobileconfig или plist собран руками и где-то незакрытый тег.

Изображение

defaults: рабочая лошадка

Команда defaults write - это твой основной инструмент. Синтаксис:

Код: Выделить всё

defaults write <домен> <ключ> -<тип> <значение>
. Принципиально важно указывать тип явно, иначе всё ляжет строкой, и приложение, ждущее булево, твою настройку проигнорирует. Типы:
  • -bool true/false - булево (autohide Dock, например).
  • -int - целое (размер иконок).
  • -float - дробное.
  • -string - строка.
  • -array - массив значений.
  • -dict - словарь (пары ключ-значение).
Базовый цикл чтение-запись-применение:

Код: Выделить всё

$ defaults read com.apple.dock autohide
0

$ defaults write com.apple.dock autohide -bool true

$ defaults read com.apple.dock autohide
1

$ killall Dock
Разбор. Сначала читаем - 0 значит выключено. Пишем true. Читаем снова - 1, значение принято (defaults показывает булево как 0/1). И последний шаг, который забывают: killall Dock. Многие приложения читают настройки только при старте и держат их в памяти. Пока процесс не перечитает - на экране ничего не изменится. Поэтому после правок Dock делаем killall Dock, после правок Finder - killall Finder, после SystemUIServer - killall SystemUIServer. Это не баг, это особенность: ты пишешь в plist, а кеш cfprefsd и сам процесс надо заставить перечитать.

Есть глобальный домен - настройки, общие для всех приложений. Обращение к нему через -g (или NSGlobalDomain, это синонимы):

Код: Выделить всё

$ defaults write -g AppleShowAllExtensions -bool true
$ defaults write NSGlobalDomain KeyRepeat -int 2
Первая строка - показывать все расширения файлов в Finder. Вторая - скорость автоповтора клавиш быстрее, чем даёт ползунок в настройках. Это классический пример, зачем вообще defaults: часть параметров просто не вынесена в GUI.

Полезные флаги для отладки и инвентаризации:
  • defaults domains - список всех доменов пользователя через запятую.
  • defaults read com.apple.finder - целиком дамп домена (увидишь всю структуру).
  • defaults delete com.apple.dock autohide - снести ключ (вернуть к умолчанию).
  • defaults read-type com.apple.dock tilesize - узнать тип хранимого значения.
Отдельная тема - флаг -currentHost. Часть настроек привязана к конкретной машине: разрешение экрана, раскладка для этого железа, кое-что про Screen Saver. Они живут в ByHost. Когда пишешь с -currentHost, defaults кладёт plist в ~/Library/Preferences/ByHost и дописывает к имени файла Hardware UUID этой машины:

Код: Выделить всё

$ defaults -currentHost write com.apple.screensaver idleTime -int 0
$ ls ~/Library/Preferences/ByHost/ | grep screensaver
com.apple.screensaver.A1B2C3D4-....plist
Грабли: если ты скопируешь такой ByHost-файл на другой Mac, у него другой UUID, и файл будет проигнорирован. ByHost-настройки не переносятся между машинами копированием - их надо именно прописывать командой -currentHost на каждой.

PlistBuddy: когда defaults не хватает

defaults отлично пишет плоские значения, но плохо работает с вложенностью - массив словарей, словарь внутри массива внутри словаря. Тут выходит на сцену /usr/libexec/PlistBuddy. Он не в PATH, поэтому всегда полным путём. В скриптах работаем неинтерактивно через -c (одна команда на флаг, можно несколько -c подряд).

Допустим, надо собрать plist с массивом словарей (типичная структура для списка элементов Dock или подобного):

Код: Выделить всё

$ PB=/usr/libexec/PlistBuddy
$ FILE=~/Desktop/demo.plist

$ $PB -c "Add :Apps array" "$FILE"
$ $PB -c "Add :Apps:0 dict" "$FILE"
$ $PB -c "Add :Apps:0:Name string Safari" "$FILE"
$ $PB -c "Add :Apps:0:Pinned bool true" "$FILE"

$ $PB -c "Print" "$FILE"
Dict {
    Apps = Array {
        Dict {
            Name = Safari
            Pinned = true
        }
    }
}
Разбор синтаксиса пути: двоеточие - разделитель уровней. :Apps - ключ верхнего уровня, :Apps:0 - нулевой элемент массива, :Apps:0:Name - ключ Name внутри этого словаря. Команды PlistBuddy: Add (создать), Set (изменить существующее), Delete (удалить), Print (показать, можно Print :Apps:0:Name для одного значения), Merge, Import. Важное отличие от defaults: если файла нет, PlistBuddy с Add создаст его. Если ключ уже есть - Add ругнётся, нужен Set. Краевой случай: PlistBuddy не дёргает cfprefsd и пишет прямо в файл. Для доменов приложений это риск конфликта с кешем, поэтому для com.apple.* предпочитай defaults, а PlistBuddy держи для своих файлов и для .mobileconfig, которые ты собираешь руками.

Скрипт автонастройки нового Mac

Собираем всё в один идемпотентный скрипт. Идемпотентный значит: запусти хоть десять раз - результат один и тот же, повторный прогон не ломает. defaults write для этого идеален, он перезаписывает значение, а не накапливает.

Код: Выделить всё

#!/bin/zsh
# setup-mac.sh - базовая настройка нового Mac
set -euo pipefail

echo "Finder: показывать расширения и спрятанные файлы"
defaults write NSGlobalDomain AppleShowAllExtensions -bool true
defaults write com.apple.finder AppleShowAllFiles -bool true
defaults write com.apple.finder ShowPathbar -bool true
defaults write com.apple.finder FXDefaultSearchScope -string "SCcf"

echo "Dock: автоскрытие, мелкие иконки, без недавних"
defaults write com.apple.dock autohide -bool true
defaults write com.apple.dock tilesize -int 42
defaults write com.apple.dock show-recents -bool false

echo "Скриншоты: PNG в ~/Screenshots без тени"
mkdir -p "$HOME/Screenshots"
defaults write com.apple.screencapture location -string "$HOME/Screenshots"
defaults write com.apple.screencapture type -string "png"
defaults write com.apple.screencapture disable-shadow -bool true

echo "Не плодить .DS_Store на сетевых и USB томах"
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true
defaults write com.apple.desktopservices DSDontWriteUSBStores -bool true

echo "Применяем"
killall Dock Finder SystemUIServer 2>/dev/null || true
echo "Готово. Часть настроек подхватится после релогина."
Разбор ключевых решений. set -euo pipefail - скрипт падает на первой же ошибке, а не молча идёт дальше с кривым состоянием. killall ... 2>/dev/null || true - если процесса нет, killall вернёт ошибку, а || true не даёт скрипту упасть из-за этого. FXDefaultSearchScope со значением SCcf - искать по текущей папке, а не по всему Mac (мелочь, но экономит нервы каждый день). Положи этот файл в git-репозиторий dotfiles, и новый Mac настраивается за десять секунд: clone, запуск, релогин. Это и есть конфигурация как код в чистом виде.

Профили конфигурации: декларативная альтернатива

Скрипт defaults - это императив: пользователь может тут же зайти в настройки и всё отменить. Для своей машины нормально. Для парка корпоративных Mac, где политику безопасности нельзя оставлять на совесть юзера, нужен другой механизм - профиль конфигурации, файл .mobileconfig.

Профиль - это XML property list (тот же plist, только специальной структуры): верхний словарь с метаданными плюс массив payload, где каждый payload настраивает свою подсистему - пароли, Wi-Fi, ограничения, доменные настройки приложений. Принципиальное отличие от defaults: профиль накладывает настройки сверху и блокирует их. Это managed-значение. Пользователь физически не может изменить параметр, заданный профилем, - в Системных настройках пункт станет серым с пометкой, что им управляет профиль. defaults read такое значение даже не покажет в обычном домене, потому что managed preferences живут отдельно. Снять профиль может только тот, кто его поставил (или MDM).

Скелет .mobileconfig, который форсит autohide Dock как managed:

Код: Выделить всё

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
  <key>PayloadContent</key>
  <array>
    <dict>
      <key>PayloadType</key>
      <string>com.apple.dock</string>
      <key>PayloadIdentifier</key>
      <string>ru.cyberlake.dock</string>
      <key>PayloadUUID</key>
      <string>11111111-1111-1111-1111-111111111111</string>
      <key>autohide</key>
      <true/>
    </dict>
  </array>
  <key>PayloadType</key>
  <string>Configuration</string>
  <key>PayloadIdentifier</key>
  <string>ru.cyberlake.profile</string>
  <key>PayloadUUID</key>
  <string>22222222-2222-2222-2222-222222222222</string>
  <key>PayloadDisplayName</key>
  <string>Cyberlake Dock policy</string>
</dict>
</plist>
Перед раздачей профиль обязательно прогоняем через plutil -lint profile.mobileconfig - один незакрытый тег, и установка молча провалится. PayloadUUID должны быть уникальными (сгенерируй командой ).

MDM против локального скрипта: где граница

Дважды кликнуть по .mobileconfig можно вручную - откроется установка профиля в Системных настройках. Но руками это не масштабируется, и в 2026 это уже не основной путь. Профили раздаёт MDM (Mobile Device Management) - сервер управления. И тут важный сдвиг эпохи: 2026 - год, когда Apple делает Declarative Device Management (DDM) стандартом. Разница в подходе:
Старый MDM - это команды: сервер шлёт устройству "сделай вот это". DDM - это декларации: сервер описывает желаемое состояние, а устройство само непрерывно сверяет свою конфигурацию с эталоном и само себя чинит при дрейфе, отчитываясь асинхронно. Никакого постоянного опроса сервера - меньше нагрузки на сеть в большом парке.
Как выбирать инструмент под задачу:
  • Свой Mac, dotfiles, разработчик - скрипт defaults/PlistBuddy в git. Гибко, прозрачно, версионируется.
  • Нужно запретить пользователю менять настройку - только профиль конфигурации. Скрипт тут бессилен, юзер всё откатит.
  • Парк машин, корпоратив, удалённый контроль и compliance - MDM, и в 2026 на базе DDM, где устройства держат состояние сами.
Грабли границы: не пытайся профилем заменить вообще всё. Многие чисто косметические настройки (размер иконок Dock, путь скриншотов) логичнее раздать скриптом - профиль их жёстко залочит, и пользователь не сможет подвинуть под себя даже там, где это безвредно. Здравый паттерн в больших организациях - гибрид: профили для безопасности и политик (то, что нельзя трогать), скрипт defaults для дефолтов и удобства (то, что пользователь вправе потом поменять).

Типичные грабли
  • Забыл killall - написал в plist, на экране ничего. Процесс не перечитал настройки. После Dock - killall Dock, после Finder - killall Finder.
  • Не указал тип - defaults write ... true без -bool запишет строку "true", а не булево. Приложение проигнорирует. Всегда явный -bool/-int/-string.
  • Правка plist текстовым редактором - cfprefsd закеширует и затрёт. Пиши через defaults, не открывай файл в Vim.
  • ByHost-файл скопировали на другую машину - не сработает, у неё другой Hardware UUID. -currentHost прописывай на каждой машине отдельно.
  • Битый .mobileconfig - незакрытый тег, установка молча падает. plutil -lint перед раздачей, всегда.
  • Ждёшь, что профиль изменит обычный домен - managed-значения живут отдельно, defaults read их в обычном домене не покажет. Профиль накладывает сверху, не правит пользовательский plist.
Мини-лаба

Повтори руками, на своей машине, безопасно:
  • Прочитай текущее autohide Dock:

    Код: Выделить всё

    defaults read com.apple.dock autohide
    . Запомни значение.
  • Включи автоскрытие:

    Код: Выделить всё

    defaults write com.apple.dock autohide -bool true && killall Dock
    . Посмотри на Dock.
  • Найди файл домена и проверь формат:

    Код: Выделить всё

    file ~/Library/Preferences/com.apple.dock.plist
    , затем

    Код: Выделить всё

    plutil -convert xml1 -o - ~/Library/Preferences/com.apple.dock.plist | head -20
    .
  • Создай свой plist через PlistBuddy с массивом словарей (как в примере выше) и выведи через Print. Проверь

    Код: Выделить всё

    plutil -lint ~/Desktop/demo.plist
    .
  • Верни Dock как было:

    Код: Выделить всё

    defaults write com.apple.dock autohide -bool <твоё_исходное> && killall Dock
    , либо

    Код: Выделить всё

    defaults delete com.apple.dock autohide
    .
  • Собери из трёх-четырёх своих defaults write мини-скрипт setup.sh с set -euo pipefail и killall в конце. Запусти дважды - убедись, что повторный прогон ничего не ломает (идемпотентность).
Контрольные вопросы
  • Чем отличается запись через defaults write от прямого редактирования plist в текстовом редакторе, и почему второе опасно?
  • Зачем после defaults write обычно нужен killall, и для каких процессов?
  • В каком случае defaults бессилен и нужен именно профиль конфигурации .mobileconfig?
  • Что делает флаг -currentHost, где оказывается файл, и почему такой plist нельзя просто скопировать на другую машину?
Итог

Настройки macos - это структурированные plist в трёх местах (~/Library, /Library, ByHost), читаемые plutil и правимые через defaults и PlistBuddy, но не текстовым редактором. defaults write с явным типом плюс killall - твой повседневный инструмент и основа идемпотентного скрипта автонастройки в git. PlistBuddy подключаешь, когда нужна вложенность. А когда настройку надо именно запретить пользователю или раскатать на парк - это уже профиль .mobileconfig и MDM, в 2026 - на декларативной модели DDM, где устройства держат состояние сами. Скрипт - для своего и для удобства, профиль - для безопасности и политик. Вот и вся конфигурация как код на Mac.
👍2 ❤️4 🔥1 😄 🤔1
Аватара пользователя
timaz
Сообщения: 1
Зарегистрирован: 12 май 2026, 22:22

Re: Конфигурация как код: defaults, plist и профили

Сообщение timaz »

Блин, вот про killall - я неделю не мог понять почему defaults write проходит а Dock как был так и стоит. Перезагружал даже. Спасибо, теперь ясно.
👍2 ❤️1 🔥 😄 🤔1
Аватара пользователя
grumpyburnout
Сообщения: 1
Зарегистрирован: 23 май 2026, 07:47

Re: Конфигурация как код: defaults, plist и профили

Сообщение grumpyburnout »

А если профиль поставлен через MDM, то юзер реально никак не снимет даже с админкой? И как тогда дебажить когда настройка серая а ты не помнишь какой профиль её задал - есть команда посмотреть список профилей?
👍2 ❤️2 🔥 😄 🤔
Ответить
← Предыдущая глава
Автоматизация: Shortcuts, AppleScript и osascript
Следующая глава →
APFS: снапшоты, клоны, контейнеры и шифрование

Все главы курса «macOS для профи: администрирование, терминал и Homebrew»

Поделиться темой: ✈ Telegram VK
Похожие запросы: Установка и первый конфиг nginxnginx в Dockerdefaults write и настройка macOS из терминалаMDM и управление парком Mac

Вернуться в «macOS для профи: администрирование, терминал и Homebrew»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя