본문으로 건너뛰기

PowerShell 다시 배우기 10 - 네트워크와 웹

PowerShell 다시 배우기 10/11

2010~2011년의 팁 글에는 네트워크를 다룬 것이 여럿 있었다. 핑으로 호스트 확인하기, 웹에서 파일 받기, FTP 다루기. 그때는 System.Net.NetworkInformation.Ping이나 System.Net.WebRequest 같은 .NET 클래스를 직접 만들어 썼다. 지금은 기본 명령으로 다 된다.

Test-Connection: 핑

Test-Connection -TargetName 192.168.0.1 -Count 2
   Destination: 192.168.0.1

Ping Source           Address                   Latency BufferSize Status
                                                   (ms)        (B)
---- ------           -------                   ------- ---------- ------
   1 rpi-cluster-0    192.168.0.1                     0         32 Success
   2 rpi-cluster-0    192.168.0.1                     0         32 Success

결과는 개체라서 Latency로 정렬하거나 Status로 거를 수 있다. 되는지 안 되는지만 알고 싶으면 -Quiet를 붙인다. True나 False만 돌려준다.

if (Test-Connection db1 -Count 1 -Quiet) { 'up' }

핑이 막혀 있는 곳이 많다. 그럴 때는 포트가 열렸는지를 본다.

Test-Connection github.com -TcpPort 443    # True

경로 추적(-Traceroute)과 MTU 확인(-MtuSize)도 같은 명령에 있다.

Windows PowerShell 5.1의 Test-Connection은 매개변수와 결과의 모양이 다르다(-ComputerName, ResponseTime). 5.1용으로 쓴 스크립트를 7로 가져오면 여기서 걸린다.

대역 전체를 훑기

2011년에 쓴 Ping-MultipleTarget은 주소를 하나씩 차례로 두드렸다. 응답 없는 주소마다 제한 시간을 다 기다리므로, 주소가 많을수록 그만큼 오래 걸렸다. ForEach-Object -Parallel로 한꺼번에 보내면 된다.

function Test-Host {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$Prefix,
        [ValidateRange(1, 254)][int]$Start = 1,
        [ValidateRange(1, 254)][int]$End = 254,
        [int]$TimeoutSeconds = 1
    )
    $Start..$End | ForEach-Object -Parallel {
        $address = "$using:Prefix$_"
        [pscustomobject]@{
            Address = $address
            Online  = Test-Connection -TargetName $address -Count 1 -TimeoutSeconds $using:TimeoutSeconds -Quiet
        }
    } -ThrottleLimit 64 | Sort-Object { [version]$_.Address }
}
Test-Host -Prefix '192.168.0.' | Where-Object Online

주소 30개를 훑는 데 2.4초 걸렸다. 차례로 하면 응답 없는 26개가 1초씩 기다려 26초가 넘는다.

두 가지를 짚어 둔다. 병렬로 돌린 결과는 끝나는 순서대로 나오므로 마지막에 정렬한다. IP 주소는 글자로 정렬하면 10이 2보다 앞에 오기 때문에 [version]으로 바꿔 정렬한다. 그리고 옛 함수는 결과를 Write-Host로 색칠해 찍었지만, 이 함수는 개체를 돌려준다. 켜진 것만 거르거나 CSV로 내보내는 일은 쓰는 사람이 정한다.

Invoke-RestMethod: API 부르기

JSON을 돌려주는 주소를 부르면 개체로 바꿔서 준다. 날짜는 DateTime으로 바뀌어 있다.

$release = Invoke-RestMethod https://api.github.com/repos/PowerShell/PowerShell/releases/latest
$release.tag_name                    # v7.6.6
$release.published_at.GetType().Name # DateTime
($release.assets | Where-Object name -Like '*linux-arm64.tar.gz').name

보낼 때는 -Method와 -Body를 준다. 해시 테이블을 JSON으로 바꿔 넣는다.

$body = @{ title = 'Hello'; draft = $true } | ConvertTo-Json

