From a1627ac743289e768b138f1a60753a62e0869cc4 Mon Sep 17 00:00:00 2001 From: srdusr Date: Wed, 24 Sep 2025 05:25:39 +0200 Subject: Update/Overhaul --- virt/windows.sh | 1156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1156 insertions(+) create mode 100755 virt/windows.sh (limited to 'virt/windows.sh') diff --git a/virt/windows.sh b/virt/windows.sh new file mode 100755 index 0000000..1863f8a --- /dev/null +++ b/virt/windows.sh @@ -0,0 +1,1156 @@ +#!/usr/bin/env bash + +# Windows VM Creation Script +# Description: Creates and manages Windows virtual machines using QEMU/KVM +# Features: +# - Supports Windows 10, 11, and Server +# - Automatic dependency checking +# - Multiple VM instance support +# - Cache management +# - Unattended installation +# - SMB sharing support +# - Network control + +# Usage: ./windows.sh [VERSION] [OPTIONS] +# Versions: +# 10 Windows 10 +# 11 Windows 11 (default) +# server Windows Server 2022 +# server2019 Windows Server 2019 +# server2016 Windows Server 2016 + +# Options: +# --help Show this help message +# --clean Clean dependency cache +# --check-deps Only check dependencies and exit +# --download-iso Download Windows ISO and exit +# --name NAME Set custom VM name +# --ram SIZE Set RAM size (default: 8G) +# --cpu NUM Set number of CPUs (default: 6) +# --disk SIZE Set disk size (default: 80G) +# --enable-smb Enable SMB sharing (default: disabled) +# --disable-net Disable network connectivity (default: enabled) + +# Parse command line arguments +WINDOWS_VERSION="11" +CLEAN_CACHE=false +CHECK_DEPS_ONLY=false +DOWNLOAD_ISO_ONLY=false +VM_NAME="windows-11" +VM_RAM="8G" +VM_CPU="6" +VM_SIZE="80G" +ENABLE_SMB=false +DISABLE_NET=false + +# Handle version argument if it's the first argument +if [[ $# -gt 0 && ! $1 =~ ^-- ]]; then + case "$1" in + "10") + WINDOWS_VERSION="10" + VM_NAME="windows-10" + ;; + "server" | "server2022") + WINDOWS_VERSION="server2022" + VM_NAME="windows-server-2022" + ;; + "server2019") + WINDOWS_VERSION="server2019" + VM_NAME="windows-server-2019" + ;; + "server2016") + WINDOWS_VERSION="server2016" + VM_NAME="windows-server-2016" + ;; + *) + echo "Unknown Windows version: $1" + echo "Use --help for usage information" + exit 1 + ;; + esac + shift +fi + +while [[ $# -gt 0 ]]; do + case $1 in + --help) + echo "Windows VM Creation Script" + echo "Usage: $0 [VERSION] [OPTIONS]" + echo + echo "Versions:" + echo " 10 Windows 10" + echo " 11 Windows 11 (default)" + echo " server Windows Server 2022" + echo " server2019 Windows Server 2019" + echo " server2016 Windows Server 2016" + echo + echo "Options:" + echo " --help Show this help message" + echo " --clean Clean dependency cache" + echo " --check-deps Only check dependencies and exit" + echo " --download-iso Download Windows ISO and exit" + echo " --name NAME Set custom VM name" + echo " --ram SIZE Set RAM size (default: 8G)" + echo " --cpu NUM Set number of CPUs (default: 6)" + echo " --disk SIZE Set disk size (default: 80G)" + echo " --enable-smb Enable SMB sharing (default: disabled)" + echo " --disable-net Disable network connectivity (default: enabled)" + exit 0 + ;; + --clean) + CLEAN_CACHE=true + shift + ;; + --check-deps) + CHECK_DEPS_ONLY=true + shift + ;; + --download-iso) + DOWNLOAD_ISO_ONLY=true + shift + ;; + --name) + VM_NAME="$2" + shift 2 + ;; + --ram) + VM_RAM="$2" + shift 2 + ;; + --cpu) + VM_CPU="$2" + shift 2 + ;; + --disk) + VM_SIZE="$2" + shift 2 + ;; + --enable-smb) + ENABLE_SMB=true + shift + ;; + --disable-net) + DISABLE_NET=true + shift + ;; + *) + echo "Unknown option: $1" + echo "Use --help for usage information" + exit 1 + ;; + esac +done + +# Set variables +HOST_DIR="$HOME/virt-new-new" +VM_DIR="$HOST_DIR/machines" +IMAGE_DIR="$HOST_DIR/images" +WIN_ISO_DIR="${IMAGE_DIR}/${VM_NAME}" # Directory for Windows ISO +SOCKET_DIR="$VM_DIR" +SHARED_DIR="${HOST_DIR}/shared" +FIRMWARE_DIR="${HOST_DIR}/firmware" +TPM_DIR="$WIN_ISO_DIR" +TPM_SOCKET="${WIN_ISO_DIR}/${VM_NAME}.swtpm-sock" +GUEST_PORT=22 +QCOW2_FILE="${VM_DIR}/${VM_NAME}.qcow2" + +# Try to find an available host port starting from 22220 +HOST_PORT_START=22220 +HOST_PORT_END=22300 + +for ((port = HOST_PORT_START; port <= HOST_PORT_END; port++)); do + if ! ss -tuln | grep -q ":$port\b"; then + HOST_PORT=$port + echo "Using available port: $HOST_PORT" + break + fi +done + +if [[ $port -gt $HOST_PORT_END ]]; then + echo "Error: No available ports found between $HOST_PORT_START and $HOST_PORT_END" >&2 + exit 1 +fi + +# Set SMP configuration +CORES=$((VM_CPU / 2)) +THREADS_PER_CORE=2 +SOCKETS=1 +SMP_CONFIG="cores=$CORES,threads=$THREADS_PER_CORE,sockets=$SOCKETS" + +# Create necessary directories +mkdir -p "${HOME}/${HOST_DIR}" +mkdir -p "$IMAGE_DIR" "$SHARED_DIR" "$FIRMWARE_DIR" +mkdir -p "$WIN_ISO_DIR" "$VM_DIR" +mkdir -p "${WIN_ISO_DIR}/unattended" + +# Define ISO paths and URLs +ISO_VIRTIO="${WIN_ISO_DIR}/virtio-win.iso" +ISO_UNATTENDED="${WIN_ISO_DIR}/unattended.iso" + +# Find Windows ISO with flexible pattern matching +find_windows_iso() { + # Check if directory exists + if [[ ! -d "$WIN_ISO_DIR" ]]; then + mkdir -p "$WIN_ISO_DIR" + fi + + # Try to find any Windows ISO using case-insensitive patterns + local found_iso + found_iso=$(find "$WIN_ISO_DIR" -maxdepth 1 -type f \( \ + -iname "*win11*.iso" -o \ + -iname "*win*11*.iso" -o \ + -iname "Win*.iso" -o \ + -iname "Win11*.iso" -o \ + -iname "Win*11*.iso" -o \ + -iname "*windows*11*.iso" -o \ + -iname "*windows11*.iso" \ + \) -exec stat --format="%Y %n" {} \; | sort -n | tail -n 1 | cut -d' ' -f2-) + + if [[ -n "$found_iso" && -f "$found_iso" ]]; then + echo "$found_iso" + return 0 + fi + + return 1 +} + +# Define download URLs +VIRTIO_ISO_URL="https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" +SPICE_WEBDAVD_URL="https://www.spice-space.org/download/windows/spice-webdavd/spice-webdavd-x64-latest.msi" +SPICE_VDAGENT_URL="https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-latest.msi" +SPICE_VDAGENT_FALLBACK_URL="https://www.spice-space.org/download/windows/spice-vdagent/spice-vdagent-x64-0.10.0.msi" +USBDK_URL="https://www.spice-space.org/download/windows/usbdk/UsbDk_1.0.22_x64.msi" + +# Fido download URL (Windows ISO downloader) +#FIDO_URL="https://github.com/pbatard/Fido/raw/master/Fido.ps1" +#FIDO_PATH="$WIN_DIR/Fido.ps1" + +# Print colored messages +print_info() { echo -e "\033[1;34m[INFO]\033[0m $1" >&2; } +print_success() { echo -e "\033[1;32m[SUCCESS]\033[0m $1" >&2; } +print_warning() { echo -e "\033[1;33m[WARNING]\033[0m $1" >&2; } +print_error() { echo -e "\033[1;31m[ERROR]\033[0m $1" >&2; } + +# Helper: verify file integrity +verify_file() { + local file="$1" + local expected_sha256="$2" + + if [[ ! -f "$file" ]]; then + return 1 + fi + + if [[ -n "$expected_sha256" ]]; then + local actual_sha256 + actual_sha256=$(sha256sum "$file" | cut -d' ' -f1) + if [[ "$actual_sha256" != "$expected_sha256" ]]; then + print_error "File integrity check failed for $file" + return 1 + fi + fi + + return 0 +} + +# Helper: download file with verification +download_file() { + local url="$1" + local dest="$2" + local expected_sha256="$3" + local allow_failure="$4" + + # Check if file exists and is valid + if [[ -f "$dest" ]]; then + if verify_file "$dest" "$expected_sha256"; then + print_info "File $dest already exists and verified." + return 0 + else + print_warning "File $dest exists but failed verification. Redownloading..." + rm -f "$dest" + fi + fi + + print_info "Downloading $url..." + if ! curl -fL --progress-bar -o "$dest" "$url"; then + print_error "Failed to download $url." + if [[ "$allow_failure" != "true" ]]; then + return 1 + fi + else + # Verify downloaded file + if ! verify_file "$dest" "$expected_sha256"; then + print_error "Downloaded file failed verification" + rm -f "$dest" + return 1 + fi + print_success "Successfully downloaded and verified $dest" + fi + + return 0 +} + +# Download Windows 11 ISO using Microsoft's API +download_windows_iso() { + local windows_version="11" # Default to Windows 11 + local language="English (United States)" # Default language + + # Parse arguments if provided + if [[ -n "$1" ]]; then + windows_version="$1" + fi + + print_info "Attempting to download Windows $windows_version ISO from Microsoft..." + + # Set required variables + local user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:100.0) Gecko/20100101 Firefox/100.0" + local session_id="$(uuidgen)" + local profile="606624d44113" + local url="https://www.microsoft.com/en-us/software-download/windows$windows_version" + + # Add ISO to URL for Windows 10 + case "$windows_version" in + 10) url="${url}ISO" ;; + esac + + # Step 1: Get download page HTML + print_info "Fetching download page: $url" + local iso_download_page_html + iso_download_page_html="$(curl --disable --silent --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url")" || { + handle_curl_error $? + print_error "Failed to fetch the download page. Please download Windows $windows_version ISO manually from $url" + return 1 + } + + # Step 2: Extract Product Edition ID + print_info "Getting Product Edition ID..." + local product_edition_id + product_edition_id="$(echo "$iso_download_page_html" | grep -Eo '