Check if file was modified after xx days in the past - date

I am checking for the date modified in a file. I would like to test whether the file was modified after the /d -3. According to the docs, this will check if the file was modified before that date. I need to check if the file was modified after that date. The docs also state that I can specify a date. I might end up doing it this way though it would be a little more complicated to generate a date to check against which I would prefer to avoid if possible.
How might I go about this?
forfiles /m Item_Lookup2.csv /d -3 >nul 2>nul && (
echo - updated
goto :PROCESS_FILE
) || (
echo - out of date
set outdated="true"
goto :CHECK_ERRORS
)
I found this in this answer

You're on the right track, but forfiles /d -n tests for files modified n days or earlier, not later. What you need to do is reverse your && and || code blocks, and maybe specify 4 days instead of 3.
If match, then it's 4 days old or older, and classified as out of date. If no match, it's been updated in the past 3 days.
Try this:
forfiles /d -4 /m "Item_Lookup2.csv" >NUL 2>NUL && (
echo - out of date
set outdated="true"
goto :CHECK_ERRORS
) || (
echo - updated
goto :PROCESS_FILE
)
Bonus tip: If you'd like to do some testing, you can manipulate the last modified timestamp of a file manually using a PowerShell command:
powershell "(gi Item_Lookup2.csv).LastWriteTime='6/1/2015 09:30:00 AM'"
... will set the last modified timestamp of Item_Lookup2.csv to June 1 at 9:30 AM. Salt to taste.

I really like rojo's answer - so simple. I find it interesting that it ignores the time component when computing the age. So an actual age of 1 second could be computed as one day if the current time is midnight and the last modified time stamp is 23:59:59 from the day before. This may or may not be the behavior you want.
I have a different solution based on ROBOCOPY that uses the full time stamp when computing the file age. So if you specify a max age of 3 days, then it looks for files that have been created or modified within the last 72 hours.
One nice thing about ROBOCOPY is it allows you to specify the minimum age, and/or the maximum age.
The returned ERRORLEVEL is complicated, making it inconvenient to interpret. Instead of using the ERRORLEVEL, I check to see if the command listed the file in question. I use a FOR /F loop that raises an error if no file is listed. The BREAK command is simply a command that always succeeds and produces no output if a file was listed.
There are lots of ROBOCOPY options, many of which are needed for this application :-)
(for /f %%A in (
'robocopy . "%temp%" "Item_Lookup2.csv" /maxage:3 /is /it /xx /l /ndl /njh /njs'
) do break) && (
echo - updated
goto :PROCESS_FILE
) || (
echo - out of date
set outdated="true"
goto :CHECK_ERRORS
)

Filtering files by different times is not so easy with pure batch so I've tried to create a tool for common usage - FileTimeFilterJS.bat (probably far from perfect) .Try with:
call FileTimeFilterJS.bat "." -filetime modified -direction after -dd -3

forfiles /D +n apparently looks for files with timestamps in the future. Alternatively, use this Powershell script to start with:
## usage: ff.ps1 [-age n] [-mask *.*]
## find files newer than n days
## with filenames matching mask
Param (
[float]$age = 0,
[string]$mask = '*.*'
)
$from = $(get-date).addDays(-$age)
GCI -path '.' -filter $mask -recurse -force | Where {$_.attributes -ne "Directory"-and $_.lastwritetime -gt $from } | ForEach { write-host $_.lastwritetime ' ' $_.fullname }
It's pretty simple, you can specify the maximum age (-age n) and/or the filemask (-mask *.csv). Output is timestamp + full filename which can easily be modified. Look at the date calculation and compare it to the nightmare needed with DOS batch.

Related

Deal with Date Time in PowerShell

I've written a pretty nifty PowerShell script that works with VMware PowerCLI to clone a couple of VMs off to a second storage device and then automatically delete them when they reach a certain age. It seems to work great until it gets to the end/beginning of the month, then the approach I used for date time seems to fail and all clones are deleted unexpectedly. Rather than include the entire script, here are the pieces that matter.
First, when the clones are created I am using the following code..
$vmdatestamp = (Get-Date).tostring('yyyyMMdd-HHmmss')
new-vm -Name $VM-$vmdatestamp -VM $VM -Datastore $CPFlag -vmhost host.domain.local -Location 'Regular Clone'
This variable ends up creating a VM clone that is named something like "VMName-20200214-040022" in the case that the date is Feb 14th, 2020 and the variable captured 4 AM and 00 Min and 22 seconds.
Then later on in the script there is a cleanup section that lists these cloned VMs and checks the date. The objective is to run a delete command if the clone is older than 3 days. So there is a foreach loop that runs off of all VMs found within a particular folder, "Regular Clone". $vmls is the var within the loop for each VM found. Here is the code I am using to check the dates and delete older than 3 days.
#Grab matched string and doctor it to only look at 8 digit date.
$var1 = $vmls.name
$var2 = $var1 -split '-' | Select-String '\d{8}'
$var3 = $var2 -replace '(?S)'
#Grab todays date in the same 8 digit format then subtract to compare variance. How old is the clone?
$CompareDate = (Get-Date).tostring('yyyyMMdd')
$var4 = $CompareDate - $var3
#If clone is older than 3 days, delete it. Turn this knob based on your requirements.
if($var4 -gt '3') {
So this last "if" statement that checks $var4 is greater than 3 is where the source of my problem is. I don't think the script is smart enough to figure out if for example today is the 1st, how minus '-' works. Anyone have a suggestion on how to better deal with this?
Regards,
Adam Tyler
Powershell has a great deal of flexibility in dealing with dates and times using the [datetime] type. There is probably another answer to this somewhere out there, and I'll search for it later, but here are some basics.
When you read in your filenames, which I am assuming are in 'VMName-yyyyMMdd-HHmmss' format, you can turn that into a PowerShell [datetime] object like so (Thanks to this post for the info on [datetime]::parseexact):
[string]$VMFileName = #load $VMFileName variable with the name of your VM file somehow
$VMFNSplit = $VMFileName -split '-'
$FileDateStamp = [datetime]::ParseExact("$($VMFNSplit[-2])-$($VMFNSplit[-1])",'yyyyMMdd-HHmmss',$null)
EDIT:
Tested the above, and got this:
PS> $VMFileName = 'VMName-20200222-043322'
PS> $VMFNSplit = $VMFileName -split '-'
PS> $VMFNSplit[-2]
20200222
PS> $VMFNSplit[-1]
043322
PS> "$($VMFNSplit[-2])-$($VMFNSplit[-1])"
20200222-043322
PS> $FileDateStamp = [datetime]::ParseExact("$($VMFNSplit[-2])-$($VMFNSplit[-1])",'yyyyMMdd-HHmmss',$null)
PS> $FileDateStamp
Saturday, February 22, 2020 4:33:22 AM
Once you have your file date/time stamp in a [datetime], you can use the built in methods to add/subtract your intervals, like this:
#If clone is older than 3 days, delete it. Turn this knob based on your requirements.
$TooOld = (Get-Date).AddDays(-3)
If ($FileDateStamp -lt $TooOld) {#Delete it}
Hope this helps!

What is wrong with my input for the forfiles -d value?

Whenever I enter:
forfiles /d +10/20/2019 /c "cmd /c echo #FILE last 5 days"
I get an error saying the time setting is wrong. When I change it to something like -50 or -100 it works as its supposed to showing the proper files for those sets of time. I seem to be following the format of mm/dd/year...? I don't know what is wrong. I wanted to list all files that were made within the last 5 or so days. So I basically can't get the longhand date system working.
If I move the /d to after the cmd value does the " move to the end as well like..
forfiles /c "cmd /c echo #FILE last 5 days /d +10/20/2019"
?
forfiles is an executable mainly used with cmd.
The problem is in date format. As per forfiles /? help, follow "dd.MM.yyyy" format. This might be system locale dependent, so check your installation's help; mine says:
/D date Selects files with a last modified date greater
than or equal to (+), or less than or equal to
(-), the specified date using the
"dd.MM.yyyy" format; or selects files with a
last modified date greater than or equal to (+)
the current date plus "dd" days, or less than or
equal to (-) the current date minus "dd" days. A
valid "dd" number of days can be any number in
the range of 0 - 32768.
"+" is taken as default sign if not specified.
As for a Powershell solution, use Get-ChildItem and filter based on CreationDate, like so
Get-ChildItem c:\temp | ? {$_.CreationTime -ge (Get-Date).AddDays(-5)}
This will get a directory listing and select files that have creation time greater or equal to a date five days ago.
/d 2019-10-24
Works.
/20charactersmoreplzserialdownvotingisbannableoffensemrguyfrommetathread.Ididn'tknowiwasworthit,ty.

How to change order of files listed by dir cmd

Currently upon using the dir command dir /b *.*dot my files are listed in the following random order.
C.dot
D.dot
B.dot
A.dot
What should be done so that the same command dir /b *.*dot returns an ordered list, i.e.
A.dot
B.dot
C.dot
D.dot
I was initially thinking about a touch like command and I have tried copy /b A.dot+ trying to update timestamp but it did not work.
Please suggest which command can be used in windows / powershell to achieve this.
If you're trying to sort by alphabetical order of the file name, use Sort-Object. So something like Get-ChildItem -Path . -Filter "*.*dot" | Sort-Object -Property Name. Or, if you insist on not using Get-ChildItem, you could do dir /b *.*dot | Sort-Object.
you mentioned touch, if you need the timestamp updated you can set the LastWriteTime
(Get-ChildItem a.dot).LastWriteTime = get-date
there might be a better way to do what you are trying to do lastwritetime is limited to minutes so you can only update one file per minute
i am just unsure how you would GCI into a random order...? dir (the same thing as get-ChildItem) is going to order by name unless you sort by something else.

Exact date & time in subprogram with powershell

I'm new to powershell and I try to solve a problem I already managed to solve with batch scripting. I know how to set a variable and how to get the date with powershell. But I made a special subprogram for the exact date and time in batch and I don't know how to do that in powershell. Also I'm asking myself if there's an equivalent for %~dpn0 in powershell?
This are the parts of my batch script I want to use in powershell:
set pgm=%~n0
set log=%~dpn0.log
set csv=%~dpn0.csv
set dir=%~dp0users
set txt=%~n0.txt
set fix=%~dpn0.fix
call :loggy I "Program %pgm% started..."
:loggy
set welcomesev=%1
set welcometxt=%~2
set welcomeJJJJ=%date:~6,4%
set welcomeMM=%date:~3,2%
set welcomeDD=%date:~0,2%
set welcomeHR=%time:~0,2%
set welcomeMIN=%time:~3,2%
set welcomeSEC=%time:~6,2%
set welcomeDT=%welcomeJJJJ%.%welcomeMM%.%welcomeDD% %welcomeHR%:%welcomeMIN%:%welcomeSEC%
echo %welcomeDT% [%welcomesev%] %welcometxt% 1>>%log%
goto :EOF
Sorry for the many questions but I couldn't find anything with the search function.
Greetings
Does this function help you?
function Extract-CurrentDate{
$date = (Get-Date -Format d).ToString()
$time = (Get-Date -Format t).ToString()
Write-Host "$date $time"
}
Extract-CurrentDate
In generell you can use the Cmdlet Get-Date for you issue. It has many options, see this article. Moreover, you can format your output like this.

Translate batch script to Powershell script

I currently have this script I run as a scheduled task:
#echo on
START /WAIT c:\windows\system32\Robocopy.exe "D:\folder" "\\192.168.2.87\folder" /E /MT:20 /R:50 /W:10 /V /ETA /LOG:c:\robocopy.txt
I want to convert and run this as a PowerShell script because of two reasons:
Its more modern
The most important reason is that I want to store the log with date and time as C:\robocopylog3004201510214043.txt and I am literally finding no information on how to strip characters like ":" and "/" from a batch script and I know PowerShell can.
That last number is not random. It is the date and time.
Date for example is "30/04/2015" (striping it would leave 30042015)
Time for example is "10:21:40,43" (striping it would leave 10214043)
So it would leave a file name of robocopylog3004201510214043.txt
There is little difference between CMD and PowerShell when it comes to running external programs. I'd recommend using the call operator (&), though, even if it isn't mandatory in this particular case.
& c:\windows\system32\Robocopy.exe "D:\folder" "\\192.168.2.87\folder" /E /MT:20 /R:50 /W:10 /V /ETA /LOG:c:\robocopy$(Get-Date -format 'ddMMyyyyHHmmss').txt
robocopy runs synchronously anyway, so no "wait" instruction required.
The number format ddMMyyyyHHmmss produces a timestamp consisting of day, month, year, hour, minutes and seconds. I wouldn't recommend to include milliseconds as well, because you probably won't run robocopy several times within the same second. If you must include milliseconds, append ff to the format string (or f, fff, etc., depending on the number of digits you need). You may want to consider using an ISO date format (yyyyMMddHHmmss), though, because that simplifies listing the log files in creation order.
As for replacing characters in batch scripts, that can be done via string replacements:
C:\>echo %DATE:/=%
30042015
C:\>echo %TIME::=_%
10_01_22.39