🏠: it

Что сделал - 8

Ежемесячная автоматическая отсылка статистики правовой системы Консультант+

$t = get-date
$zip = "C:\Scripts\Consultant\Cons-Stat-$($t.ToShortDateString()).zip"
$consGuy = "email@mail.eu"

# compress the statistics folder and test archive (use Compress-Archive if possible)
& 'C:\Program Files\7-Zip\7z.exe' a "$zip" "K:\ADM\STS"
$test = & 'C:\Program Files\7-Zip\7z.exe' t "$zip"

# if archive succesfully created
if ($test -match "Everything is Ok") {
# send an email
$body = "<p>Добрый день!<br>
Высылаем статистику СПС Консультант по состоянию на $($t.ToLongDateString())</p>
<p><i>С уважением,<br>
Отдел ИТ<br>
АО "ЗАО"</i></p>
<p style=`"color:red;`">Это письмо создано автоматически, не отвечайте на него.</p>
"

Send-MailMessage -SmtpServer mail.domain.ru -From "robot@domain.ru" -To "$consGuy" -Cc "bulynkin@domain.ru" -Subject "АО ЗАО - Статистика СПС Консультант" -Body "$body" -Attachments "$zip" -Encoding UTF8 -bodyashtml

# wipe statistics folder
del K:\ADM\STS\* -Force -Confirm:$false
}

# if archive creation failed, send an alert
else {
Send-MailMessage -SmtpServer mail.domain.ru -From "robot@domain.ru" -To "bulynkin@domain.ru" -Subject "АО ЗАО - Статистика СПС Консультант" -Body "Ошибка отсылки статистики!" -Priority High -Encoding UTF8 -bodyashtml
}

Система видеоконференцсвязи Jitsi

Один центральный сервер + 5 серверов Jibri — это компонент для записи, пять штук нужно для пяти одновременных потоков. Дополнительно сделал автонастройку интерфейса через скрипт в кроне, чтобы после каждого обновления не прописывать заново название конторы, логотип и т. п. По уму, конечно, надо не плодить виртуальные машины, чтобы они пыхтели 24/7, а сделать какой-то оркестратор контейнеров, где работает только основной сервер и один Jibri, а при задействовании одного записывающего потока поднимался дополнительный контейнер с Jibri и так далее, т. е., система должна распухать и сдуваться динамически. Но это дело будущего, т. к. я пока не осилил контейнеризацию, а нахожусь в процессе освоения.

Все сервера Jibri пишут в свой локальный каталог. Чтобы не лазать по всем серверам в поисках записи — ведь неизвестно, какой именно будет писать ту или иную конференцию — я сделал автоматическое копирование с них на общую папку на Windows-сервере, и последующее автоудаление: с локальных серверов через 3 дня, а на Windows-сервере — через 2 недели.

Виртуализация старого веб-сервера на Ubuntu 8.04

Заодно разобрался, как обновлять старые системы Ubuntu. Оказалось, что для всех старых систем есть репозитории, а с версии на версию в общем случае можно переползать с помощью образа ISO со следующей версией.

Группы в AD на основании статуса сотрудника

«В декрете», «в отпуске», «в командировке» и т. д., и сделал механизм, по которому пользователи автоматически добавляются-удаляются из этих групп, и в почту присылается отчёт. Пока это ни для чего не нужно, но пригодиться может. Дополнительно, статус и отдел прописываются в описание пользователя для наглядности.

Отчёт по пользователям, подключающимся по VPN

Оказалось, что в Powershell (точнее, в .NET) есть механизм генерации графиков, и помимо самого списка пользователей, в письмо вставляется почасовой график количества подключений, очень красиво.

Критерий выгрузки почтовых ящиков из Exchange

Раньше было так — если сотрудник не заходил в систему больше 180 дней, то ящик выгружался. Теперь поступило указание выгружать ящики только через месяц после увольнения сотрудников. Когда сотрудник пропадает из штатного расписания, генерируется команда на заполнение атрибута comment, от чего можно потом оттолкнуться:

Set-ADUser "CN=Петрова Светлана Викторовна,OU=1_Users,DC=domain,DC=ru" -replace `
@{'comment'="Сотрудник уволен 16.10.2020"}

И, наконец, самое вкусное —

Прокси-сервер на базе Squid с прозрачной аутентификацией через Kerberos, с управлением уровнем доступа через группы в AD + статистика

Иными словами, доменные пользователи не должны ничего вводить для выхода в интернет — они проходят проверку автоматически. Для Linux-машин и находящимся вне домена предлагается набрать логин и пароль (basic-аутентификация). С этим делом пришлось повозиться, потому что в интернете все инструкции либо старые, либо являются сборниками копипасты без рассмотрения смысла или альтернатив того или иного действия, а порой и то, и другое.

Мой подход состоит в том, чтобы иметь самую минимальную конфигурацию, которая выполняет поставленные задачи; максимально оставлять настройки по умолчанию, чтобы все настройки были по возможности осмысленными, было известно, что они конкретно делают, и документировать их. Иначе получается очередной чёрный ящик, который непонятно как работает, и через пару лет к нему становится страшно прикоснуться, потому что если он повалится, то мало того, что никто не знает, как он устроен и как его чинить и восстанавливать — никто иногда даже не знает, что он конкретно делает. В общем, классика отечественных ИТ, да и не только ИТ. Оказалось, что Kerberos не так страшен и Linux-системы довольно легко вяжутся с доменом Windows, что многие пакеты, описанные в интернет-статьях, не требуется ставить (например, Samba), либо они устарели. Но лично мне это стало понятно после двух недель напряжённой работы по разбору этих авгиевых конюшен текста и бесчисленных проб и ошибок. Не сказать, чтобы я создал идеальную конфигурацию — кое-что перекочевало из старой «до востребования», но это во всяком случае более безопасная и структурированная настройка по сравнению с тем, что было раньше.

Статистику тоже хотелось сделать красиво, генерировать списки пользователей и отделы автоматически. На старом прокси-сервере стоял LightSquid, его я и взял для этой цели. Номера отделов для отчётов по группам я сначала просто задумал генерировать скриптом, а потом подумал, что лучше брать эти номера из того же штатного расписания, и попросил коллегу-программиста 1С добавить в ежедневную выгрузку и номер подразделения. Прописав всем пользователям на этой основе атрибут departmentNumber в AD, я написал следующий скрипт на bash:

#!/bin/bash

realnamecfgUTF8="/var/www/html/stat/realname.cfg.utf8";
realnamecfg="/var/www/html/stat/realname.cfg";
groupcfgUTF8="/var/www/html/stat/group.cfg.utf8";
groupcfg="/var/www/html/stat/group.cfg";
rm -f $realnamecfgUTF8 $realnamecfg $groupcfgUTF8 $groupcfg && touch $realnamecfgUTF8 $realnamecfg $groupcfgUTF8 $groupcfg

kinit HTTP/proxy.domain.ru -k

for i in `ldapsearch -H ldap://vmws-dc1.domain.ru -b dc=domain,dc=ru -LLLQ -o ldif-wrap=no "(&(objectclass=person)(primaryGroupID=513)(!(samaccountname=*mailbox*))(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))" sAMAccountName |grep 'sAMAccountName: ' |sed 's/sAMAccountName: //'`;
do
nameRaw=`ldapsearch -H ldap://vmws-dc1.domain.ru -b dc=domain,dc=ru -LLLQ -o ldif-wrap=no "(sAMAccountName=$i)" name |grep 'name:'`;
depRaw=`ldapsearch -H ldap://vmws-dc1.domain.ru -b dc=domain,dc=ru -LLLQ -o ldif-wrap=no "(sAMAccountName=$i)" department |grep 'department:'`;
depNum=`ldapsearch -H ldap://vmws-dc1.domain.ru -b dc=domain,dc=ru -LLLQ -o ldif-wrap=no "(sAMAccountName=$i)" departmentNumber |grep 'departmentNumber:' |sed "s/departmentNumber: //"`;

if [[ $nameRaw =~ '::' ]]
then
name=`echo $nameRaw |sed "s/name:: //" |base64 -d`
else
name=`echo $nameRaw |sed "s/name: //"`
fi

if [[ $depRaw =~ '::' ]]
then
dep=`echo $depRaw |sed "s/department:: //" |base64 -d`
else
dep=`echo $depRaw |sed "s/department: //"`
fi

loginLow=`echo $i |tr "[:upper:]" "[:lower:]"`
if [[ $depNum =~ [0-9] ]]
then
login=`echo "$loginLow@domain.ru"`
echo -e "$login\t$depNum\t$dep" >> $groupcfgUTF8
else
login=`echo "$loginLow"`
fi

#echo -e "$loginRaw\t$nameRaw\t$depRaw"
#echo -e "$login\t$name\t$dep"
#echo -e "$login\t$name\t$depNum\t$dep"

echo -e "$login\t$name" >> $realnamecfgUTF8

done

iconv -f utf-8 -t cp1251 -o $realnamecfg $realnamecfgUTF8
iconv -f utf-8 -t cp1251 -o $groupcfg $groupcfgUTF8

Перекодировка в cp1251 нужна для корректного отображения в браузере. Примерный вид статистики:

Доступ к статистике нужно было тоже ограничить, и это было сделано на той же самой базе Kerberos и basic-аутентификации + LDAP-авторизация. Для Apache2 существует два модуля аутентификации Kerberos — старый mod_auth_kerb, который описан во всех статьях, и новый mod_auth_gssapi. Конечно, хотелось пользоваться новым. В процессе настройки я немножко не разобрался и задал вопрос не в тему автору модуля, но в результате всё получилось. Теперь доступ к статистике имеют только те, кто входит в определённую группу в AD, и это очень удобно. Осталось только подать нагрузку на этот новый прокси-сервер, но это не вполне от меня зависит.

Что сделал - 7

Сжатие файлов PDF

На прошлой неделе я узнал о прекрасной практике, когда люди, чтобы получить электронный документ меньшего размера, для отправки его, например, по почте или прикрепления куда-то на сторонний сайт, распечатывают его и сканируют заново. Я мог бы написать о своих впечатлениях от этого знания пару абзацев, но не буду, просто опишу конкретную реализацию моего решения этой проблемы.

Оказалось, что практически все программы, которые работают с PDF и не принадлежат компании Adobe, «под капотом» используют инструмент под названием Ghostscript. У него невероятная куча непонятных опций и жутковатый синтаксис, но для простоты в интернете рекомендуют использование предустановленных значений: ebook и screen. Первый вариант даёт разрешение конечного документа 150 точек/дюйм, что даёт порой недостаточно компактный размер, а второй — 72, что даёт ужасное качество. Нужно было найти некий промежуточный вариант, и я остановился на таком:

& "$ghostScript" -q -o "$outputFile" `
-sDEVICE=pdfwrite -dPDFSETTINGS=/screen `
-dColorImageDownsampleType=/Bicubic -dColorImageResolution=110 `
-dGrayImageDownsampleType=/Bicubic -dGrayImageResolution=110 `
-dMonoImageDownsampleType=/Bicubic -dMonoImageResolution=200 `
-f "$inputFile"

То есть, берётся предустановка screen, у которой принудительно повышается разрешение цветных, серых и чёрно-белых картинок, и режим их пересчёта меняется на более качественный. Значение точек на дюйм я тупо взял примерно среднее между 150 и 72, для чёрно-белых надо всегда ставить больше — они и так компактные сами по себе, и сильнее страдают от низкого разрешения.

Пример выше хорошо подходит для файлов с изображениями и цветной графикой, вроде детских учебников, но нужен ещё один компактный вариант для полностью чёрно-белых документов. Изучение вопроса показало, что в современных версиях Ghostscript нет простого способа переделывать документы в ч/б. Вкратце — раньше можно было сначала конвертировать исходный PDF в монохромный PS (PostScript) через опцию -sDEVICE=psmono, а потом обратно в PDF, добавляя ещё одну хитрую команду; потом psmono убрали, и если сейчас и есть способ такого преобразования, то какой-то совсем нетривиальный, а привязываться к старой версии не хочется. Можно делать документ в оттенках серого, но в этом нет смысла, потому что выяснилось, что разница в размерах с цветным вариантом ничтожна.

Чтобы решить задачу преобразования в ч/б, я задействовал ImageMagick, получилось так:

& "$imageMagick" -density 200 "$inputFile" `
-monochrome -compress Group4 `
"$bwFile"

Density — это указание рассматривать исходный документ с таким-то разрешением, а Group4 — это великолепный алгоритм сжатия ч/б изображений, используемый в факсах. ImageMagick при работе с PDF использует тот же Ghostscript, поэтому на сервере они должны стоять оба.

В результате система выглядит так: есть каталог, куда люди кладут PDF-файлы, каждые 3 минуты запускается задание в планировщике, скрипт читает каталог, берёт подходящие по критериям файлы в обработку, перенося их во временный каталог с текущим временем, а потом результат кладёт обратно в одноимённый подкаталог с добавлением к имени файла «(сжатый)» и «(сжатый чб)». Оригинал после обработки удаляется сразу, результаты — через час. В свойствах задания в планировщике нужно разрешить запуск нескольких экземпляров — ведь обработка может идти больше 3 минут.

Примеры обработки:

  1. Нотный сборник, 49 страниц:
Оригинал (22,8 МБ) Сжатый (5,5 МБ) Сжатый ч/б (1,8 МБ)
  1. Какой-то договор из интернета, 27 страниц:
Оригинал (15,7 МБ) Сжатый (4,5 МБ) Сжатый ч/б (2,4 МБ)

Позже обнаружился способ задания порога для устранения зернистости букв и уменьшения шума для ч/б режима. Нужно добавить -level 10%,90% +dither, но это существенно замедляет обработку.

Дополнительно я нашёл способ прописывания метаинформации в свойства PDF-документа, проще всего для этого использовать ExifTool:

gci "$temp\*.pdf" |% {
& "$exifTool" -charset filename=Cyrillic -charset Cyrillic `
-Author="Обработано в Институте сжатия ПДФ им. Красноглазова" "$($_.FullName)" > $null
}