Invoke-RestMethod https://api.example.com/posts -Method Post -Body $body -ContentType 'application/json'

토큰 인증은 매개변수로 있다. 헤더를 손으로 만들지 않는다.

$token = Get-Secret -Name api-token    # SecureString
Invoke-RestMethod https://api.example.com/me -Authentication Bearer -Token $token

토큰을 금고에서 꺼내는 Get-Secret은 9편에서 다뤘다.

Invoke-WebRequest: 응답 전체가 필요할 때

상태 코드, 헤더, 본문 원문이 필요하면 이쪽을 쓴다.

$response = Invoke-WebRequest https://example.com
$response.StatusCode                # 200
$response.Headers['Content-Type']   # text/html; charset=utf-8

두 명령 모두 4xx, 5xx 응답이면 예외를 던진다. 상태 코드를 직접 보고 판단하려면 -SkipHttpErrorCheck를 붙인다.

$response = Invoke-WebRequest https://api.github.com/nope -SkipHttpErrorCheck
$response.StatusCode    # 404

불안정한 상대에게는 다시 시도하게 한다.

Invoke-RestMethod $url -MaximumRetryCount 3 -RetryIntervalSec 5

파일 내려받기와 올리기

내려받기는 -OutFile 하나다. 큰 파일이 중간에 끊겼으면 -Resume으로 이어 받는다.

Invoke-WebRequest $url -OutFile ./pwsh.tar.gz
Invoke-WebRequest $url -OutFile ./pwsh.tar.gz -Resume

2010년 글에서는 System.Net.WebClient를 만들어 DownloadFile()과 UploadFile()을 불렀다. WebClient와 WebRequest는 .NET에서 더는 권하지 않는 클래스가 됐다.

올리기는 두 가지다. 파일 내용을 그대로 본문으로 보내는 것(PUT)과 폼으로 보내는 것(multipart).

Invoke-RestMethod $url -Method Put -InFile ./app.zip

Invoke-RestMethod $url -Method Post -Form @{
    description = 'nightly build'
    file        = Get-Item ./app.zip
}

FTP에 대해

옛 글 둘이 FTP였다. 지금은 권하지 않는다. FTP는 암호와 내용을 암호화하지 않고 보내며, 그때 쓴 FtpWebRequest도 .NET에서 폐기 예정이다. 파일을 옮길 일은 SSH 위에서 한다.

scp ./app.zip talsu@server1:/tmp/
Copy-Item ./app.zip -Destination /tmp/ -ToSession $session    # PowerShell 원격 세션

네트워크 어댑터 (Windows)

2010년에는 WMI의 Win32_NetworkAdapter를 찾아 Enable()과 Disable()을 불렀다. 지금 Windows에는 전용 명령이 있다. 조회는 누구나 되고, 끄고 켜는 것은 관리자 권한으로 한다.

Get-NetAdapter
Disable-NetAdapter -Name 'Wi-Fi' -Confirm:$false
Enable-NetAdapter -Name 'Wi-Fi'
Restart-NetAdapter -Name '이더넷'

어댑터 이름은 Windows의 표시 언어를 따른다. 한국어 Windows에서 유선 어댑터는 Ethernet이 아니라 이더넷이다. 먼저 Get-NetAdapter로 이름을 확인한다. 무슨 일이 일어날지만 보려면 -WhatIf를 붙인다.

Get-NetIPAddress, Get-NetRoute, Resolve-DnsName, Test-NetConnection도 같은 계열이다. 이 명령들은 Windows에만 있다. 리눅스와 macOS의 PowerShell에는 없으므로 그쪽에서는 ip, dig 같은 운영체제의 도구를 부른다. 여러 운영체제에서 돌아야 하는 스크립트라면 앞에서 본 Test-Connection과 .NET의 [System.Net.Dns]처럼 어디에나 있는 것을 쓴다.

[System.Net.Dns]::GetHostAddresses('example.com')

다음 글: 콘솔 다루기

이 글을 가리키는 글