ファイルサーバーの大掃除

2019年3月27日

ファイルサーバーを利用していて、長年経過してくるとどうしても増えてくるのが、利用されなくなったファイル。何年も利用されていない状態だと、それは既に「生きたデータ」ではなく「死んでいるデータ」となります。

多くの企業はファイルサーバー内のデータを細かく把握することはしていないと思います。そして気づけば膨大な量のデータが蓄積されていく。これを人力で「いる」「いらない」とか解決しようとするとこれまた膨大な時間が必要となってきます。「これ必要なデータ?」『知らん。消してしまえ』と即断できる管理者であれば苦労は無いのですけどね。

手段1:ファイル管理タスクを利用する

Windowsのファイルサーバーの場合、多くが「ファイルサーバーリソースマネージャー」を利用して、共有なりクォーターなりを設定していると思います。この機能の中で、「ファイル管理タスク」というものがあります。色々と出来るのですが、その中でも『指定したフォルダ配下の中で、ファイル最終アクセスから〇〇日経過しているファイルを、別の場所に移動する』ということができます。非常に便利な機能です。

もう1095日(3年)もアクセスが無いファイルがあった場合、それは既に「死んでいるデータ」として認識し、共有された領域から非共有領域へ自動的に移動、ということが出来るのです。

ちなみに、この「ファイルの最終アクセス」というのが曲者です。標準のWindowsでは単にファイルを開いただけでは、ファイルの最終アクセス日が変わりません。更新しないとファイル最終アクセス日も変わらないのです。PDFなどを閲覧しただけではファイル最終アクセス日が変わらないんです。
これを解決させるにはレジストリの変更が必要となってきます(要再起動)

<該当レジストリ>
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisableLastAccessUpdate
値 0 : 有効
値 1 : 無効(初期値)

さて、私もこの「ファイル管理タスク」を利用して、ファイルサーバーの大掃除を行おうと思ってましたが、そこでとある事に気づきました。この「ファイル管理タスク」ですが、『除外設定』が出来ないんです。

どういう事かと言うと、企業のファイルサーバーには様々なデータが存在します。特に更新頻度が低いファイルでも重要なファイルというのが存在するはずです。この『除外設定』が出来ないと、重要度関係なく移動されてしまいます。『そんなのは考えない』という方はファイル管理タスクが合っていると思います。

手段2:別途ツールを購入するか自作する

マイクロソフトに相談しましたが、やはり「ファイル管理タスク」では『除外設定』が出来ないようです。唯一できる除外は分類管理の場所で、除外フォルダへのフルパスを入れる程度ですが、そのフォルダが移動したり名前変更したりしたら除外されません。また、Windowsに搭載されている機能では、こちらが要望とする機能は存在しないとのこと。「唯一実現可能としたらPowerShellでスクリプトを組む」と回答を得ました。
別途ツールを探しましたが、良さそうなツールは200万円以上の価格。。。ちょっとこれは稟議を通しにくいので、最終的には自作することにしました。

さてさて、自作するにしてもどういう仕様にするかと考えた挙句、以下のようになりました。

  • ファイル最終アクセス日の指定ができる
  • ファイルの移動元、移動先が設定できる
  • 除外語句の設定ができる
  • 除外語句が含まれているフォルダ配下は全て除外とする
  • 移動先では移動前のフォルダ構成を維持する

もう一点重要な問題がありました。
私はPowerShellが書けない!!

PowerShellが書けないのでネットを彷徨ったところ、ちょうどよい記事を見つけました。

PowerShell でディレクトリ構造を保ったまま特定のファイルをコピーする(1)

これに除外設定を加えて、コピーではなく移動すればいいんじゃね?ってことでPowerShell歴1日未満の私が作ったのがこちらです。このスクリプトを拡張子.ps1として保存し、PowerShellを管理者モードで起動して実行してください。

$SOURCE = "C:\test"
$DESTINATION = "C:\有効期限切れ"
$DAYS = 1095
$EXCLUDE1 = "*契約*"
$EXCLUDE2 = "*規約*"
$EXCLUDE3 = "*見積*"
$EXCLUDE4 = "*予算*"
$EXCLUDE5 = "*与信*"
$EXCLUDE6 = "*資料*"
$EXCLUDE7 = "*顧客*"
$EXCLUDE8 = "*構成*"
$EXCLUDE9 = "*集計*"
$EXCLUDE10 = "*申請*"
$EXCLUDE11 = "*設定*"
$EXCLUDE12 = "*提案*"
$EXCLUDE13 = "*約款*"
$EXCLUDE14 = "*調査*"
$EXCLUDE15 = "*売上*"
$EXCLUDE16 = "*請求*"
$EXCLUDE17 = "*管理*"
$EXCLUDE18 = "*マニュアル*"
$EXCLUDE19 = "*手順*"
$EXCLUDE20 = "*納品*"
$EXCLUDE20 = "*障害*"





$DATE = Get-Date -UFormat "%Y%m%d-%H%M"
$root = $SOURCE.Replace("\","\\")
$SOURCE_DIR = Split-Path $SOURCE -noQualifier
$DST = Join-Path $DESTINATION $DATE
$DST = Join-Path $DST $SOURCE_DIR
New-Item $DST -ItemType Directory -Force

$s_cmd = Get-LongChildItem $SOURCE -Recurse -File | Where-Object { 
($_.FullName -notlike $EXCLUDE1)`
 -and ($_.FullName -notlike $EXCLUDE2)`
 -and ($_.FullName -notlike $EXCLUDE3)`
 -and ($_.FullName -notlike $EXCLUDE4)`
 -and ($_.FullName -notlike $EXCLUDE5)`
 -and ($_.FullName -notlike $EXCLUDE6)`
 -and ($_.FullName -notlike $EXCLUDE7)`
 -and ($_.FullName -notlike $EXCLUDE8)`
 -and ($_.FullName -notlike $EXCLUDE9)`
 -and ($_.FullName -notlike $EXCLUDE10)`
 -and ($_.FullName -notlike $EXCLUDE11)`
 -and ($_.FullName -notlike $EXCLUDE12)`
 -and ($_.FullName -notlike $EXCLUDE13)`
 -and ($_.FullName -notlike $EXCLUDE14)`
 -and ($_.FullName -notlike $EXCLUDE15)`
 -and ($_.FullName -notlike $EXCLUDE16)`
 -and ($_.FullName -notlike $EXCLUDE17)`
 -and ($_.FullName -notlike $EXCLUDE18)`
 -and ($_.FullName -notlike $EXCLUDE19)`
 -and ($_.FullName -notlike $EXCLUDE20)`
 -and ($_.FullName -notlike $EXCLUDE21)`
 -and ($_.LastAccessTime -lt (Get-Date).AddDays(-1 * $DAYS))
}

$s_cmd `
| %{
    $directoryName = Join-Path $DST ($_.DirectoryName -split $root |select -Last 1)
[PSCustomObject]@{
    Path = $_.FullName
    DirectoryName = $directoryName
    Destination = Join-Path $directoryName $_.Name
    }} `
| %{
    New-Item $_.DirectoryName -ItemType Directory -Force
    Move-Item -Path $_.Path -Destination $_.Destination -Force
}

このスクリプトはPowerShell5.1で動作確認済みですが、PowerShell5.1環境でもGet-LongChildItemは利用できません。
この Get-LongChildItemなどは長いファイル名(パス名)を認識させるために、追加でインストールしたモジュールとなります。
インストール方法はPowerShellを管理者モードで起動し、以下のコマンドを実行。

Install-Module -Name PSAlphaFS -Scope CurrentUser

モジュールが正常にインストールされたか確認する場合は、以下のコマンドを実行。

Get-Command -Module PSAlphaFS | Select-Object Name, Version

これで作成したスクリプトの実行が可能となります。
が、これまたPowerShellの面倒なところで、スクリプトに署名がないと実行してくれません。これを解決するために、以下のコマンドを実行します。

 Set-ExecutionPolicy RemoteSigned 

これで、本当に実行可能となります。

本番環境のファイルサーバーで実行テストを行うには躊躇したので、まずデータ量の少ないテストデータを作成し、動作テスト。動いた。
フォルダ構成を維持するために移動先でフォルダが作成されるので、その表示がコンソール上に表示されます。

そして、今度はなるべく本番環境に近いバックアップサーバーで、本番環境とほぼ同一のデータを利用し、動作テスト。赤文字で少しエラーが表示されましたが、Null Valueは移動できないとか出ているので無視。

最終的に

まだ本番環境でテストしてませんが、バックアップデータにて行った結果は、データ量の50%強が対象として移動されました。 50%強が3年以上更新されてないということです。 50%強がゴミです。死んでるデータです。