Why doesn't this create a file on the destination server? - powershell

I recently did a storage migration and we had about 700 files that failed to migrate out of around 7 million (we need to purge some files, I know). I wrote the script below that is supposed to look at the corresponding file on the destination, compare the date values and if the file doesn't exist or has an older date, it's supposed to copy it over. Unfortunately, it's not copying it over. I don't get any errors but the file doesn't land on the destination. What am I doing wrong?
Also, I originally tried to grab the entire directory but it choked on the volume of files so that's why it parses each directory in turn instead.
$toplvl = "D:\Users\"
$folders = Get-ChildItem -Path $toplvl -Directory
$file = ""
$folders | ForEach-Object {
$original = $_.FullName
$dest = $_.FullName.Replace("D:","\\NewFileServer\D$")
$OutputFile = $_.FullName.Replace($toplvl,"D:\filelist-")
$FirstFind=0 #used to create a header in the output file
# Get all files under $original, filter out directories
$filelist = Get-ChildItem -Recurse $original | Where-Object { -not $_.PsIsContainer }
Write-Host $original #write directories to host to track progress
$filelist | ForEach-Object {
## Check if the file (from $original) exists with the same path in $dest
If (Test-Path ($_.FullName.Replace($original,$dest) ) ) {
## the file from $original has a match in $dest
$file = Get-Childitem -Path $_.FullName.Replace($original,$dest)
If ($_.LastWriteTime -gt $file.LastWriteTime) {
## file from $original is newer than $dest
If ( -Not ($FirstFind)) {Add-Content -Path $OutputFile -Value "Original File, Date"}
$FirstFind = 1
Add-Content -Path $OutputFile -Value $_.FullName -NoNewline
Add-Content -Path $OutputFile -Value "," -NoNewline
Add-Content -Path $OutputFile -Value $_.LastWriteTime
Copy-Item -Path $_.FullName -Destination $file.FullName
}
else {
## file from $original is same or older than $dest; can remove else statement
}
}
else {
## the file from $original is missing from $dest
If ( -Not ($FirstFind)) {Add-Content -Path $OutputFile -Value "Original File, Date"}
$FirstFind = 1
Add-Content -Path $OutputFile -Value $_.FullName -NoNewline
Add-Content -Path $OutputFile -Value "," -NoNewline
Add-Content -Path $OutputFile -Value $_.LastWriteTime
Copy-Item -Path $_.FullName -Destination $_.FullName.Replace($original,$dest)
}
}
}
Hopefully I didn't mess this up copying it over - it's my first time posting and I'm still figuring out the formatting.

Related

PowerShell Script (foreach-loop problems)

