[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[rdiff-backup-users] Windows: backing up files the administrator cant re
From: |
don hess |
Subject: |
[rdiff-backup-users] Windows: backing up files the administrator cant read |
Date: |
Fri, 18 Jun 2010 17:14:36 -0400 |
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 address@hidden via Backup Central.
|Forward SPAM to address@hidden
+----------------------------------------------------------------------
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [rdiff-backup-users] Windows: backing up files the administrator cant read,
don hess <=