How to select the file with the maximum number of the specified file - windows

I want to keep only the file with the largest version of the specified zip file in the folder using powershell. I wrote a shell script but it returns all the files. How can I modify the script to select only the file with the largest version?
$files = Get-ChildItem -Filter "*.zip"
$max = $files |Measure-Object -Maximum| ForEach-Object {[int]($_.Split("_")[-1].Split(".")[0])}
$largestFiles = $files | Where-Object {[int]($_.Split("_")[-1].Split(".")[0]) -eq $max}
Write-Output $largestFiles
Expectation:
A1_Fantasic_World_20.zip
A1_Fantasic_World_21.zip
B1_Mythical_Realms_11.zip
B1_Mythical_Realms_12.zip
C1_Eternal_Frame_Corporation_2.zip
C1_Eternal_Frame_Corporation_3.zip
↓
A1_Fantasic_World_21.zip
B1_Mythical_Realms_12.zip
C1_Eternal_Frame_Corporation_3.zip
A1_Fantasic_World's biggest number is 21.B1_Mythical_Realms's is 12.C1_Eternal_Frame_Corporation's is 3. So I want to choose the biggest version of zip.

First you add the calculated properties to your file system objects you use for filtering. Then with a combination of Group-Object, Sort-Object and Select.Object you can filter the desired files.
$FileList =
Get-ChildItem -Filter *.zip |
Select-Object -Property *,
#{
Name = 'Title'
Expression = {($_.BaseName -split '_')[0..$(($_.BaseName -split '_').count - 2)] -join '_' }
},
#{
Name = 'Counter'
Expression = {[INT]($_.BaseName -split '_')[-1]}
}
$LastOnesList =
$FileList |
Group-Object -Property Title |
ForEach-Object {
$_.Group | Sort-Object -Property Counter | Select-Object -Last 1
}
$LastOnesList |
Select-Object -Property Name

Related

recursively check all folders and export the list of folders that has no created backup file in it during last 24 hour

There is a folder containing database backup files. I need to recursively check all folders and export the list of last backup files in each folder.
I have a code here that contains my idea. just I have to add this part:
-check for each selected file(selected file is the last created backup file) if the file creation time is older than 24 hours, export in csv file.
Thanks in advance
[Cmdletbinding()]
param(
[Parameter(Position=0,Mandatory=$false,ValueFromPipeline=$true)]$path=
"\F:\backups",
[Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true)]
$OutPutFilepath=
"f:\backup-daily.csv"
)
function Get-LastestWroteFile{
[Cmdletbinding()]
param(
[Parameter(Position=0,Mandatory=$true)]$Folder
)
begin{
$Latest = Get-ChildItem $Folder.FullName -File | select FullName,
CreationTime, LastAccessTime, LastWriteTime, Attributes, #{N='SizeInMb';E=
{$_.Length/1mb}},Name | Sort-Object CreationTime | select -Last 1
}
process{
}
end{
#new custom object with 3 props.
if($Latest){
return New-Object PSobject -Property #{"FullName"=$latest.Name;
LastWriteTime =
$latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =
[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; }
}
}
}
$OutPut=#()
Get-ChildItem -Directory -Path $path -Recurse | foreach{
$OutPut+= Get-LastestWroteFile $_
}
$OutPut | ConvertTo-Csv -NoTypeInformation -delimiter '|' | Out-File -
FilePath $OutPutFilepath
an advanced function would not be required, try below
Get-ChildItem -Path $Path -Recurse -File | Where-Object -FilterScript {
([Datetime]::Now - $_.CreationTime ).Hours -gt 24
} | Select-Object -Property Name,LastWriteTime,FullName,#{N='SizeInMb';E=
{$_.Length/1mb}},

Compare mkv's creationtime

I've been tasked with creating a script that checks to see if the office cameras we've set up have stopped uploading their feeds to the "Camera" share located on our Windows 2016 storage server. If the NEWEST .mkv is over an hour old compared to the current time (get-date) then the "problem" camera needs to be restarted manually. (No need to script that part.)
Here's what my Director has written so far:
#Variable Definitions start here
$numhours = 1
Get-ChildItem "d:\Shares\Cameras" | Foreach {
$folderToLookAt = ($_.FullName + "\*.mkv")
$result = Get-ChildItem -Recurse $folderToLookAt | Sort-Object CreationTime -Descending
echo $result[0].FullName
echo $result[0].CreationTime
}
The first variable really isn't used yet, but I'm kind of dumb-struck as what to do next. The above returns the full names and creation times successfully of the newest .mkvs
Suggestions on the next part?
Invert the logic - instead of searching all the files, sorting them, finding the most recent, and checking the date, do it the other way round.
Look for files created since the cutoff, and alert if there were none found:
$cutOffTime = [datetime]::Now.AddHours(-1)
Get-ChildItem "d:\Shares\Cameras" | Foreach {
$folderToLookAt = ($_.FullName + "\*.mkv")
$result = Get-ChildItem -Recurse $folderToLookAt | Where-Object { $_.CreationTime -gt $cuttoffTime }
if (-not $result)
{
"$($_.Name) has no files since the cutoff time"
}
}
I'm assuming your paths look like:
D:\Shares\Cameras\Camera1\file1.mkv
D:\Shares\Cameras\Camera1\file2.mkv
D:\Shares\Cameras\Camera2\file1.mkv
D:\Shares\Cameras\Camera2\file2.mkv
D:\Shares\Cameras\Camera3\file1.mkv
.
.
.
If so, I would do something like this:
# The path to your files
$CameraShareRoot = 'D:\Shares\Cameras';
# Number of Hours
$NumberOfHours = 1;
# Date and time of significance. It's $NumberOfHours in the past.
$MinFileAge = (Get-Date).AddHours( - $NumberOfHours);
# Get all the folders at the camera share root
Get-ChildItem -Path $CameraShareRoot -Directory | ForEach-Object {
# Get the most recently created file in each folder
$_ | Get-ChildItem -Recurse -Filter '*.mkv' -File | Sort-Object -Property CreationTime -Descending | Select-Object -First 1
} | Where-Object {
# Remove any files that were created after our datetime
$_.CreationTime -lt $MinFileAge;
} | Select-Object -Property FullName, CreationTime
This will just output the full file name and creation time for stale cameras.
You could do something like this to email yourself a report when the results have any files:
# The path to your files
$CameraShareRoot = 'D:\Shares\Cameras';
# Number of Hours
$NumberOfHours = 1;
# Date and time of significance. It's $NumberOfHours in the past.
$MinFileAge = (Get-Date).AddHours( - $NumberOfHours);
# Get all the folders at the camera share root, save the results to $StaleCameraFiles
$StaleCameraFiles = Get-ChildItem -Path $CameraShareRoot -Directory | ForEach-Object {
# Get the most recently created file in each folder
$_ | Get-ChildItem -Recurse -Filter '*.mkv' -File | Sort-Object -Property CreationTime -Descending | Select-Object -First 1;
} | Where-Object {
# Remove any files that were created after our datetime
$_.CreationTime -lt $MinFileAge;
}
# If there are any stale camera files
if ($StaleCameraFiles) {
# Send an email
$MailMessage = #{
SmtpServer = 'mail.example.com';
To = 'youremail#example.com';
From = 'youremail#example.com';
Subject = 'Stale Camera Files';
Body = $StaleCameraFiles | Select-Object -Property FullName, CreationTime | ConvertTo-Html -Fragment | Out-String;
BodyAsHtml = $true;
}
Send-MailMessage #MailMessage;
}
Generally you will want to use LastWriteTime instead of CreationTime since the latter can be updated by a file move or copy, but maybe that's what you want here.
You have to compare the CreationTime date with (Get-Date).AddHours(-1). The AddHours method allows you to add hours to the DateTime, but also to subtract.
You can use the following example:
$Path = 'd:\Shares\Cameras'
$CreationTime = Get-ChildItem -Path $Path -Filter *.mkv |
Sort-Object -Property CreationTime -Descending |
Select-Object -First 1 -ExpandProperty CreationTime
if ($CreationTime -lt (Get-Date).AddHours(-1)) {
# your action here (restart, send mail, write output, ...)
}
It also optimizes your code a bit. ;)
$LatestFile = Get-ChildItem C:\Users\Connor\Desktop\ | Sort CreationTime | Select -Last 1
if ($LatestFile.CreationTime -gt (Get-Date).AddHours(-1)){
#It's Currently Working
} else {
#Do Other Stuff
}
try this :
Get-ChildItem "c:\temp" -Filter *.mkv -File | sort CreationTime -Descending |
select -First 1 | where CreationTime -lt (Get-Date).AddHours(-1) |
%{Write-Host "Alert !!" -ForegroundColor Red}

How to sort the output in powershell

I am trying to list the content of a directory and try to sort them out the most recently created folders of file. I am using the following script but it is only giving me 1 item which is most recently created. All I would like to do is list all the folders in asc or desc order
$content = get-childitem 'C:\Users\tim\Desktop\tim_test'
write-output $content | Sort-Object LastWriteTime -Descending | Select-Object -First 1
Your "Select-Object -First 1" gives you only the first file, to get all files, remove that. Like so:
$newPath = 'C:\Users\tim\Desktop\tim_test2'
$content = get-childitem 'C:\Users\tim\Desktop\tim_test' | Sort-Object LastWriteTime -Descending
Write-Host $content
# Part 2
$oldFile = $content | Select-Object -first 1
$prefix = Read-Host "Enter prefix"
$newFile = "$newPath\$prefix$oldFile"
Copy $file $newFile
Something like that should work :)

Count, Sort and Group-By in Powershell

Are there any cool cmdlets that will help me do the following?
I want something in Powershell that is as simple as doing the same in SQL:
select RootElementName , count(*) from Table
group by RootElementName
order by RootElementName
I'm all XML files in a directory, finding the root element of each XML file.
$DirectoryName = "d:\MyFolder\"
$AllFiles = Get-ChildItem $DirectoryName -Force
foreach ($Filename in $AllFiles)
{
$FQFilename = $DirectoryName + $Filename
[xml]$xmlDoc = Get-Content $FQFilename
$rootElementName = $xmlDoc.SelectSingleNode("/*").Name;
Write-Host $FQFilename $rootElementName
}
Desired Result:
RootName Count
-------- -----
Root1 15
MyRoot 16
SomeRoot 24
I know I could could either create two arrays, or an array of objects, store the root elements in the array, and do the counts all using typical code, was just hoping that this new language might have something built-in that I haven't discovered yet.
Could I pipe the "Write-Host $FQFilename $rootElementName " to something that would behave something to the SQL I referred to above?
You can get groups and counts by using Group-Object like this:
$AllFiles | Group-Object RootElementName | Sort-Object Name | Select-Object Name, Count
In your current example, Write-Host doesn't write an object to the pipeline that we can sort or group. Write-Host only prints text to the screen to show the user something, ex. a script menu.
$DirectoryName = "d:\MyFolder\"
$AllFiles = Get-ChildItem $DirectoryName -Force | ForEach-Object {
#The FullName-property contains the absolute path, so there's no need to join the filename and $directoryname
[xml]$xmlDoc = Get-Content $_.FullName
$rootElementName = $xmlDoc.SelectSingleNode("/*").Name
#Outputing an object that we can group and sort
New-Object -TypeName psobject -Property #{
FileName = $_.FullName
RootElementName = $rootElementName
}
}
$grped = $AllFiles | Group-Object RootElementName | Sort-Object Name | Select-Object Name, Count
I'm creating an object with a FileName-property and the RootElementName so you have it if you need to retrieve the filename+rootelement for a list. If not, we could simplify this to:
$DirectoryName = "d:\MyFolder\"
$AllFiles = Get-ChildItem $DirectoryName -Force | ForEach-Object {
#The FullName-property contains the absolute path, so there's no need to join the filename and $directoryname
[xml]$xmlDoc = Get-Content $_.FullName
#Output rootelementname
$xmlDoc.SelectSingleNode("/*").Name
}
$grped = $AllFiles | Group-Object | Sort-Object Name | Select-Object Name, Count

Powershell: How to output folder name, lastwritetime and folder size in one line?

I want to out put folder name, lastwritetime and folder size, how can i combine both of the results in to one line?
For folder name and lastwritetime:
get-item "\\server-01\Y$\Server1" | select name,lastwritetime
For folder size:
$folder = (Get-ChildItem "\\server-01\Y$\Server1" -recurse | Measure-Object -property length -sum)
$size = "{0:N2}" -f ($folder.sum / 1024MB) + " GB"
I need output format like this:
Name LastWriteTime Size
Server1 2014-05-05 55G
Also how to make a loop of running this function through a list of PCs?
Any idea please?
For Folder name and lastwritetime:
Get-Item $Path | Where-Object { $_.BaseName ,$_.LastWriteTime}
For folder size:
$log="C:\log.txt"
$Path = "C:\Test"
$Items = Get-ChildItem $Path | Where-Object {$_.PSIsContainer -eq $True} | Sort-Object
foreach ($f in $Items){
$itemSum = Get-ChildItem ("$Path\" + $f.Name) | Select-Object #{ l="Path" ; e = {$f}},LastWriteTime,#{l="Size" ; e={((Get-childitem -recurse | measure-object length -sum).Sum /1KB)}}
}
Enjoy!!
FYI
Query Folder tree for Size and export to a log on a server
Select-Object will be your friend here:
foreach ($c in (get-content .\Servers.txt))
{ Get-Childitem \\$c\y$\mydirectory | select-object #{l="Name" ; e = {$c}},Lastwritetime,#{l="Size" ; e={(Get-childitem -recurse | measure-object length -sum).sum}} }
But you could also do yourself a favor and add a function like get-foldersize to your profile or to a standard tools module.
http://gallery.technet.microsoft.com/Get-FolderSize-b3d317f5
Here's a true one-liner with some formatting.
Get-ChildItem -Directory -Force|ForEach {"{0,-30} {1,-30} {2:N2}MB" -f $_.Name, $_.LastWriteTime, ((Get-ChildItem $_ -Recurse|Measure-Object -Property Length -Sum -ErrorAction Stop).Sum/1MB)}
Result:

Resources