PowerShell 명령어의 기초 — 가장 먼저 익힐 조작과 안전한 사용법
· 小村 豪 · PowerShell, Windows, 명령줄, 자동화, 기존 자산 활용
1. 가장 먼저 짚어야 할 것
PowerShell은 Windows 설정 확인, 파일 정리, 로그 조사, CSV 가공, 서비스 조작, 정형 작업의 자동화에 사용할 수 있는 명령어 환경입니다.
다만 처음부터 복잡한 스크립트를 작성할 필요는 없습니다. 먼저 다음 흐름만 기억해 두면, 실무에서 꽤 쓸 수 있게 됩니다.
찾는다 → 본다 → 좁힌다 → 정렬한다 → 출력한다 → 필요하면 변경한다
PowerShell의 기본은 “긴 명령어를 외우는 것”이 아닙니다. 중요한 것은 다음 세 가지입니다.
Get-Command와Get-Help로 명령어를 조사할 수 있는 것|파이프라인으로 결과를 다음 명령어에 넘길 수 있는 것- 삭제·정지·변경을 하기 전에
-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
예를 들어 서비스에는 Status나 Name 같은 속성이 있습니다.
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-Csv나 ConvertTo-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 Stop과 try/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 업무를 정리·조사·자동화하기 위한 실용적인 도구가 됩니다.
참고 링크
- 이 글의 샘플 코드 모음(주제별 스크립트·Pester 테스트) - komurasoft-blog-samples (GitHub)
- PowerShell Documentation - Microsoft Learn
- Windows에 PowerShell 7 설치하기 - Microsoft Learn
- Windows PowerShell 5.1과 PowerShell 7.x의 차이 - Microsoft Learn
- Get-Command - Microsoft Learn
- Get-Help - Microsoft Learn
- Get-Member - Microsoft Learn
- about_Pipelines - Microsoft Learn
- Where-Object - Microsoft Learn
- Select-Object - Microsoft Learn
- Import-Csv - Microsoft Learn
- Export-Csv - Microsoft Learn
- about_Execution_Policies - Microsoft Learn
관련 글
이 주제와 연결되는 서비스
Windows 앱 개발
업무용 앱, 장비 연동, 통신 도구 등 Windows 소프트웨어 개발을 지원합니다.
기존 자산 활용·마이그레이션 지원
오래된 배치 파일, VBScript, VBA, PowerShell, COM / ActiveX를 포함한 기존 자산의 실태 조사, 개선, 마이그레이션을 지원합니다.
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
PowerShell 실용 명령어 모음 ── 일상 업무에서 자주 쓰는 작은 기능 늘리기
PowerShell로 일상 업무에 쓰는 실용 명령어로서, Measure-Object, Group-Object, Select-String, Compare-Object, Tee-Object, Start-Transcript 등의 활용 시점을 정리합니다.
C#(CSharp)에서 PowerShell을 실행하고 결과를 객체로 받는 방법
C#에서 PowerShell을 실행하고 결과를 문자열이 아닌 PSObject로 받는 방법을, PowerShell SDK, AddCommand, AddParameter, BaseObject, Properties, 오류 처리까지 실무 관점에서 정리합니다.
Pester로 하는 PowerShell 테스트 정비 ── 운영 스크립트를 쉽게 망가지지 않게 만드는 실무 패턴
PowerShell 스크립트를 Pester v5로 테스트하여 날짜 처리, 파일 작업, 삭제 처리, Mock, CI 실행까지 안전하게 정비하는 실무 절차를 정리합니다.
PowerShell 스크립트 응용 ── 로그 조사·아카이브·리포트화를 안전하게 자동화하기
PowerShell 스크립트로 로그 조사, CSV 리포트, 오래된 로그 아카이브, 증적 보존, 작업 스케줄러 실행까지 안전하게 진행하는 실무 절차를 정리합니다.
VBScript 폐지에 대비하는 VBA·사내 도구 점검 가이드
VBScript 단계적 폐지에 대비해 VBA·Excel 매크로·사내 도구의 재고 조사, 정적 검출, 실행 로그, 대체 기술 선정, 테스트, 단계적 전개를 정리합니다.
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
기존 자산 활용 & 이관 지원
COM / ActiveX / OCX 자산, 네이티브 코드, 32비트 의존성을 유지하면서 단계적인 이관 계획을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- 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 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.
공개 링크