Solution for running scheduled task with 'run whether user is logged on or not' option as an AAD user?


3 min read

Recently I've noticed that it is not possible to run a scheduled task as an Azure AD user (AAD) with the enabled option 'run whether user is logged on or not'. No matter if you also enable 'do not store password...' option.

The only way how you can run scheduled task as AAD user is (as far as I know) to choose the option 'run only when user is logged on'. image.png

This has two caveats though:

  • the task is run interactively
  • the task is obviously run only when the user is logged on ๐Ÿ˜

An obvious solution to the first part could be (in the case of running a PowerShell script) to call it using -windowStyle hidden parameter. But the PowerShell console still flashes for a brief time and moreover, you will lose the previous window focus. Which is super annoying.

The solution to this matter is the old-known use of wscript.exe inside a VBS script which will then start your original PowerShell script. WScript.exe allows you to completely hide the running window ๐Ÿ‘

Therefore instead of calling your ps1 script directly: image.png

Call VBS script with the path to your ps1 script as an argument: image.png

Content of the run_hidden.vbs script:

set WshShell = WScript.CreateObject("WScript.Shell")

' regex to distinguish ps1 scripts
Set runPs1 = New RegExp
With runPs1
.Pattern    = "\.ps1$"
.IgnoreCase = True
.Global     = False
End With
' regex to distinguish base64
set runBase64 = New RegExp
With runBase64
.Pattern    = "^psbase64:"
.IgnoreCase = True
.Global     = False
End With

If Wscript.Arguments.Count < 1 Or Wscript.Arguments.Count > 2 Then
wscript.echo "ERROR, you have to enter one or two argument(s)! First has to be the path to cmd file to run and voluntarily second one as CMDs file argument"
ElseIf Wscript.Arguments.Count = 1 Then
If runPs1.Test( WScript.Arguments(0) ) Then
' it is ps1 script
        WshShell.Run "cmd /c powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File" & " " & """" & WScript.Arguments(0) & """", 0, True
    ElseIf runBase64.Test( WScript.Arguments(0) ) Then
        ' It is base64 string
'remove part before : from passed string to get just base64
        base64 = WScript.Arguments(0)
        base64 = Mid(base64,instr(base64,":")+1)
        WshShell.Run "cmd /c powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -EncodedCommand" & " " & """" & base64 & """", 0, True
        ' It is something else
WshShell.Run """" & WScript.Arguments(0) & """", 0, True
End If
ElseIf Wscript.Arguments.Count = 2 Then
'wscript.echo WScript.Arguments(0)
'wscript.echo WScript.Arguments(1)
If runPs1.Test( WScript.Arguments(0) ) Then
' it is ps1 script
        WshShell.Run "cmd /c powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File" & " " & """" & WScript.Arguments(0) & """" & " " & """" & WScript.Arguments(1) & """", 0, True
        ' It isn't ps1 script
        WshShell.Run """" & WScript.Arguments(0) & """" & """" & WScript.Arguments(1) & """", 0, True
    End If
End If

Set WshShell = Nothing

Beware that you have to save the VBS script as a UTF8 encoded file!

Did you find this article valuable?

Support Ondrej Sebela by becoming a sponsor. Any amount is appreciated!