Windows 11 Provisioning
The Xenter provisioning script configures a Windows 11 device to corporate baseline and registers it in Windows Autopilot — without requiring a custom Windows ISO. It runs directly on the bare Windows install, either during the Out-of-Box Experience (OOBE) on a new laptop or on an existing device already issued to a user. When the script finishes, the device has a standardized name, bloatware removed, BitLocker enabled, and is registered in Autopilot ready for Intune enrollment.
Table of Contents
- Quick Start
- Prerequisites
- Preparing the USB Drive
- Provisioning a New Laptop (OOBE)
- Provisioning an Existing Device
- What the Script Does
- Authentication Modes
- Post-Provisioning Steps
- Configuration Reference
- Troubleshooting
Quick Start
New laptop (OOBE)
Prepare the USB drive with a configured
.envfile (see Preparing the USB Drive).Power on the laptop and wait for the OOBE language/region screen.
Press
Shift+F10to open an admin command prompt.Insert the USB drive and navigate to the provisioning folder (adjust drive letter as needed):
D: cd windows-provisioning Provisioning.batSelect the device type when prompted (
Laptop,SharedDesktop, orConferenceRoom).If using Device Code Flow: visit
https://microsoft.com/deviceloginon another device and enter the displayed code.When the summary appears, record the BitLocker recovery key shown in red.
Remove the USB drive and proceed to Post-Provisioning Steps.
Existing device
Sign in with a local or domain admin account.
Insert the USB drive.
Open an elevated command prompt and run:
D: cd windows-provisioning Provisioning.batFollow the same prompts as above.
Reboot — the computer rename takes effect on restart.
Prerequisites
Hardware
- Secure Boot enabled in UEFI/BIOS
- TPM 2.0 present and enabled (script exits immediately if missing)
- Wired ethernet connection (Wi-Fi is unreliable during OOBE)
USB Drive
The USB must contain the provisioning files in the correct layout. See Preparing the USB Drive.
Azure AD App Registration
The script uses two Microsoft Graph API calls during provisioning: one to check for duplicate device names and one to upload the Autopilot hardware hash. This requires an App Registration in your tenant with the following permissions granted with admin consent:
| Permission | Type | Purpose |
|---|---|---|
Device.Read.All |
Application or Delegated | Device name conflict check |
DeviceManagementServiceConfig.ReadWrite.All |
Application or Delegated | Autopilot hardware hash upload |
See the Authentication Modes section and the Azure AD App Registration Setup guide for full setup instructions.
.env File
At minimum, TENANT_ID and CLIENT_ID must be set in the .env file at the USB root before running the script. See Configuration Reference for all available variables.
Preparing the USB Drive
File Layout
The USB should contain the following structure (clone or download the repository to the drive):
D:\windows-provisioning\
├── Provisioning.bat ← run this
├── .env ← your environment config
├── src\
│ ├── Start-XenterProvision.ps1
│ ├── wifi-profile.xml (optional)
│ └── assets\
│ ├── wallpaper.jpg (required)
│ └── lockscreen.jpg (optional)
| File | Required | Notes |
|---|---|---|
Provisioning.bat |
Yes | Entry point — always run this, not the .ps1 directly |
src\Start-XenterProvision.ps1 |
Yes | Main provisioning script |
.env |
Yes | Must contain at minimum TENANT_ID and CLIENT_ID |
src\assets\wallpaper.jpg |
Yes | Corporate desktop wallpaper |
src\assets\lockscreen.jpg |
No | Falls back to wallpaper if absent |
src\wifi-profile.xml |
No | Corporate Wi-Fi profile; injected if present |
Creating the .env File
Create a plain text file named .env at the USB root (alongside Provisioning.bat). At minimum:
TENANT_ID=<Directory (tenant) ID from Entra ID Overview>
CLIENT_ID=<Application (client) ID from App Registration Overview>
CLIENT_SECRET=<client secret value>
Leave CLIENT_SECRET blank or omit it entirely to use Device Code Flow (interactive sign-in). See Authentication Modes.
For additional variables (org name, support contact, timezone, etc.), see the Configuration Reference.
Adding the Corporate Wi-Fi Profile (Optional)
If you want the script to inject the corporate Wi-Fi profile so the device can connect after OOBE, export the profile from a machine already connected to the network:
netsh wlan export profile name="YourSSID" key=clear folder=C:\TempCopy the resulting .xml file to src\wifi-profile.xml on the USB. The script injects it system-wide before first user login.
Provisioning a New Laptop (OOBE)
This is the primary use case — provisioning a laptop fresh out of the box without needing a custom Windows ISO.
Power on the laptop and wait until the OOBE language/region selection screen appears. Do not proceed through OOBE setup.
Press
Shift+F10. An administrator command prompt opens.Insert the USB drive. Identify the drive letter Windows assigned to it (check with
wmic logicaldisk get captionif unsure — it is typicallyD:orE:).Navigate to the provisioning folder and run the script:
D: cd windows-provisioning Provisioning.batThe script displays the Xenter banner and begins the firmware check. If Secure Boot or TPM 2.0 is not detected, the script exits with instructions to enable them in UEFI/BIOS before re-running.
Device type: When prompted, select the device type. This becomes the Autopilot group tag used for dynamic Entra ID group assignment:
1— Laptop2— SharedDesktop3— ConferenceRoom
Authentication: Depending on how your
.envis configured, one of the following occurs:- Client Credentials (silent): Authentication completes automatically with no user action.
- Device Code Flow: The script displays a URL and a short code. On another device, open a browser, go to
https://microsoft.com/devicelogin, and enter the code. Sign in with a Global Administrator or Intune Administrator account. The provisioning script continues automatically once authentication succeeds.
The script runs through all provisioning steps (see What the Script Does). This typically takes 5–10 minutes depending on network speed.
When the summary screen appears, record the BitLocker recovery key displayed in red. Store it securely. It will also be automatically escrowed to Entra ID after the user completes Intune enrollment.
Press
Enterto close the script. Remove the USB drive.The device is now ready for handoff. The OOBE screen is still showing — do not complete setup yourself. Instead, proceed to Post-Provisioning Steps and have the user sign in with their Microsoft 365 credentials to trigger Autopilot enrollment.
Provisioning an Existing Device
The provisioning script is idempotent — it is safe to run on a device that is already in use. This is useful for bringing computers into alignment with the current corporate baseline or re-registering a device in Autopilot after a rebuild.
Sign in to the device with a local or domain administrator account.
Insert the USB drive.
Open an elevated command prompt (
Run as administrator) and run:D: cd windows-provisioning Provisioning.batFollow the same interactive prompts as the OOBE flow (device type, authentication).
After the script completes, reboot the device. The computer rename (
XMD-<serial>) does not take effect until restart.Verify the device appears in Intune Admin Center > Devices > Windows Autopilot Devices with the correct serial number.
What gets re-applied vs. skipped on an existing device:
| Step | Behavior |
|---|---|
| Computer name | Skipped if already set correctly |
| BitLocker | Skipped if already enabled |
| Bloatware removal | Re-runs and removes any remaining matches |
| Wallpaper | Re-applied |
| Autopilot registration | Re-runs; no error if already registered |
What the Script Does
The script runs 17 provisioning steps in strict order. Steps are grouped below by phase.
Firmware Validation
The very first step checks that the device meets hardware requirements. If either check fails, the script exits immediately with instructions to enable the missing feature in UEFI/BIOS.
- Secure Boot — Verified via WMI cmdlet with a registry fallback for environments where the cmdlet is unavailable during OOBE.
- TPM 2.0 — Verified via
Get-Tpm.
Identity and Authentication
- Serial number — Read from BIOS via
Win32_BIOS. If the BIOS serial is missing or a generic placeholder (e.g.,To Be Filled By O.E.M.), the script prompts IT to enter it manually. - Device type selection — The IT admin selects
Laptop,SharedDesktop, orConferenceRoom. This becomes the Autopilot group tag, which drives dynamic Entra ID group membership and profile assignment. Skipped ifGROUP_TAGis set in.env. - Network check — Pings
8.8.8.8andmicrosoft.com. Network-dependent steps are skipped gracefully if no connection is found. - Prerequisites — Installs the NuGet provider and the
Get-WindowsAutopilotInfomodule from PSGallery (used as an Autopilot registration fallback method). - Azure AD authentication — Obtains a Graph API access token using Client Credentials or Device Code Flow. See Authentication Modes.
Device Configuration
- Device name conflict check — Uses the Graph API to verify that
XMD-<serial>does not already exist in Azure AD. If a conflict is found, the script asks whether to override or abort. - Computer name — Renames the device to
XMD-<serial>(truncated to 15 characters for NetBIOS compatibility). Takes effect after reboot. - Timezone — Sets the system timezone (default:
Mountain Standard Time, configurable via.env). - Bloatware removal — Removes AppX packages matching ~30 patterns covering OEM software (Dell, HP, Lenovo), gaming apps, antivirus trials, and Microsoft consumer apps. Also removes provisioned packages so they do not reinstall on new user profiles.
- Company Portal — Installs the Microsoft Intune Company Portal via
winget. If offline, Company Portal is deployed via Intune after enrollment instead. - Wi-Fi profile — If
src\wifi-profile.xmlexists on the USB, injects it system-wide vianetsh wlan add profile. - Corporate wallpaper — Deploys the wallpaper using PersonalizationCSP and seeds the Default User registry hive so all new profiles inherit it. Stored at
C:\Windows\Web\Wallpaper\Xenter\. - OEM support info — Writes support contact information to the registry, visible under Settings > System > About.
Security
- BitLocker — Enables BitLocker with XTS-AES 256 encryption using a TPM + Recovery Password protector. The recovery key is displayed in red in the summary and written to the device provisioning log at
C:\ProgramData\Xenter\Provisioning\. Record this key. Automatic escrow to Entra ID happens after Intune enrollment.
Autopilot Registration
- Hardware hash upload — Uploads the device’s hardware hash to Windows Autopilot via the Graph API with the selected group tag. If the Graph upload fails, the script retries using the
Get-WindowsAutopilotInfocmdlet as a fallback. If the device is already registered, the step is treated as successful.
Summary
- Summary display — Shows the final provisioning report: computer name, serial number, BitLocker recovery key (if not yet escrowed), Autopilot registration status, any warnings, and next steps.
Authentication Modes
The script supports two ways to authenticate to Azure AD. Configure your preferred mode in the .env file before deploying the USB.
Client Credentials (Recommended)
Set CLIENT_SECRET in your .env file. The script authenticates silently using the app’s own identity — no user interaction is required during provisioning.
CLIENT_SECRET=<your client secret value>
Best for: Environments where multiple technicians use the same USB, or when provisioning is done unattended during OOBE without a second device available for Device Code Flow.
Requirement: The App Registration must have Application permissions and admin consent granted. A client secret must be created and have not expired.
Device Code Flow (Interactive)
Leave CLIENT_SECRET blank or omit it from .env. The script displays a short code and the URL https://microsoft.com/devicelogin. Sign in on any other device (phone, another laptop) with a Global Administrator or Intune Administrator account.
# CLIENT_SECRET not set — Device Code Flow will be used
Best for: Environments that prefer not to store a client secret on a USB drive.
Requirement: The App Registration must have Delegated permissions with admin consent, and Allow public client flows must be set to Yes under the app’s Authentication settings.
Note: The device code expires after approximately 15 minutes. If it times out before sign-in completes, re-run Provisioning.bat.
Post-Provisioning Steps
After the script finishes and you have recorded the BitLocker key:
Confirm Autopilot registration. In the Intune Admin Center, go to Devices > Enroll devices > Windows Autopilot Devices and search for the device’s serial number. Allow up to 15 minutes for the hash to sync if it was just uploaded.
Assign the device to the user. In the Intune Admin Center, navigate to Devices > All devices, find the device, and assign it to the new hire’s user account. This links Autopilot enrollment to the correct user.
Hand off to the user. The new hire powers on (or continues from the OOBE screen) and signs in with their Microsoft 365 credentials (
name@xenter.io). Windows Autopilot runs automatically:- Applies the Autopilot deployment profile
- Enrolls the device in Intune MDM
- Intune deploys apps, policies, and certificates
- Company Portal installs assigned apps
- BitLocker recovery key is automatically escrowed to Entra ID
Verify BitLocker escrow. After enrollment, confirm the recovery key appears in Entra ID: Devices > All devices > [device name] > Recovery keys.
Verify device compliance. In the Intune Admin Center, confirm the device shows as Compliant under its compliance policies after the user completes setup.
Configuration Reference
All variables are set in the .env file at the USB root (next to Provisioning.bat). Lines beginning with # are comments and are ignored.
# Example .env
TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
CLIENT_SECRET=your-secret-value
| Variable | Required | Default | Description |
|---|---|---|---|
TENANT_ID |
Yes | (none) | Azure AD Directory (tenant) ID — found on the Entra ID Overview page |
CLIENT_ID |
Yes | (none) | App Registration Application (client) ID |
CLIENT_SECRET |
No | (none) | Client secret for silent auth; omit to use Device Code Flow |
GROUP_TAG |
No | (interactive prompt) | Autopilot group tag; omit to prompt the technician at runtime |
ORG_NAME |
No | Xenter, Inc. |
Full organization name (used in OEM support info) |
ORG_SHORT |
No | Xenter |
Short org name |
COMPUTER_PREFIX |
No | XMD |
Prefix for computer names — result is PREFIX-<serial> |
TIMEZONE |
No | Mountain Standard Time |
Windows timezone string (use Get-TimeZone -ListAvailable to find valid values) |
SUPPORT_PHONE |
No | (blank) | IT support phone number shown in Settings > System > About |
SUPPORT_HOURS |
No | (blank) | Support hours shown in Settings > System > About |
SUPPORT_URL |
No | (blank) | Support URL shown in Settings > System > About |
LOG_LEVEL |
No | Information |
Minimum severity written to the device log. Accepts: Trace, Debug, Information, Warning, Error, Critical |
Troubleshooting
Script won’t run / “not digitally signed” error
Always run via Provisioning.bat, not by double-clicking the .ps1 directly. The batch file passes -ExecutionPolicy Bypass for the session so unsigned scripts are allowed.
Firmware requirements check failed (Secure Boot / TPM)
The script exits immediately if Secure Boot or TPM 2.0 cannot be confirmed.
- Shut down the device.
- Enter UEFI/BIOS setup (key varies by manufacturer:
F2,F12,Delete, etc.). - Enable Secure Boot (usually under Boot Security or Security settings).
- Enable TPM 2.0 (may appear as
PTTon Intel systems orfTPMon AMD systems). - Save and exit, then re-run
Provisioning.bat.
Network not detected
The script gates all Azure AD and Autopilot operations on network connectivity. If no network is found, those steps are skipped and the script continues with local-only tasks (naming, bloatware removal, wallpaper, etc.).
During OOBE, use a wired ethernet connection. Wi-Fi is unreliable before a user profile exists. If ethernet is not available, complete local provisioning first, then run the script again from the desktop once connected.
Device Code Flow times out
The device code is valid for approximately 15 minutes. If it expires before sign-in completes, re-run Provisioning.bat. Ensure ethernet is connected before starting and have the sign-in device ready before launching the script.
Device name conflict found
If XMD-<serial> already exists in Azure AD, the script displays the existing device’s object ID and asks whether to continue. Enter y to override (this may create a duplicate device object) or N to abort and investigate in Intune Admin Center > Devices first.
BIOS serial number missing or generic
If the BIOS reports a missing or placeholder serial (e.g., To Be Filled By O.E.M.), the script prompts you to enter one manually. Check the physical label on the device chassis or in the BIOS/UEFI System Information screen. Enter the serial exactly as shown — the script strips special characters automatically.
Autopilot registration fails
Confirm ethernet is connected and retry. If the hash still fails to upload after re-running the script, you can register manually once the device is at the Windows desktop:
$env:Path += ";C:\Program Files\WindowsPowerShell\Scripts"
Get-WindowsAutopilotInfo -OnlineDevice is already in Autopilot
If the device’s serial number is already registered, the script treats this as a successful registration and continues normally. To verify the existing registration: Intune Admin Center > Devices > Enroll devices > Windows Autopilot Devices — search for the serial number.
BitLocker key not escrowed after provisioning
This is expected. Before Intune enrollment, the device object does not exist in Azure AD, so automatic escrow cannot complete. The recovery key is printed in the provisioning summary and written to C:\ProgramData\Xenter\Provisioning\provision-<serial>.log. Intune’s BitLocker policy escrows the key automatically once the user signs in and completes enrollment. Verify afterwards under: Intune Admin Center > Devices > [device name] > Recovery keys.
Wallpaper not applied after enrollment
PersonalizationCSP may require a sign-out and sign-in to take effect. If the wallpaper does not appear after first login, ask the user to sign out and sign back in.