PowerShell 실용 명령어 모음 ── 일상 업무에서 자주 쓰는 작은 기능 늘리기

· · PowerShell, Windows, 명령줄, 자동화, 업무 효율화, 기존 자산 활용

1. 가장 먼저 짚어야 할 것

PowerShell의 기초를 익혔다면, 다음으로는 「자주 쓰는 작은 기능」을 늘려가면 실무에서 쓰기 좋아집니다.

여기서 말하는 작은 기능이란 짧은 별칭(alias)을 뜻하는 것이 아닙니다. 이 글에서는 lscat 같은 축약형이 아니라, Get-ChildItem, Get-Content, Select-String 같은 정식 명령어 이름을 사용합니다.

그리고 다음과 같은 작업을 한 줄 또는 몇 줄의 명령어로 할 수 있게 만듭니다.

개수를 센다
합계 크기를 조사한다
중복을 제거한다
종류별로 집계한다
필요한 값만 꺼낸다
두 결과를 비교한다
로그의 앞뒤 행을 본다
클립보드로 보낸다
실행 결과를 저장하면서 화면에도 출력한다
환경 변수나 네트워크를 확인한다

PowerShell은 긴 스크립트를 작성하지 않아도 편리합니다. 먼저 「자주 쓰는 부품」을 늘려서, 일상 업무 안에서 조금씩 조합할 수 있도록 만들어 갑니다.

명령어를 외우기보다, 「이럴 때는 이 부품을 쓸 수 있다」를 떠올릴 수 있는 것이 중요합니다.

또한, 이 글에 등장하는 코드는 장 구성에 맞춰 주제별로 정리한 실행 가능한 예제 세트(레시피 스크립트와 Pester 테스트)로 GitHub에 공개하고 있습니다.

powershell-practical-command-recipes - komurasoft-blog-samples (GitHub)

2. 이번 글의 사고방식

전제는 다음 3가지입니다.

  1. 명령어 이름은 정식 이름으로 쓴다
  2. 읽기 계열 명령어를 중심으로 한다
  3. 변경 계열 명령어는 반드시 대상 확인이나 -WhatIf와 함께 생각한다

예를 들어, 파일을 삭제하는 명령어를 곧바로 외우기보다, 먼저 다음 흐름을 몸에 익히는 것이 안전합니다.

대상을 본다
  → 조건으로 좁힌다
  → 개수를 센다
  → 필요하면 CSV로 남긴다
  → 변경 예정을 확인한다
  → 실행한다

이 글에서는 삭제나 정지 같은 강한 작업보다, 조사·집계·비교·출력을 중심으로 다룹니다.

3. 자주 쓰는 명령어 지도

이번에 사용할 주요 명령어입니다.

하고 싶은 일 명령어
개수나 합계를 조사한다 Measure-Object
중복을 정리한다 Sort-Object -Unique
종류별로 집계한다 Group-Object
필요한 열만 출력한다 Select-Object
각 요소를 처리한다 ForEach-Object
문자열을 검색한다 Select-String
두 결과를 비교한다 Compare-Object
해시 값을 계산한다 Get-FileHash
클립보드를 사용한다 Set-Clipboard / Get-Clipboard
화면과 파일 양쪽에 출력한다 Tee-Object
처리 시간을 측정한다 Measure-Command
에러 상세를 본다 Get-Error
네트워크 연결을 확인한다 Test-Connection / Test-NetConnection

전부를 한 번에 외울 필요는 없습니다. 「셀 때는 Measure-Object」, 「모을 때는 Group-Object」, 「비교할 때는 Compare-Object」처럼 목적과 세트로 외우는 것을 추천합니다.

4. 개수를 센다 ── Measure-Object

가장 먼저 자주 쓰는 것이 개수를 세는 작업입니다.

현재 폴더에 있는 파일 수를 셉니다.

Get-ChildItem . -File | Measure-Object

하위 폴더도 포함해서 셀 경우입니다.

Get-ChildItem . -File -Recurse | Measure-Object

Measure-Object의 결과에 있는 Count가 개수입니다.

파일 크기의 합계를 보고 싶을 때는 Length를 집계합니다.

Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

다만 이 상태로는 바이트 수라서 사람이 읽기에는 조금 어려우므로, GB 단위로 바꿉니다.

$size = Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

이것은 폴더 전체 크기를 대략 보고 싶을 때 편리합니다.

5. 최댓값·평균도 조사한다

Measure-Object는 합계뿐 아니라 최댓값이나 평균값도 낼 수 있습니다.

Get-ChildItem . -File |
  Measure-Object -Property Length -Sum -Average -Maximum -Minimum

파일 크기의 편차를 볼 때 사용할 수 있습니다.

프로세스의 누적 CPU 시간을 합계하는 것도 가능합니다. Get-ProcessCPU는 사용률이 아니라, 프로세스가 시작된 이후 사용한 CPU 시간(초)입니다.

Get-Process |
  Measure-Object -Property CPU -Sum

다만 이 값은 순간적인 CPU 사용률이 아니라 누적값이므로, 실행 시점이나 프로세스의 가동 시간에 따라 달라집니다.

조사용으로 보는 정도라면 충분하지만, 엄밀한 모니터링을 하고 싶다면 전용 모니터링 도구나 로그 설계도 필요합니다.

6. 값만 꺼낸다 ── Select-Object -ExpandProperty

Select-Object는 열을 선택할 때 자주 사용합니다.

Get-Process |
  Select-Object Name, Id, CPU

이것은 「Name, Id, CPU라는 열을 가진 객체」를 출력합니다.

반면, 값만 꺼내고 싶을 때는 -ExpandProperty를 사용합니다.

Get-Process -Name notepad -ErrorAction SilentlyContinue |
  Select-Object -ExpandProperty Id

파일 이름만 꺼낼 때도 마찬가지입니다.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name

명령어의 결과를 다른 명령어나 텍스트 파일에 넘기고 싶을 때는 -ExpandProperty가 편리합니다.

예를 들어, 파일 이름 목록만 저장합니다.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\file-names.txt -Encoding UTF8

Select-Object NameSelect-Object -ExpandProperty Name은 비슷하지만, 결과의 형태가 다릅니다.

Select-Object Name
  → Name이라는 열을 가진 표

Select-Object -ExpandProperty Name
  → Name의 값 자체

CSV로 만들고 싶다면 열로 남겨두는 쪽이 좋고, 다른 문자열 처리에 넘기고 싶다면 값만 있는 쪽이 다루기 쉽습니다.

7. 중복을 제거한다 ── Sort-Object -Unique

파일의 확장자만 목록으로 만들고 싶을 때입니다.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Extension |
  Sort-Object -Unique

실행하면 .txt, .log, .csv처럼 중복을 제외한 확장자만 표시됩니다.

프로세스 이름의 종류만 볼 수도 있습니다.

Get-Process |
  Select-Object -ExpandProperty ProcessName |
  Sort-Object -Unique

사용자 목록 CSV에서 부서명 목록만 꺼내는 예입니다.

Import-Csv .\users.csv |
  Select-Object -ExpandProperty Department |
  Sort-Object -Unique

「목록에 같은 값이 많이 나와서 보기 어렵다」고 느껴질 때는, 먼저 Sort-Object -Unique를 떠올리면 편리합니다.

8. 종류별로 집계한다 ── Group-Object

중복을 제거하는 것만이 아니라, 「무엇이 몇 건 있는지」를 보고 싶을 때는 Group-Object를 사용합니다.

확장자별로 파일 수를 셉니다.

Get-ChildItem . -File |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

-NoElement를 붙이면 각 그룹의 내용을 생략하고, 개수만 보기 쉽게 만들 수 있습니다.

서비스 상태별로 셉니다.

Get-Service |
  Group-Object -Property Status -NoElement

이벤트 로그의 레벨별로 셉니다.

Get-WinEvent -LogName System -MaxEvents 500 |
  Group-Object -Property LevelDisplayName -NoElement

Group-Object는 조사를 시작할 때 전체 모습을 파악하기에 적합합니다.

어떤 확장자가 많은지
어떤 상태의 서비스가 많은지
어떤 에러 레벨이 많은지
어떤 부서의 데이터가 많은지

세부 내용을 보기 전에, 먼저 분포를 보고 싶을 때 사용합니다.

9. 필요한 열을 만든다 ── 계산한 열 추가하기

파일 크기는 Length로 얻을 수 있지만, 단위는 바이트입니다. 매번 바이트 수를 보는 것은 힘들므로, MB나 KB로 바꾼 열을 만들면 편리합니다.

Get-ChildItem . -File |
  Select-Object Name, @{Name="SizeKB"; Expression={ [math]::Round($_.Length / 1KB, 1) }}, LastWriteTime

하위 폴더도 포함해서, 큰 파일 순으로 보는 예입니다.

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}, LastWriteTime

@{Name="..."; Expression={ ... }}은 계산한 열을 만드는 작성법입니다. 처음에는 조금 길어 보이지만, 실무에서는 자주 사용합니다.

