Exchange_iCloud_Calendar_Sync
Описание
AppleScript для односторонней синхронизации событий из Exchange-календаря в iCloud-календарь на macOS.
Языки
- AppleScript100%
Exchange → iCloud Calendar Sync
AppleScript для односторонней синхронизации событий из Exchange-календаря в iCloud-календарь на macOS.
Зачем это нужно
На Mac календарь Exchange (Outlook) и iCloud — это два разных мира. iPhone/Apple Watch показывают оба, но:
- Exchange-встречи могут не попадать в виджеты
- На Apple Watch уведомления от Exchange приходят криво или не приходят
- Если хочешь видеть рабочий календарь в iCloud-виджете — нужен «зеркальный» календарь
Этот скрипт берёт все события из Exchange-календаря (включая повторяющиеся!) и копирует их в iCloud-календарь. Запускается по расписанию — ты просто видишь актуальное расписание везде.
Что внутри
| Файл | Назначение |
|---|---|
| Основной скрипт синхронизации |
| Удаляет все синхронизированные события из целевого календаря |
| Диагностика — показывает что Calendar.app видит в твоих календарях |
Быстрый старт
1. Создай целевой календарь
Открой Calendar.app → Файл → Новый календарь → назови его (или как хочешь, но тогда поменяй настройку в скрипте).
Календарь должен быть именно в iCloud, не локальный.
2. Настрой скрипт
Открой в Script Editor (Редактор скриптов). В самом верху найди блок настроек:
Как узнать точное название Exchange-календаря:
- Открой Calendar.app
- В левой панели посмотри как называется твой рабочий календарь (обычно под заголовком «Exchange»)
- Скопируй название точно как написано — с учётом пробелов и регистра
3. Запусти
В Script Editor нажми ▶ Запустить (Cmd+R). Первый раз macOS спросит разрешение на доступ к Calendar.app — разреши.
4. Настрой автозапуск (опционально)
Чтобы синхронизация работала автоматически, используй launchd (встроенный планировщик macOS).
Создай файл :
Замени на своё имя пользователя. Затем:
Как это работает
Общая схема
Exchange-календарь (EX Work) iCloud-календарь (Work Mirror)
┌──────────────────────────┐ ┌──────────────────────────┐
│ Стендап 10:00 (повтор) │──────▶ │ Стендап 10:00 пн │
│ Митинг 14:00 │──────▶ │ Стендап 10:00 вт │
│ 1-on-1 16:00 (повтор) │──────▶ │ Стендап 10:00 ср │
│ │──────▶ │ Митинг 14:00 │
│ │──────▶ │ 1-on-1 16:00 пн │
│ │──────▶ │ 1-on-1 16:00 чт │
└──────────────────────────┘ └──────────────────────────┘
Пошагово (что делает скрипт при каждом запуске)
Шаг 1 — Проверка. Скрипт проверяет что оба календаря (источник и цель) существуют. Если нет — ошибка с понятным сообщением.
Шаг 2 — Чтение всех событий. Скрипт читает все события из Exchange-календаря. Именно все, не только за период — потому что Calendar.app не умеет разворачивать повторяющиеся события по диапазону дат (подробнее ниже).
Шаг 3 — Обработка каждого события:
- Обычное событие (без повторов): если дата попадает в диапазон «вчера → +30 дней» — берём его.
- Повторяющееся событие: скрипт читает правило повтора (RRULE) и сам вычисляет все даты вхождений в нашем диапазоне. Поддерживаются: ежедневные, еженедельные (в т.ч. по конкретным дням — пн, ср, пт), ежемесячные, ежегодные повторы.
- Дубликаты одного и того же события (Calendar.app иногда возвращает их) отбрасываются по UID.
- Каждому вхождению присваивается уникальный ID:
. Например, для стендапа в понедельник и стендапа во вторник — это два разных ID, хотя UID события один.UID события + метка времени
Шаг 4 — Сравнение с целевым календарём. Скрипт читает целевой iCloud-календарь и строит индекс всех событий, которые были созданы предыдущими синхронизациями (они содержат метку в описании).
Шаг 5 — Синхронизация. Для каждого события из источника:
| Ситуация | Действие |
|---|---|
| В целевом нет такого ID | Создаём новое событие |
| ID есть, но данные изменились (название, время, место) | Обновляем существующее |
| ID есть, данные совпадают | Ничего не делаем |
Шаг 6 — Очистка. Если в целевом календаре есть событие с меткой , но в источнике такого события больше нет (удалили или перенесли) — скрипт удаляет его из iCloud-календаря. Так календарь не зарастает мусором.
Шаг 7 — Отчёт. В лог (Console.app → Все сообщения) выводится подробный отчёт:
========================================
EXCHANGE SYNC - REPORT
========================================
Range: 08.02.2026 00:00 -> 11.03.2026 00:00
Source: 47 events
Time: 3 min 12 sec
========================================
RESULTS:
Created: 12
Updated: 3
Deleted: 1
-- Created --
NEW: Дейли EDU | 10.02.2026 10:00 [repeat]
NEW: Дейли EDU | 11.02.2026 10:00 [repeat]
NEW: FW: DSW Трек фин-юр | 10.02.2026 12:30 [repeat]
...
-- Deleted --
DEL: Старый митинг
========================================
Sync completed OK
========================================
Плюс macOS-уведомление с краткой статистикой: .
Повторяющиеся события — как это работает
Проблема
Calendar.app через AppleScript не разворачивает повторяющиеся события. Если у тебя стендап каждый день с 1 января, Calendar.app вернёт одно событие с и строкой .
Он не создаёт отдельные экземпляры для каждого понедельника, вторника и т.д. — для AppleScript это одно событие.
Решение
Скрипт сам парсит строку RRULE (стандарт iCalendar RFC 5545) и вычисляет все даты вхождений в заданном диапазоне.
Поддерживаемые типы повторов
| RRULE | Пример | Поддержка |
|---|---|---|
| Каждый день / каждые N дней | ✅ |
| Каждую неделю | ✅ |
| По конкретным дням недели | ✅ |
| Каждый месяц | ✅ |
| Каждый год | ✅ |
| Каждые N периодов | ✅ |
| Не более N повторений | ✅ |
| До конкретной даты | ✅ |
Не поддерживается
(второй вторник месяца) — порядковые префиксы игнорируются, берётся только деньBYDAY=2TU,BYMONTHDAY— экзотические правилаBYSETPOS— исключения дат (если одно вхождение удалено из серии)EXDATE- Разные часовые пояса в UNTIL
Для 95% рабочих календарей этого достаточно.
Скрипт очистки
— удаляет из целевого календаря все события, созданные синхронизацией.
Когда использовать:
- Что-то пошло не так и нужно начать с чистого листа
- Перед первым запуском новой версии скрипта
- Если нужно полностью отключить синхронизацию
Как использовать:
- Открой в Script Editor
- Проверь что
совпадает с настройкой в основном скриптеtargetCalName - Нажми ▶ Запустить
- Подтверди удаление в диалоговом окне
Скрипт удаляет только события с меткой в описании. Если ты вручную создавал события в целевом календаре — они останутся.
Диагностический скрипт
— показывает сырые данные из Calendar.app. Полезен для отладки.
Что покажет:
- Сколько событий возвращает фильтр по дате vs. всего в календаре
- Список повторяющихся событий с их RRULE-строками
- Попадают ли повторяющиеся события в фильтр по дате (спойлер: нет)
- Поиск по конкретному названию (по умолчанию DSW)
Ограничения
- Односторонняя синхронизация. Exchange → iCloud. Изменения в iCloud-календаре НЕ попадают обратно в Exchange.
- Не редактируй события в целевом календаре вручную — при следующей синхронизации скрипт перезапишет их.
- Производительность. Скрипт читает все 690+ событий из Exchange. На большом календаре может работать 1-3 минуты.
- macOS only. AppleScript работает только на Mac.
- Нет синхронизации участников и напоминаний. Копируются: название, время, место, описание, статус «весь день». Не копируются: участники, напоминания, вложения.
Устранение неполадок
Скрипт не компилируется
Убедись что открываешь файл именно в Script Editor (Редактор скриптов), а не в текстовом редакторе. Кодировка файла должна быть UTF-8.
«Календарь не найден»
Название календаря в настройках должно точно совпадать с тем, что показывает Calendar.app. Откройте Calendar.app и сверьте — с учётом пробелов, регистра, спецсимволов.
Повторяющиеся события не синхронизируются
Запусти и проверь:
- Есть ли у события поле
(неrecurrence)missing value - Какой формат RRULE — поддерживается ли он (см. таблицу выше)
Дубликаты в целевом календаре
- Запусти
— удалит все синхронизированные событияexchange_sync_cleanup.applescript - Запусти
зановоexchange_sync_v4.applescript
Где смотреть логи
Console.app (Консоль) → в поиске набери . Там будет подробный отчёт о каждой синхронизации.
Или в Script Editor → меню Окно → Журнал (Window → Log) — если запускаешь вручную.
Системные требования
- macOS 10.14 Mojave и выше
- Calendar.app с подключённым Exchange-аккаунтом
- iCloud-аккаунт с включённым календарём
- Разрешение на автоматизацию (Системные настройки → Конфиденциальность → Автоматизация)
Лицензия
MIT — делай что хочешь.