Powershell: Get-ChildItem, get latest file of files with similar names - powershell

I got a script to get files from a folder that I then put in a HTML-Table and mail.
In the folder you have files like HR May 2020, HR April 2020, RR May 2021 etc.
Below is the code itself as a sample, this looks for other files but they come every month as well. In total I will filter 8 files.
Get-ChildItem -Path D:\Temp\Test |
Where-Object { $_.Name -match '^RR_Prognos.*|^AllokeringBogNycklar.*' } |
Sort-Object -Property LastWriteTime |
Select-Object LastWriteTime,FullName
Now I am only interested in seeing the latest file of each, so using last or -days, month, hours or similar wont work.
I tried to find a better solution googling it but could not come up with anything that solved the problem.
So I just need to add to the code it it picks the lastest of each file i filter on, the filter is so it does not care about the month in the name.
Edit: Lets say I would use:
Get-ChildItem -Path c:\tm1 | Where-Object { $_.Name -match '^RR_Prognos.*|^AllokeringBogNycklar.*|^Aktivversion.*|^AllokeringNycklar.*|^HR_prognos.*|^KostnaderDK.*|KostnaderProdukt_prognos.*|^Parametrar_prognos.*|ProduktNyckel_prognos apr.*' } | Sort-Object -Property LastWriteTime -Descending | Select-First 8 | Select-Object LastWriteTime,FullName
Then if one file does not come with the batch, it would show the 2nd last one of that as well. Is there a easier way to block that from happening?

Ok, now that you've provided the whole list that you filter against I can write up a real answer. Here we'll group by file name, then sort each group and grab the last one from each group:
Get-ChildItem -Path c:\tm1 |
Where-Object { $_.Name -match '^RR_Prognos.*|^AllokeringBogNycklar.*|^Aktivversion.*|^AllokeringNycklar.*|^HR_prognos.*|^KostnaderDK.*|KostnaderProdukt_prognos.*|^Parametrar_prognos.*|ProduktNyckel_prognos apr.*' } |
Group {$_.Name -replace '.*?(^RR_Prognos|^AllokeringBogNycklar|^Aktivversion|^AllokeringNycklar|^HR_prognos|^KostnaderDK|KostnaderProdukt_prognos|^Parametrar_prognos|ProduktNyckel_prognos apr).*','$1'} |
ForEach-Object {
$_.Group |
Sort-Object -Property LastWriteTime -Descending |
Select -First 1
} |
Select-Object LastWriteTime,FullName

This might be what you are looking for. This iterates over each search string where you need the newest file.
$searchStrings = #('^pattern1*', '^pattern2*', '^pattern3*')
foreach($searchString in $searchStrings) {
$items = Get-ChildItem -Path $folder | Where-Object { $_.Name -match "$searchString" } | Sort-Object -Property LastWriteTime -Descending
$newestItem = $items[0]
Write-Host "newest item for '$searchString' is $newestItem"
}

Related

How to pick the right file using timstamp appended file name and copy the last dropped file into another folder?

I am trying to pick the right file using file name(timestamp appended in the file name).
I have 3 files: text.041922.061512, text.041922.063016, text.041922.064212. I need pick text.041922.064212 because it was created last which has data and time on the file name itself. How do i achieve this using PowerShell?
Thanks in advance. I would really appreciate it.
My script is this:
Get-ChildItem -Path "c:/demo | Sort-Object { [DateTime]::ParseExact($_.BaseName.Substring(7,13).Replace('.',' '), "MMddyy hhmmss",$null) } | Select-Object -First 1 | Copy-Item -Destination "E:/test/"
Your file names are missing their extension, but assuming the extension doesn't have any numeric digits, you could use -replace '\D+' to remove all non numeric digits from the file names and then the format for ParseExact could be MMddyyHHmmss.
If the files actually don't have an extension, use $_.Name instead of $_.BaseName.
Get-ChildItem -Path "c:/demo" | Sort-Object {
[DateTime]::ParseExact(($_.BaseName -replace '\D+'), 'MMddyyHHmmss', $null)
} -Descending | Select-Object -First 1 | Copy-Item -Destination "E:/test/"
Here is an example that you can use for testing:
[System.IO.FileInfo[]]('text.041922.061512', 'text.041922.063016', 'text.041922.064212') | Sort-Object {
[DateTime]::ParseExact(($_.Name -replace '\D+'), 'MMddyyHHmmss', $null)
} -Descending | Select-Object -Expand Name -First 1
# Returns: text.041922.064212

How to open an selected object with powershell

I'm trying to figure out how to open the selected object I just selected below.
I understand it might have some issues due to it might not know the file it's opening but even an "open with" option would work.
Basically I want to open the last file I was working with similar to the outlook attach file feature where it shows the last document you were working with.
Get-ChildItem -Path 'C:\Users\replace user name here\AppData\Roaming\Microsoft\Windows\Recent' |
Where-Object { -not $_.PsIsContainer } |
Sort-Object LastWriteTime -Descending |
Select-Object -first 1
Pipe to Invoke-Item :
Get-ChildItem -Path 'C:\Users\replace user name here\AppData\Roaming\Microsoft\Windows\Recent' | Where-Object { -not $_.PsIsContainer } | Sort-Object LastWriteTime -Descending | Select-Object -first 1 | invoke-item
or, wrap it in a scriptblock:
invoke-item {Get-ChildItem -Path 'C:\Users\replace user name here\AppData\Roaming\Microsoft\Windows\Recent' | Where-Object { -not $_.PsIsContainer } | Sort-Object LastWriteTime -Descending | Select-Object -first 1}
The Invoke-Item cmdlet works like double-clicking an item in explorer. That should run the default association for the file.

Powershell Command to Copy Latest Version of Multiple Files

I am trying to do a restore of my OneNote notebooks but they restore process isn't ideal. It stores copies of the notes and appends a date to them, and a number if there is more than one for each day. I want to grab the latest file (note) and move it to a folder and then I can restore them instead of using their process.
I have tried using gci | select last -1 which only gets me the latest file in the entire directory. But I need each notes latest version. Ideally, I would make a copy, dump it into another directory that matches the current directory name it is in, and get rid of everything after .one, but I would be happy with just a copy of each notes latest version in a directory.
This script can help you.
$dirPath = "<The directory where the files are located>"
Get-ChildItem $dirPath |
Group-Object { ($_.Name -split '\.one' | Select-Object -First 1) } |
Select-Object #{ Name = 'FileName'; Expression = { $_.Name } },
#{ Name = 'LastFileDate'; Expression = { ($_.Group -split ',') |
ForEach-Object { [DateTime](($_ -split ' ')[2] -split '\)')[0] } |
Sort-Object $_.LastFileDate |
Select-Object -Last 1
} } |
ForEach-Object { "{0}.one (On {1:dd-MM-yyyy}).one" -f $_.FileName, $_.LastFileDate }
Using Mathias' suggestion, and expanding on it to get what you wanted (the most recently modified file in each group), here is a solution that should work for you:
$grps = Get-ChildItem | Group-Object {$_.Name -split '\.one' | Select -First 1}
foreach ($group in $grps) {
$group.Group | Sort LastWriteTime | Select -Last 1 | Select Name, FullName, LastWriteTime
}
You can just grab the FullName property of each file there and use that to Copy-Item it somewhere else.

Identify duplicate files from leading number of characters

I have a file directory which contains approx. 600 employee image files which have been copied from an alternative source.
The filename format is:
xxxxxx_123456_123_20141212.jpg
When the employee image file is updated it just creates another file in the same location and only the datetime changes at the end.
I need to be able to identify the most recent file, however i need to establish first of all which files are 'duplicated'.
My initial thoughts were to try and match the first 14 characters and, if they matched, work out the recent modified date and then delete the older file.
This requires PowerShell version 3.
$Path = 'C:\Users\madtomvane\Documents\PowerShellTest'
#Get the files #Group them by name #Select the most resent file
$FilesToKeep = Get-ChildItem $Path -Recurse -File | Group-Object -Property {$_.Name[0..14]} | ForEach-Object {$_.Group | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1}
#Get the files #Group them by name #Where there is more than one file in the group #Select the old ones
$FilesToRemove = Get-ChildItem $Path -Recurse -File | Group-Object -Property {$_.Name[0..14]} | Where-Object {$_.Group.Count -gt 1} | ForEach-Object {$_.Group | Sort-Object -Property LastWriteTime -Descending | Select-Object -Skip 1}
$FilesToRemove | Remove-Item

PowerShell filtering range of file names

I am trying to write a very simple (as far as I know :-) ) script in PowerShell v2.0.
Every morning I need to look at some files to check if they are up to date.
All of the files are in the same folder.
The files are named like so: from1.rar, from2.rar from13.rar, from14.rar, from27.rar, from29.rar and so on. As you can see, the files are in different ranges. I want to filter the name of the files by a range that I determine. I suppose regex will do the trick, but I don't know how to use it...
What I have for now is just filtering and sorting all of the files by time and name into one table:
Get-ChildItem -filter "*.rar" | sort LastWriteTime -Descending | sort name | Format-Table LastwriteTime, name > C:\Users\user1\Desktop\update.txt
Now I want to break the table to form a number of groups (or smaller tables) from the names of the files.
Something like this should do the trick:
$low = 10
$high = 25
Get-ChildItem -Filter '*.rar' | ? {
$_.Name -match 'from(\d+)\.rar' -and
[int]$matches[1] -gt $low -and
[int]$matches[1] -le $high
} | ...
Demonstration:
PS C:\> $files = 'from1.rar','from13.rar','from14.rar','from27.rar','from29.rar'
PS C:\> $files
from1.rar
from13.rar
from14.rar
from27.rar
from29.rar
PS C:\> $files | ? {
>> $_ -match 'from(\d+)\.rar' -and
>> [int]$matches[1] -gt $low -and
>> [int]$matches[1] -le $high
>> }
>>
from13.rar
from14.rar
Here's one way to use a regex:
$range = 5..10
get-childitem From*.rar |
where {$range -contains ($_.name -replace 'From(\d+)\.rar','$1')}
To break your tables into groups of tables, just add the -GroupBy parameter to the cmdlet Format-Table.
For example, to create a table for each file by its property Name:
Get-ChildItem -filter "*.rar" | sort LastWriteTime -Descending | sort name | Format-Table LastwriteTime, name -GroupBy Name
But that might generate too many groups if you have many files, so you may group the table on the first letter of the Name property, like so:
Get-ChildItem -filter "*.rar" | sort LastWriteTime -Descending | sort name | Format-Table LastwriteTime, name -GroupBy #{name="First Letter";E={ ($_.name).substring(0,1) }}
Or, to group the table on the first two letters of the Name property:
Get-ChildItem -filter "*.rar" | sort LastWriteTime -Descending | sort name | Format-Table LastwriteTime, name -GroupBy #{name="First Letter";E={ ($_.name).substring(0,2) }}