Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell dates not comparing correctly

Tags:

powershell

I'm trying to reboot PC's on the last weekday of the month. The script runs daily at 7:25ish PM and the goal is to check today's date and see if it's the last weekday of the month. If it is, it reboots the PC. If it isn't it logs that it isn't.

I was thinking maybe PowerShell is comparing by ticks and the ticks are off slightly between run time of the Get-Weekday function and the Get-Date function.

Log excerpt:

COMP1 - 09/26/2018 17:24:08 - Not last weekday of month 09/28/2018 17:24:08 > 09/26/2018 17:24:08 
COMP1 - 09/27/2018 17:24:09 - Not last weekday of month 09/28/2018 17:24:09 > 09/27/2018 17:24:09 
COMP1 - 09/28/2018 17:24:01 - Not last weekday of month 09/28/2018 17:24:01 > 09/28/2018 17:24:01 
COMP1 - 09/28/2018 17:24:01 - Not last weekday of month 09/28/2018 17:24:01 > 09/28/2018 17:24:01 

Code:

#Gets last weekday of the month
function Get-Weekday {
    param(
        $Month = $(Get-Date -format 'MM'),
        $Year = $(Get-Date -format 'yyyy'),
        $Days = 1..5
        )
    $MaxDays = [System.DateTime]::DaysInMonth($Year, $Month)
    1..$MaxDays | ForEach-Object {
            Get-Date -day $_ -Month $Month -Year $Year |
              Where-Object { $Days -contains $_.DayOfWeek }  
    }
}

    #Last day of the month
    $lwom = (Get-Weekday -Month (Get-Date).Month) | Select-Object -Last 1
    #Returns:  09/28/2018 17:24:16

    # Get Today's date.
    $ModDate = Get-Date
    #Returns:  09/28/2018 17:24:16

    #If Last day of month = Today's Date    
    if ( $lwom -eq $ModDate ) { 


        #Creates the wscript shell for the popup -- box automatically closes after 10 seconds, script sleeps for 60
        $wshell = New-Object -ComObject Wscript.Shell
        $wshell.Popup("This computer will reboot in 60 seconds.  Click OK and save your work!",10,"Save Your Data",48+0)
        $xCmdString = {sleep 60}
        Invoke-Command $xCmdString

        #Next popup created to reboot in 5 seconds.  
        $wshell.Popup("Rebooting...",4,"Rebooting",48+0)
        $xCmdString = {sleep 5}
        Invoke-Command $xCmdString
        Restart-Computer -Force
          }

    else { 
        Add-Content 'EOM-reboot_log.txt' "$env:computername - $ModDate - Not last weekday of month $lwom > $ModDate " 
         }

Final Solution:

function LastDayThisMonth {
    return (Get-Date -Day 1).Date.AddMonths(1).AddDays(-1)
}

function WorkingDay {
    param ([datetime]$date=(Get-Date).Date)
    While (!([int]$date.DayOfWeek % 6)){$date=$date.AddDays(-1)}
    Return $date.Date
}

    $lwom = WorkingDay -Date (LastDayThisMonth) #Does not need .Date because it's already in the function.
    $ModDate = (Get-Date).Date  # .Date on the variables will return the date and ignores the time.  Time become 12:00:00 AM of both da


    if ( $lwom -eq $ModDate ) { 

                #Writes to the log file.
                Add-Content 'c:\EOM-reboot_log.txt' "$env:computername - $ModDate -  End of Month Weekday" 

                #Creates the wscript shell for the popup -- box automatically closes after 10 seconds, script sleeps for 60
                $wshell = New-Object -ComObject Wscript.Shell
                $wshell.Popup("This computer will reboot in 60 seconds.  Click OK and save your work!",10,"Save Your Data",48+0)
                $xCmdString = {sleep 60}
                Invoke-Command $xCmdString

                #Next popup created to reboot in 5 seconds.  
                $wshell.Popup("Rebooting...",4,"Rebooting",48+0)
                $xCmdString = {sleep 5}
                Invoke-Command $xCmdString
                Restart-Computer -Force
          }

    else { 
        Add-Content 'c:\EOM-reboot_log.txt' "$env:computername - $ModDate - Not last weekday of month $lwom > $ModDate " 
 }
like image 858
Travis Avatar asked Jan 19 '26 03:01

Travis


1 Answers

I was thinking maybe PowerShell is comparing by ticks and the ticks are off slightly between run time of the Get-Weekday function and the Get-Date function.

Yep, this is easy to test to...

$date1 = Get-Date
$date2 = Get-Date

$date1.ToString("dd-MM-yyyy hh:mm:ss:fff")
$date2.ToString("dd-MM-yyyy hh:mm:ss:fff")

$date1 -eq $date2

Running this repeatedly will show a mix of success and failures and shows that the only way datetime are equal is if every date / time value are respectively the same.

01-10-2018 09:11:02:729
01-10-2018 09:11:02:730
False

01-10-2018 09:11:04:378
01-10-2018 09:11:04:378
True

That being said,

$lwom -eq $ModDate is comparing dates and times. $lwom.Date -eq $ModDate.Date would just look at the dates themselves. So, unless you run this just before midnight, that would get consistent and predictable results.

like image 155
Matt Avatar answered Jan 20 '26 17:01

Matt