diff --git a/Dockerfile b/Dockerfile index 83773ce..7d6cbd3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM scratch -COPY --from=qemux/qemu-docker:5.07 / / +COPY --from=qemux/qemu-docker:5.08 / / ARG VERSION_ARG="0.0" ARG DEBCONF_NOWARNINGS="yes" @@ -14,6 +14,7 @@ RUN set -eu && \ 7zip \ wsdd \ samba \ + xz-utils \ wimtools \ dos2unix \ cabextract \ @@ -27,7 +28,7 @@ COPY --chmod=755 ./src /run/ COPY --chmod=755 ./assets /run/assets ADD --chmod=755 https://raw.githubusercontent.com/christgau/wsdd/v0.8/src/wsdd.py /usr/sbin/wsdd -ADD --chmod=664 https://github.com/qemus/virtiso/releases/download/v0.1.248/virtio-win-0.1.248.iso /run/drivers.iso +ADD --chmod=664 https://github.com/qemus/virtiso/releases/download/v0.1.248/virtio-win-0.1.248.tar.xz /drivers.txz EXPOSE 8006 3389 VOLUME /storage diff --git a/assets/win11x64-iot.xml b/assets/win11x64-iot.xml new file mode 100644 index 0000000..cf49f4e --- /dev/null +++ b/assets/win11x64-iot.xml @@ -0,0 +1,453 @@ + + + + + + en-US + + 0409:00000409 + en-US + en-US + en-US + + + + + 0 + true + + + + 1 + EFI + 128 + + + + 2 + MSR + 128 + + + + 3 + Primary + true + + + + + + 1 + 1 + + FAT32 + + + + 2 + 2 + + + + 3 + 3 + + C + NTFS + + + + + + + + + /image/index + 2 + + + + 0 + 3 + + false + + + + true + Never + + + false + Never + + + true + Docker + Windows for Docker + + false + + false + + + + 1 + reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassTPMCheck /t REG_DWORD /d 1 /f + + + 2 + reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassSecureBootCheck /t REG_DWORD /d 1 /f + + + 3 + reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassRAMCheck /t REG_DWORD /d 1 /f + + + 4 + reg.exe add "HKLM\SYSTEM\Setup\MoSetup" /v AllowUpgradesWithUnsupportedTPMOrCPU /t REG_DWORD /d 1 /f + + + + + + + false + + + + + true + + + 1 + + + + + true + + + * + + Dockur + Windows for Docker + 24/7 + + Dockur + https://github.com/dockur/windows/issues + + Windows for Docker + + + 1 + + + true + true + https://google.com + about:blank + + + true + true + https://google.com + about:blank + + + 0 + + + 1 + + + 0409:00000409 + en-US + en-US + en-US + + + + + 1 + reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" /v BypassNRO /t REG_DWORD /d 1 /f + + + 2 + reg.exe load "HKU\mount" "C:\Users\Default\NTUSER.DAT" + + + 3 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "ContentDeliveryAllowed" /t REG_DWORD /d 0 /f + + + 4 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "FeatureManagementEnabled" /t REG_DWORD /d 0 /f + + + 5 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "OEMPreInstalledAppsEnabled" /t REG_DWORD /d 0 /f + + + 6 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEnabled" /t REG_DWORD /d 0 /f + + + 7 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEverEnabled" /t REG_DWORD /d 0 /f + + + 8 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SilentInstalledAppsEnabled" /t REG_DWORD /d 0 /f + + + 9 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SoftLandingEnabled" /t REG_DWORD /d 0 /f + + + 10 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContentEnabled" /t REG_DWORD /d 0 /f + + + 11 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-310093Enabled" /t REG_DWORD /d 0 /f + + + 12 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338387Enabled" /t REG_DWORD /d 0 /f + + + 13 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338388Enabled" /t REG_DWORD /d 0 /f + + + 14 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338389Enabled" /t REG_DWORD /d 0 /f + + + 15 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338393Enabled" /t REG_DWORD /d 0 /f + + + 16 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-353698Enabled" /t REG_DWORD /d 0 /f + + + 17 + reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SystemPaneSuggestionsEnabled" /t REG_DWORD /d 0 /f + + + 18 + reg.exe add "HKU\mount\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableCloudOptimizedContent" /t REG_DWORD /d 1 /f + + + 19 + reg.exe add "HKU\mount\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 1 /f + + + 20 + reg.exe add "HKU\mount\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableConsumerAccountStateContent" /t REG_DWORD /d 1 /f + + + 21 + reg.exe unload "HKU\mount" + + + 22 + reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableCloudOptimizedContent" /t REG_DWORD /d 1 /f + + + 23 + reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 1 /f + + + 24 + reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableConsumerAccountStateContent" /t REG_DWORD /d 1 /f + + + 25 + reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\FirstNetwork" /v Category /t REG_DWORD /d 1 /f + Set Network Location to Home + + + + + false + + + 0 + + + + + true + all + @FirewallAPI.dll,-28752 + + + + + + + + + true + + + 1 + + + + + + Docker + Administrators + + + true</PlainText> + </Password> + </LocalAccount> + </LocalAccounts> + <AdministratorPassword> + <Value>password</Value> + <PlainText>true</PlainText> + </AdministratorPassword> + </UserAccounts> + <AutoLogon> + <Username>Docker</Username> + <Enabled>true</Enabled> + <LogonCount>65432</LogonCount> + <Password> + <Value /> + <PlainText>true</PlainText> + </Password> + </AutoLogon> + <Display> + <ColorDepth>32</ColorDepth> + <HorizontalResolution>1920</HorizontalResolution> + <VerticalResolution>1080</VerticalResolution> + </Display> + <OOBE> + <HideEULAPage>true</HideEULAPage> + <HideLocalAccountScreen>true</HideLocalAccountScreen> + <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> + <HideOnlineAccountScreens>true</HideOnlineAccountScreens> + <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> + <NetworkLocation>Home</NetworkLocation> + <ProtectYourPC>3</ProtectYourPC> + <SkipUserOOBE>true</SkipUserOOBE> + <SkipMachineOOBE>true</SkipMachineOOBE> + </OOBE> + <RegisteredOrganization>Dockur</RegisteredOrganization> + <RegisteredOwner>Windows for Docker</RegisteredOwner> + <FirstLogonCommands> + <SynchronousCommand wcm:action="add"> + <Order>1</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Allow guest access to network shares</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>2</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v LimitBlankPasswordUse /t REG_DWORD /d 0 /f</CommandLine> + <Description>Allow RDP login with blank password</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>3</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PasswordLess\Device" /v "DevicePasswordLessBuildVersion" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Enable option for passwordless sign-in</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>4</Order> + <CommandLine>cmd /C wmic useraccount where name="Docker" set PasswordExpires=false</CommandLine> + <Description>Password Never Expires</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>5</Order> + <CommandLine>cmd /C POWERCFG -H OFF</CommandLine> + <Description>Disable Hibernation</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>6</Order> + <CommandLine>cmd /C POWERCFG -X -monitor-timeout-ac 0</CommandLine> + <Description>Disable monitor blanking</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>7</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Edge" /v "HideFirstRunExperience" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Disable first-run experience in Edge</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>8</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "HideFileExt" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Show file extensions in Explorer</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>9</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\Power" /v "HibernateFileSizePercent" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Zero Hibernation File</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>10</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\Power" /v "HibernateEnabled" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Disable Hibernation</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>11</Order> + <CommandLine>cmd /C POWERCFG -X -standby-timeout-ac 0</CommandLine> + <Description>Disable Sleep</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>12</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v "fAllowUnlistedRemotePrograms" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Enable RemoteAPP to launch unlisted programs</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>13</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "ShowTaskViewButton" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Remove Task View from the Taskbar</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>14</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "TaskbarDa" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Remove Widgets from the Taskbar</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>15</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "TaskbarMn" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Remove Chat from the Taskbar</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>16</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v "NoAutoUpdate" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Turn off Windows Update auto download</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>17</Order> + <CommandLine>netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Yes</CommandLine> + <Description>Enable Network Discovery</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>18</Order> + <CommandLine>netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes</CommandLine> + <Description>Enable File Sharing</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>19</Order> + <CommandLine>reg.exe add "HKCU\Control Panel\UnsupportedHardwareNotificationCache" /v SV1 /d 0 /t REG_DWORD /f</CommandLine> + <Description>Disable unsupported hardware notifications</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>20</Order> + <CommandLine>reg.exe add "HKCU\Control Panel\UnsupportedHardwareNotificationCache" /v SV2 /d 0 /t REG_DWORD /f</CommandLine> + <Description>Disable unsupported hardware notifications</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>21</Order> + <CommandLine>cmd /C if exist "C:\OEM\install.bat" start "Install" "cmd /C C:\OEM\install.bat"</CommandLine> + <Description>Execute custom script from the OEM folder if exists</Description> + </SynchronousCommand> + </FirstLogonCommands> + </component> + </settings> +</unattend> diff --git a/assets/win11x64-ltsc.xml b/assets/win11x64-ltsc.xml new file mode 100644 index 0000000..16ec029 --- /dev/null +++ b/assets/win11x64-ltsc.xml @@ -0,0 +1,453 @@ +<?xml version="1.0" encoding="UTF-8"?> +<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"> + <settings pass="windowsPE"> + <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <SetupUILanguage> + <UILanguage>en-US</UILanguage> + </SetupUILanguage> + <InputLocale>0409:00000409</InputLocale> + <SystemLocale>en-US</SystemLocale> + <UILanguage>en-US</UILanguage> + <UserLocale>en-US</UserLocale> + </component> + <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <DiskConfiguration> + <Disk wcm:action="add"> + <DiskID>0</DiskID> + <WillWipeDisk>true</WillWipeDisk> + <CreatePartitions> + <!-- System partition (ESP) --> + <CreatePartition wcm:action="add"> + <Order>1</Order> + <Type>EFI</Type> + <Size>128</Size> + </CreatePartition> + <!-- Microsoft reserved partition (MSR) --> + <CreatePartition wcm:action="add"> + <Order>2</Order> + <Type>MSR</Type> + <Size>128</Size> + </CreatePartition> + <!-- Windows partition --> + <CreatePartition wcm:action="add"> + <Order>3</Order> + <Type>Primary</Type> + <Extend>true</Extend> + </CreatePartition> + </CreatePartitions> + <ModifyPartitions> + <!-- System partition (ESP) --> + <ModifyPartition wcm:action="add"> + <Order>1</Order> + <PartitionID>1</PartitionID> + <Label>System</Label> + <Format>FAT32</Format> + </ModifyPartition> + <!-- MSR partition does not need to be modified --> + <ModifyPartition wcm:action="add"> + <Order>2</Order> + <PartitionID>2</PartitionID> + </ModifyPartition> + <!-- Windows partition --> + <ModifyPartition wcm:action="add"> + <Order>3</Order> + <PartitionID>3</PartitionID> + <Label>Windows</Label> + <Letter>C</Letter> + <Format>NTFS</Format> + </ModifyPartition> + </ModifyPartitions> + </Disk> + </DiskConfiguration> + <ImageInstall> + <OSImage> + <InstallFrom> + <MetaData wcm:action="add"> + <Key>/image/index</Key> + <Value>1</Value> + </MetaData> + </InstallFrom> + <InstallTo> + <DiskID>0</DiskID> + <PartitionID>3</PartitionID> + </InstallTo> + <InstallToAvailablePartition>false</InstallToAvailablePartition> + </OSImage> + </ImageInstall> + <DynamicUpdate> + <Enable>true</Enable> + <WillShowUI>Never</WillShowUI> + </DynamicUpdate> + <UpgradeData> + <Upgrade>false</Upgrade> + <WillShowUI>Never</WillShowUI> + </UpgradeData> + <UserData> + <AcceptEula>true</AcceptEula> + <FullName>Docker</FullName> + <Organization>Windows for Docker</Organization> + </UserData> + <EnableFirewall>false</EnableFirewall> + <Diagnostics> + <OptIn>false</OptIn> + </Diagnostics> + <RunSynchronous> + <RunSynchronousCommand wcm:action="add"> + <Order>1</Order> + <Path>reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassTPMCheck /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>2</Order> + <Path>reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassSecureBootCheck /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>3</Order> + <Path>reg.exe add "HKLM\SYSTEM\Setup\LabConfig" /v BypassRAMCheck /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>4</Order> + <Path>reg.exe add "HKLM\SYSTEM\Setup\MoSetup" /v AllowUpgradesWithUnsupportedTPMOrCPU /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + </RunSynchronous> + </component> + </settings> + <settings pass="offlineServicing"> + <component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <EnableLUA>false</EnableLUA> + </component> + </settings> + <settings pass="generalize"> + <component name="Microsoft-Windows-PnPSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <PersistAllDeviceInstalls>true</PersistAllDeviceInstalls> + </component> + <component name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <SkipRearm>1</SkipRearm> + </component> + </settings> + <settings pass="specialize"> + <component name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <SkipAutoActivation>true</SkipAutoActivation> + </component> + <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <ComputerName>*</ComputerName> + <OEMInformation> + <Manufacturer>Dockur</Manufacturer> + <Model>Windows for Docker</Model> + <SupportHours>24/7</SupportHours> + <SupportPhone /> + <SupportProvider>Dockur</SupportProvider> + <SupportURL>https://github.com/dockur/windows/issues</SupportURL> + </OEMInformation> + <OEMName>Windows for Docker</OEMName> + </component> + <component name="Microsoft-Windows-ErrorReportingCore" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <DisableWER>1</DisableWER> + </component> + <component name="Microsoft-Windows-IE-InternetExplorer" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <DisableAccelerators>true</DisableAccelerators> + <DisableFirstRunWizard>true</DisableFirstRunWizard> + <Home_Page>https://google.com</Home_Page> + <Help_Page>about:blank</Help_Page> + </component> + <component name="Microsoft-Windows-IE-InternetExplorer" processorArchitecture="wow64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <DisableAccelerators>true</DisableAccelerators> + <DisableFirstRunWizard>true</DisableFirstRunWizard> + <Home_Page>https://google.com</Home_Page> + <Help_Page>about:blank</Help_Page> + </component> + <component name="Microsoft-Windows-SQMApi" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <CEIPEnabled>0</CEIPEnabled> + </component> + <component name="Microsoft-Windows-SystemRestore-Main" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <DisableSR>1</DisableSR> + </component> + <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <InputLocale>0409:00000409</InputLocale> + <SystemLocale>en-US</SystemLocale> + <UILanguage>en-US</UILanguage> + <UserLocale>en-US</UserLocale> + </component> + <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <RunSynchronous> + <RunSynchronousCommand wcm:action="add"> + <Order>1</Order> + <Path>reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" /v BypassNRO /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>2</Order> + <Path>reg.exe load "HKU\mount" "C:\Users\Default\NTUSER.DAT"</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>3</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "ContentDeliveryAllowed" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>4</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "FeatureManagementEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>5</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "OEMPreInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>6</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>7</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "PreInstalledAppsEverEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>8</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SilentInstalledAppsEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>9</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SoftLandingEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>10</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContentEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>11</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-310093Enabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>12</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338387Enabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>13</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338388Enabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>14</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338389Enabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>15</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-338393Enabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>16</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SubscribedContent-353698Enabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>17</Order> + <Path>reg.exe add "HKU\mount\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager" /v "SystemPaneSuggestionsEnabled" /t REG_DWORD /d 0 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>18</Order> + <Path>reg.exe add "HKU\mount\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableCloudOptimizedContent" /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>19</Order> + <Path>reg.exe add "HKU\mount\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>20</Order> + <Path>reg.exe add "HKU\mount\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableConsumerAccountStateContent" /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>21</Order> + <Path>reg.exe unload "HKU\mount"</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>22</Order> + <Path>reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableCloudOptimizedContent" /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>23</Order> + <Path>reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableWindowsConsumerFeatures" /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>24</Order> + <Path>reg.exe add "HKLM\Software\Policies\Microsoft\Windows\CloudContent" /v "DisableConsumerAccountStateContent" /t REG_DWORD /d 1 /f</Path> + </RunSynchronousCommand> + <RunSynchronousCommand wcm:action="add"> + <Order>25</Order> + <Path>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\CurrentVersion\NetworkList\Signatures\FirstNetwork" /v Category /t REG_DWORD /d 1 /f</Path> + <Description>Set Network Location to Home</Description> + </RunSynchronousCommand> + </RunSynchronous> + </component> + <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <fDenyTSConnections>false</fDenyTSConnections> + </component> + <component name="Microsoft-Windows-TerminalServices-RDP-WinStationExtensions" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <UserAuthentication>0</UserAuthentication> + </component> + <component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <FirewallGroups> + <FirewallGroup wcm:action="add" wcm:keyValue="RemoteDesktop"> + <Active>true</Active> + <Profile>all</Profile> + <Group>@FirewallAPI.dll,-28752</Group> + </FirewallGroup> + </FirewallGroups> + </component> + </settings> + <settings pass="auditSystem" /> + <settings pass="auditUser" /> + <settings pass="oobeSystem"> + <component name="Microsoft-Windows-SecureStartup-FilterDriver" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <PreventDeviceEncryption>true</PreventDeviceEncryption> + </component> + <component name="Microsoft-Windows-EnhancedStorage-Adm" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <TCGSecurityActivationDisabled>1</TCGSecurityActivationDisabled> + </component> + <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> + <UserAccounts> + <LocalAccounts> + <LocalAccount wcm:action="add"> + <Name>Docker</Name> + <Group>Administrators</Group> + <Password> + <Value /> + <PlainText>true</PlainText> + </Password> + </LocalAccount> + </LocalAccounts> + <AdministratorPassword> + <Value>password</Value> + <PlainText>true</PlainText> + </AdministratorPassword> + </UserAccounts> + <AutoLogon> + <Username>Docker</Username> + <Enabled>true</Enabled> + <LogonCount>65432</LogonCount> + <Password> + <Value /> + <PlainText>true</PlainText> + </Password> + </AutoLogon> + <Display> + <ColorDepth>32</ColorDepth> + <HorizontalResolution>1920</HorizontalResolution> + <VerticalResolution>1080</VerticalResolution> + </Display> + <OOBE> + <HideEULAPage>true</HideEULAPage> + <HideLocalAccountScreen>true</HideLocalAccountScreen> + <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> + <HideOnlineAccountScreens>true</HideOnlineAccountScreens> + <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> + <NetworkLocation>Home</NetworkLocation> + <ProtectYourPC>3</ProtectYourPC> + <SkipUserOOBE>true</SkipUserOOBE> + <SkipMachineOOBE>true</SkipMachineOOBE> + </OOBE> + <RegisteredOrganization>Dockur</RegisteredOrganization> + <RegisteredOwner>Windows for Docker</RegisteredOwner> + <FirstLogonCommands> + <SynchronousCommand wcm:action="add"> + <Order>1</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" /v "AllowInsecureGuestAuth" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Allow guest access to network shares</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>2</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v LimitBlankPasswordUse /t REG_DWORD /d 0 /f</CommandLine> + <Description>Allow RDP login with blank password</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>3</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PasswordLess\Device" /v "DevicePasswordLessBuildVersion" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Enable option for passwordless sign-in</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>4</Order> + <CommandLine>cmd /C wmic useraccount where name="Docker" set PasswordExpires=false</CommandLine> + <Description>Password Never Expires</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>5</Order> + <CommandLine>cmd /C POWERCFG -H OFF</CommandLine> + <Description>Disable Hibernation</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>6</Order> + <CommandLine>cmd /C POWERCFG -X -monitor-timeout-ac 0</CommandLine> + <Description>Disable monitor blanking</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>7</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Edge" /v "HideFirstRunExperience" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Disable first-run experience in Edge</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>8</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "HideFileExt" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Show file extensions in Explorer</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>9</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\Power" /v "HibernateFileSizePercent" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Zero Hibernation File</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>10</Order> + <CommandLine>reg.exe add "HKLM\SYSTEM\CurrentControlSet\Control\Power" /v "HibernateEnabled" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Disable Hibernation</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>11</Order> + <CommandLine>cmd /C POWERCFG -X -standby-timeout-ac 0</CommandLine> + <Description>Disable Sleep</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>12</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v "fAllowUnlistedRemotePrograms" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Enable RemoteAPP to launch unlisted programs</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>13</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "ShowTaskViewButton" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Remove Task View from the Taskbar</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>14</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "TaskbarDa" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Remove Widgets from the Taskbar</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>15</Order> + <CommandLine>reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "TaskbarMn" /t REG_DWORD /d 0 /f</CommandLine> + <Description>Remove Chat from the Taskbar</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>16</Order> + <CommandLine>reg.exe add "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" /v "NoAutoUpdate" /t REG_DWORD /d 1 /f</CommandLine> + <Description>Turn off Windows Update auto download</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>17</Order> + <CommandLine>netsh advfirewall firewall set rule group="@FirewallAPI.dll,-32752" new enable=Yes</CommandLine> + <Description>Enable Network Discovery</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>18</Order> + <CommandLine>netsh advfirewall firewall set rule group="@FirewallAPI.dll,-28502" new enable=Yes</CommandLine> + <Description>Enable File Sharing</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>19</Order> + <CommandLine>reg.exe add "HKCU\Control Panel\UnsupportedHardwareNotificationCache" /v SV1 /d 0 /t REG_DWORD /f</CommandLine> + <Description>Disable unsupported hardware notifications</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>20</Order> + <CommandLine>reg.exe add "HKCU\Control Panel\UnsupportedHardwareNotificationCache" /v SV2 /d 0 /t REG_DWORD /f</CommandLine> + <Description>Disable unsupported hardware notifications</Description> + </SynchronousCommand> + <SynchronousCommand wcm:action="add"> + <Order>21</Order> + <CommandLine>cmd /C if exist "C:\OEM\install.bat" start "Install" "cmd /C C:\OEM\install.bat"</CommandLine> + <Description>Execute custom script from the OEM folder if exists</Description> + </SynchronousCommand> + </FirstLogonCommands> + </component> + </settings> +</unattend> diff --git a/readme.md b/readme.md index e264a0f..44d461a 100644 --- a/readme.md +++ b/readme.md @@ -87,12 +87,12 @@ kubectl apply -f kubernetes.yml |---|---|---| | `win11` | Windows 11 Pro | 6.4 GB | | `win11e` | Windows 11 Enterprise | 5.8 GB | - | `win10` | Windows 10 Pro | 5.8 GB | + | `win10` | Windows 10 Pro | 5.7 GB | | `ltsc10` | Windows 10 LTSC | 4.6 GB | | `win10e` | Windows 10 Enterprise | 5.2 GB | |||| - | `win8` | Windows 8.1 Pro | 4.2 GB | - | `win8e` | Windows 8.1 Enterprise | 3.8 GB | + | `win8` | Windows 8.1 Pro | 4.0 GB | + | `win8e` | Windows 8.1 Enterprise | 3.7 GB | | `win7` | Windows 7 Enterprise | 3.0 GB | | `vista` | Windows Vista Enterprise | 3.0 GB | | `winxp` | Windows XP Professional | 0.6 GB | @@ -179,22 +179,9 @@ kubectl apply -f kubernetes.yml Replace the example path `/home/user/example.iso` with the filename of your desired ISO file, the value of `VERSION` will be ignored in this case. -* ### How do I customize the installation? - - If you want to modify the settings used during the automatic installation, you can do this by editing the answer file corresponding to your Windows edition, for example [win11x64.xml](https://raw.githubusercontent.com/dockur/windows/master/assets/win11x64.xml) in the case of Windows 11 Pro. - - Apply your modifications to it, and add this line to your compose file: - - ```yaml - volumes: - - /home/user/example.xml:/custom.xml - ``` - - Replace the example path `/home/user/example.xml` with the filename of the modified XML file. - * ### How do I run a script after installation? - To run your own script after installation, you can create a file called `install.bat` and place it in a folder together with other files it needs (programs to install for example). Then bind it in your compose file like this: + To run your own script after installation, you can create a file called `install.bat` and place it in a folder together with any additional files it needs (software to be installed for example). Then bind that folder in your compose file like this: ```yaml volumes: @@ -205,7 +192,7 @@ kubectl apply -f kubernetes.yml * ### How do I perform a manual installation? - It's best to use the automatic installation, as it prevents common issues that occur when running Windows inside a virtualized environment and optimizes various settings to give you maximum performance. + It's best to stick to the automatic installation, as it adjusts various settings to prevent common issues when running Windows inside a virtual environment. However, if you insist on performing the installation manually, add the following environment variable to your compose file: @@ -214,32 +201,6 @@ kubectl apply -f kubernetes.yml MANUAL: "Y" ``` - Then follow these steps: - - - Start the container and connect to [port 8006](http://localhost:8006) of the container in your web browser. After the download is finished, you will see the Windows installation screen. - - - Start the installation by clicking `Install now`. On the next screen, press 'OK' when prompted to `Load driver`. - - - Select the `VirtIO SCSI` driver from the list that matches your Windows version. So for Windows 11, select `D:\amd64\w11\vioscsi.inf` and click 'Next'. - - - Accept the license agreement and select your preferred Windows edition, like Home or Pro. - - - Choose `Custom: Install Windows only (advanced)`, and click `Load driver` on the next screen. - - - Select 'Browse' and navigate to the `D:\NetKVM\w11\amd64` folder, and click 'OK'. - - - Select the `VirtIO Ethernet Adapter` from the list and click 'Next'. - - - Select `Drive 0` and click 'Next'. - - - Wait until Windows finishes copying files and completes the installation. - - - Once you see the desktop, open File Explorer and navigate to the CD-ROM drive (`E:\`). - - - Double-click on `virtio-win-gt-x64.msi` and proceed to install the VirtIO drivers. - - Enjoy your brand new machine, and don't forget to star this repo! - * ### How do I verify if my system supports KVM? To verify if your system supports KVM, run the following commands: @@ -251,11 +212,11 @@ kubectl apply -f kubernetes.yml If you receive an error from `kvm-ok` indicating that KVM acceleration can't be used, check the virtualization settings in the BIOS. -* ### How do I increase the amount of CPU or RAM? +* ### How do I change the amount of CPU or RAM? - By default, 2 CPU cores and 4 GB of RAM are allocated to the container, as those are the minimum requirements of Windows 11. + By default, the container will be allowed to use a maximum of 2 CPU cores and 4 GB of RAM. - If there arises a need to increase this, add the following environment variables: + If you want to adjust this, you can specify the desired amount using the following environment variables: ```yaml environment: @@ -265,12 +226,14 @@ kubectl apply -f kubernetes.yml * ### How do I configure the username and password? - By default, a user called `Docker` is created during installation with an empty password. You can change these credentials in your compose file: + By default, a user called `Docker` is created during the installation, with an empty password. + + If you want to use different credentials, you can change them in your compose file: ```yaml environment: - USERNAME: "john" - PASSWORD: "secret" + USERNAME: "bill" + PASSWORD: "gates" ``` * ### How do I connect using RDP? @@ -279,7 +242,7 @@ kubectl apply -f kubernetes.yml So for a better experience you can connect using any Microsoft Remote Desktop client to the IP of the container, using the username `Docker` and by leaving the password empty. - There is a good RDP client for [Android](https://play.google.com/store/apps/details?id=com.microsoft.rdc.androidx) available from the Play Store and one for [iOS](https://apps.apple.com/nl/app/microsoft-remote-desktop/id714464092?l=en-GB) in the Apple Store. For Linux you can use [FreeRDP](https://www.freerdp.com/) and on Windows just type `mstsc` in the search box. + There is a RDP client for [Android](https://play.google.com/store/apps/details?id=com.microsoft.rdc.androidx) available from the Play Store and one for [iOS](https://apps.apple.com/nl/app/microsoft-remote-desktop/id714464092?l=en-GB) in the Apple Store. For Linux you can use [FreeRDP](https://www.freerdp.com/) and on Windows just type `mstsc` in the search box. * ### How do I assign an individual IP address to the container? diff --git a/src/define.sh b/src/define.sh index 06ded9a..dad5cee 100644 --- a/src/define.sh +++ b/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 } diff --git a/src/entry.sh b/src/entry.sh index 24bdf50..c2c3912 100644 --- a/src/entry.sh +++ b/src/entry.sh @@ -35,4 +35,4 @@ cat "$QEMU_TERM" 2> /dev/null | tee "$QEMU_PTY" & wait $! || : sleep 1 & wait $! -finish 0 +[ ! -f "$QEMU_END" ] && finish 0 diff --git a/src/install.sh b/src/install.sh index 558b10e..8fd09c4 100644 --- a/src/install.sh +++ b/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 diff --git a/src/mido.sh b/src/mido.sh index 59ceae7..ff285cb 100644 --- a/src/mido.sh +++ b/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/&quot;//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/&quot;//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/&amp;/\&/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/&amp;/\&/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" diff --git a/src/power.sh b/src/power.sh index 3b61825..6540a56 100644 --- a/src/power.sh +++ b/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 }