feat: Make autologin configurable (#1903)

This commit is contained in:
Kroese
2026-07-20 11:54:41 +02:00
committed by GitHub
parent 12be0a7d77
commit df5b0e639f
4 changed files with 195 additions and 59 deletions
+5 -2
View File
@@ -11,12 +11,15 @@ An empty default means the variable is unset and its value is determined automat
| `VERSION` | `11` | Windows version to install, such as `10` or `11`. | | `VERSION` | `11` | Windows version to install, such as `10` or `11`. |
| `EDITION` | | Windows edition to install, such as `core` for Windows Server Core. | | `EDITION` | | Windows edition to install, such as `core` for Windows Server Core. |
| `LANGUAGE` | `en-US` | Windows display language, such as `English`, `en-US`, or `en`. | | `LANGUAGE` | `en-US` | Windows display language, such as `English`, `en-US`, or `en`. |
| `KEY` | | Windows product key used to install and activate Windows. |
| `REGION` | | Windows regional format. Uses `LANGUAGE` when unset. | | `REGION` | | Windows regional format. Uses `LANGUAGE` when unset. |
| `KEYBOARD` | | Keyboard layout. Uses `LANGUAGE` when unset. | | `KEYBOARD` | | Keyboard layout. Uses `LANGUAGE` when unset. |
| `USERNAME` | `Docker` | Name of the Windows user account. | | `USERNAME` | `Docker` | Name of the Windows user account. |
| `PASSWORD` | `admin` | Password for the Windows account. | | `PASSWORD` | `admin` | Password for the Windows account. |
| `AUTOLOGIN` | `Y` | Automatically signs in to Windows after startup. |
| `DOMAIN` | | Active Directory domain to join during installation. | | `DOMAIN` | | Active Directory domain to join during installation. |
| `KEY` | | Windows product key used to install and activate Windows. | | `DOMAIN_OU` | | Distinguished name of the organizational unit. |
| `WORKGROUP` | | Name of the Windows workgroup to join. |
## 🧠 CPU and Memory ## 🧠 CPU and Memory
@@ -162,7 +165,7 @@ Also see [Dynamic memory allocation](https://github.com/qemus/qemu/blob/master/d
| Variable | Default | Description | | Variable | Default | Description |
|---|---|---| |---|---|---|
| `SHUTDOWN` | `Y` | Enables graceful ACPI shutdown. | | `SHUTDOWN` | `Y` | Enables graceful ACPI shutdown. |
| `TIMEOUT` | `115` | Maximum time, in seconds, to wait before forcing Windows to stop. | | `TIMEOUT` | `105` | Maximum time, in seconds, to wait before forcing Windows to stop. |
## 🐞 Debugging ## 🐞 Debugging
+3 -2
View File
@@ -171,7 +171,7 @@ kubectl apply -f https://raw.githubusercontent.com/dockur/windows/refs/heads/mas
- ./example:/shared - ./example:/shared
``` ```
Replace the example path `./example` with your desired shared folder, which then will become visible as `Shared`. Replace the example path `./example` with your desired shared folder, which then will become visible as `Shared` on the desktop and as drive `Z:`.
### How do I change the amount of CPU or RAM? ### How do I change the amount of CPU or RAM?
@@ -225,9 +225,10 @@ kubectl apply -f https://raw.githubusercontent.com/dockur/windows/refs/heads/mas
```yaml ```yaml
environment: environment:
DOMAIN: "example.com" DOMAIN: "example.com"
DOMAIN_OU: "OU=Virtual Machines,OU=Servers,DC=example,DC=com"
``` ```
Use the domain name, such as `example.com`, rather than a URL. The supplied account is added to the local Administrators group and automatically signed in after installation. Use the domain name, such as `example.com`, rather than a URL. The supplied account is added to the local Administrators group and automatically signed in after installation. `DOMAIN_OU` is optional and specifies where the computer account should be created.
Windows must be able to resolve and reach the domain controller through the domain's DNS server. Windows must be able to resolve and reach the domain controller through the domain's DNS server.
+74 -8
View File
@@ -18,6 +18,9 @@ set -Eeuo pipefail
: "${LANGUAGE:=""}" : "${LANGUAGE:=""}"
: "${USERNAME:=""}" : "${USERNAME:=""}"
: "${PASSWORD:=""}" : "${PASSWORD:=""}"
: "${DOMAIN_OU:=""}"
: "${WORKGROUP:=""}"
: "${AUTOLOGIN:=""}"
# Sanitize variables # Sanitize variables
KEY=$(strip "$KEY") KEY=$(strip "$KEY")
@@ -31,6 +34,9 @@ EDITION=$(strip "$EDITION")
KEYBOARD=$(strip "$KEYBOARD") KEYBOARD=$(strip "$KEYBOARD")
LANGUAGE=$(strip "$LANGUAGE") LANGUAGE=$(strip "$LANGUAGE")
USERNAME=$(strip "$USERNAME") USERNAME=$(strip "$USERNAME")
DOMAIN_OU=$(strip "$DOMAIN_OU")
WORKGROUP=$(strip "$WORKGROUP")
AUTOLOGIN=$(strip "$AUTOLOGIN")
MIRRORS=3 MIRRORS=3
@@ -1365,6 +1371,49 @@ validateComputerName() {
return 0 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() { validateLegacyText() {
local name="$1" local name="$1"
@@ -1426,6 +1475,11 @@ validateLegacyUsername() {
return 1 return 1
fi fi
if [[ "${value^^}" == "GUEST" ]]; then
error "The USERNAME value \"$value\" is reserved for a built-in Windows account$suffix!"
return 1
fi
return 0 return 0
} }
@@ -1704,6 +1758,7 @@ prepareInstall() {
validateResolution "WIDTH" "$WIDTH" 320 || return 1 validateResolution "WIDTH" "$WIDTH" 320 || return 1
validateResolution "HEIGHT" "$HEIGHT" 200 || return 1 validateResolution "HEIGHT" "$HEIGHT" 200 || return 1
validateMembership || return 1
validateComputerName "$HOST" || return 1 validateComputerName "$HOST" || return 1
validateLegacyText "APP" "$APP" "$desc" || return 1 validateLegacyText "APP" "$APP" "$desc" || return 1
validateLegacyText "ENGINE" "$ENGINE" "$desc" || return 1 validateLegacyText "ENGINE" "$ENGINE" "$desc" || return 1
@@ -1713,7 +1768,8 @@ prepareInstall() {
local username="${USERNAME:-Docker}" local username="${USERNAME:-Docker}"
local password="${PASSWORD:-admin}" local password="${PASSWORD:-admin}"
local sifHost sifUsername sifPassword sifOrganization local workgroup="${WORKGROUP:-WORKGROUP}"
local sifHost sifUsername sifPassword sifOrganization sifWorkgroup
local regUsername regPassword local regUsername regPassword
validateLegacyUsername "$username" "$desc" || return 1 validateLegacyUsername "$username" "$desc" || return 1
@@ -1723,6 +1779,7 @@ prepareInstall() {
sifUsername=$(escapeSIFValue "$username") || return 1 sifUsername=$(escapeSIFValue "$username") || return 1
sifPassword=$(escapeSIFValue "$password") || return 1 sifPassword=$(escapeSIFValue "$password") || return 1
sifOrganization=$(escapeSIFValue "$APP for $ENGINE") || return 1 sifOrganization=$(escapeSIFValue "$APP for $ENGINE") || return 1
sifWorkgroup=$(escapeSIFValue "$workgroup") || return 1
regUsername=$(escapeRegistryValue "$username") || return 1 regUsername=$(escapeRegistryValue "$username") || return 1
regPassword=$(escapeRegistryValue "$password") || return 1 regPassword=$(escapeRegistryValue "$password") || return 1
@@ -1756,8 +1813,12 @@ prepareInstall() {
echo " OemSkipWelcome=1" echo " OemSkipWelcome=1"
echo " AdminPassword=\"$sifPassword\"" echo " AdminPassword=\"$sifPassword\""
echo " TimeZone=0" echo " TimeZone=0"
echo " AutoLogon=Yes" if disabled "$AUTOLOGIN"; then
echo " AutoLogonCount=65432" echo " AutoLogon=No"
else
echo " AutoLogon=Yes"
echo " AutoLogonCount=65432"
fi
echo "" echo ""
echo "[UserData]" echo "[UserData]"
echo " FullName=\"$sifUsername\"" echo " FullName=\"$sifUsername\""
@@ -1766,7 +1827,7 @@ prepareInstall() {
echo " $product" echo " $product"
echo "" echo ""
echo "[Identification]" echo "[Identification]"
echo " JoinWorkgroup = WORKGROUP" echo " JoinWorkgroup = \"$sifWorkgroup\""
echo "" echo ""
echo "[Display]" echo "[Display]"
echo " BitsPerPel=32" echo " BitsPerPel=32"
@@ -1827,10 +1888,14 @@ prepareInstall() {
echo "\"Desktopchanged\"=\"1\"" echo "\"Desktopchanged\"=\"1\""
echo "" echo ""
echo "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]" echo "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]"
echo "\"AutoAdminLogon\"=\"1\"" if disabled "$AUTOLOGIN"; then
echo "\"DefaultUserName\"=\"$regUsername\"" echo "\"AutoAdminLogon\"=\"0\""
echo "\"DefaultPassword\"=\"$regPassword\"" else
echo "\"DefaultDomainName\"=\"Dockur\"" echo "\"AutoAdminLogon\"=\"1\""
echo "\"DefaultUserName\"=\"$regUsername\""
echo "\"DefaultPassword\"=\"$regPassword\""
echo "\"DefaultDomainName\"=\"Dockur\""
fi
echo "" echo ""
echo "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video\{23A77BF7-ED96-40EC-AF06-9B1F4867732A}\0000]" echo "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video\{23A77BF7-ED96-40EC-AF06-9B1F4867732A}\0000]"
echo "\"DefaultSettings.BitsPerPel\"=dword:00000020" echo "\"DefaultSettings.BitsPerPel\"=dword:00000020"
@@ -1845,6 +1910,7 @@ prepareInstall() {
echo "[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce]" 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 "\"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 "\"ScreenSaverOff\"=\"reg add \\\"HKCU\\\\Control Panel\\\\Desktop\\\" /f /v \\\"ScreenSaveActive\\\" /t REG_SZ /d \\\"0\\\"\""
echo "\"SharedDrive\"=\"cmd /C net use Z: \\\\\\\\host.lan\\\\Data /persistent:yes\""
echo "$oem" echo "$oem"
echo "" echo ""
} | unix2dos > "$dir/\$OEM\$/install.reg" || return 1 } | unix2dos > "$dir/\$OEM\$/install.reg" || return 1
+113 -47
View File
@@ -771,6 +771,8 @@ setXML() {
local file="/custom.xml" local file="/custom.xml"
CUSTOM_XML=""
if [ -d "$file" ]; then if [ -d "$file" ]; then
error "The bind $file maps to a file that does not exist!" && exit 67 error "The bind $file maps to a file that does not exist!" && exit 67
fi fi
@@ -781,6 +783,10 @@ setXML() {
[ ! -f "$file" ] || [ ! -s "$file" ] && file="/run/assets/$DETECTED.xml" [ ! -f "$file" ] || [ ! -s "$file" ] && file="/run/assets/$DETECTED.xml"
[ ! -f "$file" ] || [ ! -s "$file" ] && return 1 [ ! -f "$file" ] || [ ! -s "$file" ] && return 1
case "$file" in
"/custom.xml" | "$STORAGE/custom.xml" ) CUSTOM_XML="Y" ;;
esac
XML="$file" XML="$file"
return 0 return 0
} }
@@ -924,18 +930,19 @@ updateDomain() {
local asset="$1" local asset="$1"
local domain account auth pass local domain account auth pass
local pw cred_domain tmp result local pw cred_domain ou tmp result
domain=$(escapeXML "$2") || return 1 domain=$(escapeXML "$2") || return 1
account=$(escapeXML "$3") || return 1 account=$(escapeXML "$3") || return 1
auth=$(escapeXML "$4") || return 1 auth=$(escapeXML "$4") || return 1
pass=$(escapeXML "$5") || return 1 pass=$(escapeXML "$5") || return 1
pw="$6" pw="$6"
ou=$(escapeXML "$7") || return 1
cred_domain="$domain" cred_domain="$domain"
case "$4" in case "$4" in
*\\* | *@* ) cred_domain="" ;; *@* ) cred_domain="" ;;
esac esac
grep -Eq 'Microsoft-Windows-UnattendedJoin|<DomainAccounts([[:space:]/>])' "$asset" && return 1 grep -Eq 'Microsoft-Windows-UnattendedJoin|<DomainAccounts([[:space:]/>])' "$asset" && return 1
@@ -943,8 +950,9 @@ updateDomain() {
tmp=$(mktemp -d) || return 1 tmp=$(mktemp -d) || return 1
result="$tmp/answer.xml" result="$tmp/answer.xml"
if ! DOMAIN_XML="$domain" ACCOUNT_XML="$account" AUTH_XML="$auth" \ if ! DOMAIN_XML="$domain" ACCOUNT_XML="$account" \
PASS_XML="$pass" CRED_DOMAIN="$cred_domain" PW="$pw" \ AUTH_XML="$auth" PASS_XML="$pass" \
CRED_DOMAIN="$cred_domain" PW="$pw" OU_XML="$ou" \
awk ' awk '
/<settings[^>]*pass="specialize"[^>]*>/ { section = "specialize" } /<settings[^>]*pass="specialize"[^>]*>/ { section = "specialize" }
/<settings[^>]*pass="oobeSystem"[^>]*>/ { section = "oobeSystem" } /<settings[^>]*pass="oobeSystem"[^>]*>/ { section = "oobeSystem" }
@@ -996,8 +1004,13 @@ updateDomain() {
print " <Username>" ENVIRON["AUTH_XML"] "</Username>\n" \ print " <Username>" ENVIRON["AUTH_XML"] "</Username>\n" \
" <Password>" ENVIRON["PASS_XML"] "</Password>\n" \ " <Password>" ENVIRON["PASS_XML"] "</Password>\n" \
" </Credentials>\n" \ " </Credentials>\n" \
" <JoinDomain>" ENVIRON["DOMAIN_XML"] "</JoinDomain>\n" \ " <JoinDomain>" ENVIRON["DOMAIN_XML"] "</JoinDomain>"
" </Identification>\n" \
if (ENVIRON["OU_XML"] != "") {
print " <MachineObjectOU>" ENVIRON["OU_XML"] "</MachineObjectOU>"
}
print " </Identification>\n" \
" </component>" " </component>"
join_added = 1 join_added = 1
@@ -1057,7 +1070,7 @@ validateLocalUsername() {
"NONE" ) "NONE" )
error "The USERNAME value \"NONE\" is reserved by Windows!" error "The USERNAME value \"NONE\" is reserved by Windows!"
return 1 ;; return 1 ;;
"ADMINISTRATOR" | "GUEST" ) "ADMINISTRATOR" | "GUEST" | "DEFAULTACCOUNT" | "WDAGUTILITYACCOUNT" | "WSIACCOUNT" )
error "The USERNAME value \"$value\" is reserved for a built-in Windows account!" error "The USERNAME value \"$value\" is reserved for a built-in Windows account!"
return 1 ;; return 1 ;;
esac esac
@@ -1075,27 +1088,20 @@ validateDomainName() {
return 1 return 1
fi fi
if [ "${#value}" -gt 255 ]; then
error "The $name variable cannot contain more than 255 characters!"
return 1
fi
if [[ "$value" == *"://"* ]]; then if [[ "$value" == *"://"* ]]; then
error "The $name variable must contain a domain name, not a URL!" error "The $name variable must contain a domain name, not a URL!"
return 1 return 1
fi fi
if [[ "$value" =~ [[:cntrl:]] ]] || [[ "$value" =~ [[:space:]] ]]; then if [ "${#value}" -gt 255 ] ||
error "The $name variable cannot contain whitespace or control characters!" [[ "$value" =~ [[:cntrl:]] ]] ||
[[ "$value" =~ [[:space:]] ]] ||
[[ ! "$value" =~ ^[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$ ]]; then
error "The $name variable does not contain a valid domain name!"
return 1 return 1
fi fi
case "$value" in
*'/'* | *\\* | *'@'* | *':'* )
error "The $name variable does not contain a valid domain name!"
return 1 ;;
esac
return 0 return 0
} }
@@ -1142,19 +1148,62 @@ validateDomainUsername() {
return 0 return 0
} }
updateWorkgroup() {
local asset="$1"
local workgroup arch tmp result
workgroup=$(escapeXML "$2") || return 1
arch=$(sed -n -E '0,/processorArchitecture="/s/.*processorArchitecture="([^"]+)".*/\1/p' "$asset") || return 1
[ -z "$arch" ] && return 1
grep -q 'Microsoft-Windows-UnattendedJoin' "$asset" && return 1
tmp=$(mktemp -d) || return 1
result="$tmp/answer.xml"
if ! WORKGROUP_XML="$workgroup" ARCH_XML="$arch" awk '
/<settings[^>]*pass="specialize"[^>]*>/ { section = "specialize" }
section == "specialize" && !workgroup_added &&
/^[[:space:]]*<\/settings>[[:space:]]*$/ {
print " <component name=\"Microsoft-Windows-UnattendedJoin\" processorArchitecture=\"" ENVIRON["ARCH_XML"] "\" publicKeyToken=\"31bf3856ad364e35\" language=\"neutral\" versionScope=\"nonSxS\">\n" \
" <Identification>\n" \
" <JoinWorkgroup>" ENVIRON["WORKGROUP_XML"] "</JoinWorkgroup>\n" \
" </Identification>\n" \
" </component>"
workgroup_added = 1
}
{ print }
/^[[:space:]]*<\/settings>[[:space:]]*$/ { section = "" }
END { exit !workgroup_added }
' "$asset" > "$result" ||
! mv -f "$result" "$asset"; then
rm -rf "$tmp" || true
return 1
fi
rm -rf "$tmp" || return 1
return 0
}
updateXML() { updateXML() {
local asset="$1" local asset="$1"
local language="$2" local language="$2"
local app value culture region keyboard edition key local app value culture region keyboard edition key
local user user_xml auth_user local user user_xml auth_user admin pass pw
local admin pass pw domain qualifier host local domain qualifier host workgroup
[ -z "$WIDTH" ] && WIDTH="1280" [ -z "$WIDTH" ] && WIDTH="1280"
[ -z "$HEIGHT" ] && HEIGHT="720" [ -z "$HEIGHT" ] && HEIGHT="720"
validateResolution "WIDTH" "$WIDTH" 320 || return 1 validateResolution "WIDTH" "$WIDTH" 320 || return 1
validateResolution "HEIGHT" "$HEIGHT" 200 || return 1 validateResolution "HEIGHT" "$HEIGHT" 200 || return 1
validateMembership || return 1
validateComputerName "$HOST" || return 1 validateComputerName "$HOST" || return 1
validateProductKey "$KEY" || return 1 validateProductKey "$KEY" || return 1
validatePassword "$PASSWORD" || return 1 validatePassword "$PASSWORD" || return 1
@@ -1164,8 +1213,8 @@ updateXML() {
sed -i "s|>Windows for Docker<|>$app<|g" "$asset" || return 1 sed -i "s|>Windows for Docker<|>$app<|g" "$asset" || return 1
sed -i -E "s|<ComputerName>[^<]*</ComputerName>|<ComputerName>$host</ComputerName>|g" "$asset" || return 1 sed -i -E "s|<ComputerName>[^<]*</ComputerName>|<ComputerName>$host</ComputerName>|g" "$asset" || return 1
sed -i "s|<VerticalResolution>1080</VerticalResolution>|<VerticalResolution>$HEIGHT</VerticalResolution>|g" "$asset" || return 1 sed -i -E "s|<VerticalResolution>[^<]*</VerticalResolution>|<VerticalResolution>$HEIGHT</VerticalResolution>|g" "$asset" || return 1
sed -i "s|<HorizontalResolution>1920</HorizontalResolution>|<HorizontalResolution>$WIDTH</HorizontalResolution>|g" "$asset" || return 1 sed -i -E "s|<HorizontalResolution>[^<]*</HorizontalResolution>|<HorizontalResolution>$WIDTH</HorizontalResolution>|g" "$asset" || return 1
culture=$(getLanguage "$language" "culture") || return 1 culture=$(getLanguage "$language" "culture") || return 1
@@ -1193,6 +1242,7 @@ updateXML() {
fi fi
domain="$DOMAIN" domain="$DOMAIN"
workgroup="$WORKGROUP"
case "${DETECTED,,}" in case "${DETECTED,,}" in
"win10x64"* | "win11x64"* ) ;; "win10x64"* | "win11x64"* ) ;;
* ) domain="" ;; * ) domain="" ;;
@@ -1215,21 +1265,12 @@ updateXML() {
auth_user="$USERNAME" auth_user="$USERNAME"
qualifier="" qualifier=""
if [[ "$auth_user" == *\\* && "$auth_user" == *@* ]]; then if [[ "$auth_user" == *\\* ]]; then
error "The USERNAME variable must use only one domain account format!" error "The USERNAME variable must use either \"user\" or \"user@domain\" format!"
return 1 return 1
fi fi
case "$auth_user" in case "$auth_user" in
*\\* )
qualifier="${auth_user%%\\*}"
user="${auth_user#*\\}"
if [ -z "$qualifier" ] || [ -z "$user" ] || [[ "$user" == *\\* ]]; then
error "The USERNAME variable does not contain a valid domain account name!"
return 1
fi
;;
*@* ) *@* )
user="${auth_user%%@*}" user="${auth_user%%@*}"
qualifier="${auth_user#*@}" qualifier="${auth_user#*@}"
@@ -1238,6 +1279,13 @@ updateXML() {
error "The USERNAME variable does not contain a valid domain account name!" error "The USERNAME variable does not contain a valid domain account name!"
return 1 return 1
fi fi
validateDomainName "$qualifier" "USERNAME" || return 1
if [[ "${qualifier,,}" != "${domain,,}" ]]; then
error "The domain in the USERNAME variable must match the DOMAIN variable!"
return 1
fi
;; ;;
* ) * )
user="$auth_user" user="$auth_user"
@@ -1246,10 +1294,6 @@ updateXML() {
validateDomainUsername "$user" || return 1 validateDomainUsername "$user" || return 1
if [ -n "$qualifier" ]; then
validateDomainName "$qualifier" "USERNAME" || return 1
fi
if [[ "${user,,}" == "docker" ]]; then if [[ "${user,,}" == "docker" ]]; then
error "The USERNAME variable must be changed from its default value when joining a domain!" error "The USERNAME variable must be changed from its default value when joining a domain!"
return 1 return 1
@@ -1286,20 +1330,31 @@ updateXML() {
pw=$(printf '%s' "${pass}Password" | iconv -f utf-8 -t utf-16le | base64 -w 0) || return 1 pw=$(printf '%s' "${pass}Password" | iconv -f utf-8 -t utf-16le | base64 -w 0) || return 1
admin=$(printf '%s' "${pass}AdministratorPassword" | iconv -f utf-8 -t utf-16le | base64 -w 0) || return 1 admin=$(printf '%s' "${pass}AdministratorPassword" | iconv -f utf-8 -t utf-16le | base64 -w 0) || return 1
sed -i "s|<Value>password</Value>|<Value>$admin</Value>|g" "$asset" || return 1 sed -i -z -E "s#(<Password>[[:space:]]*<Value)([[:space:]]*/>|>[^<]*</Value>)#\1>$pw</Value>#g" "$asset" || return 1
sed -i "s|<PlainText>true</PlainText>|<PlainText>false</PlainText>|g" "$asset" || return 1 sed -i -z -E "s#(<AdministratorPassword>[[:space:]]*<Value)([[:space:]]*/>|>[^<]*</Value>)#\1>$admin</Value>#g" "$asset" || return 1
sed -i -z -E "s|<Password>([[:space:]]*)<Value[[:space:]]*/>|<Password>\1<Value>$pw</Value>|g" "$asset" || return 1 sed -i -E "s|<PlainText>[^<]*</PlainText>|<PlainText>false</PlainText>|g" "$asset" || return 1
sed -i -z -E "s|<AdministratorPassword>([[:space:]]*)<Value[[:space:]]*/>|<AdministratorPassword>\1<Value>$admin</Value>|g" "$asset" || return 1
if [ -n "$domain" ]; then if [ -n "$domain" ]; then
pw=$(printf '%s' "${PASSWORD}Password" | iconv -f utf-8 -t utf-16le | base64 -w 0) || return 1 pw=$(printf '%s' "${PASSWORD}Password" | iconv -f utf-8 -t utf-16le | base64 -w 0) || return 1
if ! updateDomain "$asset" "$domain" "$user" "$auth_user" "$PASSWORD" "$pw"; then if ! updateDomain "$asset" "$domain" "$user" \
"$auth_user" "$PASSWORD" "$pw" "$DOMAIN_OU"; then
error "Failed to add domain configuration to answer file!" error "Failed to add domain configuration to answer file!"
return 1 return 1
fi fi
elif [ -n "$workgroup" ]; then
if ! updateWorkgroup "$asset" "$workgroup"; then
error "Failed to add workgroup configuration to answer file!"
return 1
fi
fi
if disabled "$AUTOLOGIN"; then
sed -i -E '/^[[:space:]]*<AutoLogon([[:space:]>])/,/^[[:space:]]*<\/AutoLogon>[[:space:]]*$/d' "$asset" || return 1
fi fi
if [ -n "$EDITION" ]; then if [ -n "$EDITION" ]; then
@@ -1536,9 +1591,20 @@ updateImage() {
fi fi
if ! updateXML "$answer" "$language"; then if [ -n "${CUSTOM_XML:-}" ]; then
error "Failed to update answer file: $answer"
return 1 if ! xmllint --nonet --noout "$answer"; then
error "The custom answer file is not valid XML!"
return 1
fi
else
if ! updateXML "$answer" "$language"; then
error "Failed to update answer file: $answer"
return 1
fi
fi fi
if ! wimlib-imagex update "$wim" "$idx" --command "add $answer /$xml" > /dev/null; then if ! wimlib-imagex update "$wim" "$idx" --command "add $answer /$xml" > /dev/null; then