How to create file-sync script between two folders using power-shell - powershell

The following script works best but the error comes when one of the folder is empty.
$source="The source folder"
$target="The target folder"
$sourceFiles=Get-ChildItem -Path $source -Recurse
$targetFiles=Get-ChildItem -Path $target -Recurse
$syncMode=2
try{
$diff=Compare-Object -ReferenceObject $sourceFiles -DifferenceObject $targetFiles
foreach($f in $diff) {
if($f.SideIndicator -eq "<=") {
$fullSourceObject=$f.InputObject.FullName
$fullTargetObject=$f.InputObject.FullName.Replace($source, $target)
Write-Host "Attemp to copy the following: " $fullSourceObject
Copy-Item -Path $fullSourceObject -Destination $fullTargetObject
}
if($f.SideIndicator -eq "=>" -and $syncMode -eq 2) {
$fullSourceObject=$f.InputObject.FullName
$fullTargetObject=$f.InputObject.FullName.Replace($target,$source)
Write-Host "Attemp to copy the following: " $fullSourceObject
Copy-Item -Path $fullSourceObject -Destination $fullTargetObject
}
}
}
catch {
Write-Error -Message "something bad happened!" -ErrorAction Stop
}
Is it possible to have empty folder while sync the two folders together ?

Related

Powershell: Find folders with a specific name, and move contents up one level, rename if exists

I've got the first two-thirds of this one accomplished, but I'm stuck on the last part. I've got a script that searches for subfolders with a specific name, and moves their contents up one level. I have another script that moves files from one place to another, and renames them if the file already exists. What I'm trying to do now is merge the two. So here's the one that moves files up:
$sourceDir="E:\Deep Storage"
$searchFolder="Draft Materials"
Get-ChildItem -path $sourceDir -filter $searchFolder -Recurse |
ForEach-Object {
Get-ChildItem -File -Path $_.FullName |
ForEach-Object {
Move-Item -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath)
}
}
And here's the one that moves things while renaming if they already exist:
$sourceDir="E:\Test1"
$targetDir="E:\Deep Storage\Test1"
Get-ChildItem -Path $sourceDir -Filter *.* -Recurse | ForEach-Object {
$num=1
$nextName = Join-Path -Path $targetDir -ChildPath $_.name
while(Test-Path -Path $nextName)
{
$nextName = Join-Path $targetDir ($_.BaseName + "_$num" + $_.Extension)
$num+=1
}
$_ | Copy-Item -Destination $nextName -Verbose
}
And lastly, my attempt to hybridize the two:
$sourceDir="E:\Deep Storage"
$searchFolder="Draft Materials"
Get-ChildItem -path $sourceDir -filter $searchFolder -Recurse |
ForEach-Object {
Get-ChildItem -File -Path $_.FullName |
ForEach-Object {
$num=1
$nextName = Join-Path -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath)
while(Test-Path -Path $nextName)
{
$nextName = Join-Path -Path $_.FullName -Destination $(Split-Path -Parent $_.PSParentPath) ($_.BaseName + "_$num" + $_.Extension)
$num+=1
}
$_ | Copy-Item -Destination $nextName
}
}
I feel like I'm on the right track, but after two hours of attempts I haven't been able to get this to work.
EDIT: providing the exact syntax I'm giving it
$sourceDir="E:\Deep Storage\Projects"
$searchFolder="Draft Materials"
$destinationPath = "$($sourceDir)\.."
Write-Host "OPERATION: Search for Folders Named" -ForegroundColor White -BackgroundColor DarkGreen -NoNewLine;
Write-Host " '$searchFolder' " -ForegroundColor Yellow -BackgroundColor DarkGreen -NoNewLine;
Write-Host "and Move Contents Up One Level" -ForegroundColor White -BackgroundColor DarkGreen;
Write-Host "SEARCHDIR: $sourceDir" -ForegroundColor White -BackgroundColor DarkGreen;
# Get all directories in specific folders inside the source directory
$folders = Get-ChildItem -Path $sourceDir -Directory | Where-Object {$_.Name -like "$searchFolder*" -or $_.FullName -like "*\$searchFolder\*"}
foreach ($folder in $folders) {
# Get all files in the current folder
$files = Get-ChildItem -Path $folder.FullName
foreach ($file in $files) {
$destinationFile = Join-Path -Path $destinationPath -ChildPath $file.Name
if (Test-Path $destinationFile) {
# If a file with the same name exists in the destination directory, rename it
$name = $file.Name
$extension = $file.Extension
$i = 0
while (Test-Path $destinationFile) {
$i++
$name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
$destinationFile = Join-Path -Path $destinationPath -ChildPath $name
}
Write-Host "Renaming $($file.Name) to $name"
}
Move-Item $file.FullName $destinationFile -Verbose -WhatIf
}
}
Here's what I came up with reading OP's post, code, and comments:
$sourcePath = 'E:\Deep Storage\Projects'
$searchFolder = 'Draft Materials'
Write-Host "OPERATION: Search for Folders Named" -ForegroundColor White -BackgroundColor DarkGreen -NoNewLine;
Write-Host " '$searchFolder' " -ForegroundColor Yellow -BackgroundColor DarkGreen -NoNewLine;
Write-Host "and Move Contents Up One Level" -ForegroundColor White -BackgroundColor DarkGreen;
Write-Host "SEARCHDIR: $sourcePath" -ForegroundColor White -BackgroundColor DarkGreen;
# Get all directories in specific folders inside the source directory
$folders = (Get-ChildItem -LiteralPath $sourcePath -Directory -Recurse) | Where-Object Name -match $searchFolder
### Check selected folders
$Folders.FullName | Out-GridView -Title 'Selected Folders'
Read-Host 'Paused. Check selected folders in GridView. Press <enter> to continue '
###
ForEach ($folder in $folders)
{
# Get all files in the current folder
$filesToCopy = $folder | Get-ChildItem -File
# Get list of names for exising files in target (parent folder)
$targetPath = $folder.Parent.FullName
$filesInTarget = (Get-ChildItem -LiteralPath $targetPath -File).Name
ForEach ($file in $filesToCopy)
{
If ($file.Name -notIn $filesInTarget)
{
$file | Move-Item -Destination $targetPath -Verbose -WhatIf
}
Else
{
$i = 0
Do
{
$newName = '{0}_{1}{2}' -f ($file.BaseName, $i++, $file.Extension)
} Until ( $newName -notIn $FilesInTarget )
Write-Host ('Renaming "{0}" to "{1}"...' -f $file.Name , $newName)
$file | Move-Item -Destination (Join-Path $targetPath $newName) -Verbose -WhatIf
}
}
# Delete (hopefully empty) folder
If (!($folder | Get-ChildItem -Force))
{
$folder | Remove-Item -WhatIf
}
Else
{
Write-Host ('Items still exist in "{0}". Folder not deleted.' -f $folder.FullName)
}
}
Syntax choice: For any cmdlet that has Path/LiteralPath parameter sets (gci, Copy, Move, Rename, etc.), the System.IO.FileSystemInfo | <Cmdlet> syntax succeeds with items that would fail in the <Cmdlet> -Path (System.IO.FileSystemInfo).FullNaame form becasue special characters in their name would require the -LiteralPath parameter.
In many cases replacing -Path with -LiteralPath (or its alias: -lp) will work as well. But the pipelined format reads "cleaner" (IMHO) when scanning code and, if you're just learning PowerShell, reminds you to think in terms of pipelining whenever possible and avoiding intermediate variables. Just for grins, here's a version of the above code where items are piped as much as possible, using ForEach-Object:
(Get-ChildItem -LiteralPath $sourcePath -Directory -Recurse) |
where Name -match $searchFolder |
ForEach-Object {
# Get list of names for exising files in target (parent folder)
$targetPath = $_.Parent.FullName
$filesInTarget = (Get-ChildItem -LiteralPath $targetPath -File).Name
$_ | Get-ChildItem -File | ForEach-Object {
If ($_.Name -notIn $filesInTarget)
{
$_ | Move-Item -Destination $targetPath -Verbose -WhatIf
}
Else
{
$i = 0
Do
{
$newName = '{0}_{1}{2}' -f ($_.BaseName, $i++, $_.Extension)
} Until ( $newName -notIn $FilesInTarget )
Write-Host ('Renaming "{0}" to "{1}"...' -f $_.Name , $newName)
$_ | Move-Item -Destination (Join-Path $targetPath $newName) -Verbose -WhatIf
}
}
# Delete (hopefully empty) folder
If (!($_ | Get-ChildItem -Force))
{
$_ | Remove-Item -WhatIf
}
Else
{
Write-Host ('Items still exist in "{0}". Folder not deleted.' -f $_.FullName)
}
}
please try this:
$sourcePath = "C:\temp\test\Test"
$destinationPath = "$($sourcePath)\.."
# Get all files in the source directory
$files = Get-ChildItem -Path $sourcePath
foreach ($file in $files) {
$destinationFile = Join-Path -Path $destinationPath -ChildPath $file.Name
if (Test-Path $destinationFile) {
# If a file with the same name exists in the destination directory, rename it
$name = $file.Name
$extension = $file.Extension
$i = 0
while (Test-Path $destinationFile) {
$i++
$name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
$destinationFile = Join-Path -Path $destinationPath -ChildPath $name
}
Write-Host "Renaming $($file.Name) to $name"
}
Move-Item $file.FullName $destinationFile
}
This will not delete the original location and will move everything from the sourcePath to the parent location.
To delete the original location just add at the end:
Remove-Item -Path $sourcePath -Force -Confirm:$false
UPDATE1:
$sourcePath = "C:\temp\test\Test"
$destinationPath = "$($sourcePath)\.."
# Get all directories in specific folders inside the source directory
$folders = Get-ChildItem -Path $sourcePath -Directory | Where-Object {$_.Name -like "Folder1*" -or $_.FullName -like "*\Folder2\*"}
foreach ($folder in $folders) {
# Get all files in the current folder
$files = Get-ChildItem -Path $folder.FullName
foreach ($file in $files) {
$destinationFile = "$($folder.FullName)\.."
if (Test-Path $destinationFile) {
# If a file with the same name exists in the destination directory, rename it
$name = $file.Name
$extension = $file.Extension
$i = 0
while (Test-Path $destinationFile) {
$i++
$name = "{0}_{1}{2}" -f ($file.BaseName, $i, $extension)
$destinationFile = Join-Path -Path $destinationPath -ChildPath $name
}
Write-Host "Renaming $($file.Name) to $name"
}
Move-Item $file.FullName $destinationFile
}
}

Powershell - ForEach loop running twice on the same path instead of moving on next one

I am looking to move files from various paths to E:\backups\folder1\export, E:\Backups\folder2\backups, E:\backups\folder3\export and using below code...but strangely it runs twice on the same path and doesn't move to next path and duplicates the output too.
Cls
$date = Get-Date -Format "yyyMMdd_hhmmss"
#$sourcePath = "C:\Program Files\Atlassian\Application Data\JIRA\export\"
#$destPath = "E:\Backup\Jira\export"
$config = Import-Csv -Path 'E:\Backup\Scripts\Atlassian_Backups.csv'
#Write-Output $config
Start-Transcript -Path E:\Backup\Logs\Atlassian_backupMove.log
foreach ($item in $config)
{
Write-Host "Moving all files in '$($sourcePath)' to '$($destPath)'"
$fileList = #(Get-ChildItem -Path "$($sourcePath)" -File)
#Write-Output $fileList
if ($filelist.count -gt 0)
{
Write-host $filelist.Count
ForEach($file in $fileList)
{
try {
#Move-Item -Path $file.FullName -Destination ((Split-Path
$file.FullName).Replace("$($sourcePath)",$destPath)) -Force -ErrorAction Stop
Copy-Item -Path $file.FullName -Destination $destPath -Verbose -Force -ErrorAction Stop |
Format-table
}
catch{
Write-Warning "Unable to move '$($file.FullName)' to '$(((Split-Path
$file.FullName).Replace("$($sourcePath)",$destPath)))': $($_)"
return
}
}
}
}
Stop-Transcript
Rename-Item E:\Backup\Logs\Atlassian_backupMove.log
E:\Backup\Logs\Atlassian_backupMove_$date.log
write-host Log File has been created and renamed to Atlassian_backupMove_$date.log'
below was changed in my code and worked well.
{#Move-Item -Path $file.FullName -Destination ((Split-Path
$file.FullName).Replace("$($sourcePath)",$destPath)) -Force -ErrorAction Stop
Copy-Item -Path $file.FullName -Destination $item.destPath -Verbose -Force -
ErrorAction Stop | Format-table } catch{ Write-Warning "Unable to move
'$($file.FullName)' to '$(((Split-Path
$file.FullName).Replace("$($item.sourcePath)",$item.destPath)))': $($_)" return
}

powershell - check if folder exists before deleting it

I wanna delete all folders from out of a list (list.txt). Before deleting them, I want to check if they are still existing.
How can I do this task? Maybe with foreach or if? I am a newbie :)
And a second task: I have this list and I want to check for the folders which are still existent and write them into a new file.
$homedirectory = get-content -Path "c:\SCO_scripts\homedirectory_delete\list.txt"
if ( Test-Path -Path $homedirectory -PathType Container ) {
Remove-item $homedirectory -Force -recurse
}
or something like that?....
$homedirectory = get-content -Path "c:\SCO_scripts\homedirectory_delete\list.txt"
foreach ($folder in $homedirectory)
{
exists -Path $folder <---??? no idea how to make it :(
Add-Content -Path C:\SCO_scripts\homedirectory_delete\newFile.txt -Value $folder
}
**would you test this please **
$folders= Get-Content -Path C:\Temp\test.txt
foreach($i in $folders){
if (Test-Path -Path $i){
Write-Host $i exist
}
else{
Write-Host $i not exist
}
}
I have found a solution.
$folders= Get-Content -Path c:\SCO_scripts\homedirectory_delete\list.txt
foreach ($folder in $folders) {
$testpath = Test-Path $folder
if ($testpath -eq $true)
{
Write-Host "$folder Folder Exists" -ForegroundColor Green
Add-Content -Path C:\SCO_scripts\homedirectory_delete\newFile.txt -Value $folder
}
else
{
Write-Host "$folder is not Online" -ForegroundColor Red
}
}

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
}
}

Unable to delete zip folders older than 14 days

I am unable to delete zip folders older than 14 days from a directory. The rest of my script works fine, however the following code block is failing:
It has not thrown any errors, the path has been sanity checked, however, I placed old documents in to see if they are cleared up to no avail. It prints the statement that the folder path exists however does not delete anything from the folder.
if (!(Test-Path $folderpath)) {
New-Item -ItemType Directory -Path $folderpath
Write-Host "$folderpath created"
} else {
Write-Host "$folderpath already exists, will remove old items"
$HowOld = -14
Get-ChildItem $Path -Recurse |
where {$_.LastWriteTime -lt (Get-Date).AddDays($HowOld) -and -not $_.PSIsContainer} |
% {Remove-Item $_.FullName -Force -WhatIf}
}
Here is the full script for completeness:
#Get backup folder drive letter
$letter = [System.IO.DriveInfo]::getdrives() | Where-Object {$_.DriveType -eq 'Fixed' -and $_.Name -notlike '*C*'} | Select-Object -Property Name
[string] $drive = "$letter"
$Drive2 = $null
$Drive2 = $drive.Substring($drive.IndexOf('=')+1)
$BackupDrive = $Drive2.Substring(0, $Drive2.IndexOf('}'))
#Check the programname log path.
$logspath = "C:\ProgramData\programname\programname4.0\Logs"
If (!(test-path $logspath))
{
$IQlogspath = "C:\ProgramData\programname\iQSonar4.0\Logs"
}
Else
{
$IQlogspath = "C:\ProgramData\programname\programname4.0\Logs"
}
#check if backup folder exists, clean if exists and if not create it.
$folderpath = $BackupDrive + "programname_logs"
If(!(test-path $folderpath))
{
New-Item -ItemType Directory -Path $folderpath
write-host "$folderpath created"
}
Else
{
write-host "$folderpath already exists, will remove old items"
$HowOld = -14
get-childitem $Path -recurse | where {$_.lastwritetime -lt (get-date).adddays($HowOld) -and -not $_.psiscontainer} |% {remove-item $_.fullname -force -whatif}
}
#check if todays folder exists, if not create it
$todaysdate = (Get-Date).ToString('dd-MM-yyyy')
$todaysbackup = $folderpath + "\Logs_Backup_" + $todaysdate
$todaysbackupzip = $todaysbackup + ".zip"
If(!(test-path $todaysbackup))
{
New-Item -ItemType Directory -Path $todaysbackup
write-host "$todaysbackup created, now moving items"
#select and move files to backup folder
get-childitem -Path $IQlogspath |
where-object {$_.LastWriteTime -lt (get-date).AddDays(-7) -and $_.Name -notmatch "Service"} |
move-item -destination $todaysbackup
Start-Sleep -s 10
write-host "checking for zip"
If(Test-path $todaysbackupzip) {
write-host "$todaysbackupzip already exists, changing name"
$todaysbackupzip = $null
$todaysbackupzip = $folderpath + "\Logs_Backup_" + $todaysdate + ".re-run" + ".zip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
write-host "creating zip folder, $todaysbackupzip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
Else
{
write-host "$todaysbackup already exists, attempting to zip"
#check if zip backup folder already exists
If(Test-path $todaysbackupzip) {
write-host "$todaysbackupzip already exists, changing name"
$todaysbackupzip = $null
$todaysbackupzip = $folderpath + "\Logs_Backup_" + $todaysdate + ".re-run" + ".zip"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
Else
{
Start-Sleep -s 10
write-host "creating zip folder, $todaysbackupzip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
}
#Get OS disk label
$OSDisk = Get-WmiObject Win32_OperatingSystem | Select-Object WindowsDirectory
[string] $drive = "$OSDisk"
$Drive2 = $null
$Drive2 = $drive.Substring($drive.IndexOf('=')+1)
$OSDrive = $Drive2.Substring(0, $Drive2.IndexOf('\'))
$OSDrive2 = "'$OSDrive'"
$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID=$OSDrive2"| Select-Object FreeSpace
[INT] $FreeSpace = $disk.FreeSpace /1GB
If ($FreeSpace -gt 5) {
write-host "no additional backup requirement, exiting script"
exit
}
Else {
write-host "Running one off clear"
$OneOff = $IQlogspath + "\Logs_One_Off_" + $todaysdate
$OneOffZip = $OneOff + ".zip"
If(!(test-path $OneOff))
{
New-Item -ItemType Directory -Path $OneOff
write-host "$OneOff created"
}
Else {
write-host "folder already exists"
}
#select and move files to backup folder
write-host "moving logs to $OneOff"
get-childitem -Path $IQlogspath |
where-object {$_.Name -notmatch "Service"} |
move-item -destination $OneOff
Start-Sleep -s 10
write-host "creating zip folder, $todaysbackupzip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($OneOff, $OneOffZip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}