11/*
22 * Rufus: The Reliable USB Formatting Utility
33 * Windows User Experience
4- * Copyright © 2022-2025 Pete Batard <pete@akeo.ie>
4+ * Copyright © 2022-2026 Pete Batard <pete@akeo.ie>
55 *
66 * This program is free software: you can redistribute it and/or modify
77 * it under the terms of the GNU General Public License as published by
@@ -47,7 +47,6 @@ const char* bypass_name[] = { "BypassTPMCheck", "BypassSecureBootCheck", "Bypass
4747int unattend_xml_flags = 0 , wintogo_index = -1 , wininst_index = 0 ;
4848int unattend_xml_mask = UNATTEND_DEFAULT_SELECTION_MASK ;
4949char * unattend_xml_path = NULL , unattend_username [MAX_USERNAME_LENGTH ];
50- BOOL is_bootloader_revoked = FALSE;
5150
5251extern BOOL validate_md5sum ;
5352extern uint64_t md5sum_totalbytes ;
@@ -65,7 +64,7 @@ char* CreateUnattendXml(int arch, int flags)
6564{
6665 const static char * xml_arch_names [5 ] = { "x86" , "amd64" , "arm" , "arm64" };
6766 const static char * unallowed_account_names [] = { "Administrator" , "Guest" , "KRBTGT" , "Local" , "NONE" };
68- static char path [MAX_PATH ];
67+ static char path [MAX_PATH ], tmp [ MAX_PATH ] ;
6968 char * tzstr ;
7069 FILE * fd ;
7170 TIME_ZONE_INFORMATION tz_info ;
@@ -140,7 +139,8 @@ char* CreateUnattendXml(int arch, int flags)
140139 }
141140
142141 if (flags & UNATTEND_OOBE_MASK ) {
143- order = 1 ;
142+ StrArray first_logon_commands = STRARRAY_EMPTY ;
143+ StrArrayCreate (& first_logon_commands , 8 );
144144 fprintf (fd , " <settings pass=\"oobeSystem\">\n" );
145145 if (flags & UNATTEND_OOBE_SHELL_SETUP_MASK ) {
146146 fprintf (fd , " <component name=\"Microsoft-Windows-Shell-Setup\" processorArchitecture=\"%s\" language=\"neutral\" "
@@ -200,20 +200,40 @@ char* CreateUnattendXml(int arch, int flags)
200200 // Since we set a blank password, we'll ask the user to change it at next logon.
201201 // NB: In case you wanna try, please be aware that Microsoft doesn't let you have multiple
202202 // <FirstLogonCommands> sections in unattend.xml. Don't ask me how I know... :(
203- fprintf (fd , " <FirstLogonCommands>\n" );
204- fprintf (fd , " <SynchronousCommand wcm:action=\"add\">\n" );
205- fprintf (fd , " <Order>%d</Order>\n" , order ++ );
206- fprintf (fd , " <CommandLine>net user "%s" /logonpasswordchg:yes</CommandLine>\n" , unattend_username );
207- fprintf (fd , " </SynchronousCommand>\n" );
208- // Some people report that using the `net user` command above might reset the password expiration to 90 days...
203+ static_sprintf (tmp , "net user "%s" /logonpasswordchg:yes" , unattend_username );
204+ StrArrayAdd (& first_logon_commands , tmp , TRUE);
205+ // The `net user` command above might reset the password expiration to 90 days...
209206 // To alleviate that, blanket set passwords on the target machine to never expire.
210- fprintf (fd , " <SynchronousCommand wcm:action=\"add\">\n" );
211- fprintf (fd , " <Order>%d</Order>\n" , order ++ );
212- fprintf (fd , " <CommandLine>net accounts /maxpwage:unlimited</CommandLine>\n" );
213- fprintf (fd , " </SynchronousCommand>\n" );
214- fprintf (fd , " </FirstLogonCommands>\n" );
207+ StrArrayAdd (& first_logon_commands , "net accounts /maxpwage:unlimited" , TRUE);
215208 }
216209 }
210+
211+ // Apply SkuSiPolicy.p7b, if the user requested it and we're not creating a Windows To Go drive.
212+ // See https://support.microsoft.com/kb/5042562. We do it post install, on first logon, because
213+ // we'd have to patch tons of files otherwise. And we *ALWAYS* use the installed system's
214+ // SkuSiPolicy.p7b instead of the host system's, even if the latter might be more recent, on
215+ // account that the bootloaders from the installed system might be trailing behind, and wills
216+ // produce the 0xc0000428 signature validation error on (re)boot if the system hasn't gone
217+ // through a full Windows Update cycle.
218+ if (flags & UNATTEND_APPLY_SKUSIPOLICY ) {
219+ StrArrayAdd (& first_logon_commands , "cmd /c mountvol S: /S && "
220+ "copy %WINDIR%\\system32\\SecureBootUpdates\\SkuSiPolicy.p7b S:\\EFI\\Microsoft\\Boot && "
221+ "mountvol S: /D" , TRUE);
222+ }
223+
224+ // Now that we have all the commands to run, create the FirstLogonCommands section.
225+ for (order = 1 ; order <= (int )first_logon_commands .Index ; order ++ ) {
226+ if (order == 1 )
227+ fprintf (fd , " <FirstLogonCommands>\n" );
228+ fprintf (fd , " <SynchronousCommand wcm:action=\"add\">\n" );
229+ fprintf (fd , " <Order>%d</Order>\n" , order );
230+ fprintf (fd , " <CommandLine>%s</CommandLine>\n" , first_logon_commands .String [order - 1 ]);
231+ fprintf (fd , " </SynchronousCommand>\n" );
232+ if (order == first_logon_commands .Index )
233+ fprintf (fd , " </FirstLogonCommands>\n" );
234+ }
235+ StrArrayDestroy (& first_logon_commands );
236+
217237 fprintf (fd , " </component>\n" );
218238 }
219239 if (flags & UNATTEND_OOBE_INTERNATIONAL_MASK ) {
@@ -510,31 +530,6 @@ BOOL PopulateWindowsVersion(void)
510530 return ((img_report .win_version .major != 0 ) && (img_report .win_version .build != 0 ));
511531}
512532
513- // Copy this system's SkuSiPolicy.p7b to the target drive so that UEFI bootloaders
514- // revoked by Windows through WDAC policy do get flagged as revoked.
515- BOOL CopySKUSiPolicy (const char * drive_name )
516- {
517- BOOL r = FALSE;
518- char src [MAX_PATH ], dst [MAX_PATH ];
519- struct __stat64 stat64 = { 0 };
520-
521- // Only copy SkuPolicy if we warned about the bootloader being revoked.
522- if ((target_type != TT_UEFI ) || !IS_WINDOWS_1X (img_report ) ||
523- (pe256ssp_size == 0 ) || !is_bootloader_revoked )
524- return r ;
525-
526- static_sprintf (src , "%s\\SecureBootUpdates\\SKUSiPolicy.p7b" , system_dir );
527- static_sprintf (dst , "%s\\EFI\\Microsoft\\Boot\\SKUSiPolicy.p7b" , drive_name );
528- if ((_stat64U (dst , & stat64 ) != 0 ) && (_stat64U (src , & stat64 ) == 0 )) {
529- uprintf ("Copying: %s (%s) (from %s)" , dst , SizeToHumanReadable (stat64 .st_size , FALSE, FALSE), src );
530- r = CopyFileU (src , dst , TRUE);
531- if (!r )
532- uprintf (" Error writing file: %s" , WindowsErrorString ());
533- }
534-
535- return r ;
536- }
537-
538533/// <summary>
539534/// Checks which versions of Windows are available in an install image
540535/// to set our extraction index. Asks the user to select one if needed.
@@ -739,8 +734,6 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp)
739734 ErrorStatus = RUFUS_ERROR (APPERR (ERROR_ISO_EXTRACT ));
740735 }
741736
742- CopySKUSiPolicy ((use_esp ) ? ms_efi : drive_name );
743-
744737 UpdateProgressWithInfo (OP_FILE_COPY , MSG_267 , 99 , 100 );
745738
746739 // Setting internal drives offline for Windows To Go is crucial if, for instance, you are using ReFS
0 commit comments