홈시리즈멘토링

© 2026 정기창. All rights reserved.

본 블로그의 콘텐츠는 CC BY-NC-SA 4.0 라이선스를 따릅니다.

☕후원하기소개JSON Formatter러닝 대기질개인정보처리방침이용약관

© 2026 정기창. All rights reserved.

콘텐츠: CC BY-NC-SA 4.0

☕후원하기
소개|JSON Formatter|러닝 대기질|개인정보처리방침|이용약관

Vrew autosave_backup 96GB 자동 정리 — Windows 자동화 함정 5가지

정기창·2026년 5월 26일

96.5GB 라는 숫자를 본 순간

한 Windows PC 를 점검할 일이 있었습니다. 평소에 영상 편집을 자주 하시는 분이었고, C 드라이브 여유가 점점 줄어드는데 어디서 누적되는지 모르겠다는 모호한 호소가 시작이었습니다. 처음에는 Windows Update 캐시나 Recycle Bin 정도를 의심했는데, %APPDATA% 폴더를 열어본 순간 위화감이 들었습니다. vrew 한 폴더가 96.5GB 를 점유하고 있었습니다.

프로그램 하나가 OS 드라이브 절반을 먹는다는 사실이 어색했습니다. 일단 폴더를 분해해보기로 했습니다.

autosave_backup 의 정체

PowerShell 로 하위 폴더를 용량 순으로 정렬해봤습니다.

Get-ChildItem "$env:APPDATA\vrew" -Directory |
    ForEach-Object {
        $size = (Get-ChildItem $_.FullName -Recurse -File -ErrorAction SilentlyContinue |
            Measure-Object -Property Length -Sum).Sum
        [PSCustomObject]@{
            Folder = $_.Name
            SizeGB = [math]::Round($size / 1GB, 2)
        }
    } | Sort-Object SizeGB -Descending

결과는 다음과 같았습니다.

하위 폴더

용량

정체

autosave_backup/

48.5 GB

Vrew 자동저장 백업 (.vrew 12 개, 영상 raw 내장)

File System/

31.7 GB

Electron Chromium File System API blob

IndexedDB/

18.1 GB

Electron IndexedDB (STT, 썸네일 메타)

Cache/ 외

~500 MB

Chromium 렌더 캐시 + ffmpeg 바이너리

가장 큰 덩어리는 autosave_backup 이었고, .vrew 파일 12 개의 평균 크기가 한 개당 4GB 였습니다. Vrew 의 .vrew 포맷이 영상 원본을 그대로 내장하는 구조라는 점이 그제서야 분명해졌습니다. 자동 저장이 한 번 일어날 때마다 영상 raw 가 통째로 한 벌 더 쌓이는 셈입니다.

공식이 안 주는 옵션

처음에는 Vrew 안에 보관 개수나 주기 설정이 있을 거라고 생각했습니다. 메뉴를 다 뒤져봤지만 [도움말] → [설정] → [백업 파일 삭제] 라는 전체 삭제 버튼 하나뿐이었습니다. 일부만 남기고 정리하는 옵션도, 자동 저장을 끄는 옵션도, 주기를 늘리는 옵션도 없었습니다.

같은 문제로 막힌 사람이 또 있는지 검색해봤습니다. Google 검색 결과에 Vrew 공식 Q&A 의 “자동 저장&캐시 설정 요청” 이라는 제목 글이 잡혀고, 답변 스니펫에 “검토 중” 이라는 표현이 언뜻 보였습니다. 시점상 가까운 시일 안에 구현될 것 같지는 않다는 인상이었습니다. 같은 검색 결과에 “100G가 순식간에 없어짐” 같은 제목도 잡혔습니다. 다들 같은 문제로 막혀 있는 모양이었습니다. Q&A 게시판 본문 자체는 비로그인 상태에서 열리지 않아 스니펫 수준으로만 확인했습니다.

공식이 옵션을 줄 때까지 기다릴 수도 있겠지만, 그 사이 디스크는 계속 차오릅니다. 외부에서 한 겹 덮어두는 쪽이 합리적이라는 결론이 들었습니다.

자동 저장 주기 실측

스크립트를 짜기 전에 한 가지가 걸렸습니다. 자동 저장 주기가 어느 정도인지 공식 문서에 명시가 없다는 점이었습니다. 5 분인지 10 분인지, 변경 이벤트 기반인지 알 수 없으면 "active 한 백업까지 같이 지워버리는" 사고가 날 수 있습니다.

그래서 같은 폴더의 .vrew 12 개에 대해 LastWriteTime gap 을 계산해봤습니다. 같은 세션으로 추정되는 60 분 이내 gap 만 골라 정리한 결과는 다음과 같았습니다.

