feat: Refactor Windows answer file handling into separate script (#1923)

This commit is contained in:
Kroese
2026-07-21 14:05:28 +02:00
committed by GitHub
parent a831593327
commit ef49e7bb0b
4 changed files with 1381 additions and 1376 deletions
-856
View File
@@ -1298,864 +1298,8 @@ validVersion() {
return 1
}
validateResolution() {
local name="$1"
local value="$2"
local minimum="$3"
local number
if [[ ! "$value" =~ ^[0-9]+$ ]] || [ "${#value}" -gt 5 ]; then
error "The $name variable must be between $minimum and 16384!"
return 1
fi
number=$((10#$value))
if [ "$number" -lt "$minimum" ] || [ "$number" -gt 16384 ]; then
error "The $name variable must be between $minimum and 16384!"
return 1
fi
return 0
}
validateProductKey() {
local value="$1"
[ -z "$value" ] && return 0
if [[ ! "$value" =~ ^[A-Za-z0-9]{5}(-[A-Za-z0-9]{5}){4}$ ]]; then
error "The KEY variable must contain a valid 25-character product key!"
return 1
fi
return 0
}
validateComputerName() {
local value="$1"
[ -z "$value" ] && return 0
if [ "${#value}" -gt 15 ]; then
error "The HOST variable cannot contain more than 15 characters!"
return 1
fi
if [[ ! "$value" =~ ^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$ ]]; then
error "The HOST variable may only contain letters, digits, and hyphens, and cannot start or end with a hyphen!"
return 1
fi
if [[ "$value" =~ ^[0-9]+$ ]]; then
error "The HOST variable cannot contain only digits!"
return 1
fi
return 0
}
validateWorkgroup() {
local value="$1"
local safe=""
[ -z "$value" ] && return 0
if [ "${#value}" -gt 15 ]; then
error "The WORKGROUP variable cannot contain more than 15 characters!"
return 1
fi
safe=$(printf '%s' "$value" | tr -d '"/\\[]:;|=,+*?<>') || return 1
if [[ "$safe" != "$value" ]]; then
error "The WORKGROUP variable contains characters that are not valid in a NetBIOS name!"
return 1
fi
if [[ "$value" =~ ^[.[:space:]]+$ ]]; then
error "The WORKGROUP variable cannot consist only of spaces or periods!"
return 1
fi
return 0
}
validateMembership() {
if [ -n "$DOMAIN" ] && [ -n "$WORKGROUP" ]; then
error "The DOMAIN and WORKGROUP variables cannot be used together!"
return 1
fi
if [ -n "$DOMAIN_OU" ] && [ -z "$DOMAIN" ]; then
error "The DOMAIN_OU variable requires DOMAIN to be specified!"
return 1
fi
validateWorkgroup "$WORKGROUP" || return 1
return 0
}
validateLegacyText() {
local name="$1"
local value="$2"
local desc="${3:-}"
local suffix=""
[ -n "$desc" ] && suffix=" for $desc"
if [[ "$value" =~ [[:cntrl:]] ]]; then
error "The $name variable cannot contain control characters$suffix!"
return 1
fi
if [[ "$value" == *'"'* ]]; then
error "The $name variable cannot contain double quotes$suffix!"
return 1
fi
return 0
}
validateLegacyUsername() {
local value="$1"
local desc="${2:-}"
local suffix=""
[ -n "$desc" ] && suffix=" for $desc"
if [ -z "$value" ]; then
error "The USERNAME variable cannot be empty$suffix!"
return 1
fi
if [ "${#value}" -gt 20 ]; then
error "The USERNAME variable cannot contain more than 20 characters$suffix!"
return 1
fi
if [[ "$value" =~ [[:cntrl:]] ]]; then
error "The USERNAME variable cannot contain control characters$suffix!"
return 1
fi
case "$value" in
*'"'* | *'/'* | *\\* | *'['* | *']'* | *':'* | *';'* | *'|'* | *'='* | *','* | *'+'* | *'*'* | *'?'* | *'<'* | *'>'* )
error "The USERNAME variable contains unsupported characters$suffix!"
return 1 ;;
esac
if [[ "$value" == *"." ]]; then
error "The USERNAME variable cannot end with a period$suffix!"
return 1
fi
if [[ "$value" =~ ^[.[:space:]]+$ ]]; then
error "The USERNAME variable cannot consist only of spaces or periods$suffix!"
return 1
fi
if [[ "${value^^}" == "GUEST" ]]; then
error "The USERNAME value \"$value\" is reserved for a built-in Windows account$suffix!"
return 1
fi
return 0
}
validatePassword() {
local value="$1"
local desc="${2:-}"
local suffix=""
[ -n "$desc" ] && suffix=" for $desc"
if [ "${#value}" -gt 127 ]; then
error "The PASSWORD variable cannot contain more than 127 characters$suffix!"
return 1
fi
if [[ "$value" =~ [[:cntrl:]] ]]; then
error "The PASSWORD variable cannot contain control characters$suffix!"
return 1
fi
return 0
}
escapeSIFValue() {
local s="$1"
s=${s//%/%%}
s=${s//\"/\"\"}
printf '%s' "$s"
return 0
}
escapeRegistryValue() {
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
}
addFolder() {
local src="$1"
local folder="/oem" file=""
local dest="$src/\$OEM\$/\$1/OEM"
[ ! -d "$folder" ] && folder="/OEM"
[ ! -d "$folder" ] && folder="$STORAGE/oem"
[ ! -d "$folder" ] && folder="$STORAGE/OEM"
[ ! -d "$folder" ] && folder=""
[ -z "$folder" ] && [ -z "$COMMAND" ] && return 0
local msg="Adding OEM files to image..."
info "$msg" && html "$msg"
mkdir -p "$dest" || return 1
if [ -n "$folder" ]; then
cp -Lr "$folder/." "$dest" || return 1
fi
file=$(find "$dest" -maxdepth 1 -type f -iname install.bat -print -quit) || return 1
if [ -n "$COMMAND" ]; then
[ -z "$file" ] && file="$dest/install.bat"
if [ -s "$file" ]; then
printf '\n' >> "$file" || return 1
fi
printf '%s\n' "$COMMAND" >> "$file" || return 1
fi
if [ -f "$file" ]; then
if ! unix2dos -q "$file"; then
error "Failed to convert $file to DOS format!"
return 1
fi
fi
return 0
}
prepareInstall() {
local pid=""
local file=""
local dir="$2"
local desc="$3"
local driver="$4"
local drivers="/tmp/drivers"
if [ -n "$DOMAIN" ]; then
error "The DOMAIN variable is not supported for $desc!"
return 1
fi
ETFS="[BOOT]/Boot-NoEmul.img"
if [ ! -f "$dir/$ETFS" ] || [ ! -s "$dir/$ETFS" ]; then
error "Failed to locate file \"$ETFS\" in $desc ISO image!" && return 1
fi
local arch target
[ -d "$dir/AMD64" ] && arch="amd64" || arch="x86"
[[ "${arch,,}" == "x86" ]] && target="$dir/I386" || target="$dir/AMD64"
if [ ! -d "$target" ]; then
error "Failed to locate directory \"$target\" in $desc ISO image!" && return 1
fi
if [[ "${driver,,}" == "xp" || "${driver,,}" == "2k3" ]]; then
local msg="Adding drivers to image..."
info "$msg" && html "$msg"
rm -rf "$drivers" || return 1
mkdir -p "$drivers" || return 1
if ! bsdtar -xf /var/drivers.txz -C "$drivers"; then
error "Failed to extract drivers!" && return 1
fi
if [ ! -f "$drivers/viostor/$driver/$arch/viostor.sys" ]; then
error "Failed to locate required storage drivers!" && return 1
fi
cp -L "$drivers/viostor/$driver/$arch/viostor.sys" "$target" || return 1
mkdir -p "$dir/\$OEM\$/\$1/Drivers/viostor" || return 1
cp -L "$drivers/viostor/$driver/$arch/viostor.cat" "$dir/\$OEM\$/\$1/Drivers/viostor" || return 1
cp -L "$drivers/viostor/$driver/$arch/viostor.inf" "$dir/\$OEM\$/\$1/Drivers/viostor" || return 1
cp -L "$drivers/viostor/$driver/$arch/viostor.sys" "$dir/\$OEM\$/\$1/Drivers/viostor" || return 1
if [ ! -f "$drivers/NetKVM/$driver/$arch/netkvm.sys" ]; then
error "Failed to locate required network drivers!" && return 1
fi
mkdir -p "$dir/\$OEM\$/\$1/Drivers/NetKVM" || return 1
cp -L "$drivers/NetKVM/$driver/$arch/netkvm.cat" "$dir/\$OEM\$/\$1/Drivers/NetKVM" || return 1
cp -L "$drivers/NetKVM/$driver/$arch/netkvm.inf" "$dir/\$OEM\$/\$1/Drivers/NetKVM" || return 1
cp -L "$drivers/NetKVM/$driver/$arch/netkvm.sys" "$dir/\$OEM\$/\$1/Drivers/NetKVM" || return 1
file=$(find "$target" -maxdepth 1 -type f -iname TXTSETUP.SIF -print -quit) || return 1
if [ -z "$file" ]; then
error "The file TXTSETUP.SIF could not be found!" && return 1
fi
sed -i '/^\[SCSI.Load\]/s/$/\nviostor=viostor.sys,4/' "$file" || return 1
sed -i '/^\[SourceDisksFiles.'"$arch"'\]/s/$/\nviostor.sys=1,,,,,,4_,4,1,,,1,4/' "$file" || return 1
sed -i '/^\[SCSI\]/s/$/\nviostor=\"Red Hat VirtIO SCSI Disk Device\"/' "$file" || return 1
sed -i '/^\[HardwareIdsDatabase\]/s/$/\nPCI\\VEN_1AF4\&DEV_1001\&SUBSYS_00000000=\"viostor\"/' "$file" || return 1
sed -i '/^\[HardwareIdsDatabase\]/s/$/\nPCI\\VEN_1AF4\&DEV_1001\&SUBSYS_00020000=\"viostor\"/' "$file" || return 1
sed -i '/^\[HardwareIdsDatabase\]/s/$/\nPCI\\VEN_1AF4\&DEV_1001\&SUBSYS_00021AF4=\"viostor\"/' "$file" || return 1
if [ ! -d "$drivers/sata/xp/$arch" ]; then
error "Failed to locate required SATA drivers!" && return 1
fi
mkdir -p "$dir/\$OEM\$/\$1/Drivers/sata" || return 1
cp -Lr "$drivers/sata/xp/$arch/." "$dir/\$OEM\$/\$1/Drivers/sata" || return 1
cp -Lr "$drivers/sata/xp/$arch/." "$target" || return 1
sed -i '/^\[SCSI.Load\]/s/$/\niaStor=iaStor.sys,4/' "$file" || return 1
sed -i '/^\[FileFlags\]/s/$/\niaStor.sys = 16/' "$file" || return 1
sed -i '/^\[SourceDisksFiles.'"$arch"'\]/s/$/\niaStor.cat = 1,,,,,,,1,0,0/' "$file" || return 1
sed -i '/^\[SourceDisksFiles.'"$arch"'\]/s/$/\niaStor.inf = 1,,,,,,,1,0,0/' "$file" || return 1
sed -i '/^\[SourceDisksFiles.'"$arch"'\]/s/$/\niaStor.sys = 1,,,,,,4_,4,1,,,1,4/' "$file" || return 1
sed -i '/^\[SourceDisksFiles.'"$arch"'\]/s/$/\niaStor.sys = 1,,,,,,,1,0,0/' "$file" || return 1
sed -i '/^\[SourceDisksFiles.'"$arch"'\]/s/$/\niaahci.cat = 1,,,,,,,1,0,0/' "$file" || return 1
sed -i '/^\[SourceDisksFiles.'"$arch"'\]/s/$/\niaAHCI.inf = 1,,,,,,,1,0,0/' "$file" || return 1
sed -i '/^\[SCSI\]/s/$/\niaStor=\"Intel\(R\) SATA RAID\/AHCI Controller\"/' "$file" || return 1
sed -i '/^\[HardwareIdsDatabase\]/s/$/\nPCI\\VEN_8086\&DEV_2922\&CC_0106=\"iaStor\"/' "$file" || return 1
rm -rf "$drivers" || return 1
fi
local key setup
setup=$(find "$target" -maxdepth 1 -type f -iname setupp.ini -print -quit) || return 1
if [ -n "$setup" ] && [ -z "$KEY" ]; then
pid=$(<"$setup") || return 1
pid="${pid%$'\r'}"
if [[ "$driver" == "2k" ]]; then
echo "${pid:0:$((${#pid})) - 3}270" > "$setup" || return 1
else
if [[ "$pid" == *"270" ]]; then
warn "this version of $desc requires a volume license key (VLK), it will ask for one during installation."
else
file=$(find "$target" -maxdepth 1 -type f -iname PID.INF -print -quit) || return 1
if [ -n "$file" ]; then
if [[ "$driver" == "2k3" ]]; then
key=$(grep -i -A 2 "StagingKey" "$file" | tail -n 2 | head -n 1) || key=""
else
key="${pid:$((${#pid})) - 8:5}"
if [[ "${pid^^}" == *"OEM" ]]; then
key=$(grep -i -A 2 "$key" "$file" | tail -n 2 | head -n 1) || key=""
else
key=$(grep -i -m 1 -A 2 "$key" "$file" | tail -n 2 | head -n 1) || key=""
fi
key="${key#*= }"
fi
key="${key%$'\r'}"
[[ "${#key}" == "29" ]] && KEY="$key"
fi
if [ -z "$KEY" ]; then
# These are NOT pirated keys, they come from official MS documentation.
case "${driver,,}" in
"xp" )
if [[ "${arch,,}" == "x86" ]]; then
# Windows XP Professional x86 generic trial key (no activation)
KEY="DR8GV-C8V6J-BYXHG-7PYJR-DB66Y"
else
# Windows XP Professional x64 generic trial key (no activation)
KEY="B2RBK-7KPT9-4JP6X-QQFWM-PJD6G"
fi ;;
"2k3" )
if [[ "${arch,,}" == "x86" ]]; then
# Windows Server 2003 Standard x86 generic trial key (no activation)
KEY="QKDCQ-TP2JM-G4MDG-VR6F2-P9C48"
else
# Windows Server 2003 Standard x64 generic trial key (no activation)
KEY="P4WJG-WK3W7-3HM8W-RWHCK-8JTRY"
fi ;;
esac
echo "${pid:0:$((${#pid})) - 3}000" > "$setup" || return 1
fi
fi
fi
fi
validateProductKey "$KEY" || return 1
local product=""
[ -n "$KEY" ] && product="ProductID=$KEY"
mkdir -p "$dir/\$OEM\$" || return 1
if ! addFolder "$dir"; then
error "Failed to add OEM folder to image!" && return 1
fi
local oem=""
local install="$dir/\$OEM\$/\$1/OEM/install.bat"
[ -f "$install" ] && oem="\"Script\"=\"cmd /C start \\\"Install\\\" \\\"cmd /C C:\\\\OEM\\\\install.bat\\\"\""
[ -z "$WIDTH" ] && WIDTH="1280"
[ -z "$HEIGHT" ] && HEIGHT="720"
validateResolution "WIDTH" "$WIDTH" 320 || return 1
validateResolution "HEIGHT" "$HEIGHT" 200 || return 1
validateMembership || return 1
validateComputerName "$HOST" || return 1
validateLegacyText "APP" "$APP" "$desc" || return 1
validateLegacyText "ENGINE" "$ENGINE" "$desc" || return 1
XHEX=$(printf '%08x\n' "$((10#$WIDTH))") || return 1
YHEX=$(printf '%08x\n' "$((10#$HEIGHT))") || return 1
local username="${USERNAME:-Docker}"
local password="${PASSWORD:-admin}"
local workgroup="${WORKGROUP:-WORKGROUP}"
local sifHost sifUsername sifPassword sifOrganization sifWorkgroup
local regUsername regPassword
validateLegacyUsername "$username" "$desc" || return 1
validatePassword "$password" "$desc" || return 1
sifHost=$(escapeSIFValue "${HOST:-*}") || return 1
sifUsername=$(escapeSIFValue "$username") || return 1
sifPassword=$(escapeSIFValue "$password") || return 1
sifOrganization=$(escapeSIFValue "$APP for $ENGINE") || return 1
sifWorkgroup=$(escapeSIFValue "$workgroup") || return 1
regUsername=$(escapeRegistryValue "$username") || return 1
regPassword=$(escapeRegistryValue "$password") || return 1
find "$target" -maxdepth 1 -type f -iname winnt.sif -delete || return 1
{ echo "[Data]"
echo " AutoPartition=1"
echo " MsDosInitiated=\"0\""
echo " UnattendedInstall=\"Yes\""
echo " AutomaticUpdates=\"Yes\""
echo ""
echo "[Unattended]"
echo " UnattendSwitch=Yes"
echo " UnattendMode=FullUnattended"
echo " FileSystem=NTFS"
echo " OemSkipEula=Yes"
echo " OemPreinstall=Yes"
echo " Repartition=Yes"
echo " WaitForReboot=\"No\""
echo " DriverSigningPolicy=\"Ignore\""
echo " NonDriverSigningPolicy=\"Ignore\""
printf '%s\n' " OemPnPDriversPath=\"Drivers\viostor;Drivers\NetKVM;Drivers\sata\""
echo " NoWaitAfterTextMode=1"
echo " NoWaitAfterGUIMode=1"
echo " FileSystem=ConvertNTFS"
echo " ExtendOemPartition=0"
echo " Hibernation=\"No\""
echo ""
echo "[GuiUnattended]"
echo " OEMSkipRegional=1"
echo " OemSkipWelcome=1"
echo " AdminPassword=\"$sifPassword\""
echo " TimeZone=0"
if disabled "$AUTOLOGIN"; then
echo " AutoLogon=No"
else
echo " AutoLogon=Yes"
echo " AutoLogonCount=65432"
fi
echo ""
echo "[UserData]"
echo " FullName=\"$sifUsername\""
echo " ComputerName=\"$sifHost\""
echo " OrgName=\"$sifOrganization\""
echo " $product"
echo ""
echo "[Identification]"
echo " JoinWorkgroup = \"$sifWorkgroup\""
echo ""
echo "[Display]"
echo " BitsPerPel=32"
echo " XResolution=$WIDTH"
echo " YResolution=$HEIGHT"
echo ""
echo "[Networking]"
echo " InstallDefaultComponents=Yes"
echo ""
echo "[Branding]"
echo " BrandIEUsingUnattended=Yes"
echo ""
echo "[URL]"
echo " Home_Page = http://www.google.com"
echo " Search_Page = http://www.google.com"
echo ""
echo "[TerminalServices]"
echo " AllowConnections=1"
echo ""
} | unix2dos > "$target/WINNT.SIF" || return 1
if [[ "$driver" == "2k3" ]]; then
{ echo "[Components]"
echo " TerminalServer=On"
echo ""
echo "[LicenseFilePrintData]"
echo " AutoMode=PerServer"
echo " AutoUsers=5"
echo ""
} | unix2dos >> "$target/WINNT.SIF" || return 1
fi
{ echo "Windows Registry Editor Version 5.00"
echo ""
echo "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Security]"
echo "\"FirstRunDisabled\"=dword:00000001"
echo "\"UpdatesDisableNotify\"=dword:00000001"
echo "\"FirewallDisableNotify\"=dword:00000001"
echo "\"AntiVirusDisableNotify\"=dword:00000001"
echo ""
echo "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wscsvc]"
echo "\"Start\"=dword:00000004"
echo ""
echo "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\GloballyOpenPorts\List]"
echo "\"3389:TCP\"=\"3389:TCP:*:Enabled:@xpsp2res.dll,-22009\""
echo ""
echo "[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Applets\Tour]"
echo "\"RunCount\"=dword:00000000"
echo ""
echo "[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced]"
echo "\"HideFileExt\"=dword:00000000"
echo ""
echo "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer]"
echo "\"NoWelcomeScreen\"=\"1\""
echo ""
echo "[HKEY_CURRENT_USER\Software\Microsoft\Internet Connection Wizard]"
echo "\"Completed\"=\"1\""
echo "\"Desktopchanged\"=\"1\""
echo ""
echo "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]"
if disabled "$AUTOLOGIN"; then
echo "\"AutoAdminLogon\"=\"0\""
else
echo "\"AutoAdminLogon\"=\"1\""
echo "\"DefaultUserName\"=\"$regUsername\""
echo "\"DefaultPassword\"=\"$regPassword\""
echo "\"DefaultDomainName\"=\"Dockur\""
fi
echo ""
printf '%s\n' "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video\{23A77BF7-ED96-40EC-AF06-9B1F4867732A}\0000]"
echo "\"DefaultSettings.BitsPerPel\"=dword:00000020"
echo "\"DefaultSettings.XResolution\"=dword:$XHEX"
echo "\"DefaultSettings.YResolution\"=dword:$YHEX"
echo ""
printf '%s\n' "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\CurrentControlSet\Control\VIDEO\{23A77BF7-ED96-40EC-AF06-9B1F4867732A}\0000]"
echo "\"DefaultSettings.BitsPerPel\"=dword:00000020"
echo "\"DefaultSettings.XResolution\"=dword:$XHEX"
echo "\"DefaultSettings.YResolution\"=dword:$YHEX"
echo ""
echo "[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce]"
printf '%s\n' "\"ScreenSaver\"=\"reg add \\\"HKCU\\\\Control Panel\\\\Desktop\\\" /f /v \\\"SCRNSAVE.EXE\\\" /t REG_SZ /d \\\"off\\\"\""
printf '%s\n' "\"ScreenSaverOff\"=\"reg add \\\"HKCU\\\\Control Panel\\\\Desktop\\\" /f /v \\\"ScreenSaveActive\\\" /t REG_SZ /d \\\"0\\\"\""
printf '%s\n' "\"SharedDrive\"=\"cmd /C net use Z: \\\\\\\\host.lan\\\\Data /persistent:yes\""
echo "$oem"
echo ""
} | unix2dos > "$dir/\$OEM\$/install.reg" || return 1
if [[ "$driver" == "2k" ]]; then
{ echo "[HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Runonce]"
echo "\"^SetupICWDesktop\"=-"
echo ""
} | unix2dos >> "$dir/\$OEM\$/install.reg" || return 1
fi
if [[ "$driver" == "2k3" ]]; then
{ echo "[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\srvWiz]"
echo "@=dword:00000000"
echo ""
echo "[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\ServerOOBE\SecurityOOBE]"
echo "\"DontLaunchSecurityOOBE\"=dword:00000000"
echo ""
} | unix2dos >> "$dir/\$OEM\$/install.reg" || return 1
fi
{ echo "Set WshShell = WScript.CreateObject(\"WScript.Shell\")"
echo "Set WshNetwork = WScript.CreateObject(\"WScript.Network\")"
echo "Set Domain = GetObject(\"WinNT://\" & WshNetwork.ComputerName)"
echo ""
echo "Function DecodeSID(binSID)"
echo " ReDim o(LenB(binSID))"
echo ""
echo " For i = 1 To LenB(binSID)"
echo " o(i-1) = AscB(MidB(binSID, i, 1))"
echo " Next"
echo ""
echo " sid = \"S-\" & CStr(o(0)) & \"-\" & OctetArrayToString _"
echo " (Array(o(2), o(3), o(4), o(5), o(6), o(7)))"
echo " For i = 8 To (4 * o(1) + 4) Step 4"
echo " sid = sid & \"-\" & OctetArrayToString _"
echo " (Array(o(i+3), o(i+2), o(i+1), o(i)))"
echo " Next"
echo ""
echo " DecodeSID = sid"
echo "End Function"
echo ""
echo "Function OctetArrayToString(arr)"
echo " v = 0"
echo " For i = 0 To UBound(arr)"
echo " v = v * 256 + arr(i)"
echo " Next"
echo ""
echo " OctetArrayToString = CStr(v)"
echo "End Function"
echo ""
echo "For Each DomainItem in Domain"
echo " If DomainItem.Class = \"User\" Then"
echo " sid = DecodeSID(DomainItem.Get(\"objectSID\"))"
echo " If Left(sid, 9) = \"S-1-5-21-\" And Right(sid, 4) = \"-500\" Then"
echo " LocalAdminADsPath = DomainItem.ADsPath"
echo " Exit For"
echo " End If"
echo " End If"
echo "Next"
echo ""
echo "Call Domain.MoveHere(LocalAdminADsPath, \"$username\")"
echo ""
echo "Set oLink = WshShell.CreateShortcut(WshShell.SpecialFolders(\"Desktop\") & \"\\Shared.lnk\")"
echo "With oLink"
printf '%s\n' " .TargetPath = \"\\\\host.lan\\Data\""
echo " .Save"
echo "End With"
echo "Set oLink = Nothing"
echo ""
} | unix2dos > "$dir/\$OEM\$/install.vbs" || return 1
{ echo "[COMMANDS]"
echo "\"REGEDIT /s install.reg\""
echo "\"Wscript install.vbs\""
echo ""
} | unix2dos > "$dir/\$OEM\$/cmdlines.txt" || return 1
return 0
}
prepareLegacy() {
local iso="$1"
local dir="$2"
local desc="$3"
local tmp="$TMP/boot-images"
local image="$tmp/eltorito_img1_bios.img"
ETFS="boot.img"
[ -s "$dir/$ETFS" ] && return 0
rm -f "$dir/$ETFS" || return 1
rm -rf "$tmp" || return 1
if ! LC_ALL=C xorriso \
-no_rc \
-osirrox on \
-indev "$iso" \
-extract_boot_images "$tmp" >/dev/null 2>&1; then
rm -rf "$tmp" || true
error "Failed to extract boot image from $desc ISO!"
return 1
fi
if [ ! -s "$image" ]; then
rm -rf "$tmp" || true
error "Failed to locate BIOS boot image in $desc ISO!"
return 1
fi
if ! mv -f "$image" "$dir/$ETFS"; then
rm -rf "$tmp" || true
error "Failed to save boot image from $desc ISO!"
return 1
fi
rm -rf "$tmp" || return 1
return 0
}
detectLegacy() {
local dir="$1"
local find
find=$(find "$dir" -maxdepth 1 -type d -iname WIN95 -print -quit)
[ -n "$find" ] && DETECTED="win95" && return 0
find=$(find "$dir" -maxdepth 1 -type d -iname WIN98 -print -quit)
[ -n "$find" ] && DETECTED="win98" && return 0
find=$(find "$dir" -maxdepth 1 -type d -iname WIN9X -print -quit)
[ -n "$find" ] && DETECTED="win9x" && return 0
find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_W.40 -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_S.40 -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_TS.40 -print -quit)
[ -n "$find" ] && DETECTED="winnt4" && return 0
find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_NT.5 -print -quit)
if [ -n "$find" ]; then
find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_IA.5 -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_ID.5 -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_IP.5 -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname CDROM_IS.5 -print -quit)
[ -n "$find" ] && DETECTED="win2k" && return 0
fi
find=$(find "$dir" -maxdepth 1 -iname WIN51 -print -quit)
if [ -n "$find" ]; then
find=$(find "$dir" -maxdepth 1 -type f -iname WIN51AP -print -quit)
[ -n "$find" ] && DETECTED="winxpx64" && return 0
find=$(find "$dir" -maxdepth 1 -type f -iname WIN51IC -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51IP -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname setupxp.htm -print -quit)
[ -n "$find" ] && DETECTED="winxpx86" && return 0
find=$(find "$dir" -maxdepth 1 -type f -iname WIN51IS -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51IA -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51IB -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51ID -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51IL -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51AA -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51AD -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51AS -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51MA -print -quit)
[ -z "$find" ] && find=$(find "$dir" -maxdepth 1 -type f -iname WIN51MD -print -quit)
[ -n "$find" ] && DETECTED="win2003r2" && return 0
fi
return 1
}
skipVersion() {
local id="$1"
case "${id,,}" in
"win9"* | "winxp"* | "win2k"* | "win2003"* )
return 0 ;;
esac
return 1
}
isCompatible() {
return 0
}
setMachine() {
local id="$1"
local iso="$2"
local dir="$3"
local desc="$4"
case "${id,,}" in
"win9"* )
ETFS="[BOOT]/Boot-1.44M.img" ;;
"win2k"* )
if ! prepareInstall "$iso" "$dir" "$desc" "2k"; then
error "Failed to prepare $desc ISO!" && return 1
fi ;;
"winxp"* )
if ! prepareInstall "$iso" "$dir" "$desc" "xp"; then
error "Failed to prepare $desc ISO!" && return 1
fi ;;
"win2003"* )
if ! prepareInstall "$iso" "$dir" "$desc" "2k3"; then
error "Failed to prepare $desc ISO!" && return 1
fi ;;
esac
case "${id,,}" in
"win9"* )
USB="no"
VGA="cirrus"
DISK_TYPE="auto"
MACHINE="pc-i440fx-2.4"
BOOT_MODE="windows_legacy"
[ -z "${ADAPTER:-}" ] && ADAPTER="pcnet" ;;
"win2k"* )
VGA="cirrus"
MACHINE="pc"
USB="pci-ohci"
DISK_TYPE="auto"
BOOT_MODE="windows_legacy"
[ -z "${ADAPTER:-}" ] && ADAPTER="rtl8139" ;;
"winxp"* | "win2003"* )
DISK_TYPE="blk"
BOOT_MODE="windows_legacy"
[ -z "${SOUND:-}" ] && SOUND="usb-audio" ;;
"winvista"* | "win7"* | "win2008"* )
BOOT_MODE="windows_legacy" ;;
esac
case "${id,,}" in
"winxp"* | "win2003"* | "winvistax86"* | "win7x86"* | "win2008r2x86"* )
# Prevent bluescreen if 64 bit PCI hole size is >2G.
ARGS="-global q35-pcihost.x-pci-hole64-fix=false" ;;
esac
return 0
}
return 0