I have a short question, but I am standing on the wall for too long now, so I have to ask you....
The situation is:
I have a special filetype, in different folders and subfolders.
I already managed to find the files, write them into a TXT-File and I also managed to split the path so I can name a ZIP-File with the Folder-Name and Date.
But the only thing I do not get is how to only zip the special file of folder1 in a Zip-archiv "folder1-date.zip" and the file of folder2 in a Zip-archiv "folder2-date.zip".
Code part looks like this:
[string[]]$dirs = (Split-Path (Split-Path -Path $output -Parent) -Leaf | Foreach-Object { $i++; $_ })
[string[]]$arrayFromFile = Get-content -Path 'C:\TEMP\output.txt'
foreach ($file in $arrayFromFile) {
foreach ($dir in $dirs){
#
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip }
}
The Problem is, that every file with the extension found is in every ZIP-Archiv (logic because it is a foreach in a foreach) but I can not find the right way to do it....
Thank you for the help!
This will get the desired outcome and not have to save output to a text file.
$origin = "C:\TEMP\"
$filetyp = ".stl, .vol, .pct, .tif"
$destination = "C:\Daten\zipstore\"
$date = $(Get-Date -Format d)
$fileNames = Get-ChildItem "$origin" -Recurse | Where {$_.extension -eq ".stl"} | ForEach-Object { $_.FullName }
foreach ($file in $fileNames) {
$dir = (Split-Path (Split-Path -Path $file -Parent) -Leaf)
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip
}
Thank you for the answer! Here you have the whole code:
# Variablen Definition:
#
$origin = "C:\TEMP\"
$filetyp = ".stl, .vol, .pct, .tif"
$destination = "C:\Daten\zipstore\"
$date = $(Get-Date -Format d)
#
#
# Auslesen aller Files die bestimmte Dateiendung haben:
#
Get-ChildItem "$origin" -Recurse | Where {$_.extension -eq ".stl"} | ForEach-Object { $_.FullName } > C:\TEMP\output.txt
#
#
# Remove filename, keep path to file / split and only keep last directory:
#
$output = Get-content C:\TEMP\output.txt
$i = 0
#
[string[]]$dirs = (Split-Path (Split-Path -Path $output -Parent) -Leaf | Foreach-Object { $i++; $_ })
#
#
# Create ZIP-Archiv:
#
[string[]]$arrayFromFile = Get-content -Path 'C:\TEMP\output.txt'
foreach ($file in $arrayFromFile) {
foreach ($dir in $dirs){
#
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip }
}
#
#
# Delete files not needed anymore:
Remove-Item -Path $origin -Include *.txt -Recurse -Force
#
Maybe this helps!

Archive files from a folder which are older than one week to a sub folder using powershell

I have tried below powershell script to move files older than 7 days from Newfolder to Archive_folder. The script is moving the entire path to the Archive_folder (means its creating folders \Users\529817\New folder in to Archive_folder and then copying files and not zipping the folder) , I need help in copying only files from NewFolder to Archive_folder and zip that folder.
$ArchiveYear = "2018"
$ArchiveMonth = "10"
$ArchiveDay = "10"
$SourcePath = "C:\Users\529817\New folder"
$TargetPath = "C:\Users\529817\New folder\Archive_folder"
$YourDirToCompress = "C:\Users\529817\New folder"
$ZipFileResult = "C:\Users\529817\New folder\Archive_folder\$ArchiveDay$ArchiveMonth.zip"
Get-ChildItem $YourDirToCompress -Directory |
#where { $_.Name -notin $DirToExclude} |
Compress-Archive -DestinationPath $ZipFileResult -Update
$Days = "7"
$LogPath = "C:Users\529817\Temp"
$Date = Get-Date -format yyyy-MM-dd_HH-mm
$TargetFolder = "$TargetPath\$Date"
$LogFile = "$LogPath\ArchiveLog-$date.txt"
$TargetZipFile = "$TargetPath\$Date.zip"
$Activity = "Move files older than $Days days from $SourcePath to $TargetFolder"
Write-Verbose $Activity
$OldFiles = Get-Childitem -Path $SourcePath -recurse | Where-Object {$_.LastWriteTime -lt (get-date).AddDays( - $days)}
$Total = $Oldfiles.Count
$Current = 0
$OldFiles | ForEach {
$Current ++
$Filename = $_.fullname
Write-Progress -Activity $Activity -Status $FileName -PercentComplete ($Current / $Total * 100)
$Split = $FileName -split '\\'
$DestFile = $split[1..($split.Length - 1)] -join '\'
$DestFile = "$TargetFolder\$DestFile"
Try {
$null = New-Item -Path $DestFile -Type File -Force
$Null = Move-Item -Path $FileName -Destination $DestFile -Force -ErrorAction:SilentlyContinue
"Successfully moved $filename to $targetfolder" | add-content $LogFile
}
Catch {
$Err = $_.Exception.Message
Write-Error $Err
"Error moving $filename`: $Err " | add-content $LogFile
}
}
You have two problems here:
Your zip file isn't going where you want it to go
Instead, all of the items which should be in the zip are going where the zip should go.
Let's figure out why this is happening so you can do what you need to get it working.
Problem 1
You have line 10 which looks like this:
Compress-Archive -DestinationPath $ZipFileResult -Update
This creates the Zip file but you don't actually do anything with this file, as in we don't see this $ZipFileResult used again in the code. This is why your zip file isn't showing up where you want it to be.
Problem 2
The end of this script has this big block where you are expressly copying the files to the directory,right where you don't want them.
Try {
$null = New-Item -Path $DestFile -Type File -Force
$Null = Move-Item -Path $FileName -Destination $DestFile -Force -ErrorAction:SilentlyContinue
"Successfully moved $filename to $targetfolder" | add-content $LogFile
}
If you only want to move the Zip file, then you can shorten this whole script. Delete everything from line 19 and on down, which begins with this line.
$OldFiles = Get-Childitem -Path $SourcePath -recurse | Where-Object {$_.LastWriteTime -lt (get-date).AddDays( - $days)}
And instead, add a Move-Item command to copy that $ZipFileResult file over to whichever directory you want it to go.
Finally, there are a number of lines which don't do anythign and can be deleted, like this line $TargetZipFile = "$TargetPath\$Date.zip"

How can I get Powershell to generate logs after moving files?

Hi this is the first time I create a program using powershell, I created a powershell script to move old files that are not in use to a NAS, the code works as what I want, but I need a Log.txt file for find out what files have been moved. can someone please help me?
$Date = Get-Date -UFormat %d-%m-%Y
$Source = 'C:\Source\'
$Temp = 'C:\Backup-Temp\'
$Nas = 'D:\Destination\'
$Ext = "*.zip","*.rar"
$SetTime = '-5'
New-Item -Path $Temp -Name "Backup-$Date" -ItemType "directory"
Foreach ($Ext in $Ext) {
get-childitem -Path "$Source" -Recurse |
Where-object {$_.LastWriteTime -lt (get-date).AddDays($SetTime) -and $_.name -like "$Ext"} |
Move-item -destination "$Temp\Backup-$Date" |
Compress-Archive -Path "$Temp\Backup-$Date" -DestinationPath "$Nas\Backup-$date.Zip"
}
$Date = Get-Date -UFormat %d-%m-%Y
$Source = 'C:\Source\'
$Temp = 'C:\Backup-Temp\'
$Nas = 'D:\Destination\'
$Ext = "*.zip","*.rar"
$SetTime = '-5'
$LogFileFullName = 'c:\tmp\log.txt'
function Write-Log([string]$msg){
Out-File -FilePath $LogFileFullName -InputObject "$([DateTime]::Now): $msg" -Append
}
New-Item -Path $Temp -Name "Backup-$Date" -ItemType "directory"
Foreach ($Ext in $Ext) {
get-childitem -Path "$Source" -Recurse |
Where-object {$_.LastWriteTime -lt (get-date).AddDays($SetTime) -and $_.name -like "$Ext"} |
ForEach-Object {
Move-item $_.FullName -destination "$Temp\Backup-$Date" |
Compress-Archive -Path "$Temp\Backup-$Date" -DestinationPath "$Nas\Backup-$date.Zip"
Write-Log $_.FullName
}
}
You could just add the following to your chain of piped commands:
Add-Content $logfile "$_.name`n"
where $logfile is set to a static filename prior.
I may be old-fashioned, but having so many commands in one chain is prone to failure. It would be more resilient to break-up the chain so that you can include some error checking along the way.
A better but less desirable option would be to put your chain within a try/catch block.
Best of luck.

How to log copied items during the backup script?

I need to make basic / or more advanced backup script that would copy items from folder A to folder B and then log what it did.
This copies the files just fine:
$source = 'path\gamybinis\*'
$dest = 'path\backup'
Get-ChildItem -Path $source -Recurse | Where-Object { $_.LastWriteTime -gt [datetime]::Now.AddMinutes(-5)
}| Copy-Item -Destination $dest -Recurse -Force
Write-Host "Backup started"
Pause
But after this I can't write the log with | Out-File, So I've tried this:
$source = 'path\gamybinis\*'
$dest = 'path\backup'
$logFile = 'path\log.txt'
$items = Get-ChildItem -Path $source -Recurse | Where-Object { $_.LastWriteTime -gt [datetime]::Now.AddMinutes(-5)
}
foreach($item in $items){
Out-File -FilePath $logFile -Append
Copy-Item -Path "$source\$item" -Destination $dest -Recurse -Force
}
Write-Host "Backup started"
Pause
This one does absolutely nothing, what exactly am I doing wrong?
(Advanced script part would be: backing up recently modified files then files should be archived to .rar/.zip, log file have to have structure that is easily readable and log file should have information which user was working on the device during the backup) - For those who are wondering.
If you can't use robocopy, in pure PowerShell code you could do this
$source = 'path\gamybinis' # no need for '\*' because you're specifying -Recurse
$dest = 'path\backup'
$logFile = 'path\log.txt'
# test if the destination path exists. If not, create it first
if (!(Test-Path -Path $dest -PathType Container)) {
$null = New-Item -Path $dest -ItemType Directory
}
Write-Host "Backup started"
Get-ChildItem -Path $source -Recurse |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-5) } |
ForEach-Object {
$_ | Copy-Item -Destination $dest -Recurse -Force
Add-Content -Path $logFile -Value "$((Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) - Copied file '$($_.FullName)'"
}
Write-Host "Backup done"
From your comments, I understand you have problems when using the -Container switch.
Below code does not use that and creates the folder structure of the copied files in the backup folder, strictly using Powershell code:
$source = 'path\gamybinis' # no need for '\*' because you're specifying -Recurse
$dest = 'path\backup'
$logFile = 'path\log.txt'
Write-Host "Backup started"
Get-ChildItem -Path $source -File -Recurse |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddMinutes(-5) } |
ForEach-Object {
$target = Join-Path -Path $dest -ChildPath $_.DirectoryName.Substring($source.Length)
if (!(Test-Path $target -PathType Container)) {
# create the folder if it does not already exist
$null = New-Item -Path $target -ItemType Directory
}
$_ | Copy-Item -Destination $target -Force
Add-Content -Path $logFile -Value "$((Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) - Copied file '$($_.FullName)'"
}
Write-Host "Backup done"

How do I show progress of copying files older than 1 day from one folder to other another?

We need to know in code what files were copied and some files were old and were not copied.
$date = (get-date).AddDays(-1)
get-childitem -File c:\t\*.*,c:\f\*.*,c:\u\*.*,c:\s\*.* | where-object {$_.LastWriteTime -gt $date} |
Copy-Item -Destination c:\t\1 ```
If you're on PowerShell 4.0 or newer, you could use the .Where({}) extension method in "Split" mode to split new and old files into two groups:
$new,$old = #(Get-ChildItem -File C:\t\*.*).Where({$_.LastWriteTime -gt $date}, 'Split')
# Write file names to log files
$new.Name > newfiles.txt
$old.Name > oldfiles.txt
$new | Copy-Item -Destination C:\t\1\
If by 'showing progress' you mean writing some info to the console, then this could be what you want.
$date = (Get-Date).AddDays(-1)
$dest = 'C:\t\1'
# if the destination folder does not exist, create it first
if (!(Test-Path $dest -PathType Container)) {
New-Item -Path $dest -ItemType Directory | Out-Null
}
Get-ChildItem -Path 'C:\t','C:\f','C:\u','C:\s' -File | ForEach-Object {
if ($_.LastWriteTime -gt $date) {
Write-Host "Copying file '$($_.FullName)'" -ForegroundColor Green
$_ | Copy-Item -Destination $dest
}
else {
Write-Host "File '$($_.FullName)' is too old.. Skipped" -ForegroundColor Yellow
}
}