Using PowerShell to loop through the contents of a folder - powershell

I am writing a script that will loop through a folder I have, and display the name of the files. The only problem I am facing, is there are many folders, inside of folders. Example(Inside Test Upload folder, are three more files and two more folders. Inside those two folders are 3 files, and another folder that contains a single file) I am unsure how to continue the loop, until all files and every folder has been read.
$Files = Get-ChildItem "C:\Users\HelloWorld\Documents\Test Upload"
#write-host $Files
GetFolderContents($Files)
function GetFolderContents($Test){
#$Sub = Get-ChildItem "C:\Users\HelloWorld\Documents\Test Upload\$Test"
foreach($files in $Test){
#check if folder or file
if (! $files.PSIsContainer)
{
write-host "File"
}
else{
write-host "Folder"
#need to now loop through this folder and get its contents
}
}
}

Use the -Recurse switch parameter with Get-ChildItem to have it recursively enumerate the whole directory structure:
$Files = Get-ChildItem "C:\Users\HelloWorld\Documents\Test Upload" -Recurse

Related

Copy-Item with overwrite?

Here is a section of code from a larger script. The goal is to recurse through a source directory, then copy all the files it finds into a destination directory, sorted into subdirectories by file extension. It works great the first time I run it. If I run it again, instead of overwriting existing files, it fails with this error on each file that already exists in the destination:
Copy-Item : Cannot overwrite the item with itself
I try, whenever possible, to write scripts that are idempotent but I havn't been able to figure this one out. I would prefer not to add a timestamp to the destination file's name; I'd hate to end up with thirty versions of the exact same file. Is there a way to do this without extra logic to check for a file's existance and delete it if it's already there?
## Parameters for source and destination directories.
$Source = "C:\Temp"
$Destination = "C:\Temp\Sorted"
# Build list of files to sort.
$Files = Get-ChildItem -Path $Source -Recurse | Where-Object { !$_.PSIsContainer }
# Copy the files in the list to destination folder, sorted in subfolders by extension.
foreach ($File in $Files) {
$Extension = $File.Extension.Replace(".","")
$ExtDestDir = "$Destination\$Extension"
# Check to see if the folder exists, if not create it
$Exists = Test-Path $ExtDestDir
if (!$Exists) {
# Create the directory because it doesn't exist
New-Item -Path $ExtDestDir -ItemType "Directory" | Out-Null
}
# Copy the file
Write-Host "Copying $File to $ExtDestDir"
Copy-Item -Path $File.FullName -Destination $ExtDestDir -Force
}
$Source = "C:\Temp"
$Destination = "C:\Temp\Sorted"
You are trying to copy files from a source directory to a sub directory of that source directory. The first time it works because that directory is empty. The second time it doesn't because you are enumerating files of that sub directory too and thus attempt to copy files over themselves.
If you really need to copy the files into a sub directory of the source directory, you have to exclude the destination directory from enumeration like this:
$Files = Get-ChildItem -Path $Source -Directory |
Where-Object { $_.FullName -ne $Destination } |
Get-ChildItem -File -Recurse
Using a second Get-ChildItem call at the beginning, which only enumerates first-level directories, is much faster than filtering the output of the Get-ChildItem -Recurse call, which would needlessly process each file of the destination directory.

Move Folders based on files in Folder

I want to know if this is possible with PowerShell.
I have folders that have file within them
Some folders have only TIF files
Some folders have both TIF and TXT files
I want to see if PowerShell can look in each folder and when it finds a directory that has both TIF and TXT files, move that directory to another location.
I believe I have the base to move a folder but need to see if I can wrap that ability to move based on folder content.
$srcfolder = "C:\Work\Test2"
$finalfolder = "c:\work\TestReview"
$combine = "C:\Work\Scripts\Tools\ImageMagick\convert.exe "
$arg1 = " -compress zip "
if (!(Test-Path -path $finalfolder)) {
Move-Item -Path $srcfolder -Destination $finalfolder -force
}

Excluding Parent Directory if Any File is New

My company has individual folders on a share for each project they are working on, and if no files inside one of those folders or its subfolders has been touched in the last six months, I want to move them to an archive location. If any one file within the folder or any of its subfolders have been modified in the last six months, I want to skip the entire parent directory. I'm most of the way there now, but my current iteration only skips the individual files, and I'm not sure how to specify skipping the entire parent. Here is my current script:
$Date = (Get-Date).AddMonths(-6)
$Source = 'C:\Scripts\Source'
$Dest = 'C:\Scripts\Test Target'
Get-ChildItem $Source -File -Recurse | Where {$_.LastWriteTime -lt $Date} | ForEach {
$actualSource = Split-Path $_.FullName
$actualDest = Split-Path $_.FullName.Replace($source,$dest)
robocopy $actualSource $actualDest $_.Name /SEC
}
When using my test directories, I have a folder C:\Scripts\Source\Drivers. The script copies that Drivers folder like I want it to, but if I put a newer file anywhere within that Drivers folder, I want the entire folder to be skipped. Currently, the folder and anything older than six months within the folder are still being copied, and it is just skipping the individual files which are newer.
Please let me know if any more information is needed.
Simply pull back your copy and recurse statement one level up. First you want to iterate through all the parent folders. Then for each parent folder, recurse and check to see if there is any modified files, if there is, then copy the folder:
$Date = (Get-Date).AddMonths(-6)
$Source = 'C:\Scripts\Source'
$Dest = 'C:\Scripts\Test Target'
$ParentFolders = Get-ChildItem $Source -Directory
Foreach($Folder in $ParentFolders){
$NewFiles = Get-ChildItem $Folder -File -Recurse | Where {$_.LastWriteTime -lt $Date}
if($NewFiles.Count -eq 0)
{
#Archive
robocopy $Folder $Dest /SEC
}
}

Powershell - Comparing and overriding a folder

I am trying to create a powershell script to compare 1 folder to another, say Folder A to Folder B. I want my script to make folder B look exactly like Folder A every time this script runs. Overriding anything in there, and deleting anything in Folder B that is not in Folder A. I have no code for it yet, and everything ive tried does not work. I made a script that copies from Folder A to Folder B and it works but wont delete anything different and wont override a file. So if its already in there, it doesn't care that the item in Folder A is newer, it will keep Folder B old file:
Test-Path "C:\Users\Shawn\Desktop\Scripts\New Folder"
if((Test-Path True))
{
Copy-Item -Path "C:\Users\Shawn\Pictures\" -Destination "C:\Users\Shawn\Desktop\Scripts\New Folder" -recurse
}
else
{
New-Item -Path "C:\Users\Shawn\Desktop\Scripts\New Folder" -ItemType directory
Copy-Item -Path "C:\Users\Shawn\Pictures\" -Destination "C:\Users\Shawn\Desktop\Scripts\New Folder" -recurse
}

Powershell copy script with condition check

Our requirement is to copy files from source to the destination folder.
The clause is during the first run of the script everything should be copied but in the subsequent runs it should copy only those files which have not been copied till yet and are new ones.
The issue is from the destination folder we have a script that works on the files and remove them once executed. So we dont want duplicate files from source copied to destination.
Example
source-> abc.txt,def.xt
after 1strun
dest->abc.txt,def.txt
subsequent runs
source->abc.txt,def.xt, ghi.txt
dest->abc.txt,def.xt, ghi.txt
Now when another script has worked on dest folder and removed abc.txt and ghi.txt then the logic should be
source->abc.txt,def.xt, ghi.txt,jkl.txt
Now when the script runs it should only copy the new files
dest->ghi.txt, jkl.txt
I was thinking if we can log the output after the script is run for the first time to a txt file and then put a condition to check in that log file if the text file is there before copying anything from the source folder to the destination .
Hope was able to explain.
Thx
You could copy those files which are not in your history like this:
$sourceFolder = "..."
$destFolder = "..."
$historyFile = "history.txt"
$recurse = $false
$history = Get-Content $historyFile
Get-ChildItem $sourceFolder -Recurse:$recurse | ? {
-not $_.PSIsContainer -and $history -notcontains $_.FullName
} | % {
Copy-Item $_.FullName $destFolder
$_.FullName >> $historyFile
}
The line $_.FullName >> $historyFile appends the copied files to the history file.