Migrate to Windows 11 with PSADT

Explore a practical method to upgrade devices using PSADT. A reliable approach for IT teams looking to simplify Windows 11 migrations.
Picture of Perica

Perica

In our previous blog posts, we explored different approaches to migrating to Windows 11: using SCCM, through XOAP, via GPOs and registry keys and Windows Update in Settings. In this post, we’ll walk you through yet another method – deploying the Windows 11 upgrade package using our PowerShell App Deployment Toolkit (download it here for free).

Use PSADT to migrate from Windows 10 to Windows 11

To get started, extract the contents of your Windows 11 ISO file and include them in your PSADT package. Then, you’ll use the setup.exe file from the extracted ISO along with specific command-line parameters to upgrade from Windows 10 to Windows 11.

Once you’ve got your source file ready, it’s time to modify the “Deploy-Application.ps1” script. In the pre-installation part, it will check if a scheduled task exists and delete it (in case of failures/reruns).

				
					#### (Pre-Install) Delete Scheduled Task -------------------------------------------->
$DELTaskName = 'Win11Upgrade'
# Check if the task exists
$DELTaskExists = Get-ScheduledTask -TaskName $DELTaskName -ErrorAction SilentlyContinue
if ($DELTaskExists) {
    # Delete the task
    Unregister-ScheduledTask -TaskName $DELTaskName -Confirm:$false
    Write-Output "(Pre-Install) Task '$DELTaskName' has been deleted."
} else {
    Write-Output "(Pre-Install) Task '$DELTaskName' does not exist.  Moving on to Installation"
}

				
			

In the installation part, a scheduled task will be created and started. While loop is used to check if the task is still running after it was started.

				
					 ###># CREATE SCHEDULED TASK -------------------------------------------------------->
    $STExecutable = "$dirfiles\ISO\Setup.exe"
    $STArguments = "/Auto Upgrade /EULA accept /NoReboot"
    $STTaskName = "Win11Upgrade"
    $STTriggerTime = (Get-Date).AddSeconds(15)
    $STPriority = 4
    $STTrigger = New-ScheduledTaskTrigger -Once -At $STTriggerTime
    $STSettings = New-ScheduledTaskSettingsSet -StartWhenAvailable -Priority $STPriority -RunOnlyIfNetworkAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
    # Create a new scheduled task action
    $STAction = New-ScheduledTaskAction -Execute $STExecutable -Argument $STArguments -WorkingDirectory (Split-Path $STExecutable)
    # Create a new scheduled task principal for the SYSTEM account
    $STPrincipal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest
    # Create and register the new scheduled task
    $STTask = New-ScheduledTask -Action $STAction -Trigger $STTrigger -Settings $STSettings -Principal $STPrincipal
    Register-ScheduledTask -TaskName $STTaskName -InputObject $STTask

    #### KICK OFF SCHEDULED TASK ------------------------------------------------------>
    Start-Sleep 10
    Start-ScheduledTask -TaskName "Win11Upgrade"
    #### MONITOR SCHEDULED TASK ------------------------------------------------------->
    $STTaskName = "Win11Upgrade"
    # Loop until the task is no longer running
    while ((Get-ScheduledTask -TaskName $STTaskName).State -eq "Running")
    {
        # Get task information
        $taskInfo = Get-ScheduledTaskInfo -TaskName $STTaskName
        # Verify if the task is being run by SYSTEM
        if ((Get-ScheduledTask -TaskName $STTaskName).Principal.UserId -eq "SYSTEM")
        {
            # Write to the output
            Write-Output "$STTaskName is still running as SYSTEM"
        }
        else
        {
            Write-Output "$STTaskName is still running, but not as SYSTEM"
        }
        # Wait for 10 seconds before checking again
        Start-Sleep -Seconds 10
    }
    Write-Output "$STTaskName has finished running"

				
			

 In the post-installation part, created scheduled task is deleted.

				
					#### (Post-Install) Delete Scheduled Task -------------------------------------------->
    $DELTaskName = "Win11Upgrade"
    # Check if the task exists
    $DELTaskExists = Get-ScheduledTask -TaskName $DELTaskName -ErrorAction SilentlyContinue
    if ($DELTaskExists) {
        # Delete the task
        Unregister-ScheduledTask -TaskName $DELTaskName -Confirm:$false
        Write-Output "(Post-Install) Task '$DELTaskName' has been deleted."
    } else {
        Write-Output "(Post-Install) Task '$DELTaskName' does not exist."
    }

				
			

There are a couple of options to consider if you want to expand on this package:

  • Add Windows 11 prerequisites check
  • Expand it with PSADT functions like:
    – Show-InstallationWelcome
    – Show-InstallationProgress
    – Show-InstallationRestartPrompt
  • Adjust available scheduled task options:
    – RunOnlyIfNetworkAvailable
    – AllowStartIfOnBatteries
    – DontStopIfGoingOnBatteries
  • Add other parameters to setup.exe run (for example “/Product Server” as a workaround for the prerequisites check)

You're good to go!

Upgrading to Windows 11 with PSADT is a flexible option if you want more control over the process. With a few script tweaks, you can handle the upgrade from start to finish.

More blog posts like this one

Windows 11 migration made easy with XOAP automation platform
Tutorials

Windows 11 migration made easy with XOAP

Upgrading to Windows 11 is simple with XOAP, whether you’re handling one device or many. In this blog, we’ll take you through the exact steps to get everything set up.

Scroll to Top