Add scripts for creating an automatic windows installer iso

This commit is contained in:
Manuel Thalmann 2023-06-12 19:12:21 +02:00
parent 49f87333f0
commit 172b74694b
9 changed files with 459 additions and 0 deletions

2
.env.template Normal file
View file

@ -0,0 +1,2 @@
# The path to the Windows 11 ISO image
WIN11_IMAGE_PATH=

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.env
build/

15
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "bashdb",
"request": "launch",
"name": "Bash-Debug (simplest configuration)",
"program": "${file}",
"terminalKind": "integrated"
}
]
}

241
Autounattend.xml Normal file
View file

@ -0,0 +1,241 @@
<!--*************************************************
Windows 10 Answer File Generator
Created using Windows AFG found at:
;http://www.windowsafg.com
Installation Notes
Location:
Notes:
**************************************************-->
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="windowsPE">
<component name="Microsoft-Windows-International-Core-WinPE" 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">
<SetupUILanguage>
<UILanguage>en-US</UILanguage>
</SetupUILanguage>
<InputLocale>0807:00000807</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UILanguageFallback>en-US</UILanguageFallback>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-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">
<DiskConfiguration>
<Disk wcm:action="add">
<DiskID>0</DiskID>
<WillWipeDisk>true</WillWipeDisk>
<CreatePartitions>
<!-- Windows RE Tools partition -->
<CreatePartition wcm:action="add">
<Order>1</Order>
<Type>Primary</Type>
<Size>300</Size>
</CreatePartition>
<!-- System partition (ESP) -->
<CreatePartition wcm:action="add">
<Order>2</Order>
<Type>EFI</Type>
<Size>100</Size>
</CreatePartition>
<!-- Microsoft reserved partition (MSR) -->
<CreatePartition wcm:action="add">
<Order>3</Order>
<Type>MSR</Type>
<Size>128</Size>
</CreatePartition>
<!-- Windows partition -->
<CreatePartition wcm:action="add">
<Order>4</Order>
<Type>Primary</Type>
<Extend>true</Extend>
</CreatePartition>
</CreatePartitions>
<ModifyPartitions>
<!-- Windows RE Tools partition -->
<ModifyPartition wcm:action="add">
<Order>1</Order>
<PartitionID>1</PartitionID>
<Label>WINRE</Label>
<Format>NTFS</Format>
<TypeID>de94bba4-06d1-4d40-a16a-bfd50179d6ac</TypeID>
</ModifyPartition>
<!-- System partition (ESP) -->
<ModifyPartition wcm:action="add">
<Order>2</Order>
<PartitionID>2</PartitionID>
<Label>System</Label>
<Format>FAT32</Format>
</ModifyPartition>
<!-- MSR partition does not need to be modified -->
<ModifyPartition wcm:action="add">
<Order>3</Order>
<PartitionID>3</PartitionID>
</ModifyPartition>
<!-- Windows partition -->
<ModifyPartition wcm:action="add">
<Order>4</Order>
<PartitionID>4</PartitionID>
<Label>OS</Label>
<Letter>C</Letter>
<Format>NTFS</Format>
</ModifyPartition>
</ModifyPartitions>
</Disk>
<WillShowUI>OnError</WillShowUI>
</DiskConfiguration>
<ImageInstall>
<OSImage>
<InstallTo>
<DiskID>0</DiskID>
<PartitionID>4</PartitionID>
</InstallTo>
</OSImage>
</ImageInstall>
<UserData>
<ProductKey>
<!-- Do not uncomment the Key element if you are using trial ISOs -->
<!-- You must uncomment the Key element (and optionally insert your own key) if
you are using retail or volume license ISOs -->
<Key></Key>
<WillShowUI>Never</WillShowUI>
</ProductKey>
<AcceptEula>true</AcceptEula>
<FullName>Admin</FullName>
<Organization></Organization>
</UserData>
</component>
</settings>
<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="generalize">
<component name="Microsoft-Windows-Security-SPP" 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">
<SkipRearm>1</SkipRearm>
</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>0807:00000807</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UILanguageFallback>en-US</UILanguageFallback>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-Security-SPP-UX" 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">
<SkipAutoActivation>true</SkipAutoActivation>
</component>
<component name="Microsoft-Windows-SQMApi" 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">
<CEIPEnabled>0</CEIPEnabled>
</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>DerGeret</ComputerName>
<ProductKey>W269N-WFGWX-YVC9B-4J6C9-T83GX</ProductKey>
</component>
</settings>
<settings pass="oobeSystem">
<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">
<AutoLogon>
<Password>
<Value></Value>
<PlainText>true</PlainText>
</Password>
<Enabled>true</Enabled>
<Username>Admin</Username>
</AutoLogon>
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<NetworkLocation>Home</NetworkLocation>
<SkipUserOOBE>true</SkipUserOOBE>
<SkipMachineOOBE>true</SkipMachineOOBE>
<ProtectYourPC>1</ProtectYourPC>
</OOBE>
<UserAccounts>
<LocalAccounts>
<LocalAccount wcm:action="add">
<Password>
<Value></Value>
<PlainText>true</PlainText>
</Password>
<Description></Description>
<DisplayName>Admin</DisplayName>
<Group>Administrators</Group>
<Name>Admin</Name>
</LocalAccount>
</LocalAccounts>
</UserAccounts>
<RegisteredOrganization></RegisteredOrganization>
<RegisteredOwner>Admin</RegisteredOwner>
<DisableAutoDaylightTimeSet>false</DisableAutoDaylightTimeSet>
<FirstLogonCommands>
<SynchronousCommand wcm:action="add">
<Description>Control Panel View</Description>
<Order>1</Order>
<CommandLine>reg add
"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ControlPanel"
/v StartupPage /t REG_DWORD /d 1 /f</CommandLine>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>2</Order>
<Description>Control Panel Icon Size</Description>
<RequiresUserInput>false</RequiresUserInput>
<CommandLine>reg add
"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ControlPanel"
/v AllItemsIconView /t REG_DWORD /d 0 /f</CommandLine>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>3</Order>
<RequiresUserInput>false</RequiresUserInput>
<CommandLine>cmd /C wmic useraccount where name="Admin" set
PasswordExpires=false</CommandLine>
<Description>Password Never Expires</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>4</Order>
<RequiresUserInput>false</RequiresUserInput>
<CommandLine>powershell -c "Set-ExecutionPolicy Bypass"</CommandLine>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<Order>5</Order>
<RequiresUserInput>false</RequiresUserInput>
<CommandLine>powershell -c "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'));"</CommandLine>
</SynchronousCommand>
</FirstLogonCommands>
<TimeZone>W. Europe Standard Time</TimeZone>
</component>
</settings>
</unattend>

116
deploy.sh Executable file
View file

@ -0,0 +1,116 @@
#!/bin/bash
WIN_DISK="${WIN_DISK}";
workingDir="$(pwd)";
overlayDir="$(mktemp -d)";
pushd "${BASH_SOURCE%/*}" > /dev/null;
. "./.env" > /dev/null 2>&1;
. "./lib/choose-disk.sh";
if [ ! -z "$WIN11_IMAGE_PATH" ]
then
WIN11_IMAGE_PATH="$(bash -c "realpath $WIN11_IMAGE_PATH")";
fi;
if [ ! -f "$WIN11_IMAGE_PATH" ]
then
if [ ! -f "./.env" ]
then
cp .env.template .env;
fi;
echo "Please specify the path to the Windows 11 ISO image in your .env file located at:";
realpath --relative-to "$workingDir" "$(realpath .env)";
else
mountPath="/media/wininstall";
bootPath="/media/boot";
dataPath="/media/data";
setupLabel="winiso";
pwshArchive="./build/pwsh.zip";
editionField="Edition ID";
cp -r winfs/* "$overlayDir";
if [ ! -f "$pwshArchive" ]
then
curl -L "https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/PowerShell-7.3.4-win-x64.zip" -o "$pwshArchive";
fi;
unzip "$pwshArchive" -d "$overlayDir/PowerShell";
sudo mount --mkdir "$WIN11_IMAGE_PATH" "$mountPath";
isoFile="./build/win.iso";
mkdir -p "$(dirname "$isoFile")";
mkwinpeimg --iso --arch amd64 --overlay "$overlayDir" --windows-dir "$mountPath" "$isoFile";
sudo umount "$mountPath";
if [ ! -b "$WIN_DISK" ]
then
chooseDisk WIN_DISK;
fi;
{
echo "o";
echo "n";
echo "";
echo "";
echo "";
echo "+2G";
echo "y";
echo "t";
echo "c";
echo "a";
echo "";
echo "n";
echo "";
echo "";
echo "";
echo "";
echo "y";
echo "t";
echo "";
echo "7";
echo "w";
} | sudo fdisk "$WIN_DISK";
while true
do
disks=($(bash -c "echo $WIN_DISK*"));
[ "${#disks[@]}" -ge 3 ] && break;
done;
bootDisk="${disks[1]}";
dataDisk="${disks[2]}";
sudo mkfs.fat -F 32 -n "BOOT" "$bootDisk";
sudo mkfs.ntfs -fFL "$setupLabel" "$dataDisk";
sudo mount --mkdir "$bootDisk" "$bootPath";
sudo mount --mkdir "$dataDisk" "$dataPath";
sudo mount --mkdir "$isoFile" "$mountPath";
sudo cp -r "$mountPath"/* "$bootPath";
sudo umount "$mountPath";
sudo mount "$WIN11_IMAGE_PATH" "$mountPath";
sudo cp -r "$mountPath"/* "$dataPath";
sudo cp Autounattend.xml "$dataPath";
sudo cp -r "$mountPath/efi" "$bootPath";
wimFile="$dataPath/sources/install.wim";
while [ ! "$(echo $(wiminfo "$wimFile" 1 | grep "^$editionField" | cut -d ":" -f2))" == "Professional" ]
do
sudo wimdelete --soft "$wimFile" 1;
done;
while wiminfo "$wimFile" 2 2>&1 > /dev/null
do
sudo wimdelete --soft "$wimFile" 2;
done;
sudo umount "$mountPath";
sudo umount "$bootPath";
sudo umount "$dataPath";
sudo rm -rf "$mountPath" "$bootPath" "$dataPath";
fi;
popd > /dev/null;

59
lib/choose-disk.sh Normal file
View file

@ -0,0 +1,59 @@
#!/bin/bash
function chooseDisk() {
local -n result="$1";
local message="$2";
local choice;
local disk;
local -a disks;
local i;
disks=();
while read disk
do
local -a diskInfo;
diskInfo=($disk);
if [ "${diskInfo[2]}" == "TYPE" ] || [ "${diskInfo[2]}" == "disk" ]
then
disks+=("$disk");
fi;
done < <(lsblk -do NAME,SIZE,TYPE);
diskCount="$(expr "${#disks[@]}" - 1)";
padding="${#diskCount}";
if [ "$diskCount" -gt 0 ]
then
while true
do
echo "$message";
for i in $(seq 0 "$(expr "$diskCount")")
do
local index;
if [ "$i" -eq 0 ]
then
index="";
else
index="$i:";
fi;
printf "%$(expr "${diskCount}" + 1)s ${disks[$i]}" "$index";
echo "";
done;
read -p "Your choice: " choice;
if [ "$choice" -ge 1 ] && [ "$choice" -le "$diskCount" ]
then
disk=(${disks[$choice]});
result="/dev/${disk[0]}";
return;
else
>&2 echo "The specified choice \"$choice\" is invalid!";
fi;
done;
else
>&2 echo "No valid disk found!";
fi;
}

8
winfs/Scripts/Setup.cmd Normal file
View file

@ -0,0 +1,8 @@
@echo off
rem
rem Run PowerShell script to start Windows Setup
rem
cls
echo.
echo Starting windows Setup...
X:\PowerShell\pwsh.exe -ExecutionPolicy bypass -file "X:\Scripts\Setup.ps1"

13
winfs/Scripts/Setup.ps1 Normal file
View file

@ -0,0 +1,13 @@
function Invoke-Diskpart {
param (
$script
)
$file = New-TemporaryFile;
$null = Set-Content "$file" "$script";
& diskpart -s "$file";
}
$drives = & wmic volume get "DriveLetter,Label";
$drive = $($($drives | Select-String -Pattern "winiso") -split "\s+")[0];
& "$drive\setup.exe";

View file

@ -0,0 +1,3 @@
wpeinit
powercfg /s 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
X:\Scripts\Setup.cmd