5 хв читанняІнженерія

Як скоротити URL у PowerShell за допомогою Invoke-RestMethod

Скоротіть URL у PowerShell однією командою, обробіть помилки 429, не зберігайте API-ключ у скрипті та скоротіть цілий стовпець CSV за допомогою ForEach-Object -Parallel.

Marius Voß
DevRel · edge infra
Як скоротити URL у PowerShell: Invoke-RestMethod надсилає URL призначення до API скорочувача та повертає коротке посилання як об'єкт

Щоб скоротити URL у PowerShell, потрібен один командлет. Invoke-RestMethod надсилає ваше призначення до API скорочувача, передає API-ключ у заголовку Bearer і повертає розібраний об'єкт, а не рядок JSON. Нічого не потрібно встановлювати на будь-якій машині, де вже є PowerShell.

Це частина серії для системних адміністраторів, яка також охоплює Python, JavaScript, C# і Go. Форму ендпойнта та модель автентифікації задокументовано в огляді безкоштовного API скорочувача URL, а маршрут дашборда наведено в загальному посібнику зі скорочення URL.

Найшвидший спосіб: один виклик Invoke-RestMethod

$headers = @{
    Authorization  = "Bearer $env:ELIDO_API_KEY"
    'Content-Type' = 'application/json'
}

$body = @{
    destination_url = 'https://example.com/spring-sale?utm_source=newsletter'
} | ConvertTo-Json

$link = Invoke-RestMethod -Method Post `
    -Uri 'https://api.elido.app/v1/links' `
    -Headers $headers `
    -Body $body `
    -TimeoutSec 10

$link.short_url   # https://s.elido.me/ab12cd

Invoke-RestMethod десеріалізує відповідь, і саме це відрізняє його від Invoke-WebRequest. Кроку ConvertFrom-Json немає, як і .Content, який треба було б розгортати: $link уже є об'єктом із id і short_url.

ConvertTo-Json не є необов'язковим. Якщо передати хеш-таблицю безпосередньо в -Body, PowerShell закодує її як форму, API побачить application/x-www-form-urlencoded, і ви отримаєте помилку 400, яка виглядатиме як проблема на сервері.

Одна специфічна для PowerShell несподіванка: тут 401 або 404 - це помилка, що завершує виконання, а не значення, яке повертається. Усі інші клієнти в цій серії змушують вас перевіряти код стану, а цей - перехоплювати виняток.

Обробка помилок 429 і повторний безпечний запуск скрипту

Для будь-якого запланованого запуску потрібно додати три речі. try/catch через описану вище поведінку з помилкою. Очікування, що враховує Retry-After. І Idempotency-Key, щоб повторний запит повертав початкове посилання, а не створював друге для того самого призначення.

function Get-ShortLink {
    param(
        [Parameter(Mandatory)][string] $Destination,
        [int] $Attempts = 3
    )

    # stable key: the same destination always produces the same one
    $sha  = [System.Security.Cryptography.SHA256]::Create()
    $key  = [BitConverter]::ToString(
                $sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($Destination))
            ).Replace('-', '')

    $headers = @{
        Authorization     = "Bearer $env:ELIDO_API_KEY"
        'Content-Type'    = 'application/json'
        'Idempotency-Key' = $key
    }
    $body = @{ destination_url = $Destination } | ConvertTo-Json

    for ($attempt = 0; $attempt -lt $Attempts; $attempt++) {
        try {
            return (Invoke-RestMethod -Method Post -Uri 'https://api.elido.app/v1/links' `
                        -Headers $headers -Body $body -TimeoutSec 10).short_url
        }
        catch {
            $status = $_.Exception.Response.StatusCode.value__

            if ($status -eq 429) {
                $wait = $_.Exception.Response.Headers['Retry-After']
                if (-not $wait) { $wait = 2 }        # works on 5.1 too; no ?? operator
                Start-Sleep -Seconds ([int]$wait)
            }
            elseif ($status -ge 500) {
                Start-Sleep -Seconds ([math]::Pow(2, $attempt))   # 1s, 2s, 4s
            }
            else {
                throw   # 401, 403, 422: retrying will not help
            }
        }
    }

    throw "shorten failed after $Attempts attempts"
}

У PowerShell 7 можна пропустити більшу частину дослідження винятків за допомогою -SkipHttpErrorCheck: він повертає об'єкт відповіді замість того, щоб видавати помилку, тож ви можете безпосередньо прочитати тіло помилки API. Це варто зробити, коли ви налагоджуєте 422 і хочете побачити, до якого поля API висунув претензію.

PowerShell Invoke-RestMethod надсилає URL призначення з Bearer-токеном та Idempotency-Key до ендпойнта links скорочувача й повертає розібраний об'єкт, що містить short_url

Не зберігайте ключ у скрипті

$env:ELIDO_API_KEY - найпростіша відповідь, і її достатньо для запланованого завдання з власним службовим обліковим записом. Ключ, введений у файл .ps1, для цього не підходить: він опиниться в системі контролю версій, у Get-History і в будь-якому журналі транскриптів, увімкненому у вашій інфраструктурі.

Для спільного використання кращим місцем буде модуль SecretManagement:

$env:ELIDO_API_KEY = Get-Secret -Name ElidoApiKey -AsPlainText

Тоді для ротації ключа достатньо оновити один запис у сховищі, а не шукати його у скриптах на чотирьох серверах.

Хочете запускати ці приклади без змін? Створіть ключ на безкоштовному плані, задайте $env:ELIDO_API_KEY, і все на цій сторінці працюватиме без змін.

Скорочення цілого стовпця CSV

Поширене практичне завдання - не один URL, а електронна таблиця з ними. Чотири командлети й обмеження швидкості:

$rows    = Import-Csv .\campaign-urls.csv     # columns: id, destination
$funcDef = ${function:Get-ShortLink}.ToString()

$done = $rows | ForEach-Object -ThrottleLimit 8 -Parallel {
    $function:Get-ShortLink = $using:funcDef   # ship the function into each runspace
    [pscustomobject]@{
        id          = $_.id
        destination = $_.destination
        short_url   = try   { Get-ShortLink -Destination $_.destination }
                      catch { "ERROR: $($_.Exception.Message)" }
    }
}

$done | Export-Csv .\campaign-urls-short.csv -NoTypeInformation

-ThrottleLimit 8 - у цьому весь секрет: одночасно виконується вісім запитів, незалежно від того, чи містить файл п'ятдесят рядків, чи п'ятдесят тисяч. Із -Parallel пов'язані дві особливості. Кожна ітерація виконується у власному runspace, тому функції та змінні з викликача невидимі, якщо не передати їх через $using:. Також потрібен PowerShell 7; у Windows PowerShell 5.1 для кількох сотень рядків найнадійнішим варіантом буде звичайний foreach.

Запис помилок у вихідний стовпець замість переривання виконання дає змогу безпечно повторити запуск. Оскільки ключ ідемпотентності походить із призначення, повторний запуск усього файлу після виправлення трьох рядків нічого не коштує й не створює дублікатів.

Чотириетапний конвеєр PowerShell імпортує CSV із призначеннями, викликає API скорочувача для кожного рядка з обмеженням швидкості, експортує короткі посилання та вибірково перевіряє результат

Вибірково перевірте результат, перш ніж щось виводити або надсилати електронною поштою. Команда curl.exe -sI https://s.elido.me/ab12cd для трьох рядків займає десять секунд і виявляє випадок, коли стовпці зсунулися на один.

Коли PowerShell - правильний інструмент

Це правильний інструмент, коли дані вже є в CSV або Active Directory, завдання запускається за розкладом у Windows або його обслуговує системний адміністратор, а не розробник застосунків. Для того, що вбудовується у застосунок, версію для C# із типізованим клієнтом та ін'єкцією залежностей легше тестувати.

У будь-якому разі потрібні: ключ зі змінної середовища або сховища, явний -TimeoutSec, try/catch навколо виклику та стабільний ключ ідемпотентності для всього, що може запуститися двічі. На сторінці API та SDK описано згенеровані клієнти, а рішення для розробників охоплює інші можливості API.

Читайте основну серію

Цей матеріал належить до інженерного кластера. Почніть із посібника з безкоштовного API скорочувача URL, а потім прочитайте про ліміти швидкості та ідемпотентність. Актуальна довідка доступна в документації API, а масовий імпорт коротких посилань із Google Sheet описує варіант без коду для такого самого завдання з CSV.

Ще в блозі

Поширені запитання

Як скоротити URL у PowerShell?

Викличте Invoke-RestMethod з параметром -Method Post для ендпойнта links скорочувача, передавши API-ключ у заголовку Authorization, а призначення - у форматі JSON. Командлет сам розбирає відповідь, тож $link.short_url доступний одразу, без кроку ConvertFrom-Json.

Чи потрібен модуль, щоб скорочувати URL у PowerShell?

Ні. Invoke-RestMethod вбудований у Windows PowerShell 3.0 і кожну версію PowerShell 7, а виклик скорочувача - це один запит. Модулі варто використовувати, якщо вам потрібні обгортки у формі командлетів для багатьох ендпойнтів, а не один POST.

Чому Invoke-RestMethod видає помилку для 404 або 401?

Тому що він трактує будь-який код 4xx або 5xx як помилку, що завершує виконання, на відміну від більшості HTTP-клієнтів. Обгорніть виклик у try/catch або передайте -SkipHttpErrorCheck у PowerShell 7, щоб отримати назад об'єкт відповіді та прочитати тіло помилки, яке повернув API.

Як не зберігати API-ключ у скрипті PowerShell?

Прочитайте його зі змінної середовища за допомогою $env:ELIDO_API_KEY або збережіть у модулі SecretManagement і отримайте через Get-Secret. Ключ, вставлений у файл .ps1, опиниться в системі контролю версій, історії консолі та будь-якому ввімкненому журналі транскриптів.

Як скоротити цілий стовпець URL із CSV?

Імпортуйте файл через Import-Csv, передайте його через ForEach-Object -Parallel з -ThrottleLimit 8 і експортуйте результат через Export-Csv, додавши коротке посилання поруч з оригіналом. Обмеження швидкості не дає виконанню перевищити ліміт API; без нього великий файл запускає всі запити одночасно.

Чи працює ForEach-Object -Parallel у Windows PowerShell 5.1?

Ні, для нього потрібен PowerShell 7 або новіша версія. У 5.1 практичні варіанти - звичайний цикл foreach, якого достатньо для кількох сотень рядків, або пули runspace, якщо пакет достатньо великий, щоб виправдати додатковий код.

Спробуйте Elido

Вставте URL - отримайте коротке посилання

Без реєстрації. Посилання живе 30 днів. Зареєструйтесь, щоб зберегти назавжди.

Безкоштовно, без реєстрації · 2 на день

Спробуйте Elido

URL-скорочувач із хостингом у ЄС: власні домени, глибока аналітика, відкритий API. Безкоштовний тариф - без кредитної картки.

Теги
how to shorten a url in powershell
powershell url shortener
invoke-restmethod post json
url shortener api powershell
powershell bulk shorten urls
powershell csv api script

Читати далі