4.1.7 - Show-ADTInstallationRestartPrompt - Restart function not working from Intune

Hi there folks, long time reader, first time poster.

The context:
I am currently deploying a set of configuration changes leveraging PSADT so that I can make the changes in SYSTEM context and display the UI to prompt the user for restart. My environment requires quite a bit of handholding and protection for users and this graceful countdown and notice to the user is really nice to have.

I did the initial development and testing using PsExec for the execution, as recommended in many places on this forum. All my tests worked flawlessly, the configuration steps work without issue. The restart prompt shows up as expected and I can wait out the timer or restart right away.

The Issue:
When I wrap this app and deploy it through Intune everything works except the restart functionality, and when I say that, I mean literally just the restart button/restart function trigger when the countdown is done. The prompt disappears and the device does not reboot.

Here's how the restart prompt is being called in my script. Nothing fancy.

Show-ADTInstallationRestartPrompt -CountdownSeconds 4500 -CountdownNoHideSeconds 600 -WindowLocation BottomRight

I checked via:

shutdown -a

Just to validate if there was a shutdown or reboot that could be aborted but there wasn't any.

Here's what I found in the Event Viewer under the Application log.

Application: PSADT.ClientServer.Client.exe
Framework Version: v4.0.30319
Description: The application requested process termination through System.Environment.FailFast(string message).
Message: An unexpected exception occurred with HRESULT [-2147024894].
Exception Info: System.IO.FileNotFoundException: Could not load file or assembly 'System.Memory, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.
File name: 'System.Memory, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'
   at PSADT.ProcessManagement.ProcessManager.LaunchAsync(ProcessLaunchInfo launchInfo)
   at PSADT.DeviceManagement.DeviceUtilities.RestartComputer()
   at PSADT.UserInterface.Dialogs.Fluent.RestartDialog.ButtonLeft_Click(Object sender, RoutedEventArgs e)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Button.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
   at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
   at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Window.ShowHelper(Object booleanBox)
   at System.Windows.Window.ShowDialog()
   at PSADT.UserInterface.Dialogs.Fluent.FluentDialog.ShowDialog()
   at PSADT.UserInterface.DialogManager.<>c__DisplayClass8_0`1.<ShowModalDialog>b__0()
   at System.Windows.Threading.DispatcherOperation`1.InvokeDelegateCore()
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Windows.Threading.DispatcherOperation.Wait(TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherOperation operation, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.Invoke[TResult](Func`1 callback, DispatcherPriority priority, CancellationToken cancellationToken, TimeSpan timeout)
   at System.Windows.Threading.Dispatcher.Invoke[TResult](Func`1 callback)
   at PSADT.UserInterface.DialogManager.InvokeDialogAction[TResult](Func`1 callback)
   at PSADT.ClientServer.ClientExecutable.ShowModalDialog(IReadOnlyDictionary`2 arguments, BaseState closeAppsDialogState, String[] argv)
   at PSADT.ClientServer.ClientExecutable.Main(String[] argv)

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

Stack:
   at System.Environment.FailFast(System.String, System.Exception)
   at PSADT.ClientServer.ClientExecutable.Main(System.String[])

Any ideas?

Kindly,
Nik

Pretty bizarre error... Can you confirm you packaged up all files and didn't try to strip anything out of the module?

It has not been stripped down or modified in any way. I generated a clean template using the template command.

New-ADTTemplate

I checked the content of the Intune IMECache to ensure the whole set of files is there, I compared it using Beyond Compare to my original set of files and there are no differences.

The only things I did were add a few functions in the extensions file, change the icon, the accent colors for the dialog via the config.psd1 file, as well as some string tweaks in the strings.psd1 file.

Here's what I figured out:
If I allow the countdown to elapse to 0 this popup appears.

Upon further investigation it seems that the files that the ClientServer.Client.exe is running from (the GUID in the IMECache) aren't present when the restart request is invoked.

Seems like the cached files are removed by something before the deployment finishes which results in the

Exception Info: System.IO.FileNotFoundException:

This doesn't seem to be rooted in the actual Toolkit itself, more so the way Intune cleans up the cache. I have the timeouts set to 120 minutes on my application deployment in Intune and my restart countdown is for only 75 minutes, I don't see why the management extension would delete the cache if the Restart prompt is still running.

Any ideas?

So I've been able to pinpoint it. The restart prompt starts asynchronously and the

Close-ADTSession

Closes the PowerShell process and provides the exit code to IME (Intune management extension). Then, because the detection is satisfied, IME cleans up the cache files causing all the issues I was experiencing.

So, the restart prompt functionality seems to not be well suited for Intune deployment if the detection is satisfied immediately. I imagine the way I could work around it is by creating some sort of RunOnce key or a pending file operation to delete a file created by the script to flag reboot as completed to make my detection work better. I've not attempted either of these but thought I'd share.

I've been able to very crudely delay the process termination by delaying the closing out of the script by adding the restart prompt outside of the very last

Try {...} Catch {...}

Block as indicated in another post as a work around for automating the interactive/silent restart prompting without relying or being affected by the ADT session, and by adding a

Start-Sleep

Immediately after the restart prompt with a duration that exceeds the maximum of the restart prompt.

As an afterthought, based on my experience, I don't see how anyone could take advantage of the restart prompt effectively with the way IME clear cache functionality appears to behave whilst returning a [0] exit code and the detection being satisfied before the device restart.

This isn't meant to be negative or a criticism in any way. If you think I'm overthinking it, am missing something super obvious, or if this all sounds about right please feel free to chime in.

Kindly,
Nik

Great & Deep analyze ! Hope they will release a fix !

I know! I've never seen troubleshooting like this in this forum.

@cantsleep I'm definitely appreciative of the deep diagnosis! It's not obvious, but we are tracking this on our GitHub via:

We should have this addressed for 4.2.0 so there's no need to sleep the main thread waiting clumsily for the async reboot prompt to come up.

@mjr4077au That's awesome. Thanks for looking through my thoughts and showing this GitHub feature to everyone's attention here on the forum. This toolkit just keeps getting better!

You guys rock.

I've re-opened and marked your response as the true solution to this thread.

Kindly,
Nik