我正在尝试在每月的最后一个工作日重新启动PC。该脚本每天下午7:25运行,目的是检查今天的日期,看看是否是该月的最后一个工作日。如果是,它将重新引导PC。如果不是,则记录为不是。
我当时想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 "
}
答案 0 :(得分:4)
我当时想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
只会查看日期本身。因此,除非您在午夜之前运行此程序,否则将获得一致且可预测的结果。
答案 1 :(得分:3)
通过这种方式,更容易获得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))
在星期六/日的计算结果为true,因此减去了一天。所以在9/30/2018这是
$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