예를 들어, 프로세스의 메모리 사용량을 MB로 표시할 수 있습니다.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

리포트에 낼 때는 원래의 Length보다 SizeMB 같은 열이 더 읽기 쉬워집니다.

10. 최신순·오래된순·큰 순으로 본다

PowerShell에서 정렬은 Sort-Object입니다.

최근에 업데이트된 파일을 봅니다.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime -Descending |
  Select-Object -First 10 Name, LastWriteTime

오래된 파일을 봅니다.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime |
  Select-Object -First 10 Name, LastWriteTime

큰 파일을 봅니다.

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 10 FullName, Length

이 세 가지는 자주 사용합니다.

최신순 → LastWriteTime -Descending
오래된순 → LastWriteTime
큰 순 → Length -Descending

로그 조사, 불필요한 파일 정리, 디스크 용량 조사에서 자주 쓰이는 조합입니다.

11. Format 계열은 화면 표시의 마지막에만 사용한다

화면에서 보기 좋게 하고 싶을 때는 Format-Table이나 Format-List를 사용합니다.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Format-Table -AutoSize

한 건의 상세 내용을 볼 때는 Format-List가 편리합니다.

Get-Process -Id $PID |
  Format-List *

다만 Format-Table이나 Format-List는 「표시용」입니다.

CSV로 내기 전이나, 다음 명령어로 가공하기 전에는 사용하지 않는 것이 안전합니다.

# 피한다
Get-Process |
  Format-Table Name, Id |
  Export-Csv .\process.csv -NoTypeInformation

CSV로 낼 때는 Select-Object로 열을 선택합니다.

# 올바른 방법
Get-Process |
  Select-Object Name, Id |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

헷갈리면 다음과 같이 생각합니다.

화면으로만 볼 때 → Format-Table / Format-List
나중에 쓸 때      → Select-Object

12. 로그 검색을 조금 더 편리하게 ── Select-String

문자열 검색에는 Select-String을 사용합니다.

Select-String -Path .\logs\*.log -Pattern "ERROR"

여러 패턴도 지정할 수 있습니다.

Select-String -Path .\logs\*.log -Pattern "ERROR", "WARN", "FATAL"

앞뒤 행도 보고 싶을 때는 -Context를 사용합니다.

Select-String -Path .\logs\*.log -Pattern "ERROR" -Context 2

이것은 해당 행의 앞뒤 2행도 함께 표시하므로, 에러의 전후 관계를 확인하고 싶을 때 편리합니다.

단순한 문자열로 찾고 싶을 때는 -SimpleMatch를 사용합니다.

Select-String -Path .\logs\*.log -Pattern "[ERROR]" -SimpleMatch

