PowerShell 명령어의 기초 — 가장 먼저 익힐 조작과 안전한 사용법

· · PowerShell, Windows, 명령줄, 자동화, 기존 자산 활용

1. 가장 먼저 짚어야 할 것

PowerShell은 Windows 설정 확인, 파일 정리, 로그 조사, CSV 가공, 서비스 조작, 정형 작업의 자동화에 사용할 수 있는 명령어 환경입니다.

다만 처음부터 복잡한 스크립트를 작성할 필요는 없습니다. 먼저 다음 흐름만 기억해 두면, 실무에서 꽤 쓸 수 있게 됩니다.

찾는다  본다  좁힌다  정렬한다  출력한다  필요하면 변경한다

PowerShell의 기본은 “긴 명령어를 외우는 것”이 아닙니다. 중요한 것은 다음 세 가지입니다.

  1. Get-CommandGet-Help로 명령어를 조사할 수 있는 것
  2. | 파이프라인으로 결과를 다음 명령어에 넘길 수 있는 것
  3. 삭제·정지·변경을 하기 전에 -WhatIf-Confirm으로 영향을 확인하는 것

PowerShell은 “조사”와 “변경”을 같은 화면에서 실행할 수 있습니다. 편리한 반면, 삭제나 정지도 곧바로 실행할 수 있으므로, 읽기 전용 확인부터 시작하는 습관이 중요합니다.

또한 이 글에 등장하는 코드는, 장 구성에 맞춘 주제별 스크립트 모음(임시 폴더에 연습용 워크스페이스를 만들어 안전하게 시도해 볼 수 있는 구성)과 Pester 테스트를 포함한 샘플 일체로 GitHub에 공개되어 있습니다.

powershell-command-basics - komurasoft-blog-samples (GitHub)

2. PowerShell과 명령 프롬프트의 차이

PowerShell은 기존의 명령 프롬프트(cmd.exe)와 비슷해 보이지만, 내부의 사고방식이 다릅니다.

관점 명령 프롬프트 PowerShell
주된 출력 문자열 객체
명령어 이름 dir, copy Get-ChildItem, Copy-Item
결과 가공 문자열 처리가 중심 속성을 이용한 필터링·정렬
자동화 배치 파일 .ps1 스크립트
강점 분야 오래된 명령어 자산과의 호환 Windows 관리, CSV, JSON, API, 정형 작업

예를 들어 파일 목록을 가져올 때, cmd.exe에서는 dir의 표시 결과를 문자열로 바라보는 경우가 많습니다. PowerShell에서는 파일이 Name, Length, LastWriteTime 등의 속성을 가진 객체로 다루어집니다.

Get-ChildItem

이 차이를 이해하면, 다음처럼 “7일 이내에 수정된 파일만, 수정 일시가 최신인 순서로 표시한다”와 같은 처리를 자연스럽게 작성할 수 있습니다.

Get-ChildItem -File |
  Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
  Sort-Object LastWriteTime -Descending |
  Select-Object Name, Length, LastWriteTime

3. Windows PowerShell 5.1과 PowerShell 7.x

Windows에는 예전부터 들어 있는 Windows PowerShell 5.1과, 새로운 계열인 PowerShell 7.x가 있습니다.

실무에서는 다음과 같이 생각하면 이해하기 쉽습니다.

종류 실행 파일 주된 용도
Windows PowerShell 5.1 powershell.exe 오래된 Windows 전용 모듈, 기존 스크립트, 사내 자산의 유지보수
PowerShell 7.x pwsh.exe 신규 스크립트, 크로스 플랫폼, 지속적인 기능 개선

새로 배우는 경우라면 PowerShell 7.x를 기준으로 삼아도 문제없습니다. 다만 사내의 오래된 관리 스크립트나 Windows 고유 모듈은, Windows PowerShell 5.1을 전제로 만들어진 경우가 있습니다.

그래서 실무에서는 먼저 버전을 확인합니다.

$PSVersionTable

특정 버전 이상에서 동작시키고 싶은 스크립트에는, 맨 앞에 조건을 적어 두면 사고를 줄일 수 있습니다.

#Requires -Version 7.0

4. 명령어(cmdlet) 이름은 Verb-Noun

PowerShell의 표준 명령어는 기본적으로 동사-명사 형태입니다.

Get-Process
Get-Service
Get-ChildItem
Copy-Item
Remove-Item
Export-Csv

