
自作したアプリケーションをSQLiteで運用していると、アプリケーション本体と一緒にSQLiteのDBファイルもバックアップしておきたくなります。
大きなシステムであれば専用のバックアップ製品やDBバックアップの仕組みを用意しますが、個人利用や小規模な社内ツールであれば、そこまで大げさにしなくてもよい場面があります。
今回は、PowerShellで指定フォルダをZIP化し、古いバックアップを自動削除するスクリプトを作りました。
アプリケーション本体のフォルダごとZIPにしておけば、万が一ファイルを壊してしまった場合や、SQLiteのデータを戻したい場合にも、ある程度すぐ復旧できます。
⚠ 注意事項
設定内容やプログラムの内容は、用途・環境に応じて適切なものが変わります。
各種設定値や環境情報についてよく理解を深め、壊れてもよい環境で十分に検証してください。
なるべく正確に書くよう心掛けていますが、本投稿内容を実施される際には自己責任の下でお願いいたします。
やりたいこと
今回のスクリプトでやりたいことは、次のような内容です。
- 自作アプリケーションの配置フォルダを丸ごとZIP化する
- フォルダ内にあるSQLiteのDBファイルも一緒にバックアップする
- ZIPファイル名に元フォルダ名と日時を付ける
- バックアップ先フォルダがなければ自動作成する
- 指定日数より古いバックアップを削除する
- タスクスケジューラに登録して定期実行する
例えば、以下のように実行します。
powershell.exe -ExecutionPolicy Bypass -File "C:\scripts\backup-zip.ps1" -src "C:\data\myapp" -dest "D:\backup" -keepDays 14
この例では、C:\data\myapp をZIP化して D:\backup に保存します。
また、14日より古いバックアップファイルは自動で削除します。
スクリプト
# powershell.exe -ExecutionPolicy Bypass -File "C:\scripts\backup-zip.ps1" -src "C:\data\app_logs" -dest "D:\backup" -keepDays 14
param (
[Parameter(Mandatory = $true)]
[string]$src,
[Parameter(Mandatory = $true)]
[string]$dest,
[int]$keepDays = 14
)
$ErrorActionPreference = "Stop"
$src = $src.TrimEnd('\')
if (-not (Test-Path $src -PathType Container)) {
throw "バックアップ元ディレクトリが存在しません: $src"
}
if (-not (Test-Path $dest -PathType Container)) {
New-Item -ItemType Directory -Path $dest -Force | Out-Null
}
$srcFolderName = Split-Path $src -Leaf
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$zipFileName = "${srcFolderName}_backup_${timestamp}.zip"
$zipPath = Join-Path $dest $zipFileName
Compress-Archive -Path "$src\*" -DestinationPath $zipPath -Force
# 古いバックアップ削除
Get-ChildItem $dest -Filter "${srcFolderName}_backup_*.zip" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$keepDays) } |
Remove-Item -Force
Write-Host "バックアップ完了: $zipPath"
引数でバックアップ対象を指定する
バックアップ元と保存先は、スクリプト内に直接書かず、引数で渡すようにしています。
param (
[Parameter(Mandatory = $true)]
[string]$src,
[Parameter(Mandatory = $true)]
[string]$dest,
[int]$keepDays = 14
)
src がバックアップ元、dest がバックアップ先です。keepDays はバックアップを何日分残すかの指定で、省略した場合は14日になります。
この形にしておくと、アプリケーションごとに配置場所が違っても、同じスクリプトを使い回せます。
アプリケーション本体ごとバックアップする
SQLiteを使ったアプリの場合、DBファイルだけをバックアップする方法もあります。
ただ、自作のよっとしたアプリですが実行ファイル、設定ファイル、テンプレート、補助ファイルなども同じフォルダに置いてます。
そのため今回は、SQLiteのDBファイルだけではなく、アプリケーションのフォルダごとZIP化する方針にしました。
Compress-Archive -Path "$src\*" -DestinationPath $zipPath -Force
"$src\*" を指定しているので、指定フォルダの中身がZIPに入ります。
例えば、以下のような構成であれば、
C:\data\myapp
├─ myapp.exe
├─ appsettings.json
├─ data.sqlite
└─ templates
これらをまとめて1つのZIPファイルにできます。
アプリケーション本体とSQLiteの状態を同じタイミングで残せるので、あとから復元するときも分かりやすいです。
ZIPファイル名にフォルダ名と日時を入れる
ZIPファイル名は、バックアップ元フォルダ名と日時から作っています。
$srcFolderName = Split-Path $src -Leaf
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$zipFileName = "${srcFolderName}_backup_${timestamp}.zip"
例えば、バックアップ元が C:\data\myapp の場合、次のようなファイル名になります。
myapp_backup_20260618_230000.zip
ファイル名に日時が入っているので、いつ時点のバックアップなのかがすぐ分かります。
また、フォルダ名も入れているため、同じバックアップ先に複数アプリのバックアップを置いても見分けやすくなります。
保存先フォルダがなければ作成する
バックアップ先のフォルダが存在しない場合は、自動で作成します。
if (-not (Test-Path $dest -PathType Container)) {
New-Item -ItemType Directory -Path $dest -Force | Out-Null
}
初回実行時に保存先フォルダを手で作らなくてよいので、タスクスケジューラに登録する時も少し楽になります。
古いバックアップを自動で削除する
ZIPバックアップは便利ですが、放置するとどんどん増えます。
そこで、指定日数より古いバックアップを削除する処理も入れています。
Get-ChildItem $dest -Filter "${srcFolderName}_backup_*.zip" |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$keepDays) } |
Remove-Item -Force
削除対象は、同じフォルダ名から作られたバックアップファイルだけです。
例えば myapp_backup_*.zip のようなファイルだけを対象にするため、同じ保存先に別アプリのバックアップがあっても、巻き込みにくくしています。
バックアップは、取ること自体も大事ですが、増え続けたファイルをどう管理するかも地味に重要です。
保持日数を指定できるようにしておくと、バックアップ先の容量を圧迫しにくくなります。
引数を変えれば同じスクリプトを使い回せる
このスクリプトは、バックアップ元と保存先をスクリプト内に固定で書かず、引数で渡す形にしています。
そのため、バックアップ対象が増えても、スクリプト自体をコピーして増やす必要がありません。
例えば、自作アプリケーションごとにタスクスケジューラの設定を分けて、引数だけ変えれば同じスクリプトを使い回せます。
powershell.exe -ExecutionPolicy Bypass -File "C:\scripts\backup-zip.ps1" -src "C:\apps\app1" -dest "D:\backup\app1" -keepDays 14
powershell.exe -ExecutionPolicy Bypass -File "C:\scripts\backup-zip.ps1" -src "C:\apps\app2" -dest "D:\backup\app2" -keepDays 30
powershell.exe -ExecutionPolicy Bypass -File "C:\scripts\backup-zip.ps1" -src "C:\apps\tool" -dest "\\server\backup\tool" -keepDays 7
バックアップ対象によって、保存先や保持期間を変えられるのが便利です。
小さな自作アプリケーションがいくつかある場合でも、スクリプトは1つだけ管理すればよく、タスクスケジューラ側で実行内容を分けられます。
後からバックアップ対象を追加したくなった場合も、新しいタスクを作って src と dest を変えるだけです。
個人的には、この「スクリプトは共通化して、タスク側の引数だけ変える」形にしておくと、運用がかなり楽になります。
タスクスケジューラに登録して自動実行する
このスクリプトは、手動で実行するためというより、Windowsのタスクスケジューラに登録して定期実行する前提で使っています。
自作アプリケーションの場合、つい「あとでバックアップしよう」と思いながら、そのまま忘れてしまうことがあります。
特にSQLiteを使っているアプリでは、DBファイルが1つなので扱いやすい反面、そのファイルが壊れたり、誤って上書きしてしまったりすると影響が大きくなります。
そこで、タスクスケジューラで毎日決まった時間にZIPバックアップを取るようにしました。
タスクの「操作」では、プログラムに powershell.exe を指定し、引数に次のような内容を設定しています。
-ExecutionPolicy Bypass -File "C:\scripts\backup-zip.ps1" -src "C:\data\myapp" -dest "D:\backup" -keepDays 14
これで、C:\data\myapp 配下にある自作アプリケーション本体、設定ファイル、SQLiteのDBファイルをまとめてZIP化し、D:\backup に保存できます。keepDays を指定しているので、古いZIPファイルも自動で削除されます。
バックアップは増え続けるとそれ自体が管理対象になってしまうので、残す期間を決めておけるのは地味に便利です。
タスクスケジューラで運用する場合は、実行ユーザーにも注意しています。
アプリケーションの配置先やバックアップ先にアクセスできるユーザーで実行しないと、手動では成功するのにタスクでは失敗する、ということがあります。
-dest "\\server\backup"
タスクスケジューラから実行される処理は、普段のデスクトップ操作とは見えている環境が違うことがあります。
そのため、ドライブレターに依存しない形にしておくと、あとから原因不明の失敗に悩まされにくくなります。
また、SQLiteのバックアップという意味では、実行時間も少し気にしています。
頻繁に書き込みがある時間帯よりも、利用が少ない深夜帯や、アプリケーションの処理が落ち着いている(使う自分が寝ている)時間に実行するようにしました。
自分の用途では、毎日決まった時間にタスクスケジューラで動かしておき、必要なときだけバックアップフォルダを見る運用にしています。
SQLiteバックアップ時の注意点
SQLiteはファイルベースのDBなので、DBファイルをコピーすればバックアップできるように見えます。
ただし、アプリケーションがDBを書き込み中の場合、タイミングによっては中途半端な状態でコピーしてしまう可能性があります。
今回は利用者が自分1名のアプリケーションなので、寝てる時間に実行しています。
そのため、24時間入出力があるようなアプリケーションで運用するなら、次のようなタイミングで実行するのがよいと思います。
- アプリケーションを停止している時間帯を作ってそのタイミングで実行
- 書き込み処理が走らないタイミングを作って実行
- タスク実行前にアプリ側でDB書き込みを止められるタイミング
小規模な個人用アプリであればこれでも十分な場面は多いですが、重要なデータを扱う場合はSQLiteの .backup コマンドなど、DB側の整合性を意識した方法も検討した方が安全です。
小規模アプリの保険としてはちょうどいい
今回のスクリプトは、本格的なバックアップシステムではありません。
ただ、自作アプリケーション本体とSQLiteをまとめて残しておく用途なら、このくらいのシンプルな仕組みでもかなり安心感があります。
特に、アプリケーション本体、設定ファイル、SQLiteのDBファイルを同じフォルダに置いている場合は、フォルダごとZIP化しておくのが分かりやすいです。
普段はタスクスケジューラで勝手にバックアップを取っておき、必要になったときだけZIPファイルを確認する。
何か壊れたときに、少なくとも昨日の状態には戻せる。
それだけでも、自作アプリを運用する上では十分ありがたい仕組みです。