Ознакомьтесь с нашей политикой обработки персональных данных
  • ↓
  • ↑
  • ⇑
 
Записи с темой: scripting (список заголовков)
17:09 

Powershell Pinger #2

В Dash'e под Chronostasis'ом.

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

Чем больше смотрю на указанный в коде "грязный хак" - тем больше фигею и фигею. А что делать? Иначе количество ложных срабатываний выведет из себя даже самого терпеливого коллегу. Не говоря уже о том, что я и сам долготерпением не обладаю.
Формат файлов с описанием хостов не поменялся: это все те же текстовые файлы с информацией вида ipaddress,comment, лежащие в папке config рядом с самим скриптом. Там же, рядышком со скриптом будет лежать и формируемый лог взлетов и падений.

@настроение: клац-клац-клац

@темы: PowerShell, Scripting

18:52 

Powershell Pinger

В Dash'e под Chronostasis'ом.

Логи, мониторинг... Мониторинг, логи... Этих самых мониторящих и логирующих утилит на рабочем месте уже воз и маленькая тележка. А самым информативным остается самый обычный, чтоб его, ping. Отрабатывает намного быстрее, чем монструозный SCOM и к нему примазывающиеся.
На текущий момент у нас используется выдранный откуда-то из сети коллегами уже готовый PSH-скрипт, который и занимается весьма простым делом - обходом всех узлов, заданных в банальном текстовике. Пропинговался узел - вывести его имя в консоли зелененьким. Свалился - красным. После чего спим 20 секунд, очищаем окно консоли, и снова все по кругу. Добавили еще пищалку, да и все.
Проблема в том, что держать на экране это окошко - не есть хорошо, окон на рабочем столе и так полно. Пришла в голову идея сделать так, чтобы скрипт при обнаружении свалившегося хоста выдавал в системном трее уведомление, мол, такой-то хост того, сгнил. А если на это уведомление щелкнуть - выведется полный список хостов, на текущий момент лежащих в пыли. Вот что получилось на сегодняшний день.

Как работает.
В папке, где скрипт лежит, создаем папочку config, в нее в виде txt-файлов накидываем информацию о хостах, которые будем мониторить, в следующем виде:
ipaddress,comment
Например:
192.168.1.1,router
127.0.0.1,localhost
192.168.1.3,my computer
128.0.0.1,test host
Можно все хосты в один файл утрамбовать, можно разнести по нескольким файлам, например, серверы отдельно, сетевые железки отдельно...
Внутри этих текстовиков отдельные узлы можно комментировать, поставив перед адресом знак #. К примеру, знаем, что один из серверов сейчас на обслуживании, так чтоб пингер не верещал почем зря - комментируем эту строку в файле.
Если нужно что-то добавить (либо в какой-то файл, либо просто новый файл подключить) - просто добавляем и сохраняем. Перезапускать скрипт не требуется.

Из нерешенных пока проблем.
1. Скрипт этот запускать нужно через ярлык в -sta режиме консоли. По дефолту оная консоль запускается в -mta, в этом случае обработка кликов работать не будет.
2. Инертность. В тот момент, когда скрипт нарывается на свалившийся хост, пока не завершится попытка пинга - скрипт фактически ничего делать не будет. И опять же не будет обрабатывать клики. То же самое справедливо для паузы в скрипте - особенно заметно, когда скрипт добирается до команды start-sleep -seconds $timeout и выполняет ее.

@музыка: Nicolas Jeandot - Fiery Horse

@настроение: надо думать дальше...

@темы: PowerShell, Scripting

14:12 

Автоматизация смотрелок.

В Dash'e под Chronostasis'ом.

Смотрелка - Браузер, если по-нашему, по айтишному.
А началось все... с Initial.D: читать дальше

Что-то вспомнился мне этот диалог, решил, что надо бы эту задачу расколоть.
Исследуем выдачу от Mail.ru. Все ссылки не прямые, а ведущие на отдельные страницы, уже с которых можно вытащить ссылку на сами файлы. Следовательно, вариант, который я использовал в прошлый раз, отпадает. Придется как-то ходить по ссылкам из выдачи поисковика.
Ключевой момент - как можно в Powershell пойти куда-то в вебе в режиме смотрелки? Правильно, "оседлать" смотрелку!


Вот вокруг этого скрипт и будет крутиться. Погнали!



А теперь по складам.
Первый блок ничем не примечателен, обычное объявление объектов да одной переменной. Во втором уже любопытнее, происходит, собственно "автоматизация смотрелки". Мы скармливаем подопытному браузеру исходную ссылку, заставляем его перейти по ней, вытаскиваем из исходного кода этой страницы все элементы типа "якорь", а затем при помощи хитрой магии регулярного выражения из всех этих якорей получаем ссылки, ведущие на страницы загрузки нужных файлов. Эти ссылки в виде хэш-таблицы передаются в переменную $elements.
Дальнейшее уже является повторением ранее изученного. В цикле та же автоматизация смотрелок плюс "хитрая магия" плюс загрузка файла при помощи wget.

Отдельно стоит сказать по зубодробительной конструкции
@([System.__ComObject].InvokeMember(“getElementsByTagName”,[System.Reflection.BindingFlags]::InvokeMethod, $null, $ie.document, 'A'))
которая все якоря из исходника и выбирает. Вообще есть более изящное $ie.document.GetElementsByTagName('A'), но, как выяснилось, у нее есть большие проблемы с разными версиями IE. В актуальных для Windows 7, это не работает, потому пришлось идти через запасной ход.
C хэш-таблицей тоже все весело. Изначально я вообще не планировал ее использовать, ибо зачем плодить сущности. Хотелось в переменную $elements загнать непосредственно то, что будет отдано парсером GetElementsByTagName. Не тут-то было. Парсер эти данные отдал, но как только дело доходило до третьего блока, который уже загружал отдельные страницы, переменная $elements теряла все значения. Не коллекцию элементов, а именно значения. И, естественно, третий блок валился с ошибкой и многими строками красного текста, ненавистного большинству повершелльщиков. Пришлось отделить мух от котлет, после этого все заработало.

А засада этого скрипта в том, что на его отладку было потрачено больше времени, чем на ручное скачивание всех этих 40+ файлов. Ну и ладно, зато плюс одна любопытная задачка в активе :)

P.S> Но насколько же неторопливо идет парсинг кода при помощи GetElementsByTagName...

UPD. В топку internetexplorer.application, Invoke-WebRequest же!

Важно! - из &_amp нужно убрать символ подчеркивания, парсер - нехороший человек.

@музыка: The Offspring - Secrets from the Underground

@темы: PowerShell, Scripting

17:24 

Initial D OST

В Dash'e под Chronostasis'ом.

Добил таки этот опус. Понял, что заиметь некоторые треки в музыкальной коллекции просто необходимо. Действия стандартны: гугл, запрос Initial D OST, пара-тройка страниц, на одной из них находится прекрасное - список треков со ссылками. А рядом другая - скачать все оптом. ОК, нажимаем ее, говорят - регистрируйтесь. ОК, адреса вида @mailforspam.com всегда к вашим услугам. Захожу уже под логином, дают отлуп - авотфиг, дайте нам немного денег на поддержание серверов, тогда и отдадим все оптом. Нет, так не пойдет. Присмотрелся внимательнее на ссылки к песенкам по-отдельности - бааа, да они прямые! Открываем исходный код страницы и видим просто прекрасное:

Ну и далее по тексту. Эту радость ведь вполне можно обработать при помощи Ракушки. Кнопки в зубы, сохраняем страничку с исходником в links.txt:

На выходе получаем не менее прекрасный список из готовых к употреблению гиперссылок. В буфер их и в BITS!
Связка отработала, как и ожидалось. В каталоге загрузок появилось около 40 файлов, ссылки на которые нашлись. Вот только... ни один из них не являлся файлом .mp3. Засада. Для проверки догадки ткнул на одну из тех "прямых" ссылок на веб-сайте - отдали страницу с приглашением: а теперь ткните вот в эту динамическую(!) ссылку, и будет вам счастье.
На что я плюнул, и пошел искать это самое счастье в других местах. ИЧХ, нашел.
Итого:
- задачка с парсингом ссылок порадовала;
- скрипт работы с BITS все же пригодился;
- регулярки - ЗЛО :)

@музыка: Fastway - Revolution

@темы: Scripting, PowerShell

17:40 

Буфер обмена и загрузка файлов #2

В Dash'e под Chronostasis'ом.

Теперь - банановый (с)
В смысле - теперь это чудо умеет общаться с BITS:


К слову сказать, сама BITS на редкость придирчива. В цикле скормить ей сразу несколько файлов нельзя. Если требуется - список нужно оформить в виде csv-файла, а уже этот файл дать ей на вход. Если же пытаться обойтись без файла - можно будет только создать несколько заданий, в каждое из которых трамбуем один файл, то есть получится что-то вроде этого:


Посмотрим, что будет лучше.
UPD. Спасибо Cybeon. Нафиг временный файл:

@музыка: Wuauquikuna - Sweetheart Merceditas

@темы: Scripting, PowerShell

17:55 

Буфер обмена и загрузка файлов.

В Dash'e под Chronostasis'ом.

Надоело при помощи цопипасты загружать файлы из нескольких ссылок. Выделить ссылку, скопировать, вставить в браузер. Дождаться, пока вылезет окно сохранения файла, нажать ОК. А потом все это повторить n раз... На-до-е-ло. Хочу так: есть куча ссылок (прямых), выделить их все, скопировать в буфер, нажать 1 (одну) кнопку и получить все разом.
Заодно отметим переход на Powershell 4 (давно пора было это сделать, ISE стал заметно удобнее).

@музыка: Iron Savior - Starborn

@темы: PowerShell, Scripting

15:42 

Powershell + Gmail + Imgur.com = ... part 3

В Dash'e под Chronostasis'ом.

А зачем нам вообще какая-то выделенная папка для хранения фотографий, которые нужно отправить в веб? У нас же есть потрясающий пункт меню "Послать на... Send to...". Так почему бы им и не воспользоваться?
Для начала настраиваем сам ярылк, который будет лежать в папке %USERPROFILE%\AppData\Roaming\Microsoft\Windows\SendTo
Создаем там новый ярлык, в свойствах которого в поле Target прописываем следующее:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -f "PATH-TO-UPLOAD-sсript"
Имя и значок этого ярлыка выбираются по собственному вкусу.
А скрипт, который будет заниматься непосредственно отправкой, будет выглядеть так:

@темы: PowerShell, Scripting

23:18 

Powershell + Gmail + Imgur.com = ...

В Dash'e под Chronostasis'ом.

Поднадоел photobucket.com. Вот реально поднадоел. Интерфейс неповоротливый, реклама всякая опять же.
Присмотрелся поближе к imgur.com. Раньше он меня жутко бесил своими тормозами, сейчас его в этом плане облагородили. Но не только в этом. Есть там интересная возможность - заливать картинки через почту. Весьма удобно для пакетной обработки, а еще это дело можно заскриптовать.
Не думал, что эта задачка будет настолько интересной :)


А теперь разбираем по складам.
Весь блок #setting up variables ничего особого из себя не представляет. Там описываются все параметры доступа к картинкам и ящику, через который будем все отсылать. Мой ящик - на gmail.com, потому работаем на примере этого почтового сервиса.
Выбрать все картинки из указанной папки - тоже ничего особого. Вся коллекция будет сохранена в переменной $files.
Блок #setting up smtp client уже любопытнее. Там любопытна конструкция

$smtp.Credentials = New-Object System.Net.NetworkCredential($SMTPUsername, $SMTPPassword)
$smtp.EnableSSL = $true

которая говорит скрипту, что с почтой надо общаться по зашифрованному каналу связи. В противном случае gmail пошлет нас подальше с вердиктом

The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required

Еще одна деталь. Для того, чтобы это все сработало необходимо уже в настройках аккаунта gmail включить доступ для небезопасных приложений. Материал по этому поводу в сети есть. Если этого не сделать - gmail будет отбивать любые попытки работы скрипта с ящиком.
Блок #settung up message также не представляет ничего особого. Более того, там обязательными для заполнения полями будут всего лишь $msg.To.add($MailTo) и $msg.From = $MailFrom (Куда и от кого, соответственно). Адресом отправки всегда будет upload@imgur.com, а по адресу отправителя будет ясно, какая учетка на самом Imgur.com шлет картинки.
А вот секция #attach files in upload folder выпила у меня крови в три своих горла.
Сама по себе она стандартнейшая. Для каждого файла в коллекции $files, собранной ранее, делаем вложение в письмо с этим файлом. Все бы ничего, но в первой версии этого блока картинки цеплялись к письму и отсылались, но на Imgur ничего не появлялось. В чем проблема?
Как раз пока писалась первая версия скрипта, шел диалог с Линда Кайе по поводу ранее не срабатывавшей отправки картинок. Среди предположений были и лишние символы в имени файлов, и длина имени... В итоге сошлись на том, что картинки рушил формат письма. Линда, я тебя и огорчу, и порадую. Это не совсем так.
Сравнивая два письма, посланных через скрипт и через web-интерфейс самого Gmail, выяснил, что формат их был один и тот же - multipart/mixed. Тем не менее, скриптовое письмо вложения по дороге теряло. А вот в чем отличие нашлось, так это в формате самих вложений: в письмах, отправленных через web-интерфейс, формат картинок JPG показывался как Content-Type: image/jpg. А в сообщениях, сформированных скриптом, те же картинки шли в виде Content-Type: application/octet-stream. И вот именно это и не позволяло уже самому Imgur найти в письме картинки и обработать их. Для того, чтобы избавиться от этой напасти в блок формирования вложений в скрипт и добавлена строка:

$MailAttachment.ContentType.MediaType = "image/$($file.extension.substring(1))"

Причем действует она хитро. В зависимости от того, какое расширение у обрабатываемой картинки, она сменит тип контента. Есть JPG - будет "image/JPG", обрабатываем PNG - получим "image/PNG".
Завершающая же строка скрипта проста как пара копеек, просто отправляем сформированное письмо.

@музыка: Koan - Back to the Silent Lagoon - Blue Mix

@темы: PowerShell, Scripting

00:21 

MP3 Tags in CLI

В Dash'e под Chronostasis'ом.

Настала пора окончательно разобраться со своей большушей подборкой Two Steps from Hell. Все лень было теги расставить, ведь после конвертации из WAV их там просто нет. А некрасиво.
Нативно PowerShell работать с тегами не может. Вроде как кто-то даже писал стороннюю библиотеку для этих целей, но с ней ничего не сложилось. Что ж, будем использовать старый добрый invoke-expression, который так хорошо выручил в прошлый раз. В качестве инструмента расстановки тегов будет выступать id3.exe - мелкая и быстрая (реально быстрая) утилитка. Снова ISE в зубы и вперед:


Согласен, конструкция ([uri]$file.fullname).segments[5].trim("/").replace("%20", " ").replace("%23", "#").replace("_", " ").substring(7) выносит мозг, но уж что поделать. Ибо в получаемом имени каталога пробелы будут преобразованы в код %20, а знак # - в код %23, что не есть хорошо. Ну и замена подчеркивания на пробел туда же, хотя проще было переименовать исходную папку (что и было сделано уже после прогона скрипта). Отдельно по поводу конструкции .substring(7). Альбомы названы так: XXXX - Album Name, где ХХХХ - год выпуска. Потому его надо отсечь.
Пара минут, и 1049 файлов обработаны так, как требуется по условиям задачи.

P.S. Ну и на сладкое. Всем поклонникам 8-битной музыки - настоятельно рекомендую пройти вот сюда: vk.com/rus_instrumental. Альбом "Ура товарищи, космос наш!" - это нечто. Особенно хочется отметить композиции Железная Пыль и Прыжковый Ранец (must hear интервал 2:54-3:18). А за анимешную мордаху в качестве обложки альбома - просто гранд мерси! :)