이 형태를 기억해 두면, 낯선 명령어도 쉽게 찾을 수 있습니다.

동사 의미
Get 가져온다 Get-Process
Set 설정한다 Set-Location
New 만든다 New-Item
Copy 복사한다 Copy-Item
Move 이동한다 Move-Item
Remove 삭제한다 Remove-Item
Start 시작한다 Start-Service
Stop 정지한다 Stop-Process
Import 읽어들인다 Import-Csv
Export 내보낸다 Export-Csv

dir, ls, cat, cd처럼 짧은 이름도 사용할 수 있지만, 대부분은 별칭(alias)입니다.

Get-Command dir

스크립트로 남길 경우에는, 별칭이 아니라 정식 이름을 쓰는 것이 안전합니다.

# 읽기는 편하지만, 스크립트에서는 피하고 싶다
ls *.log

# 의도가 명확하다
Get-ChildItem -Filter *.log

5. 가장 먼저 익힐 3가지 조사 명령어

PowerShell은 명령어 수가 많기 때문에, 외우기보다 “찾는 방법”을 익히는 것이 실무적입니다.

1. Get-Command ── 사용할 수 있는 명령어를 찾는다

Get-Command는 설치되어 있는 명령어, 함수, 별칭, 애플리케이션을 찾기 위한 명령어입니다.

# Process라는 명사를 가진 명령어를 찾는다
Get-Command -Noun Process

# Service 관련 명령어를 찾는다
Get-Command *Service*

# CSV 관련 명령어를 찾는다
Get-Command *Csv*

명령어 이름이 어렴풋이 기억날 때는 와일드카드를 사용합니다.

Get-Command *Item*
Get-Command *Content*
Get-Command *Json*

2. Get-Help ── 사용법을 본다

Get-Help는 명령어의 설명, 매개변수, 예시를 확인하기 위한 명령어입니다.

Get-Help Get-ChildItem
Get-Help Get-ChildItem -Examples
Get-Help Get-ChildItem -Full
Get-Help Get-ChildItem -Online

처음에는 -Examples가 편리합니다.

Get-Help Where-Object -Examples

도움말이 오래되었거나 부족한 경우에는, 관리자 권한의 PowerShell에서 도움말을 업데이트합니다.

Update-Help

환경에 따라 인터넷 연결이나 권한이 필요합니다. 회사 PC에서는 프록시나 관리 정책에 의해 실패하는 경우도 있습니다.

3. Get-Member ── 객체의 내용을 본다

PowerShell의 출력은 대부분 “문자열”이 아니라 “객체”입니다. Get-Member를 사용하면, 그 객체가 어떤 속성과 메서드를 가지고 있는지 확인할 수 있습니다.

Get-Process | Get-Member
Get-Service | Get-Member
Get-ChildItem | Get-Member

예를 들어 서비스에는 StatusName 같은 속성이 있습니다.

Get-Service | Select-Object Name, Status

파일에는 Name, Length, LastWriteTime 등이 있습니다.

Get-ChildItem -File | Select-Object Name, Length, LastWriteTime

“무엇으로 좁혀야 할지 모르겠다”면, 먼저 Get-Member로 속성 이름을 확인합니다.

6. 파이프라인의 기초

PowerShell의 |는 왼쪽 명령어의 결과를 오른쪽 명령어로 넘깁니다.

Get-Process | Sort-Object CPU -Descending | Select-Object -First 10

이 예시는 다음 처리를 왼쪽에서 오른쪽으로 수행합니다.

프로세스 목록을 가져온다
   CPU 사용량 기준으로 내림차순 정렬한다
   상위 10개만 표시한다

자주 쓰는 조합은 다음과 같습니다.

명령어 역할
Where-Object 조건으로 좁힌다 정지된 서비스만 가져온다
Sort-Object 정렬한다 수정 일시가 최신인 순서로 정렬한다
Select-Object 열이나 개수를 선택한다 이름과 크기만 표시한다
ForEach-Object 각 요소를 처리한다 파일마다 처리한다
Export-Csv CSV로 출력한다 조사 결과를 저장한다

Where-Object ── 조건으로 좁힌다

# 정지된 서비스만 표시
Get-Service | Where-Object { $_.Status -eq "Stopped" }

# 100MB를 초과하는 파일만 표시
Get-ChildItem -File |
  Where-Object { $_.Length -gt 100MB }

# 이름에 backup을 포함하는 파일만 표시
Get-ChildItem -File |
  Where-Object { $_.Name -like "*backup*" }

$_는 파이프라인을 통해 흘러온 현재 객체를 나타냅니다.

Where-Object { $_.Length -gt 100MB }

이것은 “현재 보고 있는 파일의 Length가 100MB보다 큰가”를 판정하고 있습니다.

PowerShell 3.0 이후에는 간략 구문도 사용할 수 있습니다.

Get-Service | Where-Object Status -EQ "Stopped"

다만 초보 단계에서는 scriptblock 구문 쪽이 의미를 이해하기 쉽습니다.

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

Sort-Object ── 정렬한다

# 메모리 사용량이 큰 순서
Get-Process |
  Sort-Object WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet

# 수정 일시가 최신인 순서
Get-ChildItem -File |
  Sort-Object LastWriteTime -Descending |
  Select-Object -First 20 Name, LastWriteTime

Select-Object ── 필요한 열만 선택한다

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

개수를 좁힐 때도 사용합니다.

Get-Process | Select-Object -First 5
Get-Process | Select-Object -Last 5

CSV로 내보내기 전에는, Select-Object로 필요한 열만 정리해 두면 다루기 쉬워집니다.

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

7. Format 계열 명령어는 마지막에 사용한다

PowerShell에는 표시를 정리하기 위한 명령어가 있습니다.

Format-Table
Format-List
Format-Wide

이들은 “화면 표시용”입니다. CSV로 출력하기 전이나, 후속 처리로 넘기기 전에 사용하면, 원래의 속성이 아니라 표시용 객체가 되어 버립니다.

# 피해야 함: CSV에 표시용 정보가 섞인다
Get-Process |
  Format-Table Name, CPU |
  Export-Csv .\process.csv -NoTypeInformation

# 올바른 방법: 먼저 속성을 선택하고 CSV로 출력한다
Get-Process |
  Select-Object Name, CPU |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

Format-*는 “마지막에 화면에 보여주기 위한 것”이라고 기억해 두면 사고가 줄어듭니다.

8. 파일·폴더 조작의 기초

PowerShell에서 가장 자주 쓰는 것은 파일이나 폴더 조작입니다.

하고 싶은 일 명령어
현재 위치를 본다 Get-Location
위치를 이동한다 Set-Location
목록을 본다 Get-ChildItem
파일·폴더를 만든다 New-Item
복사한다 Copy-Item
이동한다 Move-Item
이름을 바꾼다 Rename-Item
삭제한다 Remove-Item
존재를 확인한다 Test-Path

현재 위치를 확인한다

Get-Location

이동합니다.

Set-Location C:\Work

경로에 공백이 포함된 경우에는 인용부호로 감쌉니다.

Set-Location "C:\Work Files\Reports"

파일 목록을 본다

Get-ChildItem
Get-ChildItem -File
Get-ChildItem -Directory
Get-ChildItem -Recurse

확장자로 좁힐 때는 -Filter가 편리합니다.

Get-ChildItem -Filter *.log

하위 폴더까지 포함해 검색할 때는 -Recurse를 사용합니다.

Get-ChildItem C:\Logs -Filter *.log -Recurse

파일이 많은 위치에서는, 갑자기 -Recurse를 실행하지 말고, 대상 폴더를 한정한 뒤에 실행합니다.

만든다

# 폴더 생성
New-Item -ItemType Directory -Path .\archive

# 빈 파일 생성
New-Item -ItemType File -Path .\memo.txt

이미 존재할 가능성이 있는 경우에는, 먼저 확인합니다.

if (-not (Test-Path .\archive)) {
  New-Item -ItemType Directory -Path .\archive
}

복사한다

Copy-Item .\report.xlsx .\backup\report.xlsx

폴더 전체를 복사할 때는 -Recurse를 사용합니다.

Copy-Item .\data .\backup\data -Recurse

덮어쓰기가 관련된 경우에는, 사전에 영향을 확인합니다.

Copy-Item .\data .\backup\data -Recurse -WhatIf

이동한다

Move-Item .\old.log .\archive\old.log

여러 파일을 조건으로 이동할 때는, 먼저 -WhatIf를 붙입니다.

Get-ChildItem .\logs -Filter *.log |
  Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
  Move-Item -Destination .\archive -WhatIf

문제가 없으면 -WhatIf를 제거합니다.

Get-ChildItem .\logs -Filter *.log |
  Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
  Move-Item -Destination .\archive

삭제한다

삭제는 특히 신중하게 다룹니다.

Remove-Item .\old.log -WhatIf

대상이 올바른지 확인한 뒤에 실행합니다.

Remove-Item .\old.log

와일드카드와 -Recurse의 조합은 강력합니다. 처음부터 운영 폴더에서 실행하지 말고, 목록 표시로 확인합니다.

# 먼저 대상을 확인
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Select-Object FullName, Length, LastWriteTime

# 다음으로 삭제 예정을 확인
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Remove-Item -WhatIf

# 마지막으로 실행
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
  Remove-Item

9. 텍스트 파일을 읽기·검색·쓰기

로그 조사에서는 텍스트 파일 조작을 자주 사용합니다.

파일을 읽는다

Get-Content .\app.log

끝부분만 볼 때는 -Tail을 사용합니다.

Get-Content .\app.log -Tail 50

추가되는 로그를 계속 지켜볼 때는 -Wait를 사용합니다.

Get-Content .\app.log -Tail 20 -Wait

문자열을 검색한다

Select-String -Path .\app.log -Pattern "ERROR"

여러 파일을 대상으로 할 수 있습니다.

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

검색 결과에서 파일 이름·행 번호·내용을 추출해 CSV로 만들 수도 있습니다.

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

파일에 씁니다

"hello" | Set-Content .\memo.txt -Encoding UTF8
"next line" | Add-Content .\memo.txt -Encoding UTF8

명령어 결과를 저장할 때는, Out-File보다 Export-CsvConvertTo-Json 쪽이 나중에 다루기 편한 경우가 있습니다.

Get-Process |
  Select-Object Name, Id, CPU |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

10. CSV를 다루는 기초

업무 자동화에서는 CSV가 매우 자주 등장합니다. PowerShell에서는 CSV를 문자열이 아니라 “열을 가진 객체”로 다룰 수 있습니다.

CSV를 읽어들인다

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

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

읽어들입니다.

$users = Import-Csv .\users.csv
$users

열 이름이 속성이 됩니다.

$users | Select-Object Name, Department

조건으로 좁힌다

$users |
  Where-Object { $_.Department -eq "Sales" }

CSV의 값은 문자열로 들어오는 경우가 많으므로, true / false나 숫자를 다룰 때는 주의합니다.

$users |
  Where-Object { $_.Enabled -eq "true" }

CSV로 출력한다

$users |
  Where-Object { $_.Department -eq "Sales" } |
  Export-Csv .\sales-users.csv -NoTypeInformation -Encoding UTF8

Export-Csv 전에 Format-Table을 넣지 않는 것이 원칙입니다.

# 피해야 함
$users | Format-Table | Export-Csv .\out.csv -NoTypeInformation

# 올바른 방법
$users | Select-Object Name, Department, Enabled | Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8

11. JSON을 다루는 기초

설정 파일이나 Web API에서는 JSON도 자주 사용합니다.

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

객체를 JSON으로 변환합니다.

[pscustomobject]@{
  Name = "BatchJob"
  Enabled = $true
  Retry = 3
} | ConvertTo-Json

깊은 계층을 포함하는 경우에는 -Depth를 지정합니다.

$config | ConvertTo-Json -Depth 10 | Set-Content .\settings.json -Encoding UTF8

12. 프로세스와 서비스의 기초

프로세스를 본다

Get-Process

메모리 사용량이 큰 프로세스를 확인합니다.

Get-Process |
  Sort-Object WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet

이름으로 좁힙니다.

Get-Process -Name notepad

정지는 신중하게 수행합니다.

Stop-Process -Name notepad -WhatIf

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

Stop-Process -Name notepad

서비스를 본다

Get-Service

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

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

이름으로 좁힙니다.

Get-Service -Name "Spooler"

재시작할 때도, 대상 확인을 먼저 수행합니다.

Get-Service -Name "Spooler"
Restart-Service -Name "Spooler" -WhatIf

서비스 조작은 업무에 영향을 주기 쉬우므로, 운영 환경에서는 절차서, 유지보수 시간, 복구 방법을 먼저 확인합니다.

13. 이벤트 로그의 기초

Windows 조사에서는 이벤트 로그를 빼놓을 수 없습니다.

최근 오류를 확인합니다.

Get-WinEvent -LogName System -MaxEvents 100 |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message

애플리케이션 로그의 최근 50건을 봅니다.

Get-WinEvent -LogName Application -MaxEvents 50 |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

기간으로 좁힐 때입니다.

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

Get-WinEvent -FilterHashtable @{
  LogName = "System"
  StartTime = $start
} |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, 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

14. 변수·배열·해시테이블

짧은 명령어만으로도 작업할 수 있지만, 조금 길어지면 변수가 편리합니다.

변수

$path = "C:\Logs"
Get-ChildItem $path

PowerShell의 변수는 $로 시작합니다.

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

배열

$extensions = @("*.log", "*.txt", "*.csv")
foreach ($ext in $extensions) {
  Get-ChildItem C:\Work -Filter $ext
}

해시테이블

해시테이블은 키와 값의 조합입니다.

$params = @{
  Path = "C:\Logs"
  Filter = "*.log"
  Recurse = $true
}

Get-ChildItem @params

@params와 같은 작성 방식을 “스플래팅(splatting)”이라고 부릅니다. 매개변수가 늘어났을 때 읽기 쉬워집니다.

15. PSCustomObject로 결과를 정리한다

조사 결과를 표 형태로 정리하고 싶을 때는, [pscustomobject]가 편리합니다.

[pscustomobject]@{
  ComputerName = $env:COMPUTERNAME
  UserName     = $env:USERNAME
  CheckedAt    = Get-Date
}

여러 결과를 만들어 CSV로 만들 수 있습니다.

Get-ChildItem C:\Logs -Filter *.log |
  ForEach-Object {
    [pscustomobject]@{
      Name          = $_.Name
      FullName      = $_.FullName
      SizeMB        = [math]::Round($_.Length / 1MB, 2)
      LastWriteTime = $_.LastWriteTime
    }
  } |
  Export-Csv .\log-files.csv -NoTypeInformation -Encoding UTF8

16. 스크립트 파일 .ps1의 기초

자주 사용하는 처리는 .ps1 파일로 만듭니다.

예로, 오래된 로그를 목록화하는 스크립트를 만듭니다.

# Find-OldLogs.ps1
param(
  [string]$Path = "C:\Logs",
  [int]$Days = 30,
  [string]$OutputPath = ".\old-logs.csv"
)

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

Get-ChildItem -Path $Path -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit } |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Exported: $OutputPath"

실행 예입니다.

.\Find-OldLogs.ps1 -Path C:\Logs -Days 60 -OutputPath .\old-logs.csv

인자를 param()으로 받으면, 나중에 조건을 바꾸기 쉬워집니다.

17. 실행 정책의 기초

.ps1을 실행하려고 하면, 다음과 같은 오류가 나오는 경우가 있습니다.

이 시스템에서는 스크립트 실행이 비활성화되어 있으므로...

이 경우에는 현재 실행 정책을 확인합니다.

Get-ExecutionPolicy
Get-ExecutionPolicy -List

개인 개발 단말에서, 로컬에서 만든 스크립트만 실행하고 싶은 경우라면, 현재 사용자 범위에서 RemoteSigned로 설정하는 경우가 많습니다.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

다만 회사 PC에서는 그룹 정책으로 제어되고 있는 경우가 있습니다. 무리하게 우회하지 말고, 관리자나 운영 규칙을 확인합니다.

실행 정책은 PowerShell의 스크립트 실행 조건을 제어하는 안전 기능입니다. 다만 완전한 보안 경계는 아닙니다. 조직에서는 서명, AppLocker, Microsoft Defender, 권한 관리, 로그 감사와 함께 고려해야 합니다.

18. 오류 처리의 기초

PowerShell은 오류가 나도 처리를 계속하는 경우가 있습니다.

중요한 처리에서는 -ErrorAction Stoptry/catch를 사용합니다.

try {
  Copy-Item .\source.txt .\backup\source.txt -ErrorAction Stop
  Write-Host "Copy succeeded"
}
catch {
  Write-Error "Copy failed: $($_.Exception.Message)"
}

여러 파일을 처리할 때도, 실패를 기록해 두면 나중에 추적할 수 있습니다.

$results = foreach ($file in Get-ChildItem .\input -File) {
  try {
    Copy-Item $file.FullName .\backup -ErrorAction Stop

    [pscustomobject]@{
      FileName = $file.Name
      Status   = "OK"
      Message  = ""
    }
  }
  catch {
    [pscustomobject]@{
      FileName = $file.Name
      Status   = "NG"
      Message  = $_.Exception.Message
    }
  }
}

$results | Export-Csv .\copy-result.csv -NoTypeInformation -Encoding UTF8

19. 변경 계열 명령어를 안전하게 실행하는 순서

PowerShell에서는 삭제·이동·정지 같은 변경 계열 명령어를 안전하게 다루는 절차가 중요합니다.

기본은 다음 순서입니다.

1. Get 계열로 대상을 본다
2. Where-Object 좁힌다
3. Select-Object 대상 목록을 확인한다
4. Export-Csv 기록한다
5. -WhatIf 변경 예정을 확인한다
6. 실제로 실행한다

예로, 30일보다 오래된 .tmp 파일을 삭제하는 경우입니다.

Step 1: 대상을 본다

Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse

Step 2: 조건으로 좁힌다

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

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

Step 3: 필요한 열만 표시한다

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

$targets |
  Select-Object FullName, Length, LastWriteTime

Step 4: 증거를 남긴다

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

Step 5: WhatIf로 확인한다

$targets | Remove-Item -WhatIf

Step 6: 실행한다

$targets | Remove-Item

이 순서로 하면, “무엇을 지웠는지 모르겠다”라는 사고를 줄일 수 있습니다.

20. 자주 쓰는 기본 명령어 목록

위치·파일

목적 명령어 예
현재 폴더를 표시 Get-Location
폴더 이동 Set-Location C:\Work
목록 표시 Get-ChildItem
파일만 표시 Get-ChildItem -File
폴더만 표시 Get-ChildItem -Directory
하위 폴더도 검색 Get-ChildItem -Recurse
존재 확인 Test-Path .\file.txt
폴더 생성 New-Item -ItemType Directory .\backup
복사 Copy-Item .\a.txt .\backup\a.txt
이동 Move-Item .\a.txt .\archive\a.txt
삭제 예정 확인 Remove-Item .\a.txt -WhatIf

객체 가공

목적 명령어 예
조건으로 좁힌다 Where-Object { $_.Status -eq "Running" }
정렬한다 Sort-Object LastWriteTime -Descending
열을 선택한다 Select-Object Name, LastWriteTime
상위만 표시 Select-Object -First 10
각 요소를 처리 ForEach-Object { $_.Name }
내용을 조사 Get-Member

입출력

목적 명령어 예
텍스트를 읽는다 Get-Content .\app.log
끝부분을 본다 Get-Content .\app.log -Tail 50
문자열 검색 Select-String -Path .\app.log -Pattern "ERROR"
CSV 읽기 Import-Csv .\users.csv
CSV 출력 Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8
JSON 읽기 Get-Content .\a.json -Raw | ConvertFrom-Json
JSON 출력 $obj | ConvertTo-Json -Depth 10

Windows 조사

목적 명령어 예
프로세스 목록 Get-Process
서비스 목록 Get-Service
이벤트 로그 Get-WinEvent -LogName System -MaxEvents 100
환경 변수 Get-ChildItem Env:
PowerShell 버전 $PSVersionTable
실행 정책 Get-ExecutionPolicy -List

21. 실무 예시: 로그를 조사해서 리포트를 만든다

다음과 같은 요구사항을 생각해 봅니다.

C:\App\Logs 이하의 .log 파일 중에서, 최근 7일 이내에 수정되었고 ERROR가 포함된 행을 찾아 CSV로 정리하고 싶다.

곧바로 완성형을 작성하지 말고, 단계적으로 만듭니다.

Step 1: 로그 파일을 찾는다

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse

Step 2: 최근 7일 이내로 좁힌다

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since }

Step 3: ERROR를 검색한다

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern "ERROR"

Step 4: CSV로 출력한다

$since = (Get-Date).AddDays(-7)

Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-report.csv -NoTypeInformation -Encoding UTF8

Step 5: 스크립트로 만든다

# Export-ErrorReport.ps1
param(
  [string]$LogPath = "C:\App\Logs",
  [int]$Days = 7,
  [string]$Pattern = "ERROR",
  [string]$OutputPath = ".\error-report.csv"
)

$since = (Get-Date).AddDays(-$Days)

Get-ChildItem $LogPath -Filter *.log -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-String -Pattern $Pattern |
  Select-Object Path, LineNumber, Line |
  Export-Csv $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Exported: $OutputPath"

실행 예입니다.

.\Export-ErrorReport.ps1 -LogPath C:\App\Logs -Days 14 -Pattern "ERROR|FATAL" -OutputPath .\errors.csv

22. 실무 예시: 오래된 파일을 아카이브한다

다음은 삭제가 아니라 이동으로 처리하는 예시입니다.

C:\Work\Reports 중에서 90일 이상 수정되지 않은 .xlsx 파일을 C:\Work\Archive로 이동한다.

대상 확인

$source = "C:\Work\Reports"
$dest = "C:\Work\Archive"
$limit = (Get-Date).AddDays(-90)

$targets = Get-ChildItem $source -Filter *.xlsx -File |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets | Select-Object FullName, Length, LastWriteTime

아카이브 대상 폴더 생성

if (-not (Test-Path $dest)) {
  New-Item -ItemType Directory -Path $dest
}

증거 출력

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

WhatIf 확인

$targets | Move-Item -Destination $dest -WhatIf

실행

$targets | Move-Item -Destination $dest

파일 이름이 중복될 가능성이 있는 경우, 이대로는 실패합니다. 실무에서는 연월 폴더를 나누거나, 이동할 파일 이름에 날짜와 시간을 붙이거나, 기존 파일이 있으면 건너뛰는 등의 규칙을 먼저 정해 둡니다.

23. 자주 하는 실수

증상 원인 대처
명령어가 길어서 외울 수 없다 외우려고 하고 있다 Get-Command, Get-Help -Examples로 찾는다
$_를 모르겠다 파이프라인 현재 값에 대한 이해 부족 Where-Object { $_.Name -like "*log*" } 형태로 기억한다
CSV가 이상한 내용이 된다 Format-Table 뒤에 Export-Csv를 하고 있다 Select-Object 뒤에 Export-Csv를 한다
경로에 공백이 있으면 실패한다 인용부호가 없다 "C:\Work Files\a.txt"처럼 감싼다
스크립트를 실행할 수 없다 실행 정책 Get-ExecutionPolicy -List로 확인한다
삭제 대상이 너무 많다 조건이 너무 넓다 먼저 Select-Object FullName-WhatIf로 확인한다
속성 이름을 모르겠다 객체 구조를 보지 않고 있다 Get-Member를 사용한다
문자가 깨진다 인코딩 전제가 다르다 입출력의 -Encoding과 사용 앱을 확인한다

24. 명령어를 익히는 순서

처음부터 모든 명령어를 외울 필요는 없습니다.

다음 순서를 추천합니다.

1단계: 보기·찾기

Get-Command
Get-Help
Get-Member
Get-Location
Set-Location
Get-ChildItem
Get-Content
Select-String

2단계: 좁히기·정리하기

Where-Object
Sort-Object
Select-Object
ForEach-Object
Format-Table
Format-List

3단계: 입출력하기

Import-Csv
Export-Csv
ConvertFrom-Json
ConvertTo-Json
Set-Content
Add-Content
Out-File

4단계: 변경하기

New-Item
Copy-Item
Move-Item
Rename-Item
Remove-Item
Start-Service
Stop-Service
Restart-Service
Stop-Process

변경 계열은 반드시 확인 계열 명령어와 세트로 기억합니다.

# 본다
Get-ChildItem .\logs -Filter *.tmp

# 삭제 예정을 본다
Get-ChildItem .\logs -Filter *.tmp | Remove-Item -WhatIf

# 실행한다
Get-ChildItem .\logs -Filter *.tmp | Remove-Item

25. 현장에서의 운영 체크리스트

PowerShell을 업무에서 사용할 때는, 다음 관점을 확인해 두면 안전합니다.

  • 실행하는 PowerShell이 powershell.exe인지 pwsh.exe인지 확인했다
  • $PSVersionTable로 버전을 확인했다
  • 변경 전에 Get-* 계열로 대상을 표시했다
  • Where-Object의 조건을 화면에서 확인했다
  • 삭제·이동·정지 전에 -WhatIf를 사용했다
  • 실행 전 대상 목록을 CSV로 저장했다
  • 운영 환경에서는 백업 또는 복구 절차를 확인했다
  • 스크립트의 실행 정책과 사내 규칙을 확인했다
  • 오류 시의 로그 출력을 준비했다
  • 공유하는 스크립트에서는 별칭이 아니라 정식 명령어 이름을 사용했다

26. 정리

