🏠: Viacheslav

Что сделал - 5

Скрипт поиска несмонтированных виртуальных дисков Hyper-V

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

Алгоритм работы: берутся все виртуальные машины всех хостов, для каждой выводится список дисков (.vhd и .vhdx), если там вместо диска снапшот, то ищется родительский диск (там другое свойство), и результаты заносятся в один массив. Затем ищутся файлы с теми же расширениями на локальных дисках серверов, результаты заносятся в другой массив. Потом массивы сравниваются — отбрасываются значения первого массива, т. е., смонтированные диски, а потом сортируются по уникальным значениям — дело в том, что если хосты принадлежат кластеру и подключены к одной дисковой полке, то и результаты у них будут практически одинаковые. Ну, а дальше из этого делается красивая табличка, подсчитывается общий итог, генерируются команды на удаление и всё высылается на почту. Выглядит это примерно так:

# Команды на удаление
del "D:\VM\disk_c.vhdx" -Force -Confirm:$false
del "L:\vm\vmws-sccm\sccm2.vhdx" -Force -Confirm:$false
del "L:\vm\vmws-dns\Virtual Hard Disks\vmws-dns.vhdx" -Force -Confirm:$false
del "L:\back\vmls-web\vmls-web_Disk0.vhdx" -Force -Confirm:$false
del "L:\vm\vmws-sccm\sccm_c.vhdx" -Force -Confirm:$false

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

$hosts = "hv01","hv02","hv03","hv04","hv05"
$allvhds = Invoke-Command -computername $hosts -command {
dir ((gcim Win32_LogicalDisk -filter "drivetype=3").DeviceID -replace "$","\") -Include *.vhd,*.vhdx -Recurse -ErrorAction SilentlyContinue
}

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

Результат работы скрипта — нашлось 49 бесхозных дисков общим объёмом немногим менее 4 терабайт.

Скрипт создания папки на файловом ресурсе

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

Конвертация виртуальных дисков VMWare (.vmdk) в Hyper-V (.vhdx)

Последний месяц плотно занимался перетаскиванием виртуальных машин со старой VMWare ESXi 5.5 на модный молодёжный Hyper-V 2016. Есть прекрасная программа под названием Microsoft Virtual Machine Converter, которая хорошо выполняет эту функцию. Но иногда виртуальные машины были уже выгружены в виде набора файлов, и нужно было просто переконвертировать диск. Оказалось, что этот конвертер имеет в своём составе модуль для Powershell, и всё заверте…

# импортировать модуль
Import-Module 'C:\Program Files\Microsoft Virtual Machine Converter\MvmcCmdlet.psd1'
# конвертировать
ConvertTo-MvmcVirtualHardDisk -SourceLiteralPath C:\temp\disk.vmdk -DestinationLiteralPath 'C:\temp' -VhdType DynamicHardDisk -VhdFormat Vhdx

И последняя на сегодня забавная история.

Прошивка дисковой полки HP P2000 G3 FC

Великая и ужасная компания Хьюлет-Паккард выпускает (или выпускала) широко известные в узких кругах дисковые полки P2000. После того, как я перенёс все виртуальные машины со старой VMWare, эта полка освободилась, и там нужно было в одном контроллере заменить сбойную флеш-карту и всячески её обновить. С обновлением возникли проблемы, потому что без наличия сервисного контракта Хьюлет-Паккард скачать свежую прошивку со своего сайта не даёт.

Начал поиск в интернетах — и обнаружилось, что эта полка — перемаркированная DotHill AssuredSAN 3000 series, и компания Дотхилл, её выпускавшая, впоследствии была поглощена компанией Сигейт, у которой эти прошивки свободно доступны на сайте. Я скачал прошивку с сайта Сигейта, и она без проблем установилась и работает.

Больше того — у Сигейта есть прошивка новее, чем последняя версия на Хьюлет-Паккарде, но я не стал бежать впереди паровоза и прошил то, что числилось последним на родном сайте.

Всем хорошего дня, не переключайтесь, продолжим после короткой рекламы.

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

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

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

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

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

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

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

# Выборка
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), так что при их наличии значение этого параметра надо проверять.

Реконструкция сетевого хранилища

Хранилище, которое я собрал без малого два года назад, совсем перестало запускаться. Оно и раньше не отличалось стабильностью при включении — один из дисков периодически не подхватывался, работало всё довольно медленно, один раз даже пришлось добавлять диск в RAID заново, так как он был потерян, хотя в системе присутствовал. В общем, в работе имелись странности.

Логично было предположить, что не хватает питания, и для проверки я приволок с работы стандартный блок (AeroCool KCAS-700W), подключил его и убедился, что хранилище прекрасно включается и работает. Вернув блок обратно, я решил пересобрать систему в новом корпусе и с новым БП.

Итак, корпус нужен как можно более компактный и совместимый с материнскими платами Mini-ITX, но чтобы туда влезали 2 диска 3,5″ и обычный блок питания ATX — со вcякой экзотикой связываться неохота. На рынке есть предложения компактных корпусов такого рода, например, компании Термалтейк, но стоят они как-то дороговато. К тому же, эти корпуса довольно широкие, а мне нужен был не шире 20 см, чтобы влезть на полку в коридоре. Что касается блока питания, то от него требуется бесшумность и наличие активного модуля коррекции коэффициента мощности (Active PFC). Самой мощности особой не нужно, 300 ватт вполне хватит.

В итоге взял супердешёвый и достаточно компактный корпус Exegate BA-110 и блок питания Zalman ZM400-LX (400 ватт, меньше они в этой линейке не делают), скрутил их вместе, пересадил туда всё остальное железо:

Стенки нового корпуса можно натурально гнуть руками, так как металл тонкий и мягкий, а винты в него нужно закручивать очень нежно, до малейшего сопротивления, иначе резьба тут же сорвётся и затянуть их потом будет невозможно. Но ничего другого от корпуса за 830 рублей и не ожидалось, а на самом деле за свои деньги это очень даже достойное изделие. Единственное, к чему может быть небольшое нарекание — что из четырёх верхних посадочных мест под 3,5-дюймовые диски реально можно использовать только два средних: сверху мешают внутренние разъёмы передней панели, а снизу проходит ребро жёсткости, соединяющее стойки корпуса — это не позволяет разнести диски дальше друг от друга. Но это не проблема, диски при работе всё равно холодные.

Светодиод питания (Power LED) оказался синим и очень ярким, я отключил его, вентилятор 80×80 из старой системы задействовать не стал. В результате хранилище получилось тихим и несветящимся — ровно то, что нужно.

Вакцинация, часть пятая

Сегодня я, по большому счёту, закончил проект по актуализации собственного иммунного статуса, который начал в октябре прошлого года. Осталась только ревакцинация против клещевого энцефалита в конце весны-начале лета.

Интересная и поучительная информация в инструкции по применению

Общий список заболеваний, от которых была проведена вакцинация:

  • Гепатит A
  • Гепатит B
  • Корь
  • Паротит
  • Дифтерия
  • Столбняк
  • Коклюш
  • Клещевой энцефалит
  • Менингококк серогрупп A, C, Y и W-135
  • Пневмококк серотипов 1, 2, 3, 4, 5, 6A, 6B, 7F, 8, 9N, 9V, 10A, 11A, 12F, 14, 15B, 17F, 18C, 19A, 19F, 20, 22F, 23F, 33F
  • Грипп 3-х актуальных на этот сезон типов

Добавление 7 июля 2020 г.: сделал ревакцинацию против клещевого энцефалита, следующий раз — через 3 года.

Пропатчил обои

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

На следующий день приступил к финальным работам — развёл обойный клей, купленный накануне, в ведре для мытья полов, повыдергал все шурупы и гвозди из стен и наклеил заплаты. Результат прекрасен.

Wallpaper_1-1_20191221_140614.jpg Wallpaper_1-2_20191223_205740.jpg Wallpaper_2-1_20191221_140628.jpg Wallpaper_2-2_20191221_143014.jpg Wallpaper_2-3_20191223_205806.jpg Wallpaper_3-1_20191221_140723.jpg Wallpaper_3-2_20191221_142939.jpg Wallpaper_3-3_20191223_210012.jpg Wallpaper_4-1_20191221_140652.jpg Wallpaper_4-2_20191223_205934.jpg Wallpaper_5-1_20191221_140707.jpg Wallpaper_5-2_20191223_205946.jpg Wallpaper_6-1_20191221_140743.jpg Wallpaper_6-2_20191221_142916.jpg Wallpaper_6-3_20191223_210052.jpg Wallpaper_7-1_20191221_140753.jpg Wallpaper_7-2_20191223_210119.jpg