PowerShell(pwsh) 쓸만한 명령어 모음

식빵·2022년 12월 11일
5

PowerShell

목록 보기
3/8
post-thumbnail

요즘 PowerShell 7.4.5 버전이 신기해서 이것저것 시도해보고 있다.
시도해보면서 "이건 나중에도 쓸만 하겠다" 싶은 것들을 모아 봤다.

참고로 Window 에 기본적으로 깔려있는 Windows Powershell 과 다른 것이다!
PowerShell 6 버전 이후로는 기본적으로 Cross-Platform 지원이 된다!
그래서 기본 명칭이 앞에 "Windows" 라는 문구를 뺀 것이다.
이런 이유로 Window 사용자여도 따로 설치해야 되며,
설치법은 여기에서 확인해보길 바란다.

추후에도 계속해서 쓸만한 것들을 찾으면 하단에 추가될 예정이다.
최근 수정일: 2024-12-03
변경 사항: 문자열이 null 또는 공백인지 체크하기 내용 추가


👏 기본적인 사항

  • Powershell 에서는 new line 을 ` (backtick, 백틱) 으로 표현한다.
  • Powershell 의 모든 명령어는 {동사}-{명사} 형태이다.
    • ex) Get-ChildItem
    • 모든 명령어는 동사, 명사의 첫글자가 대문자이지만,
      실제 사용할 때는 모두 소문자로 작성해도 동작한다.
  • Powershelltab 을 통한 명령어 및 옵션 자동완성이 지원이 된다.
  • 대부분의 명령어(cmdlet)는 alias 가 존재한다.
    • Get-Alias -Definition {명령어} 를 통해서 알 수 있다.
  • 어떤 명령어를 쓸 때 파라미터로 경로를 작성하는 경우가 있는데,
    만약 경로에 띄어쓰기가 있다면 반드시 '' 로 감싸주자.
    • ex) Copy-Item -Path 'C:\Users\devToroko\My Documents\' -Destination ...
  • List 표현 방법 : @(1,2,3,4)
  • Map 표현 방법 : @{"id"="devToroko";"job"="programmer"}
  • List [ Map ] : @(@{1 = 1}, @{2 = 2})
  • 변수사용법은 복잡하니 이 링크를 보면서 스스로 익히기

Map 표현 방법 은 반드시 숙지하시기 바랍니다. 상당히 자주 쓰입니다!



👏 기본 명령어

주의사항: 여기서 볼 명령어들은 bash 와 유사한 것들이 종종 보일 것이다.
하지만 이 모든 명령어들은 실제 PowerShell 에서 사용되는 명령어들의 Alias 이다!

PS C:\Users\devToroko> Get-Alias -Name mv, ls, cat, cp | Format-Table -AutoSize

CommandType Name                 Version Source
----------- ----                 ------- ------
Alias       mv -> Move-Item
Alias       ls -> Get-ChildItem
Alias       cat -> Get-Content
Alias       cp -> Copy-Item

즉 아래 작성된 alias 들은 bash 와 비슷한 동작을 하지만 같지는 않다라는 것을 명심하자.

  • 경로 이동 : cd
  • 단순 화면 출력: echo
  • 현재 폴더 내용물 조회: ls, dir
  • 파일 내용 확인: cat
  • 파일 내용 수정: notepad {파일명}
    • 메모장을 통한 내용 수정이다.
    • 만약 vscode 가 깔려있다면 code {파일명} 처럼 해도 된다.
    • 메모장에 내용을 다 작성한 후에 ctrl + w 를 눌러서 메모장을 닫으면 된다.
  • 콘솔창 내용들 지우기: clear
  • 파일 복사: cp
  • 파일 이동: mv
  • 현재 경로: pwd
  • 파일, 디렉토리 생성:
    • ni -Type File {파일 명} , tee {파일명}
    • ni -Type Directory {디렉토리 명}
  • 파일, 디렉토리 삭제: rm



👏 명령어 도움말 보기

Get-Help {cmdlet name}
  • 간단하게 나마라도 도움말 지원을 받을 수 있다.
  • 만약 더 상세히 알고 싶다면 -online 옵션을 덧붙여주자.



👏 명령어가 애매하게 기억날 때

명령어의 일부만 기억나는 경우가 상당히 많다.
그때 마다 인터넷을 뒤지는 건 좀 시간이 아까우니 아래처럼 검색하자.
아래 예시는 nettcp 까지만 명령어를 기억날 때
어떻게 검색하는 지를 보여준다. 참고로 대소문자 상관없이 검색된다 👍

get-command | where { $_.Name -match 'nettcp' }

### 출력:
#CommandType     Name                              Version    #Source
#-----------     ----                              -------    ------
#Function        Get-NetTCPConnection              1.0.0.0    NetTCPIP
#Function        Get-NetTCPSetting                 1.0.0.0    NetTCPIP
#Function        Set-NetTCPSetting                 1.0.0.0    NetTCPIP



👏 프로그램 위치 알아내기

(Get-Command ogr2ogr.exe).Path

# 더 간단한 방법. 
# where.exe ogr2ogr



👏 Object Properties 사용하기

Powershell 에서는 어떤 결과가 나오면 Object 이 나올 때도 있다.
이때 나온 Object 에 어떤 Properties 가 있는지 알아야 사용할 수 있다.
Properties 사용법은 아래와 같다.


(iwr -Uri https://jsonplaceholder.typicode.com/posts/1) |
Get-Member

   TypeName: Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject

Name              MemberType Definition
----              ---------- ----------
Equals            Method     bool Equals(System.Object obj)
GetHashCode       Method     int GetHashCode()
GetType           Method     type GetType()
ToString          Method     string ToString()
Content           Property   string Content {get;}

...생략...


# 특정 패턴의 프로퍼티를 찾으려면?
(iwr -Uri https://jsonplaceholder.typicode.com/posts/1) |
Get-Member -Name con*

   TypeName: Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject

Name    MemberType Definition
----    ---------- ----------
Content Property   string Content {get;}

# 이렇게 확인한 Property 는 아래처럼 사용 가능
#
# 방법 1: 
# (iwr -Uri "https://jsonplaceholder.typicode.com/posts/1").content
#
# 방법 2: 
# iwr -Uri "https://jsonplaceholder.typicode.com/posts/1" |
# Select-Object -ExpandProperty Content



👏 타입 변환하기

[Convert]::To # ...까지만 쓰고 ctrl + space 로 자동완성 기능 사용

이렇게 입력하면 아래처럼 나온다.



👏 이미지 -> base64String

[System.Convert]::ToBase64String((get-content -Path .\test.png -AsByteStream -Raw)) >> capture.txt

# WARNING: Encoding not used when '-AsByteStream' specified.
# ... 라는 경고문은 "진짜로" 무시해도 된다. 아~무 문제없다.

참고: https://jaredwinick.github.io/base64-image-viewer/ 에서 테스트 가능



👏 Directory, File 생성

PS C:\Users\devToroko> New-Item -ItemType Directory jquery_copy
PS C:\Users\devToroko> cd jquery_copy
PS C:\Users\devToroko\jquery_copy> New-Item -ItemType File 1.txt
PS C:\Users\devToroko\jquery_copy> notepad 1.txt

# 메모장으로 파일 내용 수정 후, ctrl + w 를 눌러서 메모장 닫음
# 그 후에 메모장 내용을 아래 처럼 읽으면, 편집된 내용을 확인할 수 있다.

PS C:\Users\devToroko\jquery_copy> get-content 1.txt 



👏 파일명 일괄 수정

## 예시 1 : 파일 명칭 한번에 `random_point_5179` 로 바꾸기
Get-ChildItem | 
Rename-Item -NewName {
	 'random_point_5179' + $_.Extension
}

## 예시 2 : 기존 명칭, 확장자는 유지하고, 앞에 "prefix-" 를 붙임
Get-ChildItem | foreach -ErrorAction Stop {
     Rename-Item -Path $_ -NewName "prefix-$($_.BaseName).$($_.Extension)"
}

참고: 더 응용해보고 싶다면 이 링크를 참조하시길 바랍니다.




👏 Directory Copy

copy-item -Path .\jquery_copy\ -Destination .\jquery_copy2\ -Recurse -Container
  • 참고로 Container 를 줘야 directory 구조를 유지하면서 복사를 합니다.
  • Recurse 는 directory 가 계속해서 존재하면, 재귀적으로 복사를 합니다.
  • 만약에 뭔가 잘 안되면 -Force 옵션도 주자.



👏 Directory 구조 그대로 File 복사하기

파일 복사시 파일을 복사할 곳에 폴더가 없으면 에러가 난다.
디렉토리 구조가 잡히지 않은 상태에서는 파일 복사를 원하면 아래 스크립트를 활용하자.

$source="S:/somewhere/favicon.ico"; $destination="C:/somewhere/favicon.ico"; `
Copy-Item $source -Force -Destination `
(New-Item -Path (Split-Path -Path $destination) -Type Directory -Force)

위의 명령어가 좀 장황하게 느껴질 수 있다.
만약 window 사용자면 CMD 로 위 명령으를 아래처럼 대처할 수 있다.

echo F | xcopy "S:\somewhere\favicon.ico" "C:\somewhere\favicon.ico" /E /H /K

주의! 디렉토리 경로 구분자는 "\" 를 사용해야 한다.



👏 폴더 내용 모두 삭제하기

rm -Recurse -Force .\삭제할_폴더_명

# 몇개의 파일을 제외시키고 싶다면 아래처럼
# Remove-Item -Exclude *.zip ./*



👏 폴더 및 파일 절대 경로 조회

# 현재 폴더(.) 에 있는 모든 item 들의 절대 경로를 뽑아낸다.
(Get-ChildItem . -Recurse).FullName

# alias 를 사용하면? 
(dir . -Recurse).FullName

# 만약에 이 내용들을 Clipboard 에 바로 넣어서 사용하고 싶다면?
(dir . -Recurse).FullName | set-clipboard # 이러고 나서 ctrl+v 하면 된다.

# 만약에 File 의 절대 경로만 보고 싶다면?
(dir . -File -Recurse).FullName

# 이외에도 -Filter 라는 옵션을 통해서 특정 파일 확장자만 조회할 수도 있다.
(dir . -File -Recurse -Filter *.jar).FullName # jar 파일만 조회

ps: 만약 현재 경로에 대한 조회면, 경로 표시로 사용한 "." 표기는 생략해도 됩니다.



👏 특정 문자열이 있는 파일의 절대경로 조회

# 또는 아래처럼 해도 좋다.
$searchPath = "./"
$searchString = "something"
Get-ChildItem -Path $searchPath -Recurse -File | ForEach-Object {
     if (Select-String -Path $_.FullName -Pattern $searchString -Quiet) {
         $_.FullName
     }
}



👏 정규 표현식을 이용한 재귀적 파일명 탐색

# 현재 디렉토리 경로(".")를 베이스로 재귀 검색을 시작합니다.
get-childitem -Path "." -Recurse | select -ExpandProperty FullName | Where-Object {
    $_.Substring($_.LastIndexOf('\') + 1) -match '^(?i)(?!README\.txt$).+\.(csv|txt)$'
} 

위의 재귀식(^(?i)(?!README\.txt$).+\.(csv|txt)$) 은 제가 필요해서 작성한 것이고,
여러분들 입맛에 맞게 바꾸시길 바랍니다!



👏 전체 경로 구분자 바꾸기

흔치 않지만 경로 표기를 "\" 에서 "/" 로 바꿔야 하는 경우가 있습니다.
그때는 아래처럼 해보시기 바랍니다.

# 1. 기본적인 사용법은 아래와 같습니다.
(Get-ChildItem -Recurse -Force).FullName -replace("\\", "/")

# 출력 예시:
# C:/study/spring-boot-inflearn/tool/apache-tomcat-10.1.13
# C:/study/spring-boot-inflearn/tool/apache-tomcat-10.1.13.zip
# C:/study/spring-boot-inflearn/tool/command.txt


# 2. -replace 는 여러번 호출도 가능합니다.
(Get-ChildItem -Recurse -Force).FullName -replace("\\", "/") -replace("C:/", "/")

# 출력 예시:
# /study/spring-boot-inflearn/tool/apache-tomcat-10.1.13
# /study/spring-boot-inflearn/tool/apache-tomcat-10.1.13.zip
# /study/spring-boot-inflearn/tool/command.txt



👏 특정 문자열이 있는 모든 파일 찾아내기

# 방법 1: 서브 디렉토리가 없는 구조인 경우
(Select-String -Path .\*.txt -Pattern 'Group ID' -List).Path

# 방법 2: 서브 디렉토리도 있는 구조인 경우
Get-ChildItem -Recurse |
Select-String -Pattern "Group ID" -CaseSensitive -List |
Select-Object Path



👏 문자열이 null 또는 공백인지 체크하기

[string]::IsNullOrWhiteSpace('')
# True

[string]::IsNullOrWhiteSpace($null)
# True

[string]::IsNullOrWhiteSpace(' ')
# True

[string]::IsNullOrWhiteSpace('123')
# False



👏 new line 문자열을 split 하기

참고: powershell -split('') specify a new line

@'
행정경계_시도(행정동)
행정경계_읍면동(행정동)
행정경계_시군구(행정동)
행정경계_읍면동(법정동)
행정경계_시군구(법정동)
행정경계_리(법정동)
행정경계_시도(법정동)
'@ -split '\r?\n' | ForEach-Object {
   echo $_
}

new Line 이 포함된 문자열을 복사해서 @'~'@ 사이에 붙여넣고 싶다면
약간의 노하우가 필요합니다. 먼저 아래처럼 작성합니다.

@'
'@

이 상태에서 두번째 줄에 있는 '@ 바로 앞에 커서를 맞추고,
붙여넣기를 해야합니다. 그리고 붙여넣은 문자열의 마지막에 '@ 붙어있으면,
'@ 앞에서 Enter 를 쳐서 줄바꿈을 해줍니다.



👏 압축해제

예시 1

# 현재 경로에 있는 zip 파일을 해당 위치에서 그대로 압축해제 한다. 
# 참고로 압축해제 결과물 이름도 주고 싶다면... "-DestinationPath ./<명칭작성>" 
Expand-Archive .\apache-tomcat-10.1.13.zip -DestinationPath ./

# ls 로 확인
cd apache-tomcat-10.1.13
ls

예시 2

# 디렉토리 내에 여러파일 압축해제 
#  - zip 파일명으로 디렉토리 생성
Get-ChildItem -Filter *.zip | foreach {
   Expand-Archive -Path $_.Name
}

# 디렉토리 내에 여러파일 압축해제 
#  - zip 파일 내의 파일을 현재 디렉토리 내에 모두 압축해제
Get-ChildItem -Filter *.zip | foreach {
   Expand-Archive -Path $_.Name -DestinationPath .
}

위 2개의 명령어에 따라 압축해제 모양이 조금 다릅니다. 아래 그림을 참조해주세요.


zip 파일명으로 디렉토리 생성


현재 디렉토리 내에 모두 압축해제


이외에도 더 자세한 압축하기/압축해제 방법은 powershell(v7.3) 공식문서를 참조하자.



👏 현재 경로를 파일 탐색기로 열기

invoke-item(= ii) 를 호출하면 됩니다.

ii .



👏 환경변수 동적세팅

# 자주사용되는 Path 환경변수에 원하는 경로 추가.
# 지금은 동적으로 jdk 경로를 추가했다.
$env:Path += ";C:\Users\dailycode\.jdks\azul-17.0.7"

# 맨앞에 추가하고 싶다면?
# $env:path = C:\Users\dailycode\.jdks\azul-17.0.7;" + $env:path

# 정말 등록되었는지 확인
($env:path).Split(";") | Select-String "jdk"

참고로 이 방법으로 환경변수로 세팅해도, 전역적으로 적용되는 게 아니라,
현재 콘솔화면을 열은 세션에 한해서만 적용되는 것이다.



👏 Path 동적생성 경로 새로고침

환경변수 Path동적으로 생성된 경로 를 사용하는 경우가 있습니다.
(위의 예시 그림에서는 %JAVA_HOME%\bin 경로가 그렇습니다)

만약에 pwsh 에서 env:JAVA_HOME="~~~~" 을 실행해서 값을 바꾸면
위의 Path 가 동적으로 변경되서 pwsh 에 적용되길 바라겠지만,
실제로는 그렇게 동작하지 않습니다. pwsh 을 실행했을 때 처음 가져온 Path 를 계속
유지시킵니다. 그렇기 때문에 이를 한번 새로고침(?)해줘야 되는데 방법은 아래와 같습니다.

$env:JAVA_HOME="다른 jdk home directory 경로 입력";

# 시스템 환경 변수 값 읽어서 적용하기
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine")

# 사용자 환경 변수 값 읽어서 적용하기
# $env:Path = [System.Environment]::GetEnvironmentVariable("Path","User")

아무래도 이건 alias 로 지정하고 사용하는 게 편할 듯하네요.



👏 콘솔 인코딩 깨짐문제 해결법

# 현재 콘솔 인코딩 방식 조회
[Console]::OutputEncoding

# 변경법 1
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# 변경법 2
[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding(949)

가끔 pwsh 콘솔에서 인코딩이 깨지는 경우가 있는데,
위처럼 인코딩을 변경해서 인코딩 깨짐을 해결할 수 있다.


참고: GetEncoding(949) 에서 949 는 뭘 의미하는가?

949 라는 숫자는 Window 에서 인코딩을 구분하는 아이디 값인 code page 이다.
이 code page 와 매칭되는 인코딩을 보고 싶다면 아래처럼 입력하고 검색할 수 있다.

([System.Text.Encoding]::GetEncodings()) | Where-Object {$_.CodePage -eq '949'}  

# 아래처럼 출력됨.
CodePage Name           DisplayName
-------- ----           -----------
     949 ks_c_5601-1987 ks_c_5601-1987



👏 사용한 명령어 재실행

ctrl + r 을 입력하고 자신이 사용했던 명령어의 일부를 치면 된다.
그러면 자동완성이 되는데, 여기서 그냥 취소하고 나가고 싶으면 ctrl + c,
명령어를 바로 실행시키려면 enter, 명령어를 약간 편집 하고 사용하고 싶다면
방향키를 입력하면 된다.


이외에도 아래처럼 history 와 invoke-history 명령어를 섞어서 사용도 가능하다.

  • history 로 먼저 이력을 보고
  • invoke-history {history 에서 보이는 번호} 를 입력하면 명령어 재실행이 가능하다.



👏 마지막 명령어 조회하기

get-history | Select-Object -Last 1

# 만약에 마지막 명령어를 클립보드에 복사하고 싶다면 아래처럼.
get-history | Select-Object -Last 1 | Set-Clipboard



👏 명령어 위치 알아내기

# 방법 1 : python 으로 Path 에 노출된 모든 경로를 읽어옵니다. 
# 반드시 where.exe 라고 입력해야 합니다. where 라고 입력하면 안되요!
where.exe python

# 출력 결과:
# C:\Users\devToroko\Documents\langchain\.venv\Scripts\python.exe
# C:\Users\devToroko\.pyenv\pyenv-win\shims\python
# C:\Users\devToroko\.pyenv\pyenv-win\shims\python.bat
# C:\Users\devToroko\AppData\Local\Microsoft\WindowsApps\python.exe



# 방법 2: python 으로 Path 에 노출된 것들 중 1순위만 조회합니다.
Get-Command python | select -ExpandProperty Source

# 출력 결과:
# C:\Users\devToroko\Documents\langchain\.venv\Scripts\python.exe



👏 Alias 알아내기

## 명령어 이름으로 alias 목록 조회

PS C:\Users\devToroko> Get-Alias -Definition Get-ChildItem

CommandType     Name                          Version    Source
-----------     ----                          -------    ------
Alias           dir -> Get-ChildItem
Alias           gci -> Get-ChildItem
Alias           ls -> Get-ChildItem


## alias 로 실제 사용 명령어 알아내기

PS C:\Users\devToroko> Get-Alias -Name ls

CommandType     Name                          Version    Source
-----------     ----                          -------    ------
Alias           ls -> Get-ChildItem



👏 EVAL 기능

흔하지 않지만 가끔 완성된 문자열에 대한 연산을 하고 싶을 수 있다.
그럴 때는 이렇게 하면 된다.

Invoke-Expression 0+1+2+3+4+5+6+7+8+9;
# ===> 45

$array1 = 0,1,2,3,4,5,6,7,8,9;
Invoke-Expression ($array1 | Join-String -Separator '+');
# ===> 45



👏 브라우저 열기

Start-Process https://www.naver.com/

# 또는 alias 를 사용해서 아래처럼도 가능
start https://www.naver.com/ 



👏 백그라운드에서 실행하기

Start-Process -NoNewWindow .\h2.bat

아 최근에 알았는데, 이걸 실행한 콘솔창을 끄면, 실행했던 프로세스가 꺼지네요...
이건 방법을 더 알아보겠습니다!



👏 IP, Port Connection 테스트

cmd 에서 ping 명령어와 아주 유사한 기능이다. 사용법은 아래와 같다.

# ip test ==> table 로 출력한다. 
Test-Connection 8.8.8.8 -Repeat

# ip + port test ==> True / False 를 반환한다.
Test-Connection 8.8.8.8 -TcpPort 443
  • -Repeat 인자를 주면 계속해서 테스트 요청을 전송한다. 멈추고 싶으면 ctrl + c

참고:

이상하게 -TcpPort 를 사용하면 -Repeat 를 인식을 못하는 문제가 생겼습니다.
원인은 정확히 모르겠네요. 일단 어떻게든 동작시키기 위해서 아래처럼
while 문을 돌려서 Repeat 를 대체할 순 있습니다.

while(test-connection 10.0.8.6 -TcpPort 7922) {
   Write-Host "connect date: $(Get-Date -format "yyyy.MM.dd HH:mm:ss")"
   Start-Sleep 3; # 3초마다 다시 test-connection 호출!
}

## 아래처럼 출력될 겁니다.
## connect date: 2023.09.04 18:08:01
## connect date: 2023.09.04 18:08:04


# 보충: 아래처럼도 가능합니다.
while((New-Object System.Net.Sockets.TcpClient).Client.ConnectAsync("10.0.8.6", "7922").Wait(1000)) {
   Write-Host "connect date: $(Get-Date -format "yyyy.MM.dd HH:mm:ss")"
   Start-Sleep 3; # 3초마다 다시 test-connection 호출!
}



👏 host name <-> host ip 조회하기

host ip 를 통해서 host 명을 알아내든지
반대로 host 명으로 ip 를 알아내는 방법은 아래와 같다.

# 네이버의 IP 얻어내기
[System.Net.Dns]::GetHostAddresses('naver.com') | select IPAddressToString

# IP 로 호스트 명칭 구하기
[System.Net.Dns]::GetHostEntry('8.8.8.8')


IP 를 알아내는 방법은 2가지가 더 있다.

방법1

Test-NetConnection -ComputerName "www.google.com" -InformationLevel "Detailed"

방법2

 Resolve-DnsName google.com



👏 특정 포트 죽이기

Stop-Process -Id (Get-NetTCPConnection -LocalPort "8080").OwningProcess

참고로 현재 사용되는 포트가 아니면 에러를 뱉어냅니다.



👏 웹에 요청 + 다운로드

bash 를 사용한 사람이라면 curl 을 알 것이다.
이와 상당히 비슷한 기능으로 Invoke-WebRequest 라는 명령어가 있다.
alias 로는 iwr 를 사용하며 이 기능을 사용한 웹 요청을 해보겠다.
그리고 추가적으로 이 기능을 통해서 파일을 다운로드 받는 법도 알아보자.

참고:
최근에 알았는데 curlWindow 10 (build 17063), 11 에 기본
내장되어 있다고 하네요. 참고: https://curl.se/windows/microsoft.html

### 일반적인 GET Method HTTP 요청 
(iwr -Uri "https://jsonplaceholder.typicode.com/posts/1").content

### 출력결과:
# {
#   "userId": 1,
#   "id": 1,
#   "title": "sunt aut facere repellat provident occaecati excepturi optio ..생략..",
#   "body": "quia et suscipit\nsuscipit recusandae consequuntur expe ..생략.."
# }



# Jquery 를 다운로드 받아보자.
(iwr -Uri "https://code.jquery.com/jquery-3.6.1.js").content `
| Out-File -Encoding utf8 -Path "./jquery-3-6.1.js"

