Robocopy Don't save if...


plikojim

New member
Local time
9:30 PM
Posts
4
OS
Vari
Hello everyone,
I ask those who use this Microsoft utility, if there is a way to not delete a previously saved file, if currently in use.

In practice I have been using this utility for many years, but among all its parameters, I have never found the one that suits me.

In practice, if I opened the Outlook program, the pst file is blocked, too bad that using /MIR the previously saved file is deleted and replaced with .tmp that are unusable.

Does anyone have the solution?

Thanks

type
robocopy "C:\Users\xxxxxx\Documents" "D:\Copy Pc\xxxxxx\Documents" /MIR /W:0 /R:0 /tee
 

My Computer

System One

  • OS
    Vari
This batch script makes a total copy first using Robocopy command and then incrementally, :: ie, it just copies the new files and changed files.

 

My Computer

System One

  • OS
    Windows 11
    Computer type
    PC/Desktop
    Manufacturer/Model
    HP Pavilion
    CPU
    AMD Ryzen 7 5700G
    Motherboard
    Erica6
    Memory
    Micron Technology DDR4-3200 16GB
    Graphics Card(s)
    NVIDIA GeForce RTX 3060
    Sound Card
    Realtek ALC671
    Monitor(s) Displays
    Samsung SyncMaster U28E590
    Screen Resolution
    3840 x 2160
    Hard Drives
    SAMSUNG MZVLQ1T0HALB-000H1
Sorry, but it's not an optimal solution.

I'm just asking if there is a parameter or in combination with another, it performs a mirror copy, which does not delete files that are currently in use.
The one I use as a Robocopy string, does not copy files already copied, but deletes those no longer present and copies the new ones, some sort of additional control would be needed.
The .pst file exists in the \Documents\Outlook File folder, it shouldn't do anything if the file is locked, but I don't know how to tell it....
 

My Computer

System One

  • OS
    Vari
I’m not near a PC, so I can’t test this, but try backup mode (/b).
 

My Computers

System One System Two

  • OS
    Windows 11 Pro 24H2
    Computer type
    PC/Desktop
    Manufacturer/Model
    Intel NUC12WSHi7
    CPU
    12th Gen Intel Core i7-1260P, 2100 MHz
    Motherboard
    NUC12WSBi7
    Memory
    64 GB
    Graphics Card(s)
    Intel Iris Xe
    Sound Card
    built-in Realtek HD audio
    Monitor(s) Displays
    Dell U3219Q
    Screen Resolution
    3840x2160 @ 60Hz
    Hard Drives
    Samsung SSD 990 PRO 1TB
    Keyboard
    CODE 104-Key Mechanical with Cherry MX Clears
    Antivirus
    Microsoft Defender
  • Operating System
    Linux Mint 21.2 (Cinnamon)
    Computer type
    PC/Desktop
    Manufacturer/Model
    Intel NUC8i5BEH
    CPU
    Intel Core i5-8259U CPU @ 2.30GHz
    Memory
    32 GB
    Graphics card(s)
    Iris Plus 655
    Keyboard
    CODE 104-Key Mechanical with Cherry MX Clears
Powershell:
Robocopy doesn't have a built-in option to exclude files if they exist in the source but are inaccessible in the source. As a result, when you specify the /MIR option, it treats inaccessible files in the source as if they don't exist in the source, thereby causing the /MIR option to delete them from the destination. (Even, if you don't want that.)

A possible workaround is to use a PowerShell script that tries to access all the files that it finds in the source, and, for each file that it fails to access in the source, temporarily changes the Access Control List (ACL) of the file in the destination to deny any attempt to delete the file in the destination. Temporarily, i.e., until the Robocopy process exits. The main reason why this script is a tad longer than you might expect is because an elevated PowerShell does not have all the permissions required to modify the ACLs, which is actually pretty weird IMO, but it's Microsoft so, not a big surprise there... But anyway, this PowerShell script contains inline C# code to grab these permissions, and, I know for sure that this part of the script works. The other part I haven't tested. At a glance, I think it looks like it could work.

Powershell:
# Check if the script is running with elevated permissions
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
    # Restart the script with elevated permissions
    Start-Process powershell.exe "-File `"$PSCommandPath`"" -Verb RunAs
    exit
}

Add-Type @"
using System;
using System.Runtime.InteropServices;

public class TokenManipulator
{
  [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
  internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
  ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
  [DllImport("kernel32.dll", ExactSpelling = true)]
  internal static extern IntPtr GetCurrentProcess();
  [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
  internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
  phtok);
  [DllImport("advapi32.dll", SetLastError = true)]
  internal static extern bool LookupPrivilegeValue(string host, string name,
  ref long pluid);
  [StructLayout(LayoutKind.Sequential, Pack = 1)]
  internal struct TokPriv1Luid
  {
    public int Count;
    public long Luid;
    public int Attr;
  }
  internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
  internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
  internal const int TOKEN_QUERY = 0x00000008;
  internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
  public static bool AddPrivilege(string privilege)
  {
    try
    {
      bool retVal;
      TokPriv1Luid tp;
      IntPtr hproc = GetCurrentProcess();
      IntPtr htok = IntPtr.Zero;
      retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
      tp.Count = 1;
      tp.Luid = 0;
      tp.Attr = SE_PRIVILEGE_ENABLED;
      retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
      retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
      return retVal;
    }
    catch (Exception ex)
    {
      throw ex;
    }
  }
  public static bool RemovePrivilege(string privilege)
  {
    try
    {
      bool retVal;
      TokPriv1Luid tp;
      IntPtr hproc = GetCurrentProcess();
      IntPtr htok = IntPtr.Zero;
      retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
      tp.Count = 1;
      tp.Luid = 0;
      tp.Attr = SE_PRIVILEGE_DISABLED;
      retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
      retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
      return retVal;
    }
    catch (Exception ex)
    {
      throw ex;
    }
  }
}
"@
[void][TokenManipulator]::AddPrivilege("SeRestorePrivilege")
[void][TokenManipulator]::AddPrivilege("SeBackupPrivilege")
[void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege")

$source = "C:\Source"
$destination = "D:\Destination"
$backupFile = "C:\Temp\Backup.txt"

# Function to check if a file is accessible
function Is-FileAccessible {
    param (
        [string]$filePath
    )

    try {
        $fileStream = [System.IO.File]::Open($filePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::None)
        $fileStream.Close()
        return $true
    }
    catch {
        return $false
    }
}

# Function to take ownership of a file
function Take-Ownership {
    param (
        [string]$filePath
    )
    $takeOwnershipCommand = "icacls `"$filePath`" /setowner `"Administrators`" /c /l /q"
    Invoke-Expression $takeOwnershipCommand
}

# Collect a list of inaccessible files and their corresponding files in the destination
$inaccessibleFiles = @()
Get-ChildItem -Path $source -Recurse -Force | ForEach-Object {
    if (-not (Is-FileAccessible -filePath $_.FullName) -and -not $_.Attributes.HasFlag([System.IO.FileAttributes]::ReparsePoint)) {
        $relativePath = $_.FullName.Substring($source.Length).TrimStart('\')
        $destinationPath = Join-Path $destination $relativePath
        if (Test-Path -Path $destinationPath) {
            $inaccessibleFiles += $destinationPath
        }
    }
}

# Backup the original ACL of the files, then take ownership and modify the ACL to deny deletion
$backupData = @()
foreach ($file in $inaccessibleFiles) {
    # Backup the original ACL
    $acl = Get-Acl -Path $file
    $backupData += [pscustomobject]@{ Path = $file; ACL = $acl }

    # Take ownership of the file
    Take-Ownership -filePath $file

    # Modify the ACL to deny deletion
    $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule((New-Object Security.Principal.SecurityIdentifier "S-1-1-0"), "Delete", "Deny")
    $acl.AddAccessRule($accessRule)
    Set-Acl -Path $file -AclObject $acl
}

# Save the backup data to a file
$backupData | Export-Csv -Path $backupFile -NoTypeInformation

# Run Robocopy with the /mir, /r:0, and /tee options
Start-Process robocopy -ArgumentList "$source $destination /mir /r:0 /tee" -NoNewWindow -Wait

# Restore the original ACL of the files
$backupData = Import-Csv -Path $backupFile
foreach ($entry in $backupData) {
    $acl = $entry.ACL
    Set-Acl -Path $entry.Path -AclObject $acl
}

# Cleanup the backup file
Remove-Item -Path $backupFile -Force
Also note, specifying the /W:0 option has no effect when you specify the /R:0 option.
 
Last edited:

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Mouse
    Logitech G402
    Keyboard
    Logitech K800
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF

My Computer

System One

  • OS
    Windows 11 23H2 Pro
    Computer type
    PC/Desktop
    Manufacturer/Model
    MSI
    CPU
    i3-1215U
    Memory
    8GB
    Monitor(s) Displays
    Dell S2721
    Screen Resolution
    3840x2160
    PSU
    External 65W
    Keyboard
    Cherry mechanical (Blue)
    Mouse
    Microsoft
    Browser
    FireFox
    Antivirus
    MS

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Mouse
    Logitech G402
    Keyboard
    Logitech K800
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
I corrected a stupid error that was preventing the script from backing up the owner of the files. That's what you get when you try to let Copilot write your PowerShell script. lol
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Mouse
    Logitech G402
    Keyboard
    Logitech K800
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
I ran some batches on about ten PCs, if I add only /b as recommended, the open files are not deleted in the destination and that is the expected result :) :) The only precaution is that the batch is run with administrator privileges. Normally without the /b parameter the request is not necessary. Thanks to all Ps the script for recovering permissions is a bit too "elaborate" for my purpose. Thanks again.
 

My Computer

System One

  • OS
    Vari
No, I was talking about these privileges:
I do know about privileges in Windows. I specifically said that this enabled privileges. The method I suggested is also described here: How to enable the SeCreateGlobalPrivilege in .NET without resorting to P/Invoke or reflection?

It's using reflection to get at internal features in .Net framework. I've used it succesfully with "SeRestorePrivilege" to write to registry keys owned by TrustedInstaller without changing ownership or permissions.
 

My Computer

System One

  • OS
    Windows 11 23H2 Pro
    Computer type
    PC/Desktop
    Manufacturer/Model
    MSI
    CPU
    i3-1215U
    Memory
    8GB
    Monitor(s) Displays
    Dell S2721
    Screen Resolution
    3840x2160
    PSU
    External 65W
    Keyboard
    Cherry mechanical (Blue)
    Mouse
    Microsoft
    Browser
    FireFox
    Antivirus
    MS
I do know about privileges in Windows. I specifically said that this enabled privileges. The method I suggested is also described here: How to enable the SeCreateGlobalPrivilege in .NET without resorting to P/Invoke or reflection?

It's using reflection to get at internal features in .Net framework. I've used it succesfully with "SeRestorePrivilege" to write to registry keys owned by TrustedInstaller without changing ownership or permissions.
I think the "I'm not sure it's really better, because it's more or less a hack, not supported et al., but ok, it's easy for lazy guys :-)" part is the part I will remember... 😏
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming F16 (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Mouse
    Logitech G402
    Keyboard
    Logitech K800
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF

Latest Support Threads

Back
Top Bottom