@музыка: Злые роботы - Железная Пыль

@темы: Scripting, PowerShell

03:35 

Права на каталоги

В Dash'e под Chronostasis'ом.

Задали тут задачку на прошлой работе. Строго говоря, задали ее не мне, ибо я там уже не работаю, но проблему озвучили при мне, и в голове тут же щелкнуло - это ж работа обычного скрипта, а чего б его не накатать для тренировки?
Задача состоит в следующем. Есть каталог. На этот каталог привешен доступ для определенной учетки на чтение всего, что в нем лежит. От имени этой учетки работает спец. ПО, которое таскает фотографии из подпапок этого здорового каталога в информационную систему. Беда в том, что на некоторых подпапках (почему-то) выставляются совершенно дикие разрешения, среди которых нужной учетки просто нет. Соответственно, фотографии из этой подпапки не попадают в ИС, после чего вопли до небес и т.д., и т. п., и ДТП.
Почему разрешения могут плыть - отдельный разговор, есть подозрение, что такие каталоги не создаются пользователями, а перемещаются из других папок с сохранением прав. Это еще предстоит проверить, а пока нужно найти все такие подкаталоги и поправить разрешения на них - просто сбросив их в наследуемые от родителя. Сказано - сделано:

Получившая строчка, где определяется переменная $ace - нечто, но оно мне нравится. Если непонятно, объяснение выглядит вот так:
- берется список разрешений на каталог, имя которого получаем в цикле foreach (список будет в памяти в виде объекта),
- раскрываем в этом объекте нужное нам свойство - access. Именно там перечислены все учетные записи, которые есть в списке прав доступа,
- пробегаемся по всем элементам в этом свойстве и ищем там запись, совпадающую с заданным пользователем,
- эту самую полученную запись заносим в переменную $ace (Access Control Entry)
Много слов, а строка одна, и, в общем-то, довольно простая :)

@музыка: Manowar - Black wind, fire and steel

@настроение: Рабочее

@темы: PowerShell, Scripting

05:55 

Powershell variables expansion

В Dash'e под Chronostasis'ом.

UPD. Ага, а теперь выдолби на том же лбу то, о чем тебе уже говорили: hikedaya.diary.ru/p164830971.htm


Иными словами - у нас появилась новая переменная с именем, состоящим из выражения.
---
Блин, выдолби уже у себя на лбу простую истину:

не даст то, что нужно, будет ахинея. А вот так:

выведет требуемый простое список имя. Да и вообще - раскроет переменную $comp.name так, как надо, не только в случае с компьютерами. Полезно, когда потом то, что загнано в $compname, уйдет в оператор invoke-expression, вызывающий какую-нибудь DOS утилиту. Например, выполняемое для коллекции серверов:

запись создана: 12.01.2015 в 16:17

@темы: PowerShell, Scripting

14:05 

Conversion

В Dash'e под Chronostasis'ом.

Когда-то давно попалась мне папочка под названием Two Steps from Hell. А в ней куча треков от одноименной группы, все в формате WAV. Чтоб без потери качества, так сказать. Одно плохо, в телефон не закинешь, да и места много едят. Надо бы их всех отконвертировать в идеологически верный mp3, который понимает практически все звукоиздающее барахло. Хотя нет, идеологически верным будет ogg, но мой телефон все равно его не поймет.
Вроде бы на компе есть AIMP с его конвертером. И в большинстве случаев этого хватает. Но в случае пакетной обработки он может и спасовать. Что ж делать, не руками же все это перелопачивать (папок там немало).
Кинул клич по своему контакт-листу, общими усилиями достали завалявшийся lame.exe. Дело за малым, все тот же Powershell в руки:


Крутится, жрет папку, на которую я его натравил...
Забавляет вывод от lame.exe в окне ISE - он весь краснющий, как помидор. Красный в PSH - цвет ошибок, сначала зело напугал :)
Ах, да. Если нужно удалить исходный файл сразу после преобразования - раскомментировать строку #Remove-Item $file.fullname. Без предварительного теста (например, с ключом -whatif) - не рекомендуется, впрочем, так всегда.
P.S. А потом смотрим на строку с определением целевого имени файла и понимаем, что можно было сделать еще красивее:

$destination=$file.fullname -replace $file.extension, ".mp3"

Впрочем, вариант с построением целевого имени из отдельных кирпичиков кажется более наглядным.

@музыка: Roxette - Fingertips

@темы: Scripting, PowerShell

19:27 

DPM 2012 Enumerate tapes scritpt

В Dash'e под Chronostasis'ом.

Забавный случай. Имеем скрипт, который обсчитывает все ленты в библиотеке, подконтрольной DPM 2012. Фрагмент скрипта выглядит вот так:

$RPs=Get-RecoveryPoint -Tape $Tape
$ExpDate = $RPs[0].recoverysourcelocations[0].expirydate

И вот этот кусок ведет себя на разных системах по-разному. На одной из рабочих станций - все ок. На сервере - все ок. На другой рабочей станции - все плохо, дает ошибку вида Unable to index into an object of type...
Сначала думали, что что-то не так с самим шеллом от DPM на проблемной машине. Переставили, результат нулевой.
Проверили догадку относительно прав на сам DPM и работу с ним. Отмели, потому что на сервере под той же учеткой, что и на проблемной рабочей станции, все ок.
Начал ковырять. Скрипт валится всегда на одних и тех же кассетах. А записей на этих кассетах - по одной штуке на каждую. Получается, что на выходе мы получаем обычную скалярную переменную, которую скрипт затем пытается представить как массив, и выдрать из него самый первый элемент с нулевым индексом. И получает отлуп. Проверяем:

PS C:\temp> $a=12
PS C:\temp> $a[0]
Не удается индексировать в объект типа System.Int32.
строка:1 знак:4
+ $a[ <<<< 0]
+ CategoryInfo : InvalidOperation: (0:Int32) [], RuntimeException
+ FullyQualifiedErrorId : CannotIndex

Уже интереснее. Ковыряние сети привело к корню проблем: на такой фокус с обращением к обычной переменной, как к массиву, способен Powershell 3.0 и выше. А на проблемной станции - увы и ах, всего лишь вторая.
Что ж, учтем на будущее.

@музыка: Koan - Dance of Nereids

@темы: PowerShell, Scripting

03:25 

Event Log + Powershell

В Dash'e под Chronostasis'ом.

MS в своем стиле. Давно такой зубодробиловки не встречал. Впрочем, из стана *nix, наверняка, наоборот, могут послышаться возгласы одобрения, ибо "все есть файл".
Задача. Необходимо сделать так, чтобы по возникновению в журнале Windows события с определенным кодом администратору (или другому причастному к процессу) на почту падало письмо с содержанием этого сообщения. Заскриптовать сам процесс отправки письма - не проблема. Проблема в это письмо утрамбовать содержимое самого сообщения.
Что попытались сделать? Нам известен код события. Что ж, по возникновению этого события ищем все события с этим кодом, сортируем их в порядке убывания, отсекаем самое первое в выборке. Это и будет искомое. Дальше по скрипту вытаскиваем его содержимое, трамбуем в письмо, отсылаем депешу. Казалось бы, проблема решена.
А вот и нет. Проблемы начинаются, когда копируется сразу несколько мелких файлов. В этом случае вся наша выборка становится сбойной, и в итоге события теряются, письма приходят только на часть их. Что же делать?
Вечерний треп с Cybeon принес весьма любопытные результаты. У каждого события в логе есть уникальный номер. Вот вытащить бы его, отдать скрипту, а скрипт уже пусть ищет именно это конкретное событие и пакует его в письмо. Идея хорошая, но как? А вот так:
blogs.technet.com/b/otto/archive/2011/08/24/tri...
Как уже выше было сказано - все есть файл. Именно файл нам на помощь и приходит.
Вкратце - создаем болванку задания, экспортируем его в XML файл и убиваем болванку. Она нам больше не нужна. А потом правим полученный XML файл и вносим туда следующее:

После чего импортируем этот файл в оснастку назначенных заданий. После таких вот премудростей наше задание будет отдавать три параметра: имя журнала, в котором возникло наше событие (eventChannel), его критичность (eventSeverity) и, та-дааааам, уникальный код этого события (eventRecordID).
Итак, сами значения мы выцарапали. Как их передать в скрипт? Через параметры командной строки:
powershell -command %PATH-TO-sсript% -eventChannel $(eventChannel) -eventRecordID $(eventRecordID) -eventSeverity $(eventSeverity)

А последний шаг - уже в том скрипте, который будет выполнять все действия по отсылке писем, первой строкой объявляем полученные параметры:
param($eventChannel,$eventRecordID,$eventSeverity)

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

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

@музыка: Eric "Erock" Calderone - Killer Instinct Meets Metal

@темы: PowerShell, Scripting

10:23 

Remote Desktop Connection Manager + Active Directory #2

В Dash'e под Chronostasis'ом.

Скрипт доработан до полного функционала. Берет информацию о серверах из Active Directory, вносит ее в файл настроек RDCMan, затем убирает из этого файла настроек записи о серверах, которых уже нет в AD. Доработка напильником как всегда: указать путь к файлу настроек и задать критерии отбора серверов:

@музыка: Power of Melody - Poisoned Planet

@темы: Scripting, PowerShell

15:18 

Remote Desktop Connection Manager + Active Directory

В Dash'e под Chronostasis'ом.

RDCMan попался мне на глаза довольно давно. Удобный инструмент для управления соединениями через RDP, плюс штампик "от производителя". Этот самый штампик и позволяет его использовать на рабочем месте. Да вот беда - эта программка ведет свой собственный список серверов, с Actove Directory никак не связанный. А это плохо, лениво каждый раз при вводе нового сервера добавлять его в лист RDCMan. Что же делать? Каким-то образом автоматизировать обновление списка, больше нечего.
Список серверов RDCMan хранит в специальном файле с расширением *.rdg (remote desktop group), который по своей сути является обычным XML-файлом. Вариантов его ведения может быть два - либо все серверы, добавленные в эту группу будут идти единым списком (именно это требуется и мне), либо же будут вручную разбиты по группам внутри списка. С ручной группировкой ничего не сделаешь - в AD нет сведений, по которым можно было бы серверы по группам раскидывать, а вот с простым списком можно и поковыряться. Powershell to the rescue!
Для начала заставим RDCMan создать файл группы серверов. Просто запускаем его и добавляем туда сервер-болванку, назначение которой - быть шаблоном для добавления остальных серверов. Попутно можно прописать туда общие настройки подключения - в 90% случаев все подключения проходят под одной и той же учеткой, с одинаковыми параметрами. После подготовки начинаем ваять сценарий синхронизации.
Первым делом в сценарии, который будет обновлять список серверов в RDCMan, поднимаем работу с Active Directory:

import-module activedirectory

Само собой, этот модуль уже должен быть установлен в системе.
Далее необходимо загрузить содержимое нашего файла в Powershell (нужно будет прописать путь к rdg-файлу

$doc="path-to-rdg-file"
$xml = New-Object XML
$xml.load($doc)

Следующий шаг - получение списка серверов из AD (необходимо подставить критерии отбора серверов):

$comps=get-adcomputer -filter 'insert-your-criteria'

После получения списка серверов скрипт должен пробежать по списку уже имеющихся серверов в файле и полученному списку из AD и сравнить их. Если будет найден сервер, который присутствует в AD, но отсутствующий в списке RDCMan - добавим его.

foreach ($comp in $comps) {
$isExist=$False
foreach ($node in $xml.rdcman.file.server) {
if ($node.name -eq $comp.name) {$isExist=$True}
}

if ($isExist -eq $False) {
$clone = $xml.rdcman.file.server[0].clone()
$clone.name=$comp.name
$clone.displayName=$comp.name
$clone
$xml.rdcman.file.appendchild($clone)
}
$isExist=$False
}

В завершение - сохранение нашего файла RDCMan одной простой командой:

$xml.save($doc)

К чести RDCMаn стоит добавить, что сортировку серверов по алфавиту он выполнит автоматически при запуске (отключаемо). За это некоторые его ругают, но мне этот подход нравится.
Последним шагом будет удаление из списка RDCMan сервера-болванки.
Ну и пара слов по тому, каким образом можно использовать полученный сценарий. Лично мне по душе автоматический его запуск при логине в систему. Таким образом по завершении загрузки профиля список RDCMan'а уже будет актуализирован.
Что еще можно было бы добавить: обратную проверку. Если сервер перечислен в RDCMan, но его записи нет в AD - удалить его из RDCMan.

@темы: Scripting, PowerShell

11:47 

Drive letter in CMD

В Dash'e под Chronostasis'ом.
Несмотря на мою нежную любовь к Powershell старый добрый CMD все же иногда нужен. Например, тогда, когда компьютер загружен с аварийного диска. Задача следующая - необходимо получить букву диска системного раздела. Всем известно, что во время загрузки с аварийных дисков буквы располагаются несколько в ином порядке, нежели обычно. Как же будем искать? Очень просто - по метке диска, которая была задана заранее - старая привычка маркировать раздел с ОС именно как "OS". Что ж, посмотрим, что у нас имеется. А имеется инструмент под названием wmic:
wmic logicaldisk
Эта команда покажет все логические диски, зарегистрированные в системе. А как бы нам отсечь ненужные разделы? Это можно сделать, отфильтровав вывод команды по полю volumename, а делается следующим образом:
wmic logicaldisk where volumename="OS"
В ответ получаем тонну сведений об интересующем нас логическом диске. Далее - выбираем из этого потока информации букву диска:
wmic logicaldisk where volumename="OS" get deviceID
Выводом в моем случае является вот это:

DeviceID
C:

Итак, почти добрались. Теперь бы еще избавиться от первой строки вывода. Не вопрос - воспользуемся "трубой" (конвейером) и командой поиска findstr:
wmic logicaldisk where volumename="OS" get deviceID | findstr :
Да, ищем символ двоеточия, который всегда присутствует рядом с именем диска. Получаем то, что нужно:
C:
Ну и самое вкусное - как бы теперь этот вывод утрамбовать в переменную. Именно та точка, где я снова и снова вспоминаю добрым словом Powershell, потому что там вывод можно просто присвоить некой переменной. В CMD нам это недоступно, поэтому будем обманывать через оператор FOR.

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

@музыка: Ryan Farish - Life in stereo (solarsoul remix)

@темы: Scripting

10:26 

Time Zones

В Dash'e под Chronostasis'ом.
Казалось, что кошмар с переводом стрелок уже давно и прочно забыт. Ничего подобного:
Депутаты Государственной думы вернули россиянам постоянное зимнее время без сезонных переводов часов - Клац!

Коллеги-администраторы, готовимся заранее, как говорится, потому что еще неизвестно, когда будет (если вообще будет), выпущен патч, в очередной раз меняющий временную зону. Ну а чтобы не попасть, если патча все же в нужный момент не будет:

Поскольку во временной зоне Багдада нет перехода на зимнее/летнее время, а смещение как раз UTC+3, именно она нам и подойдет. Если по каким-то причинам не нравится Багдад, можно отослать ОС аж в Найроби, благо, параметры этой временной зоны отвечают всем требованиям :)


Как запустить эту команду на удаленных компьютерах - уже было написано немало, от PsExec, до PS Remoting.

@музыка: David & Diane Arkenstone - Night Flight

@темы: Scripting, Этот безумный мир

16:52 

System image and relocating user profiles at once...

