Windows provisioning on bare metal

Anyone manage to setup windows provisioning or know a decent guide I could follow? I tried follow this video:

and also I tried this guide and tool:

But it doesn’t appear to be currently maintained and I ran into errors and needed to adjust a few of the scripts to get it somewhat working. All I need is to get a windows iso installed on a host, I plan on configuring it via ansible and won’t be managing the servers long term.

If anyone could point me in the right direction it would be greatly appreciated. I like to document as I go so if I can get it working I’ll document it and post for others. Thanks in advance.

We pretty much only do windows here. That is the original guide we started with, then trimmed parts of it down. https://github.com/LiamLeane/ForemanWindows

You wont be using a standard ISO. You will be using WIM files, which is basically the same thing.
What are your errors, maybe I can help.

Thanks Jeff I will definitely check out the guide. The resources I used a bit old so I ran into a lot of dism errors and mounting errors. The scripts also were calling an older version of the windows deployment tools and had to be edited for the newer versions. Going to take a look at what you sent and update if I have any questions. Thanks again!

What I have wont be totally up to date. Probably havent updated in quite some time. However, the basic instructions are the same. You will just need the latest WDK kit for windows. It took me 3-4 months to get windows deploys working, back when I had no clue how any of this works. So Id be more than happy to help you through it. Any issues you run into, just reply here and we’ll get it figured out as time permits.

1 Like

There were also some issues reported when using the provisioning templates from wimaging repo in recent foreman versions, we would be happy to provide supported windows templates for all users in the community templates repo if someone contributes an initial working version of them.

So I ran into 2 initial issues. One is when loading the templates into foreman and using preview
I got the following errors:

Warning! There was an error rendering the WAIK unattend.xml template: undefined method `unpack1’ for nil:NilClass – This is on the provision.erb template

Warning! There was an error rendering the WAIK peSetup.cmd template: wrong number of arguments (given 1, expected 0) — this is for the script.erb

It let me add them so not sure if this is an issue or not.

Then when I tried to build the image for a win2012r2 I got the followings errors:

Mount-WindowsImage : The system cannot find the path specified.
At C:\Users\ksuber\Documents\Code\ForemanWimScripts\ForemanWimScripts\Functions.ps1:43 char:9

  •     Mount-WindowsImage -ImagePath $sourcesInstall -Path $tempmoun ...
    
  •     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Mount-WindowsImage], COMException
    • FullyQualifiedErrorId : Microsoft.Dism.Commands.MountWindowsImageCommand

ApplyUpdates: Adding updates from C:\Users\ksuber\desktop\wsusoffline\client\w63-x64\glb to C:\Users\ksuber\Documents\Code\ForemanWimScripts\ForemanWimScripts\working\mnt\c3vxepre.cpr
Add-WindowsPackage : An error occurred. No operation was performed.
Verify that DISM is installed properly in the image, and then try the operation again.
At C:\Users\ksuber\Documents\Code\ForemanWimScripts\ForemanWimScripts\Functions.ps1:102 char:9

  •     Add-WindowsPackage -Path $path -PackagePath $updatesPath -Log ...
    
  •     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Add-WindowsPackage], COMException
    • FullyQualifiedErrorId : Microsoft.Dism.Commands.AddWindowsPackageCommand

ApplyUpdates: Adding updates from C:\Users\ksuber\desktop\wsusoffline\client\w63-x64\glb to C:\Users\ksuber\Documents\Code\ForemanWimScripts\ForemanWimScripts\working\mnt\c3vxepre.cpr
Add-WindowsPackage : An error occurred. No operation was performed.
Verify that DISM is installed properly in the image, and then try the operation again.
At C:\Users\ksuber\Documents\Code\ForemanWimScripts\ForemanWimScripts\Functions.ps1:102 char:9

  •     Add-WindowsPackage -Path $path -PackagePath $updatesPath -Log ...
    
  •     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : NotSpecified: (:slight_smile: [Add-WindowsPackage], COMException
    • FullyQualifiedErrorId : Microsoft.Dism.Commands.AddWindowsPackageCommand

Any clue on what is causing these errors? Thanks

If I manage to get it working I’ll submit what I have. I wish the documentation was better for writing the templates and at least what needs to be in at a minimum that why I could just write my own templates from scratch.

Actually, we use some very well working templates which I’m willing to share as community template; will see what needs to be done but I think it should run out-of-the-box without having to enable unsafe parameters. Will upload them this weekend :slight_smile:

2 Likes

That would be great much appreciated thanks!!!

But, now that I’m talking about it, I seem to remember we augemented the Wimaging part (the part that let’s you generate a WIM file) a teeny tiny bit as we actually inject the WinPE image with an installation script. I’ll see to document this in a wiki post perhaps; I think Windows provisioning is well worth a big update (as it works great on foreman)! :smiley:

All those scripts error out for me now. The waik in the scripts is the wrong version and some of the variables have changed names. As soon as I fix one error I get a new one. Foreman was easy to setup for centos or ubuntu but for windows its hard to know where to start. I do agree I like the tool very much and wish to use it. I just wish I knew enough to write my own templates.

So I have managed to get the image built using the ForemanWimScripts. I changed a few things for my personal taste but for the most part they seem to work out the box. I was running into an issue where it would not mount the image but in the end this turned out to be an issue with a gpo policy we have here. After getting that addressed I was able to mount and build the image.

Now I’m trying to get these templates to run https://github.com/LiamLeane/ForemanWindows . But I’m running into errors with two of the scripts when I import them.

The script.erb gives this error: Warning! There was an error rendering the WaIK script.erb template: wrong number of arguments (given 1, expected 0)

The provision.erb gives this error: Warning! There was an error rendering the WAIK provision.erb template: undefined method `unpack1’ for nil:NilClass

