cancel
Showing results for 
Search instead for 
Did you mean: 

Automatic Shutdown

cali
Novitiate II

This document details the "Automatic Shutdown" project, developed using a PowerShell script running on JumpCloud. The main objective is to automate system shutdown when a computer remains idle for a specific period.

Target Audience:

  • JumpCloud administrators
  • System administrators interested in managing idle computer shutdown

Project Overview:

  • Platform: JumpCloud
  • Scripting Language: PowerShell
  • Functionality: Detects idle user activity and initiates automatic system shutdown.
  • Key Features:
    • Idle Time Detection using Win32 API
    • Configurable Timeout
    • Forced Shutdown
    • User Confirmation Prompt
    • RunAsCurrentUser Execution

Code Structure:

  1. Dependency Checks:
    • Installs NuGet and RunAsUser PowerShell module if missing.
  2. Command Block:
    • Encapsulates the core shutdown logic within a scriptblock.
  3. Idle Time Tracking:
    • Leverages PInvoke to access Win32 API's GetLastInputInfo function for accurate idle time measurement.
  4. Shutdown Threshold:
    • Sets a configurable idle threshold in seconds ($idleThreshold) to trigger shutdown.
  5. Continuous Monitoring:
    • Employs a while loop to continuously check idle time.
  6. Shutdown Initiation:
    • If idle time exceeds the threshold:
      • Initiates shutdown with a 30-second delay using shutdown.exe.
      • Displays a confirmation prompt using a WScript.Shell message box.
      • If the user confirms (clicks OK), aborts shutdown using shutdown -a.
      • If no interaction, proceeds with shutdown using Stop-Computer -Force.
  7. Execution Context:
    • Uses Invoke-AsCurrentUser to execute the scriptblock in the context of the current user, ensuring proper idle time detection.

Additional Notes:

  • Testing: Thoroughly test the script in a controlled environment before deployment.
  • Timeout Configuration: Adjust the $idleThreshold value to suit your needs.
  • Exclusions: Consider adding logic to exclude specific applications or processes from triggering shutdown.
  • JumpCloud Integration: Explore options for centralized configuration and reporting through JumpCloud policies and tools.
  • Error Handling: Implement error handling and logging for enhanced reliability.

Benefits:

  • Energy savings
  • Enhanced security
  • Improved resource management
  • Compliance with organizational policies

Conclusion:

This project demonstrates the value of PowerShell automation for managing idle computer shutdown on JumpCloud. By combining idle time detection, configurable timeouts, user confirmation, and proper execution context, it provides a flexible and effective solution for optimizing resource utilization and security.


Code Highlights:

# If Nuget is not installed, go ahead and install it
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$PkgProvider = Get-PackageProvider
If ("Nuget" -notin $PkgProvider.Name){
    Install-PackageProvider -Name NuGet -Force
}

# If PSModule RunAsUser is not installed, install it
if ( -not (get-installedModule "RunAsUser" -ErrorAction SilentlyContinue)) {
    install-module RunAsUser -force
}



$Command = {
    #Powershell Command Goes Here - paste your code:

    <#  testing the accuracy of GetLastInputInfo - testing Idle Time (Done)#>

    <#  testing the accuracy of GetLastInputInfo - testing Idle Time (Done)#>


Add-Type @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PInvoke.Win32 {
    public static class UserInput {
        [DllImport("user32.dll", SetLastError=false)]
        private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

        [StructLayout(LayoutKind.Sequential)]
        private struct LASTINPUTINFO {
            public uint cbSize;
            public int dwTime;
        }

        public static DateTime LastInput {
            get {
                DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount);
                DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks);
                return lastInput;
            }
        }

        public static TimeSpan IdleTime {
            get {
                return DateTime.UtcNow.Subtract(LastInput);
            }
        }

        public static int LastInputTicks {
            get {
                LASTINPUTINFO lii = new LASTINPUTINFO();
                lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
                GetLastInputInfo(ref lii);
                return lii.dwTime;
            }
        }
    }
}
'@

# Set the idle threshold for shutdown (in seconds)
$idleThreshold = 20  # Adjust this value as needed

while ($true) {
    $idleTime = [PInvoke.Win32.UserInput]::IdleTime.TotalSeconds
    Write-Host ("Idle for: $idleTime seconds")

    if ($idleTime -ge $idleThreshold) {
        Write-Host "User is idle for $idleThreshold seconds. Initiating shutdown..."

        # Initiate shutdown with a delay
        Start-Process -FilePath "shutdown" -ArgumentList "-s -t 30" -NoNewWindow -Wait

        # Prompt the user to confirm or abort shutdown # Display message box
        $confirmation = (New-Object -ComObject WScript.Shell).Popup("If you see this and don't want to shut down the PC, just click OK.", 0, "Shutdown Cancellation", 1)

        if ($confirmation -eq 1) {
            # User clicked OK, abort shutdown
            Write-Host "Shutdown aborted by user."
            # Abort the shutdown using shutdown -a
            Start-Process -FilePath "shutdown" -ArgumentList "-a" -NoNewWindow -Wait


        } else {
            # User didn't interact, allow shutdown to proceed
            Write-Host "Shutting down..."
         
            # Implement your shutdown logic here
            Stop-Computer -Force
        }
    }

    Start-Sleep -Seconds 20  # Check every 20 seconds
}

# end

}

invoke-ascurrentuser -scriptblock $Command



1 REPLY 1

urvashi
Bronze I
Bronze I

@cali thank you for taking the time to share such a detailed guide with the community! We appreciate you 🙂