OOBE Challenges #2: A Better Solution

I had previously written about OOBE challenges here, and the solution I found was somewhat of a workaround.

Some of my customers are satisfied with these scheduled tasks, but I’ve received comments on the blog and on Twitter that this flow is not very reliable.

I started thinking about a better way to execute the process in the OOBE phase during OSD. For testing purposes, I created a simple batch file in the C:\Windows\Setup\Scripts folder, where SetupComplete.cmd is also located. And guess what? It was executed before the (real) OOBE phase began, without using any scheduled task or ServiceUI.exe.

Note: for me, the real OOBE phase is where the region and keyboard settings have to be selected.

Below, you can find a simple way to trigger your tasks after OS installation and after the specialize phase. Once you understand the solution, everything becomes simple and easy. 😉

Write-Host -ForegroundColor Green "Downloading and creating script for OOBE phase"
Invoke-RestMethod https://raw.githubusercontent.com/AkosBakos/OSDCloud/main/Set-KeyboardLanguage.ps1 | Out-File -FilePath 'C:\Windows\Setup\scripts\keyboard.ps1' -Encoding ascii -Force
Invoke-RestMethod https://raw.githubusercontent.com/AkosBakos/OSDCloud/main/Install-EmbeddedProductKey.ps1 | Out-File -FilePath 'C:\Windows\Setup\scripts\productkey.ps1' -Encoding ascii -Force
Invoke-RestMethod https://check-autopilotprereq.osdcloud.ch | Out-File -FilePath 'C:\Windows\Setup\scripts\autopilotprereq.ps1' -Encoding ascii -Force
Invoke-RestMethod https://start-autopilotoobe.osdcloud.ch | Out-File -FilePath 'C:\Windows\Setup\scripts\autopilotoobe.ps1' -Encoding ascii -Force


$OOBECMD = @'
@echo off
# Execute OOBE Tasks
start /wait powershell.exe -NoL -ExecutionPolicy Bypass -F C:\Windows\Setup\Scripts\keyboard.ps1
start /wait powershell.exe -NoL -ExecutionPolicy Bypass -F C:\Windows\Setup\Scripts\productkey.ps1
start /wait powershell.exe -NoL -ExecutionPolicy Bypass -F C:\Windows\Setup\Scripts\autopilotprereq.ps1
start /wait powershell.exe -NoL -ExecutionPolicy Bypass -F C:\Windows\Setup\Scripts\autopilotoobe.ps1

# Below a PS session for debug and testing in system context, # when not needed 
# start /wait powershell.exe -NoL -ExecutionPolicy Bypass

exit 
'@
$OOBECMD | Out-File -FilePath 'C:\Windows\Setup\scripts\oobe.cmd' -Encoding ascii -Force

After using this method, don’t forget to cleanup this C:\Windows\Setup\scripts folder like this:

Remove-Item C:\Windows\Setup\Scripts\*.* -Exclude *.TAG -Force | Out-Null

I hope you are disabling shift + F10 during the OSD phase with this simply file: C:\Windows\Setup\Scripts\DisableCMDRequest.TAG. More details please find Michael’s great blog post.

Bonus: please note, if you are working and executing scripts in the OOBE phase, the process will automatically create a new user, defaultuser0. The scripts run in this user’s context.

After the OSD finishes, this account should be removed. You can find a remediation script in my GitHub repo. KUDOS to Ermanno Goletto for the cleanup function.

Please leave a comment about how easy or easier this method is compared to creating two scheduled tasks.

13 Comments


    1. Any logs in this folder?
      $env:ProgramData\Microsoft\IntuneManagementExtension\Logs\OSD\

      Reply

  1. Yes there are this 3 Logfiles:
    1) Set-KeyboardLanguage.log
    2) Install-EmbeddedProductKey.log
    3) Check-AutopilotPrerequisites.log

    1 + 2 looks good.

    #3 (Check-AutopilotPrerequisites.log)

    Shows this in the beginning:
    ######################################
    # Start Autopilot prerequisite check #
    ######################################

    ———————————
    | Device information |
    ———————————
    Get-ItemPropertyValue : Cannot find path ‘HKLM:\SOFTWARE\Microsoft\Provisioning\AutopilotPolicyCache’ because it does
    not exist.
    At C:\Program Files\WindowsPowerShell\Scripts\Check-AutopilotPrerequisites.ps1:57 char:23
    + … ilotCache = Get-ItemPropertyValue -Path “HKLM:\SOFTWARE\Microsoft\Pro …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (HKLM:\SOFTWARE\…ilotPolicyCache:String) [Get-ItemPropertyValue],
    ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand
    Get-ItemPropertyValue : Cannot find path ‘HKLM:\SOFTWARE\Microsoft\Provisioning\AutopilotPolicyCache’ because it does
    not exist.
    At C:\Program Files\WindowsPowerShell\Scripts\Check-AutopilotPrerequisites.ps1:57 char:23
    + … ilotCache = Get-ItemPropertyValue -Path “HKLM:\SOFTWARE\Microsoft\Pro …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (HKLM:\SOFTWARE\…ilotPolicyCache:String) [Get-ItemPropertyValue], Item
    NotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyValueCommand

    All other tests are good

    Reply

    1. That looks good. Meaning, that the scripts have been executed successfully.
      Now you can debug each for these scripts what they are doing wrong and/or which scripts you really need in this phase.

      Reply

      1. I have the oobe.cmd placed in the Setup\Script folder, after OCD does its thing it boots up to the AutopilotOOBE Gui but you can’t click the Register button as it states that it needs to run as default0 user which does not exist. If I put the oobe.cmd somewhere else and use Shift/F10 and run it manually it works just fine. I must be missing something as I thought it would trigger the Gui automatically and be able to register

        Reply

        1. Nope, you are right: executing OOBE.cmd like this blog post said, we are SYSTEM.
          If you (manually) click Shift+F10, we are DefaultUserX.

          You can automate the AutopilotOOBE part with the well-known Get-WindowsAutopilotInfo and/or with the Get-WindowsAutopilotInfoCOMMUNITY version.

          Reply

          1. If you look at the Get-WindowsAutopilotInfo scriot, you realize that there is only a couple of infos you need. Get the hash, get the serial and the product key (empty) and use a group tag. With this infos you will be able to automate the registration using an Azure Function. No GUI or user interacton at all.


  2. Hi Akos,

    You still have to run oobe.cmd from SetupComplete.cmd correct?

    Or do you mean that you can put other .cmd files in the Scripts folder and those files will also run?

    Reply

    1. Hi Johan,

      these two scripts are complete separately.
      First, the SetupComplete.cmd will be executed and in the next OSD stage comes the OOBE.cmd.

      Reply

  3. Thanks for all the tipps and tricks, i have still the issue, the when the oobe.cmd is launched i dit not get the script for autopilot running , it shows me install error messages. if the loading screen is there to select language its working, but i want te upload automatcly to happen.

    The variable ‘$Script:PSGetSettingsFilePath’ cannot be retrieved because it has not been set.
    CategoryInfo: InvalidOperation: (script:PSGetSettingsFilePath:String) [], RuntimeException
    FullyQualifiedErrorId: VariableIsUndefined
    You cannot call a method on a null-valued expression.
    CategoryInfo: InvalidOperation: (:) [], RuntimeException
    FullyQualifiedErrorId: InvokeMethodOnNull
    Cannot index into a null array.
    CategoryInfo: InvalidOperation: (:) [], RuntimeException
    FullyQualifiedErrorId: NullArray
    WARNING: The property ‘Values’ cannot be found on this object. Verify that the property exists.
    WARNING: The property ‘Keys’ cannot be found on this object. Verify that the property exists.
    WARNING: The variable ‘$script:PSGetModuleSourcesFilePath’ cannot be retrieved because it has not been set.
    PackageManagement\Install-Package : No match was found for the specified search criteria and script name “Get-WindowsAutoPilotInfo”. Try Get-PSRepository to see all available registered script repositories.
    CategoryInfo: ObjectNotFound: (Microsoft.Power….InstallPackage:InstallPackage) [Install-Package], Exception
    FullyQualifiedErrorId: NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackage

    Any Ideas ?

    How can i add my own entries to the SetupComplete.cmd ?
    I also uploaded all my scripts to GIT.

    Greetings

    Benni

    Reply

    1. Hi Benni,

      If you work with AutopilotOOBE, start it in the OOBE phase as defaultuser0 with Shift+F10.
      Otherwise you can start it in the earlier phase with Get-WindowsAutopilotInfo.
      You can try to define these variables in your script:
      $env:APPDATA = “C:\Windows\System32\Config\SystemProfile\AppData\Roaming”
      $env:LOCALAPPDATA = “C:\Windows\System32\Config\SystemProfile\AppData\Local”
      $Env:PSModulePath = $env:PSModulePath+”;C:\Program Files\WindowsPowerShell\Scripts”
      $env:Path = $env:Path+”;C:\Program Files\WindowsPowerShell\Scripts”

      In the easiest way to define your own SetupComplete.cmd is to do like this:
      $SetupCompleteCMD = @’
      ECHO SetupComplete Phase
      ‘@
      $SetupCompleteCMD | Out-File -FilePath ‘C:\Windows\Setup\Scripts\setupcomplete.cmd’ -Encoding ascii -Force

      Reply

      1. Hi Akos,

        I found that with oobe.cmd, not all PowerShell modules will run, including Get-WindowsAutopilotInfo. Do you think it would be better to move the contents of oobe.cmd into setupcomplete.cmd and use that instead? This Autopilot automatic registration process is driving me crazy!

        Would it make sense to set up a scheduled task to run at startup, just once, to trigger my scripts before the first user login?

        Thanks so much for your help; I really appreciate your blog. It’s been a great source of information!

        greetings

        Reply

      2. A forgot to ask, i got a lot of trouble with that WINPE Drivers, i always get messages from our other IT Colleagues, installation dont work, they always show me the overview with the missing drivers, but there are no network or storage controllers listed.

        then from one model one works and the other not, its quiet confusing. i already imported all lenovo,dell,hp winpe drivers but still there popping up such issues and dont know how i should tackle them.

        greetings

        Reply

Leave a Reply

Your email address will not be published. Required fields are marked *