CopyRecreatePath (Recreate paths for archive files)

CopyRecreatePath copies the selection from the source to the destination, recreating the complete path for each item. This command functions similarly to the following standard command:

Copy CREATEFOLDER="{destpath}{filepath|..|subdir}"

The main advantage of CopyRecreatePath is its ability to recreate paths for files within archives, including files in collections that were found with Search archives.

When building the new path, the drive letter will be saved without the colon, and files from an archive named archive.ext will be saved to a folder called archive_ext.

CopyRecreatePath will write the Copy commands it intends to run in the script log. To list the commands without executing them, append the DRYRUN switch.

The command supports four arguments:

Argument Description
MOVE Move the files and folders instead of copying them. Note that this process might be slow depending on the archive.
TO Specify the target path instead of using the destination. Any notation that Opus understands is acceptable.
ARCHIVEASROOT Use the archive as the root for the folder structure instead of the drive.
DRYRUN List the Copy commands without executing them.

How to set up and use

:one: Save CommandCopyRecreatePath.js.txt to   ↓

%appdata%\GPSoftware\Directory Opus\Script AddIns

:two: Add the new command to a button, hotkey, context menu, etc. like any built-in command, or run it from the FAYT Command field.


CopyRecreatePath TO=/desktop DRYRUN
<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" textcol="none">
	<tip>Copy the selected item and recreate the full path</tip>
	<function type="normal">
		<instruction>CopyRecreatePath TO=/desktop DRYRUN</instruction>

Things you might enjoy reading

How to use buttons and scripts from this forum

The script's inner workings

function OnInit(initData) { = 'CopyRecreatePath';
    initData.version = '2024-06-21';
    initData.url = '';
    initData.desc = 'CopyRecreatePath';
    initData.default_enable = true;
    initData.min_version = '13.0';

function OnAddCommands(addCmdData) {
    var cmd = addCmdData.AddCommand(); = 'CopyRecreatePath';
    cmd.method = 'OnCopyRecreatePath';
    cmd.desc = 'CopyRecreatePath';
    cmd.label = 'CopyRecreatePath';
    cmd.template = '' +
        'move/s,' +
        'to/o,' +
        'archiveasroot/s,' +
    cmd.hide = false;
    cmd.icon = 'script';

function OnCopyRecreatePath(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    var tab = scriptCmdData.func.sourcetab;
    var dtab = scriptCmdData.func.desttab;
    var fsu = DOpus.FSUtil();
    var args = scriptCmdData.func.args;

    cmd.deselect = false;

    if (!tab.selected.count) return;

    var dstPath = ? : (dtab ? dtab.path : null);

    if (!dstPath) return;

    var dstPath = fsu.Resolve(dstPath);
    cmd.RunCommand('=$glob:myIsPath=IsPath("' + dstPath + '")');

    if (DOpus.Vars.Get('myIsPath') == 'false') {
        DOpus.Output('Not a path: ' + dstPath);



    for (var e = new Enumerator(tab.selected); !e.atEnd(); e.moveNext()) {
        var item = e.item();
        var newPath = fsu.Resolve(item.path);

        var insideArchive = false;
        do {
            if (!String(newPath)) continue;
            if (fsu.GetType(newPath, 'a') != 'file') continue;
            insideArchive = true;
        } while (newPath.Parent());

        if (insideArchive) {
            var dstFolder = (args.archiveasroot ? '' : newPath.pathpart + '\\') +
                newPath.stem_m + '_' + newPath.ext.substring(1) +
                String(item.path).replace(String(newPath), '');
        } else {
            var dstFolder = String(item.path);

        dstFolder = dstFolder.replace(':', '');
        dstFolder = dstFolder.replace(/^\\+/, '');

        var cmdLine = 'Copy' +
            (args.move ? ' MOVE' : '') +
            ' FILE="' + item + '"' +
            ' CREATEFOLDER="' + dstPath + '\\' + dstFolder + '"';

        if (args.dryrun) continue;

    DOpus.Output('... done.');