我正在使用以下PowerShell脚本,以便能够在一定时间后关闭计算机。
# Determine the path to a file in which information about a pending
# shutdown is persisted by this script.
$lastScheduleFile = Join-Path $env:TEMP ('~{0}_Schedule.txt' -f [IO.Path]::GetFileNameWithoutExtension($PSCommandPath))
[datetime] $shutdownTime = 0
# First, see if this script previously scheduled a shutdown.
try {
$shutdownTime = ([datetime] (Get-Content -ErrorAction Ignore $lastScheduleFile)).ToUniversalTime()
}
catch {}
# If the time is in the past, by definition it doesn't reflect the true pending shutdown time, so we ignore it.
if ($shutdownTime -lt [datetime]::UtcNow) {
$shutdownTime = 0
}
else {
# Warn that the retrieved shutdown time isn't *guaranteed* to be correct.
Write-Warning @'
The pending shutdown time is assumed to be what *this* script last requested,
which is not guaranteed to be the true time, nor is it guaranteed that a shutdown is even still pending.
'@
}
$shutdownAlreadyPending = $shutdownTime -ne 0
if (-not $shutdownAlreadyPending) {
# Prompt the user for when (how many minutes / hours and minutes from now) to shut down.
while ($true) {
try {
$secsFromNow = switch -Regex ((Read-Host 'Enter the timespan after which to shut down, either in minutes (e.g. 30) or hours and minutes (e.g. 1:15)').Trim()) {
'^[1-9]\d*$' { [int] $_ * 60; break }
'^\d+:\d+$' { ([timespan] $_).TotalSeconds; break }
default { throw }
}
break # input was valid; proceed below.
}
catch {
Write-Warning 'Invalid timespan entered; please try again.'
}
}
# Calculate the resulting shutdown time.
$shutdownTime = [datetime]::UtcNow.AddSeconds($secsFromNow)
# Schedule the shutdown via shutdown.exe
while ($true) {
# Note: Due to use of /t with a nonzero value, /f is implied,
# i.e. the shutdown will be forced at the implied time.
shutdown /s /t $secsFromNow
if ($LASTEXITCODE -eq 1190) {
# A shutdown/restart is already scheduled. We cannot know what its delay is.
Write-Warning "A shutdown is already pending. It will be canceled and rescheduled as requsted."
shutdown /a # Abort the pending shutdown, so that the new one can be requested as scheduled.
continue
}
break
}
if ($LASTEXITCODE) {
# Unexpected error.
Write-Error 'Scheduling a shutdown failed unexpectedly.'
exit $LASTEXITCODE
}
# Persist the scheduled shutdown time in a file, so that
# if this script gets killed, we can resume the countdown on re-execution.
$shutdownTime.ToString('o') > $lastScheduleFile
}
# Show a countdown display or handle a preexisting shutdown request,
# with support for Ctrl-C in order to cancel.
$ctrlCPressed = $true
try {
[Console]::CursorVisible = $false
# Display a countdown to the shutdown.
do {
$secsRemaining = ($shutdownTime - [datetime]::UtcNow).TotalSeconds
$timespanRemaining = $shutdownTime - [datetime]::UtcNow
Write-Host -NoNewline ("`r" + 'SHUTTING DOWN in {0:hh\:mm\:ss}, at {1}. Press Ctrl-C to CANCEL.' -f $timespanRemaining, $shutdownTime.ToLocalTime())
Start-Sleep -Seconds 1
} while ($secsRemaining -gt 0)
# Getting here means that Ctrl-C was NOT pressed.
$ctrlCPressed = $false
}
finally {
# Note: Only Write-Host statements can be used in this block.
[Console]::CursorVisible = $true
if ($ctrlCPressed) {
# Abort the pending shutdown.
shutdown /a *>$null
switch ($LASTEXITCODE) {
0 { Write-Host "`nShutdown aborted by user request." }
1116 { Write-Host "`n(Shutdown has already been canceled.)" }
default { Write-Host "`nUNEXPECTED ERROR trying to cancel the pending shutdown."; exit $_ }
}
}
# Clean up the file in which the last schedule attempt is persisted.
Remove-Item -ErrorAction Ignore $lastScheduleFile
# Note: We consider this way of exiting successful.
# If the shutdown is allowed to take place, this script never returns to a caller.
# If it *does* return:
# * If it is due to a *failure to even schedule* the shutdown (see above), it will be nonzero.
# * 0 therefore implies having successfully aborted (canceled) the shutdown.
exit 0
}
字符串
剧本运行得相当好,除了几件事;但我有几样东西想要。
1)如果存在关机请求,当我们按Ctrl-C键时,脚本会自动取消该请求。但我不想他直接取消。在取消之前,我希望它给予我一个选项“你确定要取消现有的关机倒计时(Y/N)?:“.
**2)**在当前脚本中按Ctrl-C键后,关机请求被取消,并在终端中给出如下警告:
第一个月
选择并输入Y后,端子关闭。然而,在以相同的方式选择并输入N之后,终端也被关闭。
现在我需要这个。如果我选择N选项,终端就不会关闭;让我输入一个新的关机请求换句话说应该给予我一个选项,设置一个新的关机后,目前的关机被取消。
如果有人知道这个问题,我想让他知道我真诚地表达我的感激之情。
1条答案
按热度按时间klr1opcd1#
如the answer that you took the code in the question from所示:
try
/catch
/finally
statement的finally
块处理Ctrl-C限制了您的 * 清理 * 操作-您的脚本将 * 总是 * 终止。[Console]::TreatControlCAsInput
= $true
的自定义键盘轮询循环,如this answer所示,并在下面的代码上下文中说明。这种方法还意味着您正在调用PowerShell脚本的批处理文件不会看到Ctrl-C键,因此不会显示可怕的
Terminate batch job (Y/N)?
提示符,该提示符无法被抑制(请参阅this answer)。这里有一个简化的概念证明,展示了核心技术;它循环CA。10秒,在此期间检测Ctrl-C键:
字符串
您的代码上下文中的完整解决方案:
R
(恢复)choice.exe
选项,可让您恢复当前的关机计划并关机。型