Продолжаем бахвалиться, юбилейный выпуск. Сегодня в программе сплошное построение велосипедов, что логично — скоро открытие велосезона.
- Авторесет виртуальной машины при недоступности HTTP или если она не отвечает на пинг
- Группы рассылки на базе групп подразделений компании
- Обнаружение лишних объектов в корне DFS
- Автодобавление разрешения на почтовые ящики для группы
Авторесет виртуальной машины при недоступности HTTP или если она не отвечает на пинг
Есть виртуальная машина на Ubuntu 8.04, перевезённая мной на Hyper-V с железки несколько месяцев назад, где крутится веб-сервис, управляемый CMS отечественного производства RBC Contents 4.0. В каталоге веб-сервера находится более миллиона файлов. Операционная система старая, несовместимая с виртуальной средой, поэтому сетевые адаптеры там пришлось ставить не современные синтетические, а старые эмулируемые (100 Мбит). Мало того, что версия системы управления контентом античных времён — она уже больше 10 лет вообще не существует в природе, как и компания, её выпускавшая. Инструкций тоже нет, в интернете нашлись два документа по три странички, писанных на коленке и совершенно бесполезных. В общем, классический «чёрный ящик», который невозможно тронуть, чтобы он, чего доброго, не развалился, но, вместе с тем, необходимо поддерживать его работоспособность.
Ящик время от времени по неизвестным причинам либо перестаёт отвечать по сети, либо вешается намертво; особенно радует, когда он это делает в три часа ночи. В журналах пусто. Так как всегда решением проблемы является нажатие кнопки сброса, я написал скрипт, который в нерабочее время каждые 10 минут проверяет доступность ящика по сети и порта HTTP. Если что-то не отвечает, скрипт ищет машину в кластере и жмёт ей на ресет, после чего пишет мне письмо, почему он это сделал.
$name = "webserver"
$ip = "192.168.1.10"
if (!(Test-Connection $ip -Count 4 -Quiet -OutVariable ping) -or `
!(Test-NetConnection $ip -Port 80 -OutVariable http).TcpTestSucceeded) {
$vm = Get-Clustergroup |? {$_.grouptype -eq 'VirtualMachine' -and $_.name -eq "$name"} |get-vm
if ($vm -and $vm.State -eq "Running") {
$vm |Restart-VM -force
$body = "<p>Причины:</p>"
$body += "<ul>"
if (!$ping) {$body += "<li>Нет сетевого соединения</li>"}
if (!$http.TcpTestSucceeded) {$body += "<li>Нет ответа по HTTP</li>"}
$body += "</ul>"
Send-MailMessage -SmtpServer mail.domain.ru -From support@domain.ru -Subject "Hyper-V - сервер $name был принудительно перезагружен" `
-To admin@domain.ru -Body $body -BodyAsHtml -Encoding utf8
}
}
Всё же, виртуализация в любом случае имеет преимущества, потому что ящик примерно так же вис и в свою бытность на железке, а до кнопки ресета там просто так дотянуться было нельзя.
Нужно, конечно, сделать поизящнее — привязать срабатывание скрипта к Zabbix, это дело ближайшего будущего.
Группы рассылки на базе групп подразделений компании
Обратились в просьбой сделать группу рассылки на один из отделов компании. Чтобы не возвращаться больше к этой теме в будущем, решили сделать такие группы сразу для всех отделов (кроме руководства, конечно).
Сначала я сделал скриптом динамические группы рассылки, т. е., в рассылку входят члены группы того или иного отдела. Но выяснилось, что так не работает, потому что структура отделов иерархическая, а динамическая группа рассылки не умеет смотреть в группу домена рекурсивно. Ведь тот или иной сотрудник входит в несколько разных вложенных друг в друга отделов, и должен входить во все группы рассылки этих отделов.
Пришлось создать обычные группы рассылки, а членство в группах спрашивать у домена.
function Get-ADGroupMemberEnabledAndMail {
param(
[parameter(mandatory=$true)]
$group
)
Get-ADGroupMember "$group" -Recursive |? objectclass -eq 'user' |% {
Get-ADUser -filter "name -eq '$($_.name)' -and enabled -eq 'True'" -Properties mail
}
}
В результате написал скрипт, где группы рассылки автоматически создаются и удаляются в зависимости от наличия групп подразделений компании, а пользователи добавляются и удаляются из групп рассылки в зависимости от их членства в группах подразделений.
По результатам работы скрипт шлёт отчёт, причём, я распробовал всякие html-символы, чтобы сделать его более читаемым и лаконичным. Примерный вид:
❌ Отдел по развитию (группа рассылки)
✔ Управление по повышению (группа рассылки)
Бумажкин Иван Ильич ❌ Дирекция по улучшению (группа рассылки)
Бюрократов Тихон Тарасович ✔ Группа по превозмоганию (группа рассылки)
Всё отлично работает, но есть одна мысль — ведь можно вместо довольно большого количества тяжёлых запросов к контроллерам домена брать подразделения, к которым принадлежит пользователь, просто из выгрузки штатного расписания, которую уже давно приводит в порядок мой парсер, написанный полтора года назад. Да, всё равно нужно будет получать дополнительную информацию о пользователе из домена, но хотя бы не придётся рекурсивно лопатить десятки групп. С другой стороны, мы имеем дело с реальным положением вещей, которые были приведены в соответствие с выгрузкой ранее. В общем, есть над чем подумать.
Обнаружение лишних объектов в корне DFS
Удивительным образом — видимо, не до конца разобрались в своё время в хитросплетениях раздачи прав в DFS — в корень списка папок на распределённых файловых ресурсах каким-то образом попадают пользовательские ярлыки, файлы и даже иногда каталоги. Это бывает нечасто, но тем не менее, приятнее от этого не становится, а пытаться кардинально решить эту проблему, экспериментируя с перенастройкой прав на работающей системе — это рискованная авантюра, так что опять будет паллиатив.
Удалить этот скапливающийся хлам вручную бывает непросто — нужно искать, на каком конкретно сервере он лежит и удалять уже оттуда, потому что если админ подключен к DFS на одном сервере, а хлам лежит на другом, то через DFS админ удалить хлам не сможет, даже имея все полномочия — система пишет, что файлы не найдены. Ещё нюанс — из команд Powershell, относящихся к DFS, я не смог получить путей к его корням на локальных серверах, т. е., элегантно извлечь данные из одного источника не вышло. Пришлось просто перечислить все локальные пути в явном виде в скрипте, благо, их немного.
А как вообще отделить хлам от легитимных папок? Оказывается, папки в DFS имеют атрибут d----l
(reparse point), то есть, это даже и не папки, а ссылки. Поэтому, вычислить хлам можно так:
dir `
"\\server1\c$\DFS_roots\*\*",
"\\server2\c$\корни_DFS\*\*",
"\\server3\c$\DFS_roots\*\*" |
? mode -ne 'd----l'
Скрипт, конечно, данные сам не удаляет (мало ли что может туда попасть?), а шлёт письмо, где перечислены потенциально лишние объекты, обёрнутые в команды для их удаления.
Автодобавление разрешения на почтовые ящики для группы
Это нужно, чтобы группе определённых сотрудников иметь возможность заходить через почтовый веб-интерфейс на другой ящик, вместо того, чтобы каждый раз подключать его руками и тянуть все эти гигабайты добра на свой комп.
Как обычно, хотелось дать разрешения на уровне организации Exchange, чтобы сделать это один раз и больше к теме не возвращаться. Вместе с тем, не хотелось и давать слишком много привилегий этой группе — разрешений по управлению почтовой системой ей не требовалось. Кроме того, были мысли дать права только на чтение.
В результате поиска я пришёл к выводу, что ни первого, ни второго сделать не удастся — привилегий будет слишком много, если давать их выше ящика, а доступ на чтение для веб-интерфейса невозможен. Допускаю, что решение есть, но какое-то уж слишком замороченное, да и в моём случае это было непринципиально.
Не стал писать нового скрипта, дополнил старые — в один, который контролирует видимость в глобальной адресной книге, добавил сам функционал раздачи прав на ящики, где они ещё не были розданы, а сводный отчёт по Exchange дополнил данными по явно заданным разрешениям на ящики, раз уж всё равно ковырял эту тему.
$accessNotGranted = $allUserMbxes |? {!((Get-MailboxPermission $_).user -match "$fullControlGroup")}
if ($accessNotGranted) {
$accessNotGranted |
Add-MailboxPermission -User "$fullControlGroup" -AccessRights FullAccess -InheritanceType All
}