Page 1 of 2
Powershell Performance Recommendations
Posted: 01 Sep 2021 12:02
by atfon
Do any of you folks have any recommendations when it comes to the best performance for launching powershell from a batch script? In my script I have occasions to grab information which is not available from the command line. In these cases, I invoke powershell. [You may ask why I don't just write the whole script in powershell, but that takes out the fun of batch scripting.
] Anyhow, based on what I've read, I'm using -noprofile -ExecutionPolicy Bypass, but there may be other options which help? Does the -Mta multi-threaded versus -Sta single-threaded option make a difference?
https://docs.microsoft.com/en-us/powers ... rshell-5.1
I''ll provide a quick example:
Code: Select all
for /f "tokens=*" %%g in ('where powershell.exe') do set "psLoc=%%g"
set "psParam=-noprofile -ExecutionPolicy Bypass"
for /f "skip=2 tokens=*" %%o in ('%psLoc% %psParam% /command "Get-NetConnectionProfile | Select NetworkCategory"') do set "netType=%%o"
Re: Powershell Performance Recommendations
Posted: 01 Sep 2021 13:09
by aGerman
I mean, yes it's possible to call PowerShell in a Batch script to overcome some limitations. But mixing scripts is not necessarily a good idea. Especially PowerShell takes some time to load the needed .NET ressources. If you write the whole thing in PowerShell, this will happen only once. But every time you invoke powershell.exe in a batch file you'll be facing the same delay again and again. We had some lengthy threads about performance in Batch. It turns out that any command line tool (.exe or .com files, such as the common findstr.exe) used in a loop is going to decrease the speed tremendously. That's because the OS has to schedule and load a new process again and again.
However, a possibility to speed-up initializing of a PowerShell process is the pre-compilation of assemblies every time you receive a .NET update. Refer to
viewtopic.php?p=59703#p59703
Steffen
Re: Powershell Performance Recommendations
Posted: 01 Sep 2021 13:39
by atfon
But mixing scripts is not necessarily a good idea.
Oh, I agree. I know this isn't exactly ideal.
But every time you invoke powershell.exe in a batch file you'll be facing the same delay again and again.
I've only noticed a longer delay when loading the powershell the first time. Subsequently (within the same batch script), it seems to load much faster. If I'm going to run powershell more than one time from a batch script, is there a suggested method to leave it open until the batch script has completed?
Re: Powershell Performance Recommendations
Posted: 01 Sep 2021 13:52
by aGerman
atfon wrote: ↑01 Sep 2021 13:39
I've only noticed a longer delay when loading the powershell the first time.
That's a known behavior. Probably some kind of caching.
atfon wrote: ↑01 Sep 2021 13:39
is there a suggested method to leave it open until the batch script has completed?
No. Batch executes command line tools synchronously. That means it resumes after the process of the tool terminated. And if you think about it, this is the only sensible way. Things that don't require to be executed synchronously (because the rest of the script is unrelated to their outcome) might be invoked asynchronously (in parallel) in another process using START.
Steffen
Re: Powershell Performance Recommendations
Posted: 01 Sep 2021 14:19
by Aacini
A little advice first: do not create a separate .ps file for the other code, just write the PS code directly after the PowerShell command in the .bat file. This does not require any psParams (like ExecutionPolice), just follow a couple tricks to write correct code and you will have a little more than 8000 characters for the PS code.
You may use PS code from a Batch file loop in a very efficient way if you start the PS code just once in a concurrent, parallel way and communicate both codes via input/output commands as described in
Read arrow keys and show color text in an efficient way. As examples of the use of such a method are
my Tetris game in color or my
Multi-player version in color of Snake game.
Antonio
Re: Powershell Performance Recommendations
Posted: 01 Sep 2021 14:39
by atfon
Hi Antonio,
Thanks for the advice. I never call external ps code. All of the commands are in the .bat. I will have a look at your input/output examples. That sounds promising.
Re: Powershell Performance Recommendations
Posted: 01 Sep 2021 15:22
by aGerman
This is
IPC. You have limited possibilities in Batch to do that. Antonio discovered a pipe mechanism. A more common way is the file mechanism which carries the risk of race conditions (can be resolved using lock files). It highly depends on your use case whether or not IPC is an opportunity.
I know that this is a Batch community. And I'm one of those guys who left quite some PS / Batch hybrids in the forum. However, I can only repeat myself, think about doing things in PS entirely if you can't achieve your task using Batch only ¯\_(ツ)_/¯
Steffen
Re: Powershell Performance Recommendations
Posted: 02 Sep 2021 05:26
by atfon
Thanks, Steffen.
...think about doing things in PS entirely if you can't achieve your task using Batch only
This is perfectly reasonable and I may do that at some point. But, given the size and scope of my current batch script, that may be a while. As you said, you and a number of experts on this forum have posted numerous batch / powershell hybrid scripts. I only have a few powershell calls in my script, but I like my scripts to be as efficient as I can make them.
Re: Powershell Performance Recommendations
Posted: 02 Sep 2021 13:48
by Compo
Just to provide a small counter argument to your statement
atfon wrote: ↑01 Sep 2021 12:02
In my script I have occasions to grab information which is not available from the command line.
The information you require in your example script is available without resorting to PowerShell.
The following is OS dependent
(Windows 8 / Server 2012 or newer), however:
Code: Select all
@For /F Delims^= %%G In ('%SystemRoot%\System32\wbem\WMIC.exe
/NameSpace:\\Root\StandardCimv2 Path MSFT_NetConnectionProfile
Get NetworkCategory /Value 2^>NUL') Do @Set /A %%G 2>NUL
@If "%NetworkCategory%" == "0" (Set "NetworkCategory=Public"
) Else If "%NetworkCategory%" == "1" (Set "NetworkCategory=Private"
) Else If "%NetworkCategory%" == "2" Set ("NetworkCategory=DomainAuthenticated"
) Else Set "NetworkCategory=Unknown"
@Echo NetworkCategory is %NetworkCategory%& Pause
I understand that this still requires the loading of another 'slow' built-in utility, but at least we can say that you will not suffer from PowerShell performance issues any longer!
Re: Powershell Performance Recommendations
Posted: 02 Sep 2021 14:14
by atfon
Thanks, Compo! I wasn't familiar with MSFT_NetConnectionProfile. That doesn't take care of all the other areas where I've had to call powershell, but it sure knocks this one out. This variation works for me:
Code: Select all
@echo off
setlocal enabledelayedexpansion
if exist "%__APPDIR__%wbem\WMIC.exe" set "wmic=%__APPDIR__%wbem\WMIC.exe"
set "netType.0=Public"
set "netType.1=Private"
set "netType.2=DomainAuthenticated"
for /f "skip=1 tokens=2 delims=," %%g in ('%wmic% /NameSpace:\\Root\StandardCimv2 Path MSFT_NetConnectionProfile get NetworkCategory /Format:csv') do for /f "tokens=*" %%h in ("%%g") do set "netType=!netType.%%h!"
echo Network Category: %netType%
Re: Powershell Performance Recommendations
Posted: 02 Sep 2021 20:40
by Compo
Why did you change the code I provided? Whilst I'm all for having a particular style etc. I don't understand why you'd use a variation which defines a minimum of four, possibly five variables and uses two for loops, over one which defines only one variable and uses one for loop.
Additionally, your variation has potential pitfalls. For instance, if %__APPDIR__%wbem\WMIC.exe does not exist, the code will still run using an empty variable, and generate an error messaage, leaving an undefined netType variable. You should also remember that as MSFT_NetConnectionProfile is only available in versions of Windows which has WMIC.exe built-in, in that location, there should be no need to check for its existence. After all if it doesn't exist, then MSFT_NetConnectionProfile will not be available either.
My code was designed to define the output as Unknown, if the system does not have WMIC.exe in the default location, or if MSFT_NetConnectionProfile is not available in the OS.
I also understand that your question was not necessarily specific to running this one command, but if you had several commands which could only be performed in PowerShell, you should not have chosen one which could be performed without it, as a basis for making your point. WMIC.exe is a slow command utility to run, especially on its first usage, so I could probably have leveraged WMI using something faster like cscript.exe instead.
Re: Powershell Performance Recommendations
Posted: 03 Sep 2021 05:42
by atfon
Hello Compo. Thank you for your multitude of critiques. As I've pointed out more than once, I'm still learning and welcome suggestions. I do prefer to learn from code and use my own style, but understand where I could improve it. As for:
...you should not have chosen one which could be performed without it...
As I mentioned in my post, I was not aware that MSFT_NetConnectionProfile existed and therefore was not aware that I could capture that information without the use of powershell. My searches of the internet did not reveal that information was available through WMI. There is no need to be rude about my ignorance compared to your own. This should be a supportive community.
Re: Powershell Performance Recommendations
Posted: 03 Sep 2021 06:42
by ShadowThief
atfon wrote: ↑03 Sep 2021 05:42
Hello Compo. Thank you for your multitude of critiques. As I've pointed out more than once, I'm still learning and welcome suggestions. I do prefer to learn from code and use my own style, but understand where I could improve it. As for:
...you should not have chosen one which could be performed without it...
As I mentioned in my post, I was not aware that MSFT_NetConnectionProfile existed and therefore was not aware that I could capture that information without the use of powershell. My searches of the internet did not reveal that information was available through WMI. There is no need to be rude about my ignorance compared to your own. This should be a supportive community.
Compo is notoriously grumpy, but you also have to remember that this community is geared towards experts, unlike
https://ss64.org/viewforum.php?f=2 or
https://www.reddit.com/r/batch, which are meant more for beginners.
Re: Powershell Performance Recommendations
Posted: 03 Sep 2021 07:25
by atfon
Thanks, Shadowthief. I do prefer learning from the Experts. Perhaps I need to remember one of my favorite quotes:
Better to remain silent and be thought a fool than to speak and to remove all doubt.
Author = ?
https://quoteinvestigator.com/2010/05/17/remain-silent/
Re: Powershell Performance Recommendations
Posted: 03 Sep 2021 07:46
by Compo
atfon wrote: ↑03 Sep 2021 05:42
Hello Compo. Thank you for your multitude of critiques. As I've pointed out more than once, I'm still learning and welcome suggestions.
It doesn't seem that you were very welcoming of my critique. I did not just make a blanket statement, I explained why I thought that your variation was not as good as the example I provided.
atfon wrote: ↑03 Sep 2021 05:42
I was not aware that MSFT_NetConnectionProfile existed and therefore was not aware that I could capture that information without the use of powershell. My searches of the internet did not reveal that information was available through WMI.
Please make your mind up! you said:
atfon wrote: ↑02 Sep 2021 14:14
That doesn't take care of all the other areas where I've had to call powershell, but it sure knocks this one out.
I simply made a startement that your example, considering "all the other areas where" you've "had to call powershell" was not a good one, because you did not have "to call powershell" on this occasion.
There was no need to be defensive, I was actually expecting you to provide another example where you were unable to retrieve the information using any method other than a "call" to "powershell", but based upon your response, your question now seems more like your issue was with this one particular task, and not really about performance issues with PowerShell at all.