For example, here's a folder and file structure:
Code: Select all
root
└── A/
└── B/
└── abcd.txt
Code: Select all
root
└── A/
└── B/
└── abcd.txt
Yes, by design, but not by logic.
Yeah, and it is a very frustrating situation. Because, maybe it follows some computer logic of its own, but from a human logic point of view, as I described above, it's just too weird.
Oh. I already tried this option before writing my post, but didn't get what I wanted, and now I understand why - despite the fact the modified dates of the child files were changed, their sizes remained the same.void wrote: ↑Sun Aug 18, 2024 11:48 pm There is a always_update_folder_recent_change advanced setting.
When enabled, all parents to the root are updated for the Date Recently Changed property..
However, grand parents will only update when a child file size changes.
When I try to sort files and folders in Total Commander or Windows Explorer by Date modified, I want to see the correct sorting order in whch the changes in the modified date of all files and folders would be reflected properly, but not like at the moment, when folder "A", which contains subfolder "B" with a younger modified date than folder "A", is at the end of the sorting list.
Code: Select all
#Set-PSDebug -Trace 2
# Print the full command line used to run the script
Write-Host "Script was run with the following command:"
Write-Host $MyInvocation.Line
Write-Host ""
# Function to split the input string based on the pattern "space followed by drive letter and a path"
function Split-ArgumentsByPattern {
param (
[string]$inputString
)
# Regular expression pattern to match space followed by drive letter and path
$pattern = '(?<=\s|"|^)([A-Za-z]:\\[^\/\:\*\?\"\<\>\|]+(?= [A-Za-z]:|"|$))'
# Split the string by the pattern
$folders = [regex]::Matches($inputString, $pattern) | ForEach-Object { $_.Value }
# Remove any leading or trailing whitespace from each folder path
$folders = $folders | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }
return $folders
}
# Combine all arguments into a single string
Write-Host "Arguments : $args"
Write-Host ""
#$combinedArgs = $args -join " "
#Write-Host "Combined Arguments: $combinedArgs"
#Write-Host ""
# Split the combined string into individual folder paths
$rootFolders = Split-ArgumentsByPattern -inputString $args #$combinedArgs
# Print each folder path passed in the array
Write-Host "RootFolders from arguments:"
foreach ($folder in $rootFolders) {
Write-Host "- $folder"
}
# Function to update the parent folder's LastWriteTime
function Update-ParentFolderTime {
param (
[string]$folderPath
)
# Get all items (files and subfolders) in the current folder
$items = Get-ChildItem -Path $folderPath -Recurse
# Find the item with the most recent LastWriteTime
$mostRecentItem = $items | Sort-Object LastWriteTime -Descending | Select-Object -First 1
# If there's a most recent item, compare its LastWriteTime with the parent folder
if ($mostRecentItem) {
$parentFolder = Get-Item -Path $folderPath
if ($parentFolder.LastWriteTime -lt $mostRecentItem.LastWriteTime) {
# Update the parent folder's LastWriteTime to the most recent item's LastWriteTime
Write-Host "6. Updating LastWriteTime of the folder '$folderPath' from $($parentFolder.LastWriteTime) to $($mostRecentItem.LastWriteTime)" -ForegroundColor Red
$parentFolder.LastWriteTime = $mostRecentItem.LastWriteTime
} else {
Write-Host "7. The folder '$folderPath' has the most recent LastWriteTime than its child files and subfolders" -ForegroundColor DarkGreen
}
}
}
# Function to recursively process all folders starting from the bottom level
function Process-Folders {
param (
[string]$rootFolder
)
# Get all subfolders
$subfolders = Get-ChildItem -Path $rootFolder -Directory
Write-Host "1. $subfolders = Get-ChildItem -Path $rootFolder -Directory"
Write-Host "2. $subfolders"
foreach ($subfolder in $subfolders) {
# Recursively process subfolders
Write-Host "3. Process-Folders -rootFolder $($subfolder.FullName)"
Process-Folders -rootFolder $subfolder.FullName
}
# Update the currently processed root folder
Write-Host "5. Update-ParentFolderTime -folderPath $rootfolder"
Update-ParentFolderTime -folderPath $rootFolder
}
# Validate that at least one folder is provided as argument
if (-not $rootFolders) {
Write-Host '
--------------------------------------------------------
Please provide one or more root folder paths as arguments.
For example:
.\UpdateFolderModifiedDate.ps1 "C:\path\to\folder"
or
.\UpdateFolderModifiedDate.ps1 C:\path\to\folder
or
.\UpdateFolderModifiedDate.ps1 "C:\path\to\folder" "C:\path\to\another\folder" "C:\path\to\yet\another\folder"
or
.\UpdateFolderModifiedDate.ps1 C:\path\to\folder C:\path\to\another\folder C:\path\to\yet\another\folder
--------------------------------------------------------
'
# If no arguments were provided, prompt the user to enter one or more folder paths
$input = Read-Host 'Or please enter the paths of the folders you want to process (without/with quotes, just separate multiple paths with the space/s).
For example:
"C:\path\to\folder" "C:\path\to\another\folder"
C:\path\to\folder C:\path\to\another\folder
'
# If the user provided folder paths, split them into an array
if ($input) {
$rootFolders = Split-ArgumentsByPattern -inputString $input # -split ",\s*" # Split by comma, allowing for optional spaces
Write-Host "Input: $input"
Write-Host "RootFolders from input: $rootFolders"
} else {
Write-Host "No folder paths provided. Exiting script."
Set-PSDebug -Trace 0
exit 1
}
}
# Loop through each provided folder and process it
foreach ($rootFolder in $rootFolders) {
if (Test-Path $rootFolder) {
Write-Host "RootFolders from arguments: $rootFolders"
Write-Host "Processing folder: $rootFolder"
Process-Folders -rootFolder $rootFolder
} else {
Write-Host "Folder not found: $rootFolder"
}
}
Set-PSDebug -Trace 0
Code: Select all
TOTALCMD#BAR#DATA
powershell.exe -noexit -ExecutionPolicy Bypass "X:\path\to\the\script\UpdateFolderModifiedDate.ps1"
'%X%Y%P%S%T%R'
C:\Program Files (x86)\Total Commander\Wcmicons.dll,51
Change the modification date of folders to match the most recent modification date of their child files or subfolders.
-1
Code: Select all
Directory of T:\K-ORSAIR\LIB\PLAYERS\
----------------------------------------------------------------------------
_d____ Oct 24, 2022 21:01:42 [MPlayer Skins]
_d____ Sep 12, 2022 12:13:55 [MPlayer]
_d____ Sep 07, 2022 12:07:26 [MediaPlayerClassic]
_d____ Mar 07, 2022 13:44:09 [VLC Video Lan]
_d____ Oct 27, 2021 14:23:05 [OLD]
_d____ Jul 03, 2013 11:31:19 [WMP Skins]
_d____ May 20, 2013 13:47:06 [KMPlayer Skins]
_d____ Nov 03, 2007 22:05:44 [VLC Skins]
1,527,829 ______ Dec 28, 2006 20:50:00 zp500std (zoom player free).exe
2,986,272 ______ Dec 28, 2006 20:49:00 zp500pro (zoom player pro).exe
933,478 ______ Feb 18, 2004 14:05:00 zoomplayer331std.zip
696,910 ______ Nov 07, 2002 09:55:00 zoomplayer290.zip
I will consider a search to list 'modified' folders where:If I want to know if there are any changes occurred in folder "A" - how can I do that?
I want the changes in the modified date of all descendants (files and subfolders) to be reflected on the modified date of all parent(grandfather, great-grandfather, great-great-grandfather etc.) folders.
Yes, they will be marked modified, but with the corresponding date of this modification, which will allow them to be sorted properly by Date Modified.
How?
Will it help to properly sort files and folders by the Date Modified column in TC or Windows Explorer?
Because programs will constantly write to %APPDATA%.How?Won't folders like C:, C:\Users, C:\Users\My User Name, C:\Users\My User Name\AppData get in the way?
Everything only.Will it help to properly sort files and folders by the Date Modified column in TC or Windows Explorer?
Is it possible to do this not only via limiting to a specific folder, but more broadly through blacklisting/whitelisting?
Could it be implemented in such a way that allows proper sorting by Date modified not only in Everything, but also in the system as a whole?
But I don't see any date modifications of the root folder if I make changes to files at depth 2 and below.When enabled, any change made to the Everything folder database entry will cause the recent change date to update.
This includes folder size changes.
This setting will update the date recently changed property for folders for every change single event. (even when there is no actual change)
This includes folder size changes.
For your use case, I recommend writing a script that traverses the desired folders and sets the filetime of all parents.Is it possible to do this not only via limiting to a specific folder, but more broadly through blacklisting/whitelisting?
Code: Select all
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
// update parent to latest file timestamp:
void parse_file2folder_date(char *dstpath)
{
char dstbuf[4096];
WIN32_FIND_DATA fd;
HANDLE h;
HANDLE fh;
LARGE_INTEGER best_ft;
printf("parse %s\n",dstpath);
best_ft.QuadPart = 0;
sprintf(dstbuf,"%s\\*.*",dstpath);
h = FindFirstFile(dstbuf,&fd);
if (h != INVALID_HANDLE_VALUE)
{
for(;;)
{
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((strcmp(fd.cFileName,"..") != 0) && (strcmp(fd.cFileName,".") != 0))
{
sprintf(dstbuf,"%s\\%s",dstpath,fd.cFileName);
parse_file2folder_date(dstbuf);
}
}
else
{
LARGE_INTEGER dm_ft;
dm_ft.HighPart = fd.ftLastWriteTime.dwHighDateTime;
dm_ft.LowPart = fd.ftLastWriteTime.dwLowDateTime;
if (dm_ft.QuadPart > best_ft.QuadPart)
{
best_ft.QuadPart = dm_ft.QuadPart;
}
}
if (!FindNextFile(h,&fd)) break;
}
FindClose(h);
}
if (best_ft.QuadPart)
{
HANDLE fh;
fh = CreateFile(dstpath,FILE_WRITE_ATTRIBUTES,0,0,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0);
if (fh != INVALID_HANDLE_VALUE)
{
printf("set ft %s\n",fd.cFileName);
SetFileTime(fh,0,0,(FILETIME *)&best_ft.QuadPart);
CloseHandle(fh);
}
else
{
printf("invalid file handle %s\n",dstbuf);
// ExitProcess(0);
}
}
}
// copy timestamps:
void parse(char *dstpath,char *srcpath)
{
char dstbuf[4096];
char srcbuf[4096];
WIN32_FIND_DATA fd;
HANDLE h;
HANDLE fh;
printf("parse %s %s\n",dstpath,srcpath);
sprintf(srcbuf,"%s\\*.*",srcpath);
h = FindFirstFile(srcbuf,&fd);
if (h != INVALID_HANDLE_VALUE)
{
for(;;)
{
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if ((strcmp(fd.cFileName,"..") != 0) && (strcmp(fd.cFileName,".") != 0))
{
FILETIME ft;
HANDLE fh;
sprintf(dstbuf,"%s\\%s",dstpath,fd.cFileName);
fh = CreateFile(dstbuf,FILE_WRITE_ATTRIBUTES,0,0,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0);
if (fh != INVALID_HANDLE_VALUE)
{
printf("set ft %s\n",fd.cFileName);
SetFileTime(fh,&fd.ftCreationTime,0,&fd.ftLastWriteTime);
CloseHandle(fh);
}
else
{
printf("invalid file handle %s\n",dstbuf);
// ExitProcess(0);
}
sprintf(srcbuf,"%s\\%s",srcpath,fd.cFileName);
parse(dstbuf,srcbuf);
}
}
else
{
sprintf(dstbuf,"%s\\%s",dstpath,fd.cFileName);
fh = CreateFile(dstbuf,FILE_WRITE_ATTRIBUTES,0,0,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0);
if (fh != INVALID_HANDLE_VALUE)
{
printf("set ft %s\n",fd.cFileName);
SetFileTime(fh,&fd.ftCreationTime,0,&fd.ftLastWriteTime);
CloseHandle(fh);
}
else
{
printf("invalid file handle %s\n",dstbuf);
// ExitProcess(0);
}
}
if (!FindNextFile(h,&fd)) break;
}
FindClose(h);
}
}
int main(int argc,char **argv)
{
parse_file2folder_date("E:\\Music Albums");
// parse("I:\Backup folder","D:\folder");
Yeah, it's a shame... but we have what we have.
Well, I mentioned in the very first post and even gave the code of a script that performs this function, but as I wrote then - it has the biggest drawback that it doesn't work automatically, but only in manual mode.
Excuse me, where can this code be used? In Everything?
Does it work automatically?
Do you have C code where we can preserve all 3 date and time fields of a chosen source copy of files and folders to a chosen destination ?void wrote: ↑Thu Aug 29, 2024 12:04 am It's a shame there isn't an NTFS driver level option to do this..
I would like to avoid writing to volumes with Everything.
I think this would be better as a separate tool.
For your use case, I recommend writing a script that traverses the desired folders and sets the filetime of all parents.Is it possible to do this not only via limiting to a specific folder, but more broadly through blacklisting/whitelisting?
Here's some C code that I use to update parent folder timestamps and copy timestamps to a backup location:Code: Select all
#include <stdlib.h> #include <stdio.h> #include <windows.h> // update parent to latest file timestamp: void parse_file2folder_date(char *dstpath) { char dstbuf[4096]; WIN32_FIND_DATA fd; HANDLE h; HANDLE fh; LARGE_INTEGER best_ft; printf("parse %s\n",dstpath); best_ft.QuadPart = 0; sprintf(dstbuf,"%s\\*.*",dstpath); h = FindFirstFile(dstbuf,&fd); if (h != INVALID_HANDLE_VALUE) { for(;;) { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if ((strcmp(fd.cFileName,"..") != 0) && (strcmp(fd.cFileName,".") != 0)) { sprintf(dstbuf,"%s\\%s",dstpath,fd.cFileName); parse_file2folder_date(dstbuf); } } else { LARGE_INTEGER dm_ft; dm_ft.HighPart = fd.ftLastWriteTime.dwHighDateTime; dm_ft.LowPart = fd.ftLastWriteTime.dwLowDateTime; if (dm_ft.QuadPart > best_ft.QuadPart) { best_ft.QuadPart = dm_ft.QuadPart; } } if (!FindNextFile(h,&fd)) break; } FindClose(h); } if (best_ft.QuadPart) { HANDLE fh; fh = CreateFile(dstpath,FILE_WRITE_ATTRIBUTES,0,0,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0); if (fh != INVALID_HANDLE_VALUE) { printf("set ft %s\n",fd.cFileName); SetFileTime(fh,0,0,(FILETIME *)&best_ft.QuadPart); CloseHandle(fh); } else { printf("invalid file handle %s\n",dstbuf); // ExitProcess(0); } } } // copy timestamps: void parse(char *dstpath,char *srcpath) { char dstbuf[4096]; char srcbuf[4096]; WIN32_FIND_DATA fd; HANDLE h; HANDLE fh; printf("parse %s %s\n",dstpath,srcpath); sprintf(srcbuf,"%s\\*.*",srcpath); h = FindFirstFile(srcbuf,&fd); if (h != INVALID_HANDLE_VALUE) { for(;;) { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if ((strcmp(fd.cFileName,"..") != 0) && (strcmp(fd.cFileName,".") != 0)) { FILETIME ft; HANDLE fh; sprintf(dstbuf,"%s\\%s",dstpath,fd.cFileName); fh = CreateFile(dstbuf,FILE_WRITE_ATTRIBUTES,0,0,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0); if (fh != INVALID_HANDLE_VALUE) { printf("set ft %s\n",fd.cFileName); SetFileTime(fh,&fd.ftCreationTime,0,&fd.ftLastWriteTime); CloseHandle(fh); } else { printf("invalid file handle %s\n",dstbuf); // ExitProcess(0); } sprintf(srcbuf,"%s\\%s",srcpath,fd.cFileName); parse(dstbuf,srcbuf); } } else { sprintf(dstbuf,"%s\\%s",dstpath,fd.cFileName); fh = CreateFile(dstbuf,FILE_WRITE_ATTRIBUTES,0,0,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0); if (fh != INVALID_HANDLE_VALUE) { printf("set ft %s\n",fd.cFileName); SetFileTime(fh,&fd.ftCreationTime,0,&fd.ftLastWriteTime); CloseHandle(fh); } else { printf("invalid file handle %s\n",dstbuf); // ExitProcess(0); } } if (!FindNextFile(h,&fd)) break; } FindClose(h); } } int main(int argc,char **argv) { parse_file2folder_date("E:\\Music Albums"); // parse("I:\Backup folder","D:\folder");
voidhash also has code that resets folder timestamps.
robocopy, fastcopy, turbocopy? ...Do you have C code where we can preserve all 3 date and time fields of a chosen source copy of files and folders to a chosen destination ?
robocopy does work but have to enter source folder and destination and all options manually or to make robocopy job to exclude certain paths. But, for smple copy is there a C code script or anything equivalent ?therube wrote: ↑Thu Aug 29, 2024 5:35 pmrobocopy, fastcopy, turbocopy? ...Do you have C code where we can preserve all 3 date and time fields of a chosen source copy of files and folders to a chosen destination ?
And I guess this is related, how to automate robocopy with windows copy and paste ?
And there was another thread of yours (that I'm not finding at the moment) where you asked the same question?
And all answers are likely to have gotcha's too.
Code: Select all
Param
(
[Parameter(Mandatory=$true)]
[String]$startfolder
)
# Check if valid path
If ( -not ( Test-Path $startfolder )) {
echo "Not a valid folder: $startfolder"
Exit
}
# Create list of all subfolders and sort descending by name (+ path), so deeper levels come first.
$allfolders = gci -literalpath $startfolder -dir -recurse -force | sort FullName -descending
# For each of these subfolders: check if date of most recent item in this folder is newer than folder date. If so: update folderdate.
$allfolders | % {
$ItemsDate = ''
echo "Current Folder : $($_.FullName) "
$ItemsDate = (gci -Dir -literalpath $_.FullName -force | sort LastWriteTime)[-1].LastWriteTime
echo "Most recent item date = $($ItemsDate)"
echo "FolderDate = $($_.lastWriteTime)"
If ($_.lastWriteTime -lt $ItemsDate) {
echo "FolderDate $_.FullName will be updated"
# $_.lastWriteTime = $ItemsDate
}
}
Code: Select all
folder: sort:dm count:1 columns:dm;name;size;path
Change the following line:Do you have C code where we can preserve all 3 date and time fields of a chosen source copy of files and folders to a chosen destination ?
SetFileTime(fh,&fd.ftCreationTime,0,&fd.ftLastWriteTime);
SetFileTime(fh,&fd.ftCreationTime,&fd.ftLastAccessTime,&fd.ftLastWriteTime);