### 출력결과:
PS C:\Users\devToroko> ls # jquery 파일이 생성된 것을 확인한다.

    Directory: C:\Users\devToroko\jquery_copy

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---        2022-12-11  오후 1:32             10 1.txt
-a---        2022-12-11  오후 2:06         289814 jquery-3-6.1.js



### 만약에 복잡한 Http Method Post 를 보내려면?
Invoke-WebRequest `
	-Headers @{"Authorization" = "Bearer N-..생략..";"accept"="application/json"} `
	-Method POST `
    -Body (@{"lastName"="doe";}|ConvertTo-Json) `
    -Uri https://api.dummy.com/getUsers `
    -ContentType application/json
    
# 또 다른 전송 예시
iwr -Uri http://localhost:8080/run -Method Post -ContentType "application/json" -Body @'
   {"name": "restJob", "jobParameters": {"foo": "bar", "baz": "quix"}}
'@



👏 웹 요청 다른 방법

위에서는 invoke-webrequest 를 썼다면, 이번에는 Invoke-RestMethod 사용법~

PS C:\Users\devToroko> `
Invoke-RestMethod -Uri 'https://epsg.io/?format=json&q=5179' ` 
| ConvertTo-Json -Depth 10 `
|  Out-File -Encoding utf8 -FilePath 'C:\study\geodata\5179.txt'

json 문자열을 받아서 파일에 저장한 예이다.
파일을 열어보면 아래와 같이 나온다. 인코딩되 제대로 UTF-8 로 잘 박힌다.




👏 WebRequest vs RestMethod

위의 2개의 목차에서 Invoke-WebRequestInvoke-RestMethod 를 봤는데,
둘 간의 차이가 뭔지 궁금해서 검색해봤다.

그리고 https://www.truesec.com/hub/blog/invoke-webrequest-or-invoke-restmethod 링크가
내용이 좋아서 해당글을 참조했다.

Invoke-WebRequest

The Invoke-WebRequest cmdlet sends HTTP, HTTPS, FTP, and FILE requests to a web page or web service. It parses the response and returns collections of forms, links, images, and other significant HTML elements.

Invoke-RestMethod

The Invoke-RestMethod cmdlet sends HTTP and HTTPS requests to Representational State Transfer (REST) web services that returns richly structured data.


일단 둘의 정의는 위와 같고, 좀 더 상세한 차이로는...

Invoke-WebRequest 는 네트워크에서 요청할 수 있는 다양한 프로토콜을 전반적으로
지원하고, 받는 Response 에서 Header 정보 같은 메타 정보를 제공 받을 수 있다.

반면 Invoke-RestMethodInvoke-WebRequest 을 한번 Wrapping 한
명령어로 HTTP(S) 요청만 지원하며, 반환값으로 메타정보를 모두 들고 오지 않고,
오로지 content 와 관련된 내용만 가져온다. 이때 반환받는 결과는 Http Responsecontent-type 에 따라 적절하게 객체를 생성해서 결과로 반영한다.
하지만 메타 정보를 들고 오지 않다보니, Http Status 코드가 200, 201 일 때만
정상적으로 반환받고, 이외 상태 코드를 받으면 에러를 뱉어낸다.


결론:
단순히 HTTP(S) 요청의 content 의 내용을 받아서 사용하려면 Invoke-RestMethod,
그외의 다양한 프로토콜과 메타정보가 필요하면서 Http Status 에 따라 분기 처리가
필요하다면 Invoke-WebRequest 를 사용!

분기처리 예)

PS C:\Users\devToroko>
try {
  $resp = Invoke-WebRequest -Uri 'https://jsonplaceholder.typicode.com/users' `
                            -SkipHttpErrorCheck -ErrorAction Stop;
  if($resp.statuscode -eq '200') { `
      $jsonContent = ConvertFrom-Json $resp.Content ;`
      $jsonContent = $jsonContent | ConvertTo-Json -Depth 100;` # pretty print
       echo $jsonContent; `
       Out-File -FilePath '<저장할 디렉토리 경로>\<파일명>.json' `
                -Encoding utf8 `
                -InputObject $jsonContent;
  } else {
     write $res.StatusCode;
  }
} catch [System.Net.Http.HttpRequestException] {
       write-host "HttpRequestException Occurred code: "
                  "code : " + $_.exception.innerexception.errorcode
                  "message : " + $_.exception.innerexception.message
}

