size of files based on particular extensions - powershell

I am trying to find all files in a specific drive that are accessed before 40 days, find their file type and specificy size of files based on extension.
I have 40000 files in 126 folders, and total of 51 different extensions (file types), now that i want to find what type of file occupy who much space.
With this I got file count based on extension:
Get-ChildItem -Path X:\ -Recurse |where{-not $_.PSIsContainer} | group Extension -NoElement
With this I got number of unique extensions:
Get-ChildItem -Path X:\ -Recurse | Select-Object -Property Extension -Unique
Get-ChildItem -Path X:\ -Recurse |where{-not $_.PSIsContainer} | group Extension -NoElement
Get-ChildItem -Path X:\ -Recurse | Select-Object -Property Extension -Unique

Maybe try this.
# directory path
$directory = "C:\Program Files"
# date -40 days
$date = (Get-Date).AddDays(-40)
# files which are accessed before 40 days
$files = Get-ChildItem $directory -Recurse -File:$true | Where-Object {$_.LastWriteTime -gt $date}
# sort files by extension, size
$files | Sort-Object Extension,Length | Select-Object Name,#{label = 'Length'; e = {"{0:N3} KB" -f ($_.Length / 1KB)}} | ft -AutoSize -Wrap

I'll hope it is not so bad. :)
# directory path
$directory = "X:\"
# date -40 days
$date = (Get-Date).AddDays(-40)
# files which are accessed before 40 days
$files = Get-ChildItem $directory -Recurse -File:$true | Where-Object {$_.LastWriteTime -gt $date}
# file extensions
$fileExtensions = $files | Select-Object -Property Extension -Unique
foreach ($ext in $fileExtensions){
[int]$fileSize = $null
foreach ($file in $files) {
if ($file.Extension -like $ext.Extension) {
[int]$fileSize += $file.Length / 1KB
}
}
Write-Host "Extension:" $ext.Extension " - Size: "$fileSize "KB"
}

Maybe something like this, I'm not sure how to format it in a table:
$files = Get-ChildItem $directory -Recurse -File:$true | Where-Object {$_.LastWriteTime -gt $date}
foreach($file in $files){
[IO.Path]::GetExtension($file)
$file.length
}

Related

Powershell Find all empty folders and subfolders in a given Folder name

I´m trying to get a
a) list of all empty folders and subfolders if the folder is named "Archiv"
b) I´d like to delete all those empty folders. My current approch doesn´t check the subfolders.
It would be also great if the results would be exportet in a .csv =)
$TopDir = 'C:\Users\User\Test'
$DirToFind = 'Archiv'>$EmptyDirList = #(
Get-ChildItem -LiteralPath $TopDir -Directory -Recurse |
Where-Object {
#[System.IO.Directory]::GetFileSystemEntries($_.FullName).Count -eq 0
$_.GetFileSystemInfos().Count -eq 0 -and
$_.Name -match $DirToFind
}
).FullName
$EmptyDirList
Any ideas how to adjust the code? Thanks in advance
You need to reverse the order in which Get-ChildItem lists the items so you can remove using the deepest nested empty folder first.
$LogFile = 'C:\Users\User\RemovedEmptyFolders.log'
$TopDir = 'C:\Users\User\Test'
# first get a list of all folders below the $TopDir directory that are named 'Archiv' (FullNames only)
$archiveDirs = (Get-ChildItem -LiteralPath $TopDir -Filter 'Archiv' -Recurse -Directory -Force).FullName |
# sort on the FullName.Length property in Descending order to get 'deepest-nesting-first'
Sort-Object -Property Length -Descending
# next, remove all empty subfolders in each of the $archiveDirs
$removed = foreach ($dir in $archiveDirs) {
(Get-ChildItem -LiteralPath $dir -Directory -Force) |
# sort on the FullName.Length property in Descending order to get 'deepest-nesting-first'
Sort-Object #{Expression = {$_.FullName.Length}} -Descending |
ForEach-Object {
# if this folder is empty, remove it and output its FullName for the log
if (#($_.GetFileSystemInfos()).Count -eq 0) {
$_.FullName
Remove-Item -LiteralPath $_.FullName -Force
}
}
# next remove the 'Archiv' folder that is now possibly empty too
if (#(Get-ChildItem -LiteralPath $dir -Force).Count -eq 0) {
# output this folders fullname and delete
$dir
Remove-Item -LiteralPath $dir -Force
}
}
$removed | Set-Content -Path $LogFile -PassThru # write your log file. -PassThru also writes the output on screen
Not sure a CSV is needed, I think a simple text file will suffice as it's just a list.
Anyway, here's (although not the most elegant) a solution which will also delete "nested empty directories". Meaning if a directory only contains empty directorIS, it will also get deleted
$TopDir = "C:\Test" #Top level directory to scan
$EmptyDirListReport = "C:\EmptyDirList.txt" #Text file location to store a file with the list of deleted directorues
if (Test-Path -Path $EmptyDirListReport -PathType Leaf)
{
Remove-Item -Path $EmptyDirListReport -Force
}
$EmptyDirList = ""
Do
{
$EmptyDirList = Get-ChildItem -Path $TopDir -Recurse | Where-Object -FilterScript { $_.PSIsContainer } | Where-Object -FilterScript { ((Get-ChildItem -Path $_.FullName).Count -eq 0) } | Select-Object -ExpandProperty FullName
if ($EmptyDirList)
{
$EmptyDirList | Out-File -FilePath $EmptyDirListReport -Append
$EmptyDirList | Remove-Item -Force
}
} while ($EmptyDirList)
This should do the trick, should works with nested too.
$result=(Get-ChildItem -Filter "Archiv" -Recurse -Directory $topdir | Sort-Object #{Expression = {$_.FullName.Length}} -Descending | ForEach-Object {
if ((Get-ChildItem -Attributes d,h,a $_.fullname).count -eq 0){
$_
rmdir $_.FullName
}
})
$result | select Fullname |ConvertTo-Csv |Out-File $Logfile
You can do this with a one-liner:
> Get-ChildItem -Recurse dir -filter Archiv |
Where-Object {($_ | Get-ChildItem).count -eq 0} |
Remove-Item
Although, for some reason, if you have nested Archiv files like Archiv/Archiv, you need to run the line several times.

Copy same file to multiple destinations

I want to copy a file to multiple destinations using a script that filters through a directory and selects the newest file in the $File_path then change its name and copies it to the $destination, the script i'm using is this:
$File_path = "C:\TEMP\export\liste\Text_Utf8\"
$destination = "C:\TEMP\export\C7E001"
get-childitem -path $File_path -Filter "Ges?*.txt" |
where-object { -not $_.PSIsContainer } |
sort-object -Property $_.CreationTime |
select-object -last 1 | copy-item -Destination (join-path $destination "FRER3000CCFETES01_IN.DEV")
this only copies it to one location, is there a way to improve it to copy the same file to multiple locations? i have seen this thread but it seems different.
the other locations are as follow:
C:\TEMP\export\C7P001
C:\TEMP\export\C7F001
C:\TEMP\export\C7S001
and so on.
thank you.
Although my answer isn't very different to Peter's answer, This uses the LastWriteTime property to get the latest file and uses the FullName property of the file to copy in the Copy-Item cmdlet.
$File_path = "C:\TEMP\export\liste\Text_Utf8"
$destinations = "C:\TEMP\export\C7E001", "C:\TEMP\export\C7F001", "C:\TEMP\export\C7S001"
$fileToCopy = Get-ChildItem -Path $File_path -Filter "Ges*.txt" -File |
Sort-Object -Property $_.LastWriteTime |
Select-Object -Last 1
foreach ($dest in $destinations) {
Copy-Item -Path $fileToCopy.FullName -Destination (Join-Path -Path $dest -ChildPath "FRER3000CCFETES01_IN.DEV")
}
You can use an foreach object loop
$File_path = "C:\TEMP\export\liste\Text_Utf8\"
$destination = "C:\TEMP\export\C7E001", "C:\TEMP\export\C7P001", "C:\TEMP\export\C7F001", "C:\TEMP\export\C7S001"
$Files = get-childitem -path $File_path -Filter "Ges?*.txt" |
where-object { -not $_.PSIsContainer } |
sort-object -Property $_.CreationTime |
select-object -last 1
$Destination | Foreach-Object {copy-item $Files -Destination (join-path $_ "FRER3000CCFETES01_IN.DEV")}

how to Exclude the list of selected files in powershell

In $FilesInContainer2 the exclude function is not working as expected.
I need the list of files from $files which is not in $FilesInContainer1
$srcdir = "W:\XXX\"
$zipFilepath = "W:\YYY"
$currentFileExtension = ".txt"
$logFileName = "W:\Log.txt"
$files = Get-ChildItem $srcdir -Filter *.txt | ? {$_.LastWriteTime -ge (Get-
Date).Date} | Sort-Object -Property Name -Descending
$Container1FileCount = [math]::Ceiling(($files).count/2)
$FilesInContainer1 = $files | Select-Object -First $Container1FileCount
$FilesInContainer2 = Get-ChildItem $files -Exclude $FilesInContainer1
Below code will write the list of files from $files which is not in $FilesInContainer1
$FilesInContainer2 = $files | ?{$FilesInContainer1 -notcontains $_}
Why would you do a Get-ChildItem twice at all?
To split the collection of files obtained with the first Get-ChildItem cmdlet, you can simply split that in two by doing something like this:
$srcdir = 'W:\XXX'
$files = Get-ChildItem -Path $srcdir -Filter '*.txt' -File |
Where-Object {$_.LastWriteTime -ge (Get-Date).Date} |
Sort-Object -Property Name -Descending
$half = [math]::Ceiling(($files.Count / 2))
# get the first half of the files colection
$FilesInContainer1 = $files | Select-Object -First $half
# or use $FilesInContainer1 = $files[(0..($half - 1))]
# get the rest (second half) of the files collection
$FilesInContainer2 = $files | Select-Object -Last ($files.Count - $half)
# or use $FilesInContainer2 = $files[($half..($files.Count - 1))]

Delete files older than 30 and save 1

I need to have a clean-up script that remove all files older than 30 days but if file is older than 30 days it should save the last one. Possible? :)
I have tried a couple of parameters but cannot really get it to work.. guess I need a if/else clause?
Would appreciate any guide and help with this, thanks
$Daysback = "-30"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
$path = "C:\Data\*"
$save1 = Get-ChildItem -Path $path | Where-Object {($_.Name -like "Test*.zip")} | sort LastWriteTime -Descending | select -First
Get-ChildItem $path -Recurse
{($_.CreationTime -le $(Get-Date).AddDays($Daysback))}
{
Remove-Item -Recurse -Force
}
elseif ($save1)
{
Remove-Item -Recurse -Force
}
}
Something like this should work.
$Daysback = "-30"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.AddDays($Daysback)
$path = "C:\Data\*"
$Items=Get-ChildItem -Path $path -Recurse | Where-Object {($_.Name -like "Test*.zip") -and ($_.LastWriteTime -le ($DatetoDelete))}| Sort-Object LastWriteTime -Descending
$Items|Select-Object -Skip 1 |Remove-Item -Recurse -Force -Path $_.fullname
Get-ChildItem -> Filter, only get the items that name starts with Test and ends with .Zip that were written over 30 days ago. Sort them.
In the delete line, we use -Skip 1 to skip over the first item in the sorted list and remove the items by using their path.
This can be simplified. The below block will grab all files in C:\Data that meet the filter (faster than Where-Object significantly), then further reduces those based on their CreationTime, skips 1, and deletes the rest.
Get-ChildItem -Path 'C:\Data' -Filter 'Test*.zip' -Recurse |
Where-Object { -not $_.PSIsContainer -and
$_.CreationTime -le (Get-Date).AddDays(-30) } |
Sort-Object -Property 'LastWriteTime' -Descending |
Select-Object -Skip 1 |
Remove-Item -Force -WhatIf

powershell, check a backup directory and delete old ones only if there is more than one file

Hello to the whole community, I am trying to inspect directories and subdirectories of a folder and if one of them gets more than one file if it has more than 15 days to delete it and leave only the most updated.
but I still do not get the way that if I get a single file despite having more than 15 days old do not touch it as long as there is one more updated within the same directory.
I am currently working with this code
$timeLimit = (Get-Date).AddDays(-15)
Get-ChildItem D:\backup\OldFilesTemp -Directory | where LastWriteTime -lt $timeLimit | Remove-Item -Force -Recurse
grateful for the support they can give me.
You could try something like the following:
$timeLimit = (Get-Date).AddDays(-15)
Get-ChildItem D:\backup\OldFilesTemp | Where-Object { $_.PSIsContainer } | ForEach-Object { Get-ChildItem $_ | Where-Object { -not $PSIsContainer } | Sort-Object -Property LastWriteTime -Descending | Select-Object -Skip 1 | Where-Object { $_.LastWriteTime -lt $timeLimit } | Remove-Item -Force }
Replace Remove-Item -Force with Remove-Item -WhatIf to perform a dry run.
$timeLimit = ([System.DateTime]::Today).AddDays(-15) #Dont use Get-Date.
$BackupFolder = "D:\backup\OldFilesTemp"
$FolderList = Get-ChildItem $BackupFolder -Directory -Recurse | Select FullName
Foreach ($Folder in $FolderList)
{
$FileList = Get-ChildItem $Folder -File | Sort-Object -Property LastWriteTime -Descending
$Count = ($FileList | Where-Object -Property LastWriteTime -GE $timeLimit).Count
#Keep an old file if there is only 1 or no recent backups
if ($Count -le 1)
{
$FileList | Where-Object -Property LastWriteTime -LT $timeLimit | Select-Object -Skip 1 | Remove-Item -Force
}
else
{
$FileList | Where-Object -Property LastWriteTime -LT $timeLimit | Remove-Item -Force
}
}
Better do your testing before you deploy on your environment.