Testing Off-Hours in PowerShell - date

I need a way to test Off-Hours in PowerShell. My Off-Hours are 7pm-7am. I’m not interested in the date part. The test is only for the time. I tried a few options but no access.

It's easier to use the complete timestamp.
$now = Get-Date
$start = $now.Date.AddHours(7)
$end = $now.Date.AddHours(19)
if ($start -le $now -and $end -ge $now) {
'within work hours'
} else {
'outside work hours'
}

A bit of googling for the syntax yields the following code snippet:
$a = Get-Date
if (($a.Hour -ge 19) -Or ($a.Hour -lt 7)) { Write-Host "Off Hours" } else { Write-Host "On hours" }

Here's a simplified answer:
if ((get-date).Hour -in 7..19) {
'Working Hours'
} else {
'Off hours'
}

Related

Why is a comparison between Date Time objects causing powershell to crash?

I am trying to write a simple script that lets the user select from 5 options to either write some text or run some basic commands. For some reason, the program crashes when I select option 1.
Write-Output " "
Write-Output "Hello. I am the Augur of Dunlain. I know many things. Ask, that which you do not yet know:"
sleep 2
Write-Output "1. How many more days until Christmas?"
Write-Output "2. What processes are running on my computer?"
Write-Output "3. What is System32?"
Write-Output "4. Why are the Blades saying that I have to kill Parthunaax?"
Write-Output "5. What is my age?"
$choice = Read-Host -Prompt "Choose options 1, 2, 3, 4, or 5"
If ($choice -eq "1"){
$currentDate = Get-Date
$christmas = Get-Date "12/25/2021"
$timeSpan = New-Timespan -Start $currentDate -End $christmas
if(timeSpan.days -gt 0){
Write-Output "There are " + $timeSpan.Days + " days left until Christmas."
sleep 3
}
else {
Write-Output "It is Christmas today! Merry Christmas!"
sleep 3
}
}
elseif ($choice -eq "2"){
$processes = Get-Process
Write-Output $processes
sleep 25
}
elseif ($choice -eq "3"){
Write-Output "System 32 is the collection of the following files and directories:"
$system32 = Get-ChildItem -Path C:\Windows\System32
Write-Output $system32
sleep 25
}
elseif ($choice -eq "4"){
Write-Output "They are intollerant, plain and simple. Parthunaax is a total G, so if the Blades are telling you to kill him you can tell them that they are stinky nerds and you don't want to play with them any more."
}
elseif ($choice -eq "5"){
}
else {
Write-Output "Looks like you have failed the simple task of selecting a number 1 through 5. I figured a monkey would have been capable of doing that but I guess you're inferior to the monkey. Try again but this time be better."
}
Based on the current version of the question you are missing a $ in the If(timeSpan.days) should be If($timeSpan.days) and in the write-output don't try to add strings just use PowerShell string expansion as shown.
If ($choice -eq "1"){
$currentDate = Get-Date
$christmas = Get-Date "12/25/2021"
$timeSpan = New-Timespan -Start $currentDate -End $christmas
if($timeSpan.days -gt 0){
Write-Output "There are $($timeSpan.Days) days left until Christmas."
sleep 3
}
Sample output:
Choose options 1, 2, 3, 4, or 5: 1
There are 150 days left until Christmas.
HTH
Not sure what you mean by "the program crashes when I select option 1", but you could use a switch instead of all these if() .. elseif()'s, to make the code a lot clearer.
With the time comparison, you should IMO compare the two dates without the time part, so as of midnight.
On my machine Get-Date "12/25/2021" won't work and will result in an exception:
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "12/25/2021" to type "System.DateTime".
This is because my current locale is set for Dutch, so I would need to reverse the day and month numbers to Get-Date "25/12/2021"
Then of course, if you run this after December 25th, hardcoding the Christmas date is a bad choice and you need to make an adjustment to that if this is the case.
Try below
$choice = Read-Host -Prompt "Choose options 1, 2, 3, 4, or 5"
switch ($choice) {
'1' {
# eliminate the time from both dates, so they are set to midnight
$currentDate = (Get-Date).Date
$christmas = (Get-Date -Year $currentDate.Year -Month 12 -Day 25).Date
# if today is already past December 25th of this year
if ($currentDate -gt $christmas) { $christmas.AddYears(1) }
$timeSpan = New-Timespan -Start $currentDate -End $christmas
if ($timeSpan.TotalDays -eq 0) {
"It is Christmas today! Merry Christmas!"
}
else {
"There are {0} days left until Christmas." -f $timeSpan.TotalDays
}
Start-Sleep 3
}
'2' { Get-Process | Format-Table -AutoSize; Start-Sleep 25 }
# the rest of your options go here
default { "Please enter a number from 1 to 5" }

Get last work week of month with powershell

I'm trying to get the last work week in a month using powershell. Right now, my code isn't working. I'm getting 5 when it should return 4. The work week is Mon-Fri Here is my code so far:
$d = Get-Date ; [math]::Ceiling(($d.Day+(($d.AddDays(-($d.Day-1))).DayOfWeek.value__)-7)/7+1)
if ($d -eq 5) { $d -=1 }
What can I improve or change to make this work? I'm using powershell 5.
Without understanding your [math] formula and its meaning, next code snippet shows 4 today (2016-10-25):
$d = Get-Date
$e = [math]::Ceiling(($d.Day+(($d.AddDays(-($d.Day-1))).DayOfWeek.value__)-7)/7+1)
if ($e -eq 5) { $e -=1 }
$e
In your code snippet, $d.GetTypeCode() keeps to be DateTime. In other words, $d -eq 5 always results to false.
If your are up to the last monday of a month this should work
$d = Get-Date "2016-1-01"
$LastDayinMonth = (Get-Date "$($d.year)/$($d.month+1)/1").addDays(-1)
$Offset=[int](($LastDayinMonth.dayofweek -1)* -1)
If ($Offset -eq 1) {$Offset=-6}
$LastMonday=$LastDayinMonth.addDays($Offset)
"d : {0}" -f $d.tostring("D")
"LastDayinMonth: {0}" -f $LastDayinMonth.tostring("D")
"LastMonday : {0}" -f $LastMonday.tostring("D")
HTH

Date Time day of the week comparison logic in PowerShell

Date Time objects allow us to perform actions like this:
$CurrentDate = Get-Date
$TextDate = get-date -date "02/10/2016"
if ($TextDate -lt $CurrentDate){
Write-Host "True"
}
else {
Write-Host "False"
}
This outputs "True" because $TextDate is less than $CurrentDate.
Following the same logic, why does the following code output false?
$CurrentDate = Get-Date -UFormat %V
$TextDate = Get-Date -date "02/10/2016"
$TextDate = Get-Date -date $TextDate -UFormat %V
if ($TextDate -lt $CurrentDate){
Write-Host "True"
}
else {
Write-Host "False"
}
The only difference is that we are comparing the week of the year. If you change the comparison to -gt, the code returns True.
Formatted dates are strings, not integers. The string "6" is after the string "11".
This would be the most correct way to do this:
First, decide what the "first week of the year" actually means:
$CalendarWeekRule = [System.Globalization.CalendarWeekRule]::FirstDay;
#$CalendarWeekRule = [System.Globalization.CalendarWeekRule]::FirstFourDayWeek;
#$CalendarWeekRule = [System.Globalization.CalendarWeekRule]::FirstFullWeek;
Then, decide which day of the week is the first day of the week:
$FirstDayOfWeek = [System.DayOfWeek]::Sunday;
#$FirstDayOfWeek = [System.DayOfWeek]::Monday;
#Any day is available
Then you can get your correct week number:
$Today = (Get-Date).Date;
$TodayWeek = [cultureinfo]::InvariantCulture.Calendar.GetWeekOfYear($Today, $CalendarWeekRule, $FirstDayOfWeek);
$TargetDate = Get-Date -Date "2016-02-10";
$TargetWeek = [cultureinfo]::InvariantCulture.Calendar.GetWeekOfYear($TargetDate, $CalendarWeekRule, $FirstDayOfWeek);
if ($TargetWeek -lt $TodayWeek) { $true } else { $false }
Note that if you want a full ISO 8601 week, it's somewhat more complicated.
Because you are comparing string-objects.
(Get-Date -UFormat %V).GetType().FullName
System.String
When comparing strings using -gt and -lt it sorts the strings and because 6 comes after 1, your 6 -lt 11-test returns false.
Both $TextDate and $CurrentDate are of type [string] so what you are evaluating is '6' -lt '11' which will return false. Operators are based on the left side type in PowerShell. So in order to force an integer comparison modify your expression as under
if ([int]$TextDate -lt $CurrentDate)
{
Write-Host "True"
}
else
{
Write-Host "False"
}

If/ElseIf block not working with -or

I am having a problem with a script I am writing for my son. My intent is a simple reminder to him to remember his chores. I've just started doing PowerShell recently and I'm really enjoying it. I've bought a couple books and been through numerous other posts.
What I've got so far is below, seems if evaluations aren't working correctly with the -or (or maybe I goofed?)
## REMINDERS TO DO CHORES ##
$sun = "Sunday"
$mon = "Monday"
$tue = "Tuesday"
$wed = "Wednesday"
$thu = "Thursday"
$fri = "Friday"
$sat = "Saturday"
$today = (get-date).DayOfWeek
$choreVac = "Vacuum the rooms and stairs"
$choreBath = "Clean the Bathroom Including emptying the garbage"
$choreOther = "No Chores Today -- But keep dishes done up"
if($today -eq $mon -or $wed -or $fri) {
msg /time:2500 * "Today is a Chore Day: your job is to $choreVac"
}
elseif ($today -eq $tue -or $sat ) {
msg /time:2500 * "Today is a Chore Day: your job is to $choreBath and PLEASE do a good job"
}
else {
msg /time:2500 * $choreOther
}
The problem is I don't think it's being evaluated correctly on the day, so for today being Tuesday, the evaluated result is $mon -or $wed -or $fri
If I re-code this for each day as follows it works like expected. Why is it not working with the -or?
if($today -eq $tue) {
msg /time:2500 * $choreBath
}
Like you discovered yourself PowerShell was not evaluating your if statement how you intended it to be. Your expression could be understood better like this:
if(($today -eq $mon) -or ($wed) -or ($fri))
Just as in your comment the the code you wanted was
$today -eq $mon -or $today -eq $wed -or $today -eq $fri
or another way to look at it.
($today -eq $mon) -or ($today -eq $wed) -or ($today -eq $fri)
PowerShell does not need to brackets but it is good to use them if things are not going your way.
When Non null/zero length strings in PowerShell are true when cast as booleans. Focusing on the second clause it could be rewritten as
"Wednesday" -or "Friday"
Which is always true. That is why your if statement was firing when you didn't expect it to.
What you had coded made some logical sense but it was syntactically incorrect. Another approach I would like to introduce you to, if you are not already familiar with it, is switch. It would help reduce the clutter of all the if statements and would be especially useful if they became more complicated as the chores evolved over time.
$today = (get-date).DayOfWeek
$choreVac = "Vacuum The Apt"
$choreBath = "Clean the Bathroom Including empting the garbage"
$choreOther = "NO CHORES TODAY -- BUT YOU CAN Keep dishes done up, and Keep Garbage from Overflowing AND CLEAN YOUR ROOM and OR Do Laundry!!!. Especially your bedding"
Switch ($today){
{$_ -in 1,3,5}{$message = "Today is a Chore Day: Your job is to`r$choreVac"}
{$_ -in 2,6}{$message = "Today is a Chore Day: Your job is to`r$choreBath and PLEASE do a good job"}
default{$message = $choreOther}
}
msg /time:2500 * $message
We removed all the calls to msg into one statement since only the $message changes. If a chore day is not covered with a clause in the switch then the default is simply $choreOther.
Also the days of the week can be represented as integers as well like you see above. This could arguably reduce the readability of the code but I think that is a stretch.
Here is the full code corrected and working as I wanted it to.
## REMINDERS TO DO CHORES ##
$sun = "Sunday"
$mon = "Monday"
$tue = "Tuesday"
$wed = "Wednesday"
$thu = "Thursday"
$fri = "Friday"
$sat = "Saturday"
$today = (get-date).DayOfWeek
$choreVac = "Vacuum The Apt"
$choreBath = "Clean the Bathroom Including empting the garbage"
$choreOther = "NO CHORES TODAY -- BUT YOU CAN Keep dishes done up, and Keep Garbage from Overflowing AND CLEAN YOUR ROOM and OR Do Laundry!!!. Especially your bedding"
if($today -in ($mon, $wed ,$fri) ) {
msg /time:2500 * "Today is a Chore Day: your job is to $choreVac"
}
elseif ($today -in ($tue,$sat)) {
msg /time:2500 * "Today is a Chore Day: your job is to $choreBath and PLEASE do a good job"
}
else {
msg /time:2500 * $choreOther
}
You can also use Hashtables to handle the lists of chores and the associated days. The following will allow you to easily add chores to any given day (or even put multiple chores on a single day)
$chores = #{Vac = "Vacuum the Appt";
Bath = 'Clean the bathroom including emptying the garbage';
Other = 'Nothing today -- But keep dishes done up'
}
$day = #{Sunday = $chores.Other;
Monday = $chores.Vac;
Tuesday = $chores.Bath;
Wednesday = #($chores.Vac,$chores.Other);
Thursday = $chores.Other;
Friday = $chores.Vac;
Saturday = $chores.Bath;
}
$base = "Chores for today: "
$today = (Get-Date).DayOfWeek
if ($day."$today".count -gt 1) {
$first = "`n " + $day."$today"[0]
$rest = for ($i = 1; $i -lt $day."$today".count; $i++) {
"`n " + $day."$today"[$i]
}
$msg = $base + $first + $rest
} else {
$msg = $base + "`n " + $day."$today"
}
msg /time:2500 * $msg
If you don't want to support having multiple chores on a day (which in the above applies for Wednesday), just replace the entire If/Else block with the else clause and it will simply list the chores of the day.

If / else on powershell

I am currently learning how to use powershell and was wondering how would you make a simple process like this for example.
If the time is between 9am and 12pm then write to 'Get coffee' else
write nothing.
There are a lot of ways to do this.
if ((9,10,11) -contains (get-date).Hour) { "get coffee" }
if ((get-date).hour -ge 9 -and (get-date).hour -le 11) { "get coffee" }
if (((get-date -hour 12 -min 0 -sec 0) - (get-date)).hours -in 0..2) { ... }
This might be a fun community wiki question.
This is about as short as I can get it...
if(Get-Date | ? {($_.hour -ge 9) -and ($_.hour -le 12)}){"get coffee"}
My 2 cents (using .net):
[datetime]$now = [datetime]::now.Tostring("T",[System.Globalization.CultureInfo]::InvariantCulture )
$low = [datetime] "09:00:00 am"
$hi = [datetime] "12:00:00 pm"
if ( $now -ge $low -and $now -le $hi ) { "Coffee Time!" } else {"Work!"}