В Dash'e под Chronostasis'ом.
Итак, grand finale. Образ готов, осталось самое интересное - все же заставить пользовательские папки жить не на системном разделе. Как мы уже знаем, использовать файл ответов для этих целей нельзя. В сети гуляет второй метод - обман ОС при помощи файловой системы и симлинков, которые предоставляет файловая система. Идея проста - нужно загрузиться с любого LiveCD, умеющего работать с NTFS (самый простой вариант - с установочного диска Windows 7), перетащить каталог Users на нужный раздел, а на месте этого каталога на диске C: разместить симлинк, ведущий на истинное расположение папки профилей. Подводный камень в том, что встроенные средства Win 7 не умеют работать с junctions, которых в каждом профиле штук 15. А перенести их хотелось бы. Что ж, для этого подойдет программка fastcopy, синтаксис будет примерно таким (предполагая, что папки должны будут лежать на диске D:):
fastcopy /acl %systemdrive%\Users /to=D:
Это скопирует полностью каталог Users на диск D: с сохранением всех junctions и прав на каталог. Затем делаем сам симлинк:
mklink c:\Users d:\Users /J
Сказано - сделано. Каталог скопирован, симлинк - тоже, время запускать sysprep. После которого мы получаем... неработоспособную ОС, не способную пройти даже minisetup. Что за...?
Shift+F10 на экране с ошибкой, и смотрим, что у нас происходит. А происходит у нас следующее:

Проще говоря, sysprep взял наш созданный симлинк, ведущий на диск D:, и завернул его на самого себя! Тем самым порушив нашу установку.
В общем и целом, Windows очень активно сопротивляется любым попыткам переноса каталога Users. Стало быть, придется оставить его на месте, и работать с отдельными папками.
Теория. Все создаваемые учетные записи наследуют свои настройки от стандартного пользователя Default. В том числе и пути к папкам с контентом. Стало быть, как-то надо эти настройки изменить.
Если делать это из графического интерфейса руками, то выглядит это так: открываем regedit, в нем переходим на какой-нибудь куст, куда у нас есть права записи, и в него монтируем реестр из профиля Default, он лежит вот в этом файле:
%systemdrive%\Users\Default\ntuser.dat
После этого можем приступать к редактированию.
Нужные нам настройки хранятся по следующему пути (в моем случае профиль Default был примонтирован в ветку HKLM под именем DefaultProfile): HKLM\DefaultProfile\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders"
Практика. Поменять пути к тем папкам, которые требуется перенести, после чего записать изменения в этот файл реестра просто отмонтировав его соответствующей командой.
Если это оформить в виде скрипта (мы, администраторы, ведь очень ленивые люди, да?), то получится нечто вроде следующего:

Что ж, все это замечательно. Однако, после выполнения sysprep все это добро будет сброшено на дефолтные значения. Стало быть, выполнять эту операцию придется уже после выполнения sysprep. В этом нам поможет тот самый автологин, который мы настраивали ранее. Коли у нас после развертывания запускается скрипт настройки ПК, то почему бы не включить в него и вышеуказанные инструкции по смене каталогов.
Сказано - сделано. Добавили, оттестировали, все отлично. Каталоги перенаправляются, библиотеки работают как надо, одна только проблема - в профиле остаются уже пустые каталоги документов, загрузок, музыки... Они уже не нужны, значит надо от них избавиться, чтобы лишний раз не вызывали недоумение. Это уже довольно просто:

Вышеуказанное можно оформить в виде *.cmd файла, разместив его в папке профиля пользователя Default. При этом он будет скопирован в каждый профиль каждого созданного пользователя. Осталось только обеспечить автоматический запуск этого сценария. Как сделать? Воспользуемся технологией RunOnce применительно к учетным записям. Для этого в тот код, который меняет пути к пользовательским каталогам, добавить инструкцию запуска кода очистки лишних папок (в данном примере скрипт очистки называется CleanUp.cmd и расположен в папке профиля Defaut):

На этом вроде все.

@темы: Scripting

16:16 

System Image part number next...

В Dash'e под Chronostasis'ом.
Итак, задача, в общем-то, проста. Нужно подготовить образ системы на определенную модель ПК. Очень желательно, чтобы действий администратора было по минимуму. Образ на основе русского дистрибутива ОС Windows 7. Естественно, есть куча требований к состоянию ОС уже после развертывания образа (имя компьютера, состояние встроенных учетных записей, много чего). Естественно, нужно использовать sysprep.
На первый взгляд, ничего сложного. Подготавливаем исходный ПК, ставим на него ОС, все необходимые обновления, весь необходимый софт, проводим все настройки. После чего натравливаем на компьютер sysprep, захватываем образ. И потом уже этот образ раскидываем по рабочим станциям.
А теперь - детали, в которых кроется дьявол (который таки может плакать).
После выполнения sysprep /generalize все встроенные учетные записи будут переименованы. Да, они станут Администраторм и Гостем. Ладно, это можно обойти, в конце концов, после развертывания станции в любом случае будет исполняться настроечный сценарий, который учетные записи сделает такими, какими они и должны быть. Единственное, что остается неизменным - это пароли данных учеток, sysprep их не трогает. Уже проще.
Подводный камень номер два. После развертывания образа, на который был натравлен sysprep, первое, что появится на экране - это окно Windows Welcome. То самое окошко, где нужно задать и имя пользователя, и имя компьютера, а потом еще и политику обновлений, тип сети, часовой пояс, в общем - много всего. Лениво. Ладно, это тоже обходится при помощи файла ответов, о котором речь и пойдет.
Само по себе создание такого XML файла сложностей не представляет. Есть специальный инструмент, называется Windows System Image Manager. Как им пользоваться - есть подробнейшая справка. Скажу лишь, что возможности по настройке ОС он представляет поистине широчайшие.
Итак, файл ответов подготовлен, в него внесена информация о практически всех параметрах, которые нам мешают жить (то есть прерывают автоматическую установку). В том числе и создание временной учетной записи (без этого - к сожалению, никак). Следующий этап - каким-то образом заставить систему загружаться не под новосозданной учетной записью, а под той самой административной, что была задана еще на этапе установки исходной ОС. И вот тут начинается кавардак.
Административная учетная запись после sysprep блокируется. By default and hard-coded. Среди всего многообразия настраиваемых параметров в файле ответов разблокировки этой учетной записи как таковой нет. Как же быть? Ответ следующий: методов два. Один из них - выполнение специальной команды на этапе настройки specialize:
net user Администратор /active:yes
Второй - просто настроить автологин от имени этого самого администратора, в этом случае блокировка отменяется.
Отлично, убиваем двух зайцев сразу, тем более, что нам все равно автологин понадобится. И параметры автологина как раз настроить в файле ответов не проблема:
Как именно

