How is it possible to run a PowerShell script without displaying a window or any other sign to the user?
In other words, the script should run quietly in the background without any sign to the user.
Extra credit for an answer that does not use third party components :)
You can either run it like this (but this shows a windows for a while):
PowerShell.exe -windowstyle hidden { your script.. }
Or you use a helper file I created to avoid the window called PsRun.exe that does exactly that. You can download source and exe file Run scheduled tasks with WinForm GUI in PowerShell. I use it for scheduled tasks.
Edited: as Marco noted this -windowstyle parameter is available only for V2.
I was having this same issue. I found out if you go to the Task in Task Scheduler that is running the powershell.exe script, you can click "Run whether user is logged on or not" and that will never show the powershell window when the task runs.
You can use the PowerShell Community Extensions and do this:
start-process PowerShell.exe -arg $pwdfoo.ps1 -WindowStyle Hidden
You can also do this with VBScript: http://blog.sapien.com/index.php/2006/12/26/more-fun-with-scheduled-powershell/
Schedule Hidden PowerShell Tasks (Internet Archive)
More fun with scheduled PowerShell (Internet Archive)
(Via this forum thread.)
Here's an approach that that doesn't require command line args or a separate launcher. It's not completely invisible because a window does show momentarily at startup. But it then quickly vanishes. Where that's OK, this is, I think, the easiest approach if you want to launch your script by double-clicking in explorer, or via a Start menu shortcut (including, of course the Startup submenu). And I like that it's part of the code of the script itself, not something external.
Put this at the front of your script:
$t = '[DllImport("user32.dll")] public static extern bool ShowWindow(int handle, int state);'
add-type -name win -member $t -namespace native
[native.win]::ShowWindow(([System.Diagnostics.Process]::GetCurrentProcess() | Get-Process).MainWindowHandle, 0)
Here's a one-liner:
mshta vbscript:Execute("CreateObject(""Wscript.Shell"").Run ""powershell -NoLogo -Command """"& 'C:Example Path That Has SpacesMy Script.ps1'"""""", 0 : window.close")
Although it's possible for this to flash a window very briefly, that should be a rare occurrence.
ps1 hidden from the Task Scheduler and shortcut too
mshta vbscript:Execute("CreateObject(""WScript.Shell"").Run ""powershell -ExecutionPolicy Bypass & 'C:PATHNAME.ps1'"", 0:close")
The answer with -WindowStyle Hidden
is great but the windows will still flash.
I've never seen a window flash when calling it via cmd /c start /min ""
.
Your machine or setup may differ but it works well for me.
cmd /c start /min "" powershell -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:UsersusernameDesktop est.ps1"
cmd /c start /min "" powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command ". 'C:UsersusernameDesktop est.ps1'; -Arg1 'Hello' -Arg2 ' World'"
cmd /c start /min "" powershell -WindowStyle Hidden -ExecutionPolicy Bypass -Command ". 'C:UsersusernameDesktop est.ps1'; Get-Test -stringTest 'Hello World'"
Powershell content for 3. Call a file with a function and arguments is:
function Get-Test() {
[cmdletbinding()]
Param
(
[Parameter(Mandatory = $true, HelpMessage = 'The test string.')]
[String]$stringTest
)
Write-Host $stringTest
return
}
In case you need to run this in Task Scheduler then call %comspec%
as the Program/Script and then code for calling the file above as the argument.
I think that the best way to hide the console screen of the PowerShell when your are running a background scripts is this code ("Bluecakes" answer).
I add this code in the beginning of all my PowerShell scripts that I need to run in background.
# .Net methods for hiding/showing the console in the background
Add-Type -Name Window -Namespace Console -MemberDefinition '
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'
function Hide-Console
{
$consolePtr = [Console.Window]::GetConsoleWindow()
#0 hide
[Console.Window]::ShowWindow($consolePtr, 0)
}
Hide-Console
If this answer was help you, please vote to "Bluecakes" in his answer in this post.
I was having this problem when running from c#, on Windows 7, the "Interactive Services Detection" service was popping up when running a hidden powershell window as the SYSTEM account.
Using the "CreateNoWindow" parameter prevented the ISD service popping up it's warning.
process.StartInfo = new ProcessStartInfo("powershell.exe",
String.Format(@" -NoProfile -ExecutionPolicy unrestricted -encodedCommand ""{0}""",encodedCommand))
{
WorkingDirectory = executablePath,
UseShellExecute = false,
CreateNoWindow = true
};
Here's a fun demo of controlling the various states of the console, including minimize and hidden.
Add-Type -Name ConsoleUtils -Namespace WPIA -MemberDefinition @'
[DllImport("Kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);
'@
$ConsoleMode = @{
HIDDEN = 0;
NORMAL = 1;
MINIMIZED = 2;
MAXIMIZED = 3;
SHOW = 5
RESTORE = 9
}
$hWnd = [WPIA.ConsoleUtils]::GetConsoleWindow()
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.MAXIMIZED)
"maximized $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.NORMAL)
"normal $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.MINIMIZED)
"minimized $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.RESTORE)
"restore $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.HIDDEN)
"hidden $a"
Start-Sleep 2
$a = [WPIA.ConsoleUtils]::ShowWindow($hWnd, $ConsoleMode.SHOW)
"show $a"
I got really tired of going through answers only to find it did not work as expected.
Solution
Make a vbs script to run a hidden batch file which launches the powershell script. Seems silly to make 3 files for this task but atleast the total size is less than 2KB and it runs perfect from tasker or manually (you dont see anything).
scriptName.vbs
Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "C:UsersleathanDocumentsscriptName.bat" & Chr(34), 0
Set WinScriptHost = Nothing
scriptName.bat
powershell.exe -ExecutionPolicy Bypass C:UsersleathanDocumentsscriptName.ps1
scriptName.ps1
Your magical code here.
Create a shortcut that calls the PowerShell script and set the Run option to Minimized. This will prevent a window from flashing although you will still get a momentary blip of the script running on the Task Bar.
For easy command line usage, there is a simple wrapper app:
https://github.com/stax76/run-hidden
Example command line:
run-hidden powershell -command calc.exe
I have created a small tool passing the call to any console tool you want to start windowless through to the original file:
https://github.com/Vittel/RunHiddenConsole
After compiling just rename the executable to "<targetExecutableName>w.exe" (append a "w"), and put it next to the original executable. You can then call e.G. powershellw.exe with the usual parameters and it wont pop up a window.
If someone has an idea how to check whether the created process is waiting for input, ill be happy to include your solution :)
Here is a working solution in windows 10 that does not include any third-party components. It works by wrapping the PowerShell script into VBScript.
Step 1: we need to change some windows features to allow VBScript to run PowerShell and to open .ps1 files with PowerShell by default.
-go to run and type "regedit". Click on ok and then allow it to run.
-paste this path "HKEY_CLASSES_ROOTMicrosoft.PowerShellScript.1Shell" and press enter.
-now open the entry on the right and change the value to 0.
-open PowerShell as an administrator and type "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned", press enter and confirm the change with "y" and then enter.
Step 2: Now we can start wrapping our script.
-save your Powershell script as a .ps1 file.
-create a new text document and paste this script.
Dim objShell,objFSO,objFile
Set objShell=CreateObject("WScript.Shell")
Set objFSO=CreateObject("Scripting.FileSystemObject")
'enter the path for your PowerShell Script
strPath="c:your script pathscript.ps1"
'verify file exists
If objFSO.FileExists(strPath) Then
'return short path name
set objFile=objFSO.GetFile(strPath)
strCMD="powershell -nologo -command " & Chr(34) & "&{" &_
objFile.ShortPath & "}" & Chr(34)
'Uncomment next line for debugging
'WScript.Echo strCMD
'use 0 to hide window
objShell.Run strCMD,0
Else
'Display error message
WScript.Echo "Failed to find " & strPath
WScript.Quit
End If
-now change the file path to the location of your .ps1 script and save the text document.
-Now right-click on the file and go to rename. Then change the filename extension to .vbs and press enter and then click ok.
DONE! If you now open the .vbs you should see no console window while your script is running in the background.
make sure to upvote if this worked for you!
When you scheduled task, just select "Run whether user is logged on or not" under the "General" tab.
Alternate way is to let the task run as another user.
Wait until Powershell is executed and get the result in vbs
This is an improved version of the Omegastripes code Hide command prompt window when using Exec()
Splits the confused responses from cmd.exe into an array instead of putting everything into a hard-to-parse string.
In addition, if an error occurs during the execution of cmd.exe, a message about its occurrence will become known in vbs.
Option Explicit
Sub RunCScriptHidden()
strSignature = Left(CreateObject("Scriptlet.TypeLib").Guid, 38)
GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}").putProperty strSignature, Me
objShell.Run ("""" & Replace(LCase(WScript.FullName), "wscript", "cscript") & """ //nologo """ & WScript.ScriptFullName & """ ""/signature:" & strSignature & """"), 0, True
End Sub
Sub WshShellExecCmd()
For Each objWnd In CreateObject("Shell.Application").Windows
If IsObject(objWnd.getProperty(WScript.Arguments.Named("signature"))) Then Exit For
Next
Set objParent = objWnd.getProperty(WScript.Arguments.Named("signature"))
objWnd.Quit
'objParent.strRes = CreateObject("WScript.Shell").Exec(objParent.strCmd).StdOut.ReadAll() 'simple solution
Set exec = CreateObject("WScript.Shell").Exec(objParent.strCmd)
While exec.Status = WshRunning
WScript.Sleep 20
Wend
Dim err
If exec.ExitCode = WshFailed Then
err = exec.StdErr.ReadAll
Else
output = Split(exec.StdOut.ReadAll,Chr(10))
End If
If err="" Then
objParent.strRes = output(UBound(output)-1) 'array of results, you can: output(0) Join(output) - Usually needed is the last
Else
objParent.wowError = err
End If
WScript.Quit
End Sub
Const WshRunning = 0,WshFailed = 1:Dim i,name,objShell
Dim strCmd, strRes, objWnd, objParent, strSignature, wowError, output, exec
Set objShell = WScript.CreateObject("WScript.Shell"):wowError=False
strCmd = "C:WindowsSystem32WindowsPowerShellv1.0powershell.exe -ExecutionPolicy Bypass Write-Host Hello-World."
If WScript.Arguments.Named.Exists("signature") Then WshShellExecCmd
RunCScriptHidden
If wowError=False Then
objShell.popup(strRes)
Else
objShell.popup("Error=" & wowError)
End If
c="powershell.exe -ExecutionPolicy Bypass (New-Object -ComObject Wscript.Shell).popup('Hello World.',0,'ОК',64)"
s=Left(CreateObject("Scriptlet.TypeLib").Guid,38)
GetObject("new:{C08AFD90-F2A1-11D1-8455-00A0C91F3880}").putProperty s,Me
WScript.CreateObject("WScript.Shell").Run c,0,false
powershell.exe -windowstyle hidden -noexit -ExecutionPolicy Bypass -File <path_to_file>
then set the run: Minimized
should work as expected without added code for hidden window flash just slightly more delayed execution.