mirror of
https://github.com/dockur/windows.git
synced 2025-10-27 11:25:49 +00:00
feat: Improved installation (#545)
This commit is contained in:
parent
a96941c63e
commit
fd83861e7d
9 changed files with 1437 additions and 271 deletions
128
src/define.sh
128
src/define.sh
|
|
@ -105,6 +105,10 @@ parseVersion() {
|
|||
VERSION="win10x64-enterprise-iot-eval"
|
||||
[ -z "$DETECTED" ] && DETECTED="win10x64-iot"
|
||||
;;
|
||||
"ltsc11" | "11ltsc" | "win11-ltsc" | "win11x64-ltsc" | "win11x64-enterprise-ltsc-eval" )
|
||||
VERSION="win11x64-enterprise-ltsc-eval"
|
||||
[ -z "$DETECTED" ] && DETECTED="win11x64-iot"
|
||||
;;
|
||||
"ltsc10" | "10ltsc" | "win10-ltsc" | "win10x64-ltsc" | "win10x64-enterprise-ltsc-eval" )
|
||||
VERSION="win10x64-enterprise-ltsc-eval"
|
||||
[ -z "$DETECTED" ] && DETECTED="win10x64-ltsc"
|
||||
|
|
@ -358,6 +362,10 @@ printVersion() {
|
|||
"win10"* ) desc="Windows 10" ;;
|
||||
"win11"* ) desc="Windows 11" ;;
|
||||
"winxp"* ) desc="Windows XP" ;;
|
||||
"win9x"* ) desc="Windows ME" ;;
|
||||
"win98"* ) desc="Windows 98" ;;
|
||||
"win95"* ) desc="Windows 95" ;;
|
||||
"win2k"* ) desc="Windows 2000" ;;
|
||||
"winvista"* ) desc="Windows Vista" ;;
|
||||
"win2025"* ) desc="Windows Server 2025" ;;
|
||||
"win2022"* ) desc="Windows Server 2022" ;;
|
||||
|
|
@ -556,19 +564,10 @@ getVersion() {
|
|||
*" enterprise"* ) id="$id-enterprise" ;;
|
||||
esac
|
||||
;;
|
||||
"win10"* )
|
||||
case "${name,,}" in
|
||||
*" iot"* ) id="$id-iot" ;;
|
||||
*" ltsc"* ) id="$id-ltsc" ;;
|
||||
*" home"* ) id="$id-home" ;;
|
||||
*" education"* ) id="$id-education" ;;
|
||||
*" enterprise evaluation"* ) id="$id-enterprise-eval" ;;
|
||||
*" enterprise"* ) id="$id-enterprise" ;;
|
||||
esac
|
||||
;;
|
||||
"win11"* )
|
||||
"win10"* | "win11"* )
|
||||
case "${name,,}" in
|
||||
*" iot"* ) id="$id-iot" ;;
|
||||
*" ltsc"* ) id="$id-ltsc" ;;
|
||||
*" home"* ) id="$id-home" ;;
|
||||
*" education"* ) id="$id-education" ;;
|
||||
*" enterprise evaluation"* ) id="$id-enterprise-eval" ;;
|
||||
|
|
@ -629,6 +628,14 @@ getMido() {
|
|||
size=6209064960
|
||||
sum="c8dbc96b61d04c8b01faf6ce0794fdf33965c7b350eaa3eb1e6697019902945c"
|
||||
;;
|
||||
"win11x64-enterprise-ltsc-eval" )
|
||||
size=4428627968
|
||||
sum="8abf91c9cd408368dc73aab3425d5e3c02dae74900742072eb5c750fc637c195"
|
||||
;;
|
||||
"win11x64-enterprise-iot-eval" )
|
||||
size=4428627968
|
||||
sum="8abf91c9cd408368dc73aab3425d5e3c02dae74900742072eb5c750fc637c195"
|
||||
;;
|
||||
"win10x64" )
|
||||
size=6140975104
|
||||
sum="a6f470ca6d331eb353b815c043e327a347f594f37ff525f17764738fe812852e"
|
||||
|
|
@ -1034,6 +1041,18 @@ getLink4() {
|
|||
"zh" | "zh-"* ) url="zh-cn_windows_11_business_editions_version_23h2_updated_april_2024_x64_dvd_3db5a62b.iso" ;;
|
||||
esac
|
||||
;;
|
||||
"win11x64-iot" | "win11x64-enterprise-iot-eval" )
|
||||
[[ "${lang,,}" != "en" ]] && [[ "${lang,,}" != "en-us" ]] && return 0
|
||||
size=4821989376
|
||||
sum="e8f1431c4e6289b3997c20eadbb2576670300bb6e1cf8948b5d7af179010a962"
|
||||
url="26100.1.240331-1435.ge_release_CLIENTENTERPRISE_OEM_x64FRE_en-us.iso"
|
||||
;;
|
||||
"win11x64-ltsc" | "win11x64-enterprise-ltsc-eval" )
|
||||
[[ "${lang,,}" != "en" ]] && [[ "${lang,,}" != "en-us" ]] && return 0
|
||||
size=4821989376
|
||||
sum="e8f1431c4e6289b3997c20eadbb2576670300bb6e1cf8948b5d7af179010a962"
|
||||
url="26100.1.240331-1435.ge_release_CLIENTENTERPRISE_OEM_x64FRE_en-us.iso"
|
||||
;;
|
||||
"win10x64" )
|
||||
case "${culture,,}" in
|
||||
"ar" | "ar-"* ) url="ar-sa_windows_10_consumer_editions_version_22h2_updated_april_2024_x64_dvd_9a92dc89.iso" ;;
|
||||
|
|
@ -1169,12 +1188,6 @@ getLink4() {
|
|||
"zh" | "zh-"* ) url="zh-cn_windows_10_enterprise_ltsc_2021_x64_dvd_033b7312.iso" ;;
|
||||
esac
|
||||
;;
|
||||
"win11x64-iot" | "win11x64-enterprise-iot-eval" )
|
||||
[[ "${lang,,}" != "en" ]] && [[ "${lang,,}" != "en-us" ]] && return 0
|
||||
size=6248140800
|
||||
sum="5d9b86ad467bc89f488d1651a6c5ad3656a7ea923f9f914510657a24c501bb86"
|
||||
url="en-us_windows_11_iot_enterprise_version_23h2_x64_dvd_fb37549c.iso"
|
||||
;;
|
||||
"win10x64-iot" | "win10x64-enterprise-iot-eval" )
|
||||
[[ "${lang,,}" != "en" ]] && [[ "${lang,,}" != "en-us" ]] && return 0
|
||||
size=4851668992
|
||||
|
|
@ -1918,6 +1931,32 @@ prepareLegacy() {
|
|||
return 1
|
||||
}
|
||||
|
||||
prepare9x() {
|
||||
|
||||
local iso="$1"
|
||||
local dir="$2"
|
||||
local file="$dir/boot.img"
|
||||
|
||||
ETFS=$(basename "$file")
|
||||
[ -f "$file" ] && [ -s "$file" ] && return 0
|
||||
rm -f "$file"
|
||||
|
||||
local src="[BOOT]/Boot-1.44M.img"
|
||||
[ ! -f "$dir/$src" ] && error "Boot floppy not found!" && return 1
|
||||
|
||||
cp "$dir/$src" "$file" && return 0
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
prepare2k() {
|
||||
|
||||
local dir="$2"
|
||||
ETFS="[BOOT]/Boot-NoEmul.img"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
prepareXP() {
|
||||
|
||||
local dir="$2"
|
||||
|
|
@ -1932,10 +1971,13 @@ prepareXP() {
|
|||
target="$dir/AMD64"
|
||||
fi
|
||||
|
||||
rm -rf "$drivers"
|
||||
local msg="Adding drivers to image..."
|
||||
info "$msg" && html "$msg"
|
||||
|
||||
if ! 7z x /run/drivers.iso -o"$drivers" > /dev/null; then
|
||||
error "Failed to extract driver ISO file!" && return 1
|
||||
mkdir -p "$drivers"
|
||||
|
||||
if ! tar -xf /drivers.txz -C "$drivers" --warning=no-timestamp; then
|
||||
error "Failed to extract driver!" && return 1
|
||||
fi
|
||||
|
||||
cp "$drivers/viostor/xp/$arch/viostor.sys" "$target"
|
||||
|
|
@ -1978,14 +2020,16 @@ prepareXP() {
|
|||
sed -i '/^\[SCSI\]/s/$/\niaStor=\"Intel\(R\) SATA RAID\/AHCI Controller\"/' "$target/TXTSETUP.SIF"
|
||||
sed -i '/^\[HardwareIdsDatabase\]/s/$/\nPCI\\VEN_8086\&DEV_2922\&CC_0106=\"iaStor\"/' "$target/TXTSETUP.SIF"
|
||||
|
||||
local key pid setup
|
||||
rm -rf "$drivers"
|
||||
|
||||
local key pid file setup
|
||||
setup=$(find "$target" -maxdepth 1 -type f -iname setupp.ini | head -n 1)
|
||||
pid=$(<"$setup")
|
||||
pid="${pid:(-4)}"
|
||||
pid="${pid:0:3}"
|
||||
|
||||
if [[ "$pid" == "270" ]]; then
|
||||
info "Warning: this XP version requires a volume license, it will reject the generic key during installation."
|
||||
warn "this version of Windows XP requires a volume license key (VLK), it will ask for one during installation."
|
||||
fi
|
||||
|
||||
if [[ "${arch,,}" == "x86" ]]; then
|
||||
|
|
@ -1998,10 +2042,28 @@ prepareXP() {
|
|||
key="B2RBK-7KPT9-4JP6X-QQFWM-PJD6G"
|
||||
fi
|
||||
|
||||
local oem=""
|
||||
local folder="/oem"
|
||||
|
||||
[ ! -d "$folder" ] && folder="/OEM"
|
||||
[ ! -d "$folder" ] && folder="$STORAGE/oem"
|
||||
[ ! -d "$folder" ] && folder="$STORAGE/OEM"
|
||||
|
||||
if [ -d "$folder" ]; then
|
||||
|
||||
file=$(find "$folder" -maxdepth 1 -type f -iname install.bat | head -n 1)
|
||||
|
||||
if [ -f "$file" ]; then
|
||||
unix2dos -q "$file"
|
||||
oem="\"Script\"=\"cmd /C start \\\"Install\\\" \\\"cmd /C C:\\\\OEM\\\\install.bat\\\"\""
|
||||
fi
|
||||
fi
|
||||
|
||||
local username="Docker"
|
||||
local password="*"
|
||||
[ -n "$USERNAME" ] && username="$USERNAME"
|
||||
|
||||
[ -n "$PASSWORD" ] && password="$PASSWORD"
|
||||
[ -n "$USERNAME" ] && username=$(echo "$USERNAME" | sed 's/[^[:alnum:]@!._-]//g')
|
||||
|
||||
find "$target" -maxdepth 1 -type f -iname winnt.sif -exec rm {} \;
|
||||
|
||||
|
|
@ -2055,9 +2117,6 @@ prepareXP() {
|
|||
echo " Home_Page = http://www.google.com"
|
||||
echo " Search_Page = http://www.google.com"
|
||||
echo ""
|
||||
echo "[RegionalSettings]"
|
||||
echo " Language=00000409"
|
||||
echo ""
|
||||
echo "[TerminalServices]"
|
||||
echo " AllowConnections=1"
|
||||
echo ""
|
||||
|
|
@ -2098,10 +2157,10 @@ prepareXP() {
|
|||
echo "\"DefaultSettings.XResolution\"=dword:00000780"
|
||||
echo "\"DefaultSettings.YResolution\"=dword:00000438"
|
||||
echo ""
|
||||
echo "[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnceEx]"
|
||||
echo "[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce]"
|
||||
echo "\"ScreenSaver\"=\"reg add \\\"HKCU\\\\Control Panel\\\\Desktop\\\" /f /v \\\"SCRNSAVE.EXE\\\" /t REG_SZ /d \\\"off\\\"\""
|
||||
echo "\"ScreenSaverOff\"=\"reg add \\\"HKCU\\\\Control Panel\\\\Desktop\\\" /f /v \\\"ScreenSaveActive\\\" /t REG_SZ /d \\\"0\\\"\""
|
||||
echo ""
|
||||
echo "$oem"
|
||||
} | unix2dos > "$dir/\$OEM\$/install.reg"
|
||||
|
||||
{ echo "Set WshShell = WScript.CreateObject(\"WScript.Shell\")"
|
||||
|
|
@ -2118,7 +2177,18 @@ prepareXP() {
|
|||
echo ""
|
||||
} | unix2dos > "$dir/\$OEM\$/cmdlines.txt"
|
||||
|
||||
rm -rf "$drivers"
|
||||
[ ! -d "$folder" ] && return 0
|
||||
|
||||
msg="Adding OEM folder to image..."
|
||||
info "$msg" && html "$msg"
|
||||
|
||||
local dest="$dir/\$OEM\$/\$1/"
|
||||
mkdir -p "$dest"
|
||||
|
||||
if ! cp -r "$folder" "$dest"; then
|
||||
error "Failed to copy OEM folder!" && return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,4 +35,4 @@ cat "$QEMU_TERM" 2> /dev/null | tee "$QEMU_PTY" &
|
|||
wait $! || :
|
||||
|
||||
sleep 1 & wait $!
|
||||
finish 0
|
||||
[ ! -f "$QEMU_END" ] && finish 0
|
||||
|
|
|
|||
391
src/install.sh
391
src/install.sh
|
|
@ -119,6 +119,7 @@ finishInstall() {
|
|||
fi
|
||||
|
||||
rm -f "$STORAGE/windows.old"
|
||||
rm -f "$STORAGE/windows.type"
|
||||
rm -f "$STORAGE/windows.base"
|
||||
rm -f "$STORAGE/windows.boot"
|
||||
rm -f "$STORAGE/windows.mode"
|
||||
|
|
@ -149,21 +150,30 @@ finishInstall() {
|
|||
# Enable secure boot on multi-socket systems to workaround freeze
|
||||
if [ -n "$SOCKETS" ] && [[ "$SOCKETS" != "1" ]]; then
|
||||
BOOT_MODE="windows_secure"
|
||||
echo "$BOOT_MODE" > "$STORAGE/windows.mode"
|
||||
echo "$BOOT_MODE" > "$STORAGE/windows.mode"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${DISK_TYPE:-}" ] && [[ "${DISK_TYPE:-}" != "scsi" ]]; then
|
||||
echo "$DISK_TYPE" > "$STORAGE/windows.type"
|
||||
fi
|
||||
|
||||
rm -rf "$TMP"
|
||||
return 0
|
||||
}
|
||||
|
||||
abortInstall() {
|
||||
|
||||
local iso="$1"
|
||||
local dir="$1"
|
||||
local iso="$2"
|
||||
|
||||
[[ "${iso,,}" == *".esd" ]] && exit 60
|
||||
|
||||
if [ ! -d "$dir/EFI" ]; then
|
||||
[[ "${PLATFORM,,}" == "x64" ]] && BOOT_MODE="windows_legacy"
|
||||
fi
|
||||
|
||||
if [ -n "$CUSTOM" ]; then
|
||||
BOOT="$iso"
|
||||
REMOVE="N"
|
||||
|
|
@ -468,6 +478,7 @@ detectLanguage() {
|
|||
setXML() {
|
||||
|
||||
local file="/custom.xml"
|
||||
|
||||
[ ! -f "$file" ] || [ ! -s "$file" ] && file="$STORAGE/custom.xml"
|
||||
[ ! -f "$file" ] || [ ! -s "$file" ] && file="/run/assets/custom.xml"
|
||||
[ ! -f "$file" ] || [ ! -s "$file" ] && file="$1"
|
||||
|
|
@ -478,11 +489,81 @@ setXML() {
|
|||
return 0
|
||||
}
|
||||
|
||||
detectLegacy() {
|
||||
|
||||
local dir="$1"
|
||||
local find find2 desc
|
||||
|
||||
find=$(find "$dir" -maxdepth 1 -type d -iname win95 | head -n 1)
|
||||
|
||||
if [ -n "$find" ]; then
|
||||
DETECTED="win95"
|
||||
desc=$(printEdition "$DETECTED" "Windows 95")
|
||||
info "Detected: $desc" && return 0
|
||||
fi
|
||||
|
||||
find=$(find "$dir" -maxdepth 1 -type d -iname win98 | head -n 1)
|
||||
|
||||
if [ -n "$find" ]; then
|
||||
DETECTED="win98"
|
||||
desc=$(printEdition "$DETECTED" "Windows 98")
|
||||
info "Detected: $desc" && return 0
|
||||
fi
|
||||
|
||||
find=$(find "$dir" -maxdepth 1 -type d -iname win9x | head -n 1)
|
||||
|
||||
if [ -n "$find" ]; then
|
||||
DETECTED="win9x"
|
||||
desc=$(printEdition "$DETECTED" "Windows ME")
|
||||
info "Detected: $desc" && return 0
|
||||
fi
|
||||
|
||||
find=$(find "$dir" -maxdepth 1 -type d -iname win51 | head -n 1)
|
||||
find2=$(find "$dir" -maxdepth 1 -type f -iname setupxp.htm | head -n 1)
|
||||
|
||||
if [ -n "$find" ] || [ -n "$find2" ] || [ -f "$dir/WIN51AP" ] || [ -f "$dir/WIN51IC" ]; then
|
||||
[ -d "$dir/AMD64" ] && DETECTED="winxpx64" || DETECTED="winxpx86"
|
||||
desc=$(printEdition "$DETECTED" "Windows XP")
|
||||
info "Detected: $desc" && return 0
|
||||
fi
|
||||
|
||||
if [ -f "$dir/CDROM_NT.5" ]; then
|
||||
DETECTED="win2kx86"
|
||||
desc=$(printEdition "$DETECTED" "Windows 2000")
|
||||
info "Detected: $desc" && return 0
|
||||
fi
|
||||
|
||||
if [ -f "$dir/WIN51AA" ] || [ -f "$dir/WIN51AD" ] || [ -f "$dir/WIN51AS" ] || [ -f "$dir/WIN51MA" ] || [ -f "$dir/WIN51MD" ]; then
|
||||
desc="Windows Server 2003"
|
||||
info "Detected: $desc" && error "$desc is not supported yet!" && exit 54
|
||||
fi
|
||||
|
||||
if [ -f "$dir/WIN51IA" ] || [ -f "$dir/WIN51IB" ] || [ -f "$dir/WIN51ID" ] || [ -f "$dir/WIN51IL" ] || [ -f "$dir/WIN51IS" ]; then
|
||||
desc="Windows Server 2003"
|
||||
info "Detected: $desc" && error "$desc is not supported yet!" && exit 54
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
skipVersion() {
|
||||
|
||||
local version="$1"
|
||||
|
||||
case "${version,,}" in
|
||||
"win2k"* | "winxp"* | "win9"* )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
detectImage() {
|
||||
|
||||
local dir="$1"
|
||||
local version="$2"
|
||||
local desc msg language
|
||||
local desc msg find language
|
||||
|
||||
XML=""
|
||||
|
||||
|
|
@ -492,7 +573,7 @@ detectImage() {
|
|||
|
||||
if [ -n "$DETECTED" ]; then
|
||||
|
||||
[[ "${DETECTED,,}" == "winxp"* ]] && return 0
|
||||
skipVersion "${DETECTED,,}" && return 0
|
||||
|
||||
if ! setXML "" && [[ "$MANUAL" != [Yy1]* ]]; then
|
||||
MANUAL="Y"
|
||||
|
|
@ -504,31 +585,23 @@ detectImage() {
|
|||
fi
|
||||
|
||||
info "Detecting version from ISO image..."
|
||||
detectLegacy "$dir" && return 0
|
||||
|
||||
if [ -f "$dir/WIN51" ] || [ -f "$dir/SETUPXP.HTM" ]; then
|
||||
[ -d "$dir/AMD64" ] && DETECTED="winxpx64" || DETECTED="winxpx86"
|
||||
desc=$(printEdition "$DETECTED" "Windows XP")
|
||||
info "Detected: $desc"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local src loc info
|
||||
local src wim info
|
||||
src=$(find "$dir" -maxdepth 1 -type d -iname sources | head -n 1)
|
||||
|
||||
if [ ! -d "$src" ]; then
|
||||
[[ "${PLATFORM,,}" == "x64" ]] && BOOT_MODE="windows_legacy"
|
||||
warn "failed to locate 'sources' folder in ISO image, $FB" && return 1
|
||||
fi
|
||||
|
||||
loc=$(find "$src" -maxdepth 1 -type f -iname install.wim | head -n 1)
|
||||
[ ! -f "$loc" ] && loc=$(find "$src" -maxdepth 1 -type f -iname install.esd | head -n 1)
|
||||
wim=$(find "$src" -maxdepth 1 -type f -iname install.wim | head -n 1)
|
||||
[ ! -f "$wim" ] && wim=$(find "$src" -maxdepth 1 -type f -iname install.esd | head -n 1)
|
||||
|
||||
if [ ! -f "$loc" ]; then
|
||||
[[ "${PLATFORM,,}" == "x64" ]] && BOOT_MODE="windows_legacy"
|
||||
if [ ! -f "$wim" ]; then
|
||||
warn "failed to locate 'install.wim' or 'install.esd' in ISO image, $FB" && return 1
|
||||
fi
|
||||
|
||||
info=$(wimlib-imagex info -xml "$loc" | tr -d '\000')
|
||||
info=$(wimlib-imagex info -xml "$wim" | tr -d '\000')
|
||||
! checkPlatform "$info" && exit 67
|
||||
|
||||
DETECTED=$(detectVersion "$info")
|
||||
|
|
@ -575,19 +648,33 @@ prepareImage() {
|
|||
local missing
|
||||
|
||||
case "${DETECTED,,}" in
|
||||
"win9"* | "win2k"* )
|
||||
MACHINE="pc-i440fx-2.4" ;;
|
||||
"winxp"* | "winvistax86"* | "win7x86"* )
|
||||
MACHINE="pc-q35-2.10"
|
||||
;;
|
||||
MACHINE="pc-q35-2.10" ;;
|
||||
esac
|
||||
|
||||
case "${DETECTED,,}" in
|
||||
"win9"* | "winxp"* | "win2k"* )
|
||||
HV="N"
|
||||
BOOT_MODE="windows_legacy" ;;
|
||||
"winvista"* | "win7"* | "win2008"* )
|
||||
BOOT_MODE="windows_legacy" ;;
|
||||
esac
|
||||
|
||||
case "${DETECTED,,}" in
|
||||
"winxp"* )
|
||||
BOOT_MODE="windows_legacy"
|
||||
DISK_TYPE="blk"
|
||||
prepareXP "$iso" "$dir" && return 0
|
||||
error "Failed to prepare Windows XP ISO!" && return 1
|
||||
;;
|
||||
"winvista"* | "win7"* | "win2008"* )
|
||||
BOOT_MODE="windows_legacy" ;;
|
||||
error "Failed to prepare Windows XP ISO!" && return 1 ;;
|
||||
"win9"* )
|
||||
DISK_TYPE="auto"
|
||||
prepare9x "$iso" "$dir" && return 0
|
||||
error "Failed to prepare Windows 9x ISO!" && return 1 ;;
|
||||
"win2k"* )
|
||||
DISK_TYPE="auto"
|
||||
prepare2k "$iso" "$dir" && return 0
|
||||
error "Failed to prepare Windows 2000 ISO!" && return 1 ;;
|
||||
esac
|
||||
|
||||
if [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then
|
||||
|
|
@ -596,10 +683,9 @@ prepareImage() {
|
|||
|
||||
missing=$(basename "$dir/$EFISYS")
|
||||
[ ! -f "$dir/$ETFS" ] && missing=$(basename "$dir/$ETFS")
|
||||
warn "failed to locate file '${missing,,}' in ISO image!"
|
||||
|
||||
[[ "${PLATFORM,,}" == "arm64" ]] && return 1
|
||||
BOOT_MODE="windows_legacy"
|
||||
error "failed to locate file '${missing,,}' in ISO image!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
prepareLegacy "$iso" "$dir" && return 0
|
||||
|
|
@ -659,6 +745,118 @@ updateXML() {
|
|||
return 0
|
||||
}
|
||||
|
||||
addDriver() {
|
||||
|
||||
local id="$1"
|
||||
local path="$2"
|
||||
local target="$3"
|
||||
local driver="$4"
|
||||
local folder=""
|
||||
|
||||
case "${id,,}" in
|
||||
"win7x86"* ) folder="w7/x86" ;;
|
||||
"win7x64"* ) folder="w7/amd64" ;;
|
||||
"win81x64"* ) folder="w10/amd64" ;;
|
||||
"win10x64"* ) folder="w10/amd64" ;;
|
||||
"win11x64"* ) folder="w11/amd64" ;;
|
||||
"win2022"* ) folder="2k22/amd64" ;;
|
||||
"win2019"* ) folder="2k19/amd64" ;;
|
||||
"win2016"* ) folder="2k16/amd64" ;;
|
||||
"win2012"* ) folder="2k16/amd64" ;;
|
||||
"win2008"* ) folder="2k8R2/amd64" ;;
|
||||
"win10arm64"* ) folder="w10/ARM64" ;;
|
||||
"win11arm64"* ) folder="w11/ARM64" ;;
|
||||
"winvistax86"* ) folder="2k8/x86" ;;
|
||||
"winvistax64"* ) folder="2k8/amd64" ;;
|
||||
esac
|
||||
|
||||
if [ -z "$folder" ]; then
|
||||
warn "no \"$driver\" driver found for \"$DETECTED\" !" && return 0
|
||||
fi
|
||||
|
||||
[ ! -d "$path/$driver/$folder" ] && return 0
|
||||
|
||||
if [[ "${id,,}" == "winvista"* ]]; then
|
||||
[[ "${driver,,}" == "viorng" ]] && return 0
|
||||
fi
|
||||
|
||||
local dest="$path/$target/$driver"
|
||||
mv "$path/$driver/$folder" "$dest"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
addDrivers() {
|
||||
|
||||
local file="$1"
|
||||
local index="$2"
|
||||
local version="$3"
|
||||
|
||||
local msg="Adding drivers to image..."
|
||||
info "$msg" && html "$msg"
|
||||
|
||||
local drivers="$TMP/drivers"
|
||||
mkdir -p "$drivers"
|
||||
|
||||
if ! tar -xf /drivers.txz -C "$drivers" --warning=no-timestamp; then
|
||||
error "Failed to extract driver!" && return 1
|
||||
fi
|
||||
|
||||
local target="\$WinPEDriver\$"
|
||||
local dest="$drivers/$target"
|
||||
mkdir -p "$dest"
|
||||
|
||||
wimlib-imagex update "$file" "$index" --command "delete --force --recursive /$target" >/dev/null || true
|
||||
|
||||
addDriver "$version" "$drivers" "$target" "qxl"
|
||||
addDriver "$version" "$drivers" "$target" "viofs"
|
||||
addDriver "$version" "$drivers" "$target" "sriov"
|
||||
addDriver "$version" "$drivers" "$target" "smbus"
|
||||
addDriver "$version" "$drivers" "$target" "qxldod"
|
||||
addDriver "$version" "$drivers" "$target" "viorng"
|
||||
addDriver "$version" "$drivers" "$target" "viostor"
|
||||
addDriver "$version" "$drivers" "$target" "NetKVM"
|
||||
addDriver "$version" "$drivers" "$target" "Balloon"
|
||||
addDriver "$version" "$drivers" "$target" "vioscsi"
|
||||
addDriver "$version" "$drivers" "$target" "pvpanic"
|
||||
addDriver "$version" "$drivers" "$target" "vioinput"
|
||||
addDriver "$version" "$drivers" "$target" "viogpudo"
|
||||
addDriver "$version" "$drivers" "$target" "vioserial"
|
||||
addDriver "$version" "$drivers" "$target" "qemupciserial"
|
||||
|
||||
if ! wimlib-imagex update "$file" "$index" --command "add $dest /$target" >/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -rf "$drivers"
|
||||
return 0
|
||||
}
|
||||
|
||||
addFolder() {
|
||||
|
||||
local src="$1"
|
||||
local folder="/oem"
|
||||
|
||||
[ ! -d "$folder" ] && folder="/OEM"
|
||||
[ ! -d "$folder" ] && folder="$STORAGE/oem"
|
||||
[ ! -d "$folder" ] && folder="$STORAGE/OEM"
|
||||
[ ! -d "$folder" ] && return 0
|
||||
|
||||
local msg="Adding OEM folder to image..."
|
||||
info "$msg" && html "$msg"
|
||||
|
||||
local dest="$src/\$OEM\$/\$1/"
|
||||
mkdir -p "$dest"
|
||||
|
||||
! cp -r "$folder" "$dest" && return 1
|
||||
|
||||
local file
|
||||
file=$(find "$dest" -maxdepth 1 -type f -iname install.bat | head -n 1)
|
||||
[ -f "$file" ] && unix2dos -q "$file"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
updateImage() {
|
||||
|
||||
local dir="$1"
|
||||
|
|
@ -667,9 +865,9 @@ updateImage() {
|
|||
local file="autounattend.xml"
|
||||
local org="${file//.xml/.org}"
|
||||
local dat="${file//.xml/.dat}"
|
||||
local desc path src loc xml index result
|
||||
local desc path src wim xml index result
|
||||
|
||||
[[ "${DETECTED,,}" == "winxp"* ]] && return 0
|
||||
skipVersion "${DETECTED,,}" && return 0
|
||||
|
||||
if [ ! -s "$asset" ] || [ ! -f "$asset" ]; then
|
||||
asset=""
|
||||
|
|
@ -682,29 +880,35 @@ updateImage() {
|
|||
src=$(find "$dir" -maxdepth 1 -type d -iname sources | head -n 1)
|
||||
|
||||
if [ ! -d "$src" ]; then
|
||||
[[ "${PLATFORM,,}" == "x64" ]] && BOOT_MODE="windows_legacy"
|
||||
warn "failed to locate 'sources' folder in ISO image, $FB" && return 1
|
||||
error "failed to locate 'sources' folder in ISO image, $FB" && return 1
|
||||
fi
|
||||
|
||||
loc=$(find "$src" -maxdepth 1 -type f -iname boot.wim | head -n 1)
|
||||
[ ! -f "$loc" ] && loc=$(find "$src" -maxdepth 1 -type f -iname boot.esd | head -n 1)
|
||||
wim=$(find "$src" -maxdepth 1 -type f -iname boot.wim | head -n 1)
|
||||
[ ! -f "$wim" ] && wim=$(find "$src" -maxdepth 1 -type f -iname boot.esd | head -n 1)
|
||||
|
||||
if [ ! -f "$loc" ]; then
|
||||
[[ "${PLATFORM,,}" == "x64" ]] && BOOT_MODE="windows_legacy"
|
||||
warn "failed to locate 'boot.wim' or 'boot.esd' in ISO image, $FB" && return 1
|
||||
if [ ! -f "$wim" ]; then
|
||||
error "failed to locate 'boot.wim' or 'boot.esd' in ISO image, $FB" && return 1
|
||||
fi
|
||||
|
||||
index="1"
|
||||
result=$(wimlib-imagex info -xml "$loc" | tr -d '\000')
|
||||
result=$(wimlib-imagex info -xml "$wim" | tr -d '\000')
|
||||
|
||||
if [[ "${result^^}" == *"<IMAGE INDEX=\"2\">"* ]]; then
|
||||
index="2"
|
||||
fi
|
||||
|
||||
if wimlib-imagex extract "$loc" "$index" "/$file" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex extract "$loc" "$index" "/$dat" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex extract "$loc" "$index" "/$org" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex update "$loc" "$index" --command "rename /$file /$org" > /dev/null; then
|
||||
if ! addDrivers "$wim" "$index" "$DETECTED"; then
|
||||
error "Failed to add drivers to image!" && return 1
|
||||
fi
|
||||
|
||||
if ! addFolder "$src"; then
|
||||
error "Failed to add OEM folder to image!" && return 1
|
||||
fi
|
||||
|
||||
if wimlib-imagex extract "$wim" "$index" "/$file" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex extract "$wim" "$index" "/$dat" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex extract "$wim" "$index" "/$org" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex update "$wim" "$index" --command "rename /$file /$org" > /dev/null; then
|
||||
warn "failed to backup original answer file ($file)."
|
||||
fi
|
||||
fi
|
||||
|
|
@ -723,11 +927,11 @@ updateImage() {
|
|||
cp "$asset" "$answer"
|
||||
updateXML "$answer" "$language"
|
||||
|
||||
if ! wimlib-imagex update "$loc" "$index" --command "add $answer /$file" > /dev/null; then
|
||||
if ! wimlib-imagex update "$wim" "$index" --command "add $answer /$file" > /dev/null; then
|
||||
MANUAL="Y"
|
||||
warn "failed to add answer file ($xml) to ISO image, $FB"
|
||||
else
|
||||
wimlib-imagex update "$loc" "$index" --command "add $answer /$dat" > /dev/null || true
|
||||
wimlib-imagex update "$wim" "$index" --command "add $answer /$dat" > /dev/null || true
|
||||
fi
|
||||
|
||||
rm -f "$answer"
|
||||
|
|
@ -736,10 +940,10 @@ updateImage() {
|
|||
|
||||
if [[ "$MANUAL" == [Yy1]* ]]; then
|
||||
|
||||
wimlib-imagex update "$loc" "$index" --command "delete --force /$file" > /dev/null || true
|
||||
wimlib-imagex update "$wim" "$index" --command "delete --force /$file" > /dev/null || true
|
||||
|
||||
if wimlib-imagex extract "$loc" "$index" "/$org" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex update "$loc" "$index" --command "add $TMP/$org /$file" > /dev/null; then
|
||||
if wimlib-imagex extract "$wim" "$index" "/$org" "--dest-dir=$TMP" >/dev/null 2>&1; then
|
||||
if ! wimlib-imagex update "$wim" "$index" --command "add $TMP/$org /$file" > /dev/null; then
|
||||
warn "failed to restore original answer file ($org)."
|
||||
fi
|
||||
fi
|
||||
|
|
@ -763,7 +967,7 @@ updateImage() {
|
|||
return 0
|
||||
}
|
||||
|
||||
removeDownload() {
|
||||
removeImage() {
|
||||
|
||||
local iso="$1"
|
||||
|
||||
|
|
@ -774,43 +978,10 @@ removeDownload() {
|
|||
return 0
|
||||
}
|
||||
|
||||
copyOEM() {
|
||||
|
||||
local dir="$1"
|
||||
local folder="/oem"
|
||||
local src dest file
|
||||
|
||||
[ ! -d "$folder" ] && folder="/OEM"
|
||||
[ ! -d "$folder" ] && folder="$STORAGE/oem"
|
||||
[ ! -d "$folder" ] && folder="$STORAGE/OEM"
|
||||
[ ! -d "$folder" ] && return 0
|
||||
|
||||
local msg="Copying OEM folder to image..."
|
||||
info "$msg" && html "$msg"
|
||||
|
||||
src=$(find "$dir" -maxdepth 1 -type d -iname sources | head -n 1)
|
||||
|
||||
if [ ! -d "$src" ]; then
|
||||
error "failed to locate 'sources' folder in ISO image!" && return 1
|
||||
fi
|
||||
|
||||
dest="$src/\$OEM\$/\$1/"
|
||||
mkdir -p "$dest"
|
||||
|
||||
if ! cp -r "$folder" "$dest"; then
|
||||
error "Failed to copy OEM folder!" && return 1
|
||||
fi
|
||||
|
||||
file=$(find "$dest" -maxdepth 1 -type f -iname install.bat | head -n 1)
|
||||
[ -f "$file" ] && unix2dos -q "$file"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
buildImage() {
|
||||
|
||||
local dir="$1"
|
||||
local failed="N"
|
||||
local failed=""
|
||||
local cat="BOOT.CAT"
|
||||
local log="/run/shm/iso.log"
|
||||
local base size size_gb space space_gb desc
|
||||
|
|
@ -841,31 +1012,25 @@ buildImage() {
|
|||
|
||||
if [[ "${BOOT_MODE,,}" != "windows_legacy" ]]; then
|
||||
|
||||
if ! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 4 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
|
||||
-udf -boot-info-table -eltorito-alt-boot -eltorito-boot "$EFISYS" -no-emul-boot -allow-limited-size -quiet "$dir" 2> "$log"; then
|
||||
failed="Y"
|
||||
fi
|
||||
! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 4 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
|
||||
-udf -boot-info-table -eltorito-alt-boot -eltorito-boot "$EFISYS" -no-emul-boot -allow-limited-size -quiet "$dir" 2> "$log" && failed="y"
|
||||
|
||||
else
|
||||
|
||||
if [[ "${DETECTED,,}" != "winxp"* ]]; then
|
||||
case "${DETECTED,,}" in
|
||||
"win2k"* | "winxp"* )
|
||||
! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -boot-load-seg 1984 -boot-load-size 4 -c "$cat" -iso-level 2 -J -l -D -N -joliet-long \
|
||||
-relaxed-filenames -V "${LABEL::30}" -quiet "$dir" 2> "$log" && failed="y" ;;
|
||||
"win9"* )
|
||||
! genisoimage -o "$out" -b "$ETFS" -J -r -V "${LABEL::30}" -quiet "$dir" 2> "$log" && failed="y" ;;
|
||||
* )
|
||||
! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 2 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
|
||||
-udf -allow-limited-size -quiet "$dir" 2> "$log" && failed="y" ;;
|
||||
esac
|
||||
|
||||
if ! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 2 -J -l -D -N -joliet-long -relaxed-filenames -V "${LABEL::30}" \
|
||||
-udf -allow-limited-size -quiet "$dir" 2> "$log"; then
|
||||
failed="Y"
|
||||
fi
|
||||
|
||||
else
|
||||
|
||||
if ! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -boot-load-seg 1984 -boot-load-size 4 -c "$cat" -iso-level 2 -J -l -D -N -joliet-long \
|
||||
-relaxed-filenames -V "${LABEL::30}" -quiet "$dir" 2> "$log"; then
|
||||
failed="Y"
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$failed" != "N" ]]; then
|
||||
if [ -n "$failed" ]; then
|
||||
[ -s "$log" ] && echo "$(<"$log")"
|
||||
error "Failed to build image!" && return 1
|
||||
fi
|
||||
|
|
@ -886,6 +1051,10 @@ bootWindows() {
|
|||
|
||||
[[ "${PLATFORM,,}" == "arm64" ]] && VGA="virtio-gpu"
|
||||
|
||||
if [ -s "$STORAGE/windows.type" ] && [ -f "$STORAGE/windows.type" ]; then
|
||||
DISK_TYPE=$(<"$STORAGE/windows.type")
|
||||
fi
|
||||
|
||||
if [ -s "$STORAGE/windows.mode" ] && [ -f "$STORAGE/windows.mode" ]; then
|
||||
BOOT_MODE=$(<"$STORAGE/windows.mode")
|
||||
if [ -s "$STORAGE/windows.old" ] && [ -f "$STORAGE/windows.old" ]; then
|
||||
|
|
@ -955,28 +1124,24 @@ if ! extractImage "$ISO" "$DIR" "$VERSION"; then
|
|||
fi
|
||||
|
||||
if ! detectImage "$DIR" "$VERSION"; then
|
||||
abortInstall "$ISO" && return 0
|
||||
abortInstall "$DIR" "$ISO" && return 0
|
||||
exit 60
|
||||
fi
|
||||
|
||||
if ! prepareImage "$ISO" "$DIR"; then
|
||||
abortInstall "$ISO" && return 0
|
||||
exit 60
|
||||
abortInstall "$DIR" "$ISO" && return 0
|
||||
exit 66
|
||||
fi
|
||||
|
||||
if ! updateImage "$DIR" "$XML" "$LANGUAGE"; then
|
||||
abortInstall "$ISO" && return 0
|
||||
exit 60
|
||||
fi
|
||||
|
||||
if ! removeDownload "$ISO"; then
|
||||
exit 64
|
||||
fi
|
||||
|
||||
if ! copyOEM "$DIR"; then
|
||||
abortInstall "$DIR" "$ISO" && return 0
|
||||
exit 63
|
||||
fi
|
||||
|
||||
if ! removeImage "$ISO"; then
|
||||
exit 64
|
||||
fi
|
||||
|
||||
if ! buildImage "$DIR"; then
|
||||
exit 65
|
||||
fi
|
||||
|
|
|
|||
185
src/mido.sh
185
src/mido.sh
|
|
@ -6,12 +6,18 @@ handle_curl_error() {
|
|||
local error_code="$1"
|
||||
|
||||
case "$error_code" in
|
||||
1) error "Unsupported protocol!" ;;
|
||||
2) error "Failed to initialize curl!" ;;
|
||||
3) error "The URL format is malformed!" ;;
|
||||
5) error "Failed to resolve address of proxy host!" ;;
|
||||
6) error "Failed to resolve Microsoft servers! Is there an Internet connection?" ;;
|
||||
7) error "Failed to contact Microsoft servers! Is there an Internet connection or is the server down?" ;;
|
||||
8) error "Microsoft servers returned a malformed HTTP response!" ;;
|
||||
16) error "A problem was detected in the HTTP2 framing layer!" ;;
|
||||
22) error "Microsoft servers returned a failing HTTP status code!" ;;
|
||||
23) error "Failed at writing Windows media to disk! Out of disk space or permission error?" ;;
|
||||
26) error "Ran out of memory during download!" ;;
|
||||
26) error "Failed to read Windows media from disk!" ;;
|
||||
27) error "Ran out of memory during download!" ;;
|
||||
28) error "Connection timed out to Microsoft server!" ;;
|
||||
35) error "SSL connection error from Microsoft server!" ;;
|
||||
36) error "Failed to continue earlier download!" ;;
|
||||
|
|
@ -32,22 +38,34 @@ handle_curl_error() {
|
|||
# https://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
|
||||
INT) error "Curl was interrupted!" ;;
|
||||
# There could be other signals but these are most common
|
||||
SEGV | ABRT ) error "Curl crashed! Failed exploitation attempt? Please report any core dumps to curl developers." ;;
|
||||
*) error "Curl terminated due to a fatal signal!" ;;
|
||||
SEGV | ABRT ) error "Curl crashed! Please report any core dumps to curl developers." ;;
|
||||
*) error "Curl terminated due to fatal signal $error_code !" ;;
|
||||
esac
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
get_agent() {
|
||||
|
||||
local user_agent
|
||||
|
||||
# Determine approximate latest Firefox release
|
||||
browser_version="$((124 + ($(date +%s) - 1710892800) / 2419200))"
|
||||
echo "Mozilla/5.0 (X11; Linux x86_64; rv:${browser_version}.0) Gecko/20100101 Firefox/${browser_version}.0"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
download_windows() {
|
||||
|
||||
local id="$1"
|
||||
local lang="$2"
|
||||
local desc="$3"
|
||||
local sku_id=""
|
||||
local language=""
|
||||
local session_id=""
|
||||
local browser_version=""
|
||||
local user_agent=""
|
||||
local windows_version=""
|
||||
local iso_download_link=""
|
||||
local product_edition_id=""
|
||||
|
|
@ -56,12 +74,13 @@ download_windows() {
|
|||
local language_skuid_table_html=""
|
||||
|
||||
case "${id,,}" in
|
||||
"win11${PLATFORM,,}" ) windows_version="11" ;;
|
||||
"win10${PLATFORM,,}" ) windows_version="10" ;;
|
||||
"win81${PLATFORM,,}" ) windows_version="8" ;;
|
||||
"win11x64" ) windows_version="11" ;;
|
||||
"win10x64" ) windows_version="10" ;;
|
||||
"win81x64" ) windows_version="8" ;;
|
||||
* ) error "Invalid VERSION specified, value \"$id\" is not recognized!" && return 1 ;;
|
||||
esac
|
||||
|
||||
user_agent=$(get_agent)
|
||||
language=$(getLanguage "$lang" "name")
|
||||
|
||||
local url="https://www.microsoft.com/en-us/software-download/windows$windows_version"
|
||||
|
|
@ -69,12 +88,8 @@ download_windows() {
|
|||
8 | 10) url="${url}ISO";;
|
||||
esac
|
||||
|
||||
# Determine approximate latest Firefox release
|
||||
browser_version="$((124 + ($(date +%s) - 1710892800) / 2419200))"
|
||||
local user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:${browser_version}.0) Gecko/20100101 Firefox/${browser_version}.0"
|
||||
|
||||
# uuidgen: For MacOS (installed by default) and other systems (e.g. with no /proc) that don't have a kernel interface for generating random UUIDs
|
||||
session_id="$(cat /proc/sys/kernel/random/uuid 2> /dev/null || uuidgen --random)"
|
||||
session_id=$(cat /proc/sys/kernel/random/uuid 2> /dev/null || uuidgen --random)
|
||||
|
||||
# Get product edition ID for latest release of given Windows version
|
||||
# Product edition ID: This specifies both the Windows release (e.g. 22H2) and edition ("multi-edition" is default, either Home/Pro/Edu/etc., we select "Pro" in the answer files) in one number
|
||||
|
|
@ -82,7 +97,7 @@ download_windows() {
|
|||
# Also, keeping a "$WindowsVersions" array like Fido does would be way too much of a maintenance burden
|
||||
# Remove "Accept" header that curl sends by default
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo " - Parsing download page: ${url}"
|
||||
iso_download_page_html="$(curl --silent --max-time 30 --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url")" || {
|
||||
iso_download_page_html=$(curl --silent --max-time 30 --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
|
||||
handle_curl_error $?
|
||||
return $?
|
||||
}
|
||||
|
|
@ -90,7 +105,7 @@ download_windows() {
|
|||
[[ "$DEBUG" == [Yy1]* ]] && echo -n "Getting Product edition ID: "
|
||||
# tr: Filter for only numerics to prevent HTTP parameter injection
|
||||
# head -c was recently added to POSIX: https://austingroupbugs.net/view.php?id=407
|
||||
product_edition_id="$(echo "$iso_download_page_html" | grep -Eo '<option value="[0-9]+">Windows' | cut -d '"' -f 2 | head -n 1 | tr -cd '0-9' | head -c 16)"
|
||||
product_edition_id=$(echo "$iso_download_page_html" | grep -Eo '<option value="[0-9]+">Windows' | cut -d '"' -f 2 | head -n 1 | tr -cd '0-9' | head -c 16)
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo "$product_edition_id"
|
||||
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo "Permit Session ID: $session_id"
|
||||
|
|
@ -110,17 +125,17 @@ download_windows() {
|
|||
# SKU ID: This specifies the language of the ISO. We always use "English (United States)", however, the SKU for this changes with each Windows release
|
||||
# We must make this request so our next one will be allowed
|
||||
# --data "" is required otherwise no "Content-Length" header will be sent causing HTTP response "411 Length Required"
|
||||
language_skuid_table_html="$(curl --silent --max-time 30 --request POST --user-agent "$user_agent" --data "" --header "Accept:" --max-filesize 10K --fail --proto =https --tlsv1.2 --http1.1 -- "https://www.microsoft.com/en-US/api/controls/contentinclude/html?pageId=a8f8f489-4c7f-463a-9ca6-5cff94d8d041&host=www.microsoft.com&segments=software-download,$url_segment_parameter&query=&action=getskuinformationbyproductedition&sessionId=$session_id&productEditionId=$product_edition_id&sdVersion=2")" || {
|
||||
language_skuid_table_html=$(curl --silent --max-time 30 --request POST --user-agent "$user_agent" --data "" --header "Accept:" --max-filesize 10K --fail --proto =https --tlsv1.2 --http1.1 -- "https://www.microsoft.com/en-US/api/controls/contentinclude/html?pageId=a8f8f489-4c7f-463a-9ca6-5cff94d8d041&host=www.microsoft.com&segments=software-download,$url_segment_parameter&query=&action=getskuinformationbyproductedition&sessionId=$session_id&productEditionId=$product_edition_id&sdVersion=2") || {
|
||||
handle_curl_error $?
|
||||
return $?
|
||||
}
|
||||
|
||||
# tr: Filter for only alphanumerics or "-" to prevent HTTP parameter injection
|
||||
sku_id="$(echo "$language_skuid_table_html" | grep -m 1 ">${language}<" | sed 's/"//g' | cut -d ',' -f 1 | cut -d ':' -f 2 | tr -cd '[:alnum:]-' | head -c 16)"
|
||||
sku_id=$(echo "$language_skuid_table_html" | grep -m 1 ">${language}<" | sed 's/"//g' | cut -d ',' -f 1 | cut -d ':' -f 2 | tr -cd '[:alnum:]-' | head -c 16)
|
||||
|
||||
if [ -z "$sku_id" ]; then
|
||||
language=$(getLanguage "$lang" "desc")
|
||||
error "No download for the $language language available!"
|
||||
error "No download in the $language language available for $desc!"
|
||||
return 1
|
||||
fi
|
||||
|
||||
|
|
@ -130,7 +145,7 @@ download_windows() {
|
|||
# Get ISO download link
|
||||
# If any request is going to be blocked by Microsoft it's always this last one (the previous requests always seem to succeed)
|
||||
# --referer: Required by Microsoft servers to allow request
|
||||
iso_download_link_html="$(curl --silent --max-time 30 --request POST --user-agent "$user_agent" --data "" --referer "$url" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "https://www.microsoft.com/en-US/api/controls/contentinclude/html?pageId=6e2a1789-ef16-4f27-a296-74ef7ef5d96b&host=www.microsoft.com&segments=software-download,$url_segment_parameter&query=&action=GetProductDownloadLinksBySku&sessionId=$session_id&skuId=$sku_id&language=English&sdVersion=2")"
|
||||
iso_download_link_html=$(curl --silent --max-time 30 --request POST --user-agent "$user_agent" --data "" --referer "$url" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "https://www.microsoft.com/en-US/api/controls/contentinclude/html?pageId=6e2a1789-ef16-4f27-a296-74ef7ef5d96b&host=www.microsoft.com&segments=software-download,$url_segment_parameter&query=&action=GetProductDownloadLinksBySku&sessionId=$session_id&skuId=$sku_id&language=English&sdVersion=2")
|
||||
|
||||
if ! [ "$iso_download_link_html" ]; then
|
||||
# This should only happen if there's been some change to how this API works
|
||||
|
|
@ -146,7 +161,7 @@ download_windows() {
|
|||
# Filter for 64-bit ISO download URL
|
||||
# sed: HTML decode "&" character
|
||||
# tr: Filter for only alphanumerics or punctuation
|
||||
iso_download_link="$(echo "$iso_download_link_html" | grep -o "https://software.download.prss.microsoft.com.*IsoX64" | cut -d '"' -f 1 | sed 's/&/\&/g' | tr -cd '[:alnum:][:punct:]')"
|
||||
iso_download_link=$(echo "$iso_download_link_html" | grep -o "https://software.download.prss.microsoft.com.*IsoX64" | cut -d '"' -f 1 | sed 's/&/\&/g' | tr -cd '[:alnum:][:punct:]')
|
||||
|
||||
if ! [ "$iso_download_link" ]; then
|
||||
# This should only happen if there's been some change to the download endpoint web address
|
||||
|
|
@ -162,37 +177,47 @@ download_windows_eval() {
|
|||
|
||||
local id="$1"
|
||||
local lang="$2"
|
||||
local desc="$3"
|
||||
local filter=""
|
||||
local culture=""
|
||||
local language=""
|
||||
local windows_version=""
|
||||
local user_agent=""
|
||||
local enterprise_type=""
|
||||
local windows_version=""
|
||||
|
||||
case "${id,,}" in
|
||||
"win11${PLATFORM,,}-enterprise-eval" )
|
||||
windows_version="windows-11-enterprise"
|
||||
enterprise_type="enterprise" ;;
|
||||
enterprise_type="enterprise"
|
||||
windows_version="windows-11-enterprise" ;;
|
||||
"win11${PLATFORM,,}-enterprise-iot-eval" )
|
||||
enterprise_type="iot"
|
||||
windows_version="windows-11-iot-enterprise-ltsc" ;;
|
||||
"win11${PLATFORM,,}-enterprise-ltsc-eval" )
|
||||
enterprise_type="iot"
|
||||
windows_version="windows-11-iot-enterprise-ltsc" ;;
|
||||
"win10${PLATFORM,,}-enterprise-eval" )
|
||||
windows_version="windows-10-enterprise"
|
||||
enterprise_type="enterprise" ;;
|
||||
enterprise_type="enterprise"
|
||||
windows_version="windows-10-enterprise" ;;
|
||||
"win10${PLATFORM,,}-enterprise-ltsc-eval" )
|
||||
windows_version="windows-10-enterprise"
|
||||
enterprise_type="ltsc" ;;
|
||||
enterprise_type="ltsc"
|
||||
windows_version="windows-10-enterprise" ;;
|
||||
"win2022-eval" )
|
||||
windows_version="windows-server-2022"
|
||||
enterprise_type="server" ;;
|
||||
enterprise_type="server"
|
||||
windows_version="windows-server-2022" ;;
|
||||
"win2019-eval" )
|
||||
windows_version="windows-server-2019"
|
||||
enterprise_type="server" ;;
|
||||
enterprise_type="server"
|
||||
windows_version="windows-server-2019" ;;
|
||||
"win2016-eval" )
|
||||
windows_version="windows-server-2016"
|
||||
enterprise_type="server" ;;
|
||||
enterprise_type="server"
|
||||
windows_version="windows-server-2016" ;;
|
||||
"win2012r2-eval" )
|
||||
windows_version="windows-server-2012-r2"
|
||||
enterprise_type="server" ;;
|
||||
enterprise_type="server"
|
||||
windows_version="windows-server-2012-r2" ;;
|
||||
* )
|
||||
error "Invalid VERSION specified, value \"$id\" is not recognized!" && return 1 ;;
|
||||
esac
|
||||
|
||||
user_agent=$(get_agent)
|
||||
culture=$(getLanguage "$lang" "culture")
|
||||
|
||||
local country="${culture#*-}"
|
||||
|
|
@ -200,7 +225,7 @@ download_windows_eval() {
|
|||
local url="https://www.microsoft.com/en-us/evalcenter/download-$windows_version"
|
||||
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo "Parsing download page: ${url}"
|
||||
iso_download_page_html="$(curl --silent --max-time 30 --location --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url")" || {
|
||||
iso_download_page_html=$(curl --silent --max-time 30 --user-agent "$user_agent" --location --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
|
||||
handle_curl_error $?
|
||||
return $?
|
||||
}
|
||||
|
|
@ -212,32 +237,52 @@ download_windows_eval() {
|
|||
fi
|
||||
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo "Getting download link.."
|
||||
iso_download_links="$(echo "$iso_download_page_html" | grep -o "https://go.microsoft.com/fwlink/p/?LinkID=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country^^}")" || {
|
||||
|
||||
if [[ "$enterprise_type" == "iot" ]]; then
|
||||
filter="https://go.microsoft.com/fwlink/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country^^}"
|
||||
else
|
||||
filter="https://go.microsoft.com/fwlink/p/?LinkID=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country^^}"
|
||||
fi
|
||||
|
||||
iso_download_links=$(echo "$iso_download_page_html" | grep -io "$filter") || {
|
||||
# This should only happen if there's been some change to the download endpoint web address
|
||||
if [[ "${lang,,}" == "en" ]] || [[ "${lang,,}" == "en-"* ]]; then
|
||||
error "Windows server download page gave us no download link!"
|
||||
else
|
||||
language=$(getLanguage "$lang" "desc")
|
||||
error "No download for the $language language available!"
|
||||
error "No download in the $language language available for $desc!"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Limit untrusted size for input validation
|
||||
iso_download_links="$(echo "$iso_download_links" | head -c 1024)"
|
||||
|
||||
case "$enterprise_type" in
|
||||
# Select x64 download link
|
||||
"enterprise") iso_download_link=$(echo "$iso_download_links" | head -n 2 | tail -n 1) ;;
|
||||
# Select x64 LTSC download link
|
||||
"ltsc") iso_download_link=$(echo "$iso_download_links" | head -n 4 | tail -n 1) ;;
|
||||
*) iso_download_link="$iso_download_links" ;;
|
||||
"enterprise" )
|
||||
iso_download_link=$(echo "$iso_download_links" | head -n 2 | tail -n 1)
|
||||
;;
|
||||
"iot" )
|
||||
if [[ "${PLATFORM,,}" == "x64" ]]; then
|
||||
iso_download_link=$(echo "$iso_download_links" | head -n 1)
|
||||
fi
|
||||
if [[ "${PLATFORM,,}" == "arm64" ]]; then
|
||||
iso_download_link=$(echo "$iso_download_links" | head -n 2 | tail -n 1)
|
||||
fi
|
||||
;;
|
||||
"ltsc" )
|
||||
iso_download_link=$(echo "$iso_download_links" | head -n 4 | tail -n 1)
|
||||
;;
|
||||
"server" )
|
||||
iso_download_link=$(echo "$iso_download_links" | head -n 1)
|
||||
;;
|
||||
* )
|
||||
error "Invalid type specified, value \"$enterprise_type\" is not recognized!" && return 1 ;;
|
||||
esac
|
||||
|
||||
[[ "$DEBUG" == [Yy1]* ]] && echo "Found download link: $iso_download_link"
|
||||
|
||||
# Follow redirect so proceeding log message is useful
|
||||
# This is a request we make this Fido doesn't
|
||||
# We don't need to set "--max-filesize" here because this is a HEAD request and the output is to /dev/null anyway
|
||||
iso_download_link="$(curl --silent --max-time 30 --location --output /dev/null --silent --write-out "%{url_effective}" --head --fail --proto =https --tlsv1.2 --http1.1 -- "$iso_download_link")" || {
|
||||
iso_download_link=$(curl --silent --max-time 30 --user-agent "$user_agent" --location --output /dev/null --silent --write-out "%{url_effective}" --head --fail --proto =https --tlsv1.2 --http1.1 -- "$iso_download_link") || {
|
||||
# This should only happen if the Microsoft servers are down
|
||||
handle_curl_error $?
|
||||
return $?
|
||||
|
|
@ -252,37 +297,46 @@ getWindows() {
|
|||
local version="$1"
|
||||
local lang="$2"
|
||||
local desc="$3"
|
||||
local language
|
||||
|
||||
local language edition
|
||||
language=$(getLanguage "$lang" "desc")
|
||||
edition=$(printEdition "$version" "$desc")
|
||||
|
||||
local msg="Requesting $desc from Microsoft server..."
|
||||
info "$msg" && html "$msg"
|
||||
|
||||
case "${version,,}" in
|
||||
"win2008r2" | "win81${PLATFORM,,}-enterprise-eval" | "win11${PLATFORM,,}-enterprise-iot-eval" )
|
||||
if [[ "${lang,,}" != "en" ]] && [[ "${lang,,}" != "en-"* ]]; then
|
||||
error "No download in the $language language available for $edition!"
|
||||
MIDO_URL="" && return 1
|
||||
fi ;;
|
||||
esac
|
||||
|
||||
case "${version,,}" in
|
||||
"win11${PLATFORM,,}-enterprise-iot-eval" ) ;;
|
||||
* )
|
||||
if [[ "${PLATFORM,,}" != "x64" ]]; then
|
||||
error "No download for the ${PLATFORM^^} platform available for $edition!"
|
||||
MIDO_URL="" && return 1
|
||||
fi ;;
|
||||
esac
|
||||
|
||||
case "${version,,}" in
|
||||
"win81${PLATFORM,,}" | "win10${PLATFORM,,}" | "win11${PLATFORM,,}" )
|
||||
download_windows "$version" "$lang" && return 0
|
||||
download_windows "$version" "$lang" "$edition" && return 0
|
||||
;;
|
||||
"win11${PLATFORM,,}-enterprise-eval" )
|
||||
download_windows_eval "$version" "$lang" && return 0
|
||||
;;
|
||||
"win10${PLATFORM,,}-enterprise-eval" | "win10${PLATFORM,,}-enterprise-ltsc-eval" )
|
||||
download_windows_eval "$version" "$lang" && return 0
|
||||
"win11${PLATFORM,,}-enterprise"* | "win10${PLATFORM,,}-enterprise"* )
|
||||
download_windows_eval "$version" "$lang" "$edition" && return 0
|
||||
;;
|
||||
"win2022-eval" | "win2019-eval" | "win2016-eval" | "win2012r2-eval" )
|
||||
download_windows_eval "$version" "$lang" && return 0
|
||||
download_windows_eval "$version" "$lang" "$edition" && return 0
|
||||
;;
|
||||
"win81${PLATFORM,,}-enterprise-eval" )
|
||||
if [[ "${lang,,}" == "en" ]] || [[ "${lang,,}" == "en-"* ]]; then
|
||||
MIDO_URL="https://download.microsoft.com/download/B/9/9/B999286E-0A47-406D-8B3D-5B5AD7373A4A/9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_ENTERPRISE_EVAL_EN-US-IR3_CENA_X64FREE_EN-US_DV9.ISO" && return 0
|
||||
fi
|
||||
language=$(getLanguage "$lang" "desc")
|
||||
error "No download for the $language language available!"
|
||||
MIDO_URL="https://download.microsoft.com/download/B/9/9/B999286E-0A47-406D-8B3D-5B5AD7373A4A/9600.17050.WINBLUE_REFRESH.140317-1640_X64FRE_ENTERPRISE_EVAL_EN-US-IR3_CENA_X64FREE_EN-US_DV9.ISO" && return 0
|
||||
;;
|
||||
"win2008r2" )
|
||||
if [[ "${lang,,}" == "en" ]] || [[ "${lang,,}" == "en-"* ]]; then
|
||||
MIDO_URL="https://download.microsoft.com/download/4/1/D/41DEA7E0-B30D-4012-A1E3-F24DC03BA1BB/7601.17514.101119-1850_x64fre_server_eval_en-us-GRMSXEVAL_EN_DVD.iso" && return 0
|
||||
fi
|
||||
language=$(getLanguage "$lang" "desc")
|
||||
error "No download for the $language language available!"
|
||||
MIDO_URL="https://download.microsoft.com/download/4/1/D/41DEA7E0-B30D-4012-A1E3-F24DC03BA1BB/7601.17514.101119-1850_x64fre_server_eval_en-us-GRMSXEVAL_EN_DVD.iso" && return 0
|
||||
;;
|
||||
* ) error "Invalid VERSION specified, value \"$version\" is not recognized!" ;;
|
||||
esac
|
||||
|
|
@ -385,8 +439,9 @@ getESD() {
|
|||
|
||||
size=$(stat -c%s "$dir/$eFile")
|
||||
if ((size<20)); then
|
||||
desc=$(printEdition "$version" "$desc")
|
||||
language=$(getLanguage "$lang" "desc")
|
||||
error "the $language language is not supported by this download method!" && return 1
|
||||
error "No download in the $language language available for $desc!" && return 1
|
||||
fi
|
||||
|
||||
local tag="FilePath"
|
||||
|
|
|
|||
26
src/power.sh
26
src/power.sh
|
|
@ -29,7 +29,12 @@ boot() {
|
|||
|
||||
if [ -s "$QEMU_PTY" ]; then
|
||||
if [ "$(stat -c%s "$QEMU_PTY")" -gt 7 ]; then
|
||||
if ! grep -Fq "BOOTMGR is missing" "$QEMU_PTY"; then
|
||||
local fail=""
|
||||
if [[ "${BOOT_MODE,,}" == "windows_legacy" ]]; then
|
||||
grep -Fq "No bootable device." "$QEMU_PTY" && fail="y"
|
||||
grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && fail="y"
|
||||
fi
|
||||
if [ -z "$fail" ]; then
|
||||
info "Windows started succesfully, visit http://localhost:8006/ to view the screen..."
|
||||
return 0
|
||||
fi
|
||||
|
|
@ -37,6 +42,11 @@ boot() {
|
|||
fi
|
||||
|
||||
error "Timeout while waiting for QEMU to boot the machine!"
|
||||
|
||||
local pid
|
||||
pid=$(<"$QEMU_PID")
|
||||
{ kill -15 "$pid" || true; } 2>/dev/null
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
@ -49,18 +59,14 @@ ready() {
|
|||
local last
|
||||
local bios="Booting from Hard"
|
||||
last=$(grep "^Booting.*" "$QEMU_PTY" | tail -1)
|
||||
if [[ "${last,,}" == "${bios,,}"* ]]; then
|
||||
if ! grep -Fq "BOOTMGR is missing" "$QEMU_PTY"; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
[[ "${last,,}" != "${bios,,}"* ]] && return 1
|
||||
grep -Fq "No bootable device." "$QEMU_PTY" && return 1
|
||||
grep -Fq "BOOTMGR is missing" "$QEMU_PTY" && return 1
|
||||
return 0
|
||||
fi
|
||||
|
||||
local line="\"Windows Boot Manager\""
|
||||
if grep -Fq "$line" "$QEMU_PTY"; then
|
||||
return 0
|
||||
fi
|
||||
grep -Fq "$line" "$QEMU_PTY" && return 0
|
||||
|
||||
return 1
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue