I'm running a number of scripts using PowerShell V2, and I have noticed a long pause when the console window first loads. What can I do to improve the performance of my scripts?
Thanks, MagicAndi
Other than minimize what you put in your various profile scripts (shown below) there isn't much you can do:
C:\PS> $profile | fl * -force
AllUsersAllHosts : C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
AllUsersCurrentHost : C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts : C:\Users\hillr\Documents\WindowsPowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\hillr\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
One way to check to see if profile scripts are causing the lag is to start powershell using the -noprofile option. If the startup time is different it would be due to your profile scripts. You can use a .NET stopwatch like so:
function TimeThis([scriptblock]$scriptblock, $msg)
{
if (!$stopWatch)
{
$script:stopWatch = new-object System.Diagnostics.StopWatch
}
$stopWatch.Reset()
$stopWatch.Start()
. $scriptblock
$stopWatch.Stop()
if ($msg -eq $null) { $msg = "$scriptblock" }
"Execution time: $($stopWatch.ElapsedMilliseconds) mS for $msg"
}
. TimeThis {Import-Module $Module -args ~\Pscx.UserPreferences.ps1}
While you could use Measure-Command, it doesn't show what is executed and you get no command output (only time in a very verbose fashion).
There used to be an issue in earlier CTPs where the installer wouldn't ngen the PowerShell assemblies and that could cause noticeable load time delays. However I'm pretty sure that has been fixed as of the final 2.0 install (and certainly with PowerShell built into Windows 7 and Windows Server 2008 R2). If the follow dir and its contents exist, you should be ngen'd:
dir 'C:\Windows\assembly\NativeImages_v2.0.50727_32\Microsoft.PowerShel#' -r
Tracking down a performance issue like this can be tricky, but there are a few things you can do to improve / fix things.
First off, starting PowerShell cold versus warm. At least on my workstation, the first time I run PS in the morning, it takes a bit longer to launch than subsequent times. Is there a way you can keep it warm to minimize the load times?
Second, use a tool like Process Monitor from the fine folks working for Windows Sysinternals. Set it to monitor the powershell.exe process and see what it is doing that is taking so long. For me, I have a number of mapped network drives and shared scripts that get sourced from the network. In my testing, I measured about a two second delay in starting per remote script I was loading.
PowerShell does need to load a bunch of resources from disk into memory, so it should go without saying that having your I/O system perform optimally will help as well. Defrag, make sure you have ample free RAM, etc. It even queries quite a bit from the registry so you may want to ensure your registry is completely defragged - though that is quite a long shot.
It may be completely unrelated but I have once had a massive pause during powershell startup.
It was somehow related to the fact that my laptop was in a domain, I then hibernated it and started it again when the laptop was not in the domain anymore. I looked at the startup with dottrace and could only see that somewhere in the initialization of Providers the code got stuck.
Restarting the machine helped in this case. Also it doesn't always happen (in fact, only once so far).
use inline C# speedup x100 max
Add-Type -Language CSharpVersion3 #"
"#
Add-Type #"
"#
if may not use -TypeDefinition #"
use 32bit powershell
speedup x1,5
ps-run.cmd :
SET PS32=%windir%\SysWOW64\WindowsPowerShell\v1.0\powershell
%PS32% .\%*
Related
Edit: I've been reading about Windows debugging. It's pretty complicated. Can I use that find out what's going on when I execute those commands?
I posted a question about some PowerShell code, in which every access of the recycle bin object is taking about 3 to 4 seconds. Some people commented that they ran the code and those actions reported taking zero seconds. So the code is okay, but something is slowing down the process on my computer. This is serious because I need to do that operation over 17,000 times, which adds up to over 14 hours.
I wondered if Event Viewer could help me see what's going on. I've never used it before, but read up on it and created three custom views for all event levels in:
Windows Logs
Applications > SentinelOne (my Internet security software)
Applications > PowerShell
When I run the code, none of those logs adds any entries at all.
The PowerShell code that is taking about 3 or 4 seconds is, after setting:
$oShell = New-Object -com shell.application
$ssfBitBucket = 10
$oRecycleBin = $oShell.Namespace($ssfBitBucket)
both:
echo $oRecycleBin.Items().count
and
$oRBItem = $oRecycleBin.Items().Item(0)
The context of those commands is in the other question.
How can I find out what my computer is doing when I execute those commends?
I'm trying to create a native, global, focus-independent hotkey control for incrementing/decrementing/mute-toggling system volume on Windows, specifically W10, though I expect whatever solution we find will likely work back through 7 and 8/8.1 as well.
I have found this - How can I mute/unmute my sound from PowerShell - and it works a treat, from within a PowerShell window. Ok, but I need this Type to be persistent and global then?
I then created three files, -.ps1, +.ps1, and 0.ps1, which include the entire type definition from the linked post, and then a one liner each, as follows:
[Audio]::Volume = [Audio]::Volume - .2
[Audio]::Volume = [Audio]::Volume + .2
[Audio]::Mute = [Audio]::Mute -bxor 1
Technically, all that works, but running each one pops open a PS window for 50 milliseconds or so. That's ugly, but maybe unavoidable.
Then I found this, - How to run a PowerShell script without displaying a window? - to use PSRun.exe. Turns out that in no case could I get that to successfully execute any of these scripts. I used shortcuts (.lnk) with arguments and .cmd files, and only got compilation errors.
So I tried this - https://www.faqforge.com/windows/how-to-execute-powershell-scripts-without-pop-up-window/ - using a VBS helper to hide the window. That works too, but I'd rather not use VBS if possible.
I then created a folder, %homedrive%\Users\\AppData\Roaming\Microsoft\Windows\Start Menu_hotkeys, and put one shortcut each to the .ps1 files, and assigned Alt-F6, Alt-F7, and Alt-F8 to the shortcuts.
When I run one of the shortcuts by GUI clicking, it takes about 100 milliseconds for either the .vbs or the .ps1 directly. However, when running either shortcut via hotkey, it takes more than a second!
I imagine there might be two (or more) solutions:
Can I increase the performance of a Windows shell hotkey that runs a shortcut to a script file? I realize that call stack looks silly long for something that seems like it should be so simple of a task.
OR
Can I create a persistent PowerShell window and run scripts into it by use of a global, focus-independent hotkey?
I'd even entertain building a TSR that does nothing but silently awaits hotkeys for volume control, but that seems less "nice" than working this out with PowerShell.
And before you ask, it's not a performance issue from this hardware, I'm running W10x64 on an i7-7700K with 16GB of RAM and a 128GB M.2. Running 40 Firefox tabs and 25 applications gets me to about 20% CPU use and 40% RAM use.
Feel free to slap me around if this question already has a solid, functional answer and my Google-Fu just didn't find it. My searches turned up things from across the last 5 years, but nothing conclusive or properly functional.
I am trying to create a tracking application to track the amount of time I spend on Gaming or web activities. One of the task is to get the time an application or process has been run in Windows system. This can be stored in some database and will later be accessed by my Java program Need help obtaining this information programmatically.
You can use powershell to find out these :
New-TimeSpan -Start (get-process "outlook").StartTime
I am trying to do my first script. To simply get PowerShell to pull up a script typed up in notepad and saved as a .ps1 file titled "test" (have also tried Script, but know names have nothing to do with it):
Write-Host "Hello, World!"
In PowerShell I am typing
& "C:\Scripts\test.ps1"
As well as
./test.ps1
And am only met with this:
./test.ps1.txt : The term './test.ps1.txt' is not recognized as the name of a
cmdlet, function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ ./test.ps1.txt
+ ~~~~~~~~~~~~~~
+ CategoryInfo: ObjectNotFound: (./test.ps1.txt:String) [], CommandNotFoundException
Have tried renaming the file within PowerShell with
PS C:\Scripts> Rename-Item test.ps1.txt test.ps1
I have switched between RemoteSigned and Unrestricted, I have tried a code including executionpolicy bypass (I do apologize, I closed my window without writing that one down). As far as I know everything is up to date and I am running Windows 10, Windows PowerShell, and regular Windows Notepad.
First, I'd HIGHLY recommend using the Windows PowerShell ISE for writing scripts. It's free, and provides a pretty decent console/editor experience, given that it's free (there are allegedly better ones out there, but this has always done just fine for me). I use Visual Studio for other stuff, and while it is an EXPONENTIALLY better product (and should be), the PowerShell ISE is pretty feature-rich.
Next, if you're just getting started, you should check out Don Jone's "Learn PowerShell 3.0 in a Month of Lunches" book. It's two versions behind the most current, however, all of the information is still relevant, and once you've finished the book, you'll be able to seek help for anything else pretty easily on your own. It covers all the basics, and is a very good first step to learning the language.
Now, to answer your question: PowerShell scripts commonly have the .ps1 file extension. Other extensions are generally used for modules (.psm1) or other helper content that Windows PowerShell leverages. For most things, you'll stick to .ps1, and when you've reached a point where you start needing the other extensions, I suspect you will have no problems identifying which ones you need.
There are two ways generally call a PowerShell script. The first is from a normal command prompt, and telling PowerShell to execute your script. This is shown below:
powershell.exe -File MyScript.ps1
There are some additional parameters that I'd recommend you use, but usage is dependent on your requirements. Here's what I usually tag on mine:
powershell.exe -NoProfile -ExecutionPolicy RemoteSigned -File MyScript.ps1
This will tell the PowerShell process to ignore any PowerShell profiles you have set up, which is ideal if you have a bunch of stuff in your profile script that does things like read console input (for your current situation, I'm going to assume you don't, but you may in the future). The other is that ExecutionPolicy one: RemoteSigned will tell PowerShell to basically ignore anything that's been downloaded from the interwebs, but allow anything originating inside your network to run free. Probably not the best practice, but this isn't a TERRIBLE policy if you can trust that your script repository is secured. If not, then go for something tighter than this (you can read up on execution policies by typing "Get-Help about_Execution_Policies" in the PowerShell prompt, or by visiting the TechNet page about them -- the content should be similar if not identical).
The second way is from inside of a Windows PowerShell script. It's actually much easier to do. Note that you must set your execution policy to something that will allow scripts to run, but thereafter, you're smooth sailing.
. .\MyScript.ps1
This is called "dot-sourcing" your script. The advantage of doing this from within Windows PowerShell is that if you've got something like a script full of functions, they get added to the current scope (Get-Help about_Scopes), which means they're now available in your current session. A good example would be defining a function called "Test-DomainConnection" in a script you distribute with your main script: You'd dot-source the script that is distributed with the main one (this is done usually when you separate your "standard" PowerShell functions from your main script), and then use the functions in the main script. There are pros and cons to this approach, but it seems to be generally recommended (there may be some community extensions out there that remove the need to manage this manually).
For additional information, you can call Get-Help about_Scripts from inside Windows PowerShell. Because you're using Windows 10, you may need to run Update-Help from an administrative PowerShell window before the help content is available on your local system.
If you have any more questions, feel free to message me :) I've been doing PowerShell for a while and may be able to help out.
Powershell processes in order (top-down) so the function definition needs to be before the function call:
I've tried a few different solutions but haven't had any that work. I am not use to batch scripting, so this has been quite trivial for me.
Right now, I have a script in Linux that handles the execution of services in synchronous order. They depend on one another and require the other one to be completely started before they can be executed.
I am using the following line to deal with this:
grep -qi 'Service has started.\|error' <(tail -f "/opt/app/log/daemon.log")
Works great. However, this also needs to work in Windows. I've looked into using the GNU utils but I haven't really looked into their licensing, which could pose a problem. Plus, I would like to do this natively in the Windows CL.
Cheers,
Chris
P.S.
I am looking for a platform INDEPENDENT solution. Cygwin is not an answer.
You should use native Windows "dependency" of services upon one another. Use regedit.exe or sc.exe config to introduce dependencies. This way, you can leave the service startup as automatic and they will only start executing once all services this one is dependent upon has reported their condition as "started".
If you're wanting to do this natively in Windows, 'the Windows way', you'll want to be using the *-Service cmdlets (e.g. Get-Service, Stop-Service, Start-Service and Restart-Service) in PowerShell.
I'll admit, I'm not a linux user, but I assume that you checking the status of a service after starting it?
On Windows, in a PowerShell script, you'd want to do something like the following (I'm specifically picking on the Volume Shadow Copy service, because reasons):
Start-Service -Name VSS
While ((Get-Service -Name VSS).Status -ne 'Running') {
Start-Sleep -Seconds 2
}
# Start next service or continue with script here.
Apologies if this is well off base from what you're looking for. I'm just approaching this question as a Windows admin from the perspective of how I would achieve the goal.