diff --git a/DISMTools.vbproj b/DISMTools.vbproj
index bf102266..63112caf 100644
--- a/DISMTools.vbproj
+++ b/DISMTools.vbproj
@@ -80,8 +80,8 @@
packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll
-
- packages\Markdig.0.42.0\lib\net462\Markdig.dll
+
+ packages\Markdig.0.43.0\lib\net462\Markdig.dll
packages\Microsoft.Dism.3.3.12\lib\net40\Microsoft.Dism.dll
@@ -1213,10 +1213,15 @@
+
+
+
+
+
Always
@@ -1259,6 +1264,9 @@
Always
+
+ Always
+
Always
@@ -1274,6 +1282,9 @@
Always
+
+ Always
+
Always
@@ -1893,7 +1904,6 @@
-
diff --git a/Elements/AutoUnattend/ActiveDirectory/ADDSJoinDialog.vb b/Elements/AutoUnattend/ActiveDirectory/ADDSJoinDialog.vb
index c1f923c8..10ed0926 100644
--- a/Elements/AutoUnattend/ActiveDirectory/ADDSJoinDialog.vb
+++ b/Elements/AutoUnattend/ActiveDirectory/ADDSJoinDialog.vb
@@ -258,7 +258,7 @@ Public Class ADDSJoinDialog
MsgBox("A domain name must be specified", vbOKOnly + vbCritical)
Return False
End If
- If TextBox5.Text = "" Then
+ If initialUserName = "" Then
MsgBox("A user name must be specified", vbOKOnly + vbCritical)
Return False
End If
diff --git a/Elements/AutoUnattend/StarterScripts/DuringSystemConfiguration/Set OEM Information.dtss b/Elements/AutoUnattend/StarterScripts/DuringSystemConfiguration/Set OEM Information.dtss
new file mode 100644
index 00000000..bc2b52fa
--- /dev/null
+++ b/Elements/AutoUnattend/StarterScripts/DuringSystemConfiguration/Set OEM Information.dtss
@@ -0,0 +1,29 @@
+Language: Batch
+
+@echo off
+REM This script configures OEM Information that you can see in system information screens.
+REM Configure the options below to set manufacturer information.
+
+REM ------ OPTIONS ------
+REM - 1. Manufacturer * -
+REM - 2. Model -
+REM - 3. Support Hours -
+REM - 4. Support Phone -
+REM - 5. Support URL -
+REM - 6. OEM Logo Path -
+REM ---------------------
+REM * -- Required
+
+SET "OEM_Manufacturer="
+SET "OEM_Model="
+SET "OEM_SupportHours="
+SET "OEM_SupportPhone="
+SET "OEM_SupportURL="
+SET "OEM_Logo="
+
+IF DEFINED OEM_Manufacturer ( reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\OEMInformation" /v Manufacturer /t REG_SZ /d "%OEM_Manufacturer%" /f )
+IF DEFINED OEM_Model ( reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\OEMInformation" /v Model /t REG_SZ /d "%OEM_Model%" /f )
+IF DEFINED OEM_SupportHours ( reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\OEMInformation" /v SupportHours /t REG_SZ /d "%OEM_SupportHours%" /f )
+IF DEFINED OEM_SupportPhone ( reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\OEMInformation" /v SupportPhone /t REG_SZ /d "%OEM_SupportPhone%" /f )
+IF DEFINED OEM_SupportURL ( reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\OEMInformation" /v SupportURL /t REG_SZ /d "%OEM_SupportURL%" /f )
+IF DEFINED OEM_Logo ( reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\OEMInformation" /v Logo /t REG_SZ /d "%OEM_Logo%" /f )
\ No newline at end of file
diff --git a/Elements/AutoUnattend/StarterScripts/DuringSystemConfiguration/Set Quick Machine Recovery Settings.dtss b/Elements/AutoUnattend/StarterScripts/DuringSystemConfiguration/Set Quick Machine Recovery Settings.dtss
new file mode 100644
index 00000000..6ccc3dae
--- /dev/null
+++ b/Elements/AutoUnattend/StarterScripts/DuringSystemConfiguration/Set Quick Machine Recovery Settings.dtss
@@ -0,0 +1,56 @@
+Language: Batch
+
+@echo off
+REM This script configures Quick Machine Recovery (QMR) settings. QMR is a new recovery
+REM method found in Windows 11 24H2 and higher. DO NOT USE SCRIPT IF TARGET IMAGE IS
+REM WINDOWS 11 23H2 OR OLDER!
+REM
+REM QMR is part of the set of features proposed in the Windows Resiliency Initiative,
+REM introduced after the CrowdStrike incident.
+
+REM ---------- OPTIONS -----------
+REM - 1. Cloud Remediation State - 0 or 1
+REM - 2. Auto Remediation State - 0 or 1
+REM - 3. Mins. Until Next Check -
+REM - 4. Hours Until Next Reboot -
+REM - 5. Headless Recovery - 0 or 1
+REM ------------------------------
+REM NOTES:
+REM - Options 3/4 will only take effect if auto remediation is enabled
+REM - Cloud Remediation allows the system to scan for solutions on WinRE launch
+REM - Auto Remediation allows the system to continue scanning for solutions if the
+REM first attempt fails
+REM - Headless is undocumented but defined in reagentc XML
+
+SET QMR_CloudRemediation=0
+SET QMR_AutoRemediation=0
+SET QMR_NextCheckMinutes=30
+SET QMR_NextRebootHours=72
+SET QMR_Headless=0
+
+REM leave the rest of this script as is
+
+IF NOT DEFINED QMR_CloudRemediation (SET QMR_CloudRemediation=0)
+IF NOT DEFINED QMR_AutoRemediation (SET QMR_AutoRemediation=0)
+IF NOT DEFINED QMR_NextCheckMinutes (SET QMR_NextCheckMinutes=30)
+IF NOT DEFINED QMR_NextRebootHours (SET QMR_NextRebootHours=72)
+IF NOT DEFINED QMR_Headless (SET QMR_Headless=0)
+
+REM convert hours to minutes since reagentc xml expects minutes and not hours
+SET /A QMR_NextRebootMinutes=%QMR_NextRebootHours% * 60 >nul
+
+SET "REAGENTC_XML=%SYSTEMROOT%\system32\dt_reagentc.xml"
+
+REM we'll save our custom reagentc xml to system32 - since < and > are used in cmd
+REM for redirection, we'll escape them like this: ^< ^>
+ECHO ^ > %REAGENTC_XML%
+ECHO. >> %REAGENTC_XML%
+ECHO ^ >> %REAGENTC_XML%
+ECHO ^ >> %REAGENTC_XML%
+ECHO ^ >> %REAGENTC_XML%
+ECHO ^ >> %REAGENTC_XML%
+ECHO ^ >> %REAGENTC_XML%
+ECHO ^ >> %REAGENTC_XML%
+ECHO ^ >> %REAGENTC_XML%
+
+IF EXIST "%REAGENTC_XML%" ( reagentc /setrecoverysettings /path "%REAGENTC_XML%" )
\ No newline at end of file
diff --git a/Elements/AutoUnattend/StarterScripts/WhenFirstUserLogsOn/Invoke WinUtil configuration.dtss b/Elements/AutoUnattend/StarterScripts/WhenFirstUserLogsOn/Invoke WinUtil configuration.dtss
index eb3fbe7d..2c41252d 100644
--- a/Elements/AutoUnattend/StarterScripts/WhenFirstUserLogsOn/Invoke WinUtil configuration.dtss
+++ b/Elements/AutoUnattend/StarterScripts/WhenFirstUserLogsOn/Invoke WinUtil configuration.dtss
@@ -2,6 +2,6 @@
# Export your WinUtil configuration file to "winutil-config.json" on the root of the target
# Windows installation.
-if ((Test-Connection "christitus.com") -and (Test-Path -Path "$env:SYSTEMDRIVE\winutil-config.json" -PathType Leaf)) {
+if ((Test-Connection -ComputerName "christitus.com" -Count 1) -and (Test-Path -Path "$env:SYSTEMDRIVE\winutil-config.json" -PathType Leaf)) {
iex "& { $(irm christitus.com/win) } -Config `"$env:SYSTEMDRIVE\winutil-config.json`" -Run"
}
\ No newline at end of file
diff --git a/Elements/AutoUnattend/StarterScripts/WhenFirstUserLogsOn/Set Registered Owner and Organization Information.dtss b/Elements/AutoUnattend/StarterScripts/WhenFirstUserLogsOn/Set Registered Owner and Organization Information.dtss
new file mode 100644
index 00000000..8af136c2
--- /dev/null
+++ b/Elements/AutoUnattend/StarterScripts/WhenFirstUserLogsOn/Set Registered Owner and Organization Information.dtss
@@ -0,0 +1,35 @@
+Language: Batch
+
+@echo off
+REM This script sets up registered user and organization information given the following settings:
+REM ---- Settings ----
+REM 1. AutoUserInfo - determines whether to set registered owner as the name of the
+REM currently signed user (0 | 1)
+REM 2. RegisteredUser - the registered owner. This is overridden by AutoUserInfo when
+REM set to 1
+REM 3. RegisteredOrg - the registered organization. This is optional
+REM ------------------
+REM By default, software that accesses registered user/org information, if not previously set,
+REM will return "user name" and "org name", respectively. It is recommended to run this script
+REM only when the first user logs on, because, if run when users log on for the first time,
+REM owner information will change every time a user logs on for the first time if the following
+REM conditions are met:
+REM a) Either:
+REM * multiple users are preloaded on a system using the unattended answer file, or
+REM * an account, or set of accounts, is added after OS installation
+REM b) AutoUserInfo is set to 1. Otherwise, a constant value is used and you will not notice
+REM any changes
+
+SET AutoUserInfo=0
+SET "RegisteredUser=REGISTERED_USER_HERE"
+SET "RegisteredOrg="
+
+REM If we set autouserinfo to 1 we set the registered user to the current user name.
+REM For Microsoft accounts, username information may only be the first 5 letters of
+REM the user's email address.
+IF %AutoUserInfo% EQU 1 (
+ SET "RegisteredUser=%USERNAME%"
+)
+
+IF DEFINED RegisteredUser ( reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion" /v RegisteredOwner /t REG_SZ /d "%RegisteredUser%" /f )
+IF DEFINED RegisteredOrg ( reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion" /v RegisteredOrganization /t REG_SZ /d "%RegisteredOrg%" /f )
\ No newline at end of file
diff --git a/Elements/AutoUnattend/StarterScripts/WhenUsersLogOnForFirstTime/Disable Second Chance OOBE.dtss b/Elements/AutoUnattend/StarterScripts/WhenUsersLogOnForFirstTime/Disable Second Chance OOBE.dtss
new file mode 100644
index 00000000..8c8dc02e
--- /dev/null
+++ b/Elements/AutoUnattend/StarterScripts/WhenUsersLogOnForFirstTime/Disable Second Chance OOBE.dtss
@@ -0,0 +1,9 @@
+Language: Batch
+
+@echo off
+REM This script disables the Second Chance Out-of-Box Experience (SCOOBE), responsible for
+REM suggesting (again) Microsoft services and subscriptions. This is applied for all users
+REM in a system.
+
+reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\UserProfileEngagement" /f
+reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\UserProfileEngagement" /v ScoobeSystemSettingEnabled /t REG_DWORD /d 0 /f
\ No newline at end of file
diff --git a/Elements/AutoUnattend/StarterScripts/WhenUsersLogOnForFirstTime/Disable Windows Notification Sources.dtss b/Elements/AutoUnattend/StarterScripts/WhenUsersLogOnForFirstTime/Disable Windows Notification Sources.dtss
new file mode 100644
index 00000000..86a19d38
--- /dev/null
+++ b/Elements/AutoUnattend/StarterScripts/WhenUsersLogOnForFirstTime/Disable Windows Notification Sources.dtss
@@ -0,0 +1,19 @@
+Language: Batch
+
+@echo off
+REM This script disables notifications for the notification sources defined below. Continuing with answer
+REM file creation using this script, without any modifications, will disable 4 notification sources in the target
+REM Windows image:
+REM - Suggested (Windows 10/11) - Microsoft products/services/subscriptions
+REM - Startup App Notification (Windows Server 2022+/Windows 11+)
+REM - OneDrive (SkyDrive)
+REM - Microsoft Account Health
+REM To add notification sources to disable in this script, add them to the list below, like this:
+REM FOR %%a IN (Windows.SystemToast.Suggested ... ) DO ...
+REM The sources you specify will be added to the notifications list in Settings -> System -> Notifications. You can
+REM re-enable them if you see fit.
+
+FOR %%a IN (Windows.SystemToast.Suggested Windows.SystemToast.StartupApp Microsoft.SkyDrive.Desktop Windows.SystemToast.AccountHealth) DO (
+ reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\%%a" /f
+ reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Notifications\Settings\%%a" /v Enabled /t REG_DWORD /d 0 /f
+)
\ No newline at end of file
diff --git a/Elements/EnvVarManagement/EnvironmentVariableHelper.vb b/Elements/EnvVarManagement/EnvironmentVariableHelper.vb
index b6509082..c3fed657 100644
--- a/Elements/EnvVarManagement/EnvironmentVariableHelper.vb
+++ b/Elements/EnvVarManagement/EnvironmentVariableHelper.vb
@@ -1,5 +1,6 @@
Imports System.IO
Imports Microsoft.Win32
+Imports Microsoft.VisualBasic.ControlChars
Module EnvironmentVariableHelper
@@ -54,4 +55,91 @@ Module EnvironmentVariableHelper
Return envVarList
End Function
+ Private Function ExportCurrentEnvVarInformation(IsSystemScope As Boolean) As Boolean
+ If IsSystemScope Then
+ Dim defaultControlSet As Integer = GetDefaultControlSet("zSYSTEM")
+
+ If defaultControlSet = -1 Then
+ Return False
+ End If
+
+ Return RegistryHelper.ExportRegistryToFile(String.Format("HKLM\zSYSTEM\ControlSet{0}\Control\Session Manager\Environment", defaultControlSet.ToString().PadLeft(3, "0"c)),
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
+ String.Format("SysEnvVarInformation_{0}.reg", Date.UtcNow.ToString("yyyyMMdd-HHmmss")))) = 0
+ Else
+ Return RegistryHelper.ExportRegistryToFile("HKLM\zDEFAULT\Environment",
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
+ String.Format("UserEnvVarInformation_{0}.reg", Date.UtcNow.ToString("yyyyMMdd-HHmmss")))) = 0
+ End If
+ End Function
+
+ Public Function SaveEnvironmentVariables(MountPath As String, VariableList As List(Of EnvironmentVariable)) As Boolean
+ If VariableList Is Nothing Then Return False
+
+ Dim machineVariables As List(Of EnvironmentVariable) = VariableList.Where(Function(variable) variable.Scope = EnvironmentVariable.EnvironmentVariableScope.Machine).ToList(),
+ userVariables As List(Of EnvironmentVariable) = VariableList.Where(Function(variable) variable.Scope = EnvironmentVariable.EnvironmentVariableScope.User).ToList()
+
+ Try
+ ' An interesting discovery is that environment variables can only really be string or expand string values. Even
+ ' if it only contains numeric values, it will be saved as a string.
+
+ If RegistryHelper.LoadRegistryHive(Path.Combine(MountPath, "Windows", "system32", "config", "SYSTEM"), "HKLM\zSYSTEM") = 0 Then
+ ' Back up current system env vars
+ If Not ExportCurrentEnvVarInformation(True) Then
+ If MsgBox("Current environment variable information for the system scope could not be backed up. Backups are used in case of a mistake during environment variable management. You may continue, but at your own risk." & CrLf & CrLf &
+ "Applications that rely on these variables may not work correctly, and you will not be able to use previous variable configuration, unless you had previously backed it up by yourself." & CrLf & CrLf &
+ "Do you want to continue without backing up current variable information?", vbYesNo + vbExclamation, "Environment variable information could not be backed up") = MsgBoxResult.No Then
+ Return False
+ End If
+ End If
+
+
+ Dim defaultControlSet As Integer = RegistryHelper.GetDefaultControlSet("zSYSTEM")
+ If defaultControlSet > 0 Then
+ ' If we could load the hive, we determine the control set then configure machine vars.
+ For Each machineVariable In machineVariables
+ ' We'll check if we can expand the environment variables contained within the envvar value. If we could expand them,
+ ' then we go with an expand string. Otherwise we'll go with a string
+ Dim expandedValue As String = Environment.ExpandEnvironmentVariables(machineVariable.Value)
+
+ RegistryHelper.AddRegistryItem(New RegistryItem(String.Format("HKLM\zSYSTEM\ControlSet{0}\Control\Session Manager\Environment",
+ defaultControlSet.ToString().PadLeft(3, "0"c)),
+ machineVariable.Name,
+ If(machineVariable.Value.Equals(expandedValue), RegistryValueKind.String, RegistryValueKind.ExpandString),
+ machineVariable.Value))
+ Next
+ End If
+ RegistryHelper.UnloadRegistryHive("HKLM\zSYSTEM")
+ End If
+
+ If RegistryHelper.LoadRegistryHive(Path.Combine(MountPath, "Users", "Default", "NTUSER.DAT"), "HKLM\zDEFAULT") = 0 Then
+ ' Back up current user env vars
+ If Not ExportCurrentEnvVarInformation(False) Then
+ If MsgBox("Current environment variable information for the user scope could not be backed up. Backups are used in case of a mistake during environment variable management. You may continue, but at your own risk." & CrLf & CrLf &
+ "Applications that rely on these variables may not work correctly, and you will not be able to use previous variable configuration, unless you had previously backed it up by yourself." & CrLf & CrLf &
+ "Do you want to continue without backing up current variable information?", vbYesNo + vbExclamation, "Environment variable information could not be backed up") = MsgBoxResult.No Then
+ Return False
+ End If
+ End If
+
+ ' We don't have to determine control sets here
+ For Each userVariable In userVariables
+ Dim expandedValue As String = Environment.ExpandEnvironmentVariables(userVariable.Value)
+
+ RegistryHelper.AddRegistryItem(New RegistryItem("HKLM\zDEFAULT\Environment",
+ userVariable.Name,
+ If(userVariable.Value.Equals(expandedValue), RegistryValueKind.String, RegistryValueKind.ExpandString),
+ userVariable.Value))
+
+ Next
+ RegistryHelper.UnloadRegistryHive("HKLM\zDEFAULT")
+ End If
+
+ Catch ex As Exception
+
+ Return False
+ End Try
+ Return True
+ End Function
+
End Module
diff --git a/Helpers/extps1/PE_Helper/PE_Helper.ps1 b/Helpers/extps1/PE_Helper/PE_Helper.ps1
index ed954bc8..c2f9f996 100644
--- a/Helpers/extps1/PE_Helper/PE_Helper.ps1
+++ b/Helpers/extps1/PE_Helper/PE_Helper.ps1
@@ -233,6 +233,7 @@ function Start-PEGeneration
Copy-Item -Path "$((Get-Location).Path)\files\README1ST.TXT" -Destination "$((Get-Location).Path)\ISOTEMP\media\README.TXT" -Verbose -Force -Recurse -Container -ErrorAction SilentlyContinue
New-Item -Path "$((Get-Location).Path)\ISOTEMP\media\Tools\DIM" -ItemType Directory | Out-Null
Copy-Item -Path "$((Get-Location).Path)\tools\DIM\*" -Destination "$((Get-Location).Path)\ISOTEMP\media\Tools\DIM" -Verbose -Force -Recurse -Container -ErrorAction SilentlyContinue
+ Copy-Item -Path "$((Get-Location).Path)\files\*.sh" -Destination "$((Get-Location).Path)\ISOTEMP\media" -Verbose -Force -Recurse -Container -ErrorAction SilentlyContinue
if (($unattendFile -ne "") -and (Test-Path "$unattendFile" -PathType Leaf))
{
Write-Host "Unattended answer file has been detected. Copying to ISO file..."
diff --git a/Helpers/extps1/PE_Helper/files/start_foghs_unix.sh b/Helpers/extps1/PE_Helper/files/start_foghs_unix.sh
new file mode 100644
index 00000000..e298fffc
--- /dev/null
+++ b/Helpers/extps1/PE_Helper/files/start_foghs_unix.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+FOGHELPER_SCRIPTPATH="$PWD/pxehelpers/fog/foghelper_server_unix.ps1"
+FOGHELPER_PORT="8080"
+
+clear
+
+whereis pwsh >/dev/null 2>&1
+
+if [[ ! $? ]]; then
+ echo "PowerShell is not installed. Refer to Microsoft documentation in order to install PowerShell for UNIX."
+ echo "If you see this message even when PowerShell is installed on your system, please report this issue."
+ echo ""
+ echo "Exiting..."
+ exit 1
+fi
+
+if [[ ! -f "$FOGHELPER_SCRIPTPATH" ]]; then
+ echo "The FOG Helper server component for Unix systems is not available in either the current path or the provided disc."
+ echo "Exiting..."
+ exit 2
+fi
+
+echo "You may be asked for your password as starting up the FOG Helper Server requires setting up firewall rules for"
+echo "the API listeners and the web server."
+
+sudo iptables -A INPUT -p tcp --dport $FOGHELPER_PORT -j ACCEPT
+export NOFWRULESETUP=1
+pwsh -file "$FOGHELPER_SCRIPTPATH"
+
+echo "Firewall rules set up by this script will now be removed. You may need to enter your superuser password for this"
+echo "task to succeed."
+
+sudo iptables -D INPUT -p tcp --dport $FOGHELPER_PORT -j ACCEPT
+unset NOFWRULESETUP
diff --git a/Helpers/extps1/PE_Helper/pxehelpers/fog/foghelper_server.ps1 b/Helpers/extps1/PE_Helper/pxehelpers/fog/foghelper_server.ps1
index e62c2eef..0bebfad0 100644
--- a/Helpers/extps1/PE_Helper/pxehelpers/fog/foghelper_server.ps1
+++ b/Helpers/extps1/PE_Helper/pxehelpers/fog/foghelper_server.ps1
@@ -494,7 +494,23 @@ try {
+