I'm trying to copy files for a backup script. I know that the some files aren't going to copy without an error message because of attributes. I want to log those files and not try to copy them, since it takes forever to fail in the copy. Plus we want to go back and fix/log or remove any files that don't copy once we find them.
Unfortunately, what I'm trying is finding a deeper subdir, and trying to copy that dir, and it's copying all the files in the dir, when some have an attribute I wouldn't want to copy. Ex:
\drive\folder\Forms\C Forms\ and it says it's a good attribute "16"
but there's a file in that dir that the copy is trying to copy over to my dest dir and I'm seeing it has this for attributes:
file.pdf Archive, SparseFile, ReparsePoint, Offline.
I found that by cd to the dir, and using this command:
dir | select Name,Attributes
I looked at recurse not hitting all levels, but I think it's not that recurse isn't hitting all levels, it's that it's copying higher level directories and the files are coming along too, without checking attributes first.
I was looking how check if path at is dir or file for ideas, but when I tried adding the check around the copy, it was skipping adding the dir above the file in it:
if(!((Get-Item $_) -is [System.IO.DirectoryInfo])) #true gives dir, false gives file, only handle if file
This is my code right now for the copy function (I tried an exclude but it didn't work):
function CopyFileToFolderUNC($SourcePath, $DestinationPath, $exclude){
if(-Not (Test-Path $SourcePath )) #-PathType Container
{
$global:ErrorStrings.Add("Exception: No such path, $SourcePath;; ")
write-output "++ Error: An error occured during copy operation. No such path, $SourcePath ++"
}
#$tempFileName = [System.IO.Path]::GetFileName($SourcePath)
#$tempDestFileNamePath = "$DestinationPath\$tempFileName"
Get-ChildItem -Path $SourcePath -Recurse -Depth 2| ForEach {$_} { #added file removed force -File , $SourcePath\*, $SourcePath\*\* -Depth 3
#test if maybe we are dealing with an off-line file here
#or use the enum name 'Offline'
# or use the numeric value: 4096
#$oldAttribs = $null
$attr = $_.Attributes.value__
write-output "++ $_ $attr ++"
if (($_.Attributes -eq [System.IO.FileAttributes]::Offline) -or ($_.Attributes.value__ -eq "4096")) {
$_.Attributes=[System.IO.FileAttributes]::Normal
#$oldAttribs = $_.Attributes
#make it a 'normal' file with only the Archive bit set
#$_.Attributes = [System.IO.FileAttributes]::Archive
#log that the file was an issue and copy the other ones
$global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. Offline. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, Offline $_ ++"
} #if
elseif(($_.Attributes -eq [System.IO.Fileattributes]::Archive) -or ($_.Attributes.value__ -eq "32")) {
$global:ErrorStrings.Add("Found archive file in backup dir, $_. Logging info and not copying this file. Archive. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, Archive $_ ++"
} #elseif
elseif(($_.Attributes -eq [System.IO.Fileattributes]::SparseFile) -or ($_.Attributes.value__ -eq "512")) {
$global:ErrorStrings.Add("Found sparse file in backup dir, $_. Logging info and not copying this file. SparseFile. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, SparseFile $_ ++"
} #elseif
elseif(($_.Attributes -eq [System.IO.Fileattributes]::ReparsePoint) -or ($_.Attributes.value__ -eq "1024")) {
$global:ErrorStrings.Add("Found reparse point file in backup dir, $_. Logging info and not copying this file. ReparsePoint. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, ReparsePoint $_ ++"
} #elseif
elseif( ($_.Attributes.value__ -eq "5664")) { #($_.Attributes -eq [System.IO.Fileattributes]::ReparsePoint) -or
$global:ErrorStrings.Add("Found reparse point file in backup dir, $_. Logging info and not copying this file. ReparsePoint. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, ReparsePoint $_ ++"
} #elseif
else {
#the file is not or no longer off-line, so proceed with the copy
#only if it's a file and not a dir
#if(!((Get-Item $_) -is [System.IO.DirectoryInfo])) #true gives dir, false gives file. We want to copy the files.
#{
write-output "Copying $_"
$_ | Copy-Item -Destination $DestinationPath -Force -Recurse -ErrorVariable errors
foreach($error in $errors)
{
if ($error.Exception -ne $null)
{
$global:ErrorStrings.Add("Exception: $($error.Exception);; ")
write-output "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++"
}
write-output "Error: An error occured during copy operation. Exception: $($error.Exception)"
}
#}
#else
#{
# write-output "this is a dir"
#}
} #else
} #Get-ChildItem
} #function
This is where it's called from:
$tempSource = @("\\drive\Svcs\Cr\C FORMS\",...)
$ToLocation = @("E:\DisasterBackup\toLoc\All Forms \",...)
$excludeNonSharepoint = @("\\drive\Svcs\Cred\op\zOLD_NOT USED_keep for now"...)
#non-sharepoint ones first
for($i=0; $i -lt ($tempSource.Length); $i++) {
CopyFileToFolderUNC $tempSource[$i] $ToLocation[$i] $excludeNonSharepoint
}
As requested, Minimal, Complete, and Verifiable example:
So for this dir/files/attributes, the copy will complete as follows after checking:
source From Location:
\\drive\folder\Forms attrib = normal/16
\\drive\folder\Forms\a.txt attrib = normal/16 will copy
\\drive\folder\Forms\b.txt attrib = not normal/32/512/1024/etc will not copy but log
\\drive\folder\Forms\C Forms = normal/16
\\drive\folder\Forms\C Forms\c.txt attrib = normal/16 will copy
\\drive\folder\Forms\C Forms\d.txt attrib = not normal/32/512/1024/etc will not copy but log/write-output
\\drive\folder\Forms\C Forms\e.txt attrib = not normal/32/512/1024/etc will not copy but log/write-output
\\drive\folder\Forms\C Forms\f.txt attrib = not normal/32/512/1024/etc will not copy but log/write-output
\\drive\folder\Forms\C Forms\subdir attribute = normal/16
\\drive\folder\Forms\C Forms\subdir\g.txt attribute = normal/16
\\drive\folder\Forms\C Forms\subdir\h.txt attribute = not normal/32/512/1024/etc will not copy but log/write-output
final To Location:
E:\DisasterBackup\toLoc\All Forms\a.txt
E:\DisasterBackup\toLoc\All Forms\C Forms
E:\DisasterBackup\toLoc\All Forms\C Forms
E:\DisasterBackup\toLoc\All Forms\C Forms\c.txt
E:\DisasterBackup\toLoc\All Forms\C Forms\subdir\
E:\DisasterBackup\toLoc\All Forms\C Forms\subdir\g.txt
output string at the end of the script will be something like:
"Could not copy \\drive\folder\Forms\C Forms\d.txt attrib archive
Could not copy \\drive\folder\Forms\C Forms\e.txt attrib sparse
Could not copy \\drive\folder\Forms\C Forms\f.txt attrib reparse
Could not copy \\drive\folder\Forms\C Forms\subdir\h.txt attrib offline"