어떤 수업을 찾고 있나요?

예: PowerShell, 네트워크, XSS, Step 138

전체 커리큘럼 둘러보기 →

PowerShell

Step 4. 텍스트 처리 — 로그에서 바늘 찾기

Step 4예상 실습 시간 · 2~3시간

Level 0 — 컴퓨터 조작과 구조의 이해 | 난이도 ★★☆☆☆ | 예상 소요 시간 2~3시간

전제: Step 3 완료 (파이프). 윈도우 파워쉘에서 진행합니다.

  • 준비물: 윈도우 PC, 파워쉘.
  • 안전: 오늘은 새 전용 폴더에서만 연습 파일과 보고서를 만듭니다. 같은 이름의 출력 파일은 덮어쓸 수 있으므로 실제 로그나 개인 문서를 사용하지 않습니다. 연습 파일은 직접 만들어 씁니다 — 50줄짜리 가짜 로그를 만들고 그 안에서 수사 연습을 합니다.
  • 주의: 한글이 깨지는 사건을 만날 수 있습니다. 당황하지 마세요 — 오늘 그 원인(인코딩)까지 정복합니다.

오늘의 주인공은 "로그"입니다. 로그인 성공/실패, 프로그램 오류, 접속 이력 등은 설정에 따라 로그로 남을 수 있습니다. 로그에는 텍스트, Windows 이벤트 로그, 데이터베이스 등 여러 저장 형식이 있습니다. 오늘은 직접 만든 텍스트 로그만 다룹니다. 사고 조사는 "ERROR가 든 줄만 보여 줘" 한 줄로 시작해서, 몇만 줄이 몇십 줄로 줄어들며 이야기가 보이기 시작합니다. 오늘 배우는 "텍스트에서 원하는 줄 뽑기"는 보안 분석의 알파이자 오메가입니다.


1. 학습 목표

이 챕터를 끝내면 다음을 할 수 있습니다:

  • Get-Content로 파일을 읽고, 긴 파일은 앞부분만 슬쩍 본다
  • Select-String으로 원하는 단어가 든 줄만 골라낸다
  • 결과 건수를 세고, 결과를 새 파일로 저장해 "조사 문서"를 만든다
  • 파일명:줄번호:내용 형식으로 여러 파일을 한꺼번에 수사한다
  • 한글 깨짐의 원인(인코딩 불일치)을 설명하고 -Encoding으로 대응한다

2. 배경 지식 — 오늘의 도구와 개념

오늘의 도구 한눈에 보기

구분 내용
언어·환경 Windows PowerShell 5.1 / PowerShell 7, 텍스트 로그 처리
오늘의 명령어 Get-Content(읽기), Select-String(검색), Measure-Object(개수), Out-File(저장)
오늘의 옵션 -TotalCount(앞부분만), -Path/-Pattern(검색 대상/패턴), -Encoding(인코딩 지정)
필요한 개념 텍스트 파일 = 줄의 나열, 인코딩(글자↔숫자 변환표), 패턴 안의 |(또는)

오늘 배우는 명령들을 사건 현장의 언어로 번역하면 이렇습니다: Select-String은 "수만 줄의 로그에서 수상한 줄만 낚는" 침해 조사의 1번 공구, Measure-Object는 "새벽 2~4시에 실패 로그인 300건" 같은 문장을 만드는 도구, Out-File -Encoding utf8은 "읽을 수 있는 분석 결과 파일을 만드는" 도구입니다. 보안 담당자의 일상은 거창한 해킹 도구보다, 오늘 같은 명령들로 로그와 씨름하는 시간이 훨씬 깁니다.

2-1. 텍스트 파일의 구조 — "줄"이 단위다

텍스트 파일은 안을 열어 보면 결국 줄(line)의 나열입니다. 그리고 오늘 배우는 도구들은 전부 "줄 단위"로 일합니다:

  • Get-Content: 파일을 줄들의 목록으로 읽어 온다 (한 줄 = 객체 하나)
  • Select-String: 각 줄을 검사해서 조건에 맞는 줄만 골라낸다

Step 3에서 "목록 → 필터"를 배웠죠? 텍스트 처리도 정확히 같은 사고입니다. 재료가 프로세스에서 "줄"로 바뀌었을 뿐입니다.

2-2. 인코딩 — 글자를 숫자로 바꾸는 변환표

컴퓨터는 글자를 저장할 수 없습니다. 숫자만 저장할 수 있죠. 그래서 "글자 ↔ 숫자" 변환표가 필요하고, 그 표가 인코딩입니다.

문제는 이 표가 여러 종류라는 겁니다:

인코딩 특징
UTF-8 현재 세계 표준. 한글/영문/이모지 전부 표현
UTF-16 윈도우 내부에서 자주 쓰는 방식
EUC-KR / CP949 옛날 한국 윈도우 표준

한글이 깨지는 원인 중 하나: 파일은 A표(예: UTF-8)로 숫자화해서 저장했는데, 읽는 프로그램이 B표(예: CP949)로 해석하는 경우입니다. 같은 숫자인데 다른 표로 읽으니 글자가 괴상해지는 겁니다. 암호를 열쇠가 다른 자물쇠로 여는 것과 같습니다.

해결책: 읽을 때 "이 표로 읽어라"를 명시하는 것. 오늘 실습합니다.


3. 따라 하기

3-1. 수사 현장 준비 — 가짜 로그 만들기

Step 2처럼 고유 이름의 새 폴더를 만들고, 결과 파일은 그 안의 reports에 저장합니다. $textlab에 저장된 경로를 기록하세요. 모든 IP와 계정은 가짜 로그 문자열이며 네트워크에 접속하는 명령은 없습니다:

$textlab = Join-Path $HOME ('infosec-step04-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $textlab -ErrorAction Stop
Set-Location -LiteralPath $textlab
New-Item -ItemType Directory reports
pwd

이제 50줄짜리 로그를 만듭니다. 메모장으로 해도 되지만, 우리는 CLI 연습 중이니 파워쉘로 만듭니다. 아래를 통째로 복사해서 파워쉘에 붙여넣으세요 (여러 줄이 한 번에 실행됩니다):

1..50 | ForEach-Object {
  $m = "{0:D2}" -f $_
  if ($_ % 7 -eq 0) { "2026-09-08 02:$m ERROR failed login: admin from 10.9.9.9" }
  elseif ($_ % 5 -eq 0) { "2026-09-08 02:$m WARNING disk usage high" }
  else { "2026-09-08 02:$m INFO normal operation" }
} | Set-Content log.txt -Encoding UTF8

이 반복 문법은 Step 8에서 배웁니다. 마지막 Set-Content가 이 연습의 log.txt를 50줄로 교체하므로 생성 블록을 다시 실행해도 100줄로 누적되지 않습니다. 생성 순서가 시각 순서와 일치하도록 모두 02시의 로그로 만들었습니다. "7번째 줄마다 ERROR, (7의 배수가 아닌) 5번째 줄마다 WARNING, 나머지는 INFO를 넣은 50줄 파일"이라는 것만 알면 됩니다.

확인:

Get-Content log.txt -Encoding UTF8 -TotalCount 8
2026-09-08 02:01 INFO normal operation
2026-09-08 02:02 INFO normal operation
2026-09-08 02:03 INFO normal operation
2026-09-08 02:04 INFO normal operation
2026-09-08 02:05 WARNING disk usage high
2026-09-08 02:06 INFO normal operation
2026-09-08 02:07 ERROR failed login: admin from 10.9.9.9
2026-09-08 02:08 INFO normal operation
  • -TotalCount 8 — "전부 말고 앞 8줄만." 긴 파일을 슬쩍 볼 때 쓰는 옵션입니다.

3-2. 전체 읽기와 문제 상황 — Get-Content

전부 읽어 봅시다:

Get-Content log.txt -Encoding UTF8

50줄이 와르르 지나갑니다. 지금이야 50줄이지만, 실제 로그는 5만 줄입니다. "전체를 눈으로 읽는다"는 선택지에 없다는 걸 체감하세요. 그래서 다음 기계가 필요합니다.

3-3. 수사 개시 — Select-String

Get-Content log.txt -Encoding UTF8 | Select-String "error"
2026-09-08 02:07 ERROR failed login: admin from 10.9.9.9
2026-09-08 02:14 ERROR failed login: admin from 10.9.9.9
...

"error"가 들어간 줄만 골라졌습니다. Step 3의 Where-Object와 같은 역할인데, 텍스트 검색 전용이라 더 간단합니다.

잠깐 — 방금 전 "ERROR"(대문자)로 저장했는데 왜 "error"(소문자)로 검색해서 걸렸을까요? Select-String은 기본적으로 대소문자를 구분하지 않습니다. (구분하고 싶으면 -CaseSensitive 옵션.)

더 짧게도 됩니다 — Select-String은 파일 경로를 직접 받을 수 있습니다:

Select-String -Path log.txt -Pattern "error" -Encoding UTF8
  • -Path — 검색할 파일
  • -Pattern — 기본적으로 정규표현식 패턴. 점(.) 같은 문자를 이름 그대로 찾으려면 -SimpleMatch를 함께 사용합니다.

3-4. 몇 건이나? — 세어 보기

공격 규모를 파악할 때 개수가 중요합니다:

Select-String -Path log.txt -Pattern "error" -Encoding UTF8 | Measure-Object
Count    : 7

여기서 Count는 ERROR에 일치한 줄 수입니다. 한 줄 안의 단어 발생 횟수나 고유 공격 사건 수와는 다릅니다. 7의 배수 줄에 ERROR가 들어갔으니 7줄입니다. "ERROR가 7건" — Step 3에서 배운 Measure-Object가 여기서도 그대로 쓰입니다. 조립 사고, 기억하시죠?

예측해 보기: Select-String -Path log.txt -Pattern "WARNING"은 몇 줄이 나올까요? 예측하고 실행해 보세요.
(정답: 9줄. 5의 배수는 10개(5,10,…,50)지만, 35는 7의 배수라 ERROR 칸으로 빠졌습니다. 생성 규칙을 떠올리며 확인해 보세요 — 이런 "조건이 겹치면 어떻게 되지?"를 의심하는 게 분석가의 감각입니다.)

3-5. 분석 결과 저장 — Out-File

검색 결과는 MatchInfo 객체입니다. 바로 Out-File에 넘기면 파일명·줄번호와 표시용 공백이 함께 저장될 수 있습니다. 이번에는 Select-Object -ExpandProperty Line으로 원래 줄 내용만 뽑아 저장합니다. 한 줄에 결과 한 개가 들어가도록 출력 형식을 명확히 정합니다:

Select-String -Path log.txt -Pattern "error" -Encoding UTF8 |
  Select-Object -ExpandProperty Line |
  Out-File .\reports\errors.txt -Encoding UTF8
Get-Content .\reports\errors.txt -Encoding UTF8
2026-09-08 02:07 ERROR failed login: admin from 10.9.9.9
...

화면 대신 reports\errors.txt에 기록됐고, 다시 읽어 확인했습니다. 이 흐름:

검색(Select-String) → 저장(Out-File) → 검증(Get-Content)

reports\errors.txt는 원래 줄 내용 7줄이어야 합니다. 보고서 파일은 다시 실행하면 덮어씁니다. 이 평문 출력에서는 검색 결과의 원본 파일 경로와 줄번호가 제외되므로, 실제 조사에서는 출처와 수집 시각을 별도로 보존해야 합니다.

3-6. 인코딩을 다르게 읽어 보기

아래 준비 코드는 BOM이 없는 UTF-8 파일을 만듭니다. 문장은 “비밀번호 초기화 필요”입니다. BOM은 파일 앞에서 인코딩을 알려 주는 표식이며, 자동 감지가 실험을 가리지 않도록 여기서는 제외합니다. .NET 생성 문법은 지금은 준비 코드로 사용해도 됩니다.

$utf8NoBom = [Text.UTF8Encoding]::new($false)
[IO.File]::WriteAllText((Join-Path $textlab 'korean.txt'), '비밀번호 초기화 필요', $utf8NoBom)
Get-Content korean.txt -Encoding ASCII
Get-Content korean.txt -Encoding UTF8

ASCII로 읽은 결과에서는 한글이 제대로 표현되지 않고, UTF8로 읽으면 원문이 나와야 합니다. 읽는 방법을 바꾸는 것은 파일 자체를 변환하거나 고치는 작업이 아닙니다. 원본이 이미 물음표로 덮어써졌다면 인코딩 옵션만 바꾸어 잃은 글자를 복구할 수 없습니다.

새 파일은 읽기와 쓰기 인코딩을 맞춥니다. 기존 파일은 생성 프로그램의 설정, 형식 문서, BOM 등으로 실제 인코딩을 확인한 뒤 사본에서 읽으세요. UTF8은 5.1에서 BOM 포함, 7에서 기본 BOM 없음이라는 차이가 있습니다. -Encoding Default는 두 버전에서 공통으로 쓸 수 있는 처방이 아닙니다.

3-7. 여러 파일을 한꺼번에 수사

Select-String의 진짜 강력함은 여기 있습니다:

Set-Content other.txt "2026-09-08 05:00 ERROR sample service failure" -Encoding UTF8
Select-String -Path .\*.txt -Pattern "error" -Encoding UTF8

other.txt에 가짜 ERROR 한 줄을 추가했습니다. 현재 폴더의 .txt 파일을 검색하면 log.txt의 7줄과 other.txt의 1줄, 총 8줄이 일치합니다. reports 하위 폴더는 이 검색에 포함되지 않습니다. 출력 형식 예시:

log.txt:7:2026-09-08 02:07 ERROR failed login: admin from 10.9.9.9
log.txt:14:2026-09-08 02:14 ERROR failed login: admin from 10.9.9.9
...

읽는 법: 파일명:줄번호:내용. 이 기능 덕분에 수백 개 로그 파일을 한 방에 수사할 수 있습니다.


4. 미션과 연습문제

미션 — 로그 분석관의 하루

사건: "우리 서버 로그에서 수상한 활동을 찾아 보고서로 제출하라"는 지시를 받았습니다. 이번에 만든 $textlab 폴더에서 진행하세요. 미션은 다른 파일을 포함하지 않고 log.txt 하나만 분석합니다. 저장 시 원래 줄 내용만 뽑고 UTF8을 명시하세요.

  1. log.txt에서 "WARNING"이 든 줄만 뽑아 reports\warnings.txt로 저장하세요.
  2. "ERROR"와 "WARNING"을 합쳐서 총 몇 건인지 계산하세요. (힌트: 패턴을 "ERROR|WARNING"처럼 쓰면 한 번에 검색됩니다 — 패턴 안의 |는 "또는"이라는 뜻. 쳐 보세요!)
  3. 두 종류를 합친 결과를 reports\incidents.txt로 저장하세요. (UTF-8 인코딩 지정 습관!)
  4. 보고서 검증: Get-Content .\reports\incidents.txt -Encoding UTF8 -TotalCount 3으로 앞 3줄이 잘 저장됐는지 확인하세요.
  5. 생각해 보기: 만약 실제 서버 로그가 10만 줄이라면, 오늘 배운 명령 중 어떤 것부터 치겠습니까? 순서를 말로 정리해 보세요.

연습문제

문제 1. log.txt에서 "INFO"가 든 줄은 총 몇 줄일까요? (50줄 중 ERROR 7줄, WARNING 9줄)

문제 2. Select-String -Path log.txt -Pattern "ERROR|WARNING"의 결과 건수는? 패턴 안의 |는 무슨 뜻인가요?

문제 3. 인터넷에서 받은 한글 텍스트 파일을 열었더니 비?번호처럼 깨져 보입니다. 원인과 처방 한 가지를 말하세요.

문제 4. Select-String -Path *.txt -Pattern "error"의 결과에서 log.txt:7:2026-09-08...은 어떻게 읽나요?


해설과 완료 기준 · 펼치기/접기

5. 모범 답안과 완료 기준

미션 해설

# 1
Select-String -Path log.txt -Pattern "WARNING" -Encoding UTF8 |
  Select-Object -ExpandProperty Line |
  Out-File .\reports\warnings.txt -Encoding UTF8
# 2: Count = 16
Select-String -Path log.txt -Pattern "ERROR|WARNING" -Encoding UTF8 | Measure-Object
# 3
Select-String -Path log.txt -Pattern "ERROR|WARNING" -Encoding UTF8 |
  Select-Object -ExpandProperty Line |
  Out-File .\reports\incidents.txt -Encoding UTF8
# 4
Get-Content .\reports\incidents.txt -Encoding UTF8 -TotalCount 3

5번 생각해 보기의 모범 답: "전체를 읽지 않는다"가 출발점입니다. ① Get-Content -TotalCount로 형식부터 파악하고, ② Select-String으로 의심 패턴("failed", "ERROR")을 좁히고, ③ Measure-Object로 규모를 재고, ④ 결과를 Out-File로 남깁니다. 좁히기 → 세기 → 기록하기, 이 순서가 10만 줄에서도 똑같이 작동합니다.

연습문제 해답

문제 1 해답. 50 − 7 − 9 = 34줄입니다. 명령으로 확인: Select-String -Path log.txt -Pattern "INFO" | Measure-Object → Count 34.

문제 2 해답. 16건 (ERROR 7 + WARNING 9). 패턴 안의 |는 "또는(or)"이라는 뜻의 정규표현식 기호입니다 — "ERROR 또는 WARNING이 든 줄"을 한 번에 검색합니다.

문제 3 해답. 원인 후보는 인코딩 불일치, 지원하지 않는 글꼴, 이미 손상된 원본 등입니다. 생성 프로그램의 설정 등으로 실제 인코딩을 확인하고 사본을 맞는 인코딩으로 읽습니다. UTF-8 파일이라면 Get-Content 파일 -Encoding UTF8입니다. 정상처럼 보인다는 이유만으로 인코딩을 확정하거나 원본을 덮어쓰지 않습니다.

문제 4 해답. 파일명:줄번호:내용 — "log.txt 파일의 7번째 줄에서 찾았고, 그 줄의 내용은 이렇다"라는 뜻입니다. 여러 파일을 동시 수사할 때 어느 파일의 어디인지가 바로 보이는 것이 이 형식의 힘입니다.

완료 기준 체크리스트

  • [ ] Get-Content로 파일을 읽고 -TotalCount로 앞부분만 볼 수 있다
  • [ ] Select-String으로 특정 단어가 든 줄만 골라낼 수 있다
  • [ ] 파일명:줄번호:내용 형식을 읽을 수 있다
  • [ ] Measure-Object로 건수를 셀 수 있다
  • [ ] 결과를 Out-File로 저장하고 검증할 수 있다
  • [ ] 한글 깨짐의 원인(인코딩 불일치)과 대응(-Encoding)을 안다
  • [ ] 미션 1~5를 완료했다

6. 흔한 실수와 해결

벽 1. 한글이 □□ 또는 이상한 글자로 깨져 나온다

인코딩 불일치뿐 아니라 글꼴이나 원본 손상도 확인합니다. 원본을 보존하고 생성 프로그램의 인코딩 설정을 확인하세요. 읽기 옵션만 바꾸는 것은 원본을 변환하지 않습니다. 이미 글자가 손실된 파일은 원본이나 백업을 다시 받아야 할 수 있습니다.

벽 2. Select-String 결과가 내가 저장한 결과 파일까지 포함한다

검색 대상 폴더에 이전에 저장한 결과 파일(errors.txt 등)이 있으면, 그 파일도 다시 검색 대상이 되어 결과가 부풀려집니다 (그래서 이 수업은 결과를 reports 하위 폴더에 저장합니다). 수사 결과는 되도록 다른 폴더에 저장하는 습관을 들이세요.

벽 3. Out-File로 저장했는데 한글이 깨진다

Out-File도 인코딩 기본값이 환경에 따라 다릅니다. 새 파일은 Out-File 파일 -Encoding utf8로 저장하고 같은 인코딩으로 읽습니다. 이미 잘못 해석된 문자를 UTF8로 저장하는 것만으로 원문이 복원되지는 않습니다.

벽 4. 찾는 단어가 분명 있는데 안 걸린다

① 철자 확인, ② -CaseSensitive를 붙였다면 대소문자까지 같아야 합니다 (error ≠ ERROR), ③ 파일 인코딩이 특수해서 검색이 실패하는 경우 — -Encoding을 지정해 읽은 뒤 파이프로 넘기세요: Get-Content 파일 -Encoding UTF8 | Select-String "단어".

벽 5. 결과가 너무 길어서 처음이 잘렸다

| Out-File로 저장하고 파일로 보거나, Step 3의 부품을 조합하세요: ... | Select-Object -First 20. 결과가 길수록 "자르기" 습관이 빛납니다.


7. 정리

오늘 배운 명령어

명령 하는 일 예
Get-Content 파일 읽기 Get-Content log.txt -TotalCount 10
Select-String 패턴 든 줄 골라내기 Select-String -Path log.txt -Pattern "error"
Measure-Object 개수 세기 ... | Measure-Object
Out-File 결과를 파일로 저장 ... | Out-File result.txt -Encoding utf8

핵심 개념

개념 한 줄 요약
텍스트 파일 = 줄의 나열 도구들은 "줄 단위"로 일한다
인코딩 글자↔숫자 변환표. 인코딩 불일치는 글자 깨짐의 원인 중 하나
-Encoding 읽기/쓰기 표 명시 (UTF-8 습관화)
결과 형식 파일명:줄번호:내용 — 수사의 단서

명령어보다 중요한 감각

"전체를 읽지 마라. 골라낼 조건을 먼저 정하라." 10만 줄의 로그도 "실패한 로그인만", "그 IP에서 온 것만"으로 좁히면 이야기가 됩니다. 그리고 결과는 반드시 파일로 남겨라 — 조사는 기록될 때 비로소 보고서가 됩니다.

알아두면 좋은 것 두 가지: Select-String의 -Pattern 자리는 사실 정규표현식(regex)이라는 패턴 언어를 받습니다 — Level 1에서 정식으로 배우는 텍스트 처리의 끝판왕입니다. 그리고 이 기술은 리눅스에서도 거의 그대로 씁니다. grep도 같은 사고방식으로 사용하지만 옵션과 정규표현식 문법·출력 객체가 다르므로 명령을 그대로 바꿔 쓸 수는 없습니다. "패턴으로 줄을 낚는다"는 사고방식은 모든 운영체제에서 통하는 만국 공용어입니다.


전부 체크되면 Step 4 완료입니다.


실습 검증 기록

2026-09-10 · Windows 11, Windows PowerShell 5.1.26100.9444와 PowerShell 7.6.5에서 가짜 로그 생성부터 보고서 저장까지 순서대로 실행했습니다. log.txt 50줄, ERROR 7줄, WARNING 9줄, INFO 34줄, 합산 보고서 16줄을 확인했습니다. 생성 코드 재실행, 결과 파일 검색 제외, 한글 UTF8 읽기, 잘못된 ASCII 해석도 확인했습니다. 실제 운영 로그나 개인정보는 사용하지 않았습니다.

참고: Microsoft Select-String · Out-File · Character encoding

한 단계 더 가까이

수업을 마쳤나요?

본문의 완료 기준을 확인한 뒤 직접 표시하세요.

화면이나 링크에 문제가 있나요? 알려주세요.
다음 수업