참고로 여기 나오는 errorcode 는 이 링크를 참조하시기 바랍니다.



참고 : https://davidhamann.de/2019/04/12/powershell-invoke-webrequest-by-example/

$s = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$c = New-Object System.Net.Cookie('Hello','World','/','httpbin.org')
$s.Cookies.Add($c)

$r = iwr 'http://httpbin.org/cookies' -WebSession $s



👏 초간단 파일 다운로드

(New-Object System.Net.WebClient).DownloadFile("https://velog.velcdn.com/images/dailylifecoding/post/5f6599b9-9197-4b71-8836-46c4b699d86d/image.png", "$pwd\downloaded.png")
  • 참고로 2번째 인자값에 ./ 경로로 시작하면 무조건 User Home 디렉토리 하부에 저장됩니다.
  • 자기가 현재 보고 있는 workspace 를 타겟팅하고 싶다면 저처럼 $pwd 를 사용해주세요.



👏 git-bash 에서 일부 기능 빌려오기

pwsh 에서 많이 아쉬운 부분이 bash 의 less 기능이다.
하지만 git 을 설치했다면 어느정도 이를 cover 할 수 있다.
git bash 가 사용하는 less.exe 를 그대로 pwsh 에서도 사용하면 된다.
아래처럼 alias 를 주면 끝이다.

Set-Alias -Name "bash-less" -Value "C:\Program Files\Git\usr\bin\less.exe"

참고로 영구적으로 계속 적용하고 싶다면 profile.ps1 에 위 명령어를 기재해둬야 합니다. profile.ps1 가 뭔지 모르겠다면 제가 이전에 작성한 글을 참조하시기 바랍니다.



👏 (참고) host pc <-> virtual pc 포워딩

이건 딱히 pwsh 의 명령어는 아니지만, 굉장히 유용해서 참고용으로 작성했습니다.

명령어 참고문서: https://learn.microsoft.com/ko-kr/windows-server/networking/technologies/netsh/netsh-contexts

외부 요청을 host pc 에서 받는 건 공유기의 포트 포워딩 을 통해서 설정하면 끝이지만,
가끔은 이 외부요청을 다시 host pc 에 생성된 virtual pc 의 특정 [ip + port]
포워딩을 해야되는 경우가 있습니다. 이때 알아두면 좋은 게 netsh 입니다.

netsh interface portproxy add v4tov4 `
listenport='<host PC port that listen to external request>' `
listenaddress='0.0.0.0' `
connectport='<virtual pc connection port>' `
connectaddress='<virtual pc ip that exposed to host pc>'



👏 (참고) Powershell 로 openssh 설치

https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?tabs=powershell#install-openssh-for-windows



👏 (참고) 중간에 공백이 있는 exe 실행시키기

종종 공백(" ")처럼 한번 띄워쓰는 경로에 있는 exe 파일이 있습니다.

ex: C:\Program Files\GDAL\ogr2ogr.exe

이럴때는 Program Files 사이에 있는 공백 바로 왼쪽에 백틱( ` )을 넣어주면 된다.
(아래 그림 참고)



👏 참고 링크

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

4개의 댓글

찾던 내용이에요 깔끔하게 정리되어있고 명령어 찾기도 편하네요.
powershell 명령어 매번 검색했는데 여기서 찾으면 되겠네요 감사합니다.😊

1개의 답글
comment-user-thumbnail
2024년 5월 27일

잘 봤습니다.

1개의 답글