Using Time in a conditional Statement in Powershell - powershell

I'm trying to just get the groundwork for running some code with a time conditional. But I can't seem to grasp how to add time into the equation. Any Powershell people out there?
The $EndDate doesnt matter anymore. I just tried to use it as a way to understand how powershell uses conditional
$StartTime=(Get-Date)
$EndDate=[datetime]”00:00”
if ($StartDate -gt "00:00" -and $StartTime -lt "11:59")
{
Write-Host "It is time to work"
}
else
{
Write-Host "it is time to go"
}
$StartTime
My code right now should say its time to go but should say its time to work because as of right now its only 11:56 AM ET.

If you want to compare against the time of day, use the TimeOfDay TimeSpan exposed by [datetime] - PowerShell will automatically convert the right-hand "HH:mm" string into a meaningful TimeSpan that can be compared against:
$StartTime = Get-Date
if($StartTime.TimeOfDay -gt "00:00" -and $StartTime.TimeOfDay -le "12:00"){
# AM
}
else{
# PM
}

These two things are usually true.
(get-date) -gt '00:00'
True
(get-date) -lt '23:59'
True
Check for unset variables:
set-strictmode -v 1

Related

Write-Progress not rendering at all when called in a loop

The script I'm working on is a ticket reserving bot for student events, it waits in the specified loop until sales start, and the write-progress is supposed to let you know when they do start. I'm fairly new to PowerShell and I'm sorry if the code is a sore for the eyes. I'm just baffled since this part did work earlier today, even though nothing about the loop changed iirc.
Here is the relevant part of the script:
While ($currentDate -lt $purchaseTime){
$currentDate = Get-Date
$waitTime = (New-TimeSpan -End $purchaseTime).TotalSeconds
Write-Progress -Activity "Waiting until sales start" -SecondsRemaining $waitTime
Start-Sleep -Milliseconds 10
If ($currentDate -ge $purchaseTime){continue}
}
I also tried this:
Do {
$currentDate = Get-Date
$waitTime = (New-TimeSpan -End $purchaseTime).TotalSeconds
Write-Progress -Activity "Waiting until sales start" -SecondsRemaining $waitTime
Start-Sleep -Milliseconds 201
} until ($currentDate -gt $purchaseTime)
I tried changing the loop from While to Do and even If statements but nothing changed. Can anyone solve this? I'm not getting any errors either, it just won't render.
EDIT 1
This is how the value is fetched, $jsonObject is made out of a GET request, and below is its value.
$purchaseTime = $jsonObject.model.product.dateSalesFrom
"2022-11-25T11:00:00+02:00"
The format shouldn't be the issue, since they've been the same throughout the process of me writing this script. And it used to with that formatting too.
I tried inserting the code suggested by Mathias before that declaration, but it didn't change the end result.
Did he mean I should insert it within the loop? Would that screw it up since I really need it to be this static place in time in order for the script to work as intended. My PSVersion is 5.1. Should I post the entire script for clarity?
EDIT 2.
I have implemented the code that Santiago suggested as the answer, but nothing has changed. The progress still won't render. Could the issue be with how the date from the jsonobject is formatted? The code Santiago posted runs and works on its own in a powershell instance, so I doubt my settings or anything like that is not working as intended.
Here is what the loop currently looks like:
$nowDate = Get-Date
$targetDate = Get-Date $jsonObject.model.product.dateSalesFrom
$timeSpan = $targetDate - $nowDate
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew()
Do {
$progess = #{
Activity = 'Waiting until sales start'
SecondsRemaining = ($timeSpan - $stopWatch.Elapsed).TotalSeconds
}
Write-Progress #progess
Start-Sleep -Milliseconds 200
}
until($stopWatch.Elapsed -ge $timeSpan)
Proof of concept
This example shows how you can achieve your your do loop (I prefer to use do in this case, though it could be done with a while loop too) for exactly 1 minute displaying a progressive countdown. I believe a StopWatch shines for this use case, and it simplifies the code a lot.
$nowDate = Get-Date
$targetDate = $nowDate.AddMinutes(1)
$timeSpan = $targetDate - $nowDate
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew()
do {
$progess = #{
Activity = 'Waiting until sales start'
SecondsRemaining = ($timeSpan - $stopWatch.Elapsed).TotalSeconds
}
Write-Progress #progess
Start-Sleep -Milliseconds 200
}
until($stopWatch.Elapsed -ge $timeSpan)
Using this same logic, you would only need to change the following:
$nowDate = Get-Date
$targetDate = Get-Date $jsonObject.model.product.dateSalesFrom
This would make your loop run until Friday, November 25, 2022 6:00:00 AM.
I have solved the issue.
The problem lies within the $progressPreference variable. I had set it to silentlyContinue to help with WebRequests being smoother, but unbeknownst to me it also affected the Write-Progress cmdlet. It works fine now.

Testing if now if between two times that span midnight

I've tried searching for this, but I'm at a loss... I can find answers for other languages, but not for PowerShell.
Basically, I want to test if the time now is between 21:15 and 5:45.
I'm pretty sure I need to use New-TimeSpan - but, for the life of me, I just can't work it out.
I'd share my test code, but I think I'm so far away from the answer that it wouldn't be of any help.
Can anyone help me?
Use Get-Date to create DateTime objects describing those thresholds as points in time on todays date, then test if the time right now is before the early one or after the late one:
$now = Get-Date
$morning = Get-Date -Date $now -Hour 5 -Minute 45
$evening = Get-Date -Date $now -Hour 21 -Minute 15
$isWithinRange = $now -le $morning -or $now -ge $evening
If this is purely about the time of day and you don't need any date calculations, you can do the following, relying on the fact that for padded number strings lexical sorting equals numeric sorting:
# Get the current point in time's time of day in 24-hour ('HH') format.
# Same as: [datetime]::Now.ToString('HH\:mm')
$timeNow = Get-Date -Format 'HH\:mm'
$timeNow -ge '21:15' -or $timeNow -le '05:45'
If you'd have to check if you are in the range 23:00-04:00, crossing the midnight, you could:
$now=(Get-Date).TimeofDay
if ($now.TotalHours -ge 23 -or $now.TotalHours -lt 04)
{"In Range"}
else
{"Out of range"}

Infinite loop in comparing Time Powershell

I've been trying to create code in PowerShell that's gonna run if the time is below a specific time but upon experimenting it always gets stuck in an infinite loop executing even when the condition is already not satisfied
here's my code:
$a = Get-Date
Write-Host $a
[datetime]$time = "05/12/2016 1:57:00 AM"
DO
{
if($a -gt $time) {break}
Write-Host "not yet time"
if($a -gt $time) {break}
}while( $a -le $time)
CLS
Write-Host "done"
But it still is running even at 1:59 AM already. Any ideas on how to properly compare time? I want it to run till a specific time or I want it to run at least 2 hours.
Since you only assign the output from Get-Date to $a once, it's never updated, and you're performing the exact same comparison (times 3) every time the loop runs.
Call Get-Date in the loop body or conditional to get the updated time:
[datetime]$time = "05/12/2016 1:57:00 AM"
do {
Write-Host "not yet time"
}while($(Get-Date) -le $time)
cls
Write-Host "done"

Use Get-Date "time" in an "if" statement PowerShell

$WshShell = New-Object -ComObject wscript.shell
$Time = (Get-Date).hour
$Time2 = Get-Date -DisplayHint Time
$Message ="Test for $Env:username at: " + $Time2
$fail = "ERROR:It is $Time2, which is past 12PM"
$PopUp = $WshShell.popup("$Message",0,"Task Scheduler Pop-up",1)
if ($Time2 > 12)
{
$PopUp = $wshShell.popup("$Message",0,"Task Scheduler Pop-up",1)
}
else {
$PopUp = $wshShell.popup("$fail",2,"Task Scheduler Pop-up",1)
}
Hi guys, I'm practicing a little bit of my PowerShell and have run across something I'm not quite sure how to Google for, or what method I need to use to get this to work correctly.
What I'm attempting to accomplish is have my box display only, the hour and minute like "12:31".
As you can see in the script I'm calling the
Hour, but I can't quite figure out how to have it display the time by itself the right way. I'm using the "Time" operator, but when you compare that in the "IF" statement, it doesn't recognize it as something it can compare itself to since it's not a real integer. I understand why, but I would like to be able to compare the .Hour to $Time2
I'm new to this and appreciate any help you can provide!
Thank you!
Don't think in terms of output strings before you actually need to.
> won't work for comparisons, you need to use -lt (less than) and -gt (greater than)
If you want to compare the time of two DateTime objects (regardless of the date), you can compare the TimeOfDay property:
$DateTimeNow = Get-Date
$DateTimeEarly = Get-Date -Hour 1 -Minute 5
if($DateTimeNow.TimeOfDay -lt $DateTimeEarly.TimeOfDay){
"It is very early right now!"
} else {
"It is at least past 01:05"
}
If you want to show the time in output, you have multiple options for formatting a DateTime string:
You can use the ToString() method with a formatting string:
PS C:\> (Get-Date).ToString('HH:mm')
20:41
The format operator -f:
PS C:\> '{0:HH:mm}' -f (Get-Date)
20:41
Or have Get-Date return a formatted string itself:
PS C:\> Get-Date -Format 'HH:mm'
20:41
If you want 12-hour style time, use hh:mm
If you need to display the time you could use one of several methods. Those would all convert the result to string. I think you need to save $time2 as just a [datetime] object. That way you can format it for display and use .Hour for comparison logic.
$Time2 = Get-Date
$Message ="Test for $Env:username at: " + $Time2.ToString("HH:mm")
$PopUp = $WshShell.popup("$Message",0,"Task Scheduler Pop-up",1)
if ($Time2.Hour -gt 12){
#Do Stuff
}
This logic would only work for 24hr time though. 1(pm) is less than 12 but later in the day. Which is what HH:mm represents.

Check timespan which may cross day boundary

I have a monitoring script which is executed every 5 minutes by task scheduler. If the script determines there is a problem, an alert condition is raised and a notification email is sent. The script then terminates. All well and good.
I want to define some 'quiet hours' during which time, monitoring still takes place on schedule, but notifications are suppressed. These hours will cross the midnight boundary.
I could do this with something like this:
$quietHoursStart = "22:00"
$quietHoursEnd = "06:00"
$timeNow = Get-Date
if ( $timeNow -lt (Get-Date $quietHoursStart ) -and
$timeNow -gt (Get-Date $quietHoursEnd ) ) {
Send-NotificationEmail
}
That's fine, but if I ever re-define the quiet hours range so that it does not cross the midnight boundary (e.g. 00:00 -> 06:00) , then the notification will always fail since the if condition can never be true.
If could add additional tests to see if the range crosses midnight, then have two separate checks to see if current time is 'quiet', but I feel there should be a more elegant solution.
The values for the quiet hours start/end are actually pulled in from an XML config file but for the sake of clarity, the example above uses simple definitions.
EDIT: To clarify; the script must run every 5 minutes, regardless of quiet hours, since it records a log of problems found. Changing the schedule will not achieve this.
Add comparison between $quietHoursStart and $quietHoursEnd to check is given interval cross midnight or not.
$quietHoursStart = "22:00"
$quietHoursEnd = "06:00"
$timeNow = Get-Date
$TimeOfDay = $timeNow.TimeOfDay
$IsQuietHours = if ( $quietHoursStart -le $quietHoursEnd ) {
$TimeOfDay -ge $quietHoursStart -and $TimeOfDay -lt $quietHoursEnd
} else {
$TimeOfDay -ge $quietHoursStart -or $TimeOfDay -lt $quietHoursEnd
}
if ( !$IsQuietHours ) {
Send-NotificationEmail
}
Alain O'Dea's link really does address your need quite well, but from a scripting focused stance I think a better way to approach this (script wise, his link to scheduling the task is probably better) would be to define a starting time, and then a duration. So you want it to start at 10PM and go until 6AM? That's an 8 hour duration. Also, I would test to see if it is in your quiet time, and then invert it with -Not (I use the alias !)Try something like this:
$quietHoursStart = "22:00"
$quietHoursDuration = 8
$timeNow = Get-Date
if (! ($timeNow -gt (Get-Date $quietHoursStart ) -and $timeNow -lt (Get-Date $quietHoursStart ).AddHours($quietHoursDuration)) ) {
Send-NotificationEmail
}