Iterate files recursively - powershell

I have a powershell script that iterates files from a certain network directory. In this directory, there are aroud 190 sub directories, each containing several files.
I use this to perform the job:
get-childitem -Path $pathFilesOrig -Recurse -Force -Include *.pdf, *.csv | ForEach {
write-host "INFO:File name: $_"
}
However, it does not loop in certain directories, whereas there are valid files in it and access rights are fine (I can access those files through windows explorer manually).
I have tried the following to check if I can at least iterate every directory:
get-childitem -Path $pathFilesOrig -Recurse -Force | ?{ $_.PSIsContainer } | ForEach {
write-host "INFO:Dir name: $_"
}
When I do it, the script displays every directory.
Now I do it to list files in each directory:
get-childitem -Path $pathFilesOrig -Recurse -Force | ?{ $_.PSIsContainer } | ForEach {
write-host "INFO:Dir name: $_"
$tmpDirName = $pathFilesOrig + $_.Name
get-childitem -Path $tmpDirName | ForEach {
Write-Host "INFO:File name: $_"
And in this case, again, some directories are missing.
There is not even the result of the second line write-host "INFO:Dir name: $_" which was working fine previously.
I don't understand, and I am certainly missing something...
Thanks for your help.

I suspect your problem has to do with the -Include parameter which filters items after the provider has collected all of the objects versus -Filter which handles it at enumeration, i.e., when it's getting the objects first. You can further improve performance by only enumerating files using the -File parameter.
#requires -Version 3
Get-ChildItem -Path $pathFilesOrig -Filter *.pdf, *.csv -File -Force -Recurse
If this command fails to resolve your problem, I suspect you actually do have a privileges problem since -Force will get hidden directories, but does not supersede access.

Related

How do I remove a Folder in Powershell?

we got a small script that creates folders named by the daily date. I got a script that deletes folders which are older than 30 days.
dir "\\nas\Backup_old\*" -ErrorAction SilentlyContinue |
Where { ((Get-Date) - $_.LastWriteTime).days -gt 30} |
Get-ChildItem -Recurse | Remove-Item -Recurse -Force
Principally it works fine. The Subfolders with contend will be deleted.
But the main folder is still existing and the LastWriteTime is canged to the runtime of the script. The folder is empty. Someone have a idea to solve this problem?
You probably just need to remove the second instance of Get-ChildItem (noting that dir is just an alias for Get-ChildItem), as that is causing it to remove the children of each of the directories returned by the first:
Get-ChildItem "\\nas\Backup_old\*" -ErrorAction SilentlyContinue |
Where-Object { ((Get-Date) - $_.LastWriteTime).days -gt 30} |
Remove-Item -Recurse -Force -WhatIf
Have a look at the WhatIf output and if it looks like it will now remove what you expect, remove -WhatIf.

Windows PowerShell - Delete Files Older than X Days

I am currently new at PowerShell and I have created a script based on gathered information on the net that will perform a Delete Operation for found files within a folder that have their LastWriteTime less than 1 day.
Currently the script is as follows:
$timeLimit = (Get-Date).AddDays(-1)
$oldBackups = Get-ChildItem -Path $dest -Recurse -Force -Filter "backup_cap_*" |
Where-Object {$_.PSIsContainer -and $_.LastWriteTime -lt $timeLimit}
foreach($backup in $oldBackups)
{
Remove-Item $dest\$backup -Recurse -Force -WhatIf
}
As far as I know the -WhatIf command will output to the console what the command "should" do in real-life scenarios. The problem is that -WhatIf does not output anything and even if I remove it the files are not getting deleted as expected.
The server is Windows 2012 R2 and the command is being runned within PowerShell ISE V3.
When the command will work it will be "translated" into a task that will run each night after another task has finished backing up some stuff.
I did it in the pipe
Get-ChildItem C:\temp | ? { $_.PSIsContainer -and $_.LastWriteTime -lt $timeLimit } | Remove-Item -WhatIf
This worked for me. So you don't have to ttake care of the right path to the file.
other solution
$timeLimit = (Get-Date).AddDays(-1)
Get-ChildItem C:\temp2 -Directory | where LastWriteTime -lt $timeLimit | Remove-Item -Force -Recurse
The original issue was $dest\$backup would assume that each file was in the root folder. But by using the fullname property on $backup, you don't need to statically define the directory.
One other note is that Remove-Item takes arrays of strings, so you also could get rid of the foreach
Here's the fix to your script, without using the pipeline. Note that since I used the where method this requires at least version 4
$timeLimit = (Get-Date).AddDays(-1)
$Backups = Get-ChildItem -Path $dest -Directory -Recurse -Force -Filter "backup_cap_*"
$oldBackups = $backups.where{$_.LastWriteTime -lt $timeLimit}
Remove-Item $oldBackups.fullname -Recurse -Force -WhatIf

Powershell script for comparing two directories based on file names only

I have two disks which has the same directory structure. C:\Files and D:\Files
Both C:\Files and D:\Files have multiple directories under them but have the same name etc, but the files inside them differ in extension. In C:\Files they are *.csv and in D:\Files, a process monitors the files (copied from C:\) and once it is done changes the files to *.processed.
I want a script that would do that copy. I.e copy files from C:\Files to D:\Files which have not been processed by comparing only the file names.
You want something like this. The property you want to compare on is called BaseName which powershell helpfully adds for you to the IO.FileSystemInfo class (FileInfo.BaseName exists in PowerShell but not in straight .NET). BaseName is just the name of the file, and doesn't contain any of the extensions that you don't care about.
$sourceFiles = Get-ChildItem C:\files -Recurse -File -Filter "*.csv"
$destinationFiles = Get-ChildItem D:\files -Recurse -File
foreach($sourceFile in $sourceFiles) {
$exists = $destinationFiles | Where-Object {$_.BaseName -eq $sourceFile.BaseName}
if(!$exists) {
Copy-Item $sourceFile.fullname -Destination "D:\Files\$($sourceFile.BaseName)"
}
}
dir .\ *csv -Recurse -File | cp -ea Ignore -WhatIf -Destination {
$dest=$_.FullName-replace'^C:','D:'-replace'\.csv','.processed'
if(Test-Path $dest){
Write-Host Already exists -ForegroundColor Yellow
$null
}else{
Write-Host Copying... -ForegroundColor Green
$dest-replace'\.processed$','.csv'
}
}
Notice the WhatIf parameter: you must remove it, if you're going to really copy the items.
Also, you may like to remove the 2 lines withwrite-host cmdlet.
Notive too, that I have hard-coded the C: and D: drives as source and destine drives.

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 }

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.