OSD icon indicating copy to clipboard operation
OSD copied to clipboard

Autounattend.xml

Open capacity-tighe-begley opened this issue 1 year ago • 13 comments

I have an existing Autounattend.xml. Can OSDCloud incorporate that into the image it pulls down from MS?

capacity-tighe-begley avatar Jan 03 '25 00:01 capacity-tighe-begley

Autounattend.xml is intended to use when running Windows Setup, which is not called by OSDCloud, but if you have an unattend.xml that is only used for OS Configuration then you can probably inject that into the OS from WinPE

OSDeploy avatar Jan 16 '25 21:01 OSDeploy

So it would be possible to use the 'spealize' and 'oobe' sections of an existing autounattend.xml to use in an unattend.xml injected into the OS from WinPE?

capacity-tighe-begley avatar Jan 17 '25 04:01 capacity-tighe-begley

Sure, you can create your own one in the WinPE phase and simple put in the correct directory: Image

AkosBakos avatar Feb 02 '25 17:02 AkosBakos

I have used the script from @AkosBakos and placed it in folder: Media\OSDCloud\Automate\Shutdown Then the file is created and is run after the installation.

MrMortensen avatar Feb 13 '25 10:02 MrMortensen

@MrMortensen Can you share you example on how you did this?

capacity-tighe-begley avatar Feb 17 '25 01:02 capacity-tighe-begley

@capacity-tighe-begley I added a powershell file with the follow code to the folder: Media\OSDCloud\Automate\Shutdown (I called it create_unattended.ps1) The powershell script is run at the end of the installation and creates the Unattend.xml in the folder C:\Windows\Panther. You can test it on your OSDCloud USB, if you add the file to "E:\OSDCloud\Automate\Shutdown" where E: is your USBs WINPE drive.

$UnattendXml = @'
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
	<settings pass="oobeSystem">
		<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
			<InputLocale>0406:00000406</InputLocale>
			<SystemLocale>en-US</SystemLocale>
			<UILanguage>en-US</UILanguage>
			<UserLocale>da-DK</UserLocale>
		</component>
		<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
			<TimeZone>Romance Standard Time</TimeZone>
			<RegisteredOrganization>Your organization</RegisteredOrganization>
			<RegisteredOwner>IT Services</RegisteredOwner>
		</component>
    </settings>
</unattend>
'@ 

if (-NOT (Test-Path 'C:\Windows\Panther')) {
    New-Item -Path 'C:\Windows\Panther'-ItemType Directory -Force -ErrorAction Stop | Out-Null
}

$Panther = 'C:\Windows\Panther'
$UnattendPath = "$Panther\Unattend.xml"
$UnattendXml | Out-File -FilePath $UnattendPath -Encoding utf8 -Width 2000 -Force

You can find the different OOBE settings here: https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-international-core https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup

MrMortensen avatar Feb 25 '25 10:02 MrMortensen

Here’s an alternative take on this issue that I’ve tested.

I've used https://schneegans.de/windows/unattend-generator/ to generate an autounattend.xml file to my liking.

From OSDCloudGUI Defaults and Automate-paths, it is shown that OSDCloud will place files inside the Automate folder created in your workspace on the ISO or directly inside the USB key.

#Content will be on the ISO or USB Boot Partition
#Ideal for Virtual Machine testing
$(Get-OSDCloudWorkspace)\Media\OSDCloud\Automate

#Content will be on the USB Drive
#Ideal for Physical Machine testing
$(Get-OSDCloudWorkspace)\OSDCloud\Automate

So, I’ve put my autounattend.xml in this location. In my case, I’ve used $(Get-OSDCloudWorkspace)\Media\OSDCloud\Automate.

Sadly, that was not enough to make the Windows OS use it afterward. It needs to be placed inside the C:\Windows\Panther folder of the downloaded Windows OS.

To solve this, I created the following custom script and placed it inside the $(Get-OSDCloudWorkspace)\Config\Scripts\Shutdown folder.

autounattend.ps1

# Dynamically find the drive containing the OSDCloud folder
$OSDDrive = Get-PSDrive -PSProvider FileSystem | ForEach-Object {
    if (Test-Path "$($_.Root)OSDCloud\Automate") {
        $_.Root
    }
} | Select-Object -First 1

# Check if the drive was found
if ($OSDDrive) {
    # Define paths
    $CustomUnattend = "$OSDDrive\OSDCloud\Automate\autounattend.xml"  # Path to custom unattend
    $PantherUnattend = "C:\Windows\Panther\unattend.xml"              # Destination path in Panther folder

    # Check if the custom unattend file exists
    if (Test-Path $CustomUnattend) {
        Write-Host "Copying custom autounattend.xml to the Windows Panther folder..." -ForegroundColor Yellow

        # Ensure the Panther folder exists
        if (!(Test-Path "C:\Windows\Panther")) {
            New-Item -Path "C:\Windows\Panther" -ItemType Directory -Force
        }

        # Copy the custom unattend to the Panther folder
        Copy-Item -Path $CustomUnattend -Destination $PantherUnattend -Force
        Write-Host "Custom unattend.xml has been placed in the Windows Panther folder successfully." -ForegroundColor Green
    } else {
        Write-Host "Custom autounattend.xml not found in OSDCloud\Automate folder!" -ForegroundColor Red
    }
} else {
    Write-Host "OSDCloud drive not found!" -ForegroundColor Red
}

How It Works:

PowerShell scripts inside the Shutdown folder are executed just after Windows installs the OS on the drive. This happens after the first shutdown or possibly before—it’s unclear at this point. What’s important is that the C: drive represents the Windows OS that OSDCloud downloaded and installed. Steps in the Script:

  • The script dynamically locates the drive containing the OSDCloud folder.
  • It checks for the presence of the autounattend.xml file in the Automate folder.
  • If found, it ensures the C:\Windows\Panther folder exists and copies the file there.

Once the file is in place, Windows should detect it, bypass the OOBE, and apply the settings specified in the autounattend.xml.

Understanding the Script Folders in OSDCloud:

Based on my observations, the function of the script folders seems to be:

  • SetupComplete: Scripts in this folder are executed after the first reboot, during the Windows Update steps.
  • Shutdown: These scripts are executed before or after Windows installs the OS files on the C: drive.
  • Startup: Scripts in this folder execute before OS installation starts, immediately after OSDCloud launches.
  • StartNet: Runs before OSDCloud starts, likely used for pre-networking setup or initializing environment variables.

I have yet to find anything in the code or documentation to validate this, however. If anyone could guide me further on this, I might be able to leverage it to do even more.

AdamMcKennen avatar Mar 12 '25 02:03 AdamMcKennen

Well done @AdamMcKennen and thanks for sharing ... we've closed the door on trying to get OSDCloud to easily play with custom content. It was all a bandaid trying to get customizations to work when it wasn't initially designed that way.

This is mostly corrected in the new OSDCloud that we will be releasing at MMSMOA, although the full release supporting customizations probably won't arrive until WPNinjasCH

Drop me an email or DM on Linkedin or Twitter, I'd like to discuss some use case details to make sure we get this right in the next release.

OSDeploy avatar Mar 12 '25 08:03 OSDeploy

I will gladly take this offer. I have immense respect for the work you and your colleague have done on OSDCloud.

I understand that this incredible project largely emerged during the pandemic, when there was a pressing need to deploy a variety of computer models to meet the massive increase in remote work. I can confidently say that you and your colleague have done an outstanding job—it’s truly amazing.

After reading @MrMortensen's comment above, I decided to try moving the Unattend.xml file from the USB key instead of pasting it directly into the script. I’m happy to report that it worked, as this approach makes OSDCloud a strong candidate for replacing the basic tasks of preparing computers for small IT teams.

I will absolutely continue to follow OSDCloud’s development and look forward to seeing it become even more useful over time.

In my current use case, where leveraging Intune for post-installation configurations isn’t an option, using PowerShell scripts at various stages of the Windows installation seems like an excellent alternative. That’s why I’ve been asking for clarifications about the scripts folder.

However, since the current scripts page online is empty, your response didn’t surprise or bother me—I completely understand that it wasn’t the priority. I’m glad to hear directly from you that this feature will be better addressed in the new OSDCloud release.

I’ll continue to follow this project with great interest. Thank you for the clarifications and for all the incredible work you and your colleague have put into this project!

AdamMcKennen avatar Mar 13 '25 00:03 AdamMcKennen

@AdamMcKennen did you already check this blog post?

https://akosbakos.ch/oobe-challenges-2-a-better-solution/

For script automation you can use the SetupComplete.cmd and OOBE.cmd.

AkosBakos avatar Mar 13 '25 07:03 AkosBakos

@AdamMcKennen I am used the same site of create an autounattend.xml Curious how you configured yours. I tried following your post and most of the settings in my autounattend didn't apply.

capacity-tighe-begley avatar Mar 18 '25 00:03 capacity-tighe-begley

@AdamMcKennen you are a true wizard, thank you! Your autounattend.ps1 script and instructions worked perfectly for me, my osdcloud USB with ZTI now automates the entire Windows 11 os deployment, all the way through to the first login to the desktop as local admin.

Your post here was the only one I could find so far, that 'clearly' explains what you were doing and why, in regards to getting a pre-generated autounattend.xml to work with osdcloud.

My OSDcloud journey began with the NinjaOne links below. Per the NinjaOne instructions, unattend.xml (renamed from the original generated autounattend.xml) is placed in the root of the USB winpe folder. Apparently, unattend.xml will then be used afterw osdcloud downloads a Windows image from online: https://www.ninjaone.com/blog/zero-touch-device-provisioning/ https://youtu.be/wQs8q5HauX8?si=LB9oQ9iw3Gsh8Rmc

That method did not work for my use case though, since I'm using an offline Windows image generated with: Update-OSDCloudUSB -OSName "Windows 11 24H2 x64" -OSActivation Retail -OSLanguage "en-us"

Here's my code to build winpe to use a powershell script on the USB to start OSDcloud:

Set-ExecutionPolicy RemoteSigned -Force

Install-Module OSD -Force

Import-Module OSD -Force

Edit-OSDCloudWinPE -workspacepath C:\OSDCloud -Clouddriver * -StartPSCommand "iex X:\OSDCloud\Config\Scripts\osdcloud_config_zti.ps1" -Verbose

Update-OSDCloudUSB

Here's the code for osdcloud_config_zti.ps1:

Write-Host -ForegroundColor Green "Start-OSDCloud ZTI..."
Write-Host -ForegroundColor Green "`rThis ZTI script will *ERASE* all fixed disks..."
Write-Host -ForegroundColor Green "`r...press Ctrl-C to abort and type start-osdcloudgui for manual install..."

Start-Sleep -Seconds 1

Function Wait-ForKeyOrTimeout {
    param (
        [int]$Timeout = 10
    )

    for ($i = $Timeout; $i -ge 0; $i--) {
        Write-Host -NoNewline "`rPress any key to start ZTI...all fixed disks will be erased... (Erasing in $i seconds) "
        
        if ([System.Console]::KeyAvailable) {
            [void][System.Console]::ReadKey($true)
            Write-Host "`rKey pressed, erasing disk with ZTI...                     " # Clear line with spaces
            return
        }

        Start-Sleep -Seconds 1
    }
    Write-Host "`rPress any key to start ZTI...all fixed disks will be erased... (Erasing in 0 seconds)                     " # Clear the last countdown
}

# Example usage
Wait-ForKeyOrTimeout -Timeout 720


#Start-OSDCloud -OSVersion 'Windows 11' -OSBuild 24H2 -OSEdition Pro -OSLanguage en-us -OSLicense Retail -ZTI

Start-OSDCloud -OSName 'Windows 11 24H2 x64' -OSEdition Pro -OSActivation Retail -OSLanguage 'en-us' -ZTI

#Restart from WinPE

Write-Host -ForegroundColor Green “Restarting in 5 seconds!”

Start-Sleep -Seconds 5

wpeutil reboot

chrisporosky avatar Sep 01 '25 15:09 chrisporosky

I'm glad it worked for you! That was the purpose of my post above. I haven't had the time to get back to testing OSDCloud since then, but reading your comment made me happy to see that sharing my little bit of research helped someone. This also fuels my desire to see what I can accomplish further.

I’ll write about what I find here or post it in a new thread when I have more to share.

AdamMcKennen avatar Sep 10 '25 04:09 AdamMcKennen