В новой версии я сделал HTML-таблицу проще, убрал некоторую лишнюю информацию и внес еще кое-какие никому не интересные изменения. Новый скрипт умеет экспортировать данные в *.json, правильный *.csv с кавычками, удобочитаемый *.xml с понятными названиями тегов и в *.html как графическое представление собранной информации.
Зачем нужен этот велосипед, скажете вы, если уже есть hwinfo, aida, msinfo32, siw, everest и прочие? К сожалению, ни одна из вышеперечисленных программ не удовлетворяет полностью моим задачам. Они либо платные, либо требуют установки, либо не умеют в командную строку, либо требуют дополнительных действий со стороны пользователя, либо же их функционал избыточен.
Скрипт же можно изменять под ваши конкретные нужды просто редактируя код в блокноте или Powershell ISE. Linux way, bitch. Пардон. Достаточно не нарушать структуру вложенности главного словаря $PCInfo в котором хранится вся обработанная и готовая к выводу информация. То есть, не плодить еще вложенные словари внутри уже вложенных словарей. Больше словарей богу словарей! (Нет).
Пример работы скрипта при экспорте в *.HTML файл.
Отображение информации о железе ПК в виде *.HTML файла, для просмотра которого достаточно любого браузера.
Так выглядит информация экспортированная в *.csv и открытая в MS Excel
Результаты отображения информации в формате *.CSV в программе MIcrosoft Excel
Помните, что в российском Excel разделителем в CSV считается не запятая, а точка с запятой ; Соответственно для корректного отображения *.csv в Excel нужно включить в скрипте использование региональных стандартов.
Если хотим забирать инфу в какую-нибудь NoSQL базу, то лучше всего подойдет экспорт в JSON
Результаты отображения информации в формате *.JSON
Приятно удивило, что экспорт в JSON в Powershell делается буквально двумя строчками при условии, что вы скармливаете в конвейер [ordered]Dictionary или [PSCustomObject].
Для любителей смотреть CSV в блокноте, можно открыть CSV в блокноте.
Скромное и лаконичное обаяние *.CSV
Выше показан результат экспорта в правильный международный *.csv, с запятыми в качестве разделителей и токенами в кавычках, как и должно быть согласно CSV стандарту. Акцентирую на этом внимание потому, что некоторые производители, - да, Microsoft? - считают, что заключать токены строки в кавычки при экспорте в *.CSV необязательно.
Экспорт в формат XML. При желании, информацию в таком виде тоже можно хранить в NoSQL базе или просто в виде файлового хранилища на какой-нибудь админской шаре.
01. Добавить возможность собирать информацию об удаленных компьютерах без загрузки на эти самые компьютеры. Хотя, в принципе, ничто не мешает вам, как админу, загружать скрипт на компьютеры пользователей и писать информацию в нужном формате на шару. Или же сразу забирать с клиентов готовые результаты.
02. Писать собранную информацию в, например, MySQL базу данных.
03. Собирать более детальную информацию о статусе и состоянии жестких дисков.
Если это нужно кому-то кроме меня, прошу поддержать меня рублем. Чтобы я знал, что не зря трачу время. Поскольку время моё ограничено, увы, а финансовая жопа постоянна, двойное увы.
Вводишь номер объекта в скрипт, он ищет на нём ПК в Active Directory и выдаёт информацию по количеству свободного места на диске и размеру диска. Выделенная область не совсем понятна. Знак доллара, собака, вот это вот всё. Если есть возможность разжевать цикл для тупых) и как это склеивается с командлетом.
Write-Host "ERROR!" $PCs[$i].Name $_ -ForegroundColor Red
}
}
Clear-Variable -Name "PCs"
}else{
Write-Warning "The entered value is incorrect"
}
Немного теории про переменные:
Переменная — это единица памяти, в которой хранятся значения. Рекомендуется, чтобы имена переменных включали только буквенно-цифровые символы и символ подчеркивания (_). Имена переменных, включающие пробелы и другие специальные символы, трудно использовать и следует избегать.
В PowerShell существует несколько различных типов переменных.
Созданные пользователем переменные: созданные пользователем переменные создаются и поддерживаются пользователем. По умолчанию переменные, созданные в командной строке PowerShell, существуют только во время открытия окна PowerShell. При закрытии окон PowerShell переменные удаляются. Чтобы сохранить переменную, можно добавить ее в профиль PowerShell. Можно также создавать переменные в скриптах с глобальными, скриптами или локальными область.
Автоматические переменные: автоматические переменные хранят состояние PowerShell. Эти переменные создаются PowerShell, и PowerShell изменяет их значения в соответствии с требованиями, чтобы обеспечить их точность. Пользователи не могут изменить значение этих переменных. Например, $PSHOME переменная сохраняет путь к каталогу установки PowerShell.
Переменные предпочтения: переменные предпочтения хранят пользовательские настройки для PowerShell. Эти переменные создаются PowerShell и заполняются значениями по умолчанию. Пользователи могут изменять значения этих переменных. Например, $MaximumHistoryCount переменная определяет максимальное количество записей в журнале сеансов.
Теперь с картинками:
Переменные в powershell начинаются со знака "$". Имена переменных не зависят от регистра, то есть переменные $nameVar и $NAMEvar - одна и та же переменная. Присвоение значения переменной происходит через оператор "=".
Имена переменных могут включать пробелы и специальные символы. Например: ${name of variable}. Использование такой вариации имени сомнительно, но поддерживается.
После присвоения значения переменная будет иметь свой тип. У всех типов переменных есть общие и уникальные свойства и методы, к которым можно обращаться через точку. Для того, чтобы узнать какие методы и свойства есть у текущей переменной, можно воспользоваться командой Get-Member, как в примере ниже.
Тип переменной $name - System.String, то есть строковый.
Для работы с массивами объектов в переменных 2 очень важных свойства:
Length (длина) и Count (количество). Зачастую данные свойства используют для определения элементов в массиве, но часто ошибочно используют Length, когда желательно использовать Count. Дело в том, что свойство Length действительно в большинстве сценариев отображает количество элементов массива, кроме случая, когда в массиве один элемент строкового типа. В этом случае свойство Length выдаст количество символов в строке.
Примеры получения этих свойств ниже:
Разница в значении свойств Length и Count проявляется в примере переменной $var_text. Свойство Length отобразило количество символов в строке (длину). Свойство Count отобразило отобразило количество строк (или объектов в массиве). Поэтому для корректности крайне рекомендуется использовать свойство Count для определения количества элементов массива.
Анализ
Первая проблема данного кода - обильное использование алиасов, не прозрачных конструкций и отсутствие комментариев. Попробуем разобраться, попутно изменив код на более читаемый и оставив комментарии.
Начнём с того, что приведем скрипт в читаемый вид, выровняв основные блоки кода:
Отформатированный в читаемый вид изначальный текст скрипта.
На вход описанному блоку скрипта должна прийти переменная $SearchBase со значением отличным от символа "0". Открывает выполнение кода условный оператор if () else. Условие проверки странное, так как минимально необходимая обычно проверка - это проверка на пустоту какой-либо необходимой для выполнения блока кода переменной, но для этого достаточно оставить в проверке if переменную без операторов сравнения. Здесь же у нас if получит TRUE в случае, если $SearchBase не будет эквивалентен символу "0".
Учитывая, что нам не известно какие значения $SearchBase может принимать, менять логику проверки не стоит. С учетом анализа дальнейшего использования данной переменной, становится ясно, что она используется для определения области в домене Active Directory, из которой будут выбираться объекты компьютеров в командлете Get-ADComputer
Исходя из этого (и из примеров использования Get-ADComputer), переменная $SearchBase должна содержать строку DN (Distinguished Name) контейнера Active Directory в формате
Допустим, в переменной $SearchBase у нас все таки что-то похожее на Distinguished Name контейнера в AD (либо корень домена - "DC=domainName,DC=local, такое определение области тоже имеет место быть). Идем дальше: алиас select меняем на полное имя командлета Select-Object
Здесь у нас происходит следующее: сначала получаем все объекты компьютеров из AD по указанному контейнеру в переменной $SearchBase.
Затем по конвейеру (символ | ) результаты выполнения этой команды передаются на команду Select-Object:
Командлет Select-Object выбирает указанные свойства объекта или набора объектов. В нашем случае из свойств объектов компьютеров Active Directory выбирается только свойство Name. Набор свойств по умолчанию, доступных в объекте компьютера, возвращаемый командлетом Get-ADComputer представлен ниже.
Затем все имена компьютеров сохраняются в переменную $PCs. То есть, если после оператора присвоения переменной (символ =) происходит выполнение нескольких командлетов с передачей результатов по конвейеру, в переменную будет сохранен результат выполнения последнего командлета (в нашем случае это Select-Object).
Таким образом, в переменную $PCs (при корректной передаче $SearchBase, естественно) будет сохранен массив свойства Name объектов компьютеров из AD. Примерно следующего вида:
Далее идет цикл For для обработки элементов массива переменной $PCs.
В условиях цикла For стоит перебор по одному элементу массива $PCs, начиная c нулевого ($i=0; $i -lt $PCs.Length; $i++). Условием остановки цикла является перечисление всех объектов из переменной. Для решения данной задачи немного проще использовать цикл Foreach, но про него поговорим в следующей статье. Единственное исправим $PCs.Length на $PCs.Count
Затем, для каждого элемента массива выполняется конструкция Try {} Catch {}.
Блок Try {} будет выполняться для каждого элемента массива, блок Catch {} будет выполнен только в случае, если в блоке Try будет зарегистрирована исключительная ситуация (ошибка при выполнении командлета, например).
В блоке Try {} выполняется три командлета:
получение информации о Wmi-объекте win32_volume (раздел диска) с удаленного компьютера (командлет Get-WmiObject). Первый параметр командлета Get-WmiObject -Class является позиционным, и его можно не указывать, но такая практика не является рекомендуемой, так как это усложняет чтение кода. Второй параметр -ComputerName определяет имя сервера \ рабочей станции из массива переменной $PCs. Так как в переменной $PCs у нас хранится массив свойств Name, то к этому свойству через символ точки и обращаемся, при этом указав порядковый номер элемента с помощью квадратных скобок. То есть, в записи $PCs[$i].Name - $PCs это весь массив свойств имен компьютеров из Active Directory. В квадратных скобках указан текущий номер элемента массива в цикле For, а если это первая итерация, то там у нас будет 0. И через символ точки "." мы получаем имя компьютера для передачи в параметр -ComputerName. Параметр -ErrorAction определяет поведение консоли при обработке вероятной ошибки (исключительной ситуации, например компьютер целевой не доступен и не удается получить информацию), при выполнении данного командлета.
Значение параметра -ErrorAction Stop означает, что в случае исключительной ситуации, дальнейшее выполнение блока Try {} будет прекращено в рамках данного прохода цикла For и будет выполнен код из блока Catch {}, который как раз и служит для отработки кода в исключительных ситуациях.
Для того, чтобы понимать происходящее в коде, крайне важно понимать с каким объектом (и какие у него свойства) в данный момент происходит действо.
Для примера, разберем какого типа возвращает объекты командлет Get-WmiObject. Для этого попробуем выполнить следующее:
Таким образом, можно увидеть какие свойства и какие значения этих свойств есть у объекта типа win32_volume. Вывод свойств по умолчанию у объектов разный, и зачастую избыточен, поэтому после того, как вы поняли какие свойства вас интересуют, полезно будет научиться использовать следующие командлеты:
Select-Object - командлет, используемый для отображения только указанных свойств переданных по конвейеру объектов:
Where-Object - командлет, используемый для фильтрации массива объектов по условному свойству (или совокупности свойств). Рассмотрим пример ниже с массивом объектов-служб в переменной $services. Допустим, нам необходимо отфильтровать и получить только сервисы в переменную $targetService которые имеют в DisplayName слово "Update" и у которых статус "Running":
Фигурные скобки с условиями для командлета Where-Object практически всегда используются, поэтому просто привыкните пока использовать данный командлет в таком режиме. Из нового здесь у нас использование переменной $_ - что это такое и зачем она нужна.
Если вкратце, то $_ это алиас для автоматической переменной $PSItem PowerShell, используемый в скриптблоках, обрабатывающих текущий объект, например в конвейере. То есть $_ хранит в себе текущий объект, переданный по конвейеру.
Вернемся к нашим баранам
Далее по скрипту передача по конвейеру Wmi-объекта на командлет Where-Object с целью фильтрации. Условием для фильтрации является эквивалентность свойства Name WMI-объекта значению "C:\". То есть, фильтр выставлен, чтобы дальше по конвейеру пошли только объекты, которые являются логическим диском C:\.
Затем используется уже известный командлет Select-Object, но с интересным способом изменения отображаемых полей свойств приходящего WMI-объекта при отображении:
свойство __SERVER меняется ComputerName
свойство Capacity останется в таком же виде, но значение его будет изменено согласно формуле $_.Capacity/1GB.
свойство FreeSpace останется в таком же виде, но значение будет изменено согласно формуле $_.FreeSpace/1GB.
Также будет выведено свойство Name без изменений
Касательно изменений значений объема и свободного - $_Freespace / 1GB.
Такого рода преобразование используется в случаях когда значения свойств хранятся с байтах (а это наш случай), а мы хотим вывести значение в гигабайтах.
Затем идет блок кода Catch, в котором отработает командлет Write-Host - который красным цветом напишет в консоль "ERROR!", имя текущего сервера, по которому не удалось отработать блок Try. Далее, в конце каждой итерации сработает командлет очистки переменной $PCs. Затем описано блок Else, скриптблок которого отработает в случае, если условие $SearchBase -ne "0" не будет выполнено. Скриптблок содержит один командлет, который напишет текст "The entered value is incorrect" в консоль.
Конечный, немного поправленный блок скрипта выложу картинкой
Выкручивайте остроумие на максимум и придумайте надпись для стикера из шаблонов ниже. Лучшие идеи войдут в стикерпак, а их авторы получат полугодовую подписку на сервис «Пакет».
Кто сделал и отправил мемас на конкурс — молодец! Результаты конкурса мы объявим уже 3 мая, поделимся лучшими шутками по мнению жюри и ссылкой на стикерпак в телеграме. Полные правила конкурса.
А пока предлагаем посмотреть видео, из которых мы сделали шаблоны для мемов. В главной роли Валентин Выгодный и «Пакет» от Х5 — сервис для выгодных покупок в «Пятёрочке» и «Перекрёстке».
Реклама ООО «Корпоративный центр ИКС 5», ИНН: 7728632689
На дворе Апрель месяц 2003 год. Птички поют, кукушки кукуют. Microsoft выпускает в свет свою прекрасную Windows Server 2003. Системные администраторы в слезах счастья рассказывают любителям консоли как много изменений в AD, в безопасности, в *any_windows_feature_name* произошло и как теперь здорово пользоваться окнами.
Одуревший от счастья нажиматель кнопок на клавиатуре.
И всё бы хорошо, но любители пингвинов стали активнее намекать жалким любителям GUI о том, что консоль это божественно, а кнопки мышью нажимать - удел ламеров. Bash, мол, позволяет скрипты писать и вообще делать всё что душе угодно в плане автоматизации.
Конечно, в Windows есть cmd и даже есть возможность писать bat-скрипты, но выглядит енто, конечно убого. Глобальных отличий непосредственно в самих оболочках со стороны конечного пользователя черного экрана не так много, но дьявол скрыт в мелочах.
Для начала посмотрим, что же енто за cmd \ bash такие и зачем они собственно нужны.
command line interpreter (CMD)
Типичный вид cmd.exe
CMD — это командная строка для операционной системы Microsoft Windows с функциями, основанными на командах. Конвейера нет, вывод результатов в строке. Долго отсутствовали инструменты для работы с текстом.
Bourne again shell (Bash)
Типичный вид bash
Bash — это язык командной строки и сценариев для большинства операционных систем на базе Unix/Linux. Есть конвейер, вывод результатов в строке. Имеются инструменты для работы с выводом в виде текста (grep \ awk \ cat \ tail и т.д.). Они позволяют отделить нужные буквы из строки от ненужных при выводе результатов действия команд.
Шли годы, nix-админы наращивали скилл в умении прерарировать текст, оконные админы жмакали кнопки в gui и плакали при написании bat-скриптов, попутно совместно меряясь писюнами, кому же из них работать сложнее. И так бы оно и было, пока ребята из Microsoft не решили выкатить его. Его величество Powershell.
- В чем же величие? - спросите вы.
Powershell это такая же среда выполнения скриптов и взаимодействия с OS, как и cmd \ bash. Есть одно но - powershell умеет в объекты. Он по умолчанию работает с объектами и их свойствами. Почему это так важно? Потому что вывод в строки большинства утилит и приложений, с которыми умеет работать cmd \ bash не имеют единого стандарта вывода. ipconfig может выдать вам совершенно разное полотно информации на разных OS, при разных количествах сетевых интерфейсов и просто если луна не в меркурии будет.
Вывод текста утилитой ipconfig
Допустим вы захотели вытащить через cmd IP-адрес.
На Bash сделать это достаточно легко. Для этого достаточно использовать простую команду ниже:
ifconfig eth0 | sed -n '2 {s/^.*inet addr:\([0-9.]*\) .*/\1/;p}'
Сильно, правда? Всего regexp (регулярные выражения) надо знать, как свои 9 пальцев.
В Windows тогда вообще с этим дела никак не обстояли, поэтому приходилось изучать полотно текста и радоваться, что вообще хоть какая-то информация в консоли отображается.
С приходом powershell консоль научилась работать с объектами и при вводе командлета (название стрёмное, да, так уж они там называются): Get-NetIPAddress объекты, у которых есть одинаковые свойства, к которым можно обращаться.
История с объектным ориентированием консоли сильно облегчила возможность получения информации о системе. Например, теперь чтобы получить информацию об IP адресе, нет нужды изучать regexp, а достаточно запомнить, что к свойствам в объектах можно получить доступ через точку:
Помимо этого powershell поддерживает конвейер для передачи результатов деятельности из одной команды в другую, if - else \ switch ветвления, циклы do while \ until, создание функций и своих объектов.
В первой версии Powershell 1.0 функционал был немного куцый в сравнении с текущей версией, но его объектная ориентированность уже принесла много счастья в руки любителей автоматизировать.
Вторая версия добавила возможность удаленного выполнения кода, поддержку Windows Server 2008 и Windows 7. Помимо этого большинство программных продуктов Microsoft не только нативно поддерживало работу через powershell, но и предоставляло больше возможностей, нежели GUI.
Powershell 3.0 появился рядом с Windows 2012 и Windows 8, получил еще большее развитие командлетов и возможностей отладки. В общем так и продолжалось его развитие вплоть до 5ой версии, на которой Microsoft решили, что нужно сделать cross-платформенную оболочку и объявили о создании PowerShell Core c поддержкой различных систем в названии которых отсутствует слово Windows: MacOS \ Ubuntu \ RHEL \ CentOS и так далее.
Какие еще возможности предоставляет эта оболочка я расскажу в следующей статье Cat's & Lamp.
У меня возникла ошибка файловой системы - фотографии не открывались, без ошибки, только через 15-20 минут всплывало серое окно вместо фото. В безопасном режиме виндовс мне удалось выявить ошибку "2147416359".
Сначала решил просто почистить пк - CCleaner, Malwarebytes. Последний нашёл в файловой системе зараженные файлы, кои я переместил в карантин. Так как проблема не исчезла, а эти файлы не относились к важным приложениям, я их удалил.
Проблему ничего из этого не решило, однако в какой-то момент, запущенная нескольконадцать минут назад фото выдало ошибку уже: "не удалось зарегистрировать пакет". Данную ошибку рекомендуют решать командой Get-AppXPackage -AllUsers | Для каждого {Add-AppxPackage -DisableDevelopmentMode -Register “$ ($ _. InstallLocation) \ AppXManifest.xml”} в Windows PowerShell. Однако при нажатии "Enter" ничего не происходит, сколько не жди.
После этого, я решил покопаться в интернете на предмет ошибок уже в Windows PowerShell и выявил возможный: нужно разрешить сценарии выполнения в виндовс. После этого что-то изменилось - после ввода команды появилась надпись об ошибке.
Наибольшая мощь платформы .NET раскрывается посредством IL (intermediate language, эдакий символический аналог языка ассемблера) — во что, собственно, и преобразовывается код на C# или любом ином языке платформы. Однако IL сторонятся как огня даже бывалые .NET'овцы (звучит как-то неполиткорректно), что говорить о разработчиках сценариев PowerShell?! Между тем, для последних это не просто полезный навык, скорее — возможность взять планку на порядок выше покуда другие рвут и мечут в отсутствии какой-либо фичи. Именно так в бытность второй версии PowerShell и поступал автор, реализуя, к примеру, побитовы(й|е) сдвиг(и) в(лево|право) посредством функции, в основе которой был динамический метод.
Здесь, правда, используется синтаксис pwsh, измождённым же ностальгией при переводе примера на вторую версию PowerShell следует быть аккуратными при использовании переменной $$ и принять на вид возможность имитации тернарной операции посредством массивов; для прочих пример может показаться притянутым за уши, так как pwsh уже располагает операторами -shl и -shr, а значит
(New-Shift).Invoke(7, 3)
или:
(New-Shift shr).Invoke(7, 1)
будут подобны разве что ложке дёгтя в бочке мёда. Однако, истинная причина, по которой мы сознательно избегаем синтаксиса версий ниже шестой, кроется в различного рода рестрикциях присущих .NET Framework (и, как следствие, "наследуемых" PowerShell -le v5), но отсутствующих в .NET Core, как, например, использование указателей в динамических методах. Чтобы продемонстрировать это, а заодно чуть подробнее разобрать сам принцип создания последних, рассмотрим побайтовый вывод числа через указатель.
Результатом, как и ожидается будет 00 40 00 00. А теперь немой вопрос: для чего это может понадобиться, если всё можно написать на C# и скормить Add-Type? Прежде — скорость: динамические методы создаются в динамической (кто бы мог подумать!) сборке pwsh, в то время как Add-Type создаёт физическую сборку, подгружаемую в текущий домен приложений, а это, во-первых, требует валидации кода, во-вторых, ведёт к захламлению сборками домена в текущем сеансе. Вторая немаловажная причина кроется в обработке больших данных где исключается параллелизм, например, расчёт энтропии некоторого файла, с которой, как было замечено ранее здесь, лучше и начинать исследования бинарного кода.
То, что в список ассоциаций не заглядывают даже матёрые админы (большая часть из них) — это факт. Более того, разворачивая в Windows системах какой-либо из интерпретаторов, админы соглашаются с установщиком добавить ассоциации с соответствующими расширениями файлов, а после недоумённо пожимают плечами "как же нас таки поломали?", — в самом то деле?! Windows, чай, не UNIX где для исполнения какого-либо сценария нужно уметь чмодить (хотя в UNIX своих проблем безопасности с ворох газет), так что просто нужно взять на карандаш избегать ассоциаций, предпочитая им колхозные, но более безопасные средства запуска. Для наглядности (командная строка):
assoc .url | sed "s/.*=\(.*\)/ftype \1/" | cmd | sed "/=/!d"
С виду вроде обычная ассоциативная команда, если бы не одно но. Помимо стандартных протоколов в URL файле в качестве точки назначения может быть указан и локальный файл, причём это может быть как специально сформированный HTML, так и HTA или даже PE:
Учитывая же, что некоторых разработчиков программ хлебом не корми, но дай понапихать упаковочной плёнки в виде тех же URL файлов в конечный дистрибутив, поднапрячь свои булки всё же стоит, если не взять под пристальный контроль ассоциации. Так что:
ftype InternetShortcut=
И\или:
assoc .url=
Это снизит риски, но не устранит проблемы полностью. Если вы подумали, что всё же можно будет вызвать URL файл из командной строки так:
rundll32 ieframe.dll,OpenURL <путь до URL файла>
можете запахнуть халат, ибо подобный эксгибиционизм отлавливается даже Windows Defender. Так почему же проблема не будет устранена полностью?
С одной стороны, ничто не помешает восстановить ассоциативные связи. С другой, можно вполне обойтись и без ассоциаций. ieframe.dll — это COM (явлющийся к тому же форвардом для shdocvw.dll, поэтому их интерфейсы аналогичны). Глянув содержимое ieframe.dll в OLEView, найдём весьма живописное полотно кисти анонимного танцовщика кода.