Last active
March 27, 2025 02:53
-
-
Save flipeador/29ac92f277f4c01e07659f17f8c0caa5 to your computer and use it in GitHub Desktop.
A basic GUI for backing up files and directories with ROBOCOPY in Windows.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;@Ahk2Exe-SetFileVersion 1.0.4.0 | |
;@Ahk2Exe-SetProductName Robocopy backup tool | |
;@Ahk2Exe-SetCopyright https://gist.github.com/flipeador/29ac92f277f4c01e07659f17f8c0caa5 | |
#Requires AutoHotkey v2 | |
#SingleInstance Off | |
#NoTrayIcon | |
TITLE := 'Robocopy backup tool' | |
if WinExist(TITLE . ' ahk_class AutoHotkeyGUI') | |
WinActivate(), ExitApp() | |
try action := A_Args[1] | |
defdiropts := '/mir /r:0' | |
; Alternate Data Stream for storing script data. | |
fdata := FileOpen(A_ScriptFullPath . ':data', 'rw-rwd') | |
ui := Gui(, TITLE) | |
ui.BackColor := 0xEDEDD1 | |
ui.MarginX := ui.MarginY := 0 | |
ui.SetFont(, 'Consolas') | |
lv := ui.AddListView( | |
Format('w{} R{} -LV0x10', 1000, 30), | |
['Source', 'Destination', 'Files', 'Options'] | |
) | |
ui.AddButton('x5 vSave', 'Save') | |
ui['Save'].OnEvent('Click', OnSave) | |
ui.AddButton('x+20 yp vRun', 'Run') | |
ui['Run'].OnEvent('Click', OnRun) | |
ui.AddButton('x+5 yp vInit', 'Init') | |
ui['Init'].OnEvent('Click', OnInit) | |
ui.AddButton('x+20 yp vSrc', 'Source') | |
ui['Src'].OnEvent('Click', OnSrc) | |
ui.AddButton('x+5 yp vDst', 'Destination') | |
ui['Dst'].OnEvent('Click', OnDest) | |
ui.AddButton('x+5 yp vFile', 'Files') | |
ui['File'].OnEvent('Click', OnFile) | |
ui.AddButton('x+5 yp vOpt', 'Options') | |
ui['Opt'].OnEvent('Click', OnOptions) | |
ui.AddButton('x+20 yp vDel', 'Delete') | |
ui['Del'].OnEvent('Click', OnDelete) | |
ui.AddButton('x+20 yp vHelp', 'Help') | |
ui['Help'].OnEvent('Click', OnHelp) | |
SetExplorerTheme(lv.Hwnd) | |
SetMicaEffect(ui.Hwnd) | |
ui.OnEvent('Close', (*) => ExitApp()) | |
loop parse fdata.Read(), '`n' | |
lv.Add(, StrSplit(A_LoopField, '`r')*) | |
; AutoHotkey.exe robocopy.ahk /run | |
if IsSet(action) && action = '/run' { | |
Exec(, '/q /c', 'Hide') | |
ExitApp() | |
} | |
lv.GetPos(,, &w) | |
lv.ModifyCol(1, w / 3) | |
lv.ModifyCol(2, w / 3) | |
lv.ModifyCol(3, 'AutoHdr') | |
ui.Show() | |
OnSave(*) { | |
fdata.Length := 0 | |
loop lv.GetCount() | |
fdata.Write( | |
Format( | |
'{}`r{}`r{}`r{}`n', | |
lv.GetText(A_Index, 1), | |
lv.GetText(A_Index, 2), | |
lv.GetText(A_Index, 3), | |
lv.GetText(A_Index, 4) | |
) | |
) | |
--fdata.Length | |
} | |
Exec(ln1:='', params:='', options:='', fn:='') { | |
path := A_Temp . '\~robocopy.bat' | |
f := FileOpen(path, 'w') | |
f.Write(ln1 . '`r`n') | |
loop lv.GetCount() { | |
src := lv.GetText(A_Index, 1) | |
dst := lv.GetText(A_Index, 2) | |
files := lv.GetText(A_Index, 3) | |
opts := lv.GetText(A_Index, 4) | |
if !fn || fn(f, src, dst, files, opts) | |
f.Write( | |
Format( | |
'robocopy.exe "{}" "{}" {} {}`r`n', | |
fn ? dst : src, | |
fn ? src : dst, | |
files ? files : '', | |
files ? opts : opts || defdiropts | |
) | |
) | |
} | |
Run(Format('cmd.exe {} call "{}"', params, path),, options) | |
} | |
OnRun(*) { | |
Exec('pause', '/q /k') | |
} | |
OnInit(*) { | |
fn(f, src, dst, files, opts) { | |
return !DirExist(src) | |
} | |
Exec('pause', '/q /k', '', fn) | |
} | |
OnSrc(*) { | |
ui.Opt('+OwnDialogs') | |
if index := lv.GetNext() | |
src := lv.GetText(index, 1) | |
root := IsSet(src) ? src : '' | |
root := StrReplace(root, '%AppData%', A_AppData) | |
if !path := FileSelect('D2', root) | |
return | |
path := StrReplace(path, A_AppData, '%AppData%') | |
if !index | |
return lv.Add(, path) | |
lv.Modify(index,, path) | |
} | |
OnDest(*) { | |
ui.Opt('+OwnDialogs') | |
if index := lv.GetNext() | |
dest := lv.GetText(index, 2) | |
root := IsSet(dest) ? dest : '' | |
if !path := FileSelect('D2', root) | |
return | |
if !index | |
return lv.Add(,, path) | |
lv.Modify(index,,, path) | |
} | |
OnFile(*) { | |
ui.Opt('+OwnDialogs') | |
if index := lv.GetNext() | |
src := lv.GetText(index, 1) | |
root := IsSet(src) ? src : '' | |
list := FileSelect('M', root) | |
if !list.Length | |
return | |
files := '' | |
for path in list | |
SplitPath(path, &filename) | |
, files .= '"' . filename . '" ' | |
if index | |
lv.Modify(index, 'Vis Select Focus',,, files) | |
else index := lv.Add('Vis Select Focus',,, files) | |
if !root | |
SplitPath(list[1],, &dir), lv.Modify(index,, dir) | |
} | |
OnOptions(*) { | |
ui.Opt('+OwnDialogs') | |
if index := lv.GetNext() { | |
file := lv.GetText(index, 3) | |
opts := lv.GetText(index, 4) | |
opts := file ? opts : opts || defdiropts | |
opts := InputBox(, 'Options',, opts) | |
if opts.Result = 'OK' | |
lv.Modify(index,,,,, opts.Value) | |
} | |
} | |
OnDelete(*) { | |
try lv.Delete(lv.GetNext()) | |
} | |
OnHelp(*) { | |
Run('cmd.exe /q /k robocopy.exe /?') | |
} | |
SetExplorerTheme(hWnd) { | |
DllCall('uxtheme\SetWindowTheme', 'Ptr', hWnd, 'Str', 'Explorer', 'Ptr', 0) | |
} | |
SetMicaEffect(hWnd) { | |
if (VerCompare(A_OSVersion, '10.0.22621') >= 0) | |
DllCall('dwmapi\DwmSetWindowAttribute', 'Ptr', hWnd, 'Int', 20, 'IntP', 1, 'Int', 4) | |
, DllCall('dwmapi\DwmSetWindowAttribute', 'Ptr', hWnd, 'Int', 38, 'IntP', 3, 'Int', 4) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Run the script with AutoHotkey v2.
Quiet mode:
AutoHotkey.exe robocopy.ahk /run
.The script must be stored on a file system that supports ADS:
NTFS
ReFS
.Press the
Run
button to mirrorSource
inDestination
.Press the
Init
button to mirrorDestination
inSource
, ifSource
does not exist.