Команда Powershell Invoke-WebRequest появилась в 3-ей версии консоли. Основной задачей команды - обращение к ресурсам по HTTP, HTTPS и FTP. У этой команды в Powershell есть алиасы в виде 'iwk' и 'wget'. На примерах ниже мы рассмотрим обычные запросы, работу с json, заполнение форм, аутентификацию и парсинг.
Создание запроса HTTP и HTTPS в Powershell
После выполнения простого запроса мы увидим полученную информацию:
Invoke-WebRequest -Uri fixmypc.ru
Если вы имеете прямую ссылку на файл и хотите его скачать нужно дополнительно указать ключ OutFile:
Invoke-WebRequest -Uri 'https://fixmypc.ru/media/media/news_main_images/PowerShell2_dwtURg2.jpg' -OutFile C:\pic3.jpg
Так же можно скачивать любой файл формата ZIP,MP4 и так далее.
Доступ к свойствам
Почти любая команда в Powershell по умолчанию выводит меньше информации чем имеет. Что бы вывести все можно использовать следующий подход:
$wget = Invoke-WebRequest -Uri fixmypc.ru
$wget | SELECT *
Я не рекомендую использовать подход выше, так как в этом случае вывод будет сложно читать. Мы можем посмотреть какие свойства хранит объект для следующего анализа:
$wget = Invoke-WebRequest -Uri fixmypc.ru
$wget | Get-Member
И таким образом выводить данные:
$wget.StatusCode
Само содержимое веб документа может быть доступно по двум свойствам:
$wget.Content
$wget.RawContent
Использование заголовков
Выполнив запрос к какому-то сайту может оказаться, что полученные данные не соответствуют тому что мы видим на сайте. Причин, обычно, у этого две:
- Отсутствуют заголовки;
- Часть информации обрабатывается через JavaScript.
Заголовки указываются в формате хэш-таблиц. Для примера так будет выглядеть запрос с указанными заголовками:
Invoke-WebRequest -Uri fixmypc.ru -Headers @{"accept-encoding"="gzip, deflate, br"; "cache-control"="no-cache";}
Если вы будете испытывать сложности с составлением заголовков, то можно включить отладчик на F12 и открыть закладку Networks и скопировать их. Они находятся в выделенной части на скриншоте:
Кстати через это же меню в Chrome можно получить уже сформировавшийся запрос с командой нажав на нужный элемент и выбрав "Copy as Powershell":
Команда получится достаточно длинной, но это поможет избавиться от долгих поисков нужных заголовков:
Вы можете увидеть вторую кнопку "Copy all as Powershell", которая сформирует объект типа "[object Promise]", но информацию как работать с этим я не нашел.
Такой способ не поможет пройти аутентификацию на сайте так как в Chrome Cookies устанавливаются в параметр Headers, но судя по документации они должны передаваться через параметр WebSession.
Cookies
Для входа на сайт, где используется аутентификация, понадобится использовать Cookies, которые можно увидеть на скриншоте выше. Cookies вводятся отдельно от заголовков и их можно указать двумя путями.
Во время выполнения аутентификации через Poweshell мы можем указать переменную куда будут сохранены данные, а затем передать ее для следующего запроса. В примере ниже такая переменная называется SavedSession:
Invoke-WebRequest -Uri fixmypc.ru -Headers @{"accept-encoding"="gzip, deflate, br"; "cache-control"="no-cache";} -SessionVariable SavedSession
$SavedSession
Invoke-WebRequest -Uri fixmypc.ru -Headers @{"accept-encoding"="gzip, deflate, br"; "cache-control"="no-cache";} -WebSession $SavedSession
Как вы можете увидеть в этой переменной хранятся и заголовки.
Второй способ это заполнить поля Cookies самим через контейнер .NET, то есть способом аналогичным получению заголовков. Первое что делается - создается объект аналогичный SavedSession:
$s = New-Object Microsoft.PowerShell.Commands.WebRequestSession
Теперь мы должны добавить в поле Cookies данные и передать через командлет, я использовал алиас wget:
$c = New-Object System.Net.Cookie('Password','123')
$s.Cookies.Add($c)
wget 'https://fixmypc.ru/' -WebSession $s
Cookie, которые мы передали соответствуют Password=123.
Работа с формами и загрузка
Когда мы заполняем какую-то форму на сайте или выполняем загрузку мы чаще используем метод POST, а не GET, который стоит по умолчанию. Метод можно увидеть в коде или в описании документации, если используете приложения или API:
Чаще всего используются методы описанные выше, но в Powershell доступно больше:
- Default;
- Delete;
- Get;
- Head;
- Merge;
- Options;
- Patch;
- Post;
- Put;
- Trace.
Ключ, в котором используются эти параметры так и называется Method:
wget 'https://fixmypc.ru/' -WebSession $s -Method POST
Для заполнения форм, в версии Powershell 6 +, можно использовать следующий подход:
$Uri = 'https://fixmypc.ru'
$Form = @{
firstName = 'Lora'
lastName = 'Palmler'
email = 'test@test.ru'
}
$Result = Invoke-RestMethod -Uri $Uri -Method Post -Form $Form
Если вы не установите свой тип в заголовке ContentType то он будет "application/x-www-form-urlencoded". Если это важно, то лучше использовать параметр -ContentType, а не писать это же свойство в заголовке. Синтаксис можно увидеть дальше.
Кодировка
Если вы используете данные, которые отличаются от латиницы вы можете столкнуться с проблемой кодировок. Дело в том, что следующие данные будут отосланы не в UTF-8, хоть это и будет указано:
$r = 'ччч' | `
iwr http://httpbin.org/post `
-Method 'POST' `
-Headers @{'Content-Type' = 'application/json; charset=utf-8'}
Если вы не хотите испытывать сложностей с этим командлетом я бы советовал использовать разные ключи для заголовков если у вас есть такие данные. Если указать кодировку в параметре ContentType, то все сработает нормально:
$r = 'ччч' | `
iwr http://httpbin.org/post `
-Method 'POST' `
-ContentType 'application/json; charset=utf-8'
Вы так же можете посылать данные таким образом:
$r = 'ччч'
$body = [System.Text.Encoding]::UTF8.GetBytes($r);
iwr http://httpbin.org/post `
-Method 'POST' `
-ContentType 'application/json; charset=utf-8' `
-Body $body
Аутентификация
Посмотрим на три способа аутентификации используя: базовую (Basic), с использованием сертификата, NTLM и Kerberos.
Базовая аутентификация
Обычно сервер передает дополнительные данные для аутентификации, но в примере ниже это выполнение без их использования:
$pass = "Login:Pass"
$creds = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($pass))
iwr 'http://httpbin.org/basic-auth/AzureDiamond/hunter2' `
-Headers @{ 'Authorization' = 'Basic ' + $creds }
Такой способ не рекомендуется использовать, так как данные будут доступны в истории в незашифрованном виде. Вы так же можете использовать ключ Credential, который создаст аналогичный заголовок за вас.
Используя сертификат
Если у вас установлен сертификат, то вы можете его использовать только указав отпечаток (Thumbprint):
wget 'https://fixmypc.ru' -CertificateThumbprint 28D8AB72A7276FEED46D1DF0B2AC4D4F46B7C4DF
NTLM и Kerberos
Если вам нужно пройти аутентификацию для текущего пользователя вы можете добавить ключ -DefaultCredentials:
wget 'http://domain.local' -UseDefaultCredentials
Этот ключ не будет работать вместе с аутентификацией типа Basic.
Парсинг сайтов
Парсинг, то есть возможность собирать информацию с сайтов, в Powershell реализована достаточно просто. Если мы посмотрим какие свойства имеет объект команды Invoke-WebRequest, сможем увидеть теги:
Картинки
Для примера в HTML картинки хранятся в таком виде:
<IMG title="Как работать с циклами в Powershell ForEach-Object и While на примерах | FixMyPC" class=card-img-top alt="Как работать с циклами в P
owershell ForEach-Object и While на примерах" src="/media/media/news_main_images/PowerShell2_sUFjjsx.jpg">
То есть все картинки имеют тег IMG и SRC. В Powershell часть тегов уже собрана в отдельные свойства и так мы получим список всех картинок:
$content = wget -Uri fixmypc.ru
$content.Images
$content.Images.src
Мы видим только ссылки на картинки, а значит нам нужно выполнить еще по запросу для каждой картинки. К тому же я хочу сохранить существующие имена для каждой картинки, так как у них разные форматы (PNG, JPG). Это будет выглядеть примерно так:
# Массив с картинками
$pics = $content.Images.Src
# Сайт откуда картинки
$site = 'https://fixmypc.ru'
# Папка куда будут сохранятся
$path = 'C:\TestPics\'
foreach ($pic in $pics){
# Разделяем путь на / , откуда берем только последний элемент (имя)
$name = $pic.Split('/')[-1]
# Создаем полную ссылку до картинки
$pic_uri = ($site + $pic)
# Полный путь куда картинки будет сохранена
$full_save_path = ($path + $name)
iwr -Uri $pic_uri -OutFile $full_save_path
}
Обратите внимание, что если у вас не создана директория куда будут сохранятся картинки, появится ошибка. Iwr не создает директории.
Парсинг других тегов
Парсинг остальной части сайта мало чем отличается от примера с картинками. Так как Images и Links выведены как основные свойства, то поиск, например, заголовков должен делаться через свойство AllElements. Для примера так я найду все теги h2:
$h2 = $content.AllElements | where {$_.TagName -eq 'h2'}
$h2.outerText
Кроме поиска по тегам часто приходится искать по классам. Например так я найду все заголовки h2, но используя класс:
$h2 = $content.AllElements | where {$_.class -eq 'card-title'}
$h2.outerText
JSON
По умолчанию мы не можем работать с JSON объектами. Они будут восприниматься как строки пока мы не конвертируем объект в PSCustomObject. Это делается так:
$data = wget -Uri "https://fixmypc.ru/json"
$data = ConvertFrom-Json $([String]::new($data.Content))
После этого мы можем обращаться к свойствам:
$data.GetType()
$data
$data.Employee.Name
После изменения мы возможно захотим отправить объект. Для этого мы конвертируем из PSCutomObject в JSON:
$data = ConvertTo-Json -InputObject $data
Invoke-WebRequest -Method Post -Body $data
Как получать и изменять свойства файлов в Powershell
Работа с классом Net.WebClient
При работе в Powershell доступен еще один метод для доступа к веб страницам и скачивания файлов Net.WebClient. Этот класс имеет методы все из которых мы можем увидеть так:
$source_site = New-Object Net.WebClient
$source_site | Get-Member
Скачивание
Метод DownloadString() позволяет скачивать информацию. Так, например, мы получим содержимое главной страницы сайта:
$source_site = New-Object Net.WebClient
$source_site.DownloadString("https://fixmypc.ru")
Как вы видите есть проблема с кодировкой. Ее можно исправить так:
$source_site = New-Object Net.WebClient
$source_site.Encoding = [System.Text.Encoding]::UTF8
$source_site.DownloadString("https://fixmypc.ru")
Для скачивания файлов используем метод DownloadFile():
$download = New-Object Net.WebClient
$download.DownloadFile("https://fixmypc.ru/media/media/news_main_images/PowerShell2_dwtURg2.jpg", "C:\pic.jpg")
...
Подписывайтесь на наш Telegram канал
Теги: #powershell