windowspowershellbatch-filecmdshutdown

How can we create a .BAT file that can turn off the computer after a desired time and show the remaining time on each boot?


I wanted to prepare a .BAT file to automatically shut down the computer after a desired time.

And according to the information I got, I was able to create a code directory like the one below.

But at some point it doesn't accomplish anything I want.

@echo off
setlocal

set /p hours=Please enter the number of hours to shut down your computer (leave blank for only minutes): 
set /p minutes=Please enter the number of minutes to shut down your computer: 

set total_minutes=0
if defined hours set /a total_minutes=%hours% * 60
set /a total_minutes+=minutes

REM Check if there is an active shutdown request
for /F "tokens=2,3,4 delims=:." %%a in ('shutdown /a 2^>nul ^| findstr /C:"time remaining"') do (
    set /a remaining_minutes=%%a*60+%%b
    set /a elapsed_minutes=%total_minutes% - %remaining_minutes%
    set /a new_total_minutes=%total_minutes% - %elapsed_minutes%
)

REM Display active shutdown request countdown if applicable
if defined remaining_minutes (
    echo There is a shutdown request currently active.
    echo The duration of the shutdown request is %remaining_minutes% minutes, and %elapsed_minutes% minutes have passed since the shutdown request was created.
    echo %remaining_minutes% minutes remaining until shutdown.
    echo Press Ctrl+C to cancel the shutdown.
    echo.
    choice /T 60 /C CN /D C > nul
    if errorlevel 2 (
        echo Continuing with the shutdown.
        goto SHUTDOWN
    ) else (
        echo Shutdown canceled.
        exit /b
    )
)

REM Display initial countdown information if no active shutdown request
echo Your computer will be shut down in %total_minutes% minutes.
echo Press Ctrl+C to cancel the shutdown.
echo.
choice /T 60 /C CN /D C > nul
if errorlevel 2 (
    echo Continuing with the shutdown.
    goto SHUTDOWN
) else (
    echo Shutdown canceled.
    exit /b
)

:SHUTDOWN
shutdown /s /t 0

1) When we run the bat file as "Administrator", we first encounter a screen asking how many hours we want the computer to be shut down. When we leave this part blank, we can log in directly in minutes. Or by answering "1" to the first question and "45" to the second question, we can set the computer to shut down after "1 Hour and 45 Minutes".

However, when I want to add a countdown that shows the current screen to be turned off in 60 seconds after entering this information, I cannot do it.

It needs to give us a 60 second countdown to cancel the current transaction; but I can't see any countdown on the screen. And the screen turns off automatically after 60 seconds.

2) When I run the .BAT File again, I want it to check if there is an active shutdown request and present it to us. However, when I run the file, it does not present this information to us.

I tried to do this; but it didn't work. If there is an existing shutdown request, it should specify each time the .BAT file is run.

Example: There is an active shutdown request currently set to 95 minutes. This request was created 15 minutes ago and has 80 minutes until the computer shuts down.

If you want to cancel this request, please press CTRL+C.

I don't know if this is possible; However, I think that the .BAT file can create a .TXT file in the %TEMP% folder and present us whether there is an active shutdown and the remaining time according to the information in that .TXT file. Or another way.

If there is someone who has knowledge on this subject, I would like him to know that I am expressing my gratitude with all my sincerity.


Solution

  • Since you also tagged your question , find a PowerShell solution below.

    As for what you tried:


    PowerShell solution:
    # 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 {
        $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 ($timespanRemaining -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
    }