Результат:

Может пригодиться, например, при дополнительной фильтрации входящих файлов с помощью того же ExifTool, чтобы отбрасывать на входе уже ранее сжатые этим скриптом. Вся эта возня с метаинформацией, конечно, увеличивает время обработки (при её записи файлы пересоздаются заново), так что тут надо подумать, стоит ли затеваться с этим вообще.

Включение Wake-on-LAN на Windows 8 и новее

В связи с тем, что куча народу сейчас работает из дома, пользовательские компьютеры стали работать в режиме 24/7, прямо как сервера. Тем временем, периодически проводятся какие-то работы по электрике, моргает свет и т. п., и компьютеры остаются выключенными. Чтобы включить их, сотрудник техподдержки идёт открывает кабинеты (под подпись актов, с охранником), и жмёт кнопочки включения. Есть разные способы решения этой проблемы, но, например, идея настраивать пользовательские тачки в BIOS так, чтобы они автоматически включались при обрыве питания — идея не очень; всё же есть надежда, что жизнь вернётся в нормальное русло, а в обычной ситуации такую настройку включать не нужно, да и чтобы включить её, опять же надо открыть все кабинеты, перезапустить все компьютеры, зайти им в BIOS и настроить руками, что наводит тоску, когда у тебя в хозяйстве больше полутысячи машин. Мне рассказали, что техподдержка уже несколько лет как включает в BIOS опцию пробуждения компьютера при запросе из сети (Wake-on-LAN), но проблема заключалась в том, что старые системы, типа Windows 7, нормально пробуждаются, а вот новые, вроде Windows 10 — нет. Соответственно, возникла необходимость разобраться, в чём дело.

Полез читать интернеты. Выяснилось, что поведение WoL на системах Windows 8 и новее отличается от более старых. Грубо говоря, в новых системах статус S5 (т. е., «компьютер выключен») стал более строгим — если компьютер выключен, значит, он должен быть реально выключен, т. е., энергопотребление должно быть равным нулю. В связи с этим, чтобы можно было будить комп с новой системой, он при выборе пользователем пункта «выключить компьютер» должен переходить в некое промежуточное состояние S4 (гибридное выключение или «быстрый запуск»). Этот быстрый запуск, или Fast boot, включён в новых системах изначально, но если он выключен, его нужно включить либо через групповую политику, либо через реестр.

Второй момент — в системе должен стоять свежий драйвер сетевой карты, чтобы в его настройках была вкладка «Управление электропитанием». В варианте Windows 10 1809, широко распространённом у меня на работе, стандартный драйвер не имеет этой вкладки, соответственно, комп не просыпается и настроить его невозможно. Пришлось писать скрипт, обновляющий драйверы на машинах в зависимости от модели адаптера. В варианте 1909 уже всё в порядке изначально.

