How to Show Message While Running PowerShell Script - powershell

I found below code to launch a scheduled task in Windows' 10 Task Scheduler. It spawns a PowerShell Window while the task is executing, and the task runs as expected. I expected to see the message "Waiting on scheduled task ..." displayed in the PowerShell window while the task was running. However, the message isn't displayed. How can I achieve that?
Start-ScheduledTask -TaskName "\FOLDER\TASK_NAME";
while ((Get-ScheduledTask -TaskName 'TASK_NAME').State -ne 'Ready') {
Write-Verbose -Message "Waiting on scheduled task..."
}
Thank you.

With PowerShell, it is easy to create an instance of a COM object. In our case, we need the Windows.Shell object from WSH. It can be created with the following command:
$wsh = New-Object -ComObject Wscript.Shell
Now, we can use our $wsh object to call methods available for Wscript.Shell. One of them is Popup, this is what we need. The following code can be used
$wsh = New-Object -ComObject Wscript.Shell
$wsh.Popup("Hello world")
read more

Related

PowerShell script lacks consistency when run through task scheduler, am I missing something or is this Windows being Windows?

I am a beginner in PowerShell.
I have created myself a PowerShell program to act as my alarm clock in the morning. I have task scheduler executing it on a time trigger. The problem i am having is a lack of consistency. Sometimes it will run properly without any interference, other times it will open PowerShell, error out and close immediately without executing (no error code). When i execute it myself with a double click, it seems to work just fine.
Execution Policy = All-Signed
Task Scheduler
Trigger Tab:
Trigger: Daily
Details: At 8:00 AM every Day
Status: Enabled
Action Tab:
Action: Start a Program
Program/Script: PowerShell.exe
Add arguments: -NoExit D:\Programs\AlarmClock\AlarmClockScript.ps1
Script:
#define loop start state
$Snoozevar = 'Yes'
#Import form module (for menu)
[reflection.assembly]::LoadWithPartialName("System.Windows.forms") | Out-Null
#Menu
$snoozeTxtBox = New-Object System.Windows.Forms.Button
$snoozeTxtBox.Text = 'Snooze'
$snoozeTxtBox.Location = '50,15'
$snoozeTxtBox.Size = '60,23'
$snoozeTxtBox.DialogResult = [System.Windows.Forms.DialogResult]::Yes # 'Snooze' = Yes
$quitTxtBox = New-Object System.Windows.Forms.Button
$quitTxtBox.Text = 'I`m Up'
$quitTxtBox.Location = '125,15'
$quitTxtBox.Size = '50,23'
$quitTxtBox.DialogResult = [System.Windows.Forms.DialogResult]::No # 'I`m Up' = No
$basicForm = New-Object System.Windows.Forms.Form
$basicForm.StartPosition = 'CenterScreen'
$basicForm.Size = '250,100'
$basicForm.Controls.Add($snoozeTxtBox)
$basicForm.Controls.Add($quitTxtBox)
$basicForm.TopMost = $true
while ($Snoozevar -eq 'Yes'){
Start-Process "D:\Programs\Winamp\winamp.exe" /PLAY # Start Winamp /autoplay
Start-Process D:\Programs\nircmd\nircmd.exe -ArgumentList " setsysvolume 65535" #Max Volume
$Snoozevar = $basicForm.ShowDialog() # Call Menu, assign output to $Snoozevar
$pro = Get-Process -Name "winamp" # Kill winamp post menu selection
Stop-Process -Id $pro.Id
$pro = ""
if ($Snoozevar -eq 'No'){ # Clean up powershell
$pro = Get-Process -Name powershell
Stop-Process $pro
} #end if
$rngvar = Get-Random -Minimum 540 -Maximum 720 # Time to Snooze (9-12 minutes)
Start-Sleep -Seconds $rngvar
} #end while
# SIG # Begin signature block
...
# SIG # End signature block
This is my first time asking a question here, please forgive and point out mistakes in forum standards.
Thank You in advance!
Here's a summary of the things that can be done to diagnose an inconsistend scheduled task execution.
Since your task is interactive (have a form), Run whether user is logged on or not should be left unchecked. While you'd normally want it checked most of the time, tasks that interact with the user (popup / forms / etc...) won't work properly if thus option is checked.
Add Start-Transcript -Path "Some\Path\AlarmLog_$(get-date -f 'yyyyMMdd').txt at the beginning of your file and Stop-Transcript at the end to gain more insight on when it fail
Make sure to check the Conditions tab as there are additional constraint that could affect task execution (eg: By default, task will not execute if on battery power)
If the task is running under a different user or in a different context (eg: with Highest priviledges), try to execute your script in that context to see if it fail (for instance, start Vscode / ISE using that context and run the task)
If you have multiple set of operations, you can wrap them in Try / Catch block so if one set fail, you can perform additional logging and also decide whether or not the task should be cancelled altogether or continue through. (Note: When using try/catch, you'll want to set -ErrorAction Stop on the functions that have that parameter to make sure they get caught properly in the catch block.
References
Msdocs - Start-Transcript
Msdocs - Task scheduler -Security context for running task

scheduled tasks don't show up in Get-ScheduledTask result

I have defined some scheduled task using Windows Task Scheduler GUI under "" [default] path but when i run Get-ScheduledTask in powershell, it does not return them. why?
I have tried with Get-ScheduledTask -TaskName "MyTaskName" with one of my task name but it comes up with "No MSFT_ScheduledTask objects found with property 'TaskName' equal to 'MyTaskName'"
Actually I have tried https://library.octopusdeploy.com/step-template/actiontemplate-windows-scheduled-task-disable but it doesn't work so I have tried running script directly.
UPDATE
I have found the following script to get task list on http://www.fixitscripts.com/problems/getting-a-list-of-scheduled-tasks:
# PowerShell script to get scheduled tasks from local computer
$schedule = new-object -com("Schedule.Service")
$schedule.connect()
$tasks = $schedule.getfolder("\").gettasks(0)
$tasks | Format-Table Name , LastRunTime # -AutoSize
IF($tasks.count -eq 0) {Write-Host “Schedule is Empty”}
Read-Host
UAC
The result is likely affected by UAC. To see everything try right clicking the PowerShell icon, select Run as Administrator and then run your Get-ScheduledTask command again and see if that changes anything.
Further reading: http://david-homer.blogspot.co.uk/2017/10/not-all-scheduled-tasks-show-up-when.html
Have you tried using a com object? This code works for me:
# FOR A REMOTE MACHINE
$s = 'SERVER_NAME' # update this with server name
($TaskScheduler = New-Object -ComObject Schedule.Service).Connect($s)
# FOR LOCAL MACHINE
($TaskScheduler = New-Object -ComObject Schedule.Service).Connect()
#now we can query the schedules...
cls;$TaskScheduler.GetFolder('\').GetTasks(0) | Select Name, State, Enabled, LastRunTime, LastTaskResult | Out-GridView
This code will retrieve a particular task and enable it:
$task = $TaskScheduler.GetFolder('\').GetTask("TASKNAME")
$task.Enabled = $true
When running Get-ScheduledTask from a user-level prompt, even if the user is an administrator, they will see only the tasks that they can read with user-level permissions. Seeing them in the TaskSchd.Msc window indicates that program is running with different permissions.
Therefore, running a PowerShell prompt as administrator solves the problem.
The same issue occurs when using SchTasks.exe from a command prompt.

Monitoring Start-Process with Timer

I am running in debug mode in ISE. I am starting a separate powershell script from another secondary script using start-process and specifying it's -file parameter from the primary script. I have a timer in the primary script where I am trying to execute some other code.
Please consider the following:
$timer = new-object timers.timer
$timerID = [guid]::NewGuid()
$timer.Interval = 10000
$complete = 0
$action = {
write-host "Complete Ticker: $complete"
if($complete -eq 1)
{
write-host "Completed"
$timer.stop()
Unregister-Event $timerID
}
}
Register-ObjectEvent -InputObject $timer -EventName elapsed –SourceIdentifier $timerID -Action $action
$timer.start()
$shellScript = "-file C:\Test.ps1"
$powershellArguments = $shellScript
Start-Process "powershell.exe" -Wait -ArgumentList $powershellArguments
$complete = 1
The other script is called successfully, and displays, however the timer does not appear to tick unless the script window started with the start-process is closed. The expected result is in that the interval specified that a breakpoint could be set in the action and hit while the secondary script is running.
Is there something perhaps wrong with the above code?
The start-process that starts PS uses the -Wait parameter. That prevents $action from running.
I'm not sure what the code is trying to accomplish via the timer and $action. What it would do, though (if not for -Wait), is write "Complete Ticker: 0" every ten seconds until the invoked PS completes when it will write "Complete Ticker: 1".
If the invoked PS runs longer than 10 seconds * height_of_the_parent_PS_console_in_lines, you won't really be able to see much in the way of output - the screen will be full of "Complete Ticker: 0" messages and you'd have to watch closely to see the screen kind of flicker every 10 seconds. Even if the invoked PS runs more quickly than that, the output doesn't tell how long the invoked PS will run or even that it's making progress.
In essence it's kind of like having the user watch der blinkenlights - interesting to look at possibly, but not too informative.
But if that's what the timer code is supposed to do it can be replaced by a simple loop after the start-process that checks if the invoked PS has completed and if not outputs the "Complete Ticker: 0" message.
Use the -passthru argument to start-process and then check the status of via the returned process object in the loop.

Looking for info on how to change the settings on a scheduled task from powershell

I have some PowerShell scripts which are being ran daily using a scheduled task, the scheduled task is created using PowerShell itself and is all working quite nicely.
Id like to be able to add a setting into the scheduled task as follows:-
I want to be able to change the setting -> Stop the task if it runs longer than 3 days.
Can I change this setting somehow, I've managed to create the scheduled task in PowerShell and I can change the triggers, actions and so on but I cant see how to affect the Settings, without manually changing them inside task scheduler.
help from the below link:
http://powershell.com/cs/blogs/tips/archive/2013/06/21/changing-scheduled-tasks-with-powershell.aspx
Solution:
$service = New-Object -ComObject Schedule.Service
# Can connect remotely as well, currently doing it local
$service.Connect($env:COMPUTERNAME)
# navigate to desired folder where the scheduled task is in TaskScheduler
$folder = $service.GetFolder('\Microsoft\Windows\XXX_DestinationFolder_XXX')
# Get the desired task
$task = $folder.GetTask('XXX_TaskName_XXX')
$definition = $task.Definition
# Incase you are interested in changing more settings
# $definition | Get-Member
# for 10 days it is 'P10D', by default it is 3 days so it will be 'P3D'
$definition.Settings | Where-Object {$_.ExecutionTimeLimit = 'P10D'}
# finally updating
$folder.RegisterTaskDefinition($task.Name, $definition, 4, $null, $null, $null)
If you can upgrade to PowerShell 4.0 or later, you can use ScheduledTask CMDlets to create/update them. Here is an example for changing the Time Limit:
$STSet = New-ScheduledTaskSettingsSet -ExecutionTimeLimit 72:00:00
Set-ScheduledTask ScheduledTaskName -Settings $STSet

How to use Register-Objectevent to invoke a powershell script?

I was trying to execute powershell in parallel mode. I was advised to create an event which will trigger whenever there is a change in folder.
For ex: If a folder name called "test1" is created in a particular folder then my powershell script test1.ps1 should be triggered.
I was trying to get example for this with Register-Objevent , but i am not getting any good clue.
If you have implemented some thing like this , can you please guide me?
Updated:
When i create a file named test1.ps1 in the "D:\ParallelEvent\temp" folder, it should execute test1.ps1 powershell file. Following is the code for that
$ScriptLoc="D:\My_Scripts"
$watcher = New-Object System.IO.FileSystemWatcher -Property #{Path = 'D:\ParallelEvent\temp';Filter = '*.txt';NotifyFilter = [System.IO.NotifyFilters]'FileName,LastWrite'}
$CreatedAction =
{
$FilenamewithoutExtn=$(($event.sourceEventArgs.Name).Split('.')[0])
Start-Job $ScriptLoc\$FilenamewithoutExtn.ps1
Get-Job -State Running | Wait-Job
}
Register-ObjectEvent -InputObject $watcher -EventName Created -SourceIdentifier FileCreated -Action $CreatedAction
My test1.ps1 has following line
[system.windows.forms.messagebox]::show("Hello, Test1!")
But still it doesn't execute the test1.ps1 it seems. I did not get any messagebox. Am i missing any thing?
you are not getting messagebox because powershell jobs run as background process and does not show ui.
if you modify the test1.ps1 to a file redirection
"test " > C:\AnywhereYouWantToRedirectData\testagain.txt
you will be able to see that the test1.ps1 runs and redirected file gets created (testagain.txt).