🏠: powershell

Что сделал - 9

Отчёт по VMware ESXi

Разобрался с PowerCLI, наконец.

Изображение без описания

Также, установил веб-морду на ESXi 5.5, это гораздо удобнее отдельного клиента, и она поддерживает управление машинами версии 10.

Перевод внешних прямых DNS-зон на хостинг, а обратных c Windows DNS на BIND9

До этого в конторе было два локальных внешних DNS-сервера, где крутились все зоны. Я предложил перевести DNS на внешний хостинг, чтобы не держать эти сервера у себя, что и было после долгих согласований проделано начальником. Правда, пришлось писать на Powershell конвертер DNS-записей из формата выгрузки Windows DNS в формат, принимаемый Руцентром (там, похоже, тоже крутится BIND), потому что просто передать зоны не получалось. Я не лез в процесс переноса, просто сформировал файлики, чтобы их можно было импортировать на хостинге.

Всё прошло хорошо, но оказалось, что избавиться от локальных внешних серверов DNS полностью всё равно нельзя — у компании в собственности внешний IP-диапазон и нужно обеспечивать обратные зоны (PTR), иначе почта ходить не будет.

Тогда я поднял две виртуалки с Ubuntu Server, поставил туда BIND9, оба сервера сделал подчинёнными (кэширующими) для всех прямых зон — они синхронизировались с Руцентром, а для обратных зон один сервер первичный, а второй забирает эти обратные зоны с первичного. Ресурсов обе эти машинки едят меньше, чем один старый сервер на Windows. Всё чудесно работает, и минус 2 лицензии серверной винды. Внешний хостинг DNS в любом случае полезен — он повышает отказоустойчивость, а стоит очень недорого.

Система распознавания текста (OCR) для файлов PDF

В компании закуплены лицензии FineReader, но на всех желающих не хватает, закупать их — тема трудная и долгая, а работать как-то надо, причём, прямо сейчас. Темы закупки ПО и её методов, когда вместо корпоративной лицензии всё покупается поштучно и от случая к случаю и последствиях такого подхода затрагивать не буду, это не моя область ответственности, хотя смотреть на это иногда бывает больно. Короче говоря, нужен какой-то простой способ распознавания текста в файлах PDF по типу механизма сжатия, сделанного мною ранее. Я уже довольно давно знаю о существовании очень неплохой программы gImageReader, которая является оболочкой к OCR-движку Tesseract, который я и задействовал для решения этой задачи. Сборкой этого движка для Windows занимается Маннгеймская университетская библиотека, за что ей огромное спасибо.

Сам Тессеракт не воспринимает файлов PDF, ему картинки подавай, так что пришлось сначала прогонять файл через GhostScript, который преобразует PDF в набор картинок PNG.

& "$ghostScript" -dBATCH -dNOPAUSE -sDEVICE=pnggray -r300 "-sOutputFile=$($pdf.basename)-%04d.png" "$($pdf.fullname)"

Ну, а дальше картинки скармливаются Тессеракту, он делает из них соответствующее количество текстовых файлов, которые потом лепятся в один и выдаются пользователю.

(dir *.png) -match "$($pdf.basename)" |% {
    & "$tesseract" ".\$($_.name)" "$($_.basename)" -l rus+eng
}
gc ((dir *.txt) -match "$($pdf.basename)") -Encoding UTF8 |Out-File "$path\$($pdf.basename).txt" -Encoding default

Возьмём для теста какой-то договор из интернета:

Исходник - какой-то договор из интернета (фрагмент)

Результат распознавания:

- при производстве земляных и строительных работ соглассвывать
предполагаемые работы с Главным управлением по государственной охране
объектов культурного наследия Тверской области.

2. Срок Договора

2.1. Срок аренды Участка устанавливается с 2 ^\*\_\_ по 10.04.2019 года.
2.2. Договор вступает в силу со дня его государственной регистрации. |

3. Размер и условия внесения арендной платы

3.1. Арендатор ежегодно уплачивает Арендодателю арендную плату.
3.2. Размер арендной платы за Участок определяется в соответствии с
Расчетом арендной платы, являющимся неотъемлемой частью настоящего
Договора (приложение № 2).
3.3. Порядок определения размера арендной платы за пользование земельными
участками, устанавливается органом государственной власти Тверской области.
3.4. Арендная плата вносится следующими частями:
3.4.1. юридическими лицами:
- не позднее 15.04. - 1/4 годовой суммы;
- не позднее 15.07. - 1/4 годовой суммы;
- не позднее 15.10. - 1/2 годовой суммы.
путем перечисления на реквизиты, указываемые Арендодателем в асчете
арендной платы на текущий год. Арендатор обязан ежегодно до внесения
первого арендного платежа в текущем году уточнять у Арендодателя реквизиты,
на которые перечисляется арендная плата. :
В случае заключения Договора аренды после 15 сентября (в первый год
аренды) арендная плата за период до конца года, в том числе сумма,

По-моему, для бесплатного движка это очень круто.

Для ускорения обработки можно применить Powershell 7, где есть параллельный цикл, чтобы выжать из железа всё, на что оно способно.

Движемся дальше.

P. S. Чуть позже доделал скрипт, теперь он, помимо PDF, работает с TIF-TIFF (в т. ч., многостраничными), JPG-JPEG и PNG. Тут проще, потому что Тессеракт сам умеет работать с этими форматами без предварительных преобразований. Также, сделал вариант под Powershell 7 с параллельными циклами, что работает гораздо быстрее на одном и том же компьютере.

Праздничные дни в 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

Обучение компьютера русскому

У меня на работе пользователям присылалось автоматическое уведомление о кончающемся сроке действия их пароля, где первой строкой была фраза:

Уважаемый пользователь Информационных Систем!

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

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

Первым делом нужно понять, как отделять мужские ФИО от женских. Просматривая списки, я обнаружил, что ключом к разгадке являются отчества — все мужские отчества заканчиваются на «ич», а все женские — на «на». Сначала я думал, что одинаковы три последних буквы, но, например, у мужчин есть Ильич и Кузьмич, а у женщин Ильинична и Кузьминична, так что остановился на двух.

Так-то лучше:

# Выборка
if ($user.givenname -match "на$") {$body1 = "Уважаемая $($user.givenname)!"}
elseif ($user.givenname -match "ич$") {$body1 = "Уважаемый $($user.givenname)!"}
# А случаи бывают разные
elseif (!($user.givenname)) {$body1 = "Уважаемый $($user.name)!"}
else {$body1 = "Уважаемый пользователь информационных систем АО «Мир шерстяных носков»!"}
# Результат
$body1

Уважаемый Игорь Валерианович!
Уважаемый Михаил Сергеевич!
Уважаемый Игорь Алексеевич!
Уважаемая Олеся Андреевна!
Уважаемая Анна Васильевна!
Уважаемая Светлана Николаевна!
Уважаемый Алексей Владимирович!
Уважаемый Сергей Владимирович!
Уважаемая Любовь Владимировна!
Уважаемая Полина Евгеньевна!

Следующий этап — зависимость окончания слова «день» от их количества. Надо составить фразу «Действие вашего пароля истекает через N дней». Путём нехитрых размышлений получается, что вроде бы все числа, заканчивающиеся на 1 — это «день», на 2,3 и 4 — «дня», а все остальные — «дней». Проверяем:

if ($user.daystoexp -match "1$") {$in = "через $($user.daystoexp) день"}
elseif ($user.daystoexp -match "[234]$") {$in = "через $($user.daystoexp) дня"}
else {$in = "через $($user.daystoexp) дней"}
# Результат
"Действие вашего пароля истекает $in."

Действие вашего пароля истекает через 24 дня.
Действие вашего пароля истекает через 17 дней.
Действие вашего пароля истекает через 14 дня. # !
Действие вашего пароля истекает через 2 дня.
Действие вашего пароля истекает через 49 дней.
Действие вашего пароля истекает через 23 дня.
Действие вашего пароля истекает через 55 дней.
Действие вашего пароля истекает через 12 дня. # !
Действие вашего пароля истекает через 1 день.
Действие вашего пароля истекает через 11 день. # !

Русский язык велик и могуч, его с кондачка не возьмёшь! Исключение — числа с одиннадцати до четырнадцати: они все должны заканчиваться словом «дней», причём, в любой сотне — «через 11, 112, 1513, 614 дней». Исправляем:

if ($user.daystoexp -match "(?<!1)1$") {$in = "через $($user.daystoexp) день"}
elseif ($user.daystoexp -match "(?<!1)[234]$") {$in = "через $($user.daystoexp) дня"}
else {$in = "через $($user.daystoexp) дней"}
# Результат
"Действие вашего пароля истекает $in."

Действие вашего пароля истекает через 24 дня.
Действие вашего пароля истекает через 17 дней.
Действие вашего пароля истекает через 14 дней.
Действие вашего пароля истекает через 2 дня.
Действие вашего пароля истекает через 49 дней.
Действие вашего пароля истекает через 23 дня.
Действие вашего пароля истекает через 55 дней.
Действие вашего пароля истекает через 12 дней.
Действие вашего пароля истекает через 1 день.
Действие вашего пароля истекает через 11 дней.

Так-то лучше! Теперь бездушный компьютер будет обращаться к людям по имени-отчеству, да ещё и правильно склоняя слова, что, по-моему, отлично.

Напоследок расскажу, что, оказывается, дата истечения срока действия пароля вычисляется самим контроллером домена и хранится в атрибуте msDS-UserPasswordExpiryTimeComputed, причём, в нечитаемом формате FileTime (количество 100-наносекундных интервалов с 1 января 1601 г.). Чтобы преобразовать это значение в «нормальный» формат при запросе, нужно написать что-то вроде

Get-ADUser username -Properties msDS-UserPasswordExpiryTimeComputed |
select name,samaccountname,@{n='passexpdate';e={[datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}}

У нас в домене нет Fine-Grained Password Policies (FGPP), так что при их наличии значение этого параметра надо проверять.

Ubuntu 19.10

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

Также, меня интересовал вопрос, есть ли какой-нибудь хороший редактор кода для Powershell в линуксе. Оказалось, что родной микрософтовский редактор VSCode доступен и прекрасно работает. Теперь можно везде писать скрипты на одном языке и в одном редакторе.

Как сохранить текстовые сообщения из Skype

Штатного механизма выгрузки текстовых сообщений в Скайпе нет, а копипаст не работает. Единственное, что можно сделать — это выгружать сообщения по одному.

В этом случае помогает великий Nirsoft, написавший программу SkypeLogView.

Upd: В 2021 году я написал на Powershell скрипт, который приводит экспорт сообщений Скайпа в удобочитаемый вид: Skype export parser.