【概要】
Windosのコマンドプロンプトにて、LinuxとWindows間でファイルをSCP(送受または受信)でコピーします。
コマンドプロンプトのSCPコマンドおよびSSHコマンドを利用します。
SCP後に、Windows側とLinux側の各ファイルのハッシュ値(SHA1)を比較して正常にコピーされているか確認します。
【動作環境】
下記で動作確認を行いました。
■Windows側:Windows10 Pro、Windows11 Pro
※コマンドプロンプトでSSH、SCPが使えるかどうかは、コマンドプロンプトにて下記を実施してご確認ください。
「ssh」を入力してEnter→「usage: ssh」と表示
「scp」を入力してEnter→「usage: scp」と表示
■Linux側:Ubuntu 22.04、Amazon Linux 2023
【作成手順】
1.任意のフォルダ名でフォルダを作成します。
2.テキストエディタ(メモ帳など)を開きます。
3.下記の「【scp_winlin3.bat】」の内容をテキストに貼り付けます。
4.以下の箇所を更新します。記入方法は該当箇所の記載例(「example」の箇所)を参照ください。
※SCP_SOURCE、SCP_TARGETのどちらか片方はLinux、もう片方はWindowsの記載方法で記載する必要があります。
set SCP_SOURCE=""
set SCP_TARGET=""
set SCP_SSH_KEY=""
5.作成したテキストを、作成したフォルダにファイル名「scp_winlin3.bat」で保存します。
【scp_winlin3.bat】
@echo off
setlocal enabledelayedexpansion
REM ################################################
REM ### Windows batch for Windos-Linux scp
REM ################################################
REM change directory
cd /d %~dp0
REM logfile path
set BAT_LOGFILE="%~dp0scp_winlin3_bat.log.txt"
REM scp source
REM example 1(set SCP_SOURCE="C:\Users\testuser\Desktop\scp_source")
REM example 2(set SCP_SOURCE="ubuntu@192.168.1.10:/home/ubuntu/scp_source")
set SCP_SOURCE=""
REM scp target
REM example 1(set SCP_TARGET="ubuntu@192.168.1.10:/home/ubuntu/scp_target")
REM example 2(set SCP_TARGET="C:\Users\testuser\Desktop\scp_target")
set SCP_TARGET=""
REM ssh key
REM example (set SCP_SSH_KEY="C:\Users\testuser\Desktop\scp_key\sshkey.pem")
set SCP_SSH_KEY=""
echo %date% %time% INFO: SCP Start[%SCP_SOURCE% to %SCP_TARGET%] >> %BAT_LOGFILE%
REM run scp
scp -r -i %SCP_SSH_KEY% %SCP_SOURCE% %SCP_TARGET% >> %BAT_LOGFILE% 2>&1
REM return code check
if %errorlevel% equ 0 (
echo %date% %time% INFO: SCP End[%SCP_SOURCE% to %SCP_TARGET%] >> %BAT_LOGFILE%
) else (
echo %date% %time% ERROR: SCP End[%SCP_SOURCE% to %SCP_TARGET%] Return code %errorlevel% >> %BAT_LOGFILE%
echo %date% %time% INFO: Script End. >> %BAT_LOGFILE%
exit /b
)
if not exist %~dp0scp_winlin3_hashfies (
mkdir %~dp0scp_winlin3_hashfies
)
REM get windows hash value
if exist %~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt (
copy %~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt %~dp0scp_winlin3_hashfies\winlin3_sha1_windows_old.txt
type nul > %~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt
)
set WINDOWS_PATH=
echo %SCP_SOURCE% | find "/" >NUL
if not ERRORLEVEL 1 (
call :SUB_LAST_DIR %SCP_SOURCE:/=\%
echo !LAST_DIR!
set WINDOWS_PATH=!SCP_TARGET!\!LAST_DIR!
) else (
set WINDOWS_PATH=%SCP_SOURCE%
)
set ROW_COUNT=0
for /r %WINDOWS_PATH% %%i in (*.*) do (
set ROW_COUNT=0
for /f "usebackq" %%j in (`certutil -hashfile %%i sha1`) do (
set /a ROW_COUNT=!ROW_COUNT!+1
if !ROW_COUNT!==2 (
echo %%j %%~nxi >> %~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt
)
)
)
REM get linux hash value
if exist %~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt (
copy %~dp0scp_winlin3_hashfies\winlin3_sha1_linux.txt %~dp0scp_winlin3_hashfies\winlin3_sha1_linux_old.txt
type nul > %~dp0scp_winlin3_hashfies\winlin3_sha1_linux.txt
)
echo %SCP_SOURCE% | find "\" >NUL
if not ERRORLEVEL 1 (
call :SUB_LINUX_INFO %SCP_TARGET%
call :SUB_LAST_DIR %SCP_SOURCE%
echo !LAST_DIR!
set LINUX_PATH=!LINUX_PATH!/!LAST_DIR!
) else (
call :SUB_LINUX_INFO %SCP_SOURCE%
)
ssh -i %SCP_SSH_KEY% %LINUX_USER%@%LINUX_IP% for file in `find %LINUX_PATH% -maxdepth 5 -type f` ; do if [[ -n ${file} ]] ; then if [[ ^^! \"${file}\" =~ \"/.\" ]] ; then sha1sum ${file}; fi; fi ; done >> %~dp0scp_winlin3_hashfies\winlin3_sha1_linux.txt
REM compare hash
if exist %~dp0scp_winlin3_hashfies\winlin3_sha1_check.txt (
copy %~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt %~dp0scp_winlin3_hashfies\winlin3_sha1_check_old.txt
type nul > %~dp0scp_winlin3_hashfies\winlin3_sha1_check.txt
)
set ROW_COUNT_1=0
for /f "tokens=1,2" %%a in (%~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt) do (
set /a ROW_COUNT_1=!ROW_COUNT_1!+1
)
set ROW_COUNT_2=0
for /f "tokens=1,2" %%i in (%~dp0scp_winlin3_hashfies\winlin3_sha1_linux.txt) do (
set /a ROW_COUNT_2=!ROW_COUNT_2!+1
)
set ERR_FLG=0
if %ROW_COUNT_2% neq %ROW_COUNT_1% (
set ERR_FLG=1
echo CHEKC_NG ROW COUNT IS NOT MATCH >> %~dp0scp_winlin3_hashfies\winlin3_sha1_check.txt
echo %date% %time% ERROR: SCP HASH CHECK[ROW COUNT IS NOT MATCH] >> %BAT_LOGFILE%
)
set ROW_COUNT=0
for /f "tokens=1,2" %%a in (%~dp0scp_winlin3_hashfies\winlin3_sha1_windows.txt) do (
set ROW_COUNT=0
for /f "tokens=1,2" %%i in (%~dp0scp_winlin3_hashfies\winlin3_sha1_linux.txt) do (
set /a ROW_COUNT=!ROW_COUNT!+1
if "%%a" == "%%i" (
echo CHECK_OK WINDOWS:%%a LINUX:%%i %%b >> %~dp0scp_winlin3_hashfies\winlin3_sha1_check.txt
set ROW_COUNT=0
)
if !ROW_COUNT! geq !ROW_COUNT_2! (
set ERR_FLG=1
echo CHEKC_NG WINDOWS:%%a LINUX:%%i %%b >> %~dp0scp_winlin3_hashfies\winlin3_sha1_check.txt
)
)
)
if %ERR_FLG% gtr 0 (
echo %date% %time% ERROR: SCP HASH CHECK[HASH IS NOT MATCH] >> %BAT_LOGFILE%
) else (
echo %date% %time% INFO: SCP HASH CHECK OK >> %BAT_LOGFILE%
)
echo %date% %time% INFO: Script End. >> %BAT_LOGFILE%
exit /b
:SUB_LAST_DIR
set LAST_DIR=%~n1
exit /b
:SUB_LINUX_INFO
set LINUX_USER=
set LINUX_IP=
set LINUX_PATH=
for /f "usebackq delims=: tokens=1" %%i in (`echo %1`) do (
for /f "usebackq delims=@ tokens=1" %%j in (`echo %%i`) do (
set LINUX_USER=%%j
set LINUX_USER=!LINUX_USER:~1!
)
for /f "usebackq delims=@ tokens=2" %%k in (`echo %%i`) do (
set LINUX_IP=%%k
)
)
for /f "usebackq delims=: tokens=2" %%l in (`echo %1`) do (
set LINUX_PATH=%%l
set LINUX_PATH=!LINUX_PATH:~0,-1!
)
exit /b
【実行準備】
※初回実行時に1度だけ、SCP先のサーバへの接続許可をしておく必要があります。
known_hostsファイルに登録しておくためですので、一度実施したら繰り返し実施する必要はありません。
バッチを手動実行して、「Are you sure you want to continue connecting (yes/no/[fingerprint])?」で「yes」を入力して「Enter」キーを押下します。
【実行手順】
1.「scp_winlin3.bat」をダブルクリックして実行します。
2.「scp_winlin3_bat.log.txt」が作成されるので、実行結果を確認します。
また、「scp_winlin3_hashfies」フォルダが作成され、「winlin3_sha1_check.txt」にハッシュ値の比較結果が記載されます。
【その他】
・Linuxのディレクトリのハッシュ値取得範囲は「-maxdepth 5」で5階層までに絞っています。
・「SCP_TARGET」で指定するディレクトリやフォルダは、SSH接続時に作成を行わないため、存在するものを指定する必要があります。
・Linuxに対してSSH実行するユーザに、接続先のディレクトリへの書き込み権限がない場合、「Permission denied」となり処理が失敗することがありますのでご注意ください。