Powershell Error in deleting files and folders - powershell

I have a scenario where the powershell script should be deleting the log files and log folders in a path, lets say they are under the path C:\MLA\logs.
Below is the script that I have been using, it completes removes the files but the problem is the script does not work for deleting the folders, the error it displays is something like could not find part of the path
C:\MLA\logs\ART_Daily.
below is the script
$root=C:\MLA\logs
$limit=(Get-Date).AddDays(-90)
get-childitem -Path $root -Recurse -force |
where-Object {(($_.name -match 'Daily|ART|ABC|IIC') -or ($_.PSIsContainer -match 'Daily|ART|ABC|IIC')) -and ($_.CreationTime -lt $limit)} |Remove-Item -recurse -Force
The $name checks for files ( if the names piped are part of the file name for any of the file ) in the root path and $.PSIsContainer check for folders 9 f the names piped are part of the folder name for any of the folder ) inside the root path which is parametrized.
Can you help me out.

You need to correct your filter for starters:
$_.name -match 'Daily|ART|ABC|IIC'
will match files and folders with that name.
$_.PSIsContainer -match 'Daily|ART|ABC|IIC'
Will find nothing because the PSIsContainer property is boolean (is it a container or not: True/False?).

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.

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?)

How to keep a specific folder and delete rest of the files using 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.

Recurse with PowerShell's Get-ChildItem

This seems like it should be simple, and I'm sure it is, but I've not cracked it the best way it should be done.
I want to search through a folder structure returning folders which meet the following conditions.
Folders which contain .msi files, but don't include executable files.
Folders which contain .exe files, but don't include .msi files.
Folders which contain both exe and msi files.
Each of these will be piped to a column in a CSV file.
My problem is I can't work out how to effectively return folder names which include one file type, but exclude another. I know on paper this seems simple using -include *.msi, -exclude *.exe, etc., but a command such as gci -Recurse -Include *.msi -Exclude *.exe includes folders containing an msi and exe folder where I only want that folder containing msi's only to be returned.
I am using the following directory structure as a test
msi only
msi and exe
exe only
Does this make sense?
I was experimenting with | where directory -notcontains *.exe and all kinds of similar things, but none of them worked the way I wanted or expected.
Unfortunately include and exclude only work with the recurse parameter. You won't be able to do exclusion without recursion.
Here's an alternative.
$folders = dir -path ~ -recurse | ? {$_.PsIsContainer}
$folders | ForEach-Object {
$exe_files = $_ | dir -filter *.exe
$msi_files = $_ | dir -filter *.msi
$type = ''
if ($exe_files -and $msi_files) {$type = 'Both'}
if ($msi_files -and -not $exe_files) {$type = 'MSI_ONLY'}
if ($exe_files -and -not $msi_files) {$type = 'EXE_ONLY'}
if ($type) {
New-Object -TypeName PsObject -Property #{Path=$_.FullName;Type="$type"}
}
} | ConvertTo-Csv | Set-Content ~\out.csv