Task scheduler Windows 10 - powershell

I guess this is easy but is eluding me, I have a working Powershell script that I wish to run as a Scheduled Task in Windows 10, however the script does not execute from the Task scheduler.
Script is hider.ps1
$fs = New-Object -ComObject scripting.filesystemobject
Get-ChildItem "D:\TV Shows\" -force | Where-Object {$_.psiscontainer} | ForEach-Object {
if($fs.getfolder($_.fullname).size -lt 20mb) {$_.attributes = "directory,hidden"}
else{$_.attributes = "directory"}
}
This hides empty folders in a directory
In Task scheduler I have put
Start a program Powershell
Arguments -ExecutionPolicy Bypass –File "F:\Xaved Files\Hider ps 1"

Have you set the "start in" directory???
Apparently, since windows server 2012, if a task doesn't have this field informed, the task doesn't run silently.
This worked in my case, and also to this guy

Related

Powershell Script won't run correctly in Task Scheduler

I recently created some PowerShell code that runs perfectly fine on its own or via a command prompt (or a .bat file). Hell, it runs fine as a .cmd file too. When I create a task scheduler task for it to run automatically, the result claims that the job runs 'successfully' but there isn't any output in the folder destination.
The whole goal of the script is to look at a particular subfolder within outlook and find files with a particular name. Then it outputs the latest related attachments to a specific destination.
PowerShell Script
$olFolderInbox = 6
$limit = (Get-Date).AddDays(-1)
$filepath = "C:\Scripts\attachment Project\Spreadsheets"
$ol = New-Object -com outlook.application;
$ns = $ol.GetNamespace("MAPI");
$acct = $ns.GetDefaultFolder($olFolderInbox)
$targetfolder = $acct.Folders | where-object { $_.name -eq "Training" }
$targetfolder.Items | foreach {
if ($_.ReceivedTime -ge $limit) {
$_.attachments |
foreach {
Write-Host "attached file: ",$_.filename
If ($_.filename -match 'SessionCompletions' -or $_.filename -match 'Certifications'){
$_.saveasfile((Join-Path $filepath $_.FileName))
$ol.quit()
}
}
}
}
I've tried all kinds of things to get the Task within Task Scheduler to work and nothing so far seems to help. To start I tried using a basic bat file to run the task. Mind you, this basic format has worked with many other PowerShell related tasks that I set up to run via a bat file.
Basic Bat Script
powershell -file extract-spreadsheets.ps1
Now sometimes I've needed to include an -executionpolicy argument as well but it sadly didn't work in this case.
A little more complex Script
Powershell.exe -executionpolicy RemoteSigned -File "C:\Scripts\attachment Project\extract spreadsheets.ps1"
Note: I made sure the get-executionpolicy on the computer was / is set to RemoteSigned. I've also tried Unrestricted as well.
I've also tried even more complex / different approaches such as . . .
Even more Complex of a Script
#ECHO OFF
SET ThisScriptsDirectory=C:\Scripts\David attachment Project\
SET PowerShellScriptPath=%ThisScriptsDirectory%extract-spreadsheets.ps1
PowerShell -NoProfile -ExecutionPolicy RemoteSigned -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy RemoteSigned -File ""%PowerShellScriptPath%""' -Verb RunAs}";
And I've even tried getting a .cmd file going and trying to use that within Task Scheduler:
##:: This prolog allows a PowerShell script to be embedded in a .CMD file.
##:: Any non-PowerShell content must be preceeded by "##"
##setlocal
##set POWERSHELL_BAT_ARGS=%*
##if defined POWERSHELL_BAT_ARGS set POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%
##PowerShell -Command Invoke-Expression $('$args=#(^&{$args} %POWERSHELL_BAT_ARGS%);'+[String]::Join(';',$((Get-Content '%~f0') -notmatch '^^##'))) & goto :EOF
$olFolderInbox = 6
$limit = (Get-Date).AddDays(-1)
$filepath = "C:\Scripts\attachment Project\Spreadsheets"
$ol = New-Object -com outlook.application;
$ns = $ol.GetNamespace("MAPI");
$acct = $ns.GetDefaultFolder($olFolderInbox)
$targetfolder = $acct.Folders | where-object { $_.name -eq "Training" }
$targetfolder.Items | foreach {
if ($_.ReceivedTime -ge $limit) {
$_.attachments |
foreach {
Write-Host "attached file: ",$_.filename
If ($_.filename -match 'SessionCompletions' -or $_.filename -match 'Certifications'){
$_.saveasfile((Join-Path $filepath $_.FileName))
$ol.quit()
}
}
}
}
In terms of Task Scheduler, I've tried a multitude of things. To start . . .
For Program / script, I tried various relative and explicit destinations / paths for bat, cmd and PowerShell.
Some examples:
Powershell.exe (again I've also done the full path as well)
C:\Scripts\attachment Project\Training_Reports.bat
Training_Reports.bat
C:\Scripts\attachment Project\extract-spreadsheets.cmd
Note: I've added the above Programs / Actions with and without quotes.
Again, the more frustrating thing is the basic format of Training_Reports.bat with the start in (optional) field of:
C:\Scripts\attachment Project or C:\Scripts\attachment Project\
Has worked with every other script / task I have set up in this format!
I've tried numerous arguments for Execution Policy such as RemoteSigned, Bypass and Unrestricted. I've Added other arguments like: -NoProfile, -noninteractive, -File, -command, -NoLogo etc etc.
Examples of what the Arguments Field has looked like within Task Scheduler:
-ExecutionPolicy Bypass -File "C:\Scripts\attachment Project\extract-spreadsheets.ps1"
-NoLogo -NonInteractive -ExecutionPolicy RemoteSigned -File "C:\Scripts\attachment Project\extract-spreadsheets.ps1"
-NoProfile -ExecutionPolicy Unrestricted -Command "C:\Scripts\attachment Project\extract-spreadsheets.ps1"
I tried using various accounts to 'run the task'.
my domain account (which my account is a global domain admin and has
full permissions)
local Admin account
another Domain Admin Account
I've tried even SYSTEM
None of the accounts above have changed the outcome. Other settings I've looked at that people claim could mess with Tasks.
Turned off 'Start the task only if the computer is on AC power'
Ran the task whether user is logged on or not
Also ran it as when user is logged on
Set it for 'Highest privileges'
I tried running the task in 'configure for' drop down menu for
Windows 10 and Windows 7 / Server 2008.
Other things I have tried:
The initial PowerShell Script had mapped drive destinations. I changed the code to use C drive locations.
Explicitly giving that user account full control over the
directories involved.
Changing ownership of the directories involved to the same user.
Changing the security permissions on the ps1, cmd, bat, outlook.exe files to always Run as Administrator.
Tried running the script with Outlook running and not running.
Note: running it manually works regardless if Outlook is running.
Why is this task within Task Scheduler not outputting correctly?

Write realtime powershell output during TFS release execution

In our company we use TFS 2017 (update 1) for building and releasing our products. The release part is made up of several steps which include the execution of some Powershell scripts.
This is how I configure the PS step.
What I noticed is that the output of the powershell scripts is not written realtime while it is executing, but all together in the end of the PS task. This is very annoying in case of long running scripts as we are not able to see the live progress of the task, but we have to wait the task to finish to see the results.
I wrote some simple PS scripts to debug this problem but neither using write-host (this does not write nothing at all, even in the end of the task) nor using write-output nor with write-verbose -verbose allows me to write realtime output.
This is one example script I tried, without success.
Write-Output "Begin a lengthy process..."
$i = 0
while ($i -le 100)
{
Start-Sleep 1
Write-Output "Inner code executed"
$i += 10
}
Write-Output "Completed."
Did you ever found yourself in this situation?
Regards
I can reproduce this issue, based on my test realtime output is not supported for the PowerShell on Target Machines task.
Write-output or write-verbose -verbose just can output to console but it's not real-timed, the output only displays once the powershell script completely executed.
To display the real-time output you can use the Utility:PowerShell task instead of the Deploy:PowerShell on Target Machines task.
So, as a workaround you can deploy an agent on the target machine which you want to run the powershell script, then trigger the release using that agent running powershell script with Utility:PowerShell task.
UPDATE:
Well, find another workaround with Utility:PowerShell task:
1.Set up WinRM for target computers, refer to WinRM configuration
2.Copy the target PS script to the target machine (D:\TestShare\PStest.ps1 in below sample)
3.Create a PowerShell script to call the Powershell.exe to run the target powershell script on target machine, see below sample:
Param(
[string]$computerName = "ICTFS2015.test.com",
)
$Username = "domain\usename"
$Password = ConvertTo-SecureString "Possword" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username,$password)
Invoke-Command -ComputerName $computerName -Credential $cred -ScriptBlock {Invoke-Expression -Command:"powershell.exe /c 'D:\TestShare\PStest.ps1'"}
4.Add a Utility:PowerShell task to run above PowerShell script. (You can check in or run Inline Script).

Another Task Scheduler not executing PowerShell

I have a simple PowerShell script that just creates a file. Testing this for a bigger PowerShell script.
Running on Windows Server 2012 R2 - 64-bit
its running under the Administrator account.
Run whether user is logged on or not
Run with highest privileges
Action:
Program/Script
:
Powershell.exe (I've tried it this way and the full path)
Add argumetns: -NoProfile -executionpolicy remotesigned -file C:\Scripts\test.ps1
Get-executionPolicy: RemoteSigned
added "Administrator" to:
Set-PSSSessionConfiguration -Name Microsoft.PowerShell -ShowSecurityDescriptorUI
"Administrator" has "Log on as batch job" permissions
"Administrator" is in the Admins group
PowerShell Script for testing:
$text = "Hello World"
$text | Set-Content TestMyFile.txt
$text | Out-File TestMyFile.txt
$text > TestMyFile.txt
# This is to write into a file or append to the text file created:
$text | Add-Content TestMyFile.txt
$text | Out-File TestMyFile.txt -Append
$text >> TestMyFile.txt
Nothing fancy, just trying to make sure Task Scheduler will execute a PowerShell script.
So What am I missing?
Use full paths in your output code, and for any future problems with running scripts from Task Scheduler, you should first put in logging and try/catch blocks to see what errors/outputs the script is generating before seeking further assistance. Doing this will help you find the answer faster & learn faster at the same time.
Tip: Always only name the program in the 'Program to run' aspect of Task Scheduler, as the Task Scheduler uses its own wrapper to execute the action, and in rare occasions, it can produce undesired results if you place the entire execution line in this field. Always put parameters in the parameters field.

Run Multiple Powershell Scripts Sequentially - on a Folder - Combine Scripts into a Master Script

I have 6+ scripts and growing to run on a folder, what is the best way to have them run one after the other.
I have seen and tried this thread - it did not work unfortunately.
How to run multiple Scripts one by one in a powershell script
In a master .ps file - I have put links to the power shell scripts that need to be run in order
Run Scripts in order
'C:\Users\WP\Desktop\Scripts\1.ps1'
'C:\Users\WP\Desktop\Scripts\2.ps1'
'C:\Users\WP\Desktop\Scripts\3.ps1'
etc
This did not work either. Your help is appreciated - I have searched all over and can't seem to fix this issue.
Revised: I believe I will have to wait for each power shell script to finish before running the next one - as I have had errors when I tried to run 3 scripts one after the other - nothing happened when the scripts were run
Final -
I thank you all for your help - to keep things simple this is what I have done
My folder has the scripts below - I have then created a Master.ps1 with the code below inside it:
&"$PSScriptroot\1.ps1"
&"$PSScriptroot\2.ps1"
&"$PSScriptroot\3.ps1"
&"$PSScriptroot\4.ps1"
&"$PSScriptroot\5.ps1"
&"$PSScriptroot\6.ps1"
I have then run the Master.ps1 on the folder with all the files - and it does the job so far.
If you don't want to hard code the path, you can make Master.ps1 like this:
&"$PSScriptroot\1.ps1"
&"$PSScriptroot\2.ps1"
&"$PSScriptroot\3.ps1"
And it will look for those scripts in the same directory where it is.
Simply create a text file, using any code editor or text editor, and use the following example batch script:
start /min powershell.exe C:\your folder\script1.ps1
start /min powershell.exe C:\your folder\script2.ps1
Save it as a script.bat and open it. This will make two powershell scripts run at the same time.
To get the path that your script is in you can do this:
$MyInvocation.MyCommand.Definition
That will show something like 'C:\Users\WP\Desktop\Scripts\Master.ps1'. From that we can do a Split-Path to get just the folder, and run Get-ChildItem on the folder to get a list of files. We'll probably want to exclude the master script, so that we don't end up in a recursive loop, so that would look something like:
$ScriptPath = Split-Path $MyInvocation.MyCommand.Definition
Get-ChildItem "$ScriptPath\*.ps1" | Where{$_.FullName -ne $MyInvocation.MyCommand.Definition}
Then we just run those through a ForEach-Object loop, and invoke the script with the call operator & as such:
$ScriptPath = Split-Path $MyInvocation.MyCommand.Definition
Get-ChildItem "$ScriptPath\*.ps1" | Where{$_.FullName -ne $MyInvocation.MyCommand.Definition} | ForEach-Object { & $_.FullName }
Edit: Hm, that wasn't filtering right. Here's a re-write that does filter out the master script correctly.
$Master = Split-Path $MyInvocation.MyCommand.Definition -Leaf
$ScriptPath = Split-Path $MyInvocation.MyCommand.Definition
Get-ChildItem "$ScriptPath\*.ps1" | Where{$_.Name -ne $Master} | ForEach-Object { & $_.FullName }
Are you hard coding the paths to the files in the master file?
In this case something like this should work
Invoke-Expression "C:\Users\WP\Desktop\Scripts\1.ps1"
Invoke-Expression "C:\Users\WP\Desktop\Scripts\2.ps1"
Invoke-Expression "C:\Users\WP\Desktop\Scripts\3.ps1"
The reason why the powershell screen pops up is cuz you dont have the argument -NoExit set. Please use the following as an example to see if your code is running properly:
Start-Process "$pshome\powershell.exe" -ArgumentList "-NoExit", "-Command '& script'" -wait
Sorry for the late response but I also ran into the issue and thats how I was able to resolve it to make sure it was work.
Also I changes the file names as follows:
$Scripts =
#(
".\C:\Scripts\First.ps1"
".\C:\Scripts\Second.ps1"
".\C:\Scripts\Third.ps1"
);
To run multiple scripts sequentially you can use the -Wait parameter on Start-Process like so:
$scriptsList =
#(
'C:\Users\WP\Desktop\Scripts\1.ps1'
'C:\Users\WP\Desktop\Scripts\2.ps1'
'C:\Users\WP\Desktop\Scripts\3.ps1'
)
foreach($script in $scriptsList)
{
Start-Process -FilePath "$PSHOME\powershell.exe" -ArgumentList "-command '& $script'" -Wait
}
PowerShell will wait for the current script to finish before running the next script

How to keep a powershell script running 24/7

I have a PowerShell script that needs to be restarted when it dies for whatever reason, be it a crash, a self exit or after a system reboot...
How can I, from a bat or another powershell script, see to it that if it is not running, it will be started again...
i.e. how can I find out if it is already running from another script?
I know I can make one powershell script start the active one and simply have it loop a new start as long as it doesnt exit with a specific error... but then THAT scripts need to be seen to :D So we are back to the original quesiton, how do I keep THAT script running 24/7?
do
{
$date = Get-Date -format "yyyy-MM-ddTHH:mm:ss"
"$($date) Repeat : Restarting Worker, LastExitCode $($LastExitCode)." | Out-File D:\IDM\Worker\Worker.LOG -width 180 -append
powershell -File "D:\IDM\Scripts\Worker.ps1"
sleep 10
}
while ($LastExitCode -ne $null)
I would just use scheduled tasks. There are plenty of options in there to help you do what you want. You can run the script every five minutes and have it do enough loops to take up that time and quit:
$now = Get-Date
while ($now.AddMinutes(5) -lt (Get-Date)){
...work...
}
Or you could even have it write a flag file every time the loop works and have any new process check that file to see if there hasn't been activity on it. If there's been no activity:
$workFlag = Get-Item C:\work.flg
$cutOff = (Get-Date).AddMinutes(-5)
if ($workFlag.LastWriteTime -gt $cutOff){
New-Item -force -path C:\work.flg
...work loop..
}