Хабрахабр

Создание и обновление списков рассылки в Zimbra Collaboration OSE на основе групп и пользователей Active Directory

1. Пара слов от автора

В комментариях к прошлой статье мне задали интересный вопрос об автоматическом формировании списков рассылки на основе групп безопасности AD. Есть задача – есть решение. Правда, оговорюсь сразу, решение несколько костыльное (почему – читать далее), но рабочее. Итак, поехали.

2. Исходные данные

ОС сервера: CentOS 7

По поводу ОС

Работа ведется в основном с командлетами Zimbra, так что отличия настройки будет минимальны.
На самом деле разница между CentOS7 и любой другой системой будет заключаться исключительно в командах серверу на установку пакетов, и, возможно, расположении некоторых файлов.

Домен Zimbra: zimbramail.home.local
Путь монтирования шары на хосте Zimbra: /mnt/ZM/

3. Настройка

1) Монтируем шару Windows к нашему Linux серверу. Это нужно для упрощения и автоматизации передачи данных из Windows PowerShell в Linux Bash. Процедура монтирования была описана в предыдущей статье. Не буду повторяться

Имя группы = имя списка рассылки 2) Создаем в AD отдельное OU, в котором создаем группы, на основе которых будут созданы списки рассылки в Zimbra.

Скрипт отрабатывает рекурсивно, что значит, что он соберет все данные о пользователях, состоящих в группах, которые добавлены в группы в целевом OU. 3) Добавляем в группы, созданные в новом OU, пользователей или группы безопасности, на основе которых будут наполняться списки рассылки в Zimbra. Подробнее о выводе команды Get-ADGroupMember

4) Создаем скрипт сбора данных из Active Directory

5) Создаем скрипт добавления листов рассылки и их наполнения пользователями на основе полученных данных в предыдущем скрипте

6) Наслаждаемся

3.1. По поводу OU

Я создал OU “ZimbraDL” в корне домена и запретил ему наследование групповых политик, чтобы эти группы оставались обособленными. Они не будут участвовать в жизни домена никак, помимо формирования Distribution Lists в Zimbra Collaboration OSE.

4. Скрипт на PowerShell для сбора данных из AD

Скрипт PowerShell

$Path = "C:\ZM\ZimbraDL" #Очистка каталога
if(test-path $Path)
#Создание рабочих директорий
if(!(test-path $Path))
{ New-Item -ItemType Directory -Force -Path $Path
}
if(!(Test-Path $Path\Groups))
{ New-Item -ItemType Directory -Force -Path $Path\Groups
}
if(!(Test-Path $Path\Users))
{ New-Item -ItemType Directory -Force -Path $Path\Users
}
if(!(Test-Path $Path\UsersTemp))
{ New-Item -ItemType Directory -Force -Path $Path\UsersTemp
}
if(!(Test-Path $Path\Groups\listgrp))
{ New-Item -ItemType Directory -Force -Path $Path\Groups\listgrp
}
if(!(Test-Path $Path\Users\listusr))
{ New-Item -ItemType Directory -Force -Path $Path\Users\listusr
} #Пауза
sleep 2 #Создание списка групп
Import-Module ActiveDirectory
Get-AdGroup -filter * -SearchBase "OU=ZimbraDL,DC=home,DC=local" | sort Name | select Name | Out-File "$Path\Groups\GetGroupsAD.txt" #Форматирование списка групп
(Get-Content "$Path\Groups\GetGroupsAD.txt") -notmatch "Name" | where {$_ -ne ""} | where {$_ -ne "--"} | Where-Object {$_ -notmatch '-'} | out-file "$Path\Groups\GetGroupsAD.txt"
$File = @(Get-Content $Path\Groups\GetGroupsAD.txt)
foreach ($File1 in $File) { $string=$File1.TrimStart(' ') $string=$string.TrimEnd(' ') | Out-File $Path\Groups\GroupsList.txt -Append
} #Создание структуры групп
$File = @(Get-Content "$Path\Groups\GetGroupsAD.txt")
foreach ($File1 in $File) { New-Item -ItemType File -Force -Path "$Path\Groups\listgrp\$File1"
} #Создание файлов со списком пользователей для каждой группы
$GroupName = @(Get-Content $Path\Groups\GroupsList.txt)
Foreach ($Group in $GroupName)
{ Get-ADGroupMember $Group -recursive | ft SamAccountName | out-file "$Path\UsersTemp\$Group.txt" -Append (get-content "$Path\UsersTemp\$Group.txt") -notmatch "Name" | where {$_ -ne ""} | where {$_ -ne "--"} | Where-Object {$_ -notmatch '-'} | out-file "$Path\UsersTemp\$Group.txt" $File=@(Get-Content $Path\UsersTemp\$Group.txt) foreach ($File1 in $File) { $string=$File1.TrimEnd(' ') | Out-File "$Path\UsersTemp\$Group.txt" -Append #Создание структуры пользователей $Var = @(Get-Content "$Path\UsersTemp\$Group.txt") foreach ($Var1 in $Var) { New-Item -ItemType Directory -Force -Path $Path\Users\listusr\$Group New-Item -ItemType File -Force -Path "$Path\Users\listusr\$Group\$Var1" } }
}

4.1. Как работает скрипт

1) Скрипт запускается либо руками после изменения данных в AD, либо шедалером, если «не к спеху». Сначала происходит проверка существования и удаление рабочей директории, если она существует. Это нужно, чтобы в процессе работы данные не задвоились.

2) PoSh смотрит в указанное OU, считывает группы пользователей, находящиеся в нем и записывает их в файл GetGroupsAD.txt

3) Отбрасывает из полученного файла все лишнее (PoSh пишет в файл весь свой вывод, так что в изначальном выводе команды первой строкой идет Name, второй строкой разделитель "----", и только после этого перечисляются группы по одной на строку), результатом чего является другой файл GroupsList.txt

4) Далее формируются директории с именами групп в каталоге C:\ZM\ZimbraDL\Groups\listgrp\ по именам групп.

5) В полученных директориях создаются файлы с именами пользователей, входящих в состав соответствующих групп в AD

4.1.1. Почему так сложно?

Это и есть то самое «костыльное, но рабочее решение», о котором я упоминал в самом начале. Проблема в том, что у меня просто не получилось передать в Bash текстовые файлы вывода команд PowerShell. При каждой попытке парсинга я получал странные результаты, начиная от нечитаемых символов, которые не воспринимались командлетом zmprov (что логично), заканчивая тем, что файлы вообще очищались.
Если кто-то знает, как можно передать в Bash текстовые файлы, созданные в PoSh – милости прошу в коменты!

5. Скрипт на Bash для создания списков рассылки

Оговорюсь по поводу копирования файлов-скриптов, созданных под Windows:

Ссылка на статью в конце статьи.
В прошлой статье был описан метод форматирования файлов с помощью команды cat, которая, будучи запущенная с определенным ключом, убирает все лишние нечитаемые символы.

Скрипт Bash

#!/bin/bash
#Определение переменных
#Путь к рабочему каталогу
Path="/mnt/ZM/ZimbraDL"
#имя домена Zimbra
Domain="zimbramail.home.local"
#путь к командлету zmprov
zmprov="/opt/zimbra/bin/zmprov"
#путь к лог-файлу
log="/mnt/ZM/DLlog.txt"
#путь ко временному файлу со списком групп
DLnames="/mnt/ZM/DLnames"
#путь ко временному файлу со списком пользователей
UserNames="/mnt/ZM/Usernames"
#конец блока переменных echo "Запись списка групп..."
ls $Path/Users/listusr > $DLnames
if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]" echo echo -en "ls directory for Groups correct $(date +%T)\n" >> $log
else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "ls directory for Groups INcorrect $(date +%T)\n" >> $log
fi
#Удаление списков рассылки
echo "Удаление обновляемых списков рассылки"
for DLname in $( cat $DLnames); do #Проверка существования списка рассылки echo "Проверка существования списка рассылки $DLname..." Result=$($zmprov gdl $DLname@$Domain) if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]" echo echo -en "DL $DLname exist $(date +%T)\n" >> $log #Удаление списка рассылки echo -en "Start deleting DL for group $DLname $(date +%T)\n" >> $log echo "Удаление списка рассылки $DLname..." $zmprov ddl $DLname@$Domain if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]" echo echo -en "DL for group $DLname is deleted in $(date +%T)\n" >> $log else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "DL for group $DLname is NOT deleted in $(date +%T)\n" >> $log fi else echo -n "$(tput hpa $(tput cols))$(tput cub 6)[FAIL]" echo echo -en "DL $DLname not exist! $(date +%T)\n" >> $log fi done
for DLname in $( cat $DLnames); do #Создание списка рассылки echo -en "Start create DL for group $DLname $(date +%T)\n" >> $log echo "Создание списка рассылки для группы AD $DLname..." $zmprov cdl $DLname@$Domain if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]" echo echo -en "DL for group $DLname is created in $(date +%T)\n" >> $log else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "DL for group $DLname is NOT created in $(date +%T)\n" >> $log fi #Наполнение списка рассылки echo "Наполнение списка рассылки" echo "Запись списка пользователей группы $DLname в массив..." ls $Path/Users/listusr/$DLname > $UserNames if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]" echo echo -en "ls directory for Users correct $(date +%T)\n" >> $log else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "ls directory for Users INcorrect $(date +%T)\n" >> $log fi for UserName in $( cat $UserNames); do echo "Проверка существования ящика для пользователя $UserName..." Result=$($zmprov gmi $UserName@$Domain) if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]" echo echo -en "MilBox for user $UserName exist $(date +%T)\n" >> $log echo "Добавление пользователя $UserName в список рассылки $DLname@$Domain..." $zmprov adlm $DLname@$Domain $UserName@$Domain if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6) [OK]" echo echo -en "User $UserName added in $DLname@$Domain correctly in $(date +%T)\n" >> $log else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "DL for group $DLname is NOT created in $(date +%T)\n" >> $log fi else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "MilBox for user $UserName is NOT exist $(date +%T)\n" >> $log fi done
done
#Очистка временных файлов
echo "Очистка временных файлов"
echo "Очистка файла со списком групп..."
echo -n > $DLnames
if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]" echo echo -en "File $DLnames was successfull cleared in $(date +%T)\n" >> $log
else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "File $DLnames was NOT cleared in $(date +%T)\n" >> $log
fi
echo "Очистка файла со списком пользователей..."
echo -n > $UserNames
if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]" echo echo -en "File $UserNames was successfull cleared in $(date +%T)\n" >> $log
else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "File $UserNames was NOT cleared in $(date +%T)\n" >> $log
fi
#Удаление директорий, содержащих структуру групп и пользователей
echo "Удаление рабочего каталога $Path для очистки свободного пространства..."
rm -rf $Path
if [ $? -eq 0 ]; then echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]" echo echo -en "Directory $Path was seccessfull deleted in $(date +%T)\n" >> $log
else echo -n "$(tput hpa $(tput cols))$(tput cub 6) [FAIL]" echo echo -en "Directory $Path was NOT deleted in $(date +%T)\n" >> $log
fi
#запись в лог-файл времени окончания обновления списков рассылки
echo -en "Job complete in $(date +%T)\n" >> $log
echo -en "____________________________________\n" >> $log

5.1. Как работает скрипт

1) Записать в файл список групп

2) Проверить существование списков рассылки в Zimbra, при существовании – удалить его

При этом проверяется существование почтовых ящиков пользователей в Zimbra, и если ящика не существует, то пользователь не будет добавлен в список рассылки. 3) Поочередно создать списки рассылки на основе списка групп, наполняя каждый из них пользователями (на экран выводится ID списка рассылки, это стандартный вывод командлета zmprov при создании DL). Можно, конечно, создать пользователю новый почтовый ящик и добавить его в список рассылки, но я исходит из того, что Zimbra autoprov работает в режиме Eager, и если пользователь не создался автоматически, то ему и нечего делать в системе

4) Очистить временные файлы

5) Удалить рабочую директорию

6. Заключение

В целом, задача не сложная, проблема лишь в костыльном методе «передачи данных» из PowerShell в Bash. Если избавиться от создания кучи файликов и директорий, используя вместо этого текстовые файлы с наполнением, как это планировалось вначале, то все выглядит довольно красиво. Если данная проблема будет решена — я перепишу скрипты в более правильный вид и изменю статью.

7. P.S.:

Это третья статья из серии «как я «Zimbra» внедрял». Первая, про внедрение, LDAP-авторизацию и автоматическое создание ящиков для пользователей AD, вот тут. Вторая, про настройку резервного копирования и восстановления Zimbra целиком и отдельными ящиками – тут.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»