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

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

Related

In PowerShell $Profile, test for Morning, Afternoon, or evening and make the selection a certain font color, like "Good morning Ken" in blue font

I have an if statement in my $profile file that will test the time of day and output a greeting such as "Good Morning", "Good Afternoon", etc. I just want the fone color to be, oh I don't know, let say purple.
If ($Hour -lt 12) {"Good Morning Ken!"}
ElseIf ($Hour -gt 17) {"Good Eventing Ken!"}
Else {"Good Afternoon Ken!"}
The resulting command prompt that I get whenever I open PowerShell is:
Transcript started, output file is C:\Users\Ken\PowerShellTranscript\MyTranscript.txt
Good Afternoon Ken! <-- I'd like this to have a different color when it Writes to my console.
Today is Saturday, November 5, 2022
PowerShell Version: 5
Computer Name = HPLAPTOP
Happy scripting!
PS C:>
Obviously, I don't know what I'm doing here, so I tried several things with (), {}, and piping to Write-Host
But nothing gets me a changed font color.
I tried using Write-Host, with and without various things such as:
If ($Hour -lt 12) {"Good Morning Ken!"} | Write-Host -ForgroundColor Magenta
ElseIf ($Hour -gt 17) {"Good Eventing Ken!"} | Write-Host -ForgroundColor Magenta
Else {"Good Afternoon Ken!"} | Write-Host -ForgroundColor Magenta
Leaving the typo (-ForgroundColor instead of -ForegroundColor) aside, you just need to move the } on each line to the end of that line, so that each "Good ..." string is directly piped to Write-Host:
If ($Hour -lt 12) {"Good Morning, Ken!" | Write-Host -ForegroundColor Magenta }
ElseIf ($Hour -gt 17) {"Good Eventing, Ken!" | Write-Host -ForegroundColor Magenta }
Else {"Good Afternoon, Ken!" | Write-Host -ForegroundColor Magenta }
However, you can streamline your approach:
('Good {0}, Ken' -f $(
If ($Hour -lt 12) { 'Morning' }
ElseIf ($Hour -gt 17) { 'Evening' }
Else { 'Afternoon' }
)) | Write-Host -ForegroundColor Magenta
Note the need to enclose the if statement in $(...), the subexpression operator, so that it can participate in the expression that uses -f, the format operator.

Date based foreach loop [duplicate]

I'm working on my first PowerShell script and can't figure the loop out.
I have the following, which will repeat $ActiveCampaigns number of times:
Write-Host "Creating $PQCampaign1 Pre-Qualified Report"
Invoke-Item "$PQCampaignPath1\PQ REPORT $PQCampaign1.qvw"
Write-Host "Waiting 1 minute for QlikView to update"
sleep -seconds 60 # Wait 1 minute for QlikView to Reload, create Report and Save.
DO{
Write-Host "Daily Qlikview Reports"
Write-Host "Wating for QlikView to create the $PQCampaign1 PQ Report"
Get-Date
Write-Host "Checking...."
sleep -seconds 1
Write-Host ""
Write-Host "Not Done Yet"
Write-Host "Will try again in 5 seconds."
Write-Host ""
sleep -seconds 5
}
Until (Test-Path "$PQCampaignPath1\$PQCampaign1 $PQReportName $ReportDate.xlsx" -pathType leaf)
Get-Date
Write-Host "Done with $PQCampaign1 PQ Report. Wait 10 seconds."
sleep -seconds 10
These parameters need to increase with one for each loop:
$PQCampaign1 (should become $PQCampaign2, then 3, etc.)
$PQCampaignPath1 (should become $PQCampaignPath2, then 3, etc.)
So if $ActiveCampaigns is set to 8 on a certain day, then this needs to repeat 8 times and the last time it must open $PQCampaign3 which lies in $PQCampaignPath8.
How can I fix this?
Use:
1..10 | % { write "loop $_" }
Output:
PS D:\temp> 1..10 | % { write "loop $_" }
loop 1
loop 2
loop 3
loop 4
loop 5
loop 6
loop 7
loop 8
loop 9
loop 10
This may be what you are looking for:
for ($i=1; $i -le $ActiveCampaigns; $i++)
{
$PQCampaign = Get-Variable -Name "PQCampaign$i" -ValueOnly
$PQCampaignPath = Get-Variable -Name "PQCampaignPath$i" -ValueOnly
# Do stuff with $PQCampaign and $PQCampaignPath
}
Here is a simple way to loop any number of times in PowerShell.
It is the same as the for loop above, but much easier to understand for newer programmers and scripters. It uses a range and foreach. A range is defined as:
range = lower..upper
or
$range = 1..10
A range can be used directly in a for loop as well, although not the most optimal approach, any performance loss or additional instruction to process would be unnoticeable. The solution is below:
foreach($i in 1..10){
Write-Host $i
}
Or in your case:
$ActiveCampaigns = 10
foreach($i in 1..$ActiveCampaigns)
{
Write-Host $i
If($i==$ActiveCampaigns){
// Do your stuff on the last iteration here
}
}
See this link. It shows you how to dynamically create variables in PowerShell.
Here is the basic idea:
Use New-Variable and Get-Variable,
for ($i=1; $i -le 5; $i++)
{
New-Variable -Name "var$i" -Value $i
Get-Variable -Name "var$i" -ValueOnly
}
(It is taken from the link provided, and I don't take credit for the code.)

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

Loop X number of times

I'm working on my first PowerShell script and can't figure the loop out.
I have the following, which will repeat $ActiveCampaigns number of times:
Write-Host "Creating $PQCampaign1 Pre-Qualified Report"
Invoke-Item "$PQCampaignPath1\PQ REPORT $PQCampaign1.qvw"
Write-Host "Waiting 1 minute for QlikView to update"
sleep -seconds 60 # Wait 1 minute for QlikView to Reload, create Report and Save.
DO{
Write-Host "Daily Qlikview Reports"
Write-Host "Wating for QlikView to create the $PQCampaign1 PQ Report"
Get-Date
Write-Host "Checking...."
sleep -seconds 1
Write-Host ""
Write-Host "Not Done Yet"
Write-Host "Will try again in 5 seconds."
Write-Host ""
sleep -seconds 5
}
Until (Test-Path "$PQCampaignPath1\$PQCampaign1 $PQReportName $ReportDate.xlsx" -pathType leaf)
Get-Date
Write-Host "Done with $PQCampaign1 PQ Report. Wait 10 seconds."
sleep -seconds 10
These parameters need to increase with one for each loop:
$PQCampaign1 (should become $PQCampaign2, then 3, etc.)
$PQCampaignPath1 (should become $PQCampaignPath2, then 3, etc.)
So if $ActiveCampaigns is set to 8 on a certain day, then this needs to repeat 8 times and the last time it must open $PQCampaign3 which lies in $PQCampaignPath8.
How can I fix this?
Use:
1..10 | % { write "loop $_" }
Output:
PS D:\temp> 1..10 | % { write "loop $_" }
loop 1
loop 2
loop 3
loop 4
loop 5
loop 6
loop 7
loop 8
loop 9
loop 10
This may be what you are looking for:
for ($i=1; $i -le $ActiveCampaigns; $i++)
{
$PQCampaign = Get-Variable -Name "PQCampaign$i" -ValueOnly
$PQCampaignPath = Get-Variable -Name "PQCampaignPath$i" -ValueOnly
# Do stuff with $PQCampaign and $PQCampaignPath
}
Here is a simple way to loop any number of times in PowerShell.
It is the same as the for loop above, but much easier to understand for newer programmers and scripters. It uses a range and foreach. A range is defined as:
range = lower..upper
or
$range = 1..10
A range can be used directly in a for loop as well, although not the most optimal approach, any performance loss or additional instruction to process would be unnoticeable. The solution is below:
foreach($i in 1..10){
Write-Host $i
}
Or in your case:
$ActiveCampaigns = 10
foreach($i in 1..$ActiveCampaigns)
{
Write-Host $i
If($i==$ActiveCampaigns){
// Do your stuff on the last iteration here
}
}
See this link. It shows you how to dynamically create variables in PowerShell.
Here is the basic idea:
Use New-Variable and Get-Variable,
for ($i=1; $i -le 5; $i++)
{
New-Variable -Name "var$i" -Value $i
Get-Variable -Name "var$i" -ValueOnly
}
(It is taken from the link provided, and I don't take credit for the code.)