Vrew autosave_backup 96GB 자동 정리 — Windows 자동화 함정 5가지
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결과는 다음과 같았습니다.
하위 폴더 | 용량 | 정체 |
|---|---|---|
| 48.5 GB | Vrew 자동저장 백업 (.vrew 12 개, 영상 raw 내장) |
| 31.7 GB | Electron Chromium File System API blob |
| 18.1 GB | Electron IndexedDB (STT, 썸네일 메타) |
| ~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 | 이유 |
|---|---|---|
| 1 시간 | active session 의 백업 회피. 실측 max 51.9 분 대비 약 16% 마진 |
| 3 | 크래시 복구 보험. 시간 룰을 통과해도 최근 3 개는 무조건 보존 |
OS file lock | 자동 | Vrew 가 쥐고 있는 파일은 |
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)).RepetitionDaily 트리거가 매일 새로 살아나면서 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 스크립트 전체가 필요하시면 댓글이나 이메일로 가볍게 문의 주시면 되겠습니다. 같은 문제로 헤매시는 분께 작은 단축키가 되었으면 합니다.
관련 글
Vrew 내보내기가 0%에서 멈출 때 — 로그가 알려준 진짜 원인
Vrew 내보내기가 특정 프로젝트만 0%에서 멈췄습니다. 처음엔 투명 GIF의 알파 채널이 원인이라 확신했지만, 과거 성공 로그에도 투명 GIF가 멀쩡히 들어 있었습니다. 가설을 버리고 성공·실패 GIF를 나란히 비교하니 진짜 차이는 길이였습니다. 안 되는 사례만이 아니라 되는 사례를 함께 봐야 진짜 변수가 드러난다는 것을, 로그를 따라가며 다시 배운 기록입니다.
맥에서 윈도우 PC SSH 자동화, PowerShell 함정 10가지 정리
맥북을 메인으로 쓰면서 윈도우 PC를 SSH로 자동화하다 보면, 공식 문서대로 따라가도 PowerShell 명령이 어딘가에서 자꾸 깨집니다. UAC 토큰 분리, ReadConsoleOutput, 4단 quote escape, cmd.exe와 PowerShell의 동작 차이 등 하루 동안 누적된 10가지 함정과 우회 패턴을 정리합니다.
.bat과 .exe, 그리고 Windows가 명령을 실행하는 원리
직접 만든 파이썬 CLI 도구를 .bat으로 포장해 전달하고 나니 문득 궁금해졌습니다. .bat과 .exe는 무엇이 다르고, 실행되는 파일에는 어떤 종류가 있으며, Windows는 이름만으로 명령을 어떻게 찾아내는지 — 평소 당연하게 써오던 것들을 들여다봤습니다.