Get last work week of month with powershell - 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

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

Date variable still contains todays date after assigning it the value of upcoming Friday

I have a little powershell script to find the date of the upcoming Friday. However after assigning the value of the Friday date, my date variable still prints out todays date.
$date = Get-Date
for($i=1; $i -le 7; $i++)
{
if($date.AddDays($i).DayOfWeek -eq 'Friday')
{
$date.AddDays($i)
break
}
}
Write-Host "$date"
AddDays seems to return new date object and not update the date object in $date. Try assigning $date to the new date inside the if statement as follows:
$date = $date.AddDays($i)
$date = Get-Date
for($i=1; $i -le 7; $i++)
{
if($date.AddDays($i).DayOfWeek -eq 'Friday')
{
$date = $date.AddDays($i)
break
}
}
Write-Host "$date"
You have to return the value you're assigning to $date back to itself.
You probably tested it yesterday (Wednesday) because it works today.
The problem in your code is that it reuses the same $Date each time and probably step over the expected date:
Date + 1
Date + 3 (1 + 2)
Date + 6 (1 + 2 + 3)
...
In other words, the $date = Get-Date should be in your loop.
(Get-Date).AddDays((1..7 | Where {(Get-Date).AddDays($_).DayOfWeek -eq 'Friday'}))

Testing Off-Hours in PowerShell

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

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"

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.