いつものしらべてもでてこない

調べた事を書きます

ファイルの日付文字列から更新日時や作成日時をPowerShellを利用して一括変更する方法。スマホ(Android,iOS)の写真や動画、コマンド、フリーソフト。2022年10月更新

2022年10月15日コード部分を更新。

 スマホ(Android,iOS)やデジカメでファイルを移動していたら更新日時が書き換えられて写真の並び順がばらばらになってしまった。
どうやら本体の内蔵メモリからSDカードの様な別のデバイスに移動すると更新日時が再設定されるようだ。
これを PowerShell を利用して一括変更する方法。

 PowerShellPowerShell ISE を利用すればセキュリティ設定を変更しなくてもps.1ファイルからISEを起動して実行できます。
キーボードでのショートカット操作が下の方に書いてあります。
".ps1" ファイルを選択した状態でアプリケーションキーや右クリックメニューから、または Shift+F10,EPowerShell ISE を起動したら Ctrl を押しながら IACDV の順にキーを押して「Enterキー」で実行できます。

概要

 Android等のスマホのファイルをSDカードに移動した上でスマホから取り出してPC上でPoweShellのファイルを実行して更新日時を変更します。
以前の記事の改良版になります。

以前の記事もご覧下さい。
bannan.hatenadiary.jp

PowerShellで一括変更。

 フォルダ内の該当ファイルのみ変更しフォルダについては変更しません。
フリーソフトと書いてありますがプログラムをコピペしてPowerShellスクリプトファイルを作成します。ただしスクリプトファイルを実行する場合はセキュリティ設定の変更が必要になります。
セキュリティ設定を変更せずに実行したい場合はPowerShellを起動してスクリプトをペーストすれば実行できます。この場合はスクリプトファイルを作成する必要はありませんが何度も実行する場合はスクリプトファイルを作成しておいてコピペすると楽です。

ファイル名について

 ファイル名から日時を設定するのでファイル名に日時の文字列が必要です。
一般的な YYYY-MM-DD_HH-MM-SS と言う様な形式になります。
様なと言うのは正規表現を利用して数値の間の接続文字はあってもなくても良い様にしてあるので桁数さえ合えば変更処理が出来るようにしています。(例、photo_2020w3i4_5432-01.jpg)
ファイル名の変更については以前の記事のFlexbleRenamerの部分をご覧下さい。
Exifからファイル名を付ける場合は適当なフリーソフトを使用してください。直接ファイル名を付けるか更新日時に反映後にファイル名を付けると良いです。

PowerShellについて

 作成するフリーソフト(スクリプト)はテキストファイルにコピペして拡張子を.ps1に変更するだけのものです。
自分で作成したスクリプトでも PowerShell ISE や右クリックから実行できない場合はセキュリティ設定を確認するか変更してください。(Get-ExecutionPolicy)
 詳しくは説明しませんが「検索」か「エクスプローラーのアドレスバー」に PowerShell と打ち込んで「Enterキー」を押し起動したら Set-ExecutionPolicy RemoteSigned を入力して「Enterキー」を押 しておけば大丈夫だと思います。
RemoteSigned に設定するとセキュリティ上の危険性が少し高くなります、その為実行後は元の設定か Restricted に変更しておく事をお勧めします。
ここではファイルをダウンロードする訳ではないので Restricted のままで実行できると思います。

 PowerShellにコードを貼り付けてEnterキーで実行できます。

PowerShellを使用する設定についてはこちらをご覧下さい。
technet.microsoft.com

www.atmarkit.co.jp


管理者権限が必要な場合はPowerShellCtrl+Shift+ENTER で管理者権限で起動して実行するか一時的にUACを切る等してください。

interprism.hatenablog.com

PowerShellのコード

 デスクトップかエクスプローラーの右側の空白の適当な所を右クリックしてテキストファイルを作成してください。
テキストファイルを作成したら下のコードをドラッグして選択し右クリックメニューからコピーを選んでテキストファイルの方に貼り付けてください。
貼り付けたらファイル名と拡張子を TouchMe.ps1 に変更してください。
拡張子が表示されていない場合はエクスプローラーの設定で「登録されている拡張子は表示しない」のチェックを外してください。

拡張子を表示する方法
https://support.microsoft.com/ja-jp/help/978449


コードと処理に対応するファイルの名前。ファイルの名前の形式にある括弧内の物は有っても無くても可。日付の後のコメント部分は日本語対応。
(数字以外の文字)、日付時間の数字YYYYMMDDhhmmss形式(ハイフン等の接続文字を含む)、(ドット"."以外の文字列)、ドット"."、拡張子。

# This program is to set "CreationTime" and "LastWriteTime" with DateTime from Filename.

$args = Get-ChildItem -Path *;
foreach ($arg in $args) {
 # exclude directory
 if($arg.GetType().Name -eq "FileInfo"){
 # regular expressions, name + datetime + dot + file extension.
  $regex = [regex]"^[^\d]*(\d{4})[^\d]?(\d{2}|0?\d)[^\d]?(\d{2}|0?\d)[^\d]?(\d{2})[^\d]?(\d{2})[^\d]?(\d{2})[^.]*\..+$";
  $filename = $arg.Name;
  $m = $regex.Matches($filename);
  if($m[0] -ne $null){
    # validation
   $num = [Int]("{0,0:#}" -f $m[0].Groups[2]);
   if($num -lt 1 -Or $num -gt 12){
    Write-Output("error! $num is not valid month. $arg")
    continue;
   }
   $num = [Int]("{0,0:#}" -f $m[0].Groups[3]);
   if($num -lt 1 -Or $num -gt 31){
    Write-Output("error! $num is not valid day. $arg")
    continue;
   }
   $num = [Int]("{0,0:#}" -f $m[0].Groups[4]);
   if($num -lt 0 -Or $num -gt 23){
    Write-Output("error! $num is not valid hour. $arg")
    continue;
   }
   $num = [Int]("{0,0:#}" -f $m[0].Groups[5]);
   if($num -lt 0 -Or $num -gt 59){
    Write-Output("error! $num is not valid minute. $arg")
    continue;
   }
   $num = [Int]("{0,0:#}" -f $m[0].Groups[6]);
   if($num -lt 0 -Or $num -gt 61){
    Write-Output("error! $num is not valid second. $arg")
    continue;
   }
   # end of validation
   
   # datetime
   $dtime = "{0,0:#}/{1,0:#}/{2,0:#} {3,2:##}:{4,2:##}:{5,2:##}" -f $m[0].Groups[1], $m[0].Groups[2], $m[0].Groups[3], $m[0].Groups[4], $m[0].Groups[5], $m[0].Groups[6];
   Write-Output("set ""$dtime"" $arg");
   # 作成日時を設定
   Set-ItemProperty -LiteralPath $filename -name CreationTime -value $dtime;
   # 更新日時を設定
   Set-ItemProperty -LiteralPath $filename -name LastWriteTime -value $dtime;
  }
 }
}

if (!$psISE){
    Write-Host -NoNewLine 'Press any key to continue...';
    $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}

コード終わり。

日付のチェック処理で01の様な文字をSystem.Text.RegularExpression.MatchCollection型からInt型にキャストする方法がどうにも見つからなかった為、正規表現で01の様な数字の場合に先頭の0を無視する形式で文字を取り出して型変換エラーを出さないようにしているが後ろの3グループの数字についてはしていない。

使い方

 PowerShellスクリプト ".ps1" ファイルを作成し、変更したいファイルがあるフォルダにコピー又は移動して右クリックしメニューからから「実行」をクリックするだけです。

セキュリティ上の問題でPowerShellスクリプトファイルを実行できない場合はPowerShell上でスクリプトを入力、ペーストして実行する事が出来ます。右クリックメニューの編集からはPowerShell ISEを起動でき下の部分がPowerShellになっています。右クリックメニューの編集(E)は Shift+F10,E です。PowerShell ISEで実行したい場合は Ctrl を押しながら IACDV の順にキーを押して「Enterキー」で実行できます。慣れると一瞬で実行できます。
PowerShell上から実行したい場合は該当フォルダを開いて「アドレスバーの空欄部分」をクリックし PowerShell と入力して「Enterキー」を押してPowerShellを起動してください。
PowerShellスクリプトのファイル名を打ち込んで「Enterキー」を押し実行すると変更のログを見る事が出来ます
その際は出力結果をテキストファイルにリダイレクトしておくと便利です。
TouchMe.ps1 > TouchLog.txt

日付が変なファイルがあるとログに残るのでわかります。
ログに出ないファイルは名前を見て日付となる数字が見つからなかったファイルです。

注意

 フォルダ内の日付変更のみのプログラムで動作確認はしてありますがPowerShellの実行許可も含め自己責任でお願いします。


処理がすっきりした。
以上。