Третий момент — на этой вкладке должны быть включены как минимум две верхних галки из трёх, а лучше все три, чтобы не будить комп зазря (как их включить удалённо, см. статью Information about power management setting on a network adapter). Причём, обнаружилось, что если снять верхнюю галку, компьютер перестаёт просыпаться (а отключать этот пункт — широко распространённая практика).

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

Четвёртый момент — в тех же настройках драйвера на вкладке «Дополнительно» чаще всего нужно отключить настройки типа «зелёный ethernet» и «энергосберегающий ethernet», чтобы адаптер не засыпал. Например, это указано в инструкции по настройке WoL для компьютеров Dell, которые встречаются в моей сети, в общем, надо смотреть инструкции на сайтах производителей по поводу тонкостей. А вот настройки со словами «wake» и «magic packet», наверное, стоит включить все, надо просмотреть их и разбираться в каждом отдельном случае. Для управления электропитанием сетевого адаптера в Powershell существуют удобные команды

Get-NetAdapterPowerManagement
Enable-NetAdapterPowerManagement
Disable-NetAdapterPowerManagement
# Для доп. опций
Get-NetAdapterAdvancedProperty
Set-NetAdapterAdvancedProperty

После сбора информации, тестировании на выделенном мне неттопе HP, массового обновления драйверов на компьютерах в рабочей сети, для чего был написан отдельный скрипт, и реализации всего вышеупомянутого добра в групповой политике, тачки с «десяткой», где был правильно настроен BIOS, начали включаться.

Так как, в числе прочего, у меня в AD пишется и MAC-адрес активных сетевых адаптеров компьютеров, то не проблема будить их, используя Wake-on-LAN, прямо из Powershell просто по имени машины, и это отлично.

Что сделал - 6

Скрипт синхронизации данных из базы Microsoft SQL в Active Directory

Во многих компаниях существуют сервисы, дублирующие друг друга — это происходит отчасти из-за незнания о существовании уже имеющихся инструментов или неумения их настраивать, отчасти из-за сложных взаимоотношений или плохой координации между подразделениями, а отчасти из-за конъюнктурных стремлений различных начальников. К примеру, не раз я встречал разные реализации внутренних телефонных справочников, которые не связаны с Active Directory, хотя логично было бы всю первичную информацию держать именно там, и вся информация была бы доступна через адресную книгу Outlook, или, в крайнем случае, веб-версию справочника формировать из запросов в AD. Нет, так просто нельзя — в моей нынешней конторе телефонный справочник представляет собой отдельный сервис, причём разделённый на два сервера — древняя писанная на коленке веб-морда, которая крутится на Ubuntu 14.04, и база данных, которая работает — это радует отдельно в данной ситуации — на Microsoft SQL.

Данные в этот справочник заносятся вручную, причём бессистемно — телефоны могут быть написаны и 8-495-123, и 8 (495) 123, и ещё как бог на душу положит, а сотрудники, совмещающие несколько должностей, могут быть прописаны несколько раз, причём, у одной инкарнации телефоны и кабинет могут быть прописаны, а у другой — нет. И везде куча ошибок, пропуск пробелов и т. п.

На всё вышеперечисленное безобразие я никак повлиять не могу, однако, хотелось бы иметь актуальные телефоны в Active Directory, которой я управляю. Для этого я написал скрипт синхронизации данных из базы Microsoft SQL в Active Directory. Делается выгрузка из базы (Invoke-Sqlcmd) и из AD, затем для каждого пользователя базы ищется аналог в выгрузке AD, и при несовпадении значений полей они либо меняются, либо удаляются, отчёт по результатам изменений высылается в почту. У дублирующихся пользователей в базе данных информация берётся только из самого свежесозданного по ID.

Конечно, телефоны и прочую информацию я по возможности пытаюсь причёсывать, вот, например, строка обработки телефонных номеров из базы:

@{n='tel';e={($_.tel -split ',').trim() -replace "^49","+7 49" -replace "\)",') ' `
-replace "\s+",' ' -replace '^-$' -replace "^\(|^8 \(","+7 " -replace "\)" `
-replace "123045","123-45" -join ', '}},

Переделал отчёт по несмонтированным дискам Hyper-V в полноценный отчёт по Hyper-V в целом

Отчёт включает в себя:

  1. Таблицу по виртуальным машинам — имя машины, выделенная память, кол-во процессоров, состояние, хост, кластеризована или нет, версия конфигурации. В конце статистика, типа «Всего виртуальных машин 55, общий объём памяти 363 ГБ, всего виртуальных процессоров 134, включено машин 40, выключено 15, в ином статусе 0.»
  2. Таблицу по смонтированным дискам, в конце статистика.
  3. Таблицу по несмонтированным дискам, в конце статистика.

Сбор информации о состоянии жёстких дисков с пользовательских машин

Минимальную информацию об этом может давать и Windows, но хотелось сделать красиво, для этого я привлёк программу DiskSmartView, которая умеет выгружать отчёты в форматах CSV и HTML.

Пользовательские машины не могут пересылать письма через почтовый сервер без авторизации, так что велосипед пришлось усложнить и разбить его на два этапа — одна часть выполняется на локальной машине, а вторая — на сервере.

Локальная часть делает следующее: скрипт запускается после загрузки компьютера, смотрит во временный каталог, и если последний отчёт не старше недели, прерывает работу. Если отчёта нет или он старше, запускает DiskSmartView и делает отчёт во временный каталог в формате CSV, затем проверяет, есть ли в колонке статуса значения, отличные от «OK», «неизвестно» или пустых. Если нет, то работа завершается, а если да, то отчёт делается ещё раз, но уже в общий каталог на сервере и в формате HTML. Потом этот HTML открывается, оттуда выкидывается всё ненужное и вставляется имя компьютера и время составления отчёта. На этом локальная часть исчерпывается.

Серверная часть периодически смотрит в общий каталог, куда валятся отчёты с рабочих станций, и получает оттуда актуальный список файлов .html, сравнивая его со списком в файле smart.txt, который содержит список файлов .html по состоянию на прошлый запуск. На основании всех актуальных файлов .html, отсутствующих в smart.txt, формируются письма и отправляются в техподдержку, а затем актуальный список прописывается в smart.txt, чтобы в дальнейшем не слать дубли отчётов.

Ниже — пример содержимого письма с отчётом. Диски здесь в полном порядке, это просто иллюстрация, в боевых условиях таких отчётов не присылается.

Уже опубликовал этот текст, как вспомнил ещё про один

Cкрипт, связанный с массовым переходом сотрудников на удалённую работу

Суть его в том, что он запускается при загрузке компьютера, ищет в AD пользователя, ФИО которого прописано в описании компьютера, и если находит, прописывает его в локальную группу «Пользователи удалённого рабочего стола», включает RDP через реестр, через реестр же отключает «проверку подлинности сети», прописывает правило файрволла под названием «Allow RDP COVID-2019», а потом по результатам — что было сделано — пишет отчёт в общий каталог на сервере.

Время;ФИО;Логин;Компьютер;Добавлен в группу;RDP;NLA;Правило файрволла
2020.03.25 15:05:55;Королёва Ирина Витальевна;koroleva;PC1384;Да;Включено;Отключено;Создано

Почему такой костыль — во-первых, чтобы можно было, используя статистику, откатить изменения, сделанные на пользовательских машинах, а во-вторых, когда возникла необходимость настраивать массовый удалённый доступ, обнаружилось, что групповые политики домена, касающиеся RDP, которые на протяжении ряда лет никто не трогал, были настроены чёрт-те как, и после того, как народ вернётся на рабочие места, надо будет привести всё это в нормальное контролируемое и понятное состояние.

Праздничные дни в Powershell

Сегодня у меня сработало оповещение о том, что базы Консультанта старые — скрипт смотрит на дату в файле [Путь к каталогу Консультанта]\RECEIVE\LAST_REC.TXT, и если эта дата раньше вчерашней и сегодня не понедельник, отправляет уведомление по почте.

Сегодня вторник, но вчера был выходной в счёт праздника, попавшего на воскресенье, поэтому то, что последнее обновление было 6-го числа, совершенно нормально. Тем не менее, я подумал — а можно ли учитывать и праздничные дни тоже? Как сделать так, чтобы компьютер «знал» про праздничные дни? Ведь это может много где пригодиться, начиная от более гибкого расписания выполнения автоматических заданий, каких-нибудь оповещений, да мало ли где ещё?

Можно! В данном случае я нашёл сайт xmlcalendar.ru, где выкладывают производственный календарь в формате XML. Чтобы выгрузка с него была понятнее, я сделал некоторые преобразования. Вот скрипт:

