The only thing I found to work was SubInACL. Make sure that you have the 5.2.3790.1180 version because the earlier versions are broken and it must be run on a 32 bit environment. This means on 64 bit windows, run it in the 32 bit Powershell. This will allow you to take ownership of the file and change permissions. Here is a Powershell script I wrote to help copy some really messy directories.
#============================================================================================== # NAME: Copy-DirWithPerms.ps1 # AUTHOR: Don Hess # DATE: 2010-04-08 # REV: 1.0.0 # COMMENT: # # REVISION: # 1.0.0 Release # # TODO: # SubinACL needs to have the output log file changed so that when you play it back, the perms # are applied to the destination directory # Simplify and compartmentalize so you can run robocopy or subinacl. # More switches to allow subinacl to do backup and restore one directory or recursively. #============================================================================================== param ( [string] $s = "NA" , [string] $d = "NA" , [switch] $perms = [switch]::$false , [switch] $rc = [switch]::$false , [switch] $f = [switch]::$false , [switch] $h = [switch]::$false) [string] $strScriptName = 'Copy-DirWithPerms.ps1'; [string] $script:datetimecolon = Get-Date -uformat "%Y-%m-%d %I:%M:%S %p TZ(%Z)"; # YYYY-MM-DD HH-MM-SS AM/PM note the Powershell Get-Help Get-Date -full has the wrong letter abreviations to get the date we want, this will work instead [string] $script:datetimeunder = Get-Date -uformat "%Y-%m-%d %I_%M_%S %p"; # YYYY-MM-DD HH-MM-SS AM/PM note the Powershell Get-Help Get-Date -full has the wrong letter abreviations to get the date we want, this will work instead [string] $script:cname = ( Get-Content env:computername ); [string] $script:strUserPrincipalName = $env:USERNAME + "@" + $env:USERDNSDOMAIN; # Get current user principal name # Turn both switches on by default if nothing is specified. if ( ($perms -eq $false) -and ($rc -eq $false) ) { $perms = $true; $rc = $true; } # -h help output function helpme() { Write-Host ""; Write-Host " Copy a directory to a destination with all permissions intact."; Write-Host ""; Write-Host " Usage:"; Write-Host " $strScriptName -s <string> -d <string> [-rc] [-h]"; Write-Host ""; Write-Host " Switches:"; Write-Host " -s Source directory. Required"; Write-Host " -d Destination directory. Required"; Write-Host " -perms Run permission fix only, take owership and full control via user "; Write-Host " running the script to make sure everything can be copied."; Write-Host " -rc Run robocopy only"; Write-Host " -f Force run. Used with -rc for the second run when the destination"; Write-Host " directory is already present."; Write-Host " -h This Help."; Write-Host ""; Write-Host " Examples:"; Write-Host " Copy-DirWithPerms.ps1 -s `"\\server\d$\dir1`" -d `"\\server\e$\dir2`" "; Write-Host ""; Write-Host " Do not run subinACL, run just robocopy"; Write-Host " Copy-DirWithPerms.ps1 -s `"\\server\share1`" -d `"\\server\e$\dir2`" -rc"; Write-Host " "; Write-Host " Run just subinACL to fix permissions"; Write-Host " Copy-DirWithPerms.ps1 -s `"\\server\share1`" -perms"; Write-Host " "; Write-Host " Notes:"; Write-Host " The user running this script must be able to take ownership of directories"; Write-Host " and files. This applies for the -perms and -rc switches and is usually for"; Write-Host " a domain admin."; Write-Host " The destination directory sharing is not set up, you must do that manually"; Write-Host " Robocopy will create a missing destination directory when using -rc but will "; Write-Host " not do the sharing permissions."; Write-Host " You can copy network shares but the destination should really be specified "; Write-Host " to the admin share (\\server\d$\dir) instead of the network share to "; Write-Host " eliminate any potential permission issues. "; } if ( $h.isPresent ) { helpme; Return;} [string] $script:log = "NA" # Set output switch "$l" so the funcOutputResult funtion work correctly if ( $log -ne "NA" ) { [switch] $script:l = $true; } else { [switch] $script:l = $false; } ##### Check logging capability ##### # Check if path is something other than ending in a file. if ( $l.isPresent -and (-not (Test-Path -path "$log" -pathType Leaf)) ) { $null = New-Item -Path "$log" -ItemType file -ErrorVariable $evar -ErrorAction SilentlyContinue if ( $? -eq $false ) { Write-Host "Cannot write to log file location: `'$log`' " -Backgroundcolor red; Return 3; } } # Check if path ends in a file if ( $l.isPresent -and (Test-Path -path "$log" -pathType Leaf) ) { # test of permissions on log file Out-File -Filepath "$log" -Inputobject " " -Append -ErrorVariable $evar -ErrorAction SilentlyContinue # if log file test of write fails, yell and bail out. if ( $? -eq $false ) { Write-Host " Cannot write to log file location: `'$log`' " -Backgroundcolor red; Return 3; } } # This will output text to the screen or file function funcOutputResult ( [switch] $d, [switch] $ft, [switch] $fl, [switch] $all, [object] $textobj, [string] $strBColor, [string] $strFColor ) { # -textobj can be a string object, datetime, array, or may other objects that # need to looped through to get their output. # -d will display to screen # -l will log to file. This is a script wide switch set outside this function. # You need to make sure the $log file location is specified as a param. # -fl is Format-List # -ft is Format-Table # -all is to show all attibutes of the Format-List or Format-Table # -strBColor is background color # -strFColor is forground color # -fl and -ft overrides -strBColor and -strFColor # check if log file path has been passed to us. if ( $l.IsPresent -and $log -eq "NA" ) { Write-Host "Log file doesn't exist" -BackgroundColor Red; Return; } if ( $ft.IsPresent -or $fl.IsPresent ) { if ( $l.IsPresent ) { # if display is present output that next and when done do the logging if ( $d.IsPresent ) { if ( $fl.IsPresent ) { if ( $all.IsPresent ) { $textobj | ForEach-Object { $_ | Format-List * | Out-Host; }; } else { $textobj | ForEach-Object { $_ | Format-List | Out-Host; }; } } if ( $ft.IsPresent ) { if ( $all.IsPresent ) { $textobj | ForEach-Object { $_ | Format-Table * | Out-Host; }; } else { $textobj | ForEach-Object { $_ | Format-Table | Out-Host; }; } } } # Done writing to display # Now write to log file if ( $fl.IsPresent ) { # Write list formated output to file if ( $all.IsPresent ) { $textobj | ForEach-Object { $_ | Format-List * | Out-File -Filepath "$log" -Append -ErrorVariable $evar -ErrorAction SilentlyContinue; }; # check if write failed if ( $? -eq $false ) { $textout = "Failed to write to log file: $log." ; Write-Host $textout -BackgroundColor Red; } } else # -all is not present { $textobj | ForEach-Object { $_ | Format-List | Out-File -Filepath "$log" -Append -ErrorVariable $evar -ErrorAction SilentlyContinue; }; # check if write failed if ( $? -eq $false ) { $textout = "Failed to write to log file: $log." ; Write-Host $textout -BackgroundColor Red; } } } if ( $ft.IsPresent ) { # Write list formated output to file if ( $all.IsPresent ) { $textobj | ForEach-Object { $_ | Format-Table * | Out-File -Filepath "$log" -Append -ErrorVariable $evar -ErrorAction SilentlyContinue; }; # check if write failed if ( $? -eq $false ) { $textout = "Failed to write to log file: $log." ; Write-Host $textout -BackgroundColor Red; } } else # -all is not present { $textobj | ForEach-Object { $_ | Format-Table | Out-File -Filepath "$log" -Append -ErrorVariable $evar -ErrorAction SilentlyContinue; }; # check if write failed if ( $? -eq $false ) { $textout = "Failed to write to log file: $log." ; Write-Host $textout -BackgroundColor Red; } } } } # End logging of -fl and -ft else # No logging { if ( $d.IsPresent ) { if ( $fl.IsPresent ) { if ( $all.IsPresent ) { $textobj | ForEach-Object { $_ | Format-List * | Out-Host; }; } else { $textobj | ForEach-Object { $_ | Format-List | Out-Host; }; } } if ( $ft.IsPresent ) { if ( $all.IsPresent ) { $textobj | ForEach-Object { $_ | Format-Table * | Out-Host; }; } else { $textobj | ForEach-Object { $_ | Format-Table | Out-Host; }; } } } # Done writing to display } # End just display of -fl and -ft } # End -fl and -ft else # $ft and $fl are not present { if ( $l.IsPresent ) { # if display is present output that next and when done do the logging if ( $d.IsPresent ) { if ( $strBColor -ne "" ) { if ( $strFColor -ne "" ) # bg=y, fg=y { $textobj | ForEach-Object { Write-Host $_ -BackgroundColor $strBColor -ForegroundColor $strFColor; }; } else # bg=y, fg=n { $textobj | ForEach-Object { Write-Host $_ -BackgroundColor $strBColor; }; } } else { if ( $strFColor -ne "" ) # bg=n, fg=y { $textobj | ForEach-Object { Write-Host $_ -ForegroundColor $strFColor; }; } else # bg=n, fg=n { $textobj | ForEach-Object { Write-Host $_; }; } } } # Now write to log file $textobj | ForEach-Object { $_ | Out-File -Filepath "$log" -Append -ErrorVariable $evar -ErrorAction SilentlyContinue; }; # check if write failed if ( $? -eq $false ) { $textout = "Failed to write to log file: $log." ; Write-Host $textout -BackgroundColor Red; } } # End plain logging else # No logging { if ( $d.IsPresent ) { if ( $strBColor -ne "" ) { if ( $strFColor -ne "" ) # bg=y, fg=y { $textobj | ForEach-Object { Write-Host $_ -BackgroundColor $strBColor -ForegroundColor $strFColor; }; } else # bg=y, fg=n { $textobj | ForEach-Object { Write-Host $_ -BackgroundColor $strBColor; }; } } else { if ( $strFColor -ne "" ) # bg=n, fg=y { $textobj | ForEach-Object { Write-Host $_ -ForegroundColor $strFColor; }; } else # bg=n, fg=n { $textobj | ForEach-Object { Write-Host $_; }; } } } } # End of logging for "$ft and $fl are not present" } # End $ft and $fl are not present } function funcSanityChecks() { # Check for multiple issues with inputs # # Inputs: Just the params passed in script execution # # Returns: 1 if something is wrong, 0 if everything is OK. # what version of subinacl is needed? subinacl version 5.2.3790.1180 # what version of robocopy is needed? robocopy Version XP010 # need to be in a 32 bit environment. $env:PROCESSOR_ARCHITECTURE = "x86" if we are on 32 bit, else is is AMD64 if ( ($env:PROCESSOR_ARCHITECTURE -ne "x86") -and ($perms.isPresent)) { $textobj = " This script must be run in a 32 bit environment because of the subinacl program."; funcOutputResult -d -textobj "$textobj" -strFColor "Red"; Return 1; } #$subvercheck = (( subinacl \? ) | Where-Object { $_ -cmatch "SubInAcl version 5.2.3790.1180"; } ); #if ( ) #{ # $textobj = " This script must be run in a 32 bit environment because of the subinacl program."; # funcOutputResult -d -textobj "$textobj" -strFColor "Red"; # Return 1; #} if ( (Test-Path -PathType Container "$strSource") -and ($perms.isPresent -or $rc.isPresent) ) { Out-Null; # Everything is fine. } else # Doesn't exist { $textobj = " Please input the source path directory"; funcOutputResult -d -textobj "$textobj" -strFColor "Red"; Return 1; } if ( $rc.isPresent ) { # Check if parent directory exits [string] $f1 = Split-Path "$strDest"; # Gives us the parent if ( Test-Path -PathType Container "$f1" ) { Out-Null; # Everything is fine. } else { $textobj = " The parent directory does not exist for: `'$strDest`' "; funcOutputResult -d -textobj "$textobj" -strFColor "Red"; Return 1; } # Check if destination directory already exists, and user is not looking to run robocopy only # Robocopy will create the directory if it is missing, this is to prevent overwrite of existing files. if ( (Test-Path -PathType Container "$strDest") -and ($f -eq $false) ) { $textobj = " The destination directory `'$strDest`' `n is already present. This script does not allow merging of directories. "; funcOutputResult -d -textobj "$textobj" -strFColor "Red"; $textobj = " Please rename the existing destination directory and try again. "; funcOutputResult -d -textobj "$textobj" -strFColor "Red"; Return 1; } } Return 0; } # End funcSanityChecks ############################### MAIN ############################### #################################################################### # Note that file logging is handled by the funcOutputResult function automatically $textobj = "------------------ $datetimecolon ------------------"; funcOutputResult -d -textobj "$textobj"; $textobj = " Computer name: $cname"; funcOutputResult -d -textobj "$textobj"; # Set to more readable variables [string] $script:strSource = $s; [string] $script:strDest = $d; [array] $arrSanityResult = funcSanityChecks; switch ( $arrSanityResult[0] ) { 0 { # Everything is fine Out-Null; } 1 { $textobj = ( " Error in funcSanityChecks function." ); funcOutputResult -d -textobj "$textobj" -strFColor "Red"; Return; } default { $textobj = ( " Weird error `'" + $arrSanityResult[0].tostring() + "`' was returned from the sanity checks." ); funcOutputResult -d -textobj "$textobj" -strFColor "Red"; Return; } } if ( $perms.isPresent ) { # # Get permissions of from source directory via subinacl, store to log file # [string] $suboutputlog = "$env:TEMP" + '\permsfile-' + "$datetimeunder" + '.txt'; # [string] $args2 = '/noverbose /outputlog="' + $suboutputlog + '" /subdirectories "' + $strSource + '" /display'; # [Diagnostics.Process]::Start("subinacl", "$args2").WaitForExit(); # if ( $? ) # { $textobj = " Subinacl perm backup to `'$outputlog`' completed "; # funcOutputResult -d -textobj "$textobj"; # } # else # { $textobj = "***** Subinacl perm backup to `'$outputlog`' FAILED. ***** "; # funcOutputResult -d -textobj "$textobj" -strBColor "Red"; # Return 3; # } # # # # Create destination directory, note that parent dir was checked for # # and an existing destination directory in funcSanityChecks # New-Item -ItemType Directory -Path "$strDest" -ErrorAction SilentlyContinue | Out-Null; # if ( $? ) # { $textobj = " Create destination `'$strDest`' completed "; # funcOutputResult -d -textobj "$textobj"; # } # else # { $textobj = "***** Create destination `'$strDest`' FAILED. ***** "; # funcOutputResult -d -textobj "$textobj" -strBColor "Red"; # Return 3; # } # # # # Set permissions of to destination directory via subinacl # [string] $args2 = '/playfile "' + $suboutputlog + '"'; # [Diagnostics.Process]::Start("subinacl", "$args2").WaitForExit(); # if ( $? ) # { $textobj = " Subinacl perm restore from `'$outputlog`' completed "; # funcOutputResult -d -textobj "$textobj"; # } # else # { $textobj = "***** Subinacl perm restore from `'$outputlog`' FAILED. ***** "; # funcOutputResult -d -textobj "$textobj" -strBColor "Red"; # Return 3; # } function funcTakeOwnershipFullAccess ( [string] $path1 ) { # To set ownership on <FolderPath>: # subinacl /subdirectories <FolderPath> /setowner=<DomainName\UserName> # To set ownership for all the <FolderPath> objects: # subinacl /subdirectories <FolderPath>\*.* /setowner=<DomainName\UserName> [string] $suboutputlog = "$env:TEMP" + '\permschange-' + "$datetimeunder" + '.txt'; Get-ChildItem $path1 | ForEach-Object { $strCurrentFullName = $_.FullName; if ( $_.psIsContainer -eq $false ) { # Set the owner to who we are so we can get and set permissions as needed later. #[string] $args2 = '/outputlog="' + $suboutputlog + '" /subdirectories "' + $strCurrentFullName + '" /setowner="' + $strUserPrincipalName + '"' ; [string] $args2 = '/noverbose /subdirectories "' + $strCurrentFullName + '" /setowner="' + $strUserPrincipalName + '"' ; [Diagnostics.Process]::Start("subinacl", "$args2").WaitForExit(); if ( $? ) { $textobj = " Ownership of $strCurrentFullName completed "; funcOutputResult -d -textobj "$textobj"; } else { $textobj = "***** Ownership of $strCurrentFullName completed ***** "; funcOutputResult -d -textobj "$textobj" -strBColor "Red"; Return 3; } # Allow full access so we can copy the file. $aclCurrent = Get-Acl -path "$strCurrentFullName" $Ar = New-Object system.security.accesscontrol.filesystemaccessrule("$strUserPrincipalName","FullControl","Allow") $aclCurrent.AddAccessRule($Ar) Set-Acl -path "$strCurrentFullName" -aclObject $aclCurrent if ( $? ) { $textobj = " Full control of $strCurrentFullName completed "; funcOutputResult -d -textobj "$textobj"; } else { $textobj = "***** Full control of $strCurrentFullName completed ***** "; funcOutputResult -d -textobj "$textobj" -strBColor "Red"; Return 3; } } if ( $_.psIsContainer -eq $true ) { # Set the owner to who we are so we can get and set permissions as needed later. #[string] $args2 = '/outputlog="' + $suboutputlog + '" /subdirectories "' + $strCurrentFullName + '" /setowner="' + $strUserPrincipalName + '"' ; [string] $args2 = '/noverbose /subdirectories "' + $strCurrentFullName + '" /setowner="' + $strUserPrincipalName + '"' ; [Diagnostics.Process]::Start("subinacl", "$args2").WaitForExit(); if ( $? ) { $textobj = " Ownership of $strCurrentFullName completed "; funcOutputResult -d -textobj "$textobj"; } else { $textobj = "***** Ownership of $strCurrentFullName completed ***** "; funcOutputResult -d -textobj "$textobj" -strBColor "Red"; Return 3; } # Allow full access so we can copy the file. $aclCurrent = Get-Acl -path "$strCurrentFullName" $Ar = New-Object system.security.accesscontrol.filesystemaccessrule("$strUserPrincipalName","FullControl","Allow") $aclCurrent.AddAccessRule($Ar) Set-Acl -path "$strCurrentFullName" -aclObject $aclCurrent if ( $? ) { $textobj = " Full control of $strCurrentFullName completed "; funcOutputResult -d -textobj "$textobj"; } else { $textobj = "***** Full control of $strCurrentFullName completed ***** "; funcOutputResult -d -textobj "$textobj" -strBColor "Red"; Return 3; } # call ourselves to go through this directory funcTakeOwnershipFullAccess "$strCurrentFullName"; } } } # call our function to get everything started. funcTakeOwnershipFullAccess "$strSource"; } # End of if ( $rc -eq $false ) if ( $rc.isPresent ) { # Run robocopy to copy contents from source to destination with all permissions # Note you need to have the Manage Auditing user right for robocopy to work. [string] $roboutputlog = "$env:TEMP" + '\robocopylog-' + "$datetimeunder" + '.txt'; [string] $args2 = '"' + $strSource + '" ' + '"' + $strDest + '" /V /NP /E /COPYALL /B /IPG:3 /R:10 /W:30 /TEE /LOG:"' + $roboutputlog + '"'; [Diagnostics.Process]::Start("robocopy", "$args2").WaitForExit(); if ( $? ) { $textobj = " Robocopy copy from `'$strSource`' `n to `'$strDest`' completed "; funcOutputResult -d -textobj "$textobj"; } else { $textobj = "***** Robocopy copy from `'$strSource`' to `'$strDest`' FAILED. ***** "; funcOutputResult -d -textobj "$textobj" -strBColor "Red"; Return 3; } # Robocopy switch descriptions: # /V :: produce Verbose output, showing skipped files. # /NP :: No Progress - don't display % copied. # /E :: copy subdirectories, including Empty ones. # /COPYALL :: COPY ALL file info (equivalent to /COPY:DATSOU). # /B :: copy files in Backup mode. # /IPG:n :: Inter-Packet Gap (ms), to free bandwidth on slow lines. # /R:n :: number of Retries on failed copies: default 1 million. # /W:n :: Wait time between retries: default is 30 seconds. # /TEE :: output to console window, as well as the log file. # /LOG:file :: output status to LOG file (overwrite existing log). # Other useful switches # Do not use the mirror feature (/MIR), it will delete on the source if you run into problems # /MON:n :: MONitor source; run again when more than n changes seen. # /MOT:m :: MOnitor source; run again in m minutes Time, if changed. # /LOG+:file :: output status to LOG file (append to existing log). $textobj = "`n You can now rerun robocopy to make sure nothing has been changed on the source while you were copying it. `n You should check the robocopy log file `'$roboutputlog`' `n for anything that your user did not have permission to read.`n You may also manually delete the source directory. `n"; funcOutputResult -d -textobj "$textobj"; } +---------------------------------------------------------------------- |This was sent by don.h...@braemarinc.com via Backup Central. |Forward SPAM to ab...@backupcentral.com. +---------------------------------------------------------------------- _______________________________________________ rdiff-backup-users mailing list at rdiff-backup-users@nongnu.org http://lists.nongnu.org/mailman/listinfo/rdiff-backup-users Wiki URL: http://rdiff-backup.solutionsfirst.com.au/index.php/RdiffBackupWiki