How to keep a specific folder and delete rest of the files using powershell - powershell

I am trying delete all files within a folder but there is 1 folder called pictures which I would like to keep but don't know how to do that. I am using the following script , it deletes everything in a folder
if ($message -eq 'y')
{
get-childitem "C:\test" -recurse | % {
remove-item $_.FullName -recurse
}
}

One solution is to use something like:
Get-ChildItem -Path "c:\test" -Recurse | Where-Object { $_.FullName -cnotmatch "\\Pictures($|\\)" -and (Get-ChildItem $_.FullName -Include "Pictures" -Recurse).Length -eq 0 } | Remove-Item -Recurse -ErrorAction SilentlyContinue;
I suspect there must be a way more elegant way to do this. Here's what this does: it enumerates all files in the C:\test folder recursively (Get-ChildItem), then it removes all items from the result list using Where-Object where the path contains the directory to be excluded (specified using regex syntax) or when the item in question has child items that contains the file or directory to be excluded. The resulting list is fed to Remove-Item for removal. The -ErrorAction SilentlyContinue switch is applied to prevent errors being logged with recursive removal.

Get-ChildItem $PSScriptRoot -Force| Where-Object {$_.Name -ne "Pictures"} | Remove-Item -Recurse
I just tried this, and it worked for me. If you want to change what is deleted just change the "Pictures". This uses $PSScriptRoot for the path, which is the execution path of the Powershell script. You can rename that to be the path of where you want to delete.

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.

Deleting specific folders within folders that have changing names

So my boss needs me to create a script that deletes everything in a directory with the exception of the folders with the name "incoming" and "outgoing," while still deleting all files and directories within those folders. These two folders are also stored in random company name folders so I cant specify each one as the list will keep growing.
How can I delete all the incoming and outgoing folder contents without deleting the folder that those folders are stored in?
Here is the code I have so far:
Get-ChildItem -Path ("C:\Users\testuser\Desktop\Test") -Exclude "Incoming","Outgoing" | foreach ($_) {
"CLEANING :" + $_.FullName
Remove-Item $_.FullName -Force -Recurse
"CLEANED... :" + $_.FullName
}
Is this the right approach? is there a switch or something that I should be adding to this command to add extra options? This script will be run daily via a Windows task I'm going to setup. Maybe there's a way to specify how deep the deletion script goes?
Hopefully this is what you need. This should delete files and folders that are in under the folders "Incoming" and "Outgoing."
$folders = Get-ChildItem -Path "C:\Users\mkrouse\Desktop\Test" -Recurse -Directory | Where-Object {($_.basename -contains "Incoming") -or ($_.BaseName -contains "Outgoing")}
foreach($folder in $folders){
$items = Get-ChildItem -Path $folder.FullName -Recurse
foreach($file in $items) {
Remove-Item -Path $file.FullName -Recurse -Force -WhatIf
}
}

Delete parent directory if file is present with appropriate timestamp

Using PowerShell I'd like to search a directory tree which will have a subset of folders. If a file called NOW is present within those folders and is 3 days old I'd like to delete the parent directory.
I think I have the search syntax right, then piping to a foreach loop but I can't figure out how to remove the parent directory.
Get-ChildItem -Path C:\tools\test1 -Filter NOW -Recurse |
foreach ($_) ???
Any help would be much appreciated, thanks
Get-ChildItem returns System.IO.FileInfo objects for files. One of the properties is Directory. So what you would be wanting to remove the directory. The Directory is still and object and we need the full path from it.
Remove-Item $_.Directory.FullName -Force -Recurse
The above would remove the folder, where NOW resides, and its contents. But you have another condition for age. Couple of ways to do this but one would be to use New-TimeSpan to compare the creation time to Now. Using the Days property of the TimeSPam
(New-TimeSpan -start $_.CreationTime -end ([datetime]::Now)).Days -gt 3
Putting that together with what you already have. -File will ensure we dont get folder matches.
$refdate = (Get-Date).Date.AddDays(-3)
Get-ChildItem -Path "C:\tools\test1" -Filter "NOW" -Recurse -File |
Where-Object{$_.CreationTime -gt $refdate} |
ForEach-Object{ Remove-Item $_.Directory.FullName -Force -Recurse -WhatIf }
The -WhatIf will help you identify the folders this process would attempt to remove. If you dont have at least PowerShell version 3 you could do this.
$refdate = (Get-Date).Date.AddDays(-3)
Get-ChildItem -Path "C:\tools\test1" -Filter "NOW" -Recurse |
Where-Object{(!$_.PSIsContainer) -and ($_.CreationTime -gt $refdate)} |
ForEach-Object{ Remove-Item $_.Directory.FullName -Force -Recurse -WhatIf }

XCOPY deployment script - how to include certain files?

I need to copy only certain parts of a folder using Powershell, specifically this list:
$files = #("MyProgram.exe",
"MyProgram.exe.config",
"MyProgram.pdb",
".\XmlConfig\*.xml")
In human readable form: 3 specific MyProgram.* files under root of target folder and all XML files under XmlConfig folder which itself is under root of source path (..\bin\Release\ in my case). XmlConfig folder must be created in destination, if it does not exist.
What I have tried:
(1) I tried the following, but it did not work, i.e. no folder or files were created at the destination path:
Copy-Item -Recurse -Path "..\bin\Release\" -Destination ".\Test\" -Include $files
(2) When -Include is removed, whole folder structure is successfully created, including subfolders and files:
Copy-Item -Recurse -Path "..\bin\Release\" -Destination ".\Test\"
It must be something wrong with my understanding of how -Include filter works:
(3) I tested an assumption that -Include needs an array of wildcards, but this did not work either:
$files = #("*MyProgram.exe*",
"*MyProgram.exe.config*",
"*MyProgram.pdb*",
"*.\XmlConfig\*.xml*")
Please advise on how to properly do Copy-Item in my case.
UPDATE (based on below answers):
I am looking for a generic implementation that takes an array of strings. It opens the possibility to put all necessary files/paths in one place, for easy editing, so that a non-Powershell knowledgeable person can understand and modify it as required. So in the end it would be single script to perform XCOPY deployments for any project, with input file being the only variable part. For above example, the input would look like this (saved as input.txt and passed as an argument to the main script):
MyProgram.exe
MyProgram.exe.config
MyProgram.pdb
.\XmlConfig\*.xml
I would prefer wildcards approach, since not many people know regex.
i don't know what is wrong with filter but you can still do
$files | % { copy-item ..\bin\release\$_ -Destination .\test}
if you want to preserve directoty structure you'll have to weak this a little, like :
$sourcedir="c:\temp\test"
$f=#("existing.txt","hf.csv";"..\dir2\*.txt")
$f |%{
$source=ls (join-Path $sourcedir $_) |select -expand directoryname
if ("$source" -like "$sourcedir*"){
$destination=$source.Substring($sourcedir.Length)+".\"
}
else{
$destination=$_
}
copy-item $sourcedir\$_ -Destination $destination -WhatIf
}
AFAICT -Include works only with file names or directory names and not combinations i.e. paths. You can try something like this:
$files = 'MyProgram\.exe|MyProgram\.exe\.config|MyProgram\.pdb|XmlConfig\\.*?\.xml'
Get-ChildItem ..\bin\release -r | Where {!$_.PSIsContainer -and ($_.FullName -match $files)} |
Copy-Item -Dest .\test
With wildcards you could do it this way:
$files = #('*MyProgram.exe','*MyProgram.exe.config','*MyProgram.pdb','*\XmkConfig\*.xml')
Get-ChildItem ..\bin\release -r |
Foreach {$fn=$_.Fullname;$_} |
Where {!$_.PSIsContainer -and ($files | Where {$fn -like $_})} |
Copy-Item -Dest .\test