Всем привет! В продолжении публикации о возможностях PowerShell, упомянул, что выделю в отдельную статью использование библиотеки Selenium с упомянутым языком. Этот небольшой гайд также может подойти для понимания, что из себя представляет данная библиотека и общее представление, как с ней работать, т.к. не зависимо от выбранного вами языка, принцип работы с Selenium одинаковый. Сразу отвечу на вопрос для тех, кто не знает, что это за библиотека или кому она может понадобиться. Selenium в первую очередь инструмент для функционального тестирования, это когда нужно проделать ряд действий имитируя реального пользователя и убедиться, что функционал Web-приложения работает исправно или неисправно. Реже используется для автоматизации различных задач в браузере (вызов JavaScript функций по средствам нажатий кнопок, заполнение форм и т.п.), для которых не предусмотрено API, а в некоторых случаях может выступать более удобной и полноценной альтернативой. Работая системным администратором, мне было удобно автоматизировать действия в панелях управления различных сервисах, или собирать специфические метрики с отправкой в базу данных. Selenium даже может входить в список инструментов DevOps-инженера. На мой взгляд, инструмент очень интересный с точки зрения творческого подхода к решению различных задач.
Постараюсь разложить все по полочкам, от установки всех зависимостей до примера работы с данным инструментом, также продемонстрирую альтернативный инструмент, который использовал до знакомства с Selenium. Специально для статьи подготовил модуль, который позволяет общаться с бесплатной версией ChatGPT из консоли PowerShell, который вы можете установить, используя всего две команды, а так же покажу, как просто создать такой модуль. Хочу заметить, что осознанно выделяю данную статью в средний уровень сложности Habr, по итогам ознакомления, для людей базово знакомых с PowerShell (для этого у меня есть отдельная работа с заметками), порог вхождения будет минимален. На просторах интернета не так много информации об использовании Selenium с языком PowerShell, я же узнал о данном инструменте из этой статьи, к слову, на этом ресурсе много полезного подчеркнул для себя в процессе изучения PowerShell, но несколько важных нюансов для построения собственных модулей там не было раскрыто. Также ключевой проблемой являлась установка всех зависимостей актуальной версии для дальнейшего масштабирования решений с использованием данной библиотеки, стоит упомянуть модуль selenium-powershell на GitHub, который не поддерживается с 2019 года.
Что требуется для работы:
Браузер. Вариантом несколько: Internet Explorer, Google Chrome, Mozilla Firefox. Важным моментом для меня было использовать конкретный браузер, базирующийся на Chrome.
ChromeDriver. Данный драйвер нужен для возможности Selenium управлять браузером (драйвер может быть другой, в зависимости от выбранного вами браузера). Важным моментом (и изначальной проблемой) является соответствие версии драйвера и текущей версии установленного браузера. За несколько месяцев использования я заметил тенденцию, что версия Google Chrome всегда опережает Chrome Driver на порядок релизов, из-за этого использовать драйвер с текущей версией установленного вами браузера не получится, т.к. он обновляется автоматически в целях поддержания безопасности. В поисках возможности автоматизировать данный процесс, где для сначала нужно удалить браузер из системы (тут вариантом несколько, через WMI/CIM или запускать деинсталлятор в тихом режиме) а потом устанавливать конкретную версию. Удобнее всего управлять данным процессом через менеджер пакетов, например, NuGet, Chocolatey, WinGet или Scoop. Изначально я пошел по этому пути, но тут возникали проблемы, браузер мог самостоятельно обновиться несмотря на различные запреты, а иногда вовсе отсутствовала возможность установки подходящей версии, со временем натыкаясь на различные ошибки в работе, к тому же, этот подход не позволял обновлять сразу все драйверы и приходилось производить много ручных действий. Спустя время меня посетила идея использовать Chromium, после чего весь процесс развертывания получилось очень сильно упростить и никаких проблем уже не возникало, так как у браузера имеется портативная версия. Самое приятное, Chromium имеет открытый исходный код и разрабатывается сообществом, что позволяет использовать такое решение в организации на территории РФ по сей день.
WebDriver. Драйвер Selenium. Так как для работы с драйвером мы используем язык PowerShell, который в свою очередь базируется на платформе .NET, то нам нужна версия для C# (всего вариантов несколько, поддерживаются такие языки, как Python, Java, JavaScript и Ruby). Также присутствует библиотека WebDriver.Support, которая нужна для обработки реже используемых действий.
Процесс установки и обновления вышеперечисленного у меня получилось автоматизировать. Если кратко, то для быстрого развертывания всех зависимостей достаточно воспользоваться одной командой в терминале, которая в свою очередь считает из репозитория GitHub PowerShell скрипт и запустит его в вашей системе:
Invoke-Expression(New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/Lifailon/Deploy-Selenium/rsa/Deploy-Selenium-Drivers.ps1")Данный скрипт установит по пути “домашняя директория пользователя/Документы/Selenium” портативную версию браузера Chromium, chromedriver.exe, WebDriver.dll и WebDriver.Support.dll актуальных версий на текущий момент, а при повторно запуске, обновит все файлы.
Для начала работы определимся с шаблоном, который будем использовать при написании любого скрипта в дальнейшем. В начале необходимо загрузить установленные ранее зависимости:
$path = "$home\Documents\Selenium\"
$log = "$path\ChromeDriver.log"
$ChromeDriver = "$path\ChromeDriver.exe"
$WebDriver = "$path\WebDriver.dll"
$SupportDriver = "$path\WebDriver.Support.dll"
$Chromium = (Get-ChildItem $path -Recurse | Where-Object Name -like chrome.exe).FullName
Add-Type -Path $WebDriver
Add-Type -Path $SupportDrivertry { $ChromeOptions = New-Object OpenQA.Selenium.Chrome.ChromeOptions # создаем объект с настройками запуска браузера $ChromeOptions.BinaryLocation = $Chromium # передаем путь до исполняемого файла, который отвечает за запуск браузера $ChromeOptions.AddArgument("start-maximized") # добавляем аргумент, который позволяет запустить браузер на весь экран $ChromeOptions.AcceptInsecureCertificates = $True # игнорировать предупреждение на сайтах с не валидным сертификатом #$ChromeOptions.AddArgument("headless") # скрывать окно браузера при запуске $ChromeDriverService = [OpenQA.Selenium.Chrome.ChromeDriverService]::CreateDefaultService($ChromeDriver) # создаем объект настроек службы драйвера $ChromeDriverService.HideCommandPromptWindow = $True # отключаем весь вывод логирования драйвера в консоль (этот вывод нельзя перенаправить) $ChromeDriverService.LogPath = $log # указать путь до файла с журналом $ChromeDriverService.EnableAppendLog = $True # не перезаписывать журнал при каждом новом запуске #$ChromeDriverService.EnableVerboseLogging = $True # кроме INFO и ошибок, записывать DEBUG сообщения $Selenium = New-Object OpenQA.Selenium.Chrome.ChromeDriver($ChromeDriverService, $ChromeOptions) # инициализируем запуск с указанными настройками
# Далее следует код для обработки действий в браузере
}finally { $Selenium.Close() $Selenium.Quit()
}Теперь определяемся, что мы хотим выполнить в браузере. Для примера, поставим задачу, где мы откроем онлайн калькулятор и посчитаем сумму двух чисел, а полученный результат выведем на экран консоли. Работа с Selenium всегда начинается с перехода по нужной нам ссылке (url), откуда будем начинать выполнять наши действия, для этого используем дочерний метод навигации – GoToUrl:
$Selenium.Navigate().GoToUrl("https://google.com")Если в опциях запуска браузера мы не используем аргумент headless (достаточно его закомментировать), что удобно при отладке (мы можем наблюдать все выполняемые нами действия в окне браузера или наоборот), то в браузере мы увидим, как перейдем по указанной нами ссылке, в нашем случае поисковика Google. Далее нужно передать текст для поиска, например так: “calculator online”. Для этого нужно найти элемент, который отвечает за ввод текста.
Поиск элементов является ключевым моментом при работе с данным инструментом, этот алгоритм аналогичен для всех дальнейших действий. Можно использовать два способа:
1. DevTools – это встроенный набор инструментов Web-разработчиков и тестировщиков. В своем браузере (для удобства в отдельном окне, например, Google Chrome) переходим по нужной нам ссылки и запускаем данный инструмент используя клавишу F12 (или правой кнопкой мыши на странице – Просмотреть код), где нам нужна первая вкладка – «Элементы» (еще иногда может быть полезна вкладки Сеть, что бы отслеживать образующиеся запросы во время взаимодействия с приложением). Универсальным способом будет использовать комбинацию Ctrl+Shift+C, далее используя курсор мыши наводим на нужный нам элемент, в нашем случае, поисковой строки:

Что нас тут может интересовать:
textarea – это элемент управления (он же Tag), который предоставляет пользователю возможность вводить несколько строк текста.
jsname=”yZiJbe” – это атрибут, который указывает на используемый JavaScript-код для данного элемента. В нашем случае может использоваться для поиска через метод
CssSelector.id=”#APjFqb” – это уникальный идентификатор элемента – селектор (selector), который можно скопировать правой кнопкой мыши, и использоваться для обращения к этому элементу из JavaScript, CSS, а также в нашем случае из PowerShell. Альтернативным вариантом является XPath, который также можно использовать для обращения к элементу.
class=”gLFyf” — атрибут, который определяет класс элемента, который можно использовать для поиска через
ClassName.name=”q” — атрибут, определяющий имя элемента, которое будет отправлено на сервер при отправке формы, его можно использовать для обращения к элементу по имени.
maxlength=”2048″ — атрибут, указывающий на максимальное количество символов, которые пользователь может ввести в данном поле.
rows=”1″ — атрибут, который определяет количество строк текстового поля ввода.
aria-label=”Найти” — лейбл или этикетка, который соответствует свойству объекта
ComputedAccessibleLabelи может быть полезен при фильтрации элементов, используя методFindElements.role=”combobox” — роль элемента, соответствует свойству объекта
ComputedAccessibleRole.
Исходя из полученных данных, можно составить несколько запросов, которые будут выполнять одинаковое действие, т.е. искать нужный нам элемент с строкой для ввода текста.
Проще всего обращаться к таких элементам по его
Id:
$Selenium.FindElements([OpenQA.Selenium.By]::Id('APjFqb'))Если скопировали
XPath:
$Selenium.FindElements([OpenQA.Selenium.By]::XPath('//*[@id="APjFqb"]'))Или по имени элемента:
$Selenium.FindElements([OpenQA.Selenium.By]::Name('q'))В формате XPath, аналогичный запрос будет выглядеть следующим образом (используя соответствующий метод):
$Selenium.FindElements([OpenQA.Selenium.By]::XPath('//*[@name="q"]'))Используя имя класса:
$Selenium.FindElements([OpenQA.Selenium.By]::ClassName('gLFyf'))Используя
jsnameдля CSS селектора:
$Selenium.FindElements([OpenQA.Selenium.By]::CssSelector('[jsname="yZiJbe"]'))2. Второй вариант, если вы не хотите пользоваться браузером для поиска элементом (мне иногда так было удобнее), а также если у элемента нет уникальных данных (когда в DevTools мы можем увидеть только название тэга, такое будет в примере с ChatGPT ниже) для обращения к нему или они могут меняться, в таком случае можно использовать тот же метод FindElements через PowerShell и искать по имени тэга (TagName):

При таком поиске мы можем получить несколько элементов (практически всегда их несколько), т.к. имя тэга не уникально и понадобится дополнительная фильтрация, тут нам могут помочь упомянутые выше свойства объектов ComputedAccessibleLabel и ComputedAccessibleRole, а также Text. Такой подход может занимать продолжительное время при большом количестве элементов. В нашем случае все просто, мы уже знаем нужный нам элемент, его роль combobox:
$Selenium.FindElements([OpenQA.Selenium.By]::TagName('textarea')) | Where-Object ComputedAccessibleRole -eq comboboxЕще мы знаем, что значение Lable не является пустым, и даже если бы мы этого не знали, элемента всего два, не сложно догадаться, который из них нам нужен (или просто предварительно проверить оба).
Есть множество популярных тегов, которые используются для работы с CSS и DOM (Document Object Model), и в нашем случае могут быть полезны для поиска элементов. Такие тэги и их описание не сложно найти в интернете, перечислю некоторые из них, которые использовал в данной статье:
textarea – используется для создания многострочного поля ввода текста;
input – используется для добавления различных элементов ввода, таких как текстовые поля, флажки, радиокнопки и т.п.;
div – используется для создания блочного контейнера на веб-странице, который позволяет группировать другие элементы;
span – также используется для группировки элементов, но в отличие от
divобычно не создает перенос строки и отображается в строке;button – используется для создания кнопок.
Как только мы нашли элемент, помещаем его в переменную, (в нашем случае $Search), чтобы взаимодействовать с ним на прямую. Для передачи текста, используем метод SendKeys:
$Search.SendKeys("calculator online")Теперь, чтобы не повторять поиск элемента с кнопкой поиска, просто используем привычный многим в браузере метод Enter (мы уже выяснили, что данный элемент не поддерживает несколько строк: rows=1):
$Search.SendKeys([OpenQA.Selenium.Keys]::Enter)На данном этапе мы выполнили переход на новый url, где получаем содержимое страницы с результатом поиска. В нашем случае, калькулятор уже находится на странице, специально для примера используем второй подход, где вначале находим все элементы с тэгом div, которые отвечают за нажатие, фильтруем вывод по роли (ComputedAccessibleRole) – Button и лейблу (ComputedAccessibleLabel, также можно использовать свойство Text) – 2. После чего производим два нажатия, используя метод Click(). Выглядит это так:
Start-Sleep 1
$div = $Selenium.FindElements([OpenQA.Selenium.By]::TagName("div"))
$2 = $div | Where-Object {($_.ComputedAccessibleRole -like "button") -and ($_.ComputedAccessibleLabel -like "2")}
$2.Click()
$2.Click()Мы нашли цифру 2, и нажали на нее два раза. Далее находим элемент, отвечающий за сложение. У данного элемента свойство Lable имеет содержимое «сложение», которое отличается от Text, где содержимым является «+», после чего нажимаем на искомый элемент:
$plus = $div | Where-Object {($_.ComputedAccessibleRole -eq "button") -and ($_.Text -eq "+")}
$plus.Click()К остальным элементам обратимся по jsname (которые мы предварительно находим через DevTools). Теперь, нам остается забрать полученный результат, чтобы вывести его в консоль. Для этого достаточно обратиться к нужному элементу и получить значение его свойства Text.
$3 = $Selenium.FindElement([OpenQA.Selenium.By]::CssSelector('[jsname="KN1kY"]'))
$3.Click()
$3.Click()
$sum = $Selenium.FindElement([OpenQA.Selenium.By]::CssSelector('[jsname="Pt8tGc"]'))
$sum.Click()
$result = $Selenium.FindElement([OpenQA.Selenium.By]::CssSelector('[jsname="VssY5c"]')).Text
Write-Host "Result: $result" -ForegroundColor GreenОбратите внимание, как быстро происходит обращение к элементам на прямую. При фильтрации имеющихся 1092 элементов (в примере) с тэгом div, для поиска одного элемента уходит порядка 3-4 секунд, что ощутимо дольше и нецелесообразно для использования в конечном скрипте:

Пример целиком опубликован на GitHub.
Для второго случая продемонстрирую пример с ChatGPT. Это альтернатива, т.к. для подобных сервисов (обобщаю в примере с другими модулями) присутствует API, но иногда невозможно получить такой токен бесплатно, а ввиду ограничений в нашей стране даже приобрести напрямую за деньги, что послужило для меня отправной точкой создания подобных модулей. Цель простая, общаться с ИИ используя только консоль PowerShell. Еще, это может оказаться полезным, если вы хотите внедрить такое решение в свой скрипт для генерации ответов (например, произвести парсинг динамических данных) или даже части кода (зависит от задач и потребностей, тенденция растет с каждым днем). И тут действительно все очень просто, нам нужен любой бесплатный сервис, который желательно не требует авторизации, после чего найти элемент, который отвечает за ввод текста и передать в него параметр $Text с нашим запросом (он и будет использоваться параметром в модуле для задаваемых нами вопросов), после чего дождаться ответа и получить результат. Вот пример для вышеупомянутого шаблона:
$Selenium.Navigate().GoToUrl("$url")
$Search = $Selenium.FindElements([OpenQA.Selenium.By]::TagName('textarea')) | Where-Object ComputedAccessibleRole -eq textbox
$Search.SendKeys("$Text")
$Search.SendKeys([OpenQA.Selenium.Keys]::Enter)
while ($true) { if ($($Selenium.FindElements([OpenQA.Selenium.By]::TagName('button')).Text) -eq "Clear") { $Result = $Selenium.FindElements([OpenQA.Selenium.By]::TagName('span')) return $($Result[-2].Text) break }
}Важным моментом является получение конечного результата ответа на наш вопрос, т.к. ChatGPT не отвечает сразу, а постепенно генерирует текст на экране. Нам всегда надо за что-то зацепиться, для проверки, что ответ был получен полностью, только после этого прочитать его. В примере я использую содержимое свойства кнопки – Text, когда оно имеет значение Clear, можно производить новый запрос, соответственно ответ на предыдущий запрос уже был получен. Но это всегда индивидуально, в нашем случае можно было считать кол-во элементов c тэгом div, его значение вырастает на 7 после каждого полученного ответа. Пример работы с таким модулем выглядит так:

Если вы уже установили зависимости, то для установки модуля Get-GPT из репозитория GitHub можете воспользоваться следующей командой:
Invoke-RestMethod https://raw.githubusercontent.com/Lifailon/Selenium-Modules/rsa/Modules/Get-GPT/Get-GPT.psm1 | Out-File -FilePath "$(New-Item -Path "$($($Env:PSModulePath -split ";")[0])\Get-GPT" -ItemType Directory -Force)\Get-GPT.psm1" -ForceПо тому же принципу можно написать модуль, который позволят производить запросы для перевода текста. К слову, я уже писал автоматизированный модуль для перевода текста в консоли с использованием бесплатного публичного API для Google Translate и эмулятора DeepLX, для меня это самый удобный способ, который я использую ежедневно. Планирую написать модуль для bash и отдельную статью, т.к. на мой взгляд такой простое решение может оказаться полезно и другим.
Приведу еще один пример, у меня была задача получать значения измерения скорости интернета от провайдера, используя публичные сервисы, такие как LibreSpeed, OpenSpeedTest и Ookla SpeedTest. Во всех случаях достаточно перейти на нужный url сервиса, нажать кнопку измерения, по завершению получить результат – метрики измерений, и заполнить ими объект System.Collections.Generic.List.

В большинстве случаев, когда мы хотим получить результат работы, заранее необходимо найти элемент, в котором эти данные будут нам доступны и зафиксировать его в переменной. В дальнейшем, по результатам проделанных нами действий, мы добавляем в бесконечный цикл найденный ранее элемент и сравниваем его значение с текущим значение этого же элемента, тем самым убеждаясь, что данные обновлены, после чего забираем результат и завершаем цикл. Тот же принцип, если мы ожидаем, что по результату текущий url обновится (т.е. мы перейдем на другую страницу), в таком случае проверяем его. Вот пример:
$Url = "https://www.speedtest.net/"
$Selenium.Navigate().GoToUrl($Url)
Start-Sleep 1
$UrlTemp = $Selenium.Url
$span = $Selenium.FindElements([OpenQA.Selenium.By]::TagName("span"))
$Button = $span | Where-Object Text -Match "GO"
$Button.Click()
while ($True) { if ($Selenium.Url -ne $UrlTemp) { $UrlResult = $Selenium.Url break }
}
$Cont = Invoke-RestMethod $UrlResultВ примере с SpeedTest, если из полученного url нам нужно получить данные всей страницы, то можем просто прочитать его содержимое, используя Invoke-RestMethod (аналог клиента Curl в Windows). Нужные нам значения можно получить по средствам парсинга HTML-страницы, в некоторых случаях можно попытаться вытащить кусок JSON, который PowerShell сразу преобразует в объект и его достаточно только отфильтровать или пересобрать, что очень сильно упрощает процесс:
$Data = ($Cont -split "window.OOKLA.")[3] -replace "(.+ = )|(;)" | ConvertFrom-Json
return $Data.resultИспользуя модуль Get-SpeedTest, можно прямо в консоли получать результаты измерений, которые в свою очередь возможно настроить на отправку в базу данных временных рядов, например, InfluxDB и отображать в виде графиков в Grafana:

Работу (Ookla-SpeedTest-API) с отправкой метрик измерений скорости интернета я делал еще в Internet Explorer c использованием COM (Component Object Model) интерфейса. Это устаревший вариант, который можно использовать как альтернативу Selenium. Принцип работы у него точно такой же, при этом никаких зависимостей не требуется и работает по сей день. Тем не менее, если станет интересно, я оставлял заметки на тему работы с IE, а также с InfluxDB. Планирую (как только подготовлю тестовый стенд), написать отдельную статью по работе с InfluxDB, используя PowerShell или Bash и настройки графиков в Grafana.
По итогу, если взять за основу представленный выше шаблон и ознакомиться с примерами, можно автоматизировать выполнение процессов в Web-приложениях и даже добавлять такие решения в свои Pipeline.
| Введение | |
| Похожие статьи |
Введение
Вам нужно посмотреть только конец файла по аналогии с tail в
Linux можно использовать Get-Content флагом -Tail.
Например, чтобы получить последние 100 строк файла
.log
Get-Content -Path “C:\logs\.log” -Tail 100
Если лог нужно смотреть в реальном времени – используйте флаг -Wait
Get-Content -Path “C:\logs\.log” -Wait
Можно совместить -Wait и -Tail и мониторить только последние строки в реальном времени
Get-Content -Path “C:\logs\.log” -Wait -Tail
Перезагрузить компьютер
Допустим, что имя компьютера, который вы хотите перезагрузить DESKTOP-OP12345
Restart-Computer -ComputerName DESKTOP-OP12345
| Windows | |
| PowerShell | |
| Установка | |
| Alias | |
| Функции | |
| Сеть в PowerShell | |
| Работа с пользователями в PowerShell | |
| Get-Content -Tail: Посмотреть конец файла в PowerShell (аналог tail) | |
| New-Item: Создать новый файл в PowerShell (аналог touch) | |
| Get-FileHash: Проверить контрольную сумму файла в PowerShell (аналог md5sum) | |
| Запросы к REST API на PowerShell |
Конец рекламы от Яндекса. Если в блоке пусто считайте это рекламой
моей телеги
Всем привет! Порой, написать графическую форму для консольного приложения может оказаться очень удобным решением, тем самым не нужно запоминать все ключи программы, особенно, если пользоваться им приходится изредка, тем самым автоматизируя работу с данным приложением в дальнейшем. Но, ситуация может быть обратной, когда приложение имеет только графический интерфейс, а вам нужно получить вывод его работы в консоли, например, для возможности передачи метрик в систему мониторинга. С тех пор как начал проводить все больше времени в консоли, заметил, что становится менее удобно переключаться на ранее привычные инструменты, лишний раз использовать мышь, держать открытыми излишние приложения или вкладки в браузере, особенно, если работаешь на удаленной машине без прямого доступа к графическому интерфейсу. У меня накопилась небольшая коллекция полезных модулей, большинство из которых написаны совсем недавно, успел привыкнуть при регулярном использовании и хотелось бы ими поделиться. Осознавая, что тенденция ухода Windows систем на территории РФ растет, тем не менее думаю еще очень много людей, кто так же как и я продолжают использовать данную систему и автоматизировать свою работу, возможно, представленные модули так же смогут пригодятся. Все модули опубликованы в репозитории на GitHub и менеджере пакетов Nuget, откуда их можно установить одной командой.
PowerShell модуль представляет собой набор функций, которых объединяет между собой файл с расширением psm1 и манифест psd1 (последний не обязателен для работы модуля, нужен для его описания). Модули используют для взаимодействия с приложением или целой системой (например, система хранения TrueNAS, резервного копирования Veeam, виртуализации VMWare или Hyper-V, различными системами баз данных и т.п.), с возможностью повторного применения описанных в нем функций на уровне системы и его массового распространения через менеджеров пакетов. Еще модуль можно воспринимать как cli (интерфейс командной строки) для конкретного приложения, тем самым позволяя взаимодействовать с ним оперируя параметрами в консоли, при этом имея возможность для дальнейшей автоматизации или интеграции с другими сервисами напрямую через язык PowerShell. Например, команда для вывода содержимого файлов в консоли Get-Content, или более привычный для Linux систем псевдоним cat по факту представляет PowerShell функцию, базирующуюся на .NET, которая в свою очередь входит в состав модуля Microsoft.PowerShell.Management.
Console-Translate
На протяжении нескольких лет я пользуюсь переводчиком DeepL практически на ежедневной основе. Меня не всегда устраивает то, что у него есть ограничение в 1500 символов, тем не менее, так как у него есть полноценное десктопное приложение, это удобная альтернатива браузерным решениям, которое всегда под рукой на горячей клавише. Сменив место работы, и получив ограничение в самостоятельной установке какого-либо стороннего программного обеспечения на рабочем ноутбуке, пришлось задуматься в сторону альтернативного и простого решения, так как пользоваться переводчиком и при этом консолью я реже не стал, пришла идея использовать единый интерфейс. Для доступа к переводу текста в консоли можно использовать REST API, к сожалению, получить бесплатный ключ доступа DeepL для России невозможно, но тут можно найти много альтернатив. Во-первых, существует проект DeepLX с открытым исходным кодом, с помощью которого можно запустить свой бесплатный API-сервер, который может быть доступен одновременно нескольким пользователям в сети. Во-вторых, каждый, кто использует расширение Google Translate в своем браузере может перехватить публичный API-ключ (используя интерфейс DevTools во вкладке Network) с возможностью его использования через любой REST-клиент в консоли. И в-третьих, существует немало бесплатных провайдеров для перевода текста с наличием API, например MyMemory, которая содержит одну из крупнейших баз для переводов. Все перечисленные сервисы получилось внедрить в один модуль Console-Translate, который можно установить в своей консоли с помощью одной команды:
Install-Module Console-Translate -Repository NuGetНеобходимо, чтобы предварительно у вас в системе уже был зарегистрирован менеджер пакетов Nuget:
Register-PSRepository -Name "NuGet" -SourceLocation "https://www.nuget.org/api/v2" -InstallationPolicy TrustedСинтаксис простой, в первый параметр передается текст (если вы используете более одного слова, обязательно необходимо заключить весь передаваемый текст в кавычки), второй (через пробел) отвечает на язык назначения, например так:
> Get-Translate "Как дела?"
How are you?
> Get-Translate "Как дела?" de
Wie geht es Ihnen?По умолчанию перевод происходит между Русским и Английским языком в обоих направлениях, с автоматически определением языка на уровне PowerShell. Т.к. на уровне API не всегда хорошо срабатывает определение языка, добавил достаточно простую реализацию, так как акцент сделан на двух языках, каждый раз происходит подсчет переданных букв с разбивкой (методом Char) на русские и английские символы, букв какого из языков окажется больше, тот и будет являться исходным языком, и соответственно второй будет являться языком назначения (пример на скриншоте ниже).

С появления версии PowerShell Core данный язык является кроссплатформенным, по этой причине модуль будет работать в системе Linux, где я так же часто его использую, как и сам язык в силу привычки.
CrystalDiskInfo
У программы CrystalDiskInfo нет командного интерфейса для прямого взаимодействия через консоль, есть возможность только сформировать файловый отчет, где содержится много лишней информации в текстовом виде. Помимо этого отчета, программа так же хранит информацию в конфигурационных ini-файлах, которые обновляются в процессе сканирования или изменения настроек. Модуль CrystalDisk-Cli читает эти конфигурационные файлы и выводит результат в формате OSObject или Collection (необходимо, что бы программа CrystalDiskInfo уже была установлена). Вывод работы модуля будет выглядеть так:
Установить модуль CrystalDisk-Cli можно также одной командой:
> Install-Module CrystalDisk-Cli -Repository NuGet
> Import-Module CrystalDisk-Cli
> Get-DiskInfo
Name : WD PC SN740 SDDPNQD-1T00-10272243A5454811
Date : 2024/02/19 11:16:48
HealthStatus : 1
Temperature : 48
PowerOnHours : 1010
PowerOnCount : 448
Life : 100
HostWrites : 10322
HostReads : 10092
01 : 0
02 : 0
03 : 0
04 : 0
05 : 0
ReallocatedSectorsCount : 0
06 : 0
07 : 0
08 : 0
09 : 0
0A : 0
0B : 0
0C : 0
0D : 0
0E : 0
0F : 0Если необходимо обновить информацию и получить актуальный отчет, используется параметр Report (если консоль не запущена с правами администратора, при запуске появится окно, которое запросит подтверждение). Само приложение производит автоматическое обновление с заданным промежутком времени, которое можно изменить в настройках программы, например каждые 5 минут, используя команду: Get-DiskInfoSettings -AutoRefresh 5 (при запуске без параметров вернет текущие настройки, для изменения настроек понадобится запустить консоль с правами администратора). Вот пример вывода для нескольких дисков:

Everything
Install-Module PSEverything -Repository NuGet
Find-Everything ".temp" -ComputerName plex-01 -Port 9999 -User every -Password thing # удаленное получение данных
Find-Everything ".temp" # локальное получение данных
$(Find-Everything ".temp").Count # посчитать количество файлов, подходящих под критерии поиска
Программа не содержит открытый исходный код, перед написанием модуля я ознакомился с правами лицензионного соглашения, которые крайне лояльны, и дают возможность интегрировать данное приложение для своих целей. Мне данный модуль очень мог автоматизировать поиск файлов для нескольких несложных скриптов, что было бы сложнее реализовать средствами PowerShell, не говоря про скорость работы, которая чаще не превышает 200мс (повышенная задержка при большом количестве найденных файлов вызвана не программой, а самим языком при обработке получаемых данных).
SpeedTest
У меня как-то была задача, реализовать мониторинг скорости интернета получаемую от провайдера на регулярной основе. Для примера, можно воспользоваться всеми известным Speedtest от Ookla, у данного сервиса уже присутствует cli-интерфейс, вывод которой можно распарсить, но это не единственный провайдер для предоставления подобный услуги и требует зависимость в виде исполнимого файла. В случае c встроенным Windows PowerShell версии 5.1 есть возможность использовать Internet Explorer через COM интерфейс, тем самым в браузере автоматизировать нажатие кнопок в фоновом режиме и забирать содержимое страницы прямо в консоль, для дальнейшей обработки и вывода в формате объекта, как это реализовано в модуле Ookla-SpeedTest-API. Вот пример:
Get-PackageProvider # проверяем, что провайдер пакетов nuget установлен
Find-PackageProvider # отобразить все допступные менеджеры пакетов
Install-PackageProvider nuget # установить менеджер пакетов nuget
Set-PackageSource nuget -Trusted # разрешаем установки пакетов из указанного источника
Find-Package Ookla-SpeedTest # ищем пакеты по названию во всех менеджерах
Install-Module Ookla-SpeedTest -Scope CurrentUser # установить модуль для текущего пользователя
### Запускаем модуль и забираем метрики
$test = Invoke-SpeedTest
$test | Select-Object date,download,upload
date download upload
---- -------- ------
19.02.2024 14:00:15 37263 19320
Используя такой модуль, можно настроить отправку метрик в базу данных и вывести данные на dashboard Grafana (такой пример с созданием службы есть на GitHub). Хотя данный подход уже является устаревшим, он не требует никаких зависимостей, но при этом не поддерживается в версии PowerShell Core. Для подобных целей правильнее использовать библиотеку Selenium (версии dotNET), например через браузер Chrome/Chromium, подробнее про установку зависимостей и создание модулей я уже писал пост на Habr. Вот пример вывода на примере OpenSpeedTest и LibreSpeedTest:

Сервер и клиент Syslog
Маловероятно, что вам понадобится запустить сервер для сбора логов на системе Windows, при условии, что чаще для этих целей используют сервера на базе Linux, к тому же имеется достаточно большое количество отличных альтернатив, например Visual Syslog. Но если у вас есть запрет на запуск какого-либо стороннего программного обеспечения на системах Windows (что в моем случае и послужило причиной) или например PowerShell скрипт, события работы которого необходимо настроить для передачи серверу Syslog, данный процесс можно автоматизировать с помощью модуля pSyslog. Для установки и запуска серверной части используйте следующие команды:
Install-Module pSyslog -Scope CurrentUser
Start-pSyslog -Port 514
Get-pSyslog # читает входящие сообщения в реальном времени
Show-pSyslog # читает локальный файловый журнал
Для отправки сообщения на любой сервер Syslog, используйте команду Send-pSyslog:

Серверная и клиентская часть базируются на классе .NET System.Net.Sockets, все источники документации и примеры работы есть в описании репозитория. Модуль поддерживает шифрование Base64, UDP Relay и ротацию локального журнала, который возможно настроить для получения метрик, например, по типу сообщения или содержимому. Протестировано в работе для версии Windows PowerShell на разных билдах до 3-х одновременных клиентов, также работает в версии Core.
Windows API
Модуль ps.win.api – это полноценный REST API и Web сервер на чистом PowerShell, серверная часть которого базируется на классе .NET HttpListener. Про то, как создать такой сервер я уже писал статью на Habr, с тех пор прошло не так много времени, тем не менее функционала стало больше, в том числе добавлен модуль, который позволяет запускать серверную часть в режиме фонового процесса и управлять им, а также он включает в себя большую часть используемых функций с возможностью удаленного взаимодействия с сервером для каждой команды, вывод которых будет одинаковый как для локальной, так и для удаленной машины. Все функции представляют из себя дополненный и более читаемый вывод уже встроенных WMI/CIM команд, результат которых можно получить с удаленный машины через данный модуль в PowerShell, или любой REST-клиент, например curl в Linux, без необходимости конфигурации WinRM или ssh.
Устанавливаем модуль и запускаем серверную часть на одной машине:
Install-Module ps.win.api -Repository NuGet -AllowClobber
Import-Module ps.win.api
Start-WinAPI
Test-WinAPI
Port Status
---- ------
8443 OpenНа удаленной машине предварительно устанавливаем модуль и используем функцию, например, для удаленного и локального просмотра датчиков температуры дисков:
Get-Smart
Get-Smart -ComputerName 192.168.3.100 -User rest -Pass api -Port 8443
Примеры работы и настройки можно найти в репозитории на GitHub. Также помимо запуска и остановки служб и процессов, добавлен функционал просмотра всех журналов событий Windows через Web-интерфейс с возможностью фильтрации вывода, пример для ssh подключений на скриншоте:

Get-Query
В системе Windows для просмотра в консоли списка текущих авторизованных пользователей, а также запущенных ими процессов присутствует встроенная программа query.exe, которая отдает вывод в текстовом формате. Модуль Get-Query преобразуя вывод команды в формат объекта, что позволяет использовать его для мониторинга активных пользовательских сессий, например, через активного Zabbix-агента, а также с помощью такого модуля (или любого другого подобного модуля в формате PSObject) можно заполнить таблицу DataGridView используемую в Windows Forms, данный подход я использовал в проекте RSA. Пример вывода для одного пользователя:
Install-Module Get-Query
Get-Query
User : lifailon
Session : console
ID : 1
Status : Active
IdleTime : отсутствует
LogonTime : 12.02.2024 13:08Итог
По мимо перечисленных модулей, присутствуют модули на мониторинга Veeam репозиториев и заданий, а так же датчиков температуры системы через Open и LibreHardwareMonitor, статью про последний я также писал на Habr, где упоминал про кастомизацию терминала, используя профили для oh-my-posh. Всего модулей в различных репозитория огромное множество, менеджер Nuget насчитывает больше 392 тысяч пакетов, 30 тысяч из которых составляют модули для PowerShell и библиотеки, которые могут быть интегрированы через платформу .NET. Использование удобных именно для вас модулей заставляет меньше покидать терминал, а времяпровождение в консоли приносит все больше удовольствия, и как мне кажется, формирует полезную привычку в дальнейшем.



