Link to home
Start Free TrialLog in
Avatar of Contigo1
Contigo1

asked on

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

Open in new window


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"
                }
        }

Open in new window


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
Avatar of Meir Rivkin
Meir Rivkin
Flag of Israel image

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 

Open in new window

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
}

Open in new window

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
}

Open in new window

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] }

Open in new window

Avatar of Contigo1
Contigo1

ASKER

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
                }
        }

Open in new window


   

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

Open in new window

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
}

Open in new window

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?
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
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
SOLUTION
Avatar of Qlemo
Qlemo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
That's the way it is!
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
Qlemo,

I will test your script out now.

Thanks
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%

Open in new window

You could always try to run robocopy in reverse and copy only the data but not the time stamp with /COPY:D
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
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.
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%

Open in new window

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

Open in new window


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.
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%

Open in new window

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%

Open in new window

You can, of course, echo that into a log file instead of the screen.
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%

Open in new window


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
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
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
minage needs a more recent date as maxage ...
Hi Qlemo,

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

/minage:20120524 /maxage:20120522
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.
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.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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%'

Open in new window


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
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 ...
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
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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 '+=' 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 }
  
  #>

Open in new window

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 }
  
  #>

Open in new window

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
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.
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
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!
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.