После этого задаем все остальные нужные параметры и запускаем sysprep с указанием имени файла ответов (через графический интерфейс это сделать нельзя):
sysprep /oobe /generalize /shutdown /unattend:PATH_TO_XML_FILE
Когда компьютер выключится, снимаем образ, после чего загружаем его, чтобы посмотреть, что же у нас получилось.
Каково же было мое удивление, когда я увидел, что система попыталась выполнить автовход, но нарвалась на следующее: "При первом входе пользователь должен изменить пароль"
Что за ересь?! Учитывая, что у административной записи эта галка сроду не стоит, становится не совсем понятным, откуда она взялась.
Тут небольшое отступление. Поскольку дома у меня стоит английская ОС, то все имена учетных записей в файле ответов сначала были английскими. И все заработало. После переноса файла ответов в русскую ОС с заменой имен учетных записей на русские - получили вышеописанный результат. Вопрос - что пошло не так?
Конец отступления.
Предположив, что банально произошла какая-то ошибка во время развертывания ОС и применения файла ответов развернул образ еще раз. Нет, все так же - меняйте пароль. Хорошо, давай поменяем. Подтверждаю смену и вижу просто прекрасное: система пытается загрузиться не с помощью административной учетной записи, как это было указано в файле ответов, а с помощью новосозданной временной. Да, у нее флаг смены пароля установлен по умолчанию. Но как же так?
После установки и конфигурировании экрана Windows Welcome ОС сама пытается зайти под той учетной записью, которую найдет (кроме гостевой), и которая не будет неактивной. Получается, что запись администратора она не видит, или эта запись не разблокировалась. А не разблокированной эта учетная запись может остаться только в том случае, если в файле ответов почему-то она не указана в параметрах автовхода. Проверяю файл ответов, но загружать по-новой Windows SIM было лень. Тотал, выбрать файл, нажать F4...
Давайте разберемся. На дворе теперь уже 2014 год. Полное засилье Unicode. А Windows как работала весьма коряво с кодировками, так и продолжает работать.
В общем и целом, взору предстала картина убитого имени "Администратор", превращенного в набор непонятных символов. И это - при использовании официального инструмента от MS. ОК, в заголовке полученного XML файла четко написано:

Открываем его в режиме utf-8, правим убитое имя учетной записи, сохраняем, снова выполняем sysprep на восстановленной машине. И тут sysprep выдает вовсе парадоксальное - у вас нечитаемый файл ответов.
Опустим мои не самые лучшие мысли по этому поводу. Что же делать?
Почитав справку о стадиях настройки ОС после установки и пробежавшись по интернету, выяснил, что можно переименовать учетную запись еще до появления окна Windows Welcome, а это значит, что можно избавиться от русского имени. Все бы хорошо, но ведь для того, чтобы переименовать учетную запись, ее нужно выбрать, и выбирают чаще всего по имени, что опять приводит нас к использованию русских букв в файле ответов. А этого нужно избежать. И это возможно. Все компьютеры с Windows на борту назначают встроенной учетной записи администратора один и тот же SID. А это уже кое-что.
Итак, на стадии specialize даем запуск вот такой команды:

Эта команда найдет среди всех учеток лишь одну, и это будет именно встроенная учетная запись администратора. После чего команда переименует ее в удобный для нас англоязычный вариант.
Дальнейшее - тривиально. В параметрах автовхода указываем новое имя администраторской учетки, сохраняем файл ответов, выполняем sysprep, снимаем образ, загружаем. И да, получаем желаемый результат - однократный автовход под нужной нам учетной записью. Дальнейший запуск подготовленного скрипта окончательной настройки - и система готова.
Казалось бы, на этом все? Да как бы не так, потому что Windows все же не сдается. Сразу после автоматического входа под учетной записью Administrator ради интереса открыл список всех учеток на компьютере. Каково же было мое удивление, когда я увидел учетку "Администратор". Да, именно так, по-русски! Вот так и слышу мерзкое хихиканье из системного блока, мол, ты можешь как угодно извращаться с этой записью, но все равно будет по-моему! Но так и быть, за труды твои, неправедные, малость уступлю.

@музыка: Jaime Cristopherson - Metal Gear Rising: Revengeance OST - Montenergo

@темы: Этот безумный мир, Scripting

Записная книжка

главная