PowerShell의 기본은 명령어를 대량으로 외우는 것이 아닙니다. 실무에서 효과를 발휘하는 것은, 다음 패턴을 익히는 것입니다.

Get-Command 찾는다
Get-Help 사용법을 본다
Get-Member 속성을 확인한다
Get-*  대상을 본다
Where-Object 좁힌다
Select-Object 열을 정리한다
Export-Csv 증거를 남긴다
-WhatIf 변경 예정을 확인한다
마지막으로 실행한다

특히 PowerShell은 파일 삭제, 서비스 정지, 프로세스 종료, 레지스트리 조작까지 할 수 있는 강력한 환경입니다. 그렇기 때문에 가장 먼저 익혀야 할 것은 “위험한 명령어”가 아니라, “안전하게 대상을 확인하는 절차”입니다.

본다  좁힌다  기록한다  예행한다  실행한다

이 순서를 지키면, PowerShell은 단순한 검은 화면이 아니라, Windows 업무를 정리·조사·자동화하기 위한 실용적인 도구가 됩니다.

참고 링크

관련 글

이 주제와 연결되는 서비스

Windows 앱 개발

업무용 앱, 장비 연동, 통신 도구 등 Windows 소프트웨어 개발을 지원합니다.

서비스 보기 / 문의하기

기존 자산 활용·마이그레이션 지원

오래된 배치 파일, VBScript, VBA, PowerShell, COM / ActiveX를 포함한 기존 자산의 실태 조사, 개선, 마이그레이션을 지원합니다.

문의하기

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

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

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

자주 묻는 질문

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

PowerShell 학습은 무엇부터 시작하면 좋을까요?
명령어를 외우는 것이 아니라, 찾는 방법을 익히는 것이 중요합니다. 핵심은 세 가지로, Get-Command와 Get-Help로 명령어를 조사할 수 있다는 것, 파이프라인(|)으로 결과를 다음 명령어에 넘길 수 있다는 것, 그리고 삭제·정지·변경을 실행하기 전에 -WhatIf나 -Confirm으로 영향을 확인하는 것입니다. 객체의 속성 이름을 모를 때는 Get-Member로 내용을 확인합니다. 기본 흐름은 '찾는다 → 본다 → 좁힌다 → 정렬한다 → 출력한다 → 필요하면 변경한다'입니다.
PowerShell과 명령 프롬프트는 무엇이 다른가요?
가장 큰 차이는, 명령 프롬프트의 출력이 문자열 중심인 데 비해 PowerShell의 출력은 객체라는 점입니다. 예를 들어 파일은 Name, Length, LastWriteTime 등의 속성을 가진 객체로 다루어지므로, Where-Object로 필터링하거나 Sort-Object로 정렬하는 코드를 자연스럽게 작성할 수 있습니다. 명령어 이름도 Get-ChildItem이나 Copy-Item처럼 동사-명사 형태로 통일되어 있어, 낯선 명령어도 쉽게 찾을 수 있습니다.
Windows PowerShell 5.1과 PowerShell 7.x 중 어느 쪽을 써야 하나요?
새로 배우는 경우라면 PowerShell 7.x(pwsh.exe)를 기준으로 삼아도 문제없습니다. 다만 사내의 오래된 관리 스크립트나 Windows 고유 모듈은 Windows PowerShell 5.1(powershell.exe)을 전제로 만들어진 경우가 있습니다. 실무에서는 먼저 $PSVersionTable로 버전을 확인하고, 특정 버전 이상에서만 동작시키고 싶은 스크립트에는 맨 앞에 #Requires -Version 7.0과 같은 조건을 적어 두면 사고를 줄일 수 있습니다.
PowerShell에서 삭제나 변경을 안전하게 실행하려면 어떻게 해야 하나요?
'본다 → 좁힌다 → 기록한다 → 예행한다 → 실행한다'의 순서를 지키는 것입니다. 구체적으로는, 먼저 Get 계열 명령어로 대상을 표시하고, Where-Object로 좁히고, Select-Object로 대상 목록을 확인하고, Export-Csv로 CSV에 증거를 남기고, -WhatIf로 변경 예정을 확인한 다음 실제로 실행합니다. PowerShell은 조사와 변경을 같은 화면에서 실행할 수 있으므로, 읽기 전용 확인부터 시작하는 습관이 중요합니다.

저자 프로필

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

Go Komura

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

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

블로그 목록으로 돌아가기