How to keep checking the process after every 30 minutes? - windows

I need to kill the process if start time is less than 2 hours.
I need to add sleep for 30 mins if start time is more than 2 hours.
I need to keep repeating it until the process is no more running.
I have written the below script so far to perform the above action.
$procName = 'myprocess'
$process = Get-Process | Where-Object Name -EQ $procName
if(-not $process) {
Write-Warning "$procName not found!"
}
else {
$process | ForEach-Object {
if($_.StartTime -lt [datetime]::Now.AddHours(-2)) {
Stop-Process $_ -Force
}
else {
sleep(1800)
}
}
}
}
How to add the above program in a do-while or another loop so as to keep checking until the process is no more running?
Also, how to implement a maximum timer of 4 hours?

If I understood correctly, your else condition could look like this using a do-while loop:
else {
do {
"$procName is still running, sleeping for 1800 sec"
Start-Sleep -Seconds 1800
} while(Get-Process | Where-Object Name -EQ $procName)
}
However note that this could cause an infinite loop if the process never stops or you implement a maximum timer, etc.
Following your comment regarding implementing a maximum timer, there are many ways you could do it, my personal preference would be to use a StopWatch:
else {
$timer = [System.Diagnostics.Stopwatch]::StartNew()
do {
# Do this while the process is still running AND
# the timer hasn't yet reached 4 hours
"$procName is still running, sleeping for 1800 sec"
Start-Sleep -Seconds 1800
$stillRunning = Get-Process | Where-Object Name -EQ $procName
} while($stillRunning -and $timer.Elapsed.Hours -lt 4)
$timer.Stop()
}

I suggest you use a windows schedule task that launch your powershell script every 30 minutes or so instead of blocking resource with your powershell that is waiting.
You can launch powershell and pass a script.
PowerShell.exe -File "C:\script.ps1"

Related

Kill the process if start time is less than 2 hours

I need to kill the process if start time is less than 2 hours.
I have written the below cmdlet to find out the starttime but how to find out if is it less than 2 hours:
get-process process1 | select starttime
There is also a possibility that on some hosts process1 is not running. so I need to check first if the process1 is running
You can use a loop of your choice, in this example ForEach-Object in addition to an if condition to check if the StartTime value is lower than 2 hours.
If you need to check first is the process is running then you would need to get all processes and filter by the process name you're looking for. Then check if the returned value from Where-Object is $null or not.
$procName = 'myprocess'
$process = Get-Process | Where-Object Name -EQ $procName
if(-not $process) {
Write-Warning "$procName not found!"
}
else {
$process | ForEach-Object {
if($_.StartTime -lt [datetime]::Now.AddHours(-2)) {
try {
'Attempting to stop {0}' -f $_.Name
Stop-Process $_ -Force
'{0} successfully stopped.' -f $_.Name
}
catch {
Write-Warning $_.Exception.Message
}
}
}
}

File Lock Mechanism using PowerShell

I have two processes that reads from the same file. I want to make sure that those two processes doesn't run at the same. My approach is that , when a process starts, it should look for a file(process.txt). If the file doesn't exist, it creates the file and continue execution, reading from the shared file(sharedfile.txt) between the two processes. It then deletes the process.txt file after executing.
Since both process deletes process.txt file after execution, if the file exists,it should go into a start sleep until the other process finishes and deletes the file.
The problem here is when one process finishes and deletes the file(process.txt), the other still stay in the loop without executing even if no file exists. I am not sure of the right loop to use. I tried a couple of them and couldn't achieve my goal.
Clear Host
$sleeptime = 15
$lockfile = "C:\Users\processid.txt"
$file = test-path -Path $lockfile
Try
{
if($file -eq 'True')
{
echo “Lock file found!”
echo "This means file is being used by another process"
echo "Wait for file to be deleted/released"
echo “Sleeping for $sleeptime seconds”
Start-Sleep $sleeptime -Verbose
}
else
{
New-item -Path $lockfile
#Executing a code here
}
Remove-Item $lockfile –Force
}
}
Catch
{
Write-Host $_.Exception.Message`n
}
Consider this one, it creates a lock file and opens it for exclusive access. Let's you run your script, then cleans up afterwards. If access cannot be gained it waits 5 seconds before trying again.
Using this for both scripts should make them play nice and wait for their turn. If for some reason a lock file gets left behind (unplanned reboot that aborts script or similar) this one will still work fine as well.
$LockFile = 'C:\temp\test.lock'
# Loop that runs until we have exclusive write access to $LockFile
while ($FileStream.CanWrite -eq $false) {
if (-not (Test-Path -Path $LockFile)) {
Set-Content -Path $LockFile -Value 'Lockfile'
}
try {
$FileStream = [System.IO.File]::Open("C:\temp\test.lock",'Open','Write')
}
catch {
'Waiting 5 seconds'
Start-Sleep -Seconds 5
}
}
# ---
# Your actual script here
# ---
# Cleanup
$FileStream.Close()
$FileStream.Dispose()
Remove-Item -Path $LockFile -Force
You could also go one step further and instead lock the file you're actually using, but then you'll need to read it from the file stream since it will be locked for any cmdlets.
You could use a while loop like this
Clear Host
$sleeptime = 15
$lockfile = "C:\Users\processid.txt"
While(Test-Path -Path $lockfile){
Write-Host "Lock file found!"
Write-Host "This means file is being used by another process"
Write-Host "Wait for file to be deleted/released"
Write-Host "Sleeping for $sleeptime seconds"
Start-Sleep $sleeptime -Verbose
}
try{
New-item -Path $lockfile
#Executing a code here
}
catch{
Write-Host $_.Exception.Message`n
}
finally{
Remove-Item $lockfile –Force -ErrorAction SilentlyContinue
}

How can I wait until `start-process notepad` has finished creating its window?

When I use start-process to create a new process and assign it to a variable...
$np = start-process -passThru notepad
... and then query .MainWindowHandle ...
$np.MainWindowHandle
... I seem to be given the HWND of the notepad.
However, when I try to do the same thing in one go...
(start-process -passThru notepad).MainWindowHandle
... I am given 0.
This is probably the case because MainWindowHandle is evaluated before notepad has created its window.
So, is there a way, without using start-sleep or going into a loop that repeadetly queries the value of MainWindowHandle, to wait until notepad is done starting up?
So, is there a way,
Yes
without using start-sleep or going into a loop that repeadetly queries
the value of MainWindowHandle
Not that I can think of :)
# Define a timeout threshold 10 seconds into the future
$threshold = (Get-Date).AddSeconds(10)
# Start the process
$proc = Start-Process notepad -PassThru
while(-not $proc.HasExited -and ((Get-Date) -lt $threshold -or $proc.MainWindowTitle -eq 0)){
Start-Sleep -MilliSeconds 250
}
if($proc.MainWindowTitle -eq 0){
if(-not $proc.HasExited)
$proc.Terminate()
}
throw 'Failed to spawn window in time'
return
}
# Do stuff with $proc.MainWindowHandle

Powershell equivalent of Linux timeout

As part of a Powershell script I need to perform a task that is typically quick, but can sometimes take a long amount of time. I want to execute the task, then wait either for it fo finish or for set time to pass, whichever happens first. When either condition happens, I need the Powershell script to return back to the command prompt.
Here is the closest I've come up with (using ping as an example)
$x = Start-Process -Filepath "ping" -ArgumentList 'google.com -n 100' -NoNewWindow -PassThru;
Start-Sleep -Seconds 5;
try { Stop-Process -Id $x.Id -ErrorAction stop } catch {};
This will kill the process after the timoeout is reached (if it is still running) and return back to the prompt. However, it won't return to the prompt if the command successfully completes before timeout. This results in the script always taking however long is specified in the timeout value.
The desired semantics are similar or identical to Linux's timeout command.
Requirements:
If the task completes within timeout window, control returns to the script (a prompt is displayed)
If the timeout is reached and the task is stil running, the task is killed and control returns to the script (a prompt is displayed)
Output from the task must be printed/displayed to stdout
Works over an SSH connection
Edited to use ping instead of notepad. I'm combining wait-process and "$?" into one statement with "$( )", because powershell "if" looks at the output, not the exit status.
start ping 'google.com -n 100'
if (-not $(wait-process ping 10; $?)) {
stop-process -name ping }
I think some of the requirement can be met by using a Stopwatch, you'll have to test the SSH connection.
$timeOut = New-TimeSpan -Seconds 5
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew()
do {
try {
Test-Connection -ComputerName google.ca -Count 1 -ErrorAction Stop
$timeOut = New-TimeSpan -Seconds 0 #Stop the stopWatch, we got a response
}
catch { #Write-Host "No response" }
}
While ($stopWatch.elaspsed -lt $timeOut)

Getting Scheduled Tasks Between Specific Times On Windows 10 Desktop

I'm having some troubles using the PowerShell in windows 10 in order to get specific scheduled tasks. I need to get a list of scheduled task that run between 9:00 PM to 12 PM. I couldn’t figure out how to use the “Get-ScheduledTask “ and “Get-ScheduledTaskInfo” commands properly.
I will be so grateful if someone can help me writing the script the right way!
I think this is what you need:
Get-ScheduledTask | ForEach-Object {
$NextRunTimeHour = ($_ | Get-ScheduledTaskInfo).NextRunTime.Hour
If ($NextRunTimeHour -in 21..23) { $_ }
}
Gets the Scheduled Tasks, then iterates through them with ForEach-Object, piping each to Get-ScheduledTaskInfo to get the .NextRunTime property and it's .Hour subproperty and then returning the Scheduled task if the hour is 21, 22 or 23.
Other method, give you all necessary infos :
Get-ScheduledTask| %{$taskName=$_.TaskName; $_.Triggers |
where {$_ -ne $null -and $_.Enabled -eq $true -and $_.StartBoundary -ne $null -and ([System.DateTime]$_.StartBoundary).Hour -in 21..23} | %{
[pscustomobject]#{
Name=$taskName;
trigger=$_
Enabled=$_.Enabled
EndBoundary=$_.EndBoundary
ExecutionTimeLimit=$_.ExecutionTimeLimit
Id=$_.Id
Repetition=$_.Repetition
StartBoundary=$_.StartBoundary
DaysInterval=$_.DaysInterval
RandomDelay=$_.RandomDelay
PSComputerName=$_.PSComputerName
}
}
}

Resources