When I boot the machine it gets discovered when I try to provision with windows it just boots to a boot prompt with the error: Could not find kernel image: udionly.kpxe.

Again if anyone could point me in the right direction or have any working scripts to share it would be greatly appreciated.

So is there anyone who can help with these issues or upload the templates they have so there can be a community edition? I have spent about two weeks on this with not much progress.

Yes. I can! Sorry, I wasnt getting updates on this thread for some reason.

Can you state the exact latest errors you are getting, along with what steps you are taking to get there? Also, what portion do you have working so far?

So the errors I get are the ones I listed above on the templates when importing them. Also got an error on the ipxe.erb file: Warning! There was an error rendering the ipxe.erb template: undefined method `medium_uri’ for nil:NilClass.

I tried changing it from @host.operatingsystem.medium_uri to @host.os.medium_uri and still got the same error.

The other errors are:
The script.erb gives this error: Warning! There was an error rendering the WaIK script.erb template: wrong number of arguments (given 1, expected 0)

The provision.erb gives this error: Warning! There was an error rendering the WAIK provision.erb template: undefined method `unpack1’ for nil:NilClass

I have an image built and it goes through discovery but on reboot it fails with the error:
could not find kernel image: undionly.kpxe

Not sure I’m setting Foreman up correctly for this. Under my host group which pxe loader should I be using? Under Operating sysyetm which templates go where? I think I have it right but the directions were not specific.

Right now for pxe loader I have it set to pxelinux bios if I try any other setting I got an infinite loop where it discovers reboots and discovers again.

Again the image is built I did run into issues but there were related to security in a gpo policy and image builds without an errors now.

Thanks for helping me look into this.

Some of the scripts are old and use deprecated variables. You might have to go through and change what you need. This is what my current one for Windows looks like. We only use one location, so mine is hard set. But I think you can use… @host.url_for_boot ?

#!ipxe
<%#
kind: iPXE
name: Windows iPXE
oses:
- Windows Server 2012
- Windows Server 2012 R2
- Windows Server 2016
- Windows Server 2019

%>

set sp:hex 20:20:20:20
set sp1:hex 20
set b:hex 7C:7C
set sp ${sp:string}
set sp1 ${sp1:string}
set b ${b:string}
kernel http://puppet-tftp.lab.beer.town:717/sources/Microsoft/Windows/boot/wimboot
initrd http://puppet-tftp.lab.beer.town:717/sources/Microsoft/Windows/boot/boot/BCD BCD
initrd http://puppet-tftp.lab.beer.town:717/sources/Microsoft/Windows/boot/boot/boot.sdi boot.sdi
initrd http://puppet-tftp.lab.beer.town:717/sources/Microsoft/Windows/boot/boot.wim boot.wim

echo **************************imgstat********************************
imgstat
echo ***************************ifstat********************************
ifstat
echo *****************************************************************
echo Thank you for using Foreman. Booting Into WinPE. Have a nice day.
echo *****************************************************************
echo *${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp1}${sp1}${sp1}_.-;;-._${sp}${sp}${sp}${sp}${sp}${sp1}${sp1}${sp1}${sp1}*
echo *${sp}${sp}${sp}${sp}${sp}${sp}'-..-'|${sp1}${sp1}${sp1}${b}${sp1}${sp1}${sp1}|${sp}${sp}${sp}${sp}${sp}${sp1}${sp1}${sp1}*
echo *${sp}${sp}${sp}${sp}${sp}${sp}'-..-'|_.-;;-._|${sp}${sp}${sp}${sp}${sp}${sp1}${sp1}${sp1}*
echo *${sp}${sp}${sp}${sp}${sp}${sp}'-..-'|${sp1}${sp1}${sp1}${b}${sp1}${sp1}${sp1}|${sp}${sp}${sp}${sp}${sp}${sp1}${sp1}${sp1}*
echo *${sp}${sp}${sp}${sp}${sp}${sp}'-..-'|_.-''-._|${sp}${sp}${sp}${sp}${sp}${sp1}${sp1}${sp1}*
echo *${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp}${sp1}${sp1}${sp1}*
echo *****************************************************************
sleep 2
boot

All of the rest of the craziness in this file just makes a pretty looking Windows ascii graphic on boot.

Perhaps you could share the script.erb or provision.erb - I have nothing in mine with any methods called unpack1.
Here is what my windows provision.erb script looks like:

<%#
kind: provision
name: Windows Unattend
oses:
- Windows Server 2012
- Windows Server 2012 R2
- Windows Server 2016

This template accepts the following parameters:
- windowsLicenseKey: ABCDE-ABCDE-ABCDE-ABCDE-ABCDE # Valid Windows license key
- windowsLicenseOwner: Company, INC # Legal owner of the Windows license key
%>

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <servicing></servicing>
    <settings pass="offlineServicing">
        <component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <EnableLUA>false</EnableLUA>
        </component>
    </settings>    
    <settings pass="oobeSystem">
        <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <InputLocale>en-US</InputLocale>
            <SystemLocale>en-US</SystemLocale>
            <UILanguage>en-US</UILanguage>
            <UILanguageFallback>en-US</UILanguageFallback>
            <UserLocale>en-US</UserLocale>
        </component>
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <UserAccounts>
                <AdministratorPassword>
                    <Value><%= Base64.encode64(Encoding::Converter.new("UTF-8", "UTF-16LE",:undef => nil).convert(Base64.decode64(root_pass)+"AdministratorPassword")).delete!("\n").chomp %></Value>
                    <PlainText>false</PlainText>
                </AdministratorPassword>                
            </UserAccounts>
            
            <TimeZone>Central Standard Time</TimeZone>
            <% if @host.params['windowsLicenseOwner'] -%>
                <RegisteredOrganization><%= @host.params['windowsLicenseOwner'] %></RegisteredOrganization>
                <RegisteredOwner><%= @host.params['windowsLicenseOwner'] %></RegisteredOwner>
            <% end -%>
            <OOBE>
                <HideEULAPage>true</HideEULAPage>
                <NetworkLocation>Work</NetworkLocation>
                <ProtectYourPC>1</ProtectYourPC>
                <SkipUserOOBE>true</SkipUserOOBE>
                <SkipMachineOOBE>true</SkipMachineOOBE>
            </OOBE>
            <ShowWindowsLive>false</ShowWindowsLive>            
            <% if @host.params['windowsLicenseKey'] -%>
                <ProductKey><%= @host.params['windowsLicenseKey'].to_s %></ProductKey>
            <% end -%>  
        </component>
    </settings>
    <settings pass="specialize">
        <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <InputLocale>en-US</InputLocale>
            <SystemLocale>en-US</SystemLocale>
            <UILanguage>en-US</UILanguage>
            <UILanguageFallback>en-US</UILanguageFallback>
            <UserLocale>en-US</UserLocale>
        </component>
        <component name="Microsoft-Windows-IE-ESC" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <IEHardenAdmin>false</IEHardenAdmin>
        </component>
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <ComputerName><%= @host.shortname %></ComputerName>
            <% if @host.params['windowsLicenseOwner'] -%>
                <RegisteredOrganization><%= @host.params['windowsLicenseOwner'] %></RegisteredOrganization>
                <RegisteredOwner><%= @host.params['windowsLicenseOwner'] %></RegisteredOwner>
            <% end -%>
            <TimeZone>Central Standard Time</TimeZone>
        </component>
        <component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <DomainProfile_EnableFirewall>false</DomainProfile_EnableFirewall>
            <PrivateProfile_EnableFirewall>false</PrivateProfile_EnableFirewall>
            <PublicProfile_EnableFirewall>false</PublicProfile_EnableFirewall>
        </component>
        <component name="Microsoft-Windows-ServerManager-SvrMgrNc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <DoNotOpenServerManagerAtLogon>true</DoNotOpenServerManagerAtLogon>
        </component>
        <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <fDenyTSConnections>false</fDenyTSConnections>
        </component>
        <component name="Microsoft-Windows-TerminalServices-RDP-WinStationExtensions" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <SecurityLayer>1</SecurityLayer>
            <UserAuthentication>0</UserAuthentication>
        </component>
    </settings>
    <settings pass="offlineServicing">
        <component name="Microsoft-Windows-PnpCustomizationsNonWinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <DriverPaths>
                <!--<PathAndCredentials wcm:action="add" wcm:keyValue="1">
                    
                    <Path>c:\drivers</Path>
                </PathAndCredentials>-->
            </DriverPaths>
        </component>
    </settings>
</unattend>

Just for the record, looks like Windows can generate quite long passwords which won’t fit our 255 varchar limit, so I went ahead and removed that constraint: Bug #26939: ActiveRecord::ValueTooLong: PG::StringDataRightTruncation: ERROR: value too long for type character varying(255) - Foreman

Oh neat. Surprisingly we’ve never actually ran into that issue :slight_smile:

Sorry I guess it was just a very long password :slight_smile: