Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell - Delete all items except those in specific subdirectories

Tags:

powershell

I have a directory containing a load of subdirectories and files. I need to delete all files except those under SubFolder1.

Initial State:                       Desired Output:

\                                    \
|_Folder1                            |_Folder1
| |_File1.txt                          |_SubFolder1
| |_File2.xml                            |_File3.csv
| |_SubFolder1                           |_File4.exe
| | |_File3.csv
| | |_File4.exe
| |_Subfolder2
|_Folder2
| |_ <more files here>
|_Folder3 (etc)

So here's what I tried:

Remove-Item * -exclude Folder1\Subfolder1\*

And I get a warning like this:

Confirm
The item at C:\foo\Folder1 has children and the -recurse parameter was not specified. 
If you continue, all children will be removed with the item. Are you sure you want to continue?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help
(default is "Y"):

When I specify -recurse, it deletes every file, and seems to ignore my filters.

What's going on, and what's the correct way of doing this?

Edit: I've included a zip file which contains an example folder structure as above. If you want to test a solution, please try it against there. I've also included a second zip file which has the desired output, so you can check if it's working.

like image 599
NeilD Avatar asked Mar 06 '13 11:03

NeilD


2 Answers

(Get-ChildItem c:\folder1\ -recurse | select -ExpandProperty fullname) -notlike 'c:\folder1\subfolder1*' | sort length -descending | remove-item
like image 135
mjolinor Avatar answered Oct 05 '22 17:10

mjolinor


Maybe there's a simpler solution, but this function should do the trick:

function Clean-Folder
{
    param(
        [string]$rootfolder,
        [string[]]$excluded
    )
    $rootfolder = resolve-path $rootfolder
    Push-Location $rootFolder
    if($excluded -notmatch "^\s*$")
    {
        $excluded = Resolve-Path $excluded
    }
    $filesToDel = Get-ChildItem $rootFolder -Recurse
    # Excluding files in the excluded folder
    foreach($exclusion in $excluded)
    {
        $filesToDel = $filesToDel |?{$_.fullname -notlike ("{0}\*" -f $exclusion)}
        # Excluding parent folders of the excluded folder
        while($exclusion -notmatch "^\s*$")
        {
            $filesToDel = $filesToDel |?{$_.fullname -ne $exclusion}
            $exclusion = Split-Path -parent $exclusion
        }
    }
    $filesToDel |Remove-Item -Recurse -ErrorAction SilentlyContinue
    Pop-Location
}

Basically, what it does is recursively list all the items in your folder, then remove the one you want to keep, its sub-items and all its parent folders. Finally, it deletes the remaining list.

Just declare the function above, then:

Clean-Folder -rootfolder <path> -excluded <folder you want to exclude>

Edit: made rootfolder accept relative paths, and excluded accept a list of folders

like image 38
Poorkenny Avatar answered Oct 05 '22 17:10

Poorkenny