Run scheduled tasks with WinForm GUI in PowerShell

Shortly after you started using PowerShell regularly you will probably feel that some kinds of tasks could be done automatically, after a certain period of time during your session. That means that you will go for task scheduling. However, there is a catch in case you would like to interac with the user. But let's go step by step.

Running PS command from command line

First we need to know how to run powershell tasks from windows command line. The path to PowerShell console is present in $env:path variable, so the system knows what application to launch. Ok, how do we specify the command to execute? Just type powershell -command "write-host test" and you will see the results.

C:\>powershell -command "write-host test" test C:\>
In case you don't want to execute your custom profile (located at $profile path), specify -NoProfile parameter as well.

After that we can schedule the test task:

C:\>schtasks /Create /SC MINUTE /TN schtest /TR "powershell -command 'get-date | add-content c:\temp\test.txt'"

Hide the console window

Everything is running as expected, however after several minutes you start being a little bit nervous because of the window that appears every minute. Wouldn't it be great to have the window hidden? After some searching I found a solution. Therefore we have to create a vbs file that will contain:
Dim objShell
Set objShell=CreateObject("WScript.Shell")
strExpression="get-date | add-content c:\temp\test.txt"
strCMD="powershell -sta -noProfile -NonInteractive  -nologo -command " & Chr(34) &_
"&{" & strExpression &"}" & Chr(34) 
objShell.Run strCMD,0
The magic is in the last row where number 0 says that the console window should be hidden. The script is then scheduled in this way:
C:\>schtasks /Create /SC MINUTE /TN schtest /TR "wscript c:\test.vbs"

And what happens if you use WinForms?

The previous method works for scripts that doesn't show any outputs. Just running in the background is enough. However when I needed to show a WinForm with some information, it didn't work. Nothing appeared. The only solution I was given in the discussions was to create a simple program in C# - application that creates PowerShell runspace and executes the script in the runspace. The code looks like the following:

using System; using System.Management.Automation.Runspaces; using System.Windows.Forms; namespace PowershellRunner { static class Program { [STAThread] static void Main(string[] args) { try { if (args == null || args.Length != 1) throw new ApplicationException("Empty argument list"); Runspace runspace = RunspaceFactory.CreateRunspace(); runspace.Open(); Pipeline pipeline = runspace.CreatePipeline(); pipeline.Commands.AddScript(args[0]); pipeline.Invoke(); } catch(Exception e) { MessageBox.Show(e.Message); } } } }
If you create a new project from scratch, select Windows application (not Console) and delete the default form files. To compile the code you will need to download PowerShell SDK and reference System.Management.Automation assembly.

Then after compiling the code above you can compare how the two approaches run:

C:\>powershell "Add-Type –a; $form = new-object Windows.Forms.Form; [void]$form.showdialog()"
C:\>PSRun.exe "Add-Type –a; $form = new-object Windows.Forms.Form; [void]$form.showdialog()"
You can see, that the PSRun doesn't show any command line window. So, we are done!

Last catch

There is only one disadvantage: I don't know why, but your custom profile (located at $profile) is not loaded in PSRun runspace. Even variable $profile is not defined. To bypass that you have to load the profile by handthe first:

C:\>PSRun.exe ". c:\users\....\..._profile.ps1; ..."

Meta: 2008-09-22, Pepa