Powershell Combine Switch Statement - powershell

I have the following Powershell code:
$dow = (get-date).DayOfWeek
switch($dow) {{"Sunday"}{$report_Day = (Get-Date).AddDays(-2).Day}{"Monday", "Tuesday", "Wednesday", "Thursday"}{$report_Day = (Get-Date).Day}}
switch($dow) {{"Sunday"}{$report_Month = (Get-Date).AddDays(-2).Month}{"Monday", "Tuesday", "Wednesday", "Thursday"}{$report_Month = (Get-Date).Month}}
Wonder if it is possible to combine the 2 switch statements into 1 - something such as:
$dow = (get-date).DayOfWeek
switch($dow) {{"Sunday"}{$report_Day = (Get-Date).AddDays(-2).Day, $report_Month = (Get-Date).AddDays(-2).Month}{"Monday", "Tuesday", "Wednesday", "Thursday"}{$report_Day = (Get-Date).Day, $report_Month = (Get-Date).Month }}
I tested it it wouldn't work but I wonder if there is a mean to combine them.
Thank you

First: Do yourself, and anyone who will read your code in the future, a favor and format your code so that it's readable. Whitespace doesn't cost you anything and it will save you difficulty later on.
Second: What does your code do on Friday & Saturday?
The issue is the commas between the statements in your switch statement. They should be separate lines (again, formatting will help you) or if you must put them on the same line, terminate each statement with a semicolon (;).
$dow = (get-date).DayOfWeek
switch ($dow) {
"Sunday" {
$report_Day = (Get-Date).AddDays(-2).Day;
$report_Month = (Get-Date).AddDays(-2).Month;
break
}
{($_ -eq "Monday") -or ($_ -eq "Tuesday") -or ($_ -eq "Wednesday") -or ($_ -eq "Thursday")} {
$report_Day = (Get-Date).Day;
$report_Month = (Get-Date).Month
break
}
}

Related

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"

powershell: if loop, while the first position of arraylist in in process

I have an arraylist, in which I am going to save some values. I am doing a foreach loop and if a value is going to be saved at the first position of the ArrayList, I want to output a "First position" line and otherwise, nothing should be done.
The if block that I wrote below, doesn't work.
<# Don't consider this code from here
[System.Collections.ArrayList]$alist = #()
$al ="keeranpc01,www.google.ch,192.168.0.25"
$al = $al.Split(",")
foreach($h in $al){
# Abstand vor dem Hostnamen löschen
if($h.contains(' ')) {
$h = $h -replace '\s', ''
}
$alist.Add($h)
}
to here
#>
#### Start here
[System.Collections.ArrayList]$rear = #()
foreach($ha in $alist) {
$PingConnetion = Test-Connection $ha -Count 1 -ErrorAction SilentlyContinue
$pcre = $ha
$pire = if($PingConnetion.ResponseTime -ne $null) {Write-output 'Erreichbar'}else{Write-Output 'Nicht Erreichbar'}
$zure = $PingConnetion.ResponseTime
$zeit = Get-Date -Format HH:mm:ss
if($alist[$_] -eq $alist[0]) {Write-Host 'First position'}
[void]$rear.Add([PSCustomObject]#{Zeit = $zeit; Host = $pcre; IPv4 = $PingConnetion.IPV4Address.IPAddressToString; Ping = $pire; Zugriffszeit = $zure; })
}
how should I write the if statement so that it is possible? I expect if-statement to work, Only when the first position of ArrayList is in process
thx
What you are tying to do does work except you are tying to compare element zero of your alist to a ordinal position of your alist which is invalid. You would need to compare the following:
if($ha -eq $alist[0]) {Write-Host 'First position'}
Below is a worked example that might be clearer.
$input = 1..10
foreach($x in $input){
if($input[0] -eq $x){
write-host "First Position"
}
$x
}

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

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.