수정 이력(5건, 최종 수정 2026년 09월 03일)
이 글에 적용한 변경 사항의 기록입니다. 보관해 둔 수정 전 버전은 DOI가 부여된 고정 URL에서 읽을 수 있습니다.
- Codex 리뷰에 따라 상담·문의 링크에 /ko/ 로케일 접두를 붙였습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
- permalink·저자 표기·지식 맵 래퍼·깨진 내부 링크 등 CI가 지적한 표시용 수정을 반영했습니다. 본문의 기술적인 주장은 바꾸지 않았습니다.
- 기사 맨앞에 "이 기사의 지식 맵" 절을 추가했습니다. 본문에서 다루는 개념과 그 관계를 요약·그림·상세 페이지 링크로 정리한 것입니다. 본문의 주장은 바꾸지 않았습니다.
- 외부 리뷰(1283건) 대응으로 본문을 업데이트했습니다. 개별 변경 내용은 아래 이력을 참조하세요.
- 각 레시피에 결과 읽는 법(반환 열, 정렬 순서, 무엇을 보고 맞는지 판단할지)을 추가했습니다. 이와 함께 전제 환경 표, Event Log Readers 그룹 추가 절차, XPath 골격 표와 이벤트 뷰어에서 복사하는 절차, Level 표시 이름이 표시 언어에 의존한다는 점을 추가했습니다.
- 최초 공개
이 글을 인용하기(DOI(등록된 아카이브): 10.5281/zenodo.22175067)
아래 DOI는 이전에 등록된 아카이브를 가리키며 현재 본문과 다를 수 있습니다. 현재 본문을 참조할 때는 이 페이지의 URL을 사용하세요.
Go Komura (2026). 「Get-WinEvent로 이벤트 로그를 실무에서 조사하기 ── 필터링 속도가 조사 시간을 가른다」. 합동회사 코무라소프트. https://comcomponent.com/ko/blog/powershell-get-winevent-eventlog/
- DOI(등록된 아카이브)
- 10.5281/zenodo.22175067
- DOI(마지막 등록 버전)
- 10.5281/zenodo.22175068
“지난주 금요일 한밤중에 서버가 제멋대로 재시작된 것 같다”, “특정 단말만 업무 앱이 한 달에 몇 번 죽는다” ── 이런 조사의 출발점은 거의 항상 Windows 이벤트 로그입니다. 다만 이벤트 뷰어 GUI에서 수십만 건을 스크롤하다 보면, 그것만으로 오전이 끝납니다.
PowerShell의 Get-WinEvent를 쓰면 이 작업은 수십 초 만에 끝납니다. 조건이 있습니다. 필터를 올바른 위치에서 거는 것입니다. Get-WinEvent | Where-Object { ... }로 쓰면 모든 이벤트를 읽은 뒤에 버리게 되어, GUI보다 느려지기도 합니다.
이 글에서는 Get-WinEvent 필터를 올바르게 쓰는 방법과, 현장에서 자주 나오는 조사(예기치 않은 재시작, 로그온, 앱 비정상 종료, 서비스 중지) 레시피, 여러 대에서 수집하는 방법까지 정리합니다.
전제 환경
| 항목 | 내용 |
|---|---|
| 대상 OS | Windows 10/11, Windows Server. Get-WinEvent가 읽는 대상은 Windows Vista 이후의 이벤트 로그 기반이며, 클래식 로그와 ETW 로그를 모두 다룹니다1 |
| PowerShell 버전 | Windows PowerShell 5.1과 PowerShell 7 모두에서 사용할 수 있습니다(Get-WinEvent는 Windows 전용 cmdlet이며, Linux/macOS의 PowerShell 7에서는 사용할 수 없습니다). 이 글의 코드는 5.1과 7 모두에서 동작하는 형태로 작성했습니다1 |
| 권한 | System·Application 등 많은 로그는 일반 사용자도 읽을 수 있지만, Security 로그를 읽으려면 관리자 권한 또는 그에 상응하는 권한 부여가 필요합니다. 관리자 권한으로 실행하지 않으면 정보를 가져올 수 없는 로그가 있습니다(4장 (2)에 권한 부여 절차)12 |
| 원격 수집 | 5장의 방법 1(-ComputerName)은 PowerShell 원격 처리(WinRM)에 의존하지 않습니다. 대신 대상 컴퓨터의 방화벽에서 이벤트 로그 서비스로의 원격 액세스를 허용해 두어야 합니다. 방법 2(Invoke-Command)는 WinRM이 전제입니다1 |
1. 먼저 결론
Get-EventLog가 아니라Get-WinEvent를 사용합니다. 전자는 Windows PowerShell 전용이고 클래식 로그만 다루며, PowerShell 7에서는 사용할 수 없습니다.1- 필터는
-FilterHashtable로 겁니다. 이벤트 로그 쪽에서 걸러지므로,Where-Object로 뒤에서 걸러내는 것보다 자릿수 단위로 더 빠릅니다.3 -FilterHashtable의 키는 정해져 있습니다.LogNameProviderNameIDLevelStartTimeEndTimeKeywordsPathUserID등입니다.3- 복잡한 조건이나 이벤트 데이터로 걸러낼 때는 XPath(
-FilterXPath)입니다. 이벤트 뷰어의 “사용자 지정 보기”에서 XPath를 복사할 수 있습니다.1 Level은 숫자입니다. 1=위험, 2=오류, 3=경고, 4=정보, 5=자세한 정보.4- 보안 로그를 읽으려면 별도의 권한이 필요합니다. 관리자 권한으로 실행하는 편이 간편하지만, 조사 담당자에게는 Event Log Readers 그룹이나 채널 ACL로 읽기만 주는 쪽이 최소 권한에 맞습니다.12
- 메시지 문자열이 아니라 이벤트 데이터를 봅니다.
ToXml()로 구조화 데이터를 얻으면 OS 언어 설정에 의존하지 않는 스크립트가 됩니다.1 .evtx파일도 분석할 수 있습니다.-Path를 지정하면 현장에서 가져온 로그를 로컬에서 조사할 수 있습니다.1- 상시 취합은 Windows 이벤트 전달(WEF)입니다. 단발 조사라면
Invoke-Command병렬 실행으로 충분합니다.5
그림의 실선은 항상 성립하는 관계, 점선은 조건이 붙는 관계입니다(성립 조건은 상세 페이지의 관계별 설명에 적혀 있습니다). 관계 전체 목록(총 20건, 근거와 확신도 포함)과 주요 개념의 정의는 지식 맵 상세 페이지에 정리되어 있습니다(일본어). 데이터: JSON-LD / Turtle
2. 로그 두 종류와 cmdlet 선택
Windows 이벤트 로그는 크게 두 계통입니다.
| 종류 | 예 | 읽을 수 있는 cmdlet |
|---|---|---|
| 클래식 로그 | System / Application / Security | Get-EventLog(5.1만)·Get-WinEvent |
| 응용 프로그램 및 서비스 로그 | Microsoft-Windows-TaskScheduler/Operational 등 |
Get-WinEvent만 |
후자 쪽에 조사에 쓸모 있는 정보가 들어 있습니다. 작업 스케줄러 실행 이력, PowerShell 스크립트 블록 로그, Windows Update 적용 이력처럼 원인 규명의 결정타가 되는 로그 상당수가 이쪽입니다. 따라서 앞으로 작성하는 스크립트는 Get-WinEvent로 통일하는 것이 맞습니다.1
먼저 어떤 로그가 있는지 확인합니다.
# 로그 목록(건수 많은 순). RecordCount가 0인 로그는 기록되지 않음
Get-WinEvent -ListLog * -ErrorAction SilentlyContinue |
Where-Object RecordCount -gt 0 |
Sort-Object RecordCount -Descending |
Select-Object LogName, RecordCount, MaximumSizeInBytes, IsEnabled -First 20
# 특정 제품의 로그를 찾는다
Get-WinEvent -ListLog *TaskScheduler* | Format-Table LogName, IsEnabled, RecordCount
Get-WinEvent -ListProvider *PowerShell* | Select-Object Name
3. 필터는 “어디서 거느냐”가 전부입니다
같은 결과를 얻는 세 가지 작성 방식을 비교합니다.
# 【최악】모든 이벤트를 읽은 뒤 PowerShell 쪽에서 버린다
Get-WinEvent -LogName System | Where-Object { $_.Id -eq 41 }
# 【권장】이벤트 로그 쪽에서 건다(FilterHashtable)
Get-WinEvent -FilterHashtable @{ LogName = 'System'; ID = 41 }
# 【복잡한 조건】XPath로 건다
Get-WinEvent -LogName System -FilterXPath "*[System[EventID=41]]"
첫 번째는 수십만 건 이벤트를 모두 객체로 만든 뒤에 버리므로, 대기 시간의 대부분이 낭비입니다. 두 번째·세 번째는 이벤트 로그 API 쪽에서 걸러지므로 필요한 것만 돌아옵니다.3
-FilterHashtable에서 쓸 수 있는 키는 정해져 있습니다.3
| 키 | 지정하는 것 | 예 |
|---|---|---|
LogName |
로그 이름 | 'System', 'Microsoft-Windows-TaskScheduler/Operational' |
ProviderName |
이벤트 원본 | 'Application Error', 'Service Control Manager' |
ID |
이벤트 ID(배열 가능) | 41, @(1000, 1001) |
Level |
심각도(숫자) | 2(오류), @(1,2) |
StartTime / EndTime |
기간 | (Get-Date).AddDays(-7) |
Keywords |
키워드(감사 성공/실패 등) | 9007199254740992(감사 성공) |
Path |
.evtx 파일 |
'D:\collect\srv01_System.evtx' |
UserID |
사용자 SID | 'S-1-5-21-...' |
Level 숫자는 다음과 같습니다.4
값(Level) |
한국어 환경 표시 | 영어 환경 표시 |
|---|---|---|
| 1 | 위험 | Critical |
| 2 | 오류 | Error |
| 3 | 경고 | Warning |
| 4 | 정보 | Information |
| 5 | 자세한 정보 | Verbose |
오른쪽 두 열은 이벤트 뷰어의 “수준” 열과 Get-WinEvent 결과의 LevelDisplayName 속성에 나오는 문자열입니다. LevelDisplayName은 OS 표시 언어에 따라 바뀝니다. 출력을 눈으로 맞출 때는 이 대응표를 쓰고, 스크립트에서 걸러낼 때는 반드시 숫자 Level을 지정합니다(표시 이름으로 판정하면 영어 환경에서 동작하지 않는 스크립트가 됩니다).
실무적인 형태는 다음과 같습니다.
# 최근 7일간의 오류·위험 이벤트를 원본별로 집계한다(상황 파악의 첫 단계)
$filter = @{
LogName = 'System', 'Application'
Level = 1, 2
StartTime = (Get-Date).AddDays(-7)
}
try {
Get-WinEvent -FilterHashtable $filter -ErrorAction Stop |
Group-Object ProviderName, Id |
Sort-Object Count -Descending |
Select-Object Count, Name -First 15
}
catch {
# "해당 이벤트 없음"만 조용히 흘린다. 로케일에 의존하지 않는다
# FullyQualifiedErrorId로 판정한다(메시지 문자열은 한국어 환경에서 일치하지 않음)
if ($_.FullyQualifiedErrorId -notlike 'NoMatchingEventsFound*') { throw }
}
결과 읽는 법. Group-Object 출력은 Count와 Name 두 열입니다. ProviderName, Id처럼 여러 속성으로 그룹화했으므로 Name에는 원본, 이벤트 ID가 쉼표로 이어집니다(예: Service Control Manager, 7034). 건수가 많은 순이므로, 상위에 낯설은 원본이 올라왔는지, 장애가 난 시간대에 대응하는 건수 봉우리가 있는지를 보는 것이 첫 단계입니다. 여기서 감을 잡은 뒤, 다음 장의 레시피로 개별 이벤트를 파고듭니다.
해당 이벤트가 한 건도 없으면 Get-WinEvent는 오류를 냅니다. 여기서 쉽게 -ErrorAction SilentlyContinue를 붙이지 않습니다. “해당 없음”도 “그 로그를 읽을 권한이 없음”도 “대상에 도달할 수 없음”도, 모두 같은 “빈 결과”가 됩니다. 조사 장면에서는 이것이 가장 곤란한 실패 형태입니다.
위처럼 -ErrorAction Stop으로 받은 뒤, FullyQualifiedErrorId가 NoMatchingEventsFound일 때만 삼키는 것이 맞습니다. 메시지 문자열로 판정하면 한국어 환경에서 일치하지 않아 동작하지 않습니다(오류 처리의 사고방식은 “PowerShell의 오류 처리와 재실행 설계”).
4. 현장에서 자주 나오는 조사 레시피
(1) 예기치 않은 재시작·종료
# 41: 정상 종료 없이 재시작됨(Kernel-Power)
# 6008: 예기치 않은 종료(EventLog)
# 1074: 프로세스/사용자에 의한 종료 요청(누가·무엇이 내렸는지)
# 6005/6006: 이벤트 로그 서비스 시작/중지(= 시작/중지 표시)
Get-WinEvent -FilterHashtable @{
LogName = 'System'
ID = 41, 1074, 6005, 6006, 6008
StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, ProviderName,
@{ n = 'Message'; e = { ($_.Message -split "`r?`n")[0] } } |
Sort-Object TimeCreated -Descending | Format-Table -AutoSize
결과 읽는 법. 출력은 TimeCreated / Id / ProviderName / Message(길어서 첫 줄만) 네 열이며, 새로운 순입니다. 볼 것은 한 줄씩의 내용보다, 재시작 한 번에 어떤 ID가 어떤 순서로 늘어서 있는지입니다. 계획된 재시작이면 1074(누군가 요청함) → 6006(이벤트 로그 서비스 중지=정상 종료) → 6005(시작=부팅 완료)가 세트로 나타납니다.
1074는 “누가 재시작을 요청했는지”가 나오는 중요한 이벤트입니다. 여기에 WindowsUpdate나 특정 프로세스 이름이 나오면 원인이 거의 확정됩니다. 41과 6008만 늘어서 있고 1074가 없으면, 전원 차단이나 hang에 의한 비정상 중지를 의심합니다.
(2) 로그온·로그오프 추적(보안 로그)
# 4624: 로그온 성공 / 4625: 로그온 실패 / 4634: 로그오프
# 보안 로그 읽기 권한이 필요함(관리자 권한으로 실행하거나,
# 실행 계정을 Event Log Readers 그룹에 추가해 둔다)
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 4624, 4625, 4634
StartTime = (Get-Date).AddDays(-1)
} | ForEach-Object {
$xml = [xml]$_.ToXml()
$d = @{}
foreach ($n in $xml.Event.EventData.Data) { $d[$n.Name] = $n.'#text' }
[pscustomobject]@{
시각 = $_.TimeCreated
종류 = switch ($_.Id) { 4624 { '로그온 성공' } 4625 { '로그온 실패' } 4634 { '로그오프' } }
사용자 = $d['TargetUserName']
로그온종류 = $d['LogonType'] # 2=대화 3=네트워크 10=RDP
접속원 = $d['IpAddress']
}
} | Where-Object 사용자 -notlike '*$' | Format-Table -AutoSize
여기가 이벤트 데이터를 쓰는 전형입니다. Message를 정규식으로 자르면 OS 언어 설정에 의존하지만, ToXml()의 EventData는 이름으로 참조할 수 있어 한국어 환경이든 영어 환경이든 같은 스크립트가 동작합니다.6
결과 읽는 법. 출력은 시각 / 종류 / 사용자 / 로그온종류 / 접속원 다섯 열입니다([pscustomobject]로 직접 조립하므로 열 이름과 순서도 직접 정합니다). 끝에 Where-Object 사용자 -notlike '*$'를 붙여 컴퓨터 계정(이름이 $로 끝남)을 걸렀으므로, 남는 것은 사람 계정입니다. 로그온종류가 3(네트워크)이나 10(RDP)인 행에서 접속원에 낯선 IP 주소가 없는지, 같은 사용자의 4625(실패)가 짧은 시간에 이어지지 않는지를 봅니다.
감사가 켜져 있지 않으면 이벤트 자체가 기록되지 않는다는 점도 주의합니다. “한 건도 안 나옴”은 “아무 일도 없었다”가 아니라 “기록되지 않았다”일 수 있습니다.
조사 담당자에게 “읽기만” 줍니다. 보안 로그를 읽히려고 관리자 권한을 나눠 주는 것은 피하고 싶습니다. 기본 제공 Event Log Readers 그룹(SID는 S-1-5-32-573)에 계정을 추가하면, 관리자 권한 없이 이벤트 로그를 읽을 수 있게 됩니다.2
# 대상 컴퓨터에서 실행한다(관리자 권한 필요).
# 기본 제공 그룹의 표시 이름은 OS 언어에 따라 바뀔 수 있으므로, SID로 지정하는 편이 확실하다
Add-LocalGroupMember -SID 'S-1-5-32-573' -Member 'EXAMPLE\監査担当'
# 추가됐는지 확인한다
Get-LocalGroupMember -SID 'S-1-5-32-573'
여러 대에 배포하려면 그룹 정책의 “컴퓨터 구성 > 정책 > Windows 설정 > 보안 설정 > 제한된 그룹”, 또는 그룹 정책 기본 설정의 “컴퓨터 구성 > 기본 설정 > 제어판 설정 > 로컬 사용자 및 그룹”을 사용해, 도메인 그룹을 각 서버의 로컬 Event Log Readers에 추가하는 설정을 배포합니다.
채널 단위로 더 좁히고 싶다면 로그마다 액세스 허용(SDDL)을 wevtutil로 확인·변경합니다.2
wevtutil gl Security # 현재 설정을 표시한다(channelAccess가 SDDL)
# wevtutil sl Security /ca:<SDDL> # 변경한다. /ca는 기존 SDDL을 "바꾼다"
/ca는 추가가 아니라 교체입니다. 반드시 wevtutil gl 출력을 적어 둔 뒤에 변경합니다.
(3) 애플리케이션 비정상 종료
# 1000: Application Error(앱 크래시)
# 1026: .NET Runtime(관리 코드 예외에 의한 종료)
# 1001: Windows Error Reporting(장애 버킷 정보)
Get-WinEvent -FilterHashtable @{
LogName = 'Application'
ID = 1000, 1001, 1026
StartTime = (Get-Date).AddDays(-14)
} | Select-Object TimeCreated, Id, ProviderName, Message |
Sort-Object TimeCreated -Descending | Format-List
1000에는 죽은 모듈 이름과 오프셋이, 1026에는 .NET 예외 스택이 들어갑니다. 여기서 감을 잡은 뒤 덤프 분석으로 넘어가는 편이 효율적입니다(“Windows 크래시 덤프 수집 입문”, “WinDbg + SOS로 크래시 덤프 읽기”).
(4) 서비스 중지·재시작
# 7034: 서비스가 예기치 않게 종료 / 7031: 종료 후 복구 동작 / 7045: 새 서비스가 도입됨
Get-WinEvent -FilterHashtable @{
LogName = 'System'
ProviderName = 'Service Control Manager'
ID = 7031, 7034, 7045
StartTime = (Get-Date).AddDays(-30)
} | Select-Object TimeCreated, Id, Message | Format-List
7045(새 서비스 도입)는 의도하지 않은 소프트웨어 도입을 감지하는 용도로도 쓸모 있습니다. Windows 서비스 운영 설계는 “Windows 서비스 만드는 법과 운영“을 참조합니다.
(5) 작업 스케줄러 실행 이력
이 절에서는 XPath를 쓰므로, 먼저 골격을 잡아 둡니다. 이벤트 로그 XPath에서 외울 것은 사실상 두 종류뿐입니다.1
| 작성 | 가리키는 것 | 예 |
|---|---|---|
*[System[ ... ]] |
모든 이벤트에 공통인 항목(이벤트 ID, 시각, 수준, 공급자) | *[System[EventID=41]] |
*[EventData[Data[@Name='항목명']='값']] |
그 이벤트 고유 항목(이름 붙은 이벤트 데이터) | *[EventData[Data[@Name='TaskName']='\夜間集計']] |
이 둘을 and / or로 잇기만 하면 됩니다. 값 비교에는 작은따옴표를 쓰므로, PowerShell 쪽에서는 here-string(@" 〜 "@)에 넣으면 따옴표 중첩으로 고민하지 않아도 됩니다(아래 코드가 그 형태입니다).
직접 조립하기보다 이벤트 뷰어에 쓰게 한 뒤 복사하는 편이 빠르고 확실합니다. “이벤트 뷰어 > (대상 로그를 오른쪽 클릭) > 현재 로그 필터”에서 GUI로 조건을 지정한 다음, 대화 상자의 “XML” 탭으로 전환하면 같은 조건의 쿼리가 XML로 표시됩니다. 그 <Select Path="...">와 </Select> 사이에 끼인 부분이 그대로 -FilterXPath에 넘길 문자열입니다.1
# 【NG】모든 이벤트를 가져온 뒤, 표시용 메시지(언어 의존)로 건다
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-TaskScheduler/Operational'
StartTime = (Get-Date).AddDays(-3)
} -ErrorAction SilentlyContinue |
Where-Object { $_.Message -like '*夜間集計*' }
# 【OK】작업 이름(이벤트 데이터)으로 서버 쪽에서 건다. 빠르고, 언어에도 의존하지 않는다
$xpath = @"
*[System[TimeCreated[timediff(@SystemTime) <= 259200000]]]
and
*[EventData[Data[@Name='TaskName']='\夜間集計']]
"@
Get-WinEvent -LogName 'Microsoft-Windows-TaskScheduler/Operational' `
-FilterXPath $xpath -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, LevelDisplayName, Message | Format-List
timediff는 밀리초 단위로 “지금으로부터 경과 시간”을 지정하는 XPath 함수이며, 259200000은 3일입니다. 작업 이름은 등록 시 전체 경로(루트 바로 아래면 \\작업이름)로 지정합니다. 표시용 Message는 언어 설정에 의존하고, 게다가 클라이언트 쪽 필터가 되므로, 이 글의 방침대로 이벤트 데이터로 걸러 냅니다.
이 로그는 기본값으로 꺼져 있는 경우가 있습니다. 켜는 방법과 작업이 돌지 않을 때의 원인 분리는 “작업 스케줄러 작업이 실행되지 않음·0x1로 끝남“에 정리해 두었습니다.
5. 여러 대·다른 머신의 로그를 조사하기
방법 1: 원격에서 직접 읽기
Get-WinEvent -ComputerName 'srv01' -FilterHashtable @{ LogName='System'; ID=41 } -MaxEvents 10
방법 2: Invoke-Command로 병렬 조회(대수가 많을 때는 이쪽)
$servers = 'srv01', 'srv02', 'srv03'
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-WinEvent -FilterHashtable @{
LogName = 'System'; Level = 1, 2; StartTime = (Get-Date).AddDays(-1)
} -ErrorAction SilentlyContinue |
Select-Object TimeCreated, Id, ProviderName, LevelDisplayName
} | Sort-Object PSComputerName, TimeCreated
Invoke-Command는 여러 컴퓨터에 대해 병렬로 실행됩니다(“PowerShell Remoting(WinRM) 입문”, “PowerShell의 병렬 처리”).
방법 3: .evtx를 채취해 로컬에서 분석하기
현장에서 내보낸 파일을 그대로 읽을 수 있습니다. 네트워크 너머로 여러 번 조회하는 것보다 빠르고, 증적으로도 남습니다.
# 현장에서: wevtutil epl System D:\collect\srv01_System.evtx
Get-WinEvent -Path 'D:\collect\srv01_System.evtx' -FilterXPath "*[System[(Level=1 or Level=2)]]" |
Select-Object TimeCreated, Id, ProviderName, Message
방법 4: Windows 이벤트 전달(WEF) ── 상시 취합하려면 이것입니다. 수집 서버로 각 단말 이벤트를 전달하는 표준 기능이며, 에이전트를 추가로 넣을 필요가 없습니다.5
6. 로그 크기와 보존 기간
“조사하려니 그 시간대 로그가 이미 덮어써져 있었다”는 매우 흔한 실패입니다. 기본 최대 크기는 작은 편이고, 이벤트가 많은 환경에서는 며칠이면 한 바퀴 돕니다.
# 현재 크기 설정과 보존 상황을 확인한다
Get-WinEvent -ListLog 'System', 'Application', 'Security' |
Select-Object LogName, IsEnabled, LogMode,
@{ n='MaxMB'; e={ [math]::Round($_.MaximumSizeInBytes / 1MB, 1) } },
RecordCount, OldestRecordNumber
# 최대 크기를 변경한다(관리자 권한. 예: System 로그를 256MB로)
wevtutil sl System /ms:268435456
조사를 전제로 하는 서버나 장애가 난 단말에서는 먼저 로그 크기를 늘린 뒤에 재현을 기다리는 것이 정석입니다. 로그 세대 관리와 자동 아카이브는 “PowerShell 스크립트 응용 ── 로그 조사·아카이브·리포트화“도 참조합니다.
7. 실무 정석(판단표)
| 상황 | 선택 | 보충 |
|---|---|---|
| 앞으로 작성하는 스크립트 | Get-WinEvent |
Get-EventLog는 5.1 한정·클래식 로그만1 |
| 로그 이름·ID·기간으로 걸러 낸다 | -FilterHashtable |
가장 빠르고, 읽기 쉽다3 |
| 이벤트 데이터 내용으로 걸러 낸다 | -FilterXPath / -FilterXml |
이벤트 뷰어의 사용자 지정 보기에서 복사할 수 있다1 |
| 건수가 많아 시간이 걸린다 | 기간을 좁힌다·-MaxEvents |
필터를 PowerShell 쪽에서 하지 않는다 |
| 메시지에서 값을 꺼내고 싶다 | ToXml()의 EventData |
언어 설정에 의존하지 않는 스크립트가 된다1 |
| 여러 대를 단발 조사 | Invoke-Command |
병렬 실행된다5 |
| 상시 취합 | Windows 이벤트 전달(WEF) | 추가 에이전트가 필요 없는 표준 기능5 |
| 과거 로그가 사라졌다 | 로그 크기 확장 | 재현을 기다리기 전에 해 둔다 |
8. 정리
Get-WinEvent로 통일합니다.Get-EventLog는 PowerShell 7에서 쓸 수 없고, 다룰 수 있는 로그도 한정됩니다.- 필터는
-FilterHashtable또는-FilterXPath로 겁니다.Where-Object로 뒤에서 걸러 내면 조사 시간이 자릿수 단위로 나빠집니다. - 재시작 조사는 41·6008에 더해 1074(누가 요청했는지) 를 봅니다. 앱 비정상 종료는 1000·1026·1001이 출발점입니다.
- 메시지 문자열이 아니라
ToXml()의 이벤트 데이터를 쓰면 언어 설정에 의존하지 않는 스크립트가 됩니다. - 여러 대 단발 조사는
Invoke-Command, 상시 취합은 Windows 이벤트 전달, 증적이 필요하면.evtx채취와 로컬 분석입니다. - 보고 싶은 시간대 로그가 남아 있지 않으면 아무것도 할 수 없습니다. 로그 크기 재검토는 장애 대응 준비로서 최우선입니다.
샘플 코드 다운로드
이 글에서 다룬 코드는 그대로 실행할 수 있는 형태로 묶어 배포합니다. 재시작 이력·로그온 이력·작업 실패·여러 대 수집이 들어 있습니다.
이 글의 샘플은 Windows나 테넌트에 의존하므로 실행 검증은 하지 않았습니다. 구문 분석과 PSScriptAnalyzer 정적 분석까지는 모든 파일에 대해 실시했지만, 동작은 반드시 본인의 검증용 컴퓨터에서 확인합니다.
# 구문 분석 + 정적 분석(Windows 이외에서도 실행할 수 있음)
./Invoke-SampleTests.ps1
시험할 곳이 없다면 업무 단말에서 운영 로그를 상대로 연습할 필요는 없습니다. Windows 샌드박스면 몇 분 만에 깨끗한 Windows를 띄울 수 있고, 닫으면 사라집니다(“Windows Sandbox로 앱 검증을 빠르게 하는 방법”). 다만 샌드박스는 기동 직후 환경이라 로그 축적이 거의 없어, 재시작 이력이나 로그온 이력처럼 “시간이 지나며 쌓이는 로그”를 시험하려면 평가용 가상 머신이 더 맞습니다. 우선 3장의 명령을 본인 단말에서 실행해, 필터 속도 차이를 체감하는 것부터면 충분합니다.
설정값(경로, 서버 이름, 테넌트 ID 등)은 예입니다. 그대로 운영 환경에서 실행하지 말고, 자사 환경에 맞게 바꿔 읽습니다.
관련 기사
- 작업 스케줄러 작업이 실행되지 않음·0x1로 끝남 ── 원인 분리와 안전한 운영 설계
- Windows의 이벤트 로그·ETW와 구조화 로그
- Windows 크래시 덤프 수집 입문 - WER/ProcDump/WinDbg
- PowerShell Remoting(WinRM) 입문 ── 여러 대 Windows를 일괄 관리하기
- Windows 서비스 만드는 법과 운영
- PowerShell 스크립트 응용 ── 로그 조사·아카이브·리포트화를 안전하게 자동화하기
관련 상담 영역
합동회사 코무라소프트에서는 Windows 환경의 장애 조사, 간헐적으로 발생하는 재시작·앱 비정상 종료의 원인 분석, 로그 수집과 감시 체계 구축을 다룹니다.
참고 링크
-
Microsoft Learn, Get-WinEvent. 클래식 로그와 Windows Vista 이후 이벤트 로그를 모두 가져올 수 있다는 점, -ListLog / -ListProvider로 목록을 얻는 점, -FilterHashtable / -FilterXPath / -FilterXml로 걸러 내는 점, -Path로 아카이브된 로그(.evtx)를 읽는 점, -ComputerName으로 원격 수집하는 점, -MaxEvents로 건수를 제한하는 점, 보안 로그를 읽으려면 관리자 권한이 필요하다는 점, 각 이벤트의 ToXml() 메서드로 XML 표현을 얻을 수 있다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15
-
Microsoft Learn, Active Directory security groups ─ Event Log Readers. 기본 제공 Event Log Readers 그룹 구성원이 로컬 컴퓨터의 이벤트 로그를 읽을 수 있다는 점(관리자 권한 부여를 수반하지 않는다는 점)에 대해. 개별 채널 액세스 허용을 바꾸는 방법으로는 wevtutil의 sl /ca(채널 액세스)도 참조. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Creating Get-WinEvent queries with FilterHashtable. -FilterHashtable로 지정할 수 있는 키(LogName·ProviderName·Path·Keywords·ID·Level·StartTime·EndTime·UserID·Data 등), 서버 쪽에서 필터되므로 Where-Object 필터보다 효율적이라는 점, 키워드와 심각도 값 지정 방법에 대해. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Event Levels. 이벤트 심각도 수준의 표준값(1=Critical, 2=Error, 3=Warning, 4=Informational, 5=Verbose)에 대해. ↩ ↩2
-
Microsoft Learn, Windows Event Forwarding. 에이전트를 추가로 넣지 않고 여러 Windows에서 수집 서버로 이벤트를 전달할 수 있다는 점, 구독으로 수집 대상을 지정하는 점에 대해. 아울러 Invoke-Command로 여러 컴퓨터에 병렬 실행하는 점에 대해. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, 4624(S): An account was successfully logged on. 로그온 성공 이벤트의 이벤트 데이터에 포함된 항목(TargetUserName, LogonType, IpAddress 등)과 로그온 종류 값의 의미, 감사 정책 설정에 따라 기록 여부가 바뀐다는 점에 대해. ↩
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
PowerShell 보안 강화 ── 로그·AMSI·언어 모드·JEA
PowerShell을 금지하지 않고 안전하게 쓰기 위한 실무를 정리합니다. 스크립트 블록 로그와 트랜스크립션 활성화, AMSI와 구버전 사용 중지, 언어 모드로 제한하기, JEA로 권한 위임하기까지 설명합니다.
Windows의 이름 확인 순서 ── hosts·DNS 캐시·LLMNR/mDNS·DoH
「이름을 확인할 수 없다」「일부 PC만 연결되지 않는다」는 hosts·DNS 캐시·DNS 서버·LLMNR/mDNS 중 어느 층이 답했는지에 따라 결과가 달라집니다. Windows의 이름 확인 순서와 DoH가 바꾸는 것을 구조부터 정리하고, 층별로...
OneDrive 「파일 온디맨드」와 업무 앱 ── 플레이스홀더가 깨뜨리는 전제와 대책
데스크톱 CSV가 읽히지 않거나 가져오기가 「파일을 찾을 수 없습니다」로 실패한다——원인은 OneDrive의 KFM과 파일 온디맨드일 수 있습니다. 플레이스홀더 구조, 속성 판정, 앱과 정보시스템 양쪽의 대책을 설명합니다.
Windows 보안 감사 정책과 이벤트 로그 조사 실무 ── 4625를 읽는 정보시스템 담당자가 되기
「로그온 실패 로그를 조사해 달라」는 요청에 답하기 위한 실무 가이드입니다. 기본 감사 정책과 고급 감사 정책의 관계, 최소한 활성화해야 할 하위 범주, 이벤트 ID 4624/4625/4688을 읽는 법, Security 로그의 용량 설계, Ge...
Windows 인증서 저장소 실무 가이드 ── 사용자와 컴퓨터, 어느 쪽에 넣을 것인가
클라이언트 인증서는 사용자와 컴퓨터 중 어느 저장소에 넣어야 하는가. certmgr.msc와 certlm.msc의 차이, 비밀 키 권한 부여, PowerShell로 만료를 점검하는 방법까지, 인증서의 단골 사고를 체계적으로 막는 실무 가이드입니다.
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
장애 조사 & 장기 가동 장애
간헐적 장애, 통신 진단, 장기 가동 크래시, 실패 경로 테스트 기반을 정리한 토픽 페이지입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
장애 조사 & 원인 분석
간헐적 장애, 장기 가동 중 크래시, 누수, 통신 중단 등 까다로운 프로덕션 이슈를 조사합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- Get-EventLog와 Get-WinEvent 중 어느 쪽을 써야 하나요?
- Get-WinEvent입니다. Get-EventLog는 Windows PowerShell 5.1에서만 사용할 수 있고, System·Application·Security 같은 클래식 로그만 다룹니다. Windows Vista 이후에 추가된 "응용 프로그램 및 서비스 로그" 아래의 로그, 예를 들어 Microsoft-Windows-TaskScheduler/Operational 같은 상세 로그는 Get-WinEvent가 아니면 읽을 수 없습니다. PowerShell 7에서는 Get-EventLog 자체를 쓸 수 없으므로, 앞으로 작성하는 스크립트는 Get-WinEvent로 통일합니다.
- Get-WinEvent가 너무 느려서 조사가 되지 않습니다.
- 파이프 뒤에서 Where-Object로 걸러내고 있을 가능성이 높습니다. 그 방식은 먼저 로그의 모든 이벤트를 객체로 만들어 PowerShell에 읽은 뒤, 그다음에 불필요한 항목을 버립니다. 수십만 건이면 비현실적입니다. -FilterHashtable이나 -FilterXPath를 쓰면 필터가 이벤트 로그 쪽에서 적용되어 필요한 이벤트만 돌아오므로, 속도가 자릿수 단위로 달라집니다. 먼저 로그 이름·기간·이벤트 ID를 FilterHashtable로 지정하는 습관을 들입니다.
- 보안 로그를 읽으려 하면 액세스가 거부됩니다.
- 보안 로그를 읽으려면 기본적으로 별도의 권한이 필요합니다. 로컬에서 확인만 한다면 PowerShell을 "관리자 권한으로 실행"하면 됩니다. 조사 담당자에게 관리자 권한을 주고 싶지 않다면, 기본 제공 Event Log Readers(이벤트 로그 읽기 권한자) 그룹에 넣거나, 채널 ACL로 읽기만 허용하는 방법이 있습니다. 최소 권한 관점에서는 후자를 권장합니다. 애초에 감사 로그가 기록되지 않은 경우도 있습니다. 로그온 감사 등은 감사 정책 설정에 따르므로, 이벤트가 한 건도 없으면 정책 자체가 켜져 있는지도 확인합니다.
- 이벤트 메시지에서 특정 값(사용자 이름이나 프로세스 이름)만 꺼내고 싶습니다.
- Message 속성을 정규식으로 자르기보다 Properties나 이벤트 데이터를 쓰는 편이 확실합니다. 각 이벤트는 ToXml() 메서드로 XML 표현을 얻을 수 있고, 그 안에 EventData 아래 이름이 붙은 항목이 들어 있습니다. 표시용 메시지 문자열은 OS 언어 설정에 따라 바뀌지만 이벤트 데이터 구조는 바뀌지 않으므로, 한국어 환경과 영어 환경 모두에서 동작하는 스크립트를 작성할 수 있습니다.
- 여러 대 서버의 이벤트 로그를 한꺼번에 조사하고 싶습니다.
- 대수가 적으면 Get-WinEvent의 -ComputerName 매개변수나 Invoke-Command 원격 실행으로 충분합니다. Invoke-Command는 지정한 여러 대에 대해 병렬로 실행되므로 수십 대 정도면 실용적입니다. 상시 취합하려면 Windows 이벤트 전달(WEF)로 수집 서버에 모으는 구성을 검토합니다. 단발 조사라면 각 서버에서 evtx 파일을 내보낸 뒤, 로컬에서 Get-WinEvent -Path로 분석하는 방법도 유효합니다.