n = 7 (same-session gap, ≤ 60 min)
min  =  1.8 분
max  = 51.9 분
avg  = 23.2 분

5 분 / 10 분 같은 고정 주기가 아니었습니다. 영상 편집 중 변경이 누적되면 다양한 간격으로 백업이 떨어지는 모양이었습니다. 가장 긴 gap 이 약 52 분이라는 점이 다음 설계의 기준이 되었습니다.

스크립트 설계 — 이중 가드 + OS file lock 3 겹

삭제 조건을 다음 한 줄로 잡았습니다.

삭제 = (mtime ≥ OlderThanHours 시간)
       AND (최근 KeepCount 개 보존 후보 아님)
       AND OS file lock 실패 시 catch + skip

세 겹의 이유는 각각 다음과 같습니다.

가드

default

이유

-OlderThanHours

1 시간

active session 의 백업 회피. 실측 max 51.9 분 대비 약 16% 마진

-KeepCount

3

크래시 복구 보험. 시간 룰을 통과해도 최근 3 개는 무조건 보존

OS file lock

자동

Vrew 가 쥐고 있는 파일은 Remove-Item 자체가 실패. try/catch 후 skip 로그

OS file lock 이 사실상 마지막 안전망입니다. 시간 가드와 KeepCount 가 둘 다 뚫려도, Vrew 가 현재 쓰고 있는 파일은 Windows 가 막아주기 때문에 "활성 백업을 지우는" 사고는 구조적으로 일어나기 어렵습니다.

Task Scheduler 에 매 30 분 등록

한 번 정리해서 끝낼 일이 아니라 매번 차오를 일이었습니다. Task Scheduler 로 30 분 간격 실행을 잡았습니다.

$trigger = New-ScheduledTaskTrigger -Daily -At (Get-Date).Date.AddHours(9)
$trigger.Repetition = (New-ScheduledTaskTrigger -Once -At (Get-Date).Date.AddHours(9) `
    -RepetitionInterval (New-TimeSpan -Minutes 30) `
    -RepetitionDuration (New-TimeSpan -Hours 24)).Repetition

매일 오전 9 시 트리거가 갱신되고, 그 트리거가 24 시간 동안 30 분 간격으로 반복합니다. 결과적으로 사실상 영구 30 분 반복과 동등합니다. 왜 이렇게 우회한 패턴이 필요했는지는 함정 섹션에서 다시 다루겠습니다.

실증된 함정 5 가지

여기서부터가 이 글의 진짜 가치라고 생각합니다. 큰 그림은 평범한 스크립트 + 스케줄러였지만, 작은 가장자리에서 다섯 번 막혔습니다. 다음에 같은 작업을 하실 분을 위해 적어둡니다.

함정 1 — PowerShell 5.1 의 BOM 의존성

Windows 10 / 11 에 기본 설치된 PowerShell 5.1 은 .ps1 파일에 UTF-8 BOM 이 없으면 시스템 default 인코딩으로 fallback 합니다. 한국 환경에서는 CP949 입니다. 한글 주석이나 문자열을 CP949 로 해석하다가 깨지면, 깨진 바이트가 PowerShell 파서에게 정체 모를 토큰으로 보입니다.

증상은 이렇게 나옵니다.

식 또는 문에서 예기치 않은 'MB' 토큰입니다.
식 또는 문에서 예기치 않은 'DEL:' 토큰입니다.

실제 코드 안에 MB 토큰은 없습니다. 한글 문자열이 깨지면서 우연히 만들어진 바이트 시퀀스를 파서가 그렇게 읽은 것입니다. 처음 봤을 때는 어디가 잘못된지 짚기 어려웠습니다.

흥미로운 점은 같은 파일을 iwr <raw URL> | iex 로 받아서 실행하면 잘 동작했다는 것입니다. Invoke-WebRequest 경로는 HTTP 응답을 UTF-8 로 처리하기 때문에 BOM 유무에 영향을 받지 않습니다. 문제는 파일을 직접 전송했을 때 (Taildrop, USB, OneDrive 등) 발생합니다. fix 는 단순합니다.

{ printf '\xef\xbb\xbf'; cat vrew-cleanup.ps1; } > new.ps1 \
  && mv new.ps1 vrew-cleanup.ps1

확인은 file 명령으로 합니다.

file vrew-cleanup.ps1
# 기대: UTF-8 (with BOM) text

함정 2 — Task Scheduler RepetitionDuration out of range

처음에는 "사실상 영구 반복" 을 표현하기 위해 [TimeSpan]::MaxValue 나 New-TimeSpan -Days 36500 을 넣어봤습니다. 둘 다 다음과 같이 실패합니다.

Register-ScheduledTask : The task XML contains a value
which is incorrectly formatted or out of range.

Task Scheduler 내부의 XML 스키마가 허용하는 Duration 의 상한을 넘는 값이라 그렇습니다. 검색을 좀 해보다가 결국 다음 패턴으로 우회했습니다.

$trigger = New-ScheduledTaskTrigger -Daily -At (Get-Date).Date.AddHours(9)
$trigger.Repetition = (New-ScheduledTaskTrigger -Once -At (Get-Date).Date.AddHours(9) `
    -RepetitionInterval (New-TimeSpan -Minutes 30) `
    -RepetitionDuration (New-TimeSpan -Hours 24)).Repetition

Daily 트리거가 매일 새로 살아나면서 24 시간 안에 30 분 간격으로 반복하므로, 효과적으로는 영구 30 분 반복과 같아집니다. 위 도입부에서 우회 패턴을 먼저 보인 이유가 여기에 있습니다.

함정 3 — Private repo + Invoke-WebRequest 401/404

install 스크립트 안에서 Invoke-WebRequest 로 GitHub raw URL 의 .ps1 을 받아오는 흐름을 짰는데, private repo 일 때는 인증 헤더가 없어서 404 가 돌아옵니다. 처음에는 401 을 기대했지만 GitHub 의 raw 도메인은 private 자원에 대해 의도적으로 404 를 응답합니다. (resource 존재 자체를 가리기 위함입니다.)

이 시점에는 레포가 아직 private 였습니다. 해결은 "원격 다운로드를 항상 시도하기 전에 같은 디렉토리의 sibling .ps1 부터 본다" 였습니다.

$siblingScript = Join-Path $PSScriptRoot 'vrew-cleanup.ps1'

if (Test-Path $siblingScript) {
    # 로컬 sibling 사용 (Taildrop / USB / 오프라인 호환)
    $scriptPath = $siblingScript
} else {
    # public 일 때만 원격 다운로드 fallback
    Invoke-WebRequest -Uri $ScriptUrl -OutFile $localPath -UseBasicParsing
    $scriptPath = $localPath
}

$PSScriptRoot 를 활용하면 install 스크립트와 같은 폴더에 있는 .ps1 을 안전하게 가리킬 수 있습니다. 결과적으로 private 여부와 무관하게 동작하는 install 스크립트가 됐습니다.

함정 4 — bash echo 의 \v 함정

이 함정은 한참을 헤맸습니다. macOS 에서 PowerShell 명령을 base64 로 인코딩해 Windows 로 던지는 흐름이 있었는데, 그 안에 $env:APPDATA\vrew 같은 경로 문자열이 들어 있었습니다.

echo 의 escape 해석에서 \v 가 vertical tab (ASCII 0x0B) 으로 치환됩니다. Roaming\vrew 가 Roaming<VT>rew 로 깨지고, 그걸 받은 PowerShell 은 경로를 인식하지 못 합니다. 처음에는 인코딩 문제로 의심했지만, 실제 원인은 그 한 글자 escape 였습니다.

미묘한 점은 대문자 \V 는 escape 가 아니라는 점입니다. case-sensitive 가드 한 줄이 한 시간을 잡아먹었습니다. fix 는 echo 를 버리는 것입니다.

ENCODED=$(printf '%s' "$SCRIPT" \
  | iconv -f UTF-8 -t UTF-16LE \
  | base64 \
  | tr -d '\n')

printf '%s' 는 %s 뒤의 인자를 escape 해석 없이 그대로 출력합니다. 비슷한 자동화 스크립트에서는 가능하면 처음부터 echo 를 안 쓰는 습관이 안전합니다.

함정 5 — Elevated SSH + New-Item Directory → SYSTEM-only ACL

다섯 가지 중 가장 의외였던 함정입니다. Windows OpenSSH 서버를 통해 SSH 로 들어가서 install 스크립트를 elevated 권한으로 돌렸을 때 발생했습니다.

OpenSSH 서버는 Windows 에서 NT AUTHORITY\SYSTEM 계정으로 동작합니다. SSH 세션 자체가 elevated 로 시작되는데, 이 상태에서 New-Item -ItemType Directory 로 폴더를 만들면, 그 폴더의 ACL 이 부모 ($LOCALAPPDATA) 의 권한을 상속받지 않고 SYSTEM 만 FullControl 로 잡힙니다.

진단은 Get-Acl 한 줄로 확인할 수 있습니다.

Get-Acl $env:LOCALAPPDATA\windows-bootstrap |
    Format-List Owner, AccessToString

출력은 이렇게 나옵니다.

Owner          : 도메인\사용자
AccessToString : NT AUTHORITY\SYSTEM Allow FullControl

같은 사용자명임에도 사용자 entry 가 ACL 에 없습니다. 결과적으로 이후의 Copy-Item 이 PermissionDenied 로 막힙니다. 처음에는 antivirus 나 OneDrive 동기화를 의심했지만, 원인은 SSH 가 만든 폴더의 권한 상속 단절이었습니다.

해결은 별도 디렉토리를 새로 만드는 대신, 원본 sibling 의 경로를 Task action 의 -File 인자로 직접 넘기는 것이었습니다.

$scriptPath = Join-Path $env:USERPROFILE "Downloads\vrew-cleanup.ps1"

$action = New-ScheduledTaskAction -Execute "powershell.exe" `
    -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`" -OlderThanHours 1 -KeepCount 3"

폴더를 새로 만들지 않으니 ACL 문제 자체가 발생하지 않습니다. install 스크립트의 복잡도도 한 단계 줄었습니다.

검증 결과

등록된 Task 의 상태를 확인하고, 첫 실행을 강제로 트리거해봤습니다.

Task State            : Ready
LastTaskResult        : 0
NextRunTime           : 22:00
NumberOfMissedRuns    : 0

첫 정리에서 35.65GB 가 회수됐습니다. .vrew 12 개가 3 개로 줄었고, autosave_backup 폴더가 47.38GB 에서 11.73GB 로 안정화됐습니다. 이후 30 분 단위로 트리거가 도는 동안 폴더 크기는 약 12GB 근방에서 더 늘지 않고 유지됐습니다.

정리 — 공식이 안 주는 옵션을 외부에서 메우기

돌이켜 생각해보면 이번 작업의 본체는 PowerShell 스크립트 한 개와 Task Scheduler 설정 한 줄이었습니다. 복잡한 코드는 거의 없었습니다. 그럼에도 다섯 번 막혔던 이유는, Windows 자동화의 함정이 대부분 큰 그림이 아니라 BOM 유무, vertical tab, ACL 상속 단절 같은 작은 가장자리에 숨어 있기 때문이라는 생각이 들었습니다.

공식이 옵션을 줄 때까지 기다리는 것도 한 방법이지만, 그 사이에 디스크가 100GB 씩 차오르는 상황이라면 외부에서 한 겹 덮어두는 쪽이 합리적입니다. 이번 사례에서는 PowerShell 과 Task Scheduler 의 조합이 그 한 겹의 역할을 했습니다.

스크립트와 install 도구는 별도 레포에 정리해두었지만, 비공개로 운영 중이라 링크는 박지 않았습니다. 대신 핵심 코드 조각은 이 글의 단락들에 그대로 옮겨두었으니 그 코드 자체를 복사해 쓰셔도 동일한 결과를 만드실 수 있습니다. 통합 install 스크립트 전체가 필요하시면 댓글이나 이메일로 가볍게 문의 주시면 되겠습니다. 같은 문제로 헤매시는 분께 작은 단축키가 되었으면 합니다.

VrewPowerShellTask SchedulerWindows 자동화디스크 정리ElectronOpenSSH

관련 글

Vrew %TEMP% 18GB 자동 정리 — 5-layer 가드와 OS file lock 의 한계

1편 autosave 정리 후일담입니다. Vrew %TEMP% 18.2GB 를 PowerShell 5-layer 가드로 자동 정리하려 했지만 OS file lock 이 회수를 0 으로 만든 과정, Electron helper 백그라운드 잔존 진단까지 함께 정리했습니다.

관련도 96%

Vrew 하드웨어 가속, 켜야 하나 꺼야 하나 — 지인 노트북에 SSH 로 들어가 확인한 13개 sub-feature 이야기

"Vrew 의 하드웨어 가속, 켜야 하나 꺼야 하나" 라는 한 줄짜리 질문에서 시작해, 지인 노트북에 SSH 로 들어가 Chromium 의 13개 sub-feature 와 4개 레이어를 직접 확인해본 기록. NVENC 가 살아 있는 환경의 결론과, 흔한 오해.

관련도 90%

Vrew 내보내기가 0%에서 멈출 때 — 로그가 알려준 진짜 원인

Vrew 내보내기가 특정 프로젝트만 0%에서 멈췄습니다. 처음엔 투명 GIF의 알파 채널이 원인이라 확신했지만, 과거 성공 로그에도 투명 GIF가 멀쩡히 들어 있었습니다. 가설을 버리고 성공·실패 GIF를 나란히 비교하니 진짜 차이는 길이였습니다. 안 되는 사례만이 아니라 되는 사례를 함께 봐야 진짜 변수가 드러난다는 것을, 로그를 따라가며 다시 배운 기록입니다.

관련도 89%