Adding File Properties such as the Creator or Author - powershell

As of now I have a script that will pull and export all files that are older than 7 years:
get-childitem -Path C:\ -recurse|
where-object {$_.LastWriteTime -lt (get-date).Addyears(-7)} |
Select-Object FullName, LastWriteTime, #{N='Owner';E={$_.GetAccessControl().Owner}}, #{N='Author';E={$_.GetAccessControl().Author}}|
Export-Csv C:\file.csv
Now, I need help adding the Creator or Author from the file properties. The #{N='Author';E={$_.GetAccessControl().Author}} doesn't work.

Adjusted so that you're retrieving ACLs properly. I don't think it's possible to grab the original author, however.
Get-ChildItem -Path C:\ -Recurse |
Where-Object {$_.LastWriteTime -lt (Get-Date).AddYears(-7)} |
Select-Object #( 'FullName'
'LastWriteTime'
#{ N = 'Owner'
E = { (Get-Acl -Path $_.FullName).Owner }
}
) |
Export-Csv -Path C:\file.csv

Related

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")}

size of files based on particular extensions

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
}

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.

Loop through each Folder and delete some of them

I'm trying to run the script below in multiple paths using an array. My goal is to delete folders keeping the last 7 versions, but it is not working as expected. The action is only taking into account the first path D:\Test1.
I believe that I should add something like ($folders in $folders) after ForEach-Object but I don know how.
Any idea what I missing here?
$path = #("D:\Test1","D:\Test2","D:\Test3")
$folders = Get-ChildItem -Path $path -Recurse |
Where-Object { $_.PSIsContainer } |
Group-Object { $_.Name.Split('_')[0] } |
ForEach-Object $Folders {
$_.Group |
sort CreationTime -Descending |
Select -Skip 7 |
foreach { Remove-Item $_.FullName -Force -WhatIf }
}
This should do your job.
$path= #("D:\Test1","D:\Test2","D:\Test3")
$folders= Get-ChildItem -path $path -Recurse | Where-Object {$_.PsIsContainer} |Group-Object {$_.FullName.Split('_')[0] }
ForEach($folder in $folders)
{
$folder.Group | sort CreationTime -Descending | Select -Skip 7|% { Remove-Item $_.fullname -Force -whatIf}
}
I tested in my local and it is working fine. Although I didn't get any error in your code except few formatting issue which I have taken into variable and sorted it out cause I got tangled in too many pipeline objects.
If you are using foreach after a pipeline , that means it will take the pipeline objects one by one only. But if you are separately using it , then you have to assign each iteration into a variable.
Hope it helps you.
I got the answer from #Robert Israelsson !
" If you change your group-object to not group by name but instead fullname you will get the desired result."
From:
$folders= Get-ChildItem -path $path -Recurse | Where-Object {$_.PsIsContainer} |Group-Object {$_.Name.Split('_')[0] }
To:
$folders= Get-ChildItem -path $path -Recurse | Where-Object {$_.PsIsContainer} |Group-Object {$_.FullName.Split('_')[0] }
And this works perfectly!