# Скачивание XML
curl http://xmlcalendar.ru/data/ru/2020/calendar.xml -OutFile d:\temp\cal.xml
# Импорт
[xml]$cal = gc d:\temp\cal.xml -Encoding utf8
# Обработка
foreach ($day in $cal.calendar.days.day) {
$day.d = (($cal.calendar.year + '.' + $day.d) -as [datetime]).tostring("dd.MM.yyyy")

if ($day.t -eq 1) {$day.t = "Вых"}
elseif ($day.t -eq 2) {$day.t = "Сокр"}
elseif ($day.t -eq 3) {$day.t = "Раб"}

if ($day.h -match "\d") {$day.h = ($cal.calendar.holidays.holiday |? id -eq $day.h).title}
}
# Экспорт в CSV
$cal.calendar.days.day |Export-Csv "d:\temp\cal$($cal.calendar.year).csv" -Encoding utf8 -Delimiter ';' -NoTypeInformation

Результат:

d          t    h                                                                     
-          -    -                                                                     
01.01.2020 Вых  Новогодние каникулы (в ред. Федерального закона от 23.04.2012 № 35-ФЗ)
02.01.2020 Вых  Новогодние каникулы (в ред. Федерального закона от 23.04.2012 № 35-ФЗ)
03.01.2020 Вых  Новогодние каникулы (в ред. Федерального закона от 23.04.2012 № 35-ФЗ)
04.01.2020 Вых  Новогодние каникулы (в ред. Федерального закона от 23.04.2012 № 35-ФЗ)
05.01.2020 Вых  Новогодние каникулы (в ред. Федерального закона от 23.04.2012 № 35-ФЗ)
06.01.2020 Вых  Новогодние каникулы (в ред. Федерального закона от 23.04.2012 № 35-ФЗ)
07.01.2020 Вых  Рождество Христово                                                    
08.01.2020 Вых  Новогодние каникулы (в ред. Федерального закона от 23.04.2012 № 35-ФЗ)
23.02.2020 Вых  День защитника Отечества                                              
24.02.2020 Вых                                                                        
08.03.2020 Вых  Международный женский день                                            
09.03.2020 Вых                                                                        
30.04.2020 Сокр                                                                       
01.05.2020 Вых  Праздник Весны и Труда                                                
04.05.2020 Вых                                                                        
05.05.2020 Вых                                                                        
08.05.2020 Сокр                                                                       
09.05.2020 Вых  День Победы                                                           
11.05.2020 Вых                                                                        
11.06.2020 Сокр                                                                       
12.06.2020 Вых  День России                                                           
03.11.2020 Сокр                                                                       
04.11.2020 Вых  День народного единства                                               
31.12.2020 Сокр

Дальше можно допилить автопроверку наличия календаря на следующий год где-нибудь месяце в декабре, но это уже мелочи.

Удобная альтернатива — https://www.isdayoff.ru

Подкручиваем HTTPS

Больше трёх лет назад я делал подобную заметку, настало время дальнейшего пересмотра настроек. Я мало смыслю в безопасности, но зато люблю, когда онлайн-проверки светятся зелёным. За прошедшее время появился протокол HTTP/2, который я включил в конце 2017-го, и TLS 1.3, а версии TLS 1.0 и 1.1 уже признаются устаревшими с марта этого года, и отправляются на заслуженную пенсию составлять компанию уже находящемуся там SSL.

Итак, чтобы выключить все протоколы, кроме самых новых и надёжных, нужно добавить в файл конфигурации Апача, например, /etc/apache2/sites-available/default-ssl.conf (у меня другой файл, который создаёт Let’s Encrypt), следующее:

# Set Forward Secrecy
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLHonorCipherOrder on
SSLCipherSuite HIGH:!aNULL:!MD5:!3DES

# Strict transport security
<IfModule mod_headers.c>
 Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains"
 Header always set Referrer-Policy "no-referrer-when-downgrade"
</IfModule>

С TLS 1.3, по ощущениям, действительно работает быстрее — ведь для установки защищённого соединения ему нужно меньше согласований. SSLHonorCipherOrder on — это включение расстановки приоритета алгоритмов шифрования самим сервером, что рекомендуется.

Также, я включил в Апаче поддержку OCSP Stapling — вроде бы полезная вещь — и, забавы ради, HSTS preloading, но это уже совсем необязательно.

Результат обстоятельного теста на Ssllabs после настройки:

Список других полезных тестов: