55 Comments
User's avatar
John Philipson's avatar

Hi Brady, really excellent article.

I just wondered, as I'm using a Windows 11 deployment - where the reference to "Windows 10 Device Provisioning Tool" can be edited to say "Windows 11 Device Provisioning Tool" or to actually use the correct tool ?

Expand full comment
Aaron Monson's avatar

I want to thank you for this.

I thought I would give you a heads up about an adjustment I did with the Drivers.

I adjusted it so it only grabbed the drivers for the current model of device. Lenovo is a bit different as it goes by a random deviceID rather than the actual name, but as long as you have the Device Name in the driver folder you can have all drivers for each model in your fleet.

#region Bootstrap drivers

$computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem

$manufacturer = $computerSystem.Manufacturer

$model = $computerSystem.Model

Write-Host "`nDevice Model: " -ForegroundColor Yellow -NoNewline

Write-Host $model -ForegroundColor Cyan

# Determine the folder name based on the manufacturer

if ($manufacturer -eq "LENOVO") {

$folderName = $model.Substring(0, 4)

} else {

$folderName = $model

}

Write-Host "Using folder name: $folderName" -ForegroundColor Yellow

# Construct the path to the model-specific driver folder

$driverFolderPath = Join-Path -Path $usb.driverPath.FullName -ChildPath $folderName

# Get the drivers from the model-specific folder

$drivers = Get-ChildItem -Path $driverFolderPath -Filter *.inf -Recurse

if ($drivers) {

Write-Host "Bootstrapping found drivers into WinPE Environment.." -ForegroundColor Yellow

foreach ($d in $drivers) {

. drvload $d.FullName

}

} else {

Write-Host "No drivers detected in $driverFolderPath" -ForegroundColor Yellow

}

Expand full comment
Brady Widener's avatar

Great work!!

I'll be sure to add this to my future drives as well. Thanks!

Expand full comment
John Philipson's avatar

Thanks Aaron,

I've modified your script slightly to reference the E:\drivers folder based on 4 different models of HP Elite x360 models (see script below with reference to manufatcurer = HP and $folderName = $model.Substring(0, 30) ,

So using folder structure like E:\Drivers\HP Elite x360 1040 14 inch G9, E:\Drivers\HP EliteBook x360 1040 G6 No etc.., I expected it to look for inf files in just one folder but it still searches the entire contents of the root (E:\drivers). Is this because the script still uses this line (line 23) - $this.driverPath = "$($this.installRoot)Drivers"

#region Bootstrap drivers

$computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem

$manufacturer = $computerSystem.Manufacturer

$model = $computerSystem.Model

Write-Host "`nDevice Model: " -ForegroundColor Yellow -NoNewline

Write-Host $model -ForegroundColor Cyan

# Determine the folder name based on the manufacturer

if ($manufacturer -eq "HP") {

$folderName = $model.Substring(0, 30)

} else {

$folderName = $model

}

Write-Host "Using folder name: $folderName" -ForegroundColor Yellow

# Construct the path to the model-specific driver folder

$driverFolderPath = Join-Path -Path $usb.driverPath.FullName -ChildPath $folderName

# Get the drivers from the model-specific folder

$drivers = Get-ChildItem -Path $driverFolderPath -Filter *.inf -Recurse

if ($drivers) {

Write-Host "Bootstrapping found drivers into WinPE Environment.." -ForegroundColor Yellow

foreach ($d in $drivers) {

. drvload $d.FullName

}

} else {

Write-Host "No drivers detected in $driverFolderPath" -ForegroundColor Yellow

}

Expand full comment
John Philipson's avatar

Actually, got this working by adding the following line changes - swapping in $driverFolderPath for the original $($usb.driverPath) & $usb.driverPath

#region Applying drivers

if (Get-ChildItem "$driverFolderPath\*.inf" -Recurse -ErrorAction SilentlyContinue) {

Write-Host "`nApplying drivers.." -ForegroundColor Yellow

Add-Driver -driverPath $driverFolderPath -scratchDrive $usb.scRoot

Expand full comment
Rob's avatar

Microsoft Windows Configuration Designer is block by Microsoft's own Anti-virus (are they on something?!). It also shits the bed when Security zones policies are enabled. The App from the Appstore is beyond "USELESS", 15 reviews all giving 1 star max (Seriously!?). Going to try Windows ADK full install now, to see if that is any better.

Expand full comment
Brady Widener's avatar

Full agreement there. Windows configuration designer is wonky at best, which is unfortunate considering the potential it has. However, once you jump through the hoops and make the provisioning package it really is worth it for all the time you save. There’s also an app called “Set Up a School PC” in the microsoft app store that is an education focused version of windows configuration designer. I haven’t played with it much, but when I did I remember thinking it seemed a lot more polished, but I believe it also had fewer options. Hopefully one day we get the level of polish on the original store app.

Expand full comment
Sam's avatar

I got the usb to work perfectly. I choose Sean's script using the pkg to enroll the device into our autopilot. I wait for the machine to upload in Autopilot and assign profile while the computer is at the login screen. After the the profile is assigned, I can't login to the machine. It just says incorrect username or password even though username password is correct. Profile is assigned in autopilot. What could be wrong here?

Expand full comment
Brady Widener's avatar

Not 100% sure. Outside of the faulty login, it sounds like you are doing this correctly.

I would check/try these things.

1. Check to see if your device is present in Azure or Intune. This can be done by typing .\ at the username login box on the device (it will give you the device name).

2. Try logging in with the whole email address of the user you are trying to sign into if you are not already. There's a configuration profile you can assign later to automatically add the email domain, but this may be worth trying.

3. Last thing I would try is remaking your Provision Package and configure a local admin account, just to test to see if you can find out more information once you are in the device. I would be on the lookout to see if it's pulling profiles/apps from intune at all.

Hope this helps!

Expand full comment
Brady Widener's avatar

One other thing to note and you may already be aware of it, whenever you assign an AutoPilot Profile to a device, this tells it the configuration to use the next time it is in the Out of Box Experience. If you're assigning the profile when the device is already at a login screen, those changes will take place the next time the device is factory reset or reimaged.

Expand full comment
John E's avatar

Great article. Do take a look at OSDCloud as that contains some great logic for downloading driverpacks from HP, Dell, Lenovo and MS

Expand full comment
Brady Widener's avatar

I hadn't heard of OSDCloud, but first impression is that it looks like a really cool/handy resource! Thanks for sharing :)

Expand full comment
Aaron Monson's avatar

I want to thank you for this.

I thought I would give you a heads up about an adjustment I did with the Drivers.

I adjusted it so it only grabbed the drivers for the current model of device. Lenovo is a bit different as it goes by a random deviceID rather than the actual name, but as long as you have the Device Name in the driver folder you can have all drivers for each model in your fleet.

#region Bootstrap drivers

$computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem

$manufacturer = $computerSystem.Manufacturer

$model = $computerSystem.Model

Write-Host "`nDevice Model: " -ForegroundColor Yellow -NoNewline

Write-Host $model -ForegroundColor Cyan

# Determine the folder name based on the manufacturer

if ($manufacturer -eq "LENOVO") {

$folderName = $model.Substring(0, 4)

} else {

$folderName = $model

}

Write-Host "Using folder name: $folderName" -ForegroundColor Yellow

# Construct the path to the model-specific driver folder

$driverFolderPath = Join-Path -Path $usb.driverPath.FullName -ChildPath $folderName

# Get the drivers from the model-specific folder

$drivers = Get-ChildItem -Path $driverFolderPath -Filter *.inf -Recurse

if ($drivers) {

Write-Host "Bootstrapping found drivers into WinPE Environment.." -ForegroundColor Yellow

foreach ($d in $drivers) {

. drvload $d.FullName

}

} else {

Write-Host "No drivers detected in $driverFolderPath" -ForegroundColor Yellow

}

Expand full comment
Chad Elder's avatar

Hey thanks for this! I'm having a heck of a time with drivers. For some reason, this was working great a couple weeks ago when I first set the USB drive up. I hadn't loaded any drivers on the USB drive; relied strictly on Windows managing the drivers. Now, when I go to reimage a device, upon OOBE, there are no drivers loaded for network connectivity, causing the provisioning package to fail to enroll into Azure AD/Autopilot. I am using Lenovo devices. I downloaded the WinPE from https://support.lenovo.com/us/en/solutions/ht074984 for my model 300W.

Any advice would be more than helpful! Thanks again!

Expand full comment
Brady Widener's avatar

I have had similar experience with ASUS computers, but I have also made packages for lenovo computers a bunch. Any time I'm getting drivers for a lenovo package, I'll usually go directly to the product page of the device model and get the Enterprise Management driver pack (for 300W it is here: https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/300-series/300w-gen-3/downloads/driver-list/component?name=Enterprise%20Management&id=4A3CC709-438F-487D-8739-4104CE73D368)

Once you download this, it'll be an executable that when you run it, it will unzip a folder of drivers. Unzip this to the drivers folder of the USB. You may get the same result as before, I'm not sure if the package there is any different from the one you're using, but I thought I would mention it as I always get my drivers for Lenovo device this way. Another option may be to hook up your lenovo to ethernet using a USB to ethernet adapter to make sure its failing to enroll due to network connectivity. I would imagine this is the case, but it's also important to note that Provision Packages that join to azure expire after 6 months by default. I've run into a lot of 'mystery issues' for drives failing to enroll that end up being the provision package expiring.

Hope this helps!

Expand full comment
Chad Elder's avatar

Good call I'll give that a try! Thanks again for a great product!

Expand full comment
Chad Elder's avatar

OK so drivers seem to be working, however I'm running into strange issues with provisioning. The ppkg is fresh, I made a new one just in case it had expired. All the packages seem to apply except for enrolling in AAD, which is arguably the main point of this blog. It simply shows as failing to enroll in AAD.

Internet connectivity is working, scripts get applied, the device gets renamed. Could it be that because we're coming from a hybrid-joined solution, the device objects that are already in AAD are conflicting with what the ppkg is trying to setup?

Expand full comment
Brady Widener's avatar

I haven't tried this for hybrid, so I am unsure! I wouldn't imagine it causing issues. If you're moving to full AAD and not hybrid, then here's what I would try next.

1. To test your theory, if you can, delete the local computer account of your test machine in both AD and AAD to make try and eliminate it as variables.

2. This sounds odd, but try creating the package on a different computer. One thing I have noticed is that it seems like prov packages works most consistent if you create the package on a computer that is the same or close to the same Windows Release as the ISO you're using. This part could be superstition, but I feel the need to mention it.

3. Reimage the computer you're trying to provision. This sounds odd too, but I have definitely noticed that once a prov package fails on a computer, a lot of times it will keep failing unless you wipe and start from scratch.

4. Delete and recreate your provision package. I would do a test one that is as bare bones as possible, so no wifi configuration and basically just have it join AAD. When you do this, there is a toggle to refresh credentials. This will have you sign into your AAD tenant again and refresh that token to be a brand new 'key' to AAD.

After this I would try it again and see if that works, and then start peeling back to see which specific piece of the puzzle fixed it. Hopefully one of those things is it.

Thanks!

Expand full comment
Chad Elder's avatar

Apologies for not clarifying: we are migrating away from hybrid, so I am re-imaging the devices using this method in hopes to simply join straight to Azure AD. I will try the steps you listed and let you know the outcome! Thanks again for being so responsive!

Expand full comment
Marcel's avatar

Very nice and good working this!

Is there anybody that installed a different language of knows how to do that?

By default English is installed but we want Dutch.

Expand full comment
Brady Widener's avatar

Absolutely and glad it helps!

When downloading your windows ISO, are you downloading the multi-language version or selecting the product language before downloading it? For me, when I go to download a windows ISO from here (https://www.microsoft.com/software-download/windows11), after clicking to download the multi-edition ISO, it asks me for the product language with Dutch being one of the options. This is how I imagine you would want to do it, but I've never tried installing it for another language, so I am unsure.

Expand full comment
Marcel's avatar

Thank you for your quick response!

We are using the Enterprise version and having the multi language ISO. Found some scripts for changing the language but that is applied after the first login from the user.

I will search for a Dutch only Enterprise version, that is the quickest solution I guess.

Expand full comment
Brady Widener's avatar

My pleasure!

For me when downloading the ISO above, I can choose the language before downloading. Whenever I go to create the drive with that ISO, it asks me which edition of windows to use when creating the drive.

If you have a script that is able to change the language, you may also be able to add that script to your provisioning package as well, similar to the step above where we add the script to the provisioning package to enroll the device in autopilot. Best of luck, regardless, and let me know if there is any way I can help!

Expand full comment
bmtruck's avatar

Hello, thanks for sharing this, it has worked very well. However, not sure if you've had anything similar, but we find that we need to stop the auto reboot at the end of the WinPE setup. Regardless of changing boot order in the bios the the device seems to get stuck in the boot loop on the USB unless it's removed. It seems like whatever WinPE does to the device leaves it in a different state than a normal Windows install. We use nvme drives and everytime the PE portion completes it puts the new source partition below the USB so it won't boot from it until it is removed. We also find that we need to reinsert the USB stick on the first boot up while it's sitting at the language screen for it to take the provisoning package. During the process it does say that it found the ppkg files and was writing them to the scratch drive, but they never seem to kick in on their own. Have you experienced either?

Thanks

Expand full comment
Brady Widener's avatar

Hello!

Actually yes, I have experienced both of those issues before. We had a small number of Dell laptops that had the issue with boot looping. I believe we changed the last line of the script to just shut down the device as a visual indicator that the laptop was done and needed to be restarted and to have the USB taken out. Not a perfect solution, but saves a little time for each batch.

As for the provision package, I have seen this before, but not consistently. One thing I found was on the model of laptop we were working on, it had both a USB 3.0 and a USB 2.0 port. For whatever reason, the USB 3.0 port was much more consistent for having windows OOBE detect the provision package on the first try, compared to the 2.0 port. Not sure why, but if you have other USB options, I would give them a try to see if you can draw any parallels.

Thanks!

Expand full comment
bmtruck's avatar

Thanks for the response, it sounds like you are still pulling the provisioning package off the USB then? I noticed during the WinPE steps that it grabs the provisioning package off the USB and puts it on a "scratch" drive. Maybe I'm mistaken, I was thinking it was moving my provisioning package to the "scratch" drive. This might be question for the team that created the powershell app as it seems as though they are trying to pull the package it's just not being loaded correctly. I have no issues inserting it at the language select it works everytime. Just seems like theres a step that's trying to do this for you.

Expand full comment
Brady Widener's avatar

The way I've done it is after using the Powershell tool to create the drive, it splits the physical USB into two logical drives labeled Images and WinPE. I will copy and paste the provision files in the Images drive and (in an ideal scenario) it picks up after the reboot on the Windows OOBE screen.

I will say, I've worked with Windows Configuration Designer to create packages a bunch in the past, and it's always had a level of issues with trying to detect on windows OOBE. Not all the time, but there is a level of inconsistency I've noted with it, before ever using the process in this article.

Expand full comment
JPG's avatar

Hi All, just wondering if this process is still working. I am trying to create a USB using a Windows 11 ISO and although it states that it completed successfully, it doesn't look like it copies all the required files. It also creates two partitions on the usb, not sure if it is by design?

Expand full comment
Brady Widener's avatar

Yup! It should still work. I made a new drive just last month and it's still kicking.

The two partitions are by design. As for missing files, I'm unsure. If you have a spare computer you can try it on, I would go for it and see if it works when you boot to the drive. I just wouldn't do it on a computer that has anything important on it as it will wipe it as one of the steps.

Thanks!

Expand full comment
JPG's avatar

Thank you for the prompt response. It doesn't want to boot from the USB and there are only a scripts folder and the WinPE.wim file on the first partition on the USB drive. Not sure if I am doing something wrong but I have installed all the pre-reqs and is following the guide on here https://powers-hell.azurewebsites.net/2020/05/04/create-a-bootable-windows-10-autopilot-device-with-powershell/

Expand full comment
Brady Widener's avatar

That does sound odd. I haven't personally run into this issue before, but I would suggest trying to reformat the USB and try it again from scratch. I haven't seen the exact issue you're experiencing, but I have had times where the drive wouldn't act correctly, but starting over and making a new one has fixed it. At the very least it's worth a shot!

Expand full comment
Sam's avatar

Great Article, Could you please explain the WinPE steps. Did you use the WinPE from this URL https://githublfs.blob.core.windows.net/storage/WinPE.zip? Or did you create your own Win11 PE?

If I want to deploy Windows 11 enterprise edition iso, Do I need Win11 PE or can I use the WinPE from the URL and just change the path/name of the iso here? windowsIsoPath "C:\path\to\win11.iso" ?

Expand full comment
Brady Widener's avatar

Hi Sam!

Thank you and glad you enjoyed the article!

Windows PE is what runs on the USB when you boot to it and is separate from the Windows you are installing on the laptop. Ben cloud hosts the windows PE you need at the URL you mentioned (https://githublfs.blob.core.windows.net/storage/WinPE.zip). I would leave that part of the command the same unless it is giving you issues.

For the Windows ISO part, you should be able to use the Windows enterprise ISO that you already have without modifying it. You would just need to put the path to the ISO there. For example, if I downloaded a Windows ISO to my downloads folder, the command would look like this.

Publish-ImageToUSB -winPEPath "https://githublfs.blob.core.windows.net/storage/WinPE.zip" -windowsIsoPath "C:\Users\brady\downloads\Windows11Enterprise.iso"

Hope this helps!

Expand full comment
Brayden's avatar

Great Article, I don't know if I missed it, where do you put the Import-AutopilotHashFromPpkg.ps1 ?

Expand full comment
Brayden's avatar

Never mind, i'm silly. CommandFile in the provisioning package.

Expand full comment
Brady Widener's avatar

Sorry I just now saw this!

The way I did it was by putting the script on the flashdrive and then create the provision package that calls the script. Thanks!

Expand full comment
Dzaggiel's avatar

How to come back to OOBE process? We have hybrid join solution so we need oobe to install apps and other things. After finish the process we see only "Setup completed sucessfully" and after reboot its the same only logon screen.

Expand full comment
Brady Widener's avatar

I’m not as familiar with hybrid join. My district went straight from AD to AAD. I don’t believe there is a way to go back to the out of box experience after you provision the device. I would either push the apps through intune after the fact, or when creating your provision package add the app installs to the provision package.

Expand full comment
Dzaggiel's avatar

But here in the last step it said that after reboot OOBE will start

https://github.com/tabs-not-spaces/Intune.USB.Creator

This is not possible because we have a connection to the local domain through Intune so we must have OOBE.

Expand full comment
Brady Widener's avatar

Yes, but whenever you create and add the provision package in the next step on my article, it automates the setup.

You may be able to create the provision with only the script to get your desired experience, but then you will need to finish the setup manually and domain join it manually.

Expand full comment
Ryan's avatar

Curious about drivers.. are you just relying on the native Windows drivers?

Expand full comment
Brady Widener's avatar

Previously I relied on native windows drivers, but I recently discovered that you can add drivers on the USB in the drivers folder (on the Images Drive of the USB). The best way to do this is to find the product page of your model of device and see if they have a Windows PE or SCCM driver package. Then, extract the drivers into this folder.

Expand full comment
Sara's avatar

I got the WinPe Dell drivers and extracted them into the drivers folder, but they're not getting installed. For HP the process seems to work fine.

Could you elaborate further on how you do this? Or do you have an alternative to handle drivers? We're struggling to get that network driver installed during provisioning for our Dell machines.

Thank you for putting this together! It's been a time saver.

Expand full comment
Brady Widener's avatar

Glad to hear it's been a help!

A little warning, I've had issues with this method on Dell Devices as they appear to use their own recovery partitions. You can use this method to get them up and running, but it isn't the best long-term solution as (in my case) it took away the ability to factory reset the dell in windows, or be able to autopilot reset the device. It could have been an issue specific to my model, but I would definitely test to make sure you still have this functionality on one of the Dells after reimaging this way to be sure you still have option. If you do run into this issue, what it will look like is you'll get a blue box error message that says 'Windows was unable to factory reset'. Dell makes their own USB you can download and put on a flashdrive that does not have this issue, but it is not automated and not fast. I have yet to find a great solution for this, but if you need Dell's USB image, you can find it here.

https://www.dell.com/support/home/drivers/osiso/recoverytool

If your devices are able to factory reset after the reimage then I would continue what you're doing, but just wanted to throw that out there as I have ran into this issue. As for drivers on the USB, with Dell I had the most luck with using their normal Dell Command | Deploy Driver Pack (not PE version). This is an exe you can download from the support page for your device model. Whenever you run the EXE it will ask you where it should extract the drivers. I would extract them into your Drivers folder on your USB.

After you do find a solution, for Dell you can either manage drivers using Dell Command | Update, a software tool they make. I push it directly to our devices through intune. You could also manage drivers within intune for just about any device using a driver update ring. There's lots of articles on that online.

I hope this helps!

Expand full comment
Brady Widener's avatar

Also, it's worth noting, when using a driver pack, I believe these include all 'potential' drivers for your device. For example, if Dell makes an intel and AMD version on the same model of laptop, both drivers would be included in the driver pack, but one will fail to install as it is incompatible, but the correct one should still install. I don't know this to be a fact, but to my knowledge I've seen this.

Expand full comment
Sara's avatar

Thank you for such a speedy and thorough answer! This was very helpful.

I have not encountered the issue yet, but I'm in the early stages of testing with our Dell machines, so it is a very good point to keep an eye out for. I'll keep tinkering around.

Expand full comment
David's avatar

Great solution but I’m struggling to get it working with 22H2 and suspect this is due to the reported bug with ppkgs. Has anyone experienced this and found a fix?

Expand full comment
Brady Widener's avatar

Hey David!

Thanks for the feedback. Part of this article is outdated for our current solution and needs updating, but as far as I know everything in here should still work, there just may be easier ways to do this.

Which step are you getting errors at? I recently made a package with Windows 11 22H2 using Ben's USB Image Deploy tool, but the devices I ran it on were imported into AutoPilot by the manufacturer, so I didn't have a need to add a provisional package at all because they are already in AutoPilot.

Thanks!

Expand full comment
David's avatar

I was getting error 0x800700b7 when the ppkg was launching at oobe. Applying KB5020044 to the image resolved the issue. Hope this helps others.

Expand full comment
Deniz's avatar

Could you give us the updated version?

Expand full comment
Brady Widener's avatar

Absolutely. I'll get working on that, the biggest difference is how we are enrolling them into AutoPilot.

Instead of including the script and setting up the graph API in the provisioning package, there is a toggle when creating an autopilot profile called 'Convert all targeted devices to Autopilot'. We've been having good success with imaging the device and provisioning it to AAD, letting the dynamic group pick up the device based on the name of the device, and then assigning the AutoPilot profile with this toggle to the group. When it assigns this profile, it will automatically add any devices missing from AutoPilot to AutoPilot.

I would highly recommend testing this as it is working for us, but I haven't seen other articles about it.

Outside of that, if I were to redo it today using the Graph API, instead of including the powershell script in the provision package, I would push the same powershell script through intune to the group to enroll them all. I did this to a group of 300 devices that were already out in the wild and had good success with it.

For either of these options, I would definitely recommend testing on a run of devices first, but both would cut down on the time imaging per device.

Expand full comment
aaronc's avatar

Where would we insert a grouptag?

Expand full comment
Brady Widener's avatar

Instead of adding a group tag, we're doing the dynamic filtering for our group based on the device name. Then having the provision package name the device using the same naming scheme.

For example, for teacher devices we may want to use the name TEACH-SerialNumber. We would set up the provisioning package to name the device using that same naming scheme. Then we would set up the group to use a rule that automatically adds any device with a device name staring with "TEACH" to the group. Then once they're in autopilot, we would set up a AutoPilot Provisioning Package to use that same naming scheme as well, this way any device that is AP reset after the initial image will be put back into that same group.

If you had a specific need to add a group tag, Sean does mention in his blog that you can add a grouptag in that script that goes in the provisioning package, but does not go into detail on how to do it. So I imagine there is a way, but we found that doing it by name worked well for our needs.

Expand full comment
James Cook's avatar

I managed to add the grouptag variable to the script and get it working=)

I added the line below under $hash = $devDetail.DeviceHardwareData

$grouptag = "MyGroupTagHere"

Then add the below to the $body on line 122 (123 if added the above)

"groupTag" = "$grouptag"

Expand full comment