Select-String-Pattern은 보통 정규표현식으로 취급됩니다. [. 같은 기호를 그대로 찾고 싶을 때는 -SimpleMatch를 붙이면 이해하기 쉬워집니다.

대문자·소문자를 구분하고 싶을 때입니다.

Select-String -Path .\logs\*.log -Pattern "Error" -CaseSensitive

검색 결과를 CSV로 남길 수도 있습니다.

Select-String -Path .\logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

13. 문자열을 치환한다

텍스트의 일부를 치환하려면 -replace를 사용합니다.

"server01.example.com" -replace "\.example\.com$", ""

파일 내용을 치환할 때는, 곧바로 원본 파일에 덮어쓰지 않는 것이 안전합니다. 먼저 다른 파일로 출력합니다.

(Get-Content .\appsettings.json -Raw) -replace "localhost", "db01" |
  Set-Content .\appsettings.preview.json -Encoding UTF8

확인한 다음, 필요하면 원본 파일에 반영합니다.

설정 파일이나 일괄 치환에서는, 치환 대상이 너무 많으면 사고가 됩니다. 먼저 Select-String으로 대상을 확인한 다음 치환하면 안전합니다.

Select-String -Path .\appsettings.json -Pattern "localhost" -SimpleMatch

14. 두 결과를 비교한다 ── Compare-Object

Compare-Object는 두 목록의 차이를 보는 명령어입니다.

예를 들어, 변경 전후의 파일 이름 목록을 비교합니다.

Compare-Object `
  -ReferenceObject (Get-Content .\before.txt) `
  -DifferenceObject (Get-Content .\after.txt)

SideIndicator의 의미는 다음과 같습니다.

표시 의미
<= 왼쪽, 즉 ReferenceObject에만 있음
=> 오른쪽, 즉 DifferenceObject에만 있음
== 양쪽 모두에 있음. -IncludeEqual을 붙였을 때 표시됨

폴더의 파일 이름 목록을 저장해서 비교하는 예입니다.

Get-ChildItem .\before -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before-list.txt -Encoding UTF8

Get-ChildItem .\after -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after-list.txt -Encoding UTF8

Compare-Object `
  -ReferenceObject (Get-Content .\before-list.txt) `
  -DifferenceObject (Get-Content .\after-list.txt)

서비스 목록의 변경 사항을 볼 수도 있습니다.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-before.csv -NoTypeInformation -Encoding UTF8

변경 후에 다시 한 번 출력합니다.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-after.csv -NoTypeInformation -Encoding UTF8

비교합니다.

Compare-Object `
  -ReferenceObject (Import-Csv .\services-before.csv) `
  -DifferenceObject (Import-Csv .\services-after.csv) `
  -Property Name, Status

작업 전후의 차이를 남겨두면, 조사나 보고가 쉬워집니다.

15. 파일의 해시 값을 확인한다 ── Get-FileHash

다운로드한 파일이나 배포 파일이 동일한지 확인하고 싶을 때는 해시 값을 사용합니다.

Get-FileHash .\installer.exe -Algorithm SHA256

폴더 안의 파일을 한꺼번에 확인할 경우입니다.

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 }

CSV로 남길 수도 있습니다.

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 } |
  Select-Object Path, Hash |
  Export-Csv .\hashes.csv -NoTypeInformation -Encoding UTF8

파일 이름만으로는 같아 보여도 내용이 다른 경우가 있습니다. 배포물, 백업, 이전 작업에서는 해시 값을 남겨두면 확인하기 쉬워집니다.

16. 클립보드로 보낸다 ── Set-Clipboard

명령어 결과를 메일이나 채팅에 붙여넣고 싶을 때, 클립보드로 보내면 편리합니다.

Get-Service |
  Select-Object Name, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

클립보드의 내용을 볼 경우입니다.

Get-Clipboard

Excel에 붙여넣기 위해 탭으로 구분하고 싶을 때는, ConvertTo-Csv의 구분 문자를 탭으로 지정합니다.

Get-Process |
  Select-Object Name, Id, CPU |
  ConvertTo-Csv -NoTypeInformation -Delimiter "`t" |
  Set-Clipboard

일시적으로 결과를 공유하고 싶은 것뿐이라면, 매번 파일을 만드는 것보다 편합니다. 다만 기록으로 남기고 싶을 때는 Export-Csv로 파일에 저장합니다.

17. 화면에도 출력하고, 파일에도 남긴다 ── Tee-Object

결과를 화면으로 보면서 동시에 파일에도 남기고 싶을 때는 Tee-Object를 사용합니다.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Tee-Object -FilePath .\top-process.txt

Tee-Object는 파이프라인의 결과를 두 방향으로 흘려보냅니다.

화면에 출력한다
파일에도 저장한다

조사 중에 「보면서 기록하는」 용도에 적합합니다. 다만 나중에 Excel로 열고 싶다면 Export-Csv 쪽이 다루기 쉽습니다.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Export-Csv .\top-process.csv -NoTypeInformation -Encoding UTF8

화면용이라면 Tee-Object, 표 데이터로 남기고 싶다면 Export-Csv라고 생각하면 이해하기 쉽습니다.

18. 작업 로그를 남긴다 ── Start-Transcript

일련의 작업을 기록하고 싶을 때는 Start-Transcript를 사용합니다.

Start-Transcript -Path .\work-log.txt

이후에 실행한 명령어나 화면 출력이 기록됩니다.

종료합니다.

Stop-Transcript

조사 작업에서는 나중에 다음과 같은 것을 확인하고 싶어집니다.

어떤 명령어를 실행했는지
어떤 폴더에서 작업했는지
어떤 결과가 나왔는지
에러가 발생했는지

Start-Transcript를 사용하면, 작업 메모를 놓쳤을 때의 보험이 됩니다. 다만 비밀번호나 토큰처럼 기록해서는 안 되는 정보가 화면에 나오는 작업에서는 사용법에 주의합니다.

19. CSV를 읽어서 조건으로 본다

업무 데이터에서는 CSV가 자주 등장합니다.

예를 들어, 다음과 같은 users.csv가 있다고 합시다.

Name,Department,Enabled
Suzuki,Sales,true
Tanaka,Accounting,false
Sato,Sales,true

읽어들입니다.

Import-Csv .\users.csv

부서가 Sales인 사람만 봅니다.

Import-Csv .\users.csv |
  Where-Object { $_.Department -eq "Sales" }

유효한 사용자만 별도 CSV로 출력합니다.

Import-Csv .\users.csv |
  Where-Object { $_.Enabled -eq "true" } |
  Export-Csv .\enabled-users.csv -NoTypeInformation -Encoding UTF8

CSV의 값은 문자열로 취급되는 경우가 많으므로, true / false나 숫자를 비교할 때는 필요에 따라 형 변환을 고려합니다.

예를 들어, 점수가 80 이상인 행만 볼 경우입니다.

Import-Csv .\scores.csv |
  Where-Object { [int]$_.Score -ge 80 }

20. JSON의 설정값을 본다

JSON은 설정 파일이나 웹 API에서 자주 사용됩니다.

$config = Get-Content .\settings.json -Raw | ConvertFrom-Json
$config

특정 값만 볼 수도 있습니다.

$config.Database.Host

값을 변경해서 다른 파일에 저장하는 예입니다.

$config.Database.Host = "db01"
$config |
  ConvertTo-Json -Depth 10 |
  Set-Content .\settings.updated.json -Encoding UTF8

JSON을 다룰 때는 Get-Content -Raw를 사용하는 경우가 많습니다. -Raw를 붙이면 파일 전체를 하나의 문자열로 읽어들이므로, 여러 줄로 된 JSON을 다룰 때는 이 방식이 이해하기 쉬워집니다.

21. 환경 변수를 본다

환경 변수는 앱 설정이나 경로 확인에서 자주 사용합니다.

목록을 봅니다.

Get-ChildItem Env:

현재 사용자 이름을 봅니다.

$env:USERNAME

임시 폴더를 봅니다.

$env:TEMP

PATH를 보기 쉽게 분할합니다.

$env:PATH -split ";"

현재 PowerShell 세션에서만 환경 변수를 설정합니다.

$env:APP_MODE = "Development"

이 설정은 지금 열려 있는 PowerShell 안에서만 유효합니다.

사용자 환경 변수로 저장할 경우에는 다음과 같이 합니다.

[Environment]::SetEnvironmentVariable("APP_MODE", "Development", "User")

이것은 환경을 변경하는 작업이므로, 회사 PC나 운영 서버에서는 영향 범위를 확인한 후에 진행합니다.

22. 프로필을 확인한다

PowerShell에는 시작 시 로드되는 프로필이 있습니다.

위치를 확인합니다.

$PROFILE

존재하는지 확인합니다.

Test-Path $PROFILE

생성할 경우입니다.

New-Item -ItemType File -Path $PROFILE -Force

메모장으로 엽니다.

notepad $PROFILE

자주 쓰는 설정이나 함수를 프로필에 적어두면 편리합니다. 다만 복잡한 처리를 너무 많이 작성하면 PowerShell 시작이 느려지거나, 다른 환경에서 재현하기 어려워질 수 있으므로, 처음에는 자주 쓰는 경로나 표시 설정 정도로 그치는 것을 추천합니다.

23. 프로세스를 본다

프로세스 조사에서는 먼저 메모리 사용량이 큰 순서로 보는 경우가 많습니다.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

특정 이름으로 좁힙니다.

Get-Process -Name notepad -ErrorAction SilentlyContinue

프로세스를 정지할 경우에는 곧바로 실행하지 말고 -WhatIf로 확인합니다.

Stop-Process -Name notepad -WhatIf

문제가 없으면 실행합니다.

Stop-Process -Name notepad

운영 환경에서는 프로세스 정지가 업무에 영향을 줄 수 있습니다. 정지하기 전에 대상, 이용자, 복구 방법을 확인합니다.

24. 서비스를 본다

서비스 목록을 봅니다.

Get-Service

정지 중인 서비스만 볼 경우입니다.

Get-Service |
  Where-Object { $_.Status -eq "Stopped" }

자동 시작인데도 정지되어 있는 서비스를 찾습니다.

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

서비스를 재시작할 경우에도 먼저 대상을 확인합니다.

Get-Service -Name "Spooler"

예행연습을 합니다.

Restart-Service -Name "Spooler" -WhatIf

서비스 조작은 영향이 크기 때문에, 유지보수 시간이나 복구 절차를 확인한 다음 실행합니다.

25. 이벤트 로그를 본다

Windows 조사에서는 이벤트 로그를 보는 상황이 자주 있습니다.

시스템 로그의 최근 100건을 봅니다.

Get-WinEvent -LogName System -MaxEvents 100 |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

에러와 경고만으로 좁힙니다.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

최근 24시간의 에러만 봅니다.

$start = (Get-Date).AddHours(-24)

Get-WinEvent -FilterHashtable @{ LogName = "System"; StartTime = $start } |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message

조사 결과를 CSV로 남길 경우입니다.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message |
  Export-Csv .\system-events.csv -NoTypeInformation -Encoding UTF8

이벤트 로그는 건수가 많아지기 쉬우므로, -MaxEvents나 기간 지정으로 범위를 좁히는 것이 중요합니다.

26. 네트워크를 확인한다

연결 확인에는 Test-Connection을 사용합니다.

Test-Connection example.com -Count 4

Windows에서 TCP 포트의 연결을 확인할 경우에는 Test-NetConnection이 편리합니다.

Test-NetConnection example.com -Port 443

DNS 확인(해석)을 확인할 경우입니다.

Resolve-DnsName example.com

네트워크 조사에서는 다음과 같이 원인을 구분합니다.

이름 해석이 되는지
IP로 도달하는지
목적 포트가 열려 있는지
프록시나 방화벽의 영향이 없는지

PowerShell만으로 전부 판단하는 것이 아니라, 원인 구분의 입구로 사용하면 편리합니다.

27. 웹 결과를 본다

웹 페이지 가져오기에는 Invoke-WebRequest를 사용합니다.

Invoke-WebRequest https://example.com |
  Select-Object StatusCode, StatusDescription

JSON API의 결과를 다룰 경우에는 Invoke-RestMethod가 편리합니다.

Invoke-RestMethod https://api.github.com/repos/PowerShell/PowerShell |
  Select-Object full_name, stargazers_count, forks_count

API의 결과는 처음부터 PowerShell 객체로 다룰 수 있는 경우가 많아, Select-ObjectWhere-Object와 조합하기 쉽습니다.

사내 API를 조사할 경우에도, 먼저 읽기 계열인 GET부터 시작합니다.

인증 정보나 토큰을 다룰 경우에는 화면 표시나 transcript 기록에 주의합니다.

28. 실행 시간을 측정한다 ── Measure-Command

처리에 시간이 얼마나 걸리는지 알고 싶을 때는 Measure-Command를 사용합니다.

Measure-Command {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

결과에는 TotalSecondsTotalMilliseconds가 포함됩니다.

$result = Measure-Command {
  Get-ChildItem . -File -Recurse | Measure-Object
}

$result.TotalSeconds

스크립트를 빠르게 만들고 싶을 때는, 감으로 판단하지 말고 시간을 측정하는 것이 중요합니다. 다만 파일 수, 디스크 상태, 네트워크 상태에 따라 결과가 달라지므로, 한 번의 결과만으로 판단하지 말고 여러 번 확인합니다.

29. 시간이 걸리는 처리를 백그라운드로 실행한다 ── Start-Job

시간이 걸리는 조사를 별도의 작업(job)으로 실행하고 싶을 때는 Start-Job을 사용합니다.

$job = Start-Job -ScriptBlock {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

작업의 상태를 봅니다.

Get-Job

결과를 받습니다.

Receive-Job $job

필요 없어진 작업을 삭제합니다.

Remove-Job $job

Start-Job은 편리하지만, 처음부터 많이 쓸 필요는 없습니다. 먼저 평범하게 실행해보고, 시간이 걸리는 처리만 작업화하면 이해하기 쉬워집니다.

30. 명령어 기록을 사용한다

과거에 실행한 명령어를 보려면 Get-History를 사용합니다.

Get-History

명령어 줄만 보기 쉽게 만듭니다.

Get-History |
  Select-Object Id, CommandLine

특정 기록을 다시 실행합니다.

Invoke-History 12

기록은 편리하지만, 위험한 명령어도 다시 실행할 수 있습니다. Remove-Item이나 Stop-Process 같은 변경 계열 명령어를 기록에서 다시 실행할 때는 내용을 확인한 다음 실행합니다.

31. 에러 상세를 본다 ── Get-Error

PowerShell 7에서는 최근 에러를 자세히 보기 위해 Get-Error를 사용할 수 있습니다.

Get-Error

최근 에러 메시지만 보고 싶을 경우입니다.

$Error[0].Exception.Message

에러가 발생했을 때는 화면의 빨간 글자만 보지 말고, 다음 사항을 확인합니다.

어떤 명령어에서 실패했는지
어떤 경로나 대상에서 실패했는지
권한 문제인지
파일이 존재하지 않는 것인지
네트워크나 잠금 문제인지

조사 결과를 남기고 싶을 때는 Start-TranscriptExport-Csv와 조합합니다.

32. 자주 쓰는 비교 연산자

Where-Object에서는 비교 연산자를 자주 사용합니다.

연산자 의미
-eq 같다 $_.Status -eq "Running"
-ne 같지 않다 $_.Status -ne "Running"
-gt 초과 $_.Length -gt 10MB
-ge 이상 $_.Length -ge 10MB
-lt 미만 $_.Length -lt 10MB
-le 이하 $_.Length -le 10MB
-like 와일드카드 일치 $_.Name -like "*.log"
-match 정규표현식 일치 $_.Name -match "^app"
-in 값이 목록에 포함됨 $_.Status -in @("Running", "Paused")
-contains 목록이 값을 포함함 @("a", "b") -contains "a"

예입니다.

Get-ChildItem . -File |
  Where-Object { $_.Length -gt 10MB }
Get-Service |
  Where-Object { $_.Status -in @("Running", "Paused") }
Get-ChildItem . -File |
  Where-Object { $_.Name -match "\.log$" }

처음에는 -eq, -ne, -gt, -lt, -like만으로도 충분합니다. 익숙해지면 -match-in을 사용하면 조건을 작성하기 쉬워집니다.

33. 조금 실용적인 실무 레시피

여기서부터는 실무에서 그대로 쓰기 좋은 형태의 예입니다.

확장자별 파일 수 보기

Get-ChildItem C:\Work -File -Recurse |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

폴더 내용을 대략 파악하고 싶을 때 사용합니다.

큰 파일 상위 20건 보기

Get-ChildItem C:\Work -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}

디스크 용량 조사에서 자주 사용합니다.

최근 24시간 이내에 업데이트된 파일 보기

$since = (Get-Date).AddHours(-24)

Get-ChildItem C:\Work -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-Object FullName, Length, LastWriteTime

장애 발생 후, 어떤 파일이 업데이트되었는지 볼 때 사용할 수 있습니다.

ERROR가 포함된 로그 행을 CSV로 만들기

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

조사 결과를 공유하기 쉬워집니다.

ERROR의 앞뒤 2행 보기

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" -Context 2

원인의 전후 관계를 보고 싶을 때 사용합니다.

메모리 사용량이 큰 프로세스 보기

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

자동 시작인데 정지된 서비스 보기

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

시스템 로그의 에러를 CSV로 만들기

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message |
  Export-Csv .\system-errors.csv -NoTypeInformation -Encoding UTF8

명령어 결과를 클립보드로 보내기

Get-Service |
  Select-Object Name, DisplayName, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

메일이나 채팅에 붙여넣을 때 편리합니다.

작업 전후 파일 목록 비교하기

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before.txt -Encoding UTF8

작업 후에 다시 한 번 가져옵니다.

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after.txt -Encoding UTF8

비교합니다.

Compare-Object (Get-Content .\before.txt) (Get-Content .\after.txt)

폴더의 합계 크기를 GB로 보기

$size = Get-ChildItem C:\Work -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

34. 변경 계열 명령어와 조합할 때의 주의점

지금까지의 대부분은 읽기 계열로, 이것들만이라면 비교적 편하게 시도해볼 수 있습니다. 반면, 다음은 변경 계열 명령어입니다.

작업 명령어
복사 Copy-Item
이동 Move-Item
삭제 Remove-Item
이름 변경 Rename-Item
프로세스 정지 Stop-Process
서비스 재시작 Restart-Service
환경 변수의 영구 설정 [Environment]::SetEnvironmentVariable()

변경 계열은 다음 순서로 사용합니다.

1. Get 계열로 대상을 본다
2. Where-Object로 좁힌다
3. Select-Object로 대상 목록을 본다
4. Measure-Object로 개수를 센다
5. 필요하면 Export-Csv로 남긴다
6. -WhatIf를 쓸 수 있으면 예행연습한다
7. 실행한다

예를 들어, 오래된 .tmp 파일을 삭제할 경우입니다.

먼저 대상을 봅니다.

$limit = (Get-Date).AddDays(-30)

$targets = Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets |
  Select-Object FullName, Length, LastWriteTime

개수를 셉니다.

$targets | Measure-Object

CSV로 남깁니다.

$targets |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv .\delete-targets.csv -NoTypeInformation -Encoding UTF8

삭제 예정을 확인합니다.

$targets | Remove-Item -WhatIf

문제가 없으면 실행합니다.

$targets | Remove-Item

이 흐름만 지켜도 사고를 꽤 줄일 수 있습니다.

35. 외우는 방법

명령어를 개별로 암기하려고 하면 힘들기 때문에, 목적별로 외우는 쪽이 쓰기 편해집니다.

목적 떠올릴 명령어
세고 싶다 Measure-Object
합계를 내고 싶다 Measure-Object -Sum
종류별로 보고 싶다 Group-Object
중복을 없애고 싶다 Sort-Object -Unique
필요한 값만 원한다 Select-Object -ExpandProperty
열을 정리하고 싶다 Select-Object
큰 순서로 보고 싶다 Sort-Object -Descending
문자열을 찾고 싶다 Select-String
앞뒤를 보고 싶다 Select-String -Context
둘을 비교하고 싶다 Compare-Object
기록을 남기고 싶다 Export-Csv / Start-Transcript
화면과 파일 양쪽에 출력하고 싶다 Tee-Object
클립보드로 보내고 싶다 Set-Clipboard
시간을 측정하고 싶다 Measure-Command
에러를 자세히 보고 싶다 Get-Error

36. 정리

PowerShell은 스크립트를 작성할 수 있게 되면 강력합니다. 다만 실무에서 가장 자주 쓰는 것은, 의외로 작은 명령어의 조합입니다.

센다
정렬한다
모은다
비교한다
찾는다
꺼낸다
저장한다
클립보드로 보낸다
작업 로그를 남긴다

이것들만 할 수 있어도, 일상 업무는 꽤 편해집니다. 처음부터 어려운 자동화를 목표로 할 필요는 없습니다. 먼저 읽기 계열 명령어로 상황을 정확하게 볼 수 있게 하고, 그런 다음 필요할 때만 Copy-Item, Move-Item, Remove-Item, Restart-Service 같은 변경 계열 명령어를 사용합니다.

PowerShell을 안전하게 사용하는 요령은 다음 순서입니다.

본다 → 센다 → 정리한다 → 남긴다 → 예행연습한다 → 실행한다

이 패턴을 익히면, PowerShell은 「검은 화면에 명령어를 입력하는 도구」가 아니라, 매일의 조사, 정리, 보고를 지원하는 실용적인 도구가 됩니다.

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

PowerShell에서 파일 개수나 합계 크기를 조사하려면 어떻게 해야 하나요?
Get-ChildItem의 결과를 Measure-Object에 파이프로 넘깁니다. 개수는 결과의 Count 속성으로 확인할 수 있고, 하위 폴더도 포함하려면 -Recurse를 붙입니다. 합계 크기는 Measure-Object -Property Length -Sum으로 집계하며, 바이트 수 그대로는 읽기 어려우므로 [math]::Round($size.Sum / 1GB, 2)처럼 GB 단위로 변환하면 보기 편해집니다. -Average나 -Maximum을 붙이면 평균값·최댓값도 한 번에 낼 수 있습니다.
Select-Object의 -ExpandProperty는 일반적인 지정과 무엇이 다른가요?
Select-Object Name은 「Name이라는 열을 가진 표(객체)」를 반환하지만, Select-Object -ExpandProperty Name은 「Name의 값 자체」를 반환합니다. CSV로 출력하고 싶을 때는 열로 남겨두는 일반적인 지정이 적합하고, 다른 명령어나 문자열 처리, 텍스트 파일에 값만 넘기고 싶을 때는 -ExpandProperty가 다루기 쉽습니다. 목적에 따라 구분해서 사용합니다.
Format-Table을 Export-Csv 앞에 사용하면 안 되는 이유는 무엇인가요?
Format-Table이나 Format-List는 화면 표시용 명령어로, 출력이 표시용 객체로 바뀌어 버리기 때문에 이후의 CSV 출력이나 가공이 제대로 이루어지지 않기 때문입니다. CSV로 출력하거나 다음 명령어로 가공할 경우에는 Select-Object로 열을 선택한 다음 Export-Csv에 넘깁니다. 「화면으로만 볼 거라면 Format 계열, 나중에 쓸 거라면 Select-Object」라고 외워두면 헤매지 않습니다.
Remove-Item 같은 변경 계열 명령어를 안전하게 사용하는 절차가 있나요?
바로 실행하지 말고, 먼저 Get 계열 명령어로 대상을 보고, Where-Object로 좁힌 다음, Select-Object로 대상 목록을 확인하고, Measure-Object로 개수를 세고, 필요하면 Export-Csv로 기록을 남깁니다. 그런 다음 -WhatIf를 쓸 수 있는 명령어라면 예행연습으로 삭제·이동 예정을 확인하고, 문제가 없으면 실행합니다. 이 순서만 지켜도 사고를 꽤 줄일 수 있습니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기