# Short Version
$arr=@();
$arr+=[PSCustomObject]@{From='D:\Someshare';To='\\NEWSERVER\Someshare'}
$arr+=[PSCustomObject]@{From='D:\Test';To='\\NEWSERVER\Test'}
# Normal copying
# $arr|%{emcopy $_.From $_.To /s /de /sdd /purge /secforce /r:1 /w:2 /c /log+:C:\emcopy_log.txt}
# Exclude recycle bins and preserve file owners
$emcopySwitches='/o /s /de /sd /sdd /purge /secforce /r:0 /w:0 /th 32 /c /log+:C:\emcopy_log.txt'
$arr|%{
$sourceParentFolder=split-path $_.From -Parent
$cmdlet="emcopy.exe '$($_.From)' '$($_.To)' $emcopySwitches /xd '$sourceParentFolder\`System Volume Information' '$sourceParentFolder\`$RECYCLE.BIN'"
write-host $cmdlet
Invoke-Expression $cmdlet
}
# Quick-Emcopy.ps1
# Longer Version
# This system backup privilege escalation should be ran only once per session
function addSystemPrivilege{
param(
[String[]]$privileges=@("SeBackupPrivilege","SeRestorePrivilege")
)
function includeSystemPrivileges{
$win32api = @'
using System;
using System.Runtime.InteropServices;
namespace SystemPrivilege.Win32API
{
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public UInt32 LowPart;
public Int32 HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID_AND_ATTRIBUTES
{
public LUID Luid;
public UInt32 Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_PRIVILEGES
{
public UInt32 PrivilegeCount;
public LUID Luid;
public UInt32 Attributes;
}
public class Privileges
{
public const UInt32 DELETE = 0x00010000;
public const UInt32 READ_CONTROL = 0x00020000;
public const UInt32 WRITE_DAC = 0x00040000;
public const UInt32 WRITE_OWNER = 0x00080000;
public const UInt32 SYNCHRONIZE = 0x00100000;
public const UInt32 STANDARD_RIGHTS_ALL = (
READ_CONTROL |
WRITE_OWNER |
WRITE_DAC |
DELETE |
SYNCHRONIZE
);
public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000u;
public const UInt32 STANDARD_RIGHTS_READ = 0x00020000u;
public const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001u;
public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002u;
public const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004u;
public const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000u;
public const UInt32 TOKEN_QUERY = 0x00000008;
public const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x00000001u;
public const UInt32 TOKEN_DUPLICATE = 0x00000002u;
public const UInt32 TOKEN_IMPERSONATE = 0x00000004u;
public const UInt32 TOKEN_QUERY_SOURCE = 0x00000010u;
public const UInt32 TOKEN_ADJUST_GROUPS = 0x00000040u;
public const UInt32 TOKEN_ADJUST_DEFAULT = 0x00000080u;
public const UInt32 TOKEN_ADJUST_SESSIONID = 0x00000100u;
public const UInt32 TOKEN_READ = (
STANDARD_RIGHTS_READ |
TOKEN_QUERY
);
public const UInt32 TOKEN_ALL_ACCESS = (
STANDARD_RIGHTS_REQUIRED |
TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE |
TOKEN_IMPERSONATE |
TOKEN_QUERY |
TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID
);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr GetCurrentThread();
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, UInt32 BufferLengthInBytes, IntPtr PreviousStateNull, IntPtr ReturnLengthInBytesNull);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool OpenThreadToken(IntPtr ThreadHandle, UInt32 DesiredAccess, bool OpenAsSelf, out IntPtr TokenHandle);
[DllImport("ntdll.dll", EntryPoint = "RtlAdjustPrivilege")]
public static extern int RtlAdjustPrivilege(
UInt32 Privilege,
bool Enable,
bool CurrentThread,
ref bool Enabled
);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
//
//
private static LUID LookupPrivilege(string privilegeName)
{
LUID privilegeValue = new LUID();
bool res = LookupPrivilegeValue(null, privilegeName, out privilegeValue);
if (!res)
{
throw new Exception("Error: LookupPrivilegeValue()");
}
return privilegeValue;
}
//
//
public static void AdjustPrivilege(string privilegeName, bool enable)
{
IntPtr accessToken = IntPtr.Zero;
bool res = false;
try
{
LUID privilegeValue = LookupPrivilege(privilegeName);
res = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, false, out accessToken);
if (!res)
{
res = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out accessToken);
if (!res)
{
throw new Exception("Error: OpenProcessToken()");
}
}
TOKEN_PRIVILEGES tokenPrivileges = new TOKEN_PRIVILEGES();
tokenPrivileges.PrivilegeCount = 1;
tokenPrivileges.Luid = privilegeValue;
if (enable)
{
tokenPrivileges.Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
tokenPrivileges.Attributes = 0;
}
res = AdjustTokenPrivileges(accessToken, false, ref tokenPrivileges, (uint)System.Runtime.InteropServices.Marshal.SizeOf(tokenPrivileges), IntPtr.Zero, IntPtr.Zero);
if (!res)
{
throw new Exception("Error: AdjustTokenPrivileges()");
}
}
finally
{
if (accessToken != IntPtr.Zero)
{
CloseHandle(accessToken);
accessToken = IntPtr.Zero;
}
}
}
}
}
'@
if ([object]::Equals(('SystemPrivilege.Win32API.Privileges' -as [type]), $null)) {
Add-Type -TypeDefinition $win32api
}
}
includeSystemPrivileges;
$privileges|%{[SystemPrivilege.Win32API.Privileges]::AdjustPrivilege($_, $true)}
# Validation
whoami /priv|?{$_ -match "SeBackupPrivilege|SeRestorePrivilege"}
}
addSystemPrivilege;
# Custom variables
$sourceDirectory="H:\HOME"
$destinationDirectory="\\FILESHERVER002\HOME"
$node="NODE05"
# Autogen variables
$logFile="\\snapshots\FileServerClusters\filecopy_logs\$node\quick-emcopy-log.txt"
$log="/LOG+:$logFile"
#$quickEmcopySwitches="/de /s /purge /r:0 /w:0 /c $log"
$quickEmcopySwitches="/o /s /de /sd /sdd /purge /secforce /r:1 /w:2 /th 32 /c $log"
function quickEmcopy{
param(
$sourceDirectory,
$destinationDirectory,
$logFile
)
$timer=[System.Diagnostics.Stopwatch]::StartNew();
$log="/LOG+:$logFile";
$message="=========================QuickEmcopy is starting on $env:computername at $(get-date -Format "yyyy-MM-dd-hh:mm:ss")=========================`r`n=========================Source: $sourceDirectory => Destination: $destinationDirectory=========================";
write-host $message;
Add-Content $logFile $message;
function expandZipfile($file, $destination){
$shell = new-object -com shell.application
$zip = $shell.NameSpace($file)
foreach($item in $zip.items()){
$shell.Namespace($destination).copyhere($item)
}
}
function installEmcopy{
$emcopyIsInstalled=(Get-Command emcopy.exe -ErrorAction SilentlyContinue) # Deterministic check on whether emcopy is already available on this system
if (!($emcopyIsInstalled)){
$tempDir="C:\Temp";
$extractionDir="C:\Windows"
$emCopySource = "https://blog.kimconnect.com/wp-content/uploads/2019/08/emcopy.zip";
$destinationFile = "$tempDir\emcopy.zip";
try{[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12}catch{}
New-Item -ItemType Directory -Force -Path $tempDir
New-Item -ItemType Directory -Force -Path $extractionDir
$webclient = New-Object System.Net.WebClient;
$WebClient.DownloadFile($emCopySource,$destinationFile);
expandZipfile $destinationFile -Destination $extractionDir
}else{
"EMCOPY is currently available in this system.`n";
}
}
if(!(Get-Command emcopy.exe -ea silentlycontinue)){installEmcopy};
$sourceParentFolder=split-path $sourceDirectory -Parent
$expression="emcopy.exe '$sourceDirectory' '$destinationDirectory' $quickEmcopySwitches /xd '$sourceParentFolder`System Volume Information' '$sourceParentFolder`$RECYCLE.BIN'";
try{
write-host $expression;
Invoke-Expression $expression;
}
catch{
write-host "There were errors`r`n $Error";
}
$hoursElapsed=[math]::round($timer.Elapsed.TotalHours,2);
$message="`r`n=========================QuickEmcopy has completed at $(get-date -Format "yyyy-MM-dd-hh:mm:ss") - Total Hours: $hoursElapsed=========================";
Add-Content $logFile $message;
return $timer.Elapsed.TotalHours
}
quickEmcopy -sourceDirectory $sourceDirectory -destinationDirectory $destinationDirectory -logFile $logFile
Categories: