# PowerShell script to compare last write time details in files

Hi,

I am trying to change the Last Write time of some files based on the dates of files in another directory.  The files in the other directory have the same name. To do this I am trying to write a PowerShell script that will find the files of a specific date (23 May 2012) in the one directory and then update the last write time of those files with the date from the corresponding files in the other directory.

To change the file date I can just use the below command per file:

$a = Get-Item <FILENAME>;$a.LastWriteTime = $Date  What I am struggling with however is writing a PowerShell script that will find the files of the specific date in one directory and then find the corresponding files in the other directory and then update the dates correctly on the original files. So far I have written this script below to try and prove this can be done but I can’t get it to work. The script should run through and do a check for each file but it is just doing them in one go and not processing them correctly. $CorrectDatePath="V:\Testing"
$InCorrectDatePath="W:\Testing"$FilesWithInCorrectDate='Get-ChildItem $InCorrectDatePath -r | Where-Object {$_.lastwritetime -lt "23 May 2012 23:59" -and $_.LastWriteTime -gt "23 May 2012 00:01" } | Select-Object FullName' ForEach ($I in $FilesWithInCorrectDate) { Get-ChildItem$CorrectDatePath -r | Select-Object Fullname

if ($FilesWithInCorrectDate =$I)
{
write-host $FilesWithInCorrectDate write-host$I
write-host "Filename correct"
}

else

{
write-host $FilesWithInCorrectDate write-host$I
Write-host "Filename Incorrect"
}
}


This doesn't seem to be processing the files individually and is just spitting them out in one big lump which means it can't check the dates
LVL 1
###### Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x

DeveloperCommented:
Sorry, but your choices are either exact matches, or multiple matches. Nothing in-between, as you will not be able to find any logic managing that.
0

Full stack Software EngineerCommented:
first of all u have single quote before calling Get-ChildItem which is wrong.
secondly, line 12 is syntax wrong cause u should use -eq when comparing objects.
another thing, u look for files that last write time is between 23 May 2012 23:59 and
23 May 2012 00:01, which always yields nothing, since 23 May 2012 23:59 is greater than 23 May 2012 00:01.
is want the files that the last write time is on 23 May 2012 (whole day) then use this:
$FilesWithInCorrectDate = Get-ChildItem$InCorrectDatePath -r | Where-Object {(Get-Date $files[0].LastWriteTime -format d) -eq "5/23/2013" } | Select-Object FullName  0 Full stack Software EngineerCommented: here's the script, change$newLastWriteTimeDate to valid date.
cls
CorrectDatePath="V:\Testing"
$InCorrectDatePath="W:\Testing"$newLastWriteTimeDate = "new last write time"
$files = gci$InCorrectDatePath -r | Where-Object {$_.PSIsContainer -eq$false -and (Get-Date $_.LastWriteTime).ToShortDateString() -eq "5/23/2012"}$files | %{
$name =$_.Name
$file = gci$InCorrectDatePath -r | Where-Object {$_.Name -eq$name }
$file.LastWriteTime =$Date
}

0

DeveloperCommented:
That's not very efficient. We can use gci with the names directly, which should speed up things. And $Date is not set: cls$CorrectDatePath="V:\Testing"
$InCorrectDatePath="W:\Testing"$newLastWriteTimeDate = "new last write time"
$files = gci$CorrectDatePath -r | Where-Object {$_.PSIsContainer -eq$false -and (Get-Date $_.LastWriteTime).ToShortDateString() -eq "5/23/2012"}$files | foreach {
(gci $InCorrectDatePath -r -include$_.Name).LastWriteTime = $_.LastWriteTime }  0 DeveloperCommented: Or this one, which will go thru each directory only once: cls$CorrectDatePath="V:\Testing"
$InCorrectDatePath="W:\Testing"$dt = [DateTime] "05/23/2012"

$files =$null
gci $CorrectDatePath -Recurse | ? { !$_.PsIsContainer -and $_.LastWriteTime.Date -eq$dt } |
% { $files += @{$_.Name = $_.LastWriteTime } } gci c:\temp\ee\tst.copy -include$($files.keys) -Recurse | ? {$_.LastWriteTime -ne $files[$_.Name] } |
% { $_.LastWriteTime =$files[$_.Name] }  0 Author Commented: Hi, Looking at the scripts I am not sure they are using the date from the file (named the same) in the other directory. Essentialy I am trying to set the LastWrite time of a file in Directory 'A' with the date of the same file in Directory 'B' So the script should query the files in Direcory 'A' to find the files created on '23/05/2013' and then find the corisponding file in Directory 'B' and use the last write time of this file (file 'B') to reset the Last write time of file 'A'. I have made a few changes to my script and incorporated the changes that @sedwick suggested but I am still not getting the output I expect. Using brake points in PowerShell ISE I have narrowed the problem down to the$CorrectFile variable not being populated but I can't work out why it isn't.

My edited script is below:

$CorrectDatePath="V:\Testing"$InCorrectDatePath="W:\Testing"

$FilesWithInCorrectDate=Get-ChildItem$InCorrectDatePath -recurse | Where-Object {$_.LastWriteTime -gt "23 May 2012 00:01" -and$_.lastwritetime -lt "23 May 2012 23:59"} | Select-Object Name

ForEach
($I in$FilesWithInCorrectDate)

{
$CorrectFile=Get-ChildItem$CorrectDatePath -recurse | Where-Object {$_.Name -eq$I} | Select-Object Name
$IncorrectFile=$I

if ($FilesWithInCorrectDate -eq$CorrectFile)
{
write-output "Filename Match" >> C:\Log\Log.txt
write-output "CorrectFiles" >> C:\Log\Log.txt
write-output $CorrectFile >> C:\Log\Log.txt write-output "IncorrectFiles" >> C:\Log\Log.txt write-output$IncorrectFile >> C:\Log\Log.txt

$CorrectDate=Get-ChildItem$CorrectDatePath -r | Where-Object {$_.Name -eq$CorrectFileName } | Select-Object LastWriteTime
Write-Output $CorrectDate >> C:\Log\Log.txt } else { write-output$I >> C:\Log\Log.txt
Write-output "Filename Incorrect" >> C:\Log\Log.txt
}
}


I think the issue is being caused by these lines:

  $CorrectFile=Get-ChildItem$CorrectDatePath -recurse | Where-Object {$_.Name -eq$I} | Select-Object Name
$IncorrectFile=$I

0

Full stack Software EngineerCommented:
i had a bug in my script, the date compare was wrong and i fixed it, try now:
cls
$CorrectDatePath="V:\Testing"$InCorrectDatePath="W:\Testing"
$files = gci$CorrectDatePath -r | Where-Object {$_.PSIsContainer -eq$false -and (Get-Date $_.LastWriteTime).ToString("MM/dd/yyyy") -eq "05/23/2012"}$files | %{
(gci $InCorrectDatePath -r -include$_.Name).LastWriteTime = $_.LastWriteTime }  0 DeveloperCommented: If I understood correctly, you want to filter the files in$IncorrectdatePath for the date 05/23/2012; all those files should get the timestamp of $CorrectDatePath files. Then the code is indeed wrong. Can you confirm? 0 Author Commented: Hi Segwick, Looking at the script you have written it looks like you are looking for files in the$CorrectDataPath Variable where the date = 23/05/2013 which is incorrect the files which have the LastWritetime set to  23/05/2013  are in the $IncorrectDatePath variable location. The files in the$CorrectDatePath variable location have the correct date and this is the date that is going to be used to reset the date on the files in the $InCorrectDatePath location. Thanks 0 Author Commented: Qlemo, The script should filter the files in the$incorrectdatepath location for files with the last Write time of 23/05/2012 then it should find the files of the same name in the $correctdatelocation and use the time stamp of the files in the$correctdatelocation to reset the timestamp of the files in the $incorrectdatepath location. Thanks 0 DeveloperCommented: Then we need to change the code. My last suggestion looks like this: cls$CorrectDatePath="V:\Testing"
$InCorrectDatePath="W:\Testing"$dt = [DateTime] "05/23/2012"

$files =$null
gci $InCorrectDatePath -Recurse | ? { !$_.PsIsContainer -and $_.LastWriteTime.Date -eq$dt } |
% { $files += @{$_.Name = $_ } } gci$CorrectDatePath -include $($files.keys) -Recurse |
? { $_.LastWriteTime -ne$files[$_.Name].LastWriteTime } | % {$files[$_.Name].LastWriteTime =$_.LastWriteTime }

0

Author Commented:
Hi Qlemo,

Just to double check your script will:

Find files within the $InCorrectDatePath with a last modified date of 23/05/2013. It will then find the same file in the$CorrectDatePath (The file has the same name) and use the last modified time on this file to update the date of the file in the $InCorrectDatePath? Thanks 0 DeveloperCommented: That's the way it is! 0 Commented: I'm not sure exactly what you want, but I was just wondering if this could all be done more simply with the robocopy command. Assuming your two directories have the same files you could run the following. robocopy x:/PATH1 x:/path2 /copy:T /minage:1 /maxage:2 You could even set dates robocopy x:/PATH1 x:/path2 /copy:T /minage:20130513 /maxage:20130512 The option /copy:T means only copy the time stamp, not the data or attributes or other security information. I've tested this quickly with one file in the folders and only the time stamp gets updated. The file contents remain unchanged. 0 Author Commented: Hi Serialband, The files with the correct date on them do not have the correct contents so will the robocopy command only copy the timestamp and no other data? e.g. contents ect..... Thanks 0 Author Commented: Qlemo, I will test your script out now. Thanks 0 DeveloperCommented: Checked the robocopy - and it works as serialband described! No content change, only the timestamp. But: The /minage and /maxage switches only work on the source files ($CorrectDataPath), and the requirement is to filter for destination file timestamps.
So using robocopy, we first have to get a file list of $IncorrectDataPath with the timestamp condition met, and then stuff that list into RoboCopy to change the timestamps based on$CorrectDataPath:
@echo off
set EnableDelayedExpansion

set CorrectDataPath=V:\Testing
set IncorrectDataPath=W:\Testing

set files=
for /F "tokens=*" %%A in (
'robocopy /L /NJH /NJS /NDL /NC /NS /NP /minage:20130513 /maxage:20130512 %IncorrecDataPath% %CorrectDataPath%'
) do set files=!files! "%%~A"
robocopy /copy:T %CorrectDataPath% %InCorrectDataPath %files%

0

Commented:
You could always try to run robocopy in reverse and copy only the data but not the time stamp with /COPY:D
0

Author Commented:
Hi Qlemo,

When I try to run your script I get the below error:

!files! "****  /MIR can DELETE files as well as copy them !"

Do you know what would cause this?

Thanks

Matt
0

Author Commented:
Hi serialband,

The files with the correct date should remain intact and not changed so copy the data from the files with the incorrect date would not be an option unfortunatly.

Thanks for the suggestion though.
0

DeveloperCommented:
That is a strange output ;-). It is the last line of RoboCopy, if a syntax error occured. And it does - one character got lost somewhere in the copy & paste :(.
@echo off
set EnableDelayedExpansion

set CorrectDataPath=V:\Testing
set IncorrectDataPath=W:\Testing

set files=
for /F "tokens=*" %%A in (
'robocopy /L /NJH /NJS /NDL /NC /NS /NP /minage:20130513 /maxage:20130512 %IncorrectDataPath% %CorrectDataPath%'
) do set files=!files! "%%~A"
robocopy /copy:T %CorrectDataPath% %InCorrectDataPath %files%

0

Author Commented:
Hi Qlemo,

I was just trying to check the script before I actually ran it so I commented out the 2nd Robocopy line (Line 11) and added:

echo %files% >> C:\Log\RLog.txt


I did this to check what files where being picked up by the script so I could double check it was all working correctly. When I did this the script doesn't produce any values. Is the script not setting the %files% variable correctly or is my echo to log file in the wrong place in the script (Should it be within the brackets?)

Thanks again.
0

DeveloperCommented:
Assuming you have replaced the very last line, you've done it correctly. Not having anything logged means there are no files. For testing which files would be changed, use this first:
@echo off
set CorrectDataPath=V:\Testing
set IncorrectDataPath=W:\Testing
robocopy /L /NJH /NJS /NDL /NC /NS /NP /minage:20130513 /maxage:20130512 %IncorrectDataPath% %CorrectDataPath%

If you are getting a file list, continue with the "original" script, and prefix an echo in the last line (then sounding:
echo robocopy /copy:T %CorrectDataPath% %InCorrectDataPath %files%

You can, of course, echo that into a log file instead of the screen.
0

Author Commented:
Hi Qlemo,

Sorry about the late reply on this I have tried to run the scipt again and it is still not picking up any files at my end.

I have attached the log files I have got it to create and also the command output.

Below is the script with the logging modifications:

::@echo off
set EnableDelayedExpansion
set CorrectDataPath="E:\Testing.Old"
set IncorrectDataPath="E:\Testing"
set LogPath="E:\RoboLog.txt"
pause
set files=
for /F "tokens=*" %%A in (
'robocopy /L /NJH /NJS /NDL /NC /NS /NP /minage:20120523 /maxage:20120523 %IncorrectDataPath% %CorrectDataPath%'
) do set files=!files! "%%~A"
pause
::robocopy /copy:T %CorrectDataPath% %InCorrectDataPath %files%
echo %CorrectDataPath% >> %LogPath%
echo %InCorrectDataPath% >> %LogPath%
echo %files% >> %LogPath%


I have also attached a CSV Export from a PowerShell command that lists all of the files with the Last Modified date of 23/05/2012.

Thanks
CommandOutPut.txt
RoboLog.txt
WrongDate.csv
0

DeveloperCommented:
Note that we used a minage of one day ahead of maxage - try if that makes a difference. Here it should be /minage:20130523 /maxage:20130522
0

Author Commented:
Hi Qlemo,

I tried setting the minage and maxage to:

/minage:20120522 /maxage:20120523

I am still not seeing any files appear in the log or outputin to screen when I run the script.

Thanks
0

DeveloperCommented:
minage needs a more recent date as maxage ...
0

Author Commented:
Hi Qlemo,

So the minage needs to be a later date than the maxage? e.g.

/minage:20120524 /maxage:20120522
0

DeveloperCommented:
Yes. "maxage" of 22th is 7 days back, "minage" of 24th 5 days, so the condition is "at least 5 days, but no more than 7 days old". If you think that way, it is easier to remember.
0

Author Commented:
Hi Qlemo,

I have my minage and maxage set as bellow:

/minage:20120524 /maxage:20120522

Which I belive is correct as the date I am intrested in is the 23/05/2012 however the script is still not pulling any files out.

I have noticed an error saying the EnableDelayedExpansion variable is not being set due to a null value.

Other than that there are no errors.
0

DeveloperCommented:
Ooops, that line is wrong since the very beginning. The proper line is
setlocal EnableDelayedExpansion

I have tested the robocopy itself with some sample files again here, and it works great. However, I've seen that the list might contain files which are only in %IncorretDataPath%, so let's add /XL to exclude those:
@echo off
setlocal EnableDelayedExpansion
set CorrectDataPath="E:\Testing.Old"
set IncorrectDataPath="E:\Testing"
set LogPath="E:\RoboLog.txt"
pause
set files=
for /F "tokens=*" %%A in (
'robocopy /L /NJH /NJS /NDL /NC /NS /NP /XL /minage:20120524 /maxage:20120522 %IncorrectDataPath% %CorrectDataPath%'
) do set files=!files! "%%~A"
pause
::robocopy /copy:T %CorrectDataPath% %InCorrectDataPath %files%
echo %CorrectDataPath% >> %LogPath%
echo %InCorrectDataPath% >> %LogPath%
echo %files% >> %LogPath%

Please pay attention that you must not switch echoing on! The FOR loop is parsing the command output, and command echoing will interfere with the desired data.
0

Author Commented:
Hi Qlemo,

Thanks for the advice about leaving the echo on I will do this in future.

I have run the script again and it pulled back no files again however I then swapped the DataPath variables around in the robocopy line so it is like:

'robocopy /L /NJH /NJS /NDL /NC /NS /NP /XL /minage:20120524 /maxage:20120522 %IncorrectDataPath% %CorrectDataPath%'


This has then pulled back some files into the log file (Which is attached) however it has only pulled back 2 files which are both in the top level diretory with a last modified date of 15/03/2012 which means I dont think they should of been picked up.

Thanks
RoboLog.txt
0

DeveloperCommented:
The RoboCopy should not visit subfolders, that far it is correct.
Without having the files here, I cannot tell why it should not work. It does for my test cases.

BTW, did you ever try out http:#a39174933 ? That one is the PS approach, as requested originally ...
0

Author Commented:
Hi Qlemo,

You have just linked back to this forum?

Anyway would a better option be to have a PowerShell script list out the name of the files with the incorrect date and then feed these names into the Robocopy script?

Thanks
0

DeveloperCommented:
The EE parser was including the trailing question mark into the link. Doh! I have corrected the link now, it should point to a comment of me in this thread.
0

Author Commented:
Hi Qlemo,

I just tried to the run the script with some logging so I can double check what files are being editied. When I ran the script I got the below error:

The '+=' operator failed: Item has already been added. Key in dictionary: 'Thum
At E:\Files.ps1:9 char:16
+   % { $files += <<<< @{$_.Name = $_ } } + CategoryInfo : InvalidOperation: (System.Collections.Hashtable: Hashtable) [], RuntimeException + FullyQualifiedErrorId : OperatorFailed The '+=' operator failed: Item has already been added. Key in dictionary: 'Thum bs.db' Key being added: 'Thumbs.db'. At E:\Files.ps1:9 char:16 + % {$files += <<<<  @{ $_.Name =$_ } }
+ CategoryInfo          : InvalidOperation: (System.Collections.Hashtable:
Hashtable) [], RuntimeException
+ FullyQualifiedErrorId : OperatorFailed

The errors just repeats over and over again so I am guessing for some reason it is trying to add the same files into the variable.

The editted script basically commented out the part of the script that is doing the editing and added in a Write-Host line to export the txt. The edited script is below:

cls
$CorrectDatePath="E:\Testing.old"$InCorrectDatePath="E:\Testing"
$dt = [DateTime] "05/23/2012"$files = $null gci$InCorrectDatePath -Recurse |
? { !$_.PsIsContainer -and$_.LastWriteTime.Date -eq $dt } | % {$files += @{ $_.Name =$_ } }

Write-Host $files >> E:\PLog.txt <# gci$CorrectDatePath -include $($files.keys) -Recurse |
? { $_.LastWriteTime -ne$files[$_.Name].LastWriteTime } | % {$files[$_.Name].LastWriteTime =$_.LastWriteTime }

#>

0

DeveloperCommented:
Oh, you have thumb.db files in all of your folders?! The way I implemented it, no file name may occur twice. We could exclude Thumb.DB, or add a check to skip doing anything if the file name has been seen already:
cls
$CorrectDatePath="E:\Testing.old"$InCorrectDatePath="E:\Testing"
$dt = [DateTime] "05/23/2012"$files = $null gci$InCorrectDatePath -Recurse |
? { !$_.PsIsContainer -and$_.LastWriteTime.Date -eq $dt } | ? {$files[$_.Name] -eq$null } |
% { $files += @{$_.Name = $_ } } Write-Host$files >> E:\PLog.txt

<#

gci $CorrectDatePath -include$($files.keys) -Recurse | ? {$_.LastWriteTime -ne $files[$_.Name].LastWriteTime } |
% { $files[$_.Name].LastWriteTime = $_.LastWriteTime } #>  0 Author Commented: Hi Qlemo, We might have a few files names the same not just the Thumbs.DB files. I guess we can run the scipt multiple times though and each time it will sort out one instance of the file name? Also I am not majorly fussed about the timestamp on the Thumbs.DB file so we can probably exclude it. Thanks 0 DeveloperCommented: gci$InCorrectDatePath -Recurse -exclude "Thumbs.db"
should exclude those.  And yes, running the script multiple times should work if you have duplicate file names. However, if there are duplicate file names in $CorrectDataPath, the time stamp will get changed several times, and eventually have the one of the latest file encountered. 0 Author Commented: Thanks all for your responses, i will test out over the next few days and let you know how i get on much appreciated for your time 0 Author Commented: Hi Qlemo, Sorry for the late reply on this I was on Leave and didnt have access to my laptop. The files in the$CorrectDataPath should be named the same as they are in the $InCorrectDataPath so would their be issues where the name is the same in the$CorrectDataPath like you mentioned?

Also would a potential solution to this to get the script to match the file names as the files are in different directorys the fullnames wont match. Then get once it has matched the filenames get it to spit out the fullname for the file?

Sorry again for the late reply on this!
0

Author Commented:
Hi Guys,

I still can't seem to get this to work so I am going to knock it on the head thanks for all the help I have distributed the points around to the helpful comments.

If I do find a solution that works out I will post it on here for future reference.
0