Притворяемся что пишем на C#, но только на Powershell

от автора


Powershell — удобная API построенная на .net. Powershell позволяет пользователям писать скрипты, не упираясь в программирование, при этом получая схожие результаты. Что происходит на КДВП, автор объяснит позже по тексту. Сейчас нам срочно нужно притвориться, что мы программируем на C#.

TL;DR: Postman не нужен, если есть Powershell. Но сперва нужно зайти издалека.

Делаем простой класс

Автор слышал, что крутые программисты делают все через классы и их методы.
Так как PowerShell это позволяет, давайте автор покажет, как можно сложить 1 + 1 притворившись, что мы программируем.

class ClassName {       [string] Sum ($A, $B) {                 $Result = $A + $B         return $Result     } } 

Вот наш класс ClassName и его метод Sum. Экземпляр класса можно вызвать ровно так же, как в настоящих языках программирования.

$NewClass = [ClassName]::new() $NewClass.Sum(1, 1)

Создаем новый экземпляр класса и вызываем метод, всё просто.

Есть ли Void в Powershell

При написании сложных скриптов этот же вопрос вставал у автора. Как сделать функцию, которая будет Void?

Говорят, что можно сделать так:

Get-Date | Out-Null

Однако, | Out-Null так же глушит весь Verbose, ErrorAction и не работает с Invoke-Command.

Если вам нужна функция с [Void] – делайте новый класс, другого выхода нет.

class ClassName {       #Конструктов класса     [void] Start () {         #Создаем экземпляр класса прямо внутри этого же класса.         $q = [ClassName]::new()         $q.GetDate()     }       #Своего рода метод внутри класса     [void] GetDate () {         #А вот тут вызываем еще один метод из .Net 	  #Просто так, потому что можем         $Result = [DateTime]::UtcNow.ToString()         Write-Host $Result     } } 

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

Вот так мы добились того, что не заглушили Verbose, при этом сделали функцию с Void.

Список методов класса

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

Перечислить все методы интересующего класса можно так:

#Делаем любовь, а не класс $Love = [ClassName]::new()   #Выбираем члены интересующего нас класса и записываем в массив. foreach ($i in $Love | Get-Member -MemberType Method | Select-Object name) {     [array]$array += $i.Name }   #Вызываем члены класса, если нужно. $Array | ForEach-Object {     $Love.$_() } 

Отправляем HTTP запросы скриптом (оправдываем КДПВ)

Классами мы можем представлять данные и эти данные конвертировать в разные форматы. К примеру, нам нужно отправить POST запрос на веб сайт в формате JSON.

Сначала мы делаем модель данных и заполним данные в новый экземпляр.

#В качестве модели данных делаем новый класс class DataModel {     $Data     $TimeStamp }   #Создаем экземляр класса $i = [DataModel]::new()   #Заполняем данные $i.Data = "My Message in string" $i.TimeStamp = Get-Date 

Так выглядит экземпляр класса после заполнения:

PS C:\> $i   Data                 TimeStamp ----                 --------- My Message in string 30.07.2020 5:51:56

Потом этот экземпляр можно конвертировать в XML или JSON или даже SQL запрос. Остановимся на JSON:

#Конвертируем данные в JSON $Request = $i | ConvertTo-Json

Так выглядит JSON после его конвертации:

PS C:\> $Request {   "Data": "My Message in string",   "TimeStamp": "2020-07-30T05:51:56.6588729+03:00" } 

И отправляем:

#Отправляем JSON Invoke-WebRequest localhost -Body $Request -Method Post -UseBasicParsing

В случае если нужно отправлять один и тот же JSON файл 24/7, можно сохранить его как файл и отправлять уже из файла. К примеру, возьмем этот же самый $Request.

#Сохраняем данные конвертированные ранее в JSON в файл $Request | Set-Content C:\Users\User\Desktop\YourRequest.json   #Отправляем ранее сохраненный в файл JSON Invoke-WebRequest localhost -Body (Get-Content C:\Users\User\Desktop\YourRequest.json) -Method Post -UseBasicParsing

Получаем HTTP запросы скриптом (оправдываем КДПВ 2)

Автор терпеть не может Postman, зачем кому-либо нужен Postman, когда есть руки и PowerShell? (Автор предвзято относится к этой программе и его нелюбовь ничем не обоснована.)
Делать свою альтернативу мы будем это с помощью System.Net.HttpListener, то есть мы сейчас запустим настоящий веб сервер из скрипта.

#Создаем новый экземпляр класса $http = [System.Net.HttpListener]::new()   #Добавляем HTTP префиксы. Их может быть сколько угодно $http.Prefixes.Add("http:/localhost/") $http.Prefixes.Add("http://127.0.0.1/")   #Запускаем хттп листенер $http.Start()     $http.Close() 

Так проходит запуск класса.

Экземпляр класса был создан и его процесс запустился, мы можем слушать от него вывод. Вывод представлен как System.Net.HttpListener.GetContext. В это примере мы принимаем и конвертируем только POST запрос.

while ($http.IsListening) {       #GetContext нужен для получения сырых данных из HttpListener     $context = $http.GetContext()       #Определяем тип запроса с помощью Request.HttpMethod      if ($context.Request.HttpMethod -eq 'POST') {           #Читаем сырые данные из GetContext         #Для каждого отдельного запроса создаем свой конвейер         [System.IO.StreamReader]::new($context.Request.InputStream).ReadToEnd() | ForEach-Object {                          #С помощью System.Web.HttpUtility делаем urlDecore, иначе кириллица превращается в руны             $DecodedContent = [System.Web.HttpUtility]::UrlDecode($_)               #Конвертируем прилетевшие данные в нужный нам формат             $ConvertedForm = $DecodedContent | ConvertFrom-Json -ErrorAction SilentlyContinue               #Cконвертированные данные отображаем таблицой             $ConvertedForm | Format-Table                     }     } }  

Готовый скрипт

С помощью этого скрипта можно принимать запросы:

#Создаем новый экземпляр класса $http = [System.Net.HttpListener]::new()   #Добавляем HTTP префиксы. Их может быть сколько угодно $http.Prefixes.Add("http://localhost/") $http.Prefixes.Add("http://127.0.0.1/")    #Запускаем веб листенер $http.Start()   if ($http.IsListening) {     Write-Host "Скрипт запущен" }   while ($http.IsListening) {       #GetContext нужен для получения сырых данных из HttpListener     $context = $http.GetContext()       #Определяем тип запроса с помощью Request.HttpMethod      if ($context.Request.HttpMethod -eq 'POST') {           #Читаем сырые данные из GetContext         #Для каждого отдельного запроса создаем свой конвейер         [System.IO.StreamReader]::new($context.Request.InputStream).ReadToEnd() | ForEach-Object {                          #С помощью System.Web.HttpUtility делаем urlDecore, иначе кириллица превращается в руны             $DecodedContent = [System.Web.HttpUtility]::UrlDecode($_)               #Конвертируем прилетевшие данные в нужный нам формат             $ConvertedForm = $DecodedContent | ConvertFrom-Json -ErrorAction SilentlyContinue               #Cконвертированные данные отображаем таблицей             $ConvertedForm | Format-Table                     }           #Отвечаем клиенту 200 OK и закрываем стрим.         $context.Response.Headers.Add("Content-Type", "text/plain")         $context.Response.StatusCode = 200         $ResponseBuffer = [System.Text.Encoding]::UTF8.GetBytes("")         $context.Response.ContentLength64 = $ResponseBuffer.Length         $context.Response.OutputStream.Write($ResponseBuffer, 0, $ResponseBuffer.Length)         $context.Response.Close()       }     #Cконвертированные данные отображаем таблицей     $http.Close()     break } 

Данные будут автоматичеки конвертироваться из JSON и выводиться в терминал.

Автор надеется, что вы выбросите Postman, так же, как и GIT с GUI.

ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/513900/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *