# 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