Powershell Bug? - powershell

I observe a strange behaviour when calling an external script using & cmd /c myscript.cmd
When quite a lot of errors (let's say 200) are raised before the external script is called, the external call is not handled properly : the batch file is not executed at all.
When the number of error is not high (let's say 10), it is working normally (the external batch is called).
Is this a bug ? here is the PoC : change the value of $numberOfError to differents values (10, then 200) and see the output changing.
PoC
# Creation of a temporary Batch
Set-Content foo.cmd '#echo THE BATCH SCRIPT HAS BEEN CALLED !' -Encoding ASCII
$numberOfError = 10
# $numberOfError = 200 # if high value (sometimes only 40 is enough,
# other times > 140 do the trick)
for($i=0;$i -lt $numberOfError;$i++){
Rename-Item c:\not_existing.txt c:\blah.txt # just used to raise an Error
}
Write-Host "Before call"
# the below line won't be called if $numberOfError is >= 87
# (might be a higher value on some other machines maybe)
& cmd /c foo.cmd
Write-Host "Still there"
Here is the kind of output i am getting :
When $numberOfError = 10
[... Bunch of Error Messages ...]
Before call
THE BATCH SCRIPT HAS BEEN CALLED ! <------ THIS LINE CHANGE
Still there
When $numberOfError = 200
[... Bunch of Error Messages ...]
Before call
Still there
Please let me know if this is a known powershell bug, i know i could handle errors but this behaviour don't seems normal to me.
P.S: Tested only with Powershell v2.0 binaries.

Related

How should I write a Powershell script to execute a single program on multiple files?

I'm using Kalles' Fraktaler on Windows 10 to render images of the Mandelbrot set. Bundled with KF is a program to take a single parameter file and beak it into multiple tiles for easier rendering.
The output for the tiling program is multiple files with the following naming scheme: name-0000-0000.kfr, name-0000-0000.kfs, where the name can be anything and the numbers increment as needed.
The .kfr files are the parameter files.
The .kfs files are the settings files.
After I have these generated parameter and setting files, I can execute KF on the command line with the following arguments:
kf.exe -s name-0000-0000.kfs -l name-0000-0000.kfr -p name-0000-0000.png
Doing this for every pair of parameter and setting files works perfectly fine, taking the input files and saving the render to name-0000-0000.png
I asked the developer for an example PowerShell script to automate the process for when there are dozens or more of the files that need to be rendered, and this is what he gave me. The script needs to be run from the same directory as the files are stored.
Get-ChildItem "." -Filter *.kfr |
Foreach-Object {
$kfr = $_.FullName
$kfs = $kfr.replace("kfr", "kfs")
$png = $kfr.replace("kfr", "png")
C:/path/to/kf.exe -s $kfs -l $kfr -p $png
}
Unfortunately, I've tried every variation of this script that I could think of, and nothing gives me any results. I have already allowed unsigned scripts to be run on my computer. I would greatly appreciate some help on this.
(PowerShell is nice and flexible - but only when you use it to invoke only PowerShell commands rather than running native executables. For example, to run a program in the current directory you need to prefix the program's name with ./ - ostensibly this is done for safety and I assume for similarity to Unix shells, but it's the first in a long list of gotchas for anyone wanting to use PowerShell for tasks that would be trivial in old-school batch files)
Anyway, you need to use Invoke-Command or Start-Process.
I've changed your script from using a piped expression into an easier-to-digest loop (and invoking .NET's Path.ChangeExtension directly because PowerShell's built-in string match-and-replace syntax is too arcane for me):
$kfrFiles = Get-ChildItem "." -Filter "*.kfr"
foreach ( $kfrFile in $kfrFiles ) {
$kfr = $kfrFile.Name
$kfs = [System.IO.Path]::ChangeExtension( $kfrFile.Name, "kfs" )
$png = [System.IO.Path]::ChangeExtension( $kfrFile.Name, "png" )
Start-Process -FilePath "C:\path\to\kfs.exe" -ArgumentList "-s $kfs", "-l $kf", "-p $png" -Wait
}
The -Wait option will wait for the kfs.exe program to finish before starting the next instance - otherwise if you have hundreds of .kfr files then you'll end-up with hundreds of kfr processes running concurrently.
I don't know how to allow concurrent processes but impose a limit on the maximum-number of concurrent processes in PowerShell. It is possible, just complicated.

Insert text into a file (.bat) as well as increase a number sequentially

For instance, I am creating reboot scripts for about 400 servers to reboot every night. I already have the task scheduler portion done with a script.
What I need is, how to insert "shutdown /r /m \servername-001 /f" into a file called "servername-001_Reboot.bat".
and in the same script change the 001 to 002 into the next batch file and so on and so forth.
Unless someone has a more efficient way of doing an automated reboot schedule.
Have a variable $ServerNumber = 1 and inside your for-loop just keep incrementing it.
The filename for the batchfile can be made like so:
$filename = "servername-$( "{0:D3}" -f $ServerNumber )_Reboot.bat"
(Read here to learn more about formatting numbers in powershell)
Any variable including a string, let's call it $str, can be piped to any file:
$str | Out-File "path/to/file/$filename"
use the -Append flag if you want to append data to the file if it already exists (as opposed to overwriting it).

Powershell fails to run multi-line commands from stdin?

I'm wanting to pass arbitrary scripts to Powershell via stdin.
(In practice, I'd like to avoid having to put the script into a temporary file, but for the purposes of this question I will pipe the contents of a file to powershell.)
So I'm doing something like so (in this example, from a Windows cmd shell):
type myfile.txt | powershell -
It works if myfile.txt contains something like this:
1..3 | % { $_ *2 }
echo done
(It outputs 2\n4\n6\ndone.)
However, if I split this first statement across multiple lines like so, then Powershell simply exists without generating any output at all:
1..3 |
% { $_ *2 }
echo done
This seems to fail for any multiline statement. For example, this also fails to produce output:
1..3 | % {
$_ *2 }
echo done
I'm surprised by this since each are legal Powershell scripts that would work normally if placed into a .ps1 file and run as normal.
I've tried various things including escaping the EOL using line continuation chars, to no avail. The same effect occurs if the parent shell is Powershell, or even Python (using subprocess.Popen with stdin=PIPE). In each case, Powershell exits without any error, and the exit code is 0.
Interestingly, if I run the following, only "before.txt" gets created.
"before" | out-file before.txt
1..3 |
% { $_ *2 }
"after" | out-file after.txt
echo done
Any ideas why Powershell would have trouble reading a multi-line command, if read from stdin?
I'm going to consider this answered by this:
How to end a multi-line command in PowerShell since it shows that an extra newline is required.
However, I'm going to raise this to MS as a bug since this should not be required when reading from a non-tty, or when -NonInteractive switch is specified.
Please vote on my bug report to the Powershell team.
This is not a complete answer, but from what I can tell, the problem has to do with the input being sent in line by line.
To demonstrate the line-by-line issue, I invoke powershell this way:
powershell.exe -command "gc myfile.txt" | powershell.exe -
vs
powershell.exe -command "gc myfile.txt -raw" | powershell.exe -
The first example replicates what you see with type, the second reads the entire contents of the file, and it works as expected.
It also works from within PowerShell if you put the script contents in a string and pipe it into powershell.exe -.
I had a theory that it had to do with line-by-line input lacking line breaks, but it's not so clear cut. If that were the case, why would the first option work but not the second (removing the line break splitting the single pipeline should have no effect, while removing the line break between the pipeline and the echo should make it fail). Maybe there's something unclear about the way powershell is handling the input with or without line breaks.

AgeStore Fails to Remove Expired Debug Symbol Files

I’m trying to use AgeStore to remove some expired symbol files. I’ve written a Powershell script in which the AgeStore command works sometimes, but, not always.
For example, my symbol store contains symbol files dating back to 2010. I’d like to clean out the “expired” symbols because they are no longer needed. To that end, I use the -date command line argument to specify “-date=10-01-2010”. Additionally, I use the “-l” switch to force AgeStore to
Causes AgeStore not to delete any files, but merely to list all the
files that would be deleted if this same command were run without the
-l option.
Here’s a snippet of the script code that runs…
$AgeStore = "$DebuggingToolsPath\AgeStore"
$asArgs = "`"$SymbolStorePath`" -date=$CutoffDate -s -y "
if ($WhatIf.IsPresent) { $asArgs += "-l" }
# determine size of the symbol store before delete operation.
Write-Verbose ">> Calculating current size of $SymbolStorePath before deletion.`n" -Verbose
">> $SymbolStorePath currently uses {0:0,0.00} GB`n" -f (((Get-ChildItem -R $SymbolStorePath | measure-object length -Sum ).Sum / 1GB))
Write-Verbose ">> Please wait...processing`n`n" -Verbose
& $AgeStore $asArgs
When the above code runs, it returns the following output…
processing all files last accessed before 10-01-2010 12:00 AM
0 bytes would be deleted
The program 'RemoveOldDebugSymbols.ps1: PowerShell Script' has exited
with code 0 (0x0).
I have verified that there are symbol files with dates earlier than “10-01-2010” in the symbol store. I’ve subsequently tried the same experiment with a different cutoff date, “11-01-2015” and the output indicates that there are several files it would have deleted, but, not those that are from 2010. I’m at a loss as to what may cause the discrepancy.
Has anyone tried to delete symbol files from a symbol store using AgeStore? If so, have you run into this problem? How did you resolve it?
I’ve tried to resolve this many different ways using AgeStore. For the sake of moving forward with a project, I’ve decided to rewrite the script to use the SymStore command with a delete transaction. Basically, I created a list of the debug symbol transactions that should be removed and wrote a loop that iterates over the list and deletes each entry one at a time.
Hope this is helpful for anyone who runs into the same problems.
EDIT: Per request....I cannot post the entire script, but, I used the following code in a loop as a replacement for the AgeStore command.
$ssArgs = ".\symstore.exe del /i $SymbolEntryTransactionID /s `"$SymbolStorePath`""
Invoke-Expression $ssArgs

Script for monitoring CPU

I need to create some kind of script/runnable file for monitoring my Freeswitch PBX on Windows Server 2012 that:
checks a number of calls each ~5s and then writes in into a file,
checks % of CPU usage at that point and also writes it (into second column).
For the first part, I figured out how to check for actual number of calls flowing through:
fs_cli.exe -x "show calls count" > testlog.txt
but I have to do this manually and it always overwrites the previous one. I need the script to do this automatically every 5s until I stop the script.
fs_cli.exe -x "show calls count" >> testlog.txt
(notice the additional >) will append text to the file instead of overwriting the file
You can write a loop using this kind of code in PS:
#never-ending loop, condition is always true
while($true) {
#run a command (fs_cli.exe -x "show calls count" >> testlog.txt)
#or maybe several
date
(Get-WmiObject Win32_Processor).LoadPercentage >> c:\cpu_usage.txt
#sleep for 5 seconds
Start-Sleep -Seconds 5
}