Compare date from string with current date - powershell

I am have string which contain date and I want to compare that all last 15 days date with the date in string.
I have stored all 15 days date in array and comparing with the date in string.
#last 15 days date.
$Q = #()
$Q = for ($i=15; $i -gt 1; $i--) {
$date=Get-Date -DisplayHint Date #-Format "dd MMM yyyy"
$final=$date.AddDays(-$i)
$final.tostring("dd MMM yyyy")
}
# $array.'Description' have string like this "Enabled AD ID as per Call id: 509112 29 Oct 2019"
#comparing
if($array.'Description' -notcontains $Q){
Write-host ("true")
}else
{
write-host ("false")
}
I want comparing result.

You can split $array.'Description', then join the last three elements and then compare it with $Q.
($($array.'Description').Split(" ") | Select-Object -Last 3) -join " "
The comparison would look something like:
if ((($($array.'Description').Split(" ") | Select-Object -Last 3) -join " ") -notcontains $Q){
Write-host ("true")
}else
{
write-host ("false")
}

I think you should always compare dates to dates, not their string representation unless it is in Sortable format.
Below code takes the date string from the Description attribute and converts it to a local DateTime object to compare against:
$refDate = (Get-Date).AddDays(-15).Date # midnight 15 days ago
$array | ForEach-Object {
# parse a date object from the Description string
$dateString = ([regex]'(\d{1,2} \w{3} \d{4})$').Match($_.Description).Groups[1].Value
$date = [datetime]::ParseExact($dateString, 'd MMM yyyy', [cultureinfo]"en-US")
# make it a Local date
$date = [datetime]::SpecifyKind($date, 'Local')
if ($date -gt $refDate) {
# the description date is inside the last 15 days
Write-Host "True"
}
else { Write-Host "False" }
}
Edit
As per Esperanto57's comment, in case the Description string does not contain a date to parse, below uses a try{..} catch{..} block to tackle that:
$array | ForEach-Object {
try {
# parse a date object from the Description string
$dateString = ([regex]'(\d{1,2} \w{3} \d{4})$').Match($_.Description).Groups[1].Value
$date = [datetime]::ParseExact($dateString, 'd MMM yyyy', [cultureinfo]"en-US")
# make it a Local date
$date = [datetime]::SpecifyKind($date, 'Local')
if ($date -gt $refDate) {
# the description date is inside the last 15 days
Write-Host "True"
}
else { Write-Host "False" }
}
catch {
Write-Host "False. (The Description attribute does not contain a date.)"
}
}

Related

How to do time "HH:mm" comparison in Powershell?

Apparently my code is like this and it is now working. I think the logic is already there. the $openTime and $closeTime is read from csv using import-csv in "HH:mm" form.
$openTime = $ip.openTime
$closeTime = $ip.closeTime
$time = Get-Date -UFormat "%R"
if (($time -ge $openTime) -and ($time -le $closeTime)) {
Write-Host "Store is Open!" -ForegroundColor Green
}else{
Write-Host "Store is outside open hours!" -ForegroundColor Red
}
powershell 7
$csv = #"
store, openTime, closeTime
Wallmart, 08:00, 18:00
Ikea, 10:00, 20:30
"# | ConvertFrom-Csv
Get-Date
$csv | ForEach-Object{
[int]([datetime]::Now - [datetime]::Today).TotalMinutes -in (.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.openTime.split(":"))..(.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.closeTime.split(":")) ? "Store {0} is Open! " -f $_.store : "Store {0} is outside open hours!" -f $_.store
}
16 февраля 2021 г. 8:52:42
Store Wallmart is Open!
Store Ikea is outside open hours!
powershell 5
$csv = #"
store, openTime, closeTime
Wallmart, 08:00, 18:00
Ikea, 10:00, 20:30
"# | ConvertFrom-Csv
Get-Date
$csv | ForEach-Object{
("Store {0} is outside open hours!", "Store {0} is Open! ")[[int]([datetime]::Now - [datetime]::Today).TotalMinutes -in (.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.openTime.split(":"))..(.{[int]$args[0][0]*60 + [int]$args[0][1]} $_.closeTime.split(":"))] -f $_.store
}
Try it online!
I find it's much easier to work with date and times if I convert them to [DateTime] objects. We can use the DateTime class method ParseExact to convert the time into [DateTime] objects for us. This object will actually contain today's date as well as the time we supply, but for our purposes this is fine since the $time object also will be today's date. For the current time ($time) just let Get-Date return to us a [DateTime] object that will represent the current date and time (now). After that the rest of your code works as expected. Hurray!
# this $ip hashtable object just represents data similar to your csv import
$ip = #{
openTime = "09:00"
closeTime = "21:00"
}
$openTime = [datetime]::ParseExact($ip.openTime, 'HH:mm', $null)
$closeTime = [datetime]::ParseExact($ip.closeTime, 'HH:mm', $null)
$time = Get-Date
if (($time -ge $openTime) -and ($time -le $closeTime)) {
Write-Host "Store is Open!" -ForegroundColor Green
}
else {
Write-Host "Store is outside open hours!" -ForegroundColor Red
}
If you are working with the time are imported from csv, make sure the time format in the csv file is in "HH:mm"

datetime comparison letting thread proceed when shouldn't

I have a backup script that puts files in a dated directory every night. I have another script, below, that goes through a list of dated directories and if it's within the range I want to delete, I will delete the directory, keeping the Saturday dated file. For some reason, for the dir dated Saturday, 1/12/2019, it's being deleted, even though the if statement should indicate it wouldn't be deleted.
This is my code:
function WeeklyCleanup($folderWeeklyCleanupDatedSubdirs) {
#find out date range to cleanup
$lastSaturday = GetLastSaturdayDate
$lastSaturday = [datetime]$lastSaturday
$weekAgoSunday = GetWeekAgoSundayDate
$weekAgoSunday = [datetime]$weekAgoSunday
#find out filename with Saturday date before current date but within week
Get-ChildItem $folderWeeklyCleanupDatedSubdirs | ForEach-Object {
write-output $_
#check to see if item is before day we want to remove
$temp = $_
$regex = [regex]::Matches($temp,'([0-9]+)-([0-9]+)-([0-9]+)')
if($regex.length -gt 0) #it matched
{
$year = $regex[0].Groups[1].Value
$month = $regex[0].Groups[2].Value
$day = $regex[0].Groups[3].Value
write-output $year
write-output $month
write-output $day
write-output "*************"
$dirDate = $regex[0].Groups[0].Value + " 12:00:00 PM"
write-output $dirDate
if($dirDate.length -gt 0) #it matched
{
$dateTimeObjectFromRegex = [datetime]$dirDate
##########this next statement is letting $dateTimeObjectFromRegex of 1/12/2019 through when it shouldn't. See time comparison below
if(([datetime]$dateTimeObjectFromRegex -lt [datetime]$lastSaturday) -and ([datetime]$dateTimeObjectFromRegex -ge [datetime]$weekAgoSunday)) #we're removing extra ones over last week, keep Saturday
{
$dirPathToRemove = Join-Path -path $folderWeeklyCleanupDatedSubdirs -ChildPath $temp.ToString()
Get-ChildItem -Path $dirPathToRemove #list the dir
#remove dir
if(-Not (Test-Path $dirPathToRemove )) #-PathType Container
{
$global:ErrorStrings.Add("Exception: No such path, $dirPathToRemove;; ")
write-output "++ Error: An error occured during copy operation. No such path, $dirPathToList ++"
}
else
{
#remove dir and subdirs
Remove-Item $dirPathToRemove -Force -Recurse
Get-ChildItem -Path $dirPathToRemove #list the dir
}
#Write-Output $_
#Write-Output " 1 "
} #if within last week
} #if dirDate length
} #if regex matched
} #get-childItem
}
function GetLastSaturdayDate()
{
$date = Get-Date #"$((Get-Date).ToString('yyyy-MM-dd'))"
#for($i=1; $i -le 7; $i++){
# if($date.AddDays(-$i).DayOfWeek -eq 'Saturday') #if found Saturday
# {
# $date.AddDays(-$i)
# $newDate = $date.AddDays(-$i)
# break
# }
#}
$newdate = $date.AddDays(-($date.DayOfWeek+1)%7)
return $newdate
}
function GetWeekAgoSundayDate()
{
$numberOfWeeks = 1; #week ago
$date = Get-Date #"$((Get-Date).ToString('yyyy-MM-dd'))"
#for($i=1; $i -le 7; $i++){
# if(($date.AddDays(-$i).DayOfWeek -eq 'Sunday') -and ($date.AddDays(-$i) -ne $date)) #if found a Sunday and it's not today
# {
# $date.AddDays(-$i)
# $newDate = $date.AddDays(-$i)
# break
# }
#}
#$newdate = $date.AddDays(-($date.DayOfWeek+1)%0)
$numDaysSincePreviousDate = $date.DayOfWeek.value__ + 0 #0 is Sunday
([System.DateTime] $previousDayOfWeek = $date.AddDays(- $numDaysSincePreviousDate)) | Out-Null
$previousDate = $previousDayOfWeek.AddDays(-($numberOfWeeks *7)).ToString("MM-dd-yyyy")
return $previousDate
}
The WeeklyCleanup script is called with this parameter:
$folderToCleanupDatedSubdirs = [System.IO.DirectoryInfo]"E:\Bak_TestDatedFolderCleanup"
For time comparison:
Directory item toLocRobo_2019-01-12 - Once I get regex with timestamp, I add the time in of 12:00:00 PM for the $dirDate variable. This becomes $dateTimeObjectFromRegex. Debugger shows it as Saturday, January 12, 2019 12:00:00 PM
When I run the program, I get $lastSaturday as Saturday, January 12, 2019 3:59:04 PM
When I run the program, debugger also shows $weekAgoSunday as Sunday, January 6, 2019 12:00:00 AM
From what I can see, it shouldn't be getting through that if statement to delete the dir for 1/12/2019.
I tried casting the dates to datetime to make sure it wasn't doing a string comparison in the if statement, even though I casted it above.
I've been looking at these links for more info on this, but it looks correct to me:
dateTimeComparisons not working expectedly
convert string to datetime
All I can think is that it's still treating the datetime in the first part of the if statement comparison like a string, so it's thinking 3:59 PM is greater than 12:00 PM. Any ideas how to get this date check to work? I don't care about times, just want to make sure it doesn't get rid of the Saturday-dated file from this past week, but only cleanup other dir's over that week.
Update
Made changes suggested by #brianist below, and it worked great. This is what it looks like so far. Saturday and Sunday functions haven't changed. He's asking me to post it. If he has any other suggestions how to get it to treat/compare what's returned from the last Saturday and weekAgoSunday functions as dates, without the cast, that'd make it look less clunky/easier to read. Thanks Brian!
#do weekly cleanup of DisasterBackup folder
function WeeklyCleanup($folderWeeklyCleanupDatedSubdirs) {
#find out current date
$currentDate = "$((Get-Date).ToString('yyyy-MM-dd'))" #example 2019-01-15
$currentDayOfWeek = (get-date).DayOfWeek.value__ #returns int value for day of week
#find out current day of week
$lastSaturday = GetLastSaturdayDate
$lastSaturday = [datetime]$lastSaturday #if we take away extra casts it won't do comparison line (-lt and -ge)
$weekAgoSunday = GetWeekAgoSundayDate
$weekAgoSunday = [datetime]$weekAgoSunday #if we take away extra casts it won't do comparison line (-lt and -ge), and can't move cast before function call because it isn't recognizing function anymore if I do
#find out filename with Saturday date before current date but within week
#get each dir item to check if we need to remove it
Get-ChildItem $folderWeeklyCleanupDatedSubdirs | ForEach-Object {
write-output $_
#check to see if item is before day we want to remove
$temp = $_
if($_.Name -match '(\d{4}-\d{2}-\d{2})$'){ #regex
write-output $Matches[1]
$dirDate = Get-Date $Matches[1] #turn regex into date
if(([datetime]$dirDate.Date -lt [datetime]$lastSaturday.Date) -and ([datetime]$dirDate.Date -ge [datetime]$weekAgoSunday.Date)) #we're removing extra ones over last week, keep Saturday
{
$dirPathToRemove = Join-Path -path $folderWeeklyCleanupDatedSubdirs -ChildPath $temp.ToString()
Get-ChildItem -Path $dirPathToRemove #list the dir
#remove dir
if(-Not (Test-Path $dirPathToRemove )) #-PathType Container
{
$global:ErrorStrings.Add("Exception: No such path, $dirPathToRemove;; ")
write-output "++ Error: An error occured during copy operation. No such path, $dirPathToList ++"
}
else
{
#remove dir and subdirs
Remove-Item $dirPathToRemove -Force -Recurse
Get-ChildItem -Path $dirPathToRemove #list the dir
}
} #if within last week
} #if regex matched
} #get-childItem
}
Re-reading your last sentence, I now see that your intention is to ignore times, not to include them in your comparison.
You are right to want to use [DateTime] objects when comparing, but do note that those objects always include a time.
Conveniently you can use the .Date property of such an object which returns a new one, with the time set to midnight. This is useful for comparing because the time would no longer be a factor.
Pulling out my modified if statement from below, you can do it like this:
if ($dirDate.Date -lt $lastSaturday.Date -and $dirDate.Date -ge $weekAgoSunday.Date) {
# do stuff
}
Now you're only comparing dates, and ignoring time!
Based on what you're showing it looks like the if statement is working as expected. To summarize, you say that:
$dateTimeObjectFromRegex is Saturday, January 12, 2019 12:00:00 PM
$lastSaturday is Saturday, January 12, 2019 3:59:04 PM
$weekAgoSunday is Sunday, January 6, 2019 12:00:00 AM
The conditional is:
if(([datetime]$dateTimeObjectFromRegex -lt [datetime]$lastSaturday)
-and ([datetime]$dateTimeObjectFromRegex -ge [datetime]$weekAgoSunday))
Therefore in pseudo-code it's:
if (
("January 12, 2019 12:00:00 PM" is earlier than "January 12, 2019 3:59:04 PM") # true
and
("January 12, 2019 12:00:00 PM" is later or the same as "January 6, 2019 12:00:00 AM") # true
) # true
I do want to point out that you are doing an awful lot of unnecessary datetime chopping and casting, and cleaning that up would help with readability and with debugging these types of issues.
$lastSaturday = GetLastSaturdayDate
$lastSaturday = [datetime]$lastSaturday
$weekAgoSunday = GetWeekAgoSundayDate
$weekAgoSunday = [datetime]$weekAgoSunday
Your functions already return [DateTime] objects, so there's no need for those casts.
$temp = $_
$regex = [regex]::Matches($temp,'([0-9]+)-([0-9]+)-([0-9]+)')
if($regex.length -gt 0) #it matched
{
$year = $regex[0].Groups[1].Value
$month = $regex[0].Groups[2].Value
$day = $regex[0].Groups[3].Value
write-output $year
write-output $month
write-output $day
write-output "*************"
$dirDate = $regex[0].Groups[0].Value + " 12:00:00 PM"
write-output $dirDate
This is quite complex, you could simplify it down to something like this:
if ($_.Name -match '(\d{4}-\d{2}-\d{2})$') {
# in here, you know the match was successful
$dirDate = Get-Date $Matches[1] # double check this, might need .Groups or something
if ($dirDate -lt $lastSaturday -and $dirDate -ge $weekAgoSunday) {
# do stuff
}
}
Probably some more optimizations etc. Hope this was helpful!

How to compare the sysdate and the date stored in CSV file

I have a .csv file in which I have made a column where dates are given in a random manner. I want a script in which I want to compare the today date i.e., sysdate with the date present in CSV file.
And if today date matches with the date in CSV then it will Write-Output "true" else "false".
The date strings look like this:
3/10/2016
4/12/2016
3/09/2016
I've tried this:
$CheckDate = (Get-Date).Date
Import-Csv 'C:\Downloads\date.csv' | Select-Object -Property *, #{n='Date';e={ [DateTime]::ParseExact($_.'Date', 'MM-dd-yyyy') }} -Exclude 'Date' | ForEach-Object {
if ($_.'Date' -eq $CheckDate) {
write-Output "$true"
} else {
Write-output "$false"
}
}
and this:
$data = Get-item "C:\Downloads\date.csv"
$a = Get-Date -Format d
if($a = $data) {
write-output "Its working!!"
} else {
write-output "Its not working!!"
}
You say that the dates in the csv file look like:
3/10/2016
4/12/2016
3/09/2016
But in your example, you attempt to parse the date using the format string MM-dd-yyyy - ie. expecting a month with leading zeros and - as the separator.
The correct date format for the samples you describe would be %M/dd/yyyy:
PS C:\> [datetime]::ParseExact('3/10/2016','%M/dd/yyyy',$null)
Thursday, March 10, 2016 12:00:00 AM

Powershell compare months and exclude which are not required

I have a text file as shown below. I need to preserve the files which are within 6 months old (from the previous month) and write every other content to other file which are more than 6 months old.
What I've done so far is like:
$array3 =
do {
foreach($monthl in $monthlookup)
{
$mnthl = $monthl -split '-'
$m_day = $mnthl[1]
$m_month = $mnthl[2]
$m_year = $mnthl[3]
$m_temp = 0
$prevmonth = (Get-Date).AddMonths(-1).ToString("dd-MM-yy")
while(($m_temp -eq "0"))
{
if(($m_month -ge $startmonth) -and ($m_month -le $prevmonth))
{
$monthl | Add-Content "C:\each_month_latest.txt"
break;
}else
{
$monthl | Add-Content "C:\exclusions.txt"
}
}
}
} until ($m_month -ge $m)
What the issue I identified here is like: If the current month is 1, then it wont go back to the last 6 months and check, as I use just strings here.
Any suggestions or code improvements, anyone of you can think of..? Would be really appreciated.
Edit
monthlookup will look like:
testdatabase-30-11-14-23-00
testdatabase-31-12-14-23-00
testdatabase-30-01-15-23-00
testdatabase-31-01-15-23-00
testdatabase-27-05-15-23-00
testdatabase-28-02-15-23-00
testdatabase-31-03-15-23-00
testdatabase-30-04-15-23-00
testdatabase-31-05-15-23-00
$m is $m = Get-Date -Format "MM"
Well, I don't completly understand what you want to do but here some tipps:
$prevmonth = (Get-Date).AddMonths(-1).ToString("dd-MM-yy") shouldn't be done each time within the foreach loop
You could extract the date using a simple regex: [regex]::Match('testdatabase-30-11-14-23-00', '^.*?-(\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$)').Groups[1].Value
Parse the date using [datetime]::ParseExact and a format string
So it could look like this:
# this doesn't have to be done each time in the foreach loop
$sixMonthBefore = (Get-Date).AddMonths(-6)
foreach($monthl in $monthlookup)
{
# extract the date
$dateString = [regex]::Match($monthl, '^.*?-(\d{2}-\d{2}-\d{2}-\d{2}-\d{2}$)').Groups[1].Value
# create a datetime using format string
$date = [datetime]::ParseExact($dateString, 'dd-MM-yy-HH-mm', $null)
if ($date.Month -eq (Get-Date).Month -and $date.Year -eq (Get-Date).Year)
{
Write-Host "$monthl is from this month"
}
elseif ($date -gt $sixMonthBefore)
{
$monthl | Add-Content "C:\each_month_latest.txt"
}
else
{
$monthl | Add-Content "C:\exclusions.txt"
}
}

remove last 14 digits from string, if there are digits

I have a textfile where I store my testname. The testname sometimes has a date afterwards consisting of a 14 digit timestamp. The testname can be:
data-c(festo1-small1);divider-bin-1.4.4;divider-conf-1.3.3-w(1,16);storage-bin-1.5.4;storage-conf-1.5.0-w(1);worker-bin-4.5.1;worker-conf-4.4.1-c(festo1)-win1
or
data-c(festo1-small1);divider-bin-1.4.4;divider-conf-1.3.3-w(1,16);storage-bin-1.5.4;storage-conf-1.5.0-w(1);worker-bin-4.5.1;worker-conf-4.4.1-c(festo1)-win1_20130620123306
I want to reuse this file/testname. I need to strip off the timestamp, if there is already one, and add the current timestamp. This is what I got so far:
#rescue testname for another run
$testname = Get-Content "output\testname"
Write-Host Old: $testname
#strip date from testname
$testname = $testname.Substring(0,$string.Length - 14)
$olddate = $testname.Substring($string.Length - 14)
Write-Host OldDate: $olddate
#add new Date
$startTime = Get-Date -format yyyyMMddHHmmss
$testname += "_"
$testname += $startTime
Write-Host New: $testname
How do I check if there is a timestamp/if the last 14 characters are digits? How do I cut the testname from the string?
this?
$filename = "data-c(festo1-small1);divider-bin-1.4.4;divider-conf-1.3.3-w(1,16);storage-bin-1.5.4;storage-conf-1.5.0-w(1);worker-bin-4.5.1;worker-conf-4.4.1-c(festo1)-win1_20130620123306"
$filename -replace '\d{14}$'