Даты PowerShell не сравниваются правильно - PullRequest
0 голосов
/ 01 октября 2018

Я пытаюсь перезагрузить компьютер в последний день недели месяца.Сценарий выполняется ежедневно в 7:25 вечера, и цель состоит в том, чтобы проверить текущую дату и посмотреть, является ли это последний день недели месяца.Если это так, он перезагружает ПК.Если это не так, это регистрирует, что это не так.

Я подумал, что, возможно, PowerShell сравнивает по тикам, и тики немного отключаются между временем выполнения функции Get-Weekday и функции Get-Date.

Выдержка из журнала:

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 

Код:

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

Окончательное решение:

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

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

IMO получить последний день в текущем месяце проще:

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
}
  • здесь (!([int]$date.DayOfWeek % 6)) оценивается как истинное в субботу / солнце, поэтому вычитается один день

Итак, 30.09.2008 это:

$lwom = WorkingDay -Date (LastDayThisMonth)

возвращает

09/28/2018 00: 00: 00

избегая проблемы миллисекунд / тиков.

РЕДАКТИРОВАТЬ Только для полноты, расширенная функция WorkingDay с -After переключиться, чтобы получить следующий рабочий день (включен) или после указанной даты / сегодня.

function WorkingDay {
    param ([Parameter(Mandatory=$False,Position=0)] [datetime]$Date=(Get-Date).Date,
           [Parameter(Mandatory=$False,Position=1)] [switch]$After)
    If($PSBoundParameters.ContainsKey("After")){[int]$Offset=1}else{[int]$Offset=-1}
    While (!([int]$Date.DayOfWeek % 6)){$Date=$Date.AddDays($Offset)}
    Return $Date.Date
}

"Date       WDayBefore WDayAfter"
"----       ---------- ---------"
-7..7|%{
    $Date=(get-Date).Date.AddDays($_)
    "{0,-10:ddd dd} {1,-10:ddd dd} {2,-10:ddd dd} " -f `
        $Date,
        (WorkingDay -Date $Date),
        (WorkingDay -Date $Date -After )
}

Вывод процедуры теста (немецкий язык):

> Q:\Test\2018\10\01\SO_17-56.ps1
Date       WDayBefore WDayAfter
----       ---------- ---------
Mo 24      Mo 24      Mo 24
Di 25      Di 25      Di 25
Mi 26      Mi 26      Mi 26
Do 27      Do 27      Do 27
Fr 28      Fr 28      Fr 28
Sa 29      Fr 28      Mo 01
So 30      Fr 28      Mo 01
Mo 01      Mo 01      Mo 01
Di 02      Di 02      Di 02
Mi 03      Mi 03      Mi 03
Do 04      Do 04      Do 04
Fr 05      Fr 05      Fr 05
Sa 06      Fr 05      Mo 08
So 07      Fr 05      Mo 08
Mo 08      Mo 08      Mo 08
0 голосов
/ 01 октября 2018

Я подумал, что, возможно, PowerShell сравнивает по тикам, и тики немного отключаются между временем выполнения функции Get-Weekday и функции Get-Date.

Да, этолегко проверить, чтобы ...

$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

Повторный запуск покажет смесь успеха и неудач и покажет, что единственный способ datetime равен, если каждые дата / времязначения соответственно одинаковы.

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

При этом

$lwom -eq $ModDate сравнивает даты и времена .$lwom.Date -eq $ModDate.Date просто посмотрел бы на сами даты.Таким образом, если вы не выполните это до полуночи, это приведет к последовательным и предсказуемым результатам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...