Batch Script for Data Migration to Box

We are sharing the source code for a batch script used to migrate data from a file server to Box in a professional setting.

Functional Requirements of the Box Data Migration Batch

  1. When a source folder and a target folder are specified, all files, including subfolders within the source folder, will be copied.
  2. Folders containing specified strings can be excluded from migration.
    • Folders containing strings like "old" or "backup" can be excluded from the migration target.
  3. The following files and folders that cannot be migrated to Box will not be copied:
    • System files
    • Hidden files
    • Hidden folders
    • Temporary files (files with the ".tmp" extension or filenames starting with "~")
    • Windows shortcuts
    • Outlook PST files
    • QuickBooks files
  4. Specify whether to copy the source folder itself.
    • For example, if the source folder structure is as follows, you can specify whether to create a folder named "original" in the target folder and have "folder1" and "folder2" as its subfolders:
      • ./original/
        • └folder1/
        • └folder2/

Prerequisites for Using the Box Data Migration Batch

  1. Install Box Drive.
    • Box Drive is a free application provided by Box, Inc., allowing you to operate Box via your file explorer.
  2. Windows commands may fail in some cases. Always check the generated logs and appropriately address any folders or files that could not be migrated.
  3. Test the batch behavior with a small number of folders before migrating a large volume of folders and files.
  4. For disclaimers and other details, please review the Privacy Policy.

Source Code

@echo off
setlocal enabledelayedexpansion

REM Set the source directory
set "source_directory=%~1"

call :GET_BASE_DIRECTORY "%source_directory%" directory

REM If copying the source directory as a whole
if "%~4" == "1" (
    set "copy_base_directory=!directory!"
)

REM Set the destination directory
set "destination_directory=%~2"

REM Set the strings representing directories to be excluded from copying (multiple)
set "exclude_directory_strings=%~3"

REM Recursively inspect the source directory
for /r "%source_directory%" %%D in (*) do (
    REM Set the directory path
    set "directory_path=%%~dpD"

    REM Set as "directory to be copied"
    set "can_exclude_directory=0"

    for %%E in (%exclude_directory_strings%) do (
        REM If the directory path contains strings of directories to be excluded from copying
        echo !directory_path! | find /i "%%E" > nul && (
            echo Skipped [!directory_path!] Excluded directory
            REM Set as "directory not to be copied"
            set "can_exclude_directory=1"
        )
    )

    REM Copy the directory if necessary
    if "!can_exclude_directory!" == "0" (
        call :GET_DESTINATION_DIRECTORY_PATH "!directory_path!" destination_sub_directory

        if not exist "!destination_sub_directory!" (
            REM Create the destination directory
            mkdir "!destination_sub_directory!"

            if errorlevel 0 (
                echo Success [!destination_sub_directory!] Directory created successfully
            ) else (
                echo Failed [!destination_sub_directory!] Directory creation failed
            )
        )
    )
)

REM Recursively inspect the source directory
for /r "%source_directory%" %%F in (*) do (
    REM Set the file path
    set "file_path=%%~dpF"

    REM Set file attributes
    set "file_attributes=%%~aF"

    REM If the attributes indicate it's not a directory
    if "!file_attributes:~0,1!" neq "d" (
        if /i "%%~xF"==".lnk" (
            REM If the extension indicates it's a shortcut file, do not copy
            echo Skipped [%%~F] Shortcut file
        ) else if /i "%%~xF" == ".pst" (
            REM If the extension indicates it's an Outlook data file, do not copy
            echo Skipped [%%~F] Outlook data file
        ) else if /i "%%~xF" == ".ost" (
            REM If the extension indicates it's an Outlook data file, do not copy
            echo Skipped [%%~F] Outlook data file
        ) else if /i "%%~xF" == ".qbo" (
            REM If the extension indicates it's a QuickBooks file, do not copy
            echo Skipped [%%~F] QuickBooks file
        ) else if /i "%%~xF" == ".qbw" (
            REM If the extension indicates it's a QuickBooks file, do not copy
            echo Skipped [%%~F] QuickBooks file
        ) else if /i "%%~xF" == ".tmp" (
            REM If the extension indicates it's a temporary file, do not copy
            echo Skipped [%%~F] Temporary file
        ) else (
            set "first_file_str=%%~nF"
            if "!first_file_str:~0,1!" neq "~" (
                call :GET_DESTINATION_DIRECTORY_PATH "!file_path!" destination_sub_directory

                REM If the destination directory exists
                if exist "!destination_sub_directory!" (
                    copy "%%~F" "!destination_sub_directory!" /Y

                    if errorlevel 0 (
                        echo Success [%%~F] File copied successfully
                    ) else (
                        echo Failed [%%~F] File copy failed
                    )
                ) else (
                    echo Skipped [%%~F] Destination directory does not exist
                )
            )
        )
    )
)

echo File copy process completed.
goto :EOF

:GET_BASE_DIRECTORY
setlocal
    REM Set the full path
    set "full_path=%~1"

    REM Get the last character of the full path
    set "path_last_charactor=!full_path:~-1,1!"

    REM Remove the last character if it is "\"
    if "!path_last_charactor!" == "\" (
        set "full_path=!full_path:~0,-1!"
    )

    for %%I in ("!full_path!") do (
        set "base_directory=%%~nxI"
    )
endlocal & set "%~2=%base_directory%"
goto :EOF

:GET_SOURCE_DIRECTORY_RELATIVE_PATH
setlocal
    set "full_path=%~1"
    set "relative_path=!full_path:%source_directory%\=!"
endlocal & set "%~2=%relative_path%"
goto :EOF

:GET_DESTINATION_DIRECTORY_PATH
setlocal
    set "destination_directory_path=%destination_directory%"

    if defined copy_base_directory (
        set "destination_directory_path=!destination_directory_path!\%copy_base_directory%"
    )

    call :GET_SOURCE_DIRECTORY_RELATIVE_PATH "%~1" relative_path

    set "destination_directory_path=!destination_directory_path!\!relative_path!"
endlocal & set "%~2=%destination_directory_path%"
goto :EOF

Batch Arguments

  • First argument: Absolute path of the source folder
  • Second argument: Absolute path of the target folder (Box)
  • Third argument: Strings contained in folder names to be excluded from migration
    • You can specify multiple strings separated by spaces.
  • Fourth argument: Set "1" to include the source folder in the copy; otherwise, set "0".

Batch Execution Signature

The batch name is "copy_to_box.bat". To copy the "org" folder from "C:\Users\xxx\OneDrive\bats\org" to "C:\Users\xxx\OneDrive\bats\dest", excluding folders with "old" or "backup" in their names, and to log results to "copy.log", use the following command:

If there are no folders to exclude, set the third argument of the batch file to "".

copy_to_box.bat "C:\Users\xxx\OneDrive\bats\org" "C:\Users\xxx\OneDrive\bats\dest" "old backup" 1 >> copy.log

Follow me!

photo by:Todd Trapani