Running Powershell script within Powershell 'silently' - powershell

My setup:
One Powershell script with a menu. Upon selecting a a menu item, a specific Powershell script is run assigned to that menu item.
I'm attempting to make this second Powershell script run silently as in - nothing is shown in the main Powershell script.
Bonus:
The full setup I'm looking at is:
User runs Powershell script
User selects a menu item (this executes another Powershell script)
The information in the other Powershell script is not shown to the user
After the second Powershell script has been executed, the user is shown a line of text such as: "Script has been run successfully"
What I've tried:
Adding the following code to each secondary 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)
Unfortunately this closes the main Powershell window which isn't what I desire.

You could run the secondary command as a background-job and wait for it to finish. That way no output is shown in the shell
Start-Job -FilePath YourSecondaryScript.ps1 | Wait-Job
if you need, you can still analyze the job result (the script output)

Fixed by appending
| out-null
at the end of each line of code in the secondary scripts.

Related

Run command on powershell launch using pwd variable

When you're in file explorer you can click on File > Open Windows Powershell(or its icon in the Quick Access Toolbar) to start an instance of Powershell in the directory that your file explorer is in. I would like to then automatically run a simple command in this directory and close the Powershell window after it is done.
I have tried adding my command to my Powershell Profile but it executes before the path variable has been set and it runs with $pwd being equal to C:\Users\MyUsername (my home directory) or C:\WINDOWS\system32 (seems to be a race condition of some sort, no idea why it does one or the other). To the best of my understanding this is because the file explorer "open in powershell button" opens powershell and THEN cd's to the directory I was in in file explorer. So when the profile.ps1 is ran it is using the only directories it knows if since the cd call hasn't been made yet. This is similar to running the command start powershell.exe in cmd vs start powershell.exe -command "cd 'C:\wherever'". The former correctly runs my profile command while the latter uses the current directory of cmd and not the C:\wherever.
So, obviously the $pwd variable is being assigned at different times in the case of opening it from cmd and opening it from file explorer. Is there some way to delay the execution of a command in the profile until after the shell has fully loaded? Simply sleeping the script doesn't help.
Alternatively, if anyone knows how to edit the registry so that I can change the behavior of clicking File > Open Windows Powershell (since it must have access to some variable storing the current directory and I assume it calls the Powershell executable with this variable as an argument being cd'd to), that would work too.
Then again I could be incredibly naive about how File > Open Windows Powershell and the Powershell instantiation process works.
Any help is greatly appreciated, thank you!
I figured it out in the most hacky, gross way ever, but without easy access to Windows internals this is the only working method I could find. I set up my powershell profile to make my window title my prompt like so:
function Prompt
{
$host.ui.RawUI.WindowTitle = $(get-location)
“PS> “
}
Then I set up a task in the Task Scheduler that was triggered by powershell reaching its prompt (there are 3 possible hooks, when the console is starting up, when it starts an IPC listening thread, and when the console is ready for input). I used the Event Viewer to do this (I was going to post screenshots but I don't have 10 reputation yet).
Then, I set the action on this task to run the script shown below, which reads from the window title of my first instance of powershell
Start-Sleep -s 1
$A = Get-Process -Name powershell | Where-Object -FilterScript {$_.Id -ne $PID}
$B = $A.MainWindowTitle
& C:\Program` Files\MyProgram\MyProgram.exe "$B"
stop-process -Id $A.Id
stop-process -Id $PID
This whole menagerie of events properly runs my program with the current file explorer directory as an argument (and then closes powershell) when I click the little powershell icon on the quick access toolbar in file explorer.
Found a much cleaner and faster way to do this. All I had to do was set up my profile to look like this, no tasks or second instance of powershell required
function Prompt
{
& C:\Program` Files\MyProgram\MyProgram.exe "$pwd"
stop-process -Id $PID
}

Windows Task Scheduler Powershell get URL and download file

I am struggling with automating download of a file from website that opens a new tab when download is triggered and closes it right before the prompt to Save/Open/Close comes up in the main window. The script itself works just fine when launched manually until I try it in Task Scheduler. It runs great until it snags on the download. I've included a code to capture the URL of the file that needs to be downloaded and then pass it to Invoke-WebRequest which works fine out of PowerShell ISE but doesn't return any results when launched from Task Scheduler. I've included the counter and test file creation into the code to see if contents of do-while execute at all, and all 10 attempts were recorded. It's the part that searches through active URLs that's not returning results when launched via Task Scheduler.
# >> Keep trying to capture the CSV download link
$i = 1
Do {
$i | Add-Content -Path "C:\userfolder\try.txt"
$urls = (New-Object -ComObject Shell.Application).Windows() |
Where-Object {$_.LocationUrl -like "https://sitename.com/ReportViewer*"} |
Where-Object {$_.LocationUrl}
$reportURL = #($urls)[0].LocationURL
$i ++
}
While ($reportURL -eq $NULL -and $i -le 10)
# >> Send download link to web request and save to file
Invoke-WebRequest -Uri $reportURL -OutFile "C:\userfolder\ProfileList.csv"
I have tried the Wscript.Shell AppActivate and SendKeys('%S') before but the AppActivate wouldn't work probably because the PowerShell console window was hijakcing focus when launched via Task Scheduler. The task is set to execute powershell.exe with Arguments: C:\userfolder\CPdownload.ps1 -RunType $true, - and Start in: C:\userfolder. Run: only when user is logged in and with highest privileges; configured for Windows Server 2012 R2.
I've also tried launching the shell script through batch file from Task Scheduler with exactly the same result.
Thanks in advance for any pointers.
Probably your task needs to be run in interactive mode. By default scheduled tasks are run in Session 0. You can schedule task for interactive mode with /IT parameter. Check the following link for more info
https://msdn.microsoft.com/en-us/library/bb736357(VS.85).aspx
Old post however besides changing the script to interactive mode (this fixes it) you can change the Powershell execution policy to unrestricted (Set-ExecutionPolicy -ExecutionPolicy Unrestricted) if you wish to run the script outside of interactive mode. Just thought I'd post as recently come across this myself.

Powershell script run from task scheduler unable to open word document

I am trying to use a powershell script to get the wordcount from a number of word files and then output that to a csv file. This works as expected when run from the powershell prompt, and works when called from the cmd prompt directly or from inside a perl script, however the script fails to work when called as a scheduled task.
This is not an ExecutionPolicy issue causing the script to not run at all. The script is running and produces some output, but when launched from task scheduler it is unable to open any word documents.
The relevant powershell code is below:
$folderpath = "C:\some\where\*"
$fileTypes = "*.docx"
$word = New-Object -ComObject word.application
$word.visible = $false
Get-ChildItem -path $folderpath -recurse -include $fileTypes |
foreach-object `
{
$path = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
try {
$doc = $word.documents.open($_.fullname, $confirmConversion, $readOnly, $addToRecent, $passwordDocument)
} catch {
"FROM CATCH UNABLE TO OPEN $($_.fullname)" >> $wordCountFile
}
if($doc) {
$wordCount = $doc.ComputeStatistics("wdStatisticWords")
"$($_.name), $wordCount" >> $wordCountFile
$doc.close([ref]$false)
} else {
"UNABLE TO OPEN $($_.fullname)" >> $wordCountFile
}
} #end Foreach-Object
$word.Quit()
(Note that alternative methods people cite for getting the word count from word documents do not actually return the correct count as this method does when it works.)
When run as a scheduled task (set to run with highest privileges and as an administrator user) using:
cmd /c start PowerShell.exe -NoLogo -NonInteractive -ExecutionPolicy Bypass -File "C:\path\to\script\CountsInWords.ps1"
or when run with a similar command from a perl script launched by a scheduled task (my normal use case) and in both cases the task is set to run with highest privileges the powershell script does not work correctly.
The catch block is apparently never reached, as the print statement never makes it to the file, however the $doc is always null.
Additionally, when started as a task the script leaves a word process open and using a 100% cpu for 1 thread which will eventually cripple my machine.
To summarise:
run script as human (no matter how many levels of indirection) -> works perfectly
run script from task (as administrator user) -> script runs but cannot access word documents, also unable to stop word process despite always hitting the $word.Quit line.
EDIT: With #TheMadTechnician's advice about office first time startup for a new user requiring some details: On further inspection, looking at the processes in task manager, I don't see the word processes unless I click on "show processes from all users", but then they show up, but have the user listed as me. How can a process be both explicitly listed as me, but count as another user?
Attempting to set $word.visible = $true in the script didn't actually make anything appear when launched from task scheduler, so I don't know either how to verify that it is waiting for input, or how to give it that input as the correct user to make it go away...
You may be able to follow the solution named at the question How to run a Windows 2008 task from the scheduler with "interact with desktop".
Summary: If you have 64-bit Windows: Create %SystemRoot%\SysWOW64\config\systemprofile\Desktop. If you have 32-bit Windows, create %SystemRoot%\system32\config\systemprofile\Desktop.

How do I run a PowerShell script when the computer starts?

I have a PowerShell script that monitors an image folder. I need to find a way to automatically run this script after the computer starts.
I already tried the following methods, but I couldn't get it working.
Use msconfig and add the PowerShell script to startup, but I cannot find the PowerShell script on that list.
Create a shortcut and drop it to startup folder. No luck.
%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -File "C:\Doc\Files\FileMonitor.ps1"
or
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -File "C:\Doc\Files\FileMonitor.ps1"
Here's my PowerShell script:
$folder = "C:\\Doc\\Files"
$dest = "C:\\Doc\\Files\\images"
$filter = "*.jpg"
$fsw = new-object System.IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubDirectories=$false
NotifyFilter = [System.IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
Start-Sleep -s 10
Move-Item -Path C:\Doc\Files\*.jpg C:\Doc\Files\images
}
I also tried to add a basic task using taskschd.msc. It is still not working.
Here's what I found, and maybe that will help to debug it.
If I open up a PowerShell window and run the script there, it works. But if I run it in a command prompt,
powershell.exe -File "C:\Doc\Files\FileMonitor.ps1"
It will not work. I am not sure it's a permission problem or something else.
BTW, I have PowerShell 3.0 installed, and if I type $host.version, it will show 3 there. But my powershell.exe seems like it is still v1.0.
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
I finally got my PowerShell script to run automatically on every startup. You will need to create two files: the first is the Powershell script (e.g. script.ps1) and the second is a .cmd file that will contain commands that will run on the command prompt (e.g. startup.cmd).
The second file is what needs to be executed when the computer starts up, and simply copy-pasting the .ps1 to the startup folder won't work, because that doesn't actually execute the script - it only opens the file with Notepad. You need to execute the .cmd which itself will execute the .ps1 using PowerShell. Ok, enough babbling and on to the steps:
Create your .ps1 script and place it in a folder. I put it on my desktop for simplicity. The path would look something like this:
%USERPROFILE%\Desktop\script.ps1
Create a .cmd file and place it in
%AppData%\Microsoft\Windows\Start Menu\Programs\Startup\startup.cmd
Doing this will execute the cmd file every time on startup. Here is a link of how to create a .cmd file if you need help.
Open the .cmd file with a text editor and enter the following lines:
PowerShell -Command "Set-ExecutionPolicy Unrestricted" >> "%TEMP%\StartupLog.txt" 2>&1
PowerShell %USERPROFILE%\Desktop\script.ps1 >> "%TEMP%\StartupLog.txt" 2>&1
This will do two things:
Set the Execution Policy of your PowerShell to Unrestricted. This is needed to run scripts or else PowerShell will not do it.
Use PowerShell to execute the .ps1 script found in the path specified.
This code is specifically for PowerShell v1.0. If you're running PowerShell v2.0 it might be a little different. In any case, check this source for the .cmd code.
Save the .cmd file
Now that you have your .ps1 and .cmd files in their respective paths and with the script for each, you are all set.
You could set it up as a Scheduled Task, and set the Task Trigger for "At Startup"
What I do is create a shortcut that I place in shell:startup.
The shortcut has the following:
Target: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\scripts\script.ps1"
(replacing scripts\scripts.ps1 with what you need)
Start In: C:\scripts
(replacing scripts with folder which has your script)
You could create a Scheduler Task that runs automatically on the start, even when the user is not logged in:
schtasks /create /tn "FileMonitor" /sc onstart /delay 0000:30 /rl highest /ru system /tr "powershell.exe -file C:\Doc\Files\FileMonitor.ps1"
Run this command once from a PowerShell as Admin and it will create a schedule task for you. You can list the task like this:
schtasks /Query /TN "FileMonitor" /V /FO List
or delete it
schtasks /Delete /TN "FileMonitor"
This is really just an expansion on #mjolinor simple answer [Use Task Scheduler].
I knew "Task Scheduler" was the correct way, but it took a bit of effort to get it running the way I wanted and thought I'd post my finding for others.
Issues including:
Redirecting output to logs
Hiding the PowerShell window
Note: You must have permission to run script see ExecutionPolicy
Then in Task Scheduler, the most important/tricky part is the Action
It should be Start a Program
Program/Script:
powershell
Add arguments (optional) :
-windowstyle hidden -command full\path\script.ps1 >> "%TEMP%\StartupLog.txt" 2>&1
Note:
If you see -File on the internet, it will work, but understand nothing can be after -File except the File Path, IE: The redirect is taken to be part of the file path and it fails, you must use -command in conjunction with redirect, but you can prepend additional commands/arguments such as -windowstyle hidden to not show PowerShell window.
I had to adjust all Write-Host to Write-Output in my script as well.
Try this: create a shortcut in startup folder and input
PowerShell "& 'PathToFile\script.ps1'"
This is the easiest way.
Prerequisite:
1. Start powershell with the "Run as Administrator" option
2. Enable running unsigned scripts with:
set-executionpolicy remotesigned
3. prepare your powershell script and know its path:
$path = "C:\Users\myname\myscript.ps1"
Steps:
1. setup a trigger, see also New-JobTrigger (PSScheduledJob) - PowerShell | Microsoft Docs
$trigger = New-JobTrigger -AtStartup -RandomDelay 00:00:30
2. register a scheduled job, see also Register-ScheduledJob (PSScheduledJob) - PowerShell | Microsoft Docs
Register-ScheduledJob -Trigger $trigger -FilePath $path -Name MyScheduledJob
you can check it with Get-ScheduledJob -Name MyScheduledJob
3. Reboot Windows (restart /r) and check the result with:
Get-Job -name MyScheduledJob
see also Get-Job (Microsoft.PowerShell.Core) - PowerShell | Microsoft Docs
References:
How to enable execution of PowerShell scripts? - Super User
Use PowerShell to Create Job that Runs at Startup | Scripting Blog
Copy ps1 into this folder, and create it if necessary. It will run at every start-up (before user logon occurs).
C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup
Also it can be done through GPEDIT.msc if available on your OS build (lower level OS maybe not).
Be sure, whenever you want PowerShell to run automatically / in the background / non-interactive, it’s a good idea to specify the parameters
-ExecutionPolicy Bypass to PowerShell.exe
PowerShell.exe -ExecutionPolicy Bypass
I have a script that starts a file system watcher as well, but once the script window is closed the watcher dies. It will run all day if I start it from a powershell window and leave it open, but the minute I close it the script stops doing what it is supposed to.
You need to start the script and have it keep powershell open.
I tried numerous ways to do this, but the one that actually worked was from http://www.methos-it.com/blogs/keep-your-powershell-script-open-when-executed
param ( $Show )
if ( !$Show )
{
PowerShell -NoExit -File $MyInvocation.MyCommand.Path 1
return
}
Pasting that to the top of the script is what made it work.
I start the script from command line with
powershell.exe -noexit -command "& \path\to\script.ps1"
A relatively short path to specifying a Powershell script to execute at startup in Windows could be:
Click the Windows-button (Windows-button + r)
Enter this:
shell:startup
Create a new shortcut by rightclick and in context menu choose menu item: New=>Shortcut
Create a shortcut to your script, e.g:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "C:\Users\someuser\Documents\WindowsPowerShell\Scripts\somesscript.ps1"
Note the use of -NoProfile
In case you put a lot of initializing in your $profile file, it is inefficient to load this up to just run a Powershell script. The -NoProfile will skip loading your profile file and is smart to specify, if it is not necessary to run it before the Powershell script is to be executed.
Here you see such a shortcut created (.lnk file with a Powershell icon with shortcut glyph):
This worked for me. Created a Scheduled task with below details:
Trigger : At startup
Actions:
Program/script : powershell.exe
Arguments : -file
You can see scripts and more scheduled for startup inside Task Manager in the Startup tab. Here is how to add a new item to the scheduled startup items.
First, open up explorer to shell:startup location via start-button => run:
explorer shell:startup
Right click in that folder and in the context menu select a new shortcut. Enter the following:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile
-Command "C:\myfolder\somescript.ps1"
This will startup a Powershell script without starting up your $profile scripts for faster execution. This will make sure that the powershell script is started up.
The shell:startup folder is in:
$env:APPDATA\Microsoft\Windows
And then into the folder:
Start Menu\Programs\Startup
As usual, Microsoft makes things a bit cumbersome for us when a path contains spaces, so you have to put quotes around the full path or just hit tab inside Powershell to autocomplete in this case.
If you do not want to worry about execution policy, you can use the following and put into a batch script. I use this a lot when having techs at sites run my scripts since half the time they say script didnt work but really it's cause execution policy was undefined our restricted. This will run script even if execution policy would normally block a script to run.
If you want it to run at startup. Then you can place in either shell:startup for a single user or shell:common startup for all users who log into the PC.
cmd.exe /c Powershell.exe -ExecutionPolicy ByPass -File "c:\path\to\script.ps1"
Obviously, making a GPO is your best method if you have a domain and place in Scripts (Startup/Shutdown); under either Computer or User Configurations\Windows Settings\Scripts (Startup/Shutdown).
If you go that way make a directory called Startup or something under **
\\yourdomain.com\netlogon\
and put it there to reference in the GPO. This way you know the DC has rights to execute it. When you browse for the script on the DC you will find it under
C:\Windows\SYSVOL\domain\scripts\Startup\
since this is the local path of netlogon.
Execute PowerShell command below to run the PowerShell script .ps1 through the task scheduler at user login.
Register-ScheduledTask -TaskName "SOME TASKNAME" -Trigger (New-ScheduledTaskTrigger -AtLogon) -Action (New-ScheduledTaskAction -Execute "${Env:WinDir}\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument "-WindowStyle Hidden -Command `"& 'C:\PATH\TO\FILE.ps1'`"") -RunLevel Highest -Force;
-AtLogOn - indicates that a trigger starts a task when a user logs on.
-AtStartup - indicates that a trigger starts a task when the system is started.
-WindowStyle Hidden - don't show PowerShell window at startup. Remove if not required.
-RunLevel Highest - run PowerShell as administrator. Remove if not required.
P.S.
If necessary execute PowerShell command below to enable PowerShell scripts execution.
Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy Unrestricted -Force;
Bypass - nothing is blocked and there are no warnings or prompts.
Unrestricted - loads all configuration files and runs all scripts. If you run an unsigned script that was downloaded from the internet, you're prompted for permission before it runs.
I 'm aware that people around here don't need a tool like this. But I think it will be useful especially for novice users. Auto start tool It is a Portable freeware which designed to simplify the process to automatically launch an App or script when you login to Windows. It offers 3 different options for autostart
Task Scheduler
Startup folder
Registry run key
The best part of the tool is supports powershell scripts (.Ps1) . this means that you can run a Powershell script automatically at system startup with all 3 methods.
Download
https://disk.yandex.com.tr/d/dFzyB2Fu4lC-Ww
Source:
https://www.portablefreeware.com/forums/viewtopic.php?f=4&t=25761
One thing I found. if you are using Write-Host within your PowerShell scripts, and are also using Task Scheduler (as shown in the posts above), you don't get all the output from the command line.
powershell.exe -command C:\scripts\script.ps1 >> "C:\scripts\logfile.log"
In my case, I was only seeing output from commands that ran successfully from the PowerShell script.
My conclusion so far is PowerShell uses Out-File to output to another command or in this case a log file.
So if you use *> instead of >> you get all the output from the CLI for your PowerShell script, and you can keep using Write-Host within your script.
powershell.exe -command C:\scripts\script.ps1 *> "C:\scripts\logfile.log"
https://lazyadmin.nl/powershell/output-to-file/
You can also run the script in the background, regardless of user login.
Within your task in Task Scheduler set "Run whether user is logged on or not", and then in the password prompt type your hostname\username then your password (In my case an account with Admin permissions).
I used Set-ExecutionPolicy RemoteSigned -Scope CurrentUser to get around the script execution problem. I still would have preferred to run it on a per-process basis though. A problem for another time.

Hide or Minimize the powershell prompt after Winform Launch

I have written a simple powershell script to launch a winform(Winform code written within powershell script for example showContent.ps1 file) & showing some content.
I need to hide the powershell.exe command prompt after the launch of the Winform.
After searching some cases in web, I tried below Scenario:
1)I tried to execute "powershell.exe -Command -windowstyle Hidden" in the start of the script file "showContent.ps1"
2) Created a new script file exa:LaunchWinForm.ps1 and in that mentioned the command as:
PowerShell.exe -windowstyle Hidden showContent.ps1
It is not working.
I am using Powershell 3.0
Could anyone tell what is going wrong or suggest any way to do it.
In the new separate script file you created, try this:
powershell.exe -WindowStyle Hidden -File "c:\path\to the\GUI_Script.ps1"
This solution Minimizes Powershell window after it starts. Powershell window opens, then disapears, without using any outside code. I put at beginning of my scripts, but sounds like you want to put the code after you open your form.
$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)