Compare commits

..

7 Commits
v2.08 ... v2.11

Author SHA1 Message Date
Kroese
8a5f233e34 fix: Verify files are not empty (#383) 2024-04-16 16:22:28 +02:00
Kroese
2a98081549 feat: Allow filenames in VERSION (#381) 2024-04-16 14:15:38 +02:00
Kroese
56cb787c55 fix: Delete ISO when extraction fails (#372) 2024-04-13 16:58:04 +02:00
Kroese
da9ef0e061 docs: Readme (#356) 2024-04-07 01:59:20 +02:00
Kroese
b02f65a41e feat: Improve Windows XP configuration (#350) 2024-04-05 16:34:35 +02:00
Kroese
7921b1eb54 build: Update wsdd to v0.8 (#328) 2024-03-31 04:45:27 +02:00
Kroese
463ec9fb49 docs: Add video (#323) 2024-03-28 16:11:43 +01:00
6 changed files with 102 additions and 34 deletions

View File

@@ -6,6 +6,8 @@
.gitmodules
Dockerfile
Dockerfile.archive
compose.yml
compose.yaml
docker-compose.yml
docker-compose.yaml
*.md

View File

@@ -1,5 +1,5 @@
FROM scratch
COPY --from=qemux/qemu-docker:4.19 / /
COPY --from=qemux/qemu-docker:4.22 / /
ARG DEBCONF_NOWARNINGS "yes"
ARG DEBIAN_FRONTEND "noninteractive"
@@ -25,7 +25,7 @@ RUN apt-get update && \
COPY ./src /run/
COPY ./assets /run/assets
ADD https://raw.githubusercontent.com/christgau/wsdd/master/src/wsdd.py /usr/sbin/wsdd
ADD https://raw.githubusercontent.com/christgau/wsdd/v0.8/src/wsdd.py /usr/sbin/wsdd
ADD https://github.com/qemus/virtiso/releases/download/v0.1.248/virtio-win-0.1.248.iso /run/drivers.iso
RUN chmod +x /run/*.sh && chmod +x /usr/sbin/wsdd

View File

@@ -19,9 +19,13 @@ Windows in a Docker container.
- KVM acceleration
- Web-based viewer
## Video
[![Youtube](https://img.youtube.com/vi/xhGYobuG508/0.jpg)](https://www.youtube.com/watch?v=xhGYobuG508)
## Usage
Via `docker-compose.yml`
Via Docker Compose:
```yaml
version: "3"
@@ -43,7 +47,7 @@ services:
restart: on-failure
```
Via `docker run`
Via Docker CLI:
```bash
docker run -it --rm --name windows -p 8006:8006 --device=/dev/kvm --cap-add NET_ADMIN --stop-timeout 120 dockurr/windows

View File

@@ -93,6 +93,7 @@ fi
CUSTOM=$(find "$STORAGE" -maxdepth 1 -type f -iname custom.iso -printf "%f\n" | head -n 1)
[ -z "$CUSTOM" ] && CUSTOM=$(find "$STORAGE" -maxdepth 1 -type f -iname boot.iso -printf "%f\n" | head -n 1)
[ -z "$CUSTOM" ] && CUSTOM=$(find "$STORAGE" -maxdepth 1 -type f -iname custom.img -printf "%f\n" | head -n 1)
[ -z "$CUSTOM" ] && CUSTOM=$(find "$STORAGE" -maxdepth 1 -type f -iname "${VERSION/\/storage\//}" -printf "%f\n" | head -n 1)
ESD_URL=""
MACHINE="q35"
@@ -203,7 +204,7 @@ hasDisk() {
[ -b "${DEVICE:-}" ] && return 0
if [ -f "$STORAGE/data.img" ] || [ -f "$STORAGE/data.qcow2" ]; then
if [ -s "$STORAGE/data.img" ] || [ -s "$STORAGE/data.qcow2" ]; then
return 0
fi
@@ -309,6 +310,8 @@ startInstall() {
else
rm -f "$STORAGE/$BASE"
if skipInstall; then
BASE=""
return 1
@@ -316,6 +319,7 @@ startInstall() {
fi
rm -rf "$TMP"
mkdir -p "$TMP"
if [ ! -f "$STORAGE/$CUSTOM" ]; then
@@ -325,7 +329,6 @@ startInstall() {
ISO="$STORAGE/$CUSTOM"
fi
rm -f "$TMP/$BASE"
return 0
}
@@ -369,7 +372,7 @@ getESD() {
cd /run
if [ ! -f "$dir/products.xml" ]; then
if [ ! -s "$dir/products.xml" ]; then
error "Failed to find products.xml!" && return 1
fi
@@ -433,7 +436,7 @@ downloadImage() {
if (( rc == 0 )); then
[ ! -f "$iso" ] && return 1
[ ! -s "$iso" ] && return 1
html "Download finished successfully..."
return 0
@@ -445,6 +448,9 @@ downloadImage() {
info "Failed to download $desc using Mido, will try a different method now..."
rm -rf "$TMP"
mkdir -p "$TMP"
ISO="$TMP/$VERSION.esd"
iso="$ISO"
file="$ISO"
@@ -473,7 +479,7 @@ downloadImage() {
fKill "progress.sh"
(( rc != 0 )) && error "Failed to download $url , reason: $rc" && exit 60
[ ! -f "$iso" ] && return 1
[ ! -s "$iso" ] && return 1
html "Download finished successfully..."
return 0
@@ -573,6 +579,7 @@ extractImage() {
if [[ "${iso,,}" == *".esd" ]]; then
if ! extractESD "$iso" "$dir"; then
rm -f "$iso"
error "Failed to extract ESD file!"
exit 67
fi
@@ -604,6 +611,7 @@ extractImage() {
rm -rf "$dir"
if ! 7z x "$iso" -o"$dir" > /dev/null; then
rm -f "$iso"
error "Failed to extract ISO file!"
exit 66
fi
@@ -626,7 +634,7 @@ detectImage() {
if [ -n "$DETECTED" ]; then
if [ -f "/run/assets/$DETECTED.xml" ]; then
if [ -s "/run/assets/$DETECTED.xml" ]; then
[[ "$MANUAL" != [Yy1]* ]] && XML="$DETECTED.xml"
return 0
fi
@@ -645,7 +653,7 @@ detectImage() {
info "Detecting Windows version from ISO image..."
if [ -f "$dir/WIN51" ] || [ -f "$dir/SETUPXP.HTM" ]; then
if [ -s "$dir/WIN51" ] || [ -s "$dir/SETUPXP.HTM" ]; then
DETECTED="winxpx86"
info "Detected: Windows XP"
return 0
@@ -661,9 +669,9 @@ detectImage() {
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)
[ ! -s "$loc" ] && loc=$(find "$src" -maxdepth 1 -type f -iname install.esd | head -n 1)
if [ ! -f "$loc" ]; then
if [ ! -s "$loc" ]; then
warn "failed to locate 'install.wim' or 'install.esd' in ISO image, $FB"
BOOT_MODE="windows_legacy"
return 1
@@ -691,7 +699,7 @@ detectImage() {
desc=$(printVersion "$DETECTED")
[ -z "$desc" ] && desc="$DETECTED"
if [ -f "/run/assets/$DETECTED.xml" ]; then
if [ -s "/run/assets/$DETECTED.xml" ]; then
[[ "$MANUAL" != [Yy1]* ]] && XML="$DETECTED.xml"
info "Detected: $desc"
else
@@ -768,7 +776,7 @@ prepareXP() {
find "$target" -maxdepth 1 -type f -iname winnt.sif -exec rm {} \;
{ echo "[Data]"
{ echo "[Data]"
echo "AutoPartition=1"
echo "MsDosInitiated=\"0\""
echo "UnattendedInstall=\"Yes\""
@@ -811,10 +819,12 @@ prepareXP() {
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/ie_rsearch.html"
echo "AutoConfig = 0"
echo "Search_Page = http://www.google.com"
echo ""
echo "[RegionalSettings]"
echo "Language=00000409"
@@ -823,6 +833,57 @@ prepareXP() {
echo "AllowConnections=1"
} | unix2dos > "$target/WINNT.SIF"
{ echo "Windows Registry Editor Version 5.00"
echo ""
echo "[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Security]"
echo "\"FirstRunDisabled\"=dword:00000001"
echo "\"AntiVirusOverride\"=dword:00000001"
echo "\"FirewallOverride\"=dword:00000001"
echo "\"FirewallDisableNotify\"=dword:00000001"
echo "\"UpdatesDisableNotify\"=dword:00000001"
echo "\"AntiVirusDisableNotify\"=dword:00000001"
echo ""
echo "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wscsvc]"
echo "\"Start\"=dword:00000004"
echo ""
echo "[HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\WindowsFirewall\StandardProfile]"
echo "\"EnableFirewall\"=dword:00000000"
echo ""
echo "[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess]"
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_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]"
echo "\"LimitBlankPasswordUse\"=dword:00000000"
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 NT\CurrentVersion\Winlogon]"
echo "\"DefaultUserName\"=\"Docker\""
echo "\"DefaultDomainName\"=\"Dockur\""
echo "\"AltDefaultUserName\"=\"Docker\""
echo "\"AltDefaultDomainName\"=\"Dockur\""
echo "\"AutoAdminLogon\"=\"1\""
} | unix2dos > "$dir/\$OEM\$/install.reg"
{ echo "Set WshShell = WScript.CreateObject(\"WScript.Shell\")"
echo "Set WshNetwork = WScript.CreateObject(\"WScript.Network\")"
echo "Set oMachine = GetObject(\"WinNT://\" & WshNetwork.ComputerName)"
echo "Set oInfoUser = GetObject(\"WinNT://\" & WshNetwork.ComputerName & \"/Administrator,user\")"
echo "Set oUser = oMachine.MoveHere(oInfoUser.ADsPath,\"Docker\")"
} | unix2dos > "$dir/\$OEM\$/admin.vbs"
{ echo "[COMMANDS]"
echo "\"REGEDIT /s install.reg\""
echo "\"Wscript admin.vbs\""
} | unix2dos > "$dir/\$OEM\$/cmdlines.txt"
rm -rf "$drivers"
return 0
}
@@ -858,7 +919,7 @@ prepareImage() {
if [[ "${DETECTED,,}" != "winxp"* ]] && [[ "${DETECTED,,}" != "win2008"* ]]; then
if [[ "${DETECTED,,}" != "winvista"* ]] && [[ "${DETECTED,,}" != "win7"* ]]; then
if [ -f "$dir/$ETFS" ] && [ -f "$dir/$EFISYS" ]; then
if [ -s "$dir/$ETFS" ] && [ -s "$dir/$EFISYS" ]; then
return 0
fi
@@ -894,7 +955,7 @@ updateImage() {
local asset="/run/assets/$3"
local path src loc index result
[ ! -f "$asset" ] && return 0
[ ! -s "$asset" ] && return 0
path=$(find "$dir" -maxdepth 1 -type f -iname autounattend.xml | head -n 1)
[ -n "$path" ] && cp "$asset" "$path"
@@ -908,9 +969,9 @@ updateImage() {
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)
[ ! -s "$loc" ] && loc=$(find "$src" -maxdepth 1 -type f -iname boot.esd | head -n 1)
if [ ! -f "$loc" ]; then
if [ ! -s "$loc" ]; then
warn "failed to locate 'boot.wim' or 'boot.esd' in ISO image, $FB"
BOOT_MODE="windows_legacy"
return 1
@@ -965,7 +1026,7 @@ buildImage() {
if ! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 4 -J -l -D -N -joliet-long -relaxed-filenames -V "$label" \
-udf -boot-info-table -eltorito-alt-boot -eltorito-boot "$EFISYS" -no-emul-boot -allow-limited-size -quiet "$dir" 2> "$log"; then
[ -f "$log" ] && echo "$(<"$log")"
[ -s "$log" ] && echo "$(<"$log")"
return 1
fi
@@ -975,7 +1036,7 @@ buildImage() {
if ! genisoimage -o "$out" -b "$ETFS" -no-emul-boot -c "$cat" -iso-level 2 -J -l -D -N -joliet-long -relaxed-filenames -V "$label" \
-udf -allow-limited-size -quiet "$dir" 2> "$log"; then
[ -f "$log" ] && echo "$(<"$log")"
[ -s "$log" ] && echo "$(<"$log")"
return 1
fi
@@ -983,7 +1044,7 @@ buildImage() {
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" -quiet "$dir" 2> "$log"; then
[ -f "$log" ] && echo "$(<"$log")"
[ -s "$log" ] && echo "$(<"$log")"
return 1
fi
@@ -993,7 +1054,7 @@ buildImage() {
local error=""
local hide="Warning: creating filesystem that does not conform to ISO-9660."
[ -f "$log" ] && error="$(<"$log")"
[ -s "$log" ] && error="$(<"$log")"
[[ "$error" != "$hide" ]] && echo "$error"
if [ -f "$STORAGE/$BASE" ]; then
@@ -1019,7 +1080,8 @@ if ! startInstall; then
return 0
fi
if [ ! -f "$ISO" ]; then
if [ ! -s "$ISO" ]; then
rm -f "$ISO"
if ! downloadImage "$ISO" "$VERSION"; then
error "Failed to download $VERSION"
exit 61

View File

@@ -25,7 +25,7 @@ _trap() {
ready() {
[ -f "$STORAGE/windows.boot" ] && return 0
[ ! -f "$QEMU_PTY" ] && return 1
[ ! -s "$QEMU_PTY" ] && return 1
if [ -f "$STORAGE/windows.old" ]; then
local last
@@ -52,7 +52,7 @@ finish() {
touch "$QEMU_END"
if [ -f "$QEMU_PID" ]; then
if [ -s "$QEMU_PID" ]; then
pid=$(<"$QEMU_PID")
error "Forcefully terminating Windows, reason: $reason..."
@@ -61,7 +61,7 @@ finish() {
while isAlive "$pid"; do
sleep 1
# Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break
[ ! -s "$QEMU_PID" ] && break
done
fi
@@ -74,7 +74,7 @@ finish() {
fi
pid="/var/run/tpm.pid"
[ -f "$pid" ] && pKill "$(<"$pid")"
[ -s "$pid" ] && pKill "$(<"$pid")"
fKill "wsdd"
fKill "smbd"
@@ -91,7 +91,7 @@ terminal() {
local dev=""
if [ -f "$QEMU_OUT" ]; then
if [ -s "$QEMU_OUT" ]; then
local msg
msg=$(<"$QEMU_OUT")
@@ -139,7 +139,7 @@ _graceful_shutdown() {
touch "$QEMU_END"
info "Received $1, sending ACPI shutdown signal..."
if [ ! -f "$QEMU_PID" ]; then
if [ ! -s "$QEMU_PID" ]; then
error "QEMU PID file does not exist?"
finish "$code" && return "$code"
fi
@@ -168,7 +168,7 @@ _graceful_shutdown() {
! isAlive "$pid" && break
# Workaround for zombie pid
[ ! -f "$QEMU_PID" ] && break
[ ! -s "$QEMU_PID" ] && break
info "Waiting for Windows to shutdown... ($cnt/$QEMU_TIMEOUT)"