A friend of mine with a Business Intelligence company asked me a favor. They have a lot of data (files & folders) that have to be copied around in the lab, at clients etc. This often leaves the date modified on the folders not reflecting the last modified date of the most recent modification in that folder’s sub structure. This causes a lot of confusion in their processes, communication and testing.
The needed a script to correct that. Now they wanted a script, not an application (no installations, editable code). Good news they had a Windows machine (XP or higher) to run the code on and file sharing on Linux was using SAMBA so we could use PowerShell. VBScript/Java Script can only change dates on files using the Shell.Application object but NOT of folders. They also can’t directly call Windows API’s. First of all that’s “unmanaged code to the extreme” and using a COM dll to get access to the Windows API violates the condition set out from the start. But luckily PowerShell came to the rescue!
To accomplish the request we sort of needed to walk the tree backwards from all it’s branches back to the root. I’m no math guru so writing that sort of a reverse incursive algorithm wasn’t really an option. I decided to use plain good old recursion and count the depth of the folder structure to know how many times I needed to recursively parse through to get the correct modified date to “walk up” the folder structure. Here a snippet as a demo:
# Demo snippet $root = "E:TestRootTestDataStructure" # The folder structure to parse $DeepestLevel = 0 # A counter to persist the deepest level found up to that moment $File $LevelCheck $Return #Loop through the folder structure recursively to determine the deepest level. foreach ($folder in Get-ChildItem $root -recurse | Where-Object {$_.PsIsContainer -eq "True"}) { $search = $folder.FullName Write-Host "Folder: $search" #Sort the returned objects by modified date and select the most recent (last) one $Return = Get-ChildItem $search | Sort-Object LastWriteTime | Select-Object -last 1 Write-Host "Childe File/Subfolder most recently modified: $Return" #Check how deep is the current level $LevelCheck = $Return.FullName.split("").Count -1 # Compare above with deepest level foudn so far and set to new value if needed. if ($LevelCheck -gt $DeepestLevel) {$DeepestLevel = $LevelCheck} Write-Host "LevelCheck: $LevelCheck" Write-Host "DeepestLevel: $DeepestLevel" } # Now actually recurively walk the folder structure x times where x = Deepestlevel do { foreach ($folder in Get-ChildItem $root -recurse | Where-Object {$_.PsIsContainer -eq "True"}) { $search = $folder.FullName #Sort the returned objects by modified date and select the most recent (last) one $Return = Get-ChildItem $search | Sort-Object LastWriteTime | Select-Object -last 1 Write-Host "Child File or Folder most recently modified: " $Return.Fullname #Set the modified date on the parent folder to the one of most recent modified child object if ($Return -ne $null) {$folder.LastWriteTime = $Return.LastWriteTime} Write-Host "Parent folder " $search " last modified date set to " $Return.LastWriteTime } ; $DeepestLevel-- } #Counter -1 until ($DeepestLevel -eq 0)
Going through the folder structure to0 often is OK, going through it to0 few times is bad as it doesn’t accomplish the goal. So the logical bug in the code that loops once to much due to “\” in the UNC path isn’t an issue. Not really elegant but very effective. The speed is also acceptable. It ran through 30,000 files, 20 GB in all in about a minute. Quick & Dirty does the trick sometimes.
The code will work with PowerShell 1.0/2.0 against a local and a UNC path as long as you have the correct permissions.
This is just a code snippet, not the production code with error handling, so please test it in a lab & understand what it does before letting it rip through your folder structures.
Cheers