I have a little code I wrote that checks to see if Outlook is running, and if it is not, opens Outlook. The problem is that my work PC tends to idle around 7% usage, but spikes up to the upper 30s while the script is running. If it detects that Outlook is no longer active, CPU usage can spike up to nearly 100% while opening Outlook. This ~33% increase while the script is running could cause problems when I am working. Is there another way to accomplish the functionality of my code while using less processing power?
do{
$running = Get-Process outlook -ErrorAction SilentlyContinue
if (!$running)
{
Start-Process outlook
}
} while (1 -eq 1)
You need to add a Start-Sleep in there, to keep the script from continuously using CPU time. Otherwise it's continuously looping without rest, making sure Outlook is running. At the end of your do-block:
Start-Sleep -s 60
You can adjust the number of seconds, or even specify milliseconds instead with the -m parameter you require it.
Another way of solving this problem is running below batchfile (scheduled)
#echo off
SET outlookpath=C:\Program Files\Microsoft Office 15\root\office15\outlook.exe
for /f "usebackq" %%f in (`tasklist /FI "IMAGENAME eq outlook.exe"`) do set a=%%f
REM echo A:%a%
if not "%a%"=="outlook.exe" start "" "%outlookpath%"
If you schedule this to run every 5 minutes, than within 5 minutes after closing outlook, it will start again. If you think 5 minutes is too long, schedule it more often. 😉
Related
I need to run a function more than 200 times simultaneously with PowerShell. So far I have two options Start-Job and Start-ThreadJob. In both cases I use a "launcher" as is
$MyFunction = [scriptblock]::Create(#"
Function FunctionName {$function:FunctionName}
"#)
foreach($i in $loop){
Start-ThreadJob -name $JobName -ThrottleLimit 30 -InitializationScript $MyFunction -ScriptBlock {FunctionName $Using:var1 $Using:var2}
#Start-Job -name $JobName -InitializationScript $MyFunction -ScriptBlock {FunctionName $Using:var1 $Using:var2}
}
With Start-Job, it takes about 30 seconds for a job to start. I noticed two things
This time depends on the function (here FunctionName). If there are more variables it takes more time. My function has about 15 variables. I create a PSCustomObject and some data are stored in a MySQL DB every 2 seconds.
If I comment all my code, the time remains the same! But if I remove all the code the job is created instantly.
With Start-Job, it then takes about 30 * 200 = 6000 seconds which is really too long.
Now with Start-ThreadJob, every jobs start instantly. There is a but, otherwise I would not post here, the data in MySQL are stored every 10 seconds! which is really too long. I don't believe this is a MySQL issue but a performance issue with PowerShell.
Do you have more option to propose or do you know how to improve performance?
Thank you for your time.
Yann
Edit: I started asking this as a PowerShell / .Net question and couldn't find any reference to it on the internet. With feedback, it appears to be a WINAPI issue so this is an edit/rewrite/retag, but much of the tests and background reference .Net for that reason.
Summary
WINAPI ping function IcmpSendEcho2 appears to have a timing bug if the ping timeout parameter is set below 1000ms (1 second). This causes it to return intermittent false timeout errors. Rather than a proportional "lower timeout = more fails" behaviour, it appears to be a cutoff of >=1000ms+ is expected behaviour, <=999ms triggers false timeouts, often in an alternating success/fail/success/fail pattern.
I call them false timeouts because I have WireShark packet capture showing a reply packet coming back well within the timeout, and partly because the 1ms change shouldn't be a significant amount of time when the replies normally have 500-800ms of headroom, and partly because I can run two concurrent sets of pings with different timeouts and see different behavior between the two.
In the comments of my original .Net question, #wOxxOm has:
located the Open Source .Net code where System.Net.NetworkInformation.Ping() wraps the WinAPI and there appears to be no specific handling of timeouts there, it's passed down to the lower layer directly - possibly line 675 with a call to UnsafeNetInfoNativeMethods.IcmpSendEcho2()
and #Lieven Keersmaekers has investigated and found things beyond my skill level to interpret:
"I can second this being an underlying WINAPI problem. Following a success and timedout call into IPHLPAPI!IcmpSendEcho2Ex: the 000003e7 parameter is on the stack, both set up an event and both return into IPHLPAPI!IcmpEchoRequestComplete with the difference of the success call's eax register containing 00000000 and the timedout call's eax register containing 00000102 (WAIT_TIMEOUT)
"Compiling a 64bit C# version, there's no more calls into IPHLPAPI. A consistent thing that shows up is clr.dll GetLastError() returning WSA_QOS_ADMISSION_FAILURE for timeouts. Also consistent in my sample is the order of thread executions between a success and a timeout call being slightly different."
This StackOverflow question hints that the WSA_QOS_ADMISSION_FAILURE might be a misleading error, and is actually IP_REQ_TIMED_OUT.
Testing steps:
Pick a distant host and set some continuous pings running. (The IP in my examples belongs to Baidu.cn (China) and has ping replies around ~310ms to me). Expected behaviour for all of them: almost entirely ping replies, with occasional drops due to network conditions.
PowerShell / .Net, with 999ms timeout, actual result is bizarre reply/drop/reply/drop patterns, far more drops than expected:
$Pinger = New-Object -TypeName System.Net.NetworkInformation.Ping
while($true) {
$Pinger.Send('111.13.101.208', 999)
start-sleep -Seconds 1
}
command prompt ping.exe with 999ms timeout, actual result is more reliable (edit: but later findings call this into question as well):
ping 111.13.101.208 -t -w 999
PowerShell / .Net, with 1000ms timeout, actual result is as expected:
$Pinger = New-Object -TypeName System.Net.NetworkInformation.Ping
while($true) {
$Pinger.Send('111.13.101.208', 1000)
start-sleep -Seconds 1
}
It's repeatable with C# as well, but I've edited that code out now it seems to be a WinAPI problem.
Example screenshot of these running side by side
On the left, .Net with 999ms timeout and 50% failure.
Center, command prompt, almost all replies.
On the right, .Net with 1000ms timeout, almost all replies.
Earlier investigations / Background
I started with a 500ms timeout, and the quantity of fake replies seems to vary depending on the ping reply time of the remote host:
pinging something 30ms away reports TimedOut around 1 in 10 pings
pinging something 100ms away reports TimedOut around 1 in 4 pings
pinging something 300ms away reports TimedOut around 1 in 2 pings
From the same computer, on the same internet connection, sending the same amount of data (32 byte buffer) with the same 500ms timeout setting, with no other heavy bandwidth use. I run no antivirus networking filter outside Windows 10 defaults, two other people I know have confirmed this frequent TimedOut behaviour on their computers (now two more have in the comments), with more or fewer timeouts, so it ought not to be my network card or drivers or ISP.
WireShark packet capture of ping reply which is falsely reported as a timeout
I ran the ping by hand four times to a ~100ms away host, with a 500ms timeout, with WireShark capturing network traffic. PowerShell screenshot:
WireShark screenshot:
Note that the WireShark log records 4 requests leaving, 4 replies coming back, each with a time difference of around 0.11s (110 ms) - all well inside the timeout, but PowerShell wrongly reports the last one as a timeout.
Related questions
Googling shows me heaps of issues with System.Net.NetworkInformation.Ping but none which look the same, e.g.
System.Net.NetworkInformation.Ping crashing - it crashes if allocated/destroyed in a loop in .Net 3.5 because its internals get wrongly garbage collected. (.Net 4 here and not allocating in a loop)
Blue screen when using Ping - 6+ years of ping being able to BSOD Windows (not debugging an Async ping here)
https://github.com/dotnet/corefx/issues/15989 - it doesn't timeout if you set a timeout to 1ms and a reply comes back in 20ms, it still succeeds. False positive, but not false negative.
The documentation for Ping() warns about the low-timeout-might-still-say-success but I can't see it warns that timeout might falsely report failure if set below 1 second.
Edit: Now that I'm searching for ICMPSendEcho2, I have found exactly this problem documented before in a blog post in May 2015 here: https://www.frameflow.com/ping-utility-flaw-in-windows-api-creating-false-timeouts/ - finding the same behavior, but having no further explanation. They say that ping.exe is affected, when I originally thought it wasn't. They also say:
"In our tests we could not reproduce it on Windows Server 2003 R2 nor on Windows Server 2008 R2. However it was seen consistently in Windows Server 2012 R2 and in the latest builds of Windows 10."
Why? What's wrong with the timeout handling that makes it ignore ping repsonses coming into the network stack completely? Why is 1000ms a significant cutoff?
I have looked around every forum going for this and the two solutions that are suggested are to either use Ping or use timeout. I am using the timeout, but I have the same issue with ping.
The issue I am having is that if I use the timeout command at the very beginning it works fine but if I sandwich the timeout between two calls for instance, the timeout is completely ignored.
CALL C:\Progra~1\Folder\Batchscript1.bat
timeout /t 30 /nobreak
CALL C:\Progra~1\Folder\Batchscript2.bat
The two batch scripts are both sending an email. With the set up above, this batch finishes almost instantly (should timeout for 30 seconds) and sends both emails successfully.
When I look at what is happening in the batch, I am getting the following error:
"timeout is not recognised as an internal or external command, operable program or batch file". Again this doesn't make sense too me seeing as the timeout works just fine in the below batch.
timeout /t 30 /nobreak
CALL C:\Progra~1\Folder\Batchscript2.bat
Any help would be appreciated
I assume there must be something in your call to Batchscript1.bat which is having an impact on your call to timeout.exe.
Try extending the call of timeout.exe with the fully qualified path:
"%windir%\system32\timeout.exe" /t 30 /nobreak
However, keep in mind, that you may have only treated a symptom. The cause of the issue may still affect your second script.
If you are not required to use a variable of batchscript1 in batchscript2 you should consider using setlocal and endlocal around the batchscript1 call.
I have two VBScripts. ScriptA calls ScriptB using the command below
C:\Windows\System32\wscript.exe"" //Nologo //B ""C:\Program Files\ROC\ScriptB.vbs
From the ScriptA log file I can see at every run there is a delay of 5 seconds in starting ScriptB. Both scripts runs on Windows XP.
Is this a default behaviour? how can I change this?
Windows XP won't add a delay to the start of the second script. There may be a delay if the system is under extremely heavy load, but doubtful with just a vbscript.
The best way to determine where your delay is coming from is to search through scriptA and see if you can find any Sleep methods being used. Sleep takes in an argument that tells it to pause for that many milliseconds, so you would pause for 5 seconds if you had a Sleep(5000) statement somewhere in your code.
If sleep is not being called, then most likely scriptA is just finishing up some code that doesn't log out to the log file before scriptB gets kicked off. If you want to determine the exact point of the delay, start at the point in scriptA where you call scriptB and add a two log statements that will print out the time to the log file. Slowly move the first log statement upwards away from the point where scriptB is called and you will be able to determine which code is taking 5 seconds to process before scriptB is started.
Currently we have a sequential workflow in sharepoint 2010 that has a delay activity.
The delay is set to five minutes. The workflow checks on the status of five tasks and depending on the results, it either delays or completes.
I have a workflow history log item set to write right before the delay and right after the delay.
Sometimes the delay does not fire, an example would be as follows:
Delay activity fires every five minutes for 3 full days on one item, then for no particular reason it fails to wake up for 17 hours...then fires and completes.
Any ideas? I have verified all of the timer services are running properly etc.
The other odd thing is that there can be 20 workflows items running and only 4 or 5 will have this issue, it seems totally random.
Also: If I make a change to the workflow item that causes the workflow to re-run, the delay activity will awaken at the next 5 minute cycle.
Update: I have found an error in my error log that occurs when the delay fails to awaken.
Workflow ID=07acf527-d5cb-41c7-a8e4-58329652dc53 attempting to run on a thread currently executing workflow ID=fe2d7670-7d3e-4e6a-b024-0cc3485aa73b. This workflow will be run at a later time.
Update: Apparently this is occurring because the workflow with the delay is being started programmatically from another workflow. This causes the second workflow to be started in the same thread. Anyone know how to specify a new thread programmatically?
Update 2: I setup some workflows to run with a 5 minute delay to see if there was any pattern to the sleep cycles. The workflows slept at 5 minute intervals for around 6 hours then the timer started to increment as follows
5 minutes
15 minutes
45 minutes
1.5 hours
3 hours
6 hours
12 hours
It looks like the delay timers are being doubled for the most part. I sure MS can figure this one out, I have tons of logs and examples.
This issue has been resolved. I had forgotten to post the resolution...
Three settings needed to be modified. Workflow Throttle, Workflow Batch, and the Hidden Workflow Timer.
You can check the current throttle setting by running the following command:
stsadm -o getproperty -pn
workflow-eventdelivery-throttle
Here is my new setting:
stsadm -o setproperty -pn
workflow-eventdelivery-throttle -pv
"45"
You can check the current batch size setting by running the following command:
stsadm -o getproperty -pn
workitem-eventdelivery-batchsize
Here is my new setting.
stsadm -o setproperty -pn
workitem-eventdelivery-batchsize -pv
"250"
You can check the current interval setting by running the following command, in which you replace the URL with a valid path to a SharePoint application:
stsadm -o getproperty -pn job-workflow
-url http://yoursiteurl
Here is my setting:
stsadm -o setproperty -pn job-workflow
-pv "Every 5 minutes between 0 and 59" -url http://yoursiteurl