ラベル バッチ の投稿を表示しています。 すべての投稿を表示
ラベル バッチ の投稿を表示しています。 すべての投稿を表示

2024年2月14日水曜日

ROBOCOPYでファイルのバックアップをやろうとしたら色々嵌った話

どうも皆様ぐーてんもるげん!相変わらずPCに噛り付いている私です。
今回のネタはずばり「ROBOCOPY」。

調べたことを色々メモ書きにしてたんですが、鳥頭な私のことです、きっとそのうちメモごと無くして綺麗さっぱり忘れちゃうんじゃないか?と思い立ち、自分の備忘録も兼ねて今回記事にしてみることにしました。
 

注意!
本記事に記載した内容は不肖私のつたないPC知識で書いた内容ですので、検証不足な点や誤り等ある可能性が御座います。
可能な限り情報の正確性を心がけていますが、安全性や確実な情報提供を保証するものではありません。
当方では責任を負いかねますのでご了承ください。

では本編!!

ROBOCOPYって?

指定した二つのフォルダを同期させることで、ファイルやフォルダのバックアップ等に広く利用されているコマンドになります。
ちなみに、ROBOCOPYの正式名称は「Robust File Copy」で、直訳すると「堅固で確実なファイルコピー」。
「ロボットがコピーするからロボコピー」じゃないんですね。へぇ~。
堅固で確実なファイルコピーを提供すると銘打っているだけあって、そのあたりの機能はかなりリッチです。具体的には

・エラー発生時の再試行回数の制限と待ち時間を任意に設定可能
・ネットワーク越し(NASからのファイルコピーとか)を実施した際、何らかの理由でネットワーク接続が切断された場合、中断と再開が可能
・属性やセキュリティ設定もコピー可能
・MIRコマンドを使用すれば、コピー先にある余分なファイルを削除することも可能
・256文字を超える長いパスを処理できる
・動作ログを記録できる

とまぁ、ググればわらわら出てくるんですが、かなりの機能を有している訳です。
しかもこんなに使えるROBOCOPY、WinXP以降の環境であればサポートしているため、昨今世に出回っているWindows環境であれば、ほぼどこでも使えちゃう、環境に依存しにくいコマンドなのです。

と、ここまで書いといて「何でコマンドでやるわけ?フォルダ開いてコピペすればいいやーん」と思われた方、いらっしゃると思います。
でも考えてみてください。対象のファイルが5~6個とかならまだいいでしょうが、これが10~20、下手すりゃ100を超える場合、それを一個ずつ比較して、新しいファイルかどうかを確認して、更新されてたらコピーする。
それを毎日定期的にやれ、と言われたら???
数多の世界に存在するかもしれない、真性PCドM気質な方なら耐えられるかも知れませんが、特殊な訓練を受けていない我々からすれば、そらもう発狂ものですよね?
やってられるかこの野郎であり、ミスって悲惨な結果になって泣くことになってもおかしくありません。

要は手動でやるにはあまりに現実的でない、定期的なファイルコピーを自動で行う、そこでROBOCOPYが登場する訳です!


ROBOCOPYを使ってみる

ま、とりあえずやってみましょう!今回用意した環境は以下の通り。

・コピー元:C:\FROM
0001.txt
0002.txt
0003.txt が入っています。

・コピー先:C:\TO
該当フォルダはカラの状態です。

今回発行したコマンドは下記になります。


×
@ECHO OFF

REM カレントディレクトリを保持
SET CAL_DIR=%~dp0

REM カレントディレクトリに実行ログを出力するように設定
SET LOGFILE=%CAL_DIR%ROBOCOPY.log

REM 同期元
SET DATA_FROM="C:\from"

REM 同期先
SET DATA_TO="C:\to"

ROBOCOPY %DATA_FROM% %DATA_TO% /copy:DT /B /e /XO /R:1 /W:1 /NP /NC /NS /NDL /NFL /LOG+:%LOGFILE%	

注目頂きたいのはROBOCOPYの行。何やらやたらとごちゃごちゃ並んでます。
これがROBOCOPYのオプション設定。各パラメータに意味があり、これでROBOCOPYの動作を制御しています。

今回設定したオプションは以下の通りです。

%DATA_FROM% コピー元フォルダ
%DATA_TO% コピー先フォルダ
/copy:DT コピーフラグ。DTはそれぞれD=データ、T=タイムスタンプを示します。
本オプションを設定しないと、NAS等からのデータコピーでは高確率で失敗します。
今回の例ではA=属性情報(Attributes)をコピー対象から除外する事で、異なるファイルシステム間のファイルコピーを実現しています。
/B バックアップモードでファイルのコピーを試みます。
本オプションを付与することで、ROBOCOPYコマンドの実行ユーザに該当ファイルへのアクセス権が付与されていなかったとしても、コピーすることが可能になります。
※実行ユーザがAdministratorsグループか、Backup Operatorsグループのいずれかに所属している必要があります。
/e カレントディレクトだけでなく、サブフォルダも再帰的にコピーします。
類似するオプション「/s」と異なり、/eを指定した場合、サブフォルダが
空フォルダである場合であっても、コピー対象として扱います。
/XO コピー元ファイルがコピー先ファイルより古い場合、処理対象から除外されます。
/R:1 コピー時にエラーが発生した際の再試行回数を指定します。
本パラメータを設定しない場合、規定値で100万回のリトライを繰り返します。
/W:1 再試行時の待機時間を秒単位で指定します。
本パラメータを設定しない場合、規定値で30秒待機します。
/NP ログにコピー処理の進捗状況を出力しません。
本設定を入れておかないとログが非常に煩雑になり、読みにくくなります。
/NC コピー対象ファイルがコピーされる、コピーされない理由(ファイルクラス)をログに出力しません。
/NS コピー対象ファイルのサイズ情報をログに含めません。
/NDL ログにディレクトリ一覧情報を含めません。
/NFL ログにファイル一覧情報を含めません。
/LOG+:%LOGFILE% ログに処理状況を「追記モード」で出力します。

 

 実行結果はこんな感じですね。 


×
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows の堅牢性の高いファイル コピー                              
-------------------------------------------------------------------------------

  開始: 2024年2月1日  9:57:50
   コピー元 : C:\FROM\
     コピー先 : C:\TO\

    ファイル: *.*
	    
  オプション: *.* /NS /NC /NDL /NFL /S /E /DCOPY:D /COPY:DT /B /NP /XO /R:1 /W:1 

------------------------------------------------------------------------------


------------------------------------------------------------------------------

                  合計     コピー済み      スキップ       不一致        失敗    Extras
   ディレクトリ:         1         0         1         0         0         0
     ファイル:         3         3         0         0         0         0
      バイト:     2.3 k     2.3 k         0         0         0         0
       時刻:   0:00:00   0:00:00                       0:00:00   0:00:00


       速度:              105913 バイト/秒
       速度:               6.060 MB/分
   終了: 2024年2月1日  9:57:50

無事、TOフォルダにFROMフォルダに入っていたテキスト3つがコピーされました。

検証1.コピー元フォルダの中身とコピー先フォルダの中身が完全一致だった場合

まぁ、これに関しては検証するまでもないですね。実行結果は以下の通りです。


×
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows の堅牢性の高いファイル コピー                              
-------------------------------------------------------------------------------

  開始: 2024年2月1日 10:53:49
   コピー元 : C:\FROM\
     コピー先 : C:\TO\

    ファイル: *.*
	    
  オプション: *.* /NS /NC /NDL /NFL /S /E /DCOPY:D /COPY:DT /B /NP /XO /R:1 /W:1 

------------------------------------------------------------------------------


------------------------------------------------------------------------------

                  合計     コピー済み      スキップ       不一致        失敗    Extras
   ディレクトリ:         1         0         1         0         0         0
     ファイル:         3         0         3         0         0         0
      バイト:     2.3 k         0     2.3 k         0         0         0
       時刻:   0:00:00   0:00:00                       0:00:00   0:00:00
   終了: 2024年2月1日 10:53:49

一覧化するとこんな感じ。更新対象ファイルはひとつも無いので、何も変化しません。

DATA_FROMフォルダ(コピー元) DATA_TOフォルダ(コピー先) 結果
0001.txt
(2024/01/01)
0001.txt
(2024/01/01)
スキップ
0002.txt
(2024/01/05)
0002.txt
(2024/01/05)
スキップ
0003.txt
(2024/01/05)
0003.txt
(2024/01/05)
スキップ

検証2.コピー元フォルダ、コピー先フォルダに同じファイルがあり、かつコピー元の方が新しかった場合

これまた結果は非常にわかりやすいです。


×
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows の堅牢性の高いファイル コピー                              
-------------------------------------------------------------------------------

  開始: 2024年2月1日 10:59:57
   コピー元 : C:\FROM\
     コピー先 : C:\TO\

    ファイル: *.*
	    
  オプション: *.* /NS /NC /NDL /NFL /S /E /DCOPY:D /COPY:DT /B /NP /XO /R:1 /W:1 

------------------------------------------------------------------------------


------------------------------------------------------------------------------

                  合計     コピー済み      スキップ       不一致        失敗    Extras
   ディレクトリ:         1         0         1         0         0         0
     ファイル:         3         1         2         0         0         0
      バイト:     2.3 k       543     1.8 k         0         0         0
       時刻:   0:00:00   0:00:00                       0:00:00   0:00:00


       速度:              108600 バイト/秒
       速度:               6.214 MB/分
   終了: 2024年2月1日 10:59:57

結果一覧はこんな感じです。
ここまではほぼ予想通りかと思います。次からが本題。

DATA_FROMフォルダ(コピー元) DATA_TOフォルダ(コピー先) 結果
0001.txt
(2024/01/01)
0001.txt
(2024/01/01)
スキップ
0002.txt
2024/01/10にファイル更新
0002.txt
(2024/01/10)
上書き
0003.txt
(2024/01/05)
0003.txt
(2024/01/05)
スキップ

検証3.コピー元フォルダにコピー先にあるファイルが無かった場合

では、コピー先には該当ファイルがあるのに、コピー元に該当ファイルが無かったらどうなるでしょう?

実行結果からどうぞ。


×
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows の堅牢性の高いファイル コピー                              
-------------------------------------------------------------------------------

  開始: 2024年2月1日 11:03:50
   コピー元 : C:\FROM\
     コピー先 : C:\TO\

    ファイル: *.*
	    
  オプション: *.* /NS /NC /NDL /NFL /S /E /DCOPY:D /COPY:DT /B /NP /XO /R:1 /W:1 

------------------------------------------------------------------------------


------------------------------------------------------------------------------

                  合計     コピー済み      スキップ       不一致        失敗    Extras
   ディレクトリ:         1         0         1         0         0         0
     ファイル:         2         0         2         0         0         1
      バイト:     1.4 k         0     1.4 k         0         0       986
       時刻:   0:00:00   0:00:00                       0:00:00   0:00:00
   終了: 2024年2月1日 11:03:50

MIRオプションを付与したときと同様、Extrasとして計上されました。
ただし、Extrasにカウントアップはされますが、MIRオプションと違ってコピー先フォルダから該当ファイルは削除されません

DATA_FROMフォルダ(コピー元) DATA_TOフォルダ(コピー先) 結果
0001.txt
→削除
0001.txt
(2024/01/01)
変化なし
0002.txt
(2024/01/05)
0002.txt
(2024/01/05)
スキップ
0003.txt
(2024/01/05)
0003.txt
(2024/01/05)
スキップ

検証4.コピー元フォルダよりコピー先フォルダのファイルの方が新しかった場合

では最後、コピー先フォルダの資源の方が最近更新されてたらどうなるか。

×
-------------------------------------------------------------------------------
   ROBOCOPY     ::     Windows の堅牢性の高いファイル コピー                              
-------------------------------------------------------------------------------

  開始: 2024年2月1日 11:05:48
   コピー元 : C:\FROM\
     コピー先 : C:\TO\

    ファイル: *.*
	    
  オプション: *.* /NS /NC /NDL /NFL /S /E /DCOPY:D /COPY:DT /B /NP /XO /R:1 /W:1 

------------------------------------------------------------------------------


------------------------------------------------------------------------------

                  合計     コピー済み      スキップ       不一致        失敗    Extras
   ディレクトリ:         1         0         1         0         0         0
     ファイル:         3         0         3         0         0         0
      バイト:     2.3 k         0     2.3 k         0         0         0
       時刻:   0:00:00   0:00:00                       0:00:00   0:00:00
   終了: 2024年2月1日 11:05:48


何と何も変化しません。ROBOCOPYの仕様では原則として、新旧関係なくコピー元資源でコピー先資源を上書きするので意外だったのでは無いでしょうか。
理由は上記のオプション「/XO」。
これによりコピー元資源の方がコピー先資源より古い場合、処理対象から無視されます

DATA_FROMフォルダ(コピー元) DATA_TOフォルダ(コピー先) 結果
0001.txt
(2024/01/01)
0001.txt
(2024/01/01)
スキップ
0002.txt
(2024/01/05)
0002.txt
(2024/01/05)
スキップ
0003.txt
(2024/01/05)
0003.txt
2024/01/20に更新、コピー元より新しい
スキップ

他のオプションの設定とか、MIRオプションを設定した場合の動きとかを書き出すと、とんでもなく長くなるので、そのあたりに興味のある方は是非ググってみてください!

最後までお読みいただき有難う御座いました。

2024年1月9日火曜日

バッチプログラムで上位ディレクトリの取得に地味にはまったので覚書

どうも皆様ぐーてんもるげん!そしてあけましておめでとうございます。
年末年始休暇を息子の発熱で潰した私です。

今回のネタはバッチプログラム。
ひょんなことから実行資産が格納されている上位ディレクトリのパスを取得したい!という事があり、私のアタマだと地味に試行錯誤するハメになったので、自分の備忘録も兼ねてメモを残しておくことにしました。
以下サンプルです。
@echo off

REM カレントディレクトリを保持
SET CAL_DIR=%~dp0

REM pushdコマンドで一時的にカレントディレクトリの上位ディレクトリに移動
pushd %CAL_DIR%..

REM pushdコマンドで移動したディレクトリの絶対パスを取得し、変数に格納
SET UPPER_DIR=%CD%

REM pushdコマンド発行前のディレクトリに戻る
popd

ECHO カレントディレクトリパス:%CAL_DIR%
ECHO 上位ディレクトリパス:%UPPER_DIR%


たったこれだけ。マジ??
今回登場したpushdコマンドとpopdコマンドについて調べてみたんですが、

・使い方はcdコマンドと同様、pushd 移動先で指定可能。今回の様に「..」とかもOK!
・実行すると指定されたディレクトリが「一時的な」カレントディレクトリと扱われる
・popdコマンドを使えば移動前のディレクトリに帰ってこれる
というものでした。ええ、便利!

年末年始の面白ネタは特にごじゃいません!またそのうち色々アップしようかと思います。
では、本年もこの頭のおかしい超絶低空飛行ブログをよろしくお願い致します!

2022年10月31日月曜日

PowerPointスライドショーを自動開始するバッチを作りたい

PowerPointで作成したスライドショーを、自動開始させたいケースがあったのでバッチを作ってみました。今回はPCの電源投入後、自動開始させたいとの内容。

多分これから先、同じ内容でぶち当たることがありそうなので、自分用の備忘録用に記事にして残しておきます。役に立つといいなぁ。

以下、作成したソース。

@ECHO OFF
REM 要設定変更(ここから)

REM PowerPointのインストール先を指定(フルパス)
SET powerPointPath="C:\Program Files\Microsoft Office\root\Office16\POWERPNT.EXE"

REM 再生したいpptファイルを指定(フルパス)

SET pptFilePath="C:\sample\Test.pptx"

REM 端末起動からファイル表示開始までの待機時間を指定
SET timeWait=30
REM 要設定変更(ここまで)

REM スライドショー開始までディレイをかける
timeout /t %timeWait%

REM スライドショー自動開始
%powerPointPath% /S %pptFilePath%

exit

PowerPointViewer時代と違い、POWERPNT.exeに渡す起動引数が「/S」になっていたのでちょっとハマりました。こういう起動引数系のヘルプってどこかにまとまってないもんなんですかね。。。

 

ではまた。

2022年3月25日金曜日

Windowsのモニタ認識番号でどうしようもなくハマったので覚書

仕事でマルチモニタで作業をすることが多い私。今回はその中で「あんちきしょう!」と叫びたくなるくらいハマったので、自分用の覚書的に記事にしてみました。

なお、今回の記事ではレジストリを弄りまわしているので、自力で元に戻す自信のない方や、レジストリって何?って方は不用意に試さないで下さいね。失敗すると本気でPC壊れちゃうので。 

では、本題。仕事上で使うツールの中に、マルチモニタ環境で複数のツール画面を展開できるものがあるんですが、この中のとあるウィンドウが、表示して欲しいモニタに出てくれない!という事態に遭遇。当初「プライマリディスプレイになってないからでしょ?」程度に軽く考えていたものの、プライマリディスプレイの設定はきちんと行われており、何ら問題ないことを確認。接続を変えてもダメ。

困り果ててリファレンスに目を通すと

「本ツールのウィンドウ制御は、ディスプレイの識別番号によって表示位置を認識しています」との記述を発見。

つまり、プライマリディスプレイを起点とした絶対座標でもなければ、ツールのメインウィンドウを起点とした相対座標でもなく、各ディスプレイ毎の絶対座標をディスプレイ識別番号で設定し、表示していたわけです。

で、困ったのがモニタの接続は入れ替えられるけど、モニタ自体は入れ替えられないって事。いや、入れ替えようと思えば入れ替えられるんですが、モニタアームを使用している環境だったので「めんどくっさ!」となった訳ですね。

何とか設定変更で解決できないものかと色々調べたところ、どうもレジストリでディスプレイ毎のハードウェア的な情報と表示時に付与する番号を管理しているらしい、ということが判明しました。

HKLM\Systems\CurrentControlSet\Control\GraphicsDrivers\Configuration
HKLM\Systems\CurrentControlSet\Control\GraphicsDrivers\Connectivity

 要はこの2つのレジストリを消しちゃえば、過去に当該端末へ接続したディスプレイの識別情報は綺麗さっぱりなくなるということ、ですね。

※作業時に接続するディスプレイは、識別上1番で認識して欲しいディスプレイのみに限定する必要はあるみたいです。

まぁレジストリはレジストリなわけで、下手に弄ると取り返しのつかないことになるわけですね。ええ、訳も分からず弄るとOS壊すって事です。やはり作業前に消そうとしているレジストリはバックアップを取るべきでしょうね。

 ただこの作業、結構な頻度で発生しそうなので(仕事柄マルチモニタ環境を作る機会が結構多い)全部ひっくるめてbatファイルにしちゃうことにしました。

 以下ソース

@echo off

REM カレントディレクトリを保持します
SET CAL_DIR=%~dp0

REM バックアップしたレジストリの出力先
SET TmpFile=%CAL_DIR%%date:/=-%


ECHO 本バッチプログラムを実行すると、過去に端末に接続されたディスプレイの認識情報をすべて初期化されます。
SET /P USR="処理を続行します。よろしいですか?(y/n)"

REM 第1段階チェック処理
IF NOT %USR%==y (
 ECHO ユーザ操作により中止されました
 GOTO END
)

ECHO 本バッチプログラムを実行する前に、ディプレイ認識番号1番で認識させたい
ECHO ディスプレイのみ、接続されている状態であることを確認してください。
SET /P USR="処理を続行します。よろしいですか?(y/n)"

REM 第2段階チェック処理
IF NOT %USR%==y (
 ECHO ユーザ操作により中止されました
 GOTO END
)

REM バックアップしたレジストリファイルの格納先を用意
IF NOT EXIST %TmpFile% (
 MKDIR %TmpFile%
)

REM 既存レジストリをバックアップ
REG EXPORT HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Configuration %TmpFile%\GraphicsDriversConfiguration.reg /y
REG EXPORT HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Connectivity %TmpFile%\GraphicsDriversConnectivity.reg /y

REM 既存レジストリのバックアップ実行状態チェック
IF NOT EXIST %TmpFile%\GraphicsDriversConfiguration.reg (
 ECHO 既存レジストリのバックアップに失敗しました。処理を中止します。
 GOTO END
)
IF NOT EXIST %TmpFile%\GraphicsDriversConnectivity.reg (
 ECHO 既存レジストリのバックアップに失敗しました。処理を中止します。
 GOTO END
)

ECHO 最終確認 過去に端末に接続されたディスプレイの情報を初期化します。
ECHO 実行しているプログラム等によっては、予期しない不具合が生じる可能性があります。
SET /P USR="処理を続行します。よろしいですか?(y/n)"

REM 最終段階チェック処理
IF NOT %USR%==y (
 ECHO ユーザ操作により中止されました
 GOTO END
)

REM 既存レジストリを削除
REG DELETE HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Configuration /f
REG DELETE HKLM\System\CurrentControlSet\Control\GraphicsDrivers\Connectivity /f

:END
pause

はい、わかる方からしたらかなり無駄な事してるなぁと思われそうな(笑)。

処理の流れとしては、

1.既存のレジストリをバックアップするフォルダを日付でカレントディレクトリに作成

2.キー「Configuration」とキー「Connectivity」をバックアップ

3.キー「Connectivity」とキー「Connectivity」を削除

って感じです。気を付けないといけないのは、本処理を実施する場合、事前に認識番号1番で認識して欲しいディスプレイのみ接続されている状態になるようにしなきゃいけないって事と、管理者での実行が必須って事ですかね。 

ちなみに、実行後に認識番号2番以降で接続して欲しいディスプレイをつなぐ場合、必ず再起動すること。というのも、本バッチプログラムで削除したふたつのキーは、ディスプレイの「再接続」時に生成されるため、実行直後は空っぽの状態になっています。これがちょっと厄介。

どういうことかというと、認識番号1番で拾って欲しいディスプレイの接続情報、バッチ実行直後(レジストリ削除直後)には再作成されていない為、「うほーい!レジストリが消えたぜ!」と意気揚々と認識番号1番で拾って欲しいディスプレイが接続されている端末に、認識番号2番で拾って欲しいディスプレイを再起動せずに接続しちゃうと、後から接続したディスプレイに認識番号1番が付与されてしまい、本来1番で認識して欲しかったディスプレイの認識番号が2になっちゃうんですね。何とまぁ。。。

コレ、環境によって再現したり再現しなかったりマチマチで、気づくまでに滅茶苦茶時間がかかりました。あうあうあー。

 

というかこれ、UIレベルで修正できるようにならないものなんですかね。。まったく。

 

 2022/4/4 追記

その後調査してみたところ、オンボードグラフィックと別にUSB接続のグラフィックアダプタや、一部のマザボでは上記手順を実施してもうまくいかないケースがあることが判明。要はUSBアダプタのディスプレイ番号を、オンボード接続のディスプレイ番号の間に割り込むような形(オンボード DVIがNo1,USBアダプタがNo2,オンボードD-SubがNo3)みたいな認識は出来ないみたいです。面倒くさいなぁ。。。

 

ではまた!