PowerShell remove last sub folder - powershell

Is there a way how to remove only last empty folder with PowerShell?
Example: I have a folder structure
..-mainFolder
...................-subFolder1
........................................- a
........................................- b
........................................- c
..................-subFolder2
........................................- a
........................................- b
Every night with robocopy i copy everything to another server and afterword i should delete all last sub folders (a,b,c, etc..).
With /MUVE it removes "subFolder1" & "subFolder2" but they should stay there
(if i remove folders "a", "b", "c" the "subFolder1" is empty too so i cant delete all empty folders.)
I cant use /FX and i don't know the name of folders just root directory path "C:\SharedFolders\". and i know that the folders that should be removed is in 3rd level.

You could use the Get-ChildItem cmdlet with the -Directory switch to retrieve all folders, filter the empty folders using the Test-Path cmdlet and finally delete the folders using Remove-Item:
Get-ChildItem 'C:\SharedFolders' -Directory -Recurse |
where { -not (Test-Path (Join-Path $_.FullName '*')) } |
Remove-Item
This will remove only the last empty folders, result:
..-mainFolder
...................-subFolder1
..................-subFolder2

You can use Get-ChildItem -Recurse to retrieve all folders, then call the GetFiles() and GetDirectories() methods on the directory objects to determine if they are empty:
$EmptyDirs = Get-ChildItem C:\path\to\mailFolder -Directory -Recurse | Where {-not $_.GetFiles() -and -not $_.GetDirectories()}
# and then remove those
$EmptyDirs | Remove-Item

Related

Powershell: Find Folders and Run Command in Those Folders

so trying to find a way to combine a couple of things the Stack Overflow crowd has helped me do in the past. So I know how to find folders with a specific name and move them where I want them to go:
$source_regex = [regex]::escape($sourceDir)
(gci $sourceDir -recurse | where {-not ($_.psiscontainer)} | select -expand fullname) -match "\\$search\\" |
foreach {
$file_dest = ($_ | split-path -parent) -replace $source_regex,$targetDir
if (-not (test-path $file_dest)){mkdir $file_dest}
move-item $_ -Destination $file_dest -force -verbose
}
And I also know how to find and delete files of a specific file extension within a preset directory:
Get-ChildItem $source -Include $searchfile -Recurse -Force | foreach{ "Removing file $($_.FullName)"; Remove-Item -force -recurse $_}
What I'm trying to do now is combine the two. Basically, I'm looking for a way to tell Powershell:
"Look for all folders named 'Draft Materials.' When you find a folder with that name, get its full path ($source), then run a command to delete files of a given file extension ($searchfile) from that folder."
What I'm trying to do is create a script I can use to clean up an archive drive when and if space starts to get tight. The idea is that as I develop things, a lot of times I go through a ton of incremental non-final drafts (hence folder name "Draft Materials"), and I want to get rid of the exported products (the PDFs, the BMPs, the AVIs, the MOVs, atc.) and just leave the master files that created them (the INDDs, the PRPROJs, the AEPs, etc.) so I can reconstruct them down the line if I ever need to. I can tell the script what drive and folder to search (and I'd assign that to a variable since the backup location may change and I'd like to just change it once), but I need help with the rest.
I'm stuck because I'm not quite sure how to combine the two pieces of code that I have to get Powershell to do this.
If what you want is to
"Look for all folders named 'Draft Materials.' When you find a folder with that name, get its full path ($source), then run a command to delete files of a given file extension ($searchfile) from that folder."
then you could do something like:
$rootPath = 'X:\Path\To\Start\Searching\From' # the starting point for the search
$searchFolder = 'Draft Materials' # the folder name to search for
$deleteThese = '*.PDF', '*.BMP', '*.AVI', '*.MOV' # an array of file patterns to delete
# get a list of all folders called 'Draft Materials'
Get-ChildItem -Path $rootPath -Directory -Filter $searchFolder -Recurse | ForEach-Object {
# inside each of these folders, get the files you want to delete and remove them
Get-ChildItem -Path $_.FullName -File -Recurse -Include $deleteThese |
Remove-Item -WhatIf
}
Or use Get-ChildItem only once, having it search for files. Then test if their fullnames contain the folder called 'Draft Materials'
$rootPath = 'X:\Path\To\Start\Searching\From'
$searchFolder = 'Draft Materials'
$deleteThese = '*.PDF', '*.BMP', '*.AVI', '*.MOV'
# get a list of all files with extensions from the $deleteThese array
Get-ChildItem -Path $rootPath -File -Recurse -Include $deleteThese |
# if in their full path names the folder 'Draft Materials' is present, delete them
Where-Object { $_.FullName -match "\\$searchFolder\\" } |
Remove-Item -WhatIf
In both cases I have added safety switch -WhatIf so when you run this, nothing gets deleted and in the console is written what would happen.
If that info shows the correct files are being removed, take off (or comment out) -Whatif and run the code again.

I would like to exclude the files in subfolders and delete files in the other folders

I have mulitple sub-folders in the main folder which has number of files in each of them. I want to keep the contents of certain folders intact and delete the contents in the rest of them.
I tested the code, but it deletes the files in all the sub-folders 7 days before.
$Path="C:\Shreyas1"
$NumberOfDays="-7"
$CurrentDate=Get-Date
$DeleteDays=$CurrentDate.AddDays($NumberOfDays)
## Heading
##$excludes="Specs"
Get-ChildItem $Path -Exclude $excludes -Recurse |
Where-Object{($_.LastWriteTime -lt $DeleteDays )} |
Remove-Item
You should try using the same "Where" statement after your Get-ChildItem cmdlet to filter out specific file names. Try something like this:
Get-ChildItem $Path -Recurse | Where-Object {$_.Name -notlike "*$excludes*" -and $_.LastWriteTime -lt $DeleteDays}
Run that first to make sure you get what you want, then you can pipe to Remove-item -Confirm:$false like you have done in your OP. Edit: The -Confirm:$false switch means that it won't prompt you to confirm whether or not you want to delete the file, it will just delete. That is why you want to run Get-ChildItem first.

Powershell Recursive Copy Except Files found in Exclusion directory

Hi I have a folder Called "A" and folder "A" has files and sub folders within it. I also have another folder directory called "Exclusion" with some copied files and folders from "A" within it. I'm looking for a Powershell script or Command Line option that will COPY & MOVE all the objects from A that are NOT found in the Exclusion directory to a new folder directory called "Output".
Thanks,
-B
Use Get-ChildItem to get a list of files in your exclusion directory, then take only the names of the files and hold those in an array.
Optionally use New-Item with the -Force parameter to ensure that your output directory exists before sending files there.
Next use Get-ChildItem to iterate through all files in our source (A) directory, use Where-Object and the -notin operator to exclude any files which have the same names as those gathered from your exclusion directory, then use Move-Item to move the files to your destination (Output) directory.
[string[]]$filenamesToExclude = Get-ChildItem -Path 'c:\somewhere\exclusion' -Recurse | Select-Object -ExpandProperty Name
New-Item -Path 'c:\somewhere\output\' -ItemType 'Directory' -Force | Out-Null #ensure the target directory exists / don't output this command's return value to the pipeline
Get-ChildItem -Path 'c:\somewhere\A' -Recurse | Where-Object {$_.Name -notin $filenamesToExclude} | Move-Item -Destination 'c:\somewhere\output\'

Copying Folders with Wildcards

I am trying to copy a whole bunch of files using Powershell, from one directory to another on my computer.
I used Get-ChildItem C:\Users\Tom\Google Drive\My Files\*\Assessment 1\* to identify that this was the path that I wanted to copy too, and I know about Copy-Item, but I want to maintain parts of the path name when copied.
Example:
If I copy from C:\Users\Tom\Google Drive\My Files\Cool Stuff\Assessment 1\*
I want the files to go to a folder that is created called C:\Users\Tom\Archive\Cool Stuff\Assessment 1
Whereas if I copy from C:\Users\Tom\Google Drive\My Files\New Stuff\Assessment 1\*
I want the files to go to a folder that is created called C:\Users\Tom\Archive\New Stuff\Assessment 1
You could use the Get-ChildItem cmdlet to recursively find all Assessment 1 folders within your base directory and then remove the base path using -replace to finally copy the items using the Copy-Item cmdlet:
$baseDir = 'C:\Users\Tom\Google Drive\My Files\'
$destination = 'C:\Users\Tom\Archive\'
Get-ChildItem $baseDir -directory -Filter 'Assessment 1' -Recurse | ForEach-Object {
$newPath = Join-Path $destination ($_.FullName -replace [regex]::Escape($baseDir))
Copy-Item $_.FullName $newPath -Force -Recurse
}

How can Powershell copy an entire folder structure but exclude one folder and its contents

This seems like a simple operation but I can't figure out how to get Powershell to copy an entire folder structure from one location to another but exclude one folder (called 'connections') and its contents.
I've tried combining Copy-Item and Get-ChildItem like so
cpi (gci folder1 -Exclude connections) folder2 -recurse
but it seems the -recurse parameter overwrites the -exclude parameter and the connections folder and its contents are copied. Without -recurse the contents of the folders I do want copied are ignored.
I'm not sure why that isn't working, it seems to behave correctly on my machine.
You could always pipe to Copy-Item:
Get-ChildItem folder1 | where { !(($_ -is [System.IO.DirectoryInfo]) -and ($_.Name -eq "connections")) } | Copy-Item -Destination folder2 -Recurse
The advantage of this is that you can just get PowerShell to print out the output after:
Get-ChildItem folder1 | where { !(($_ -is [System.IO.DirectoryInfo]) -and ($_.Name -eq "connections")) }
That way you can check exactly what is getting copied (i.e. is the "connections" folder missing?)