maintenance ahead

Introduction

A common challenge faced by administrators transitioning from ConfigMgr (SCCM) to Intune is the perceived lack of control over application installation and reboot timing. ConfigMgr’s robust capabilities allow precise scheduling for application installations and reboots, minimizing disruption for end users. Intune, while powerful in its own right, lacks some of these granular controls, leading to concerns about application deployment timing and system reboots.

To address this gap, we’ve developed a PowerShell script that offers a simple yet effective solution for controlling application installations in Intune. While it doesn’t replicate the full feature set of ConfigMgr, this script provides a practical workaround to manage installation timing, aiming to install applications during specified maintenance windows.

The Solution: A PowerShell Script

This PowerShell script determines whether the current local time falls within a predefined maintenance window (10 PM to 5 AM). If it does, the script allows the application installation to proceed. If not, it creates a scheduled task to run an Intune Management Extension (IME) sync during the next maintenance window. This sync increases the chances that the computer checks for policy updates and installs the application during the maintenance window.

Script Overview

The script performs the following tasks:

  1. Check Current Time: Determines if the current time is within the maintenance window.
  2. Create a Scheduled Task: If the current time is outside the maintenance window, it creates a scheduled task to run a script that triggers an IME sync during the next maintenance window.
  3. Handle Existing Scripts and Tasks: Ensures old scripts and tasks are cleaned up before creating new ones.

Full Script

For your reference, here’s the complete script:

PowerShell
<#
.SYNOPSIS
This PowerShell script determines if the current local time falls between 10 PM (22:00) and 5 AM (05:00).

.DESCRIPTION
Retrieves the current local time, extracts the hour, and checks if it is within the specified range.
Based on the result, it either proceeds with the installation or creates a scheduled task to sync Intune during the maintenance window (MW).
If the current time is within the MW, it outputs a message to install and exits with a success code.
If the current time is not within the MW, it outputs a message not to install, creates a scheduled task to run hourly from 11 PM for 5 hours syncing Intune policies, and exits with a non-success code.

Script Name: Intune_MaintenanceWindow.ps1
Author: John Marcum (PJM)
Date: 7/01/2024
Version: 1.0

.NOTES
This script can be used as a requirement rule for Intune Win32 app deployments to control installation timing based on maintenance windows.

# LEGAL DISCLAIMER
# This script is provided "as is" without any warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability, fitness for a particular purpose, or non-infringement. The entire risk as to the quality and performance of the script is with you.
# In no event shall the authors or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the script or the use or other dealings in the script.
# You should never run any script from the Internet without understanding its contents and effects. It is highly recommended that you thoroughly test the script in a safe environment before running it in production.
#>

# Get the current local time and extract the hour as integer
$currentTime = Get-Date -UFormat %R
$Hour = $currentTime.Split(":")[0]
$intHour = [int]$Hour

# Check if the current time is between 10 PM (22:00) and 5 AM (05:00)
$isInMaintenanceWindow = ($intHour -ge 22) -or ($intHour -le 5)

# Output the boolean value
Write-Host " Is in maintenance windows? $($isInMaintenanceWindow)"

# If the current time is within the maintenance window, exit with success code
if ($isInMaintenanceWindow) {
    # Current time is within the maintenance window. Install the app
    Write-Host "Install at $($intHour)"
    Write-Output -inputobject $isInMaintenanceWindow
    Exit 0
} else {
    # Current time is not within the maintenance window. Do not install the app. Create a scheduled task to sync Intune during the MW in hopes of getting the app to install when we want it to.
    Write-Host  "Do Not install at $($intHour)"
    
    # Define the folder and script path
    $folderPath = "C:\Temp"
    $scriptPath = "$folderPath\Invoke-IntuneSyncApp.ps1"

    # Ensure the folder exists
    if (-not (Test-Path -Path $folderPath)) {
        New-Item -Path $folderPath -ItemType Directory | Out-Null
    }

    # Check for and delete any old script
    if (Test-Path -Path $scriptPath) {
        Remove-Item -Path $scriptPath -Force
    }

    # Create the PowerShell script
    @"
$Shell = New-Object -ComObject Shell.Application
$Shell.open("intunemanagementextension://syncapp")
"@ | Set-Content -Path $scriptPath
    
    # Define the task name
    $taskName = "IntuneSyncApp"

    # Check if the scheduled task already exists
    $taskExists = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue

    if ($null -eq $taskExists) {
        try {
            # Define the start time
            $startTime = (Get-Date).Date.AddHours(23)  # 11 PM today

            # Create and register the task with the EndBoundary set after creation
            Register-ScheduledTask -TaskName $taskName -User "NT AUTHORITY\SYSTEM" -InputObject (
                (
                    New-ScheduledTask -Action (
                        New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-noprofile -executionpolicy bypass -File `"$scriptPath`""
                    ) -Trigger (
                        New-ScheduledTaskTrigger -Once -At $startTime
                    ) -Settings (
                        New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 1) -DeleteExpiredTaskAfter (New-TimeSpan -Minutes 1)
                    )
                ) | % { $_.Triggers[0].EndBoundary = $startTime.AddMinutes(60).ToString('s') ; $_ } # Run through a pipe to set the end boundary of the trigger
            )

            Write-Host  "Scheduled task '$taskName' created successfully."
        } catch {
            Write-Host  "Failed to create scheduled task '$taskName'. Error: $_"
        }
    } else {
        Write-Host  "Scheduled task '$taskName' already exists. No action taken."
    }

    # Exit with false so the app does not install!
    Write-Output -inputobject $isInMaintenanceWindow
    Exit 0
}

Key Features of the Script

  1. Time-Based Decision Making: The script checks if the current time is within the maintenance window. If it is, the installation proceeds immediately.
  2. Scheduled Task Creation: If the current time is outside the maintenance window, the script creates a scheduled task to run a PowerShell script that triggers an IME sync at the next available maintenance window.
  3. Script and Task Management: The script ensures that any existing script or task is removed before creating new ones, preventing conflicts and ensuring a clean setup.
  4. Error Handling: The script includes robust error handling to ensure administrators are informed if the scheduled task creation fails.

Using the Script in Intune Win32 App Requirement Rule

To use this script as a requirement rule in an Intune Win32 app deployment, follow these steps:

  1. Create the PowerShell Script: Save the provided PowerShell script as Check-InstallationWindow.ps1.
  2. Create the Win32 App:
    • Package your application using the Microsoft Win32 Content Prep Tool.
    • In the Intune portal, go to Apps > Windows > Add.
    • Select Windows app (Win32) and upload the .intunewin file created by the Content Prep Tool.
  3. Define the required settings for the Program.
  4. In the Requirements section:
    1. Select the Operating system architecture and the minimum operating system requirements.
    2. Add the Requirement Script:
      1. Select + Add to add a new requirement rule.
      2. Choose Script as the requirement type.
      3. Select the Check-InstallationWindow.ps1 script to upload it.
      4. Set Select output data type to Boolean.
      5. Set Operator to Equals.
      6. Set the Value to Yes.
  5. Define the Detection rules.
  6. Assign the App: Assign the application to the desired user or device groups.

Benefits and Limitations

While this script provides a simple and effective solution for controlling application installation timing in Intune, it does have some limitations compared to ConfigMgr:

  • Granularity: ConfigMgr offers more granular control over maintenance windows and deployment schedules.
  • Reboot Management: This script does not handle reboots; however, this can be controlled with the app deployment settings. 
  • System Availability: The script depends on the system being powered on during the maintenance window. If the system is powered off, the task will not run as scheduled.
  • Intune Policy Retrieval: Windows 10/11 devices perform policy refresh cycles approximately every 8 hours. In an effort to ensure the device(s) perform a policy refresh cycles during the maintenance window this script creates a scheduled task to perform a policy refresh cycle at 11pm. YMMV.

Despite these limitations, this script offers a practical workaround for administrators looking to regain some control over application deployment timing in Intune.

Conclusion

Transitioning from ConfigMgr to Intune can be challenging, especially when it comes to managing maintenance windows. This PowerShell script provides a simple yet effective solution for controlling application installations during specified maintenance windows, helping to minimize disruption for end users. While it may not offer the full robustness of ConfigMgr, it serves as a valuable tool for administrators seeking to enhance their control over Intune deployments.

By incorporating this script into your Intune deployment process, you can aim for applications to be installed during designated maintenance windows, providing a more controlled and predictable deployment experience. However, it’s important to note that this solution is not foolproof and relies on systems being powered on during the maintenance windows as well as other unforeseen factors.