I have a script that examines a folder and finds the oldest file (by LastWrittenTime) and writes the found file's LastWriteTime to a log file.
If I run this script again I would like it to find the next oldest file, which has LastWriteTime greater than the one previously written to the log file.
But there is a problem. My scipt can find only the oldest file in the folder each time and ignores the one in the log file.
My script:
$programdir = "C:\Data\PowerShell\Learning"
$folder = "C:\Data\PowerShell\Learning\folder" #there is the files
$TimeLog = "$programdir\LastFileDate.log" #this file contains the last found file's LastWriteTime attribute
$LastWriteTime = Get-Content $TimeLog
$File = Get-ChildItem -Path $folder | Sort-Object LastWriteTime -Descending | Select-Object -Last 1 | Where-Object {$_.LastWriteTime -gt $LastWriteTime}
Clear-Content $TimeLog
$File.LastWriteTime | Set-Content $TimeLog
You immediately cripple your selection set with this line. Specifically where you have Select-Object -Last 1:
$File = Get-ChildItem -Path $folder | Sort-Object LastWriteTime -Descending | Select-Object -Last 1 | Where-Object {$_.LastWriteTime -gt $LastWriteTime}
In the second last pipe statement you limit your selection set to 1 file. Then afterwards you apply your date logic. You need to filter on your dates first then grab the appropriate entry.
Get-ChildItem -Path $folder -File |
Sort-Object LastWriteTime -Descending |
Where-Object {$_.LastWriteTime -lt $LastWriteTime} |
Select-Object -First 1
There are other similar approaches that would work as well.
Also...
Clear-Content $TimeLog
$File.LastWriteTime | Set-Content $TimeLog
That is redundant since Set-Content will overwrite by default. You can remove the Clear-Content.
While this is not an issue in your code be aware that $LastWriteTime, as returned by Get-Content, is a string and not a datetime object. Since it is on the RHS of the statement in your where clause is cast as a [datetime] for the purpose of evaluating the clause.
Also be careful that your code could act differently if there is more than one line in your $timelog
Related
A bit different from the others. I'm retrieving an arraylist of files for processing (basically handling DLL registration on a local machine), and I need my script to properly handle multiple DLLs with the same name. The select -Unique doesn't work, since technically the files aren't duplicates - each has its own unique full path.
I need this script to retrieve all DLLs in a folder (as well as sub-folders), but only return the last instance of each named file. For example if I have files:
C:\Path\Update1\GRM.DLL
C:\Path\Update1\HTCP.DLL
C:\Path\Update2\GRM.DLL
C:\Path\Update3\GRM.DLL
The script should return the objects for Update3\GRM.DLL and Update1\HTCP.DLL.
[System.Collections.ArrayList]$dlls = #(Get-ChildItem -Path $PSScriptRoot -Recurse | Where-Object
{$_.Extension -eq ".dll" -and $_.FullName -notmatch 'dll_Old'})
Edit: Got it going with this, but it's selecting the first instance that shows up, and I need the last. In this example, that means it's snagging Update1/GRM.DLL instead of Update3/GRM.DLL
$dlls = #(Get-ChildItem -Path $PSScriptRoot -Recurse | Where-Object {$_.Extension -eq ".dll" -and $_.FullName -notmatch 'dll_Old'}) | Select-Object -Unique
Use a hashtable to keep track of the last file seen for a specific file name:
$files = #{}
Get-ChildItem -Path $PSScriptRoot -File -Recurse -Filter *.dll |Where-Object FullName -notmatch 'dll_Old' |ForEach-Object {
$files[$_.Name] = $_
}
$uniqueFiles = $files.Values
Mathias R. Jessen's helpful answer is probably the best (fastest) solution in this case, but here's an alternative based on the Group-Object cmdlet:
Get-ChildItem -LiteralPath $PSScriptRoot -Recurse -Filter *.dll |
Where-Object FullName -notmatch dll_Old |
Group-Object Name |
ForEach-Object { $_.Group[-1] }
Group-Object Name groups all matching files by their .Name property.
ForEach-Object { $_.Group[-1] } then extracts the last (-1) member from each resulting group.
Note that Group-Object will implicitly sort the groups by the grouping property, so the resulting list of file-info objects (System.IO.FileInfo, as output by Get-ChildItem) will be sorted by file name.
Sorry for the dump question as I am a beginner in PowerShell. We have a lot of coming files into a directory, and they are always increasing and decreasing in that directory because it is moved to another directory after we are done from using them.
We have a priority file list in a txt file which has only partial name of the file name.
For example, for the file name:
2017-06-5---666-12-05-01.txt
In the priority list, I have the partial name as ---666---.
How can I check if the files in the folder are already in the priority list by using Powershell?
I wrote the below script since I need only the files which are older than a given time. But it is not working.
Get-ChildItem -path $Struct.Path -filter $Struct.filter |
Where-Object {$_.CreationTime -lt $time} |
Where-Object {$_.Name -contains "*$PriorityList*"} |
ForEach-Object { $counterP++}
I have updated your code and now it is working perfectly
Get-ChildItem -path $Struct.Path -filter $Struct.filter |
Where-Object {$_.CreationTime -lt $time} | ForEach-Object { If($_.name -
Match $Priorfilter) { $counterP++ }
First of all, the file name in your example doesn't match the partial name. So let's assume that pattern is "666". If you have several patterns, you can join them in one filter:
$PriorityList = "---666---","---555---"
$PriorityFilter = $PriorityList -join '|'
Then use this filter to check Name property:
Get-ChildItem -path $Struct.Path -filter $Struct.filter |
Where-Object {$_.CreationTime -lt $time} |
Where-Object {$_.Name -match $PriorityFilter |
ForEach-Object { $counterP++}
The -contains operator works with a collection as left operand and do not accept wildcards for matching.
I'd like to get an overview of the latest accessed file per profile directory out of a list of profile directories and then write the result in a file.
Given:
A folder with a ton of profile directories in it. In every profile directory, there are more folders and files.
Wanted:
I need the date with the name of the profile directory of the latest accessed file of each profile directory within the parent folder.
What I already have:
With the following commands, the output file lists the last accessed file out of all files in the whole directory times the count of profile directories in the folder:
cd \\Servername\Patch\Profiles
$folder = Get-ChildItem -Directory
$folder | ForEach-Object {
Get-ChildItem -Recurse |
Sort-Object -Property LastAccessTime -Descending |
Select-Object -First 1
} | Out-File "C:\Users\User-abc\Desktop\Log.txt"
So I tried to add the specific path for each profile folder within the parent folder to the Get-ChildItem command like this:
... ForEach-Object {
Get-ChildItem -Path ".\$folder" -Recurse |
Sort-Object ...
I also tried to add a .Name to the $folder variable and to remove the " or put ' instead of ", but nothing helped. I always get the response that there is no parameter found for the parameter -Path.
I also tried to remove the -Path parameter but let the .\$folder or even add a [0] or [1] to the $folder variable, but that also doesn't help.
Call Get-ChildItem on the full path of the current object in the pipeline:
Get-ChildItem \\Servername\Patch\Profiles -Directory | ForEach-Object {
Get-ChildItem $_.FullName -Recurse |
Sort-Object -Property LastAccessTime -Descending |
Select-Object -First 1
}
I have the directory E:\NugetRoot\NugetServer where I need to cycle through the subdirectories on this path and within the packages folder within that subdirectory I need to count the files ending in .nupkg and output them to a cvs file named d:\monitoring\NugetStatistics and each time the script is run, it should append to the file.
Count the files ending in .nupkg in "C:\NugetRoot\NugetServer\\**\Packages" for each folder. (I need to Loop through the ** folders and count each file ending on .nupkg)
Output in cvs file with two columns: one showing the "**" folder name & the other showing the file count.
First find all the *.nupkg files using Get-Childitem with the recurse flag to get all files in sub folders, then filter the results using a regex to exclude any where the final folder is not called Package. Then use another regex to extract the previous folder name, feed that in to a Group-Object to get the count and then into a Export-Csv which includes the append flag.
cd E:\NugetRoot\NugetServer
Get-ChildItem -Filter *.nupkg -Recurse | ? {
$_.DirectoryName -match '\\Packages$'
} | % {
$_.DirectoryName -Replace '^.*\\([^\\]+)\\Packages$', '$1'
} | Group-Object | Select Name, Count | Export-Csv outfile.csv -Append -NoTypeInformation
cd "C:\NugetRoot\NugetServer\\**\Packages"
$a = Get-ChildItem -Name
foreach ($i in $a) {
$b = (Get-ChildItem -Recurse -Force -Include .nupkg -Path $i | Select-Object -ExpandProperty Name).Count
$i + "`t" + $b
}
Here's what I have so far. It displays the server name, ProjectgroupID(or folder name), but get error for package count. Also, I am having trouble getting the average file size as well, I commented those out:
$folders = gci C:\NuGetRoot\NugetServer -Directory
foreach($folder in $folders){
#{ServerName=$env:COMPUTERNAME;
ProjectGroupID = $folder.Name;
NuGetPackageCount = (gci $folder.FullName\packages -Include '*.nupkg') | %{$_.Size}.Count;
#AverageSize= Measure-Object (listof sizes) -Average
} #| Export-Csv -Path c:\temp -NoTypeInformation -Append
}
Measure-Object -Average
what i do is to search files and write some of them with their absoulte path in a file.
now after this searching i want some statistics, like extensions, filesize...
So i need to read the file.txt and get these informations and after all are done, it should show the statistic. It doesnt work yet...
I think i have to store the information in arrays so i can group them later.
$directory="d:\file.txt"
get-content $directory|foreach {
MISSING PART?!
Get-ChildItem -Path $_ |
#Get only files
Where-Object { !$_.PSIsContainer } |
#Group by extension
Group-Object Extension |
#Get data
Select-Object #{n="Extension";e={$_.Name -replace '^\.'}}, #{n="Size (MB)";e={[math]::Round((($_.Group | Measure-Object Length -Sum).Sum / 1MB), 2)}}, Count}
do you have any idea? Thanks
I see you got this code from Determine recursively both COUNT and SUM of all extensions in a folder .
I'm guessing you are modifying it so that instead of a path, you can do different locations based on what is in the text file. In that case, this works:
#Get all items
Get-ChildItem -Path (Get-content C:\Users\krla226\Desktop\file.txt) |
#Get only files
Where-Object { !$_.PSIsContainer } |
#Group by extension
Group-Object Extension |
#Get data
Select-Object #{n="Extension";e={$_.Name -replace '^\.'}}, #{n="Size (MB)";e={[math]::Round((($_.Group | Measure-Object Length -Sum).Sum / 1MB), 2)}}, Count
All I changed from the answer on the other post was instead of a directory, I used Get-Content to pull the files paths from the text file.