If / else on powershell - 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!"}

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

Is there a term used to describe variables that are not set as [int] or [string], etc?

The below code calculates either the full ISO date or ISO Week according to user preferences. $Year, $Month and $Day are set as integers. $Week is not set as anything. If I set $Week as an integer, the code won't add a leading zero to the week number, which is not a deal killer, but ISO weeks are generally formatted that way. If I set it as a string, it results in an error. As better practice, I could use a separate variable to add the leading zero and use that variable in either of the two posible results, but what I really want to know is how I should refer to it. I'd call it a variant in VB langauges, but what is it called in PowerShell?
Function Get-ISODate {
Param(
[datetime]$Date = (Get-Date),
[switch]$LongFormat
)
[int]$Year = $Date.Year
[int]$Month = $Date.Month
[int]$Day = $Date.DayOfWeek.value__
If ($Day -eq 0) {$Day = 7}
If ($Day -ge 1 -and $Day -le 3) {$Date = $Date.AddDays(3)}
$Week = (Get-Culture).Calendar.GetWeekOfYear($Date, 'FirstFourDayWeek', 'Monday')
Switch ($Week)
{
52 {If ($Day -ge 5 -and $Day -le 7 -and $Month -ne 12) {$Year = $Year - 1} ; Break}
53 {If ($Day -ge 5 -and $Day -le 7 -and $Month -ne 12) {$Year = $Year - 1} ; Break}
1 {If ($Month -eq 12) {$Year = $Year + 1} ; Break}
}
$Week = $Week.ToString('00')
If ($LongFormat.IsPresent)
{
"$Year-W$Week-$Day"
}
Else
{
"W$Week"
}
}
I can't find an explicit reference, but there's a couple of Microsoft articles that call them typed vs untyped, which makes sense...
About Assignment Operators
The assignment by subtraction operator
To delete a variable, use the Remove-Variable cmdlet. This method is useful when the variable is explicitly cast to a particular data type, and you want an untyped variable. The following command deletes the $a variable:
Remove-Variable -Name a
About Script Bblocks
Using delay-bind script blocks with parameters
A typed parameter that accepts pipeline input (by Value) or (by PropertyName) enables use of delay-bind script blocks on the parameter. Within the delay-bind script block, you can reference the piped in object using the pipeline variable $_.
The parameter must not be untyped, and the parameter's type cannot be [scriptblock] or [object].

Powershell studio datagridview if statement

I have a cellpainting event and am trying to correct/clean this IF statement up. I think I'm getting lost in my parenthess. Is someone able to take a second look at this? Thanks for your time.
My end goal is the IF statemant to be: Column 1 date older than 42 days or not $null and column 4 value = "SEP"
$datagridview1_CellPainting=[System.Windows.Forms.DataGridViewCellPaintingEventHandler]{
$SEPreturnlimit = "{0:MM/dd/yyyy}" -f (get-date).AddDays(-42)
if ((($_.ColumnIndex -eq 1 -and ([datetime]$_.Value -le $SEPreturnlimit -and [datetime]$_.Value.ToString() -ne $null))) -and ($datagridview1.rows .Cells[4].Value -eq "SEP")) #Column 1 date older than 42 days or not $null **and** column 4 value = "SEP"
{
$this.Rows[$_.RowIndex] | %{ $_.DefaultCellStyle.BackColor = 'crimson' } #Color Row
}
I would split the if conditions into separate nested ifs and also add a try..catch
$datagridview1_CellPainting = [System.Windows.Forms.DataGridViewCellPaintingEventHandler] {
if ($_.ColumnIndex -eq 1 -and $datagridview1.rows.Cells[4].Value -eq 'SEP') {
$SEPreturnlimit = (Get-Date).AddDays(-42).Date # set to 42 days back at midnight
try {
# if we succeed in parsing out a datetime object
$date = [datetime]$_.Value
# test if we have a DateTime object and if that date is older than the reference date
if (($date) -and $date-le $SEPreturnlimit) {
# cannot check this myself, but shouldn't that simply be
# $this.Rows[$_.RowIndex].DefaultCellStyle.BackColor = 'crimson'
$this.Rows[$_.RowIndex] | ForEach-Object{ $_.DefaultCellStyle.BackColor = 'crimson' } #Color Row
}
}
catch { <# do nothing #> }
}
}
I think I fixed the placement, but check the logic. Have a look at it this way
if
(
(
$_.ColumnIndex -eq 1 -and
(
[datetime]$_.Value -le
$SEPreturnlimit -and
[datetime]$_.Value.ToString() -ne
$null
)
) -and
(
$datagridview1.rows .Cells[4].Value -eq
'SEP'
)
) #Column 1 date older than 42 days or not $null **and** column 4 value = "SEP"

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

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