@@ -142,63 +142,101 @@ function Test-CanUpgrade {
142142 }
143143}
144144
145- function Write-SetupError ([ Bool ] $MaybeSuccess ) {
145+ function Write-SetupError {
146146 $RegPath = ' HKLM:\SYSTEM\Setup\setupdiag\results' ;
147- $Success = Get-RegistryKey $RegPath ' OperationCompletedSuccessfully' ;
148- if ($False -and $MaybeSuccess -and $Success -eq ' True' ) {
149- Invoke-Info ' Windows 11 upgrade completed successfully' ;
147+ $FailureData = Get-RegistryKey $RegPath ' FailureData' ;
148+ $FailureDetails = Get-RegistryKey $RegPath ' FailureDetails' ;
149+
150+ Invoke-Error " Windows 11 upgrade failed, see the details below:" ;
151+ Invoke-Error " Failure Data: $FailureData " ;
152+ Invoke-Error " Failure Details: $FailureDetails " ;
153+
154+ $ScanResultFile = " $env: SystemDrive \`$ WINDOWS.~BT\Sources\Panther\ScanResult.xml" ;
155+ if (Test-Path $ScanResultFile ) {
156+ Invoke-Verbose ' Checking for blocking drivers...' ;
157+
158+ $PnpDevices = Get-PnpDevice - PresentOnly;
159+ $PnpDeviceInfs = @ {};
160+ $PnpDevices | ForEach-Object {
161+ $InfPath = $_ | Get-PnpDeviceProperty - KeyName ' DEVPKEY_Device_DriverInfPath' ;
162+ $PnpDeviceInfs [$_.InstanceId ] = $InfPath.Data ;
163+ }
150164
165+ $DriverPackages = (Select-Xml - Path $ScanResultFile - XPath ' /*' ).Node.DriverPackages.DriverPackage;
166+ $DriverPackages | ForEach-Object {
167+ $Driver = $_ ;
168+ if ($Driver.BlockMigration -eq ' True' ) {
169+ $DriverName = $Driver.Inf ;
170+ $DriverDetails = Get-WindowsDriver - Online - Driver $DriverName ;
171+ $InUseByDevices = $PnpDevices | Where-Object {
172+ $PnpDeviceInfs [$_.InstanceId ] -eq $DriverName ;
173+ }
151174
152- $Local :Message = @"
153- Message from AMT
175+ Invoke-Error @"
176+ Driver: $DriverName is blocking the upgrade to Windows 11, see the details below:
177+ In Use By Devices: $ ( $InUseByDevices | Select-Object - ExpandProperty FriendlyName -Join ' , ' )
178+ Driver Details: $DriverDetails
179+ "@
180+ }
181+ }
182+ }
183+ }
154184
155- Your PC needs to restart to install Windows 11.
156- Please save your work and close all applications before proceeding.
185+ $Script :LogPhaseReader = @ {
186+ LastKnownPhase = ' Unknown' ;
187+ LastKnownPhaseTime = [DateTime ]::Now;
188+
189+ LinesRead = 0 ;
190+ ReadHandle = $null ;
191+ };
192+ function Get-CurrentUpgradePhase {
193+ $Path = " C:\`$ WINDOWS.~BT\Sources\Panther\setupact.log"
194+ $PrefixRegex = ' (^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}), Info\s+MOUPG\s+' ;
195+ $Regex1 = $PrefixRegex + ' Setup phase change: \[(.+?)\] -> \[(.+?)\]$' ;
196+ $Regex2 = $PrefixRegex + ' SetupManager::DetermineSetupPhase: CurrentSetupPhase \[(.+?)\]$' ;
197+
198+ # Approx 400k lines in total on a clean install.
199+
200+ if (-not (Test-Path $Path )) {
201+ return $null ; # Not started yet.
202+ }
157203
158- This will take place in 30 minutes at $ ( [DateTime ]::Now.AddMinutes(30 ).ToString(' hh:mm tt' )) or reboot immediately if you choose to do so.
159- "@ ;
204+ if ($null -eq $Script :LogPhaseReader.ReadHandle ) {
205+ $Script :LogPhaseReader.ReadHandle = [System.IO.StreamReader ]::new($Path );
206+ }
160207
161- $Local :Message | . msg * / TIME:3600 ;
162- } else {
163- $FailureData = Get-RegistryKey $RegPath ' FailureData' ;
164- $FailureDetails = Get-RegistryKey $RegPath ' FailureDetails' ;
165-
166- Invoke-Error " Windows 11 upgrade failed, see the details below:" ;
167- Invoke-Error " Failure Data: $FailureData " ;
168- Invoke-Error " Failure Details: $FailureDetails " ;
169-
170- # $ErrorCode = $FailureDetails | Select-String -Pattern 'ErrorCode = (0x\d+),' | ForEach-Object { $_.Matches.Groups[1].Value };
171- # $ScanResultFile = "$env:SystemDrive\`$WINDOWS.~BT\Sources\Panther\ScanResult.xml";
172- $ScanResultFile = " C:\Users\JamesDraycott\AppData\Local\Temp\ScanResult.xml" ;
173- if (Test-Path $ScanResultFile ) {
174- Invoke-Verbose ' Checking for blocking drivers...' ;
175-
176- $PnpDevices = Get-PnpDevice - PresentOnly;
177- $PnpDeviceInfs = @ {};
178- $PnpDevices | ForEach-Object {
179- $InfPath = $_ | Get-PnpDeviceProperty - KeyName ' DEVPKEY_Device_DriverInfPath' ;
180- $PnpDeviceInfs [$_.InstanceId ] = $InfPath.Data ;
181- }
208+ for ($i = $Script :LogPhaseReader.LinesRead ; $i -lt $LogPhaseReader.Handle.BaseStream.Length ) {
209+ $Line = $Script :LogPhaseReader.ReadHandle.ReadLine ();
210+ $Script :LogPhaseReader.LinesRead ++ ;
182211
183- $DriverPackages = (Select-Xml - Path $ScanResultFile - XPath ' /*' ).Node.DriverPackages.DriverPackage;
184- $DriverPackages | ForEach-Object {
185- $Driver = $_ ;
186- if ($Driver.BlockMigration -eq ' True' ) {
187- $DriverName = $Driver.Inf ;
188- $DriverDetails = Get-WindowsDriver - Online - Driver $DriverName ;
189- $InUseByDevices = $PnpDevices | Where-Object {
190- $PnpDeviceInfs [$_.InstanceId ] -eq $DriverName ;
191- }
192-
193- Invoke-Error @"
194- Driver: $DriverName is blocking the upgrade to Windows 11, see the details below:
195- In Use By Devices: $ ( $InUseByDevices | Select-Object - ExpandProperty FriendlyName -Join ' , ' )
196- Driver Details: $DriverDetails
197- "@
198- }
212+ # We know all the lines we care about are less than 140 characters long.
213+ if ($Line.Length -gt 140 ) {
214+ continue ;
215+ }
216+
217+ if ($Line -match $Regex1 ) {
218+ $Time = [DateTime ]::ParseExact($matches [1 ], " yyyy-MM-dd HH:mm:ss" , $null );
219+ $OldPhase = $matches [1 ];
220+ $NewPhase = $matches [2 ];
221+
222+ if ($NewPhase -ne $Script :LogPhaseReader.LastKnownPhase ) {
223+ Invoke-Info " Setup phase changed from $OldPhase to $NewPhase at $Time " ;
224+ $Script :LogPhaseReader.LastKnownPhase = $NewPhase ;
225+ $Script :LogPhaseReader.LastKnownPhaseTime = $Time ;
226+ }
227+ } elseif ($Line -match $Regex2 ) {
228+ $Time = [DateTime ]::ParseExact($matches [1 ], " yyyy-MM-dd HH:mm:ss" , $null );
229+ $NewPhase = $matches [2 ];
230+
231+ if ($NewPhase -ne $Script :LogPhaseReader.LastKnownPhase ) {
232+ Invoke-Info " Setup phase changed to $NewPhase at $Time " ;
233+ $Script :LogPhaseReader.LastKnownPhase = $NewPhase ;
234+ $Script :LogPhaseReader.LastKnownPhaseTime = $Time ;
199235 }
200236 }
201237 }
238+
239+ return $Script :LogPhaseReader.LastKnownPhase ;
202240}
203241
204242function Update-ToWin11 {
@@ -225,20 +263,42 @@ function Update-ToWin11 {
225263 $Status = Get-WindowsOptionalFeature - FeatureName $_ - Online;
226264 if ($Status.State -eq ' Enabled' -or $Status.State -eq ' EnablePending' ) {
227265 Invoke-Info " Disabling feature: $_ " ;
228- Disable-WindowsOptionalFeature - FeatureName $_ - Online;
266+ Disable-WindowsOptionalFeature - FeatureName $_ - Online - NoRestart ;
229267 }
230268 }
231269
232- # TODO - Maybe use the processes resource monitor to determine if its downloading, copying or what?
233- Start-Process - FilePath $Private :OutputFile - ArgumentList " /QuietInstall /SkipEULA /auto upgrade /UninstallUponUpgrade /copylogs $Private :Dir " - Wait;
270+ $UpgradeJob = Start-Job - ScriptBlock {
271+ Start-Process - FilePath $Using :OutputFile - ArgumentList " /QuietInstall" , " /SkipEULA" , " /auto" , " upgrade" , " /UninstallUponUpgrade" , " /copylogs $Using :Dir " - Wait;
272+ };
273+
274+ while ($UpgradeJob.Finished -eq $False ) {
275+ # TODO - This can probably find errors too.
276+ $CurrentPhase = Get-CurrentUpgradePhase ;
277+ if ($CurrentPhase -eq ' SetupPhasePostFinalize' ) {
278+ Invoke-Info ' Windows 11 upgrade is complete, notifying user & exiting...' ;
279+ $Local :Message = @"
280+ Message from AMT
281+
282+ Your PC needs to restart to install Windows 11.
283+ Please save your work and close all applications before proceeding.
284+
285+ This will take place in 30 minutes at $ ( [DateTime ]::Now.AddMinutes(30 ).ToString(' hh:mm tt' )) or reboot immediately if you choose to do so.
286+ "@ ;
287+
288+ $Local :Message | . msg * / TIME:3600 ;
289+
290+ return ;
291+ }
292+
293+ Start-Sleep - Seconds 5 ;
294+ }
234295
235- Write-SetupError $True ;
296+ Write-SetupError ;
236297 } catch {
237- Invoke-Error " There was an error upgrading to Windows 11, please check the logs for more information inside $Private :Dir " ;
238- Write-SetupError $False ;
298+ Write-SetupError ;
239299 $PSCmdlet.ThrowTerminatingError ($_ );
240300 }
241301 }
242302}
243303
244- Export-ModuleMember - Function ' Update-ToWin11' , ' Test-CanUpgrade' , ' Get-SupportedProcessor ' , ' Write-SetupError ' ;
304+ Export-ModuleMember - Function ' Update-ToWin11' , ' Test-CanUpgrade' ;
0 commit comments