Simple PowerShell script refuses to write file when running from command line but works fine in ISE - powershell

So I have a pretty simple PowerShell script used to update a version number during a build.
$InputFile = 'D:\BuildAgent\work\c9716e2651305a2e\web\WEB-INF\classes\version.properties'
$OutputFile = $InputFile
Write-Host $('Updating "' + $OutputFile + '" to reflect version "2.10.0.51"')
(Get-Content $InputFile) |
Foreach-Object {
$_ -replace 'version.release\s*:.*','version.release: 2.10.0.51'
} |
Out-File $OutputFile
It works completely fine from within ISE, but when I run it from the command line with
powershell.exe -Command - < powershell2447437064467034590.ps1
or
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy ByPass
-Command - < powershell2447437064467034590.ps1
All this does though is blank out the file. How can this work fine from ISE but not from the command line?

"Windows Powershell does not load commands from the current location by default. If you trust this command, instead type ".\test.ps1"
-Windows Powershell
powershell.exe .\powershell2447437064467034590.ps1
I tested with Powershell command prompt and classic command prompt
For more information
Run from an elevated script or command, Powershell 3.0
Update-Help
Get-help about_Command_Precedence

I figured it out. I used tabs in the file to pretty print and format the text. Apparently that breaks it. If I copy and past it into ISE, it silently converts all the tabs into spaces which is why it worked there. Pretty surprising that the tokenizer doesn't treat all whitespace the same.

Related

Running a Powershell script from cmd

I'm trying to use a simple Port-Scanner as a PowerShell one-liner that looks like this:
1..1024 | % {echo ((new-object Net.Sockets.TcpClient).Connect("192.168.171.1",$_)) "Port $_ is open!"} 2>$null
It works perfectly in a PowerShell Window. But, if I try to start it from a Windows Command Window (CMD), I get the following error message:
Your quotes are conflicting. Try using:
powershell '1..1024 | % {echo ((new-object Net.Sockets.TcpClient).Connect("192.168.171.1",$_)) "Port $_ is open!"} 2>$null'
Unless you on PowerShellv2, why not simplify this. Use the built-in cmdlets.
powershell -Command "1..1024 | ForEach {Test-NetConnection 192.168.171.1 -Port $PSitem}"
Absolutely, PowerShell is cleaner, the present/future, and where you want to be, but you could do this VBScript as well.
VBS Script to Check Port Availability in Windows

Command to run PowerShell command from Windows CMD

Consider:
(Get-Content Rel_DDL.SQL) | ForEach-Object {
$_ -replace "SWIFT [\d\.]+", "SWIFT 2.4.0"
} | Set-Content Rel_DDL.SQL
The above PowerShell code replaces SWIFT 2.3.0 with SWIFT 2.4.0 in a SQL file, which when I run through PowerShell works fine.
I want to run the PowerShell command through Windows CMD, but I am getting errors.
You can use the Powershell.exe command in CMD Windows with the -command parameter. Did you try it?
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
If the value of Command is "-", the command text is read from standard input.
If the value of Command is a script block, the script block must be enclosed in braces ({}).
You can specify a script block only when running PowerShell.exe in Windows PowerShell. The results of the script block are returned to the parent shell as deserialized XML objects, not live objects.
If the value of Command is a string, Command must be the last parameter in the command, because any characters typed after the command are interpreted as the command arguments.
To write a string that runs a Windows PowerShell command, use the format: "& {}" where the quotation marks indicate a string and the invoke operator (&) causes the command to be executed.
Use the powershell command in that .bat script. I would not write to the same file as used for the input. Yes, I know this works because Get-Content reads the entire file, but it is not a good practice.
powershell -NoProfile -Command "(Get-Content Rel_DDL.SQL) |" ^
"ForEach-Object { $_ -replace 'SWIFT [\d\.]+', 'SWIFT 2.4.0' } |" ^
"Out-File -FilePath Rel_DDL2.SQL -Encoding Default"

how do I make it easy for my parents to run this Powershell command?

I am not a programmer and my parents' Windows 10 PC tends to loose its start menu and cortana processes, resulting in start menu not showing up at all when the start icon is clicked.
I made a quick search and found + tested this Powershell command and it worked:
Get-AppxPackage | % { Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppxManifest.xml" -verbose }
I wish to turn this command into a shortcut/batchfile that executes the command and restarts the PC whenever the desktop icon is double clicked, in order to avoid explaining to my parents what to do to fix the problem. Can any one help me out please?
Thank you in Advance.
you can encode the command and put the whole thing into a single batch file (no .ps1 necessary)
details here
https://blogs.msdn.microsoft.com/timid/2014/03/26/powershell-encodedcommand-and-round-trips/
or you can use this function
https://github.com/gangstanthony/PowerShell/blob/master/Encode-Text.ps1
first, either use Get-Content or Get-Clipboard (copy your whole script to the clipboard) to encode your desired script
PS> Encode-Text (Get-Clipboard | out-string)
RwBlAHQALQBBAHAAcAB4AFAAYQBjAGsAYQBnAGUAIAB8ACAAJQAgAHsAIABBAGQAZAAtAEEAcABwAHgAUABhAGMAawBhAGcAZQAgAC0ARABpAHMAYQBiAGwAZQBEAGUAdgBlAGwAbwBwAG0AZQBuAHQATQBvAGQAZQAgAC0AUgBlAGcAaQBzAHQAZQByACAAIgAkACgAJABfAC4ASQBuAHMAdABhAGwAbABMAG8AYwBhAHQAaQBvAG4AKQBcAEEAcABwAHgATQBhAG4AaQBmAGUAcwB0AC4AeABtAGwAIgAgAC0AdgBlAHIAYgBvAHMAZQAgAH0ADQAKAA==
then you can use that in your batch file like so
powershell -encodedcommand RwBlAHQALQBBAHAAcAB4AFAAYQBjAGsAYQBnAGUAIAB8ACAAJQAgAHsAIABBAGQAZAAtAEEAcABwAHgAUABhAGMAawBhAGcAZQAgAC0ARABpAHMAYQBiAGwAZQBEAGUAdgBlAGwAbwBwAG0AZQBuAHQATQBvAGQAZQAgAC0AUgBlAGcAaQBzAHQAZQByACAAIgAkACgAJABfAC4ASQBuAHMAdABhAGwAbABMAG8AYwBhAHQAaQBvAG4AKQBcAEEAcABwAHgATQBhAG4AaQBmAGUAcwB0AC4AeABtAGwAIgAgAC0AdgBlAHIAYgBvAHMAZQAgAH0ADQAKAA==
You could execute the PowerShell script via a batch file.
Batch file:
set powerscriptPath=C:\Example.ps1
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%powerscriptPath%""' -Verb RunAs}"
This will bypass the execution policies on the computer allowing the script to run in Administrator mode too. NOTE: You will need to edit the powerscriptPath to point to your PowerShell script location, I just used C:\Example.ps1 as an example.
You will want to add Restart-Computer -Force to the end of your PowerShell script to restart the computer
Get-AppxPackage | % { Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppxManifest.xml" -verbose }
Restart-Computer -Force
Make a bat file which executes powershell with that file. Then add a shortcut to the bat file
I am really unsure why you would run a batch file just to call a powershell script! Talk about hokey approaches to a non-problem.
To call a powershell script is really no different than calling a batch script:
It's simply path to PowerShell, and the script path as a parameter:
"%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe" "C:\users\austinfrench\desktop\example.ps1"
You can also use the exact same format as the target for a desktop shortcut.

Capturing different streams in file

I'm trying to capture the Verbose, Error and other streams of a PowerShell script in a file. This to monitor the output of my script.
The following code works fine:
$LogFile = 'S:\ScriptLog.log'
$ScriptFile = 'S:\TestieScript.ps1'
powershell -Command $ScriptFile *>&1 > $LogFile
However, the moment I try to put a space in one of the file paths, it's no longer working. I tried a lot of things, like double quotes, single quotes, .. but no luck.
To illustrate, the following code doesn't work:
$LogFile = 'S:\ScriptLog.log'
$ScriptFile = 'S:\Testie Script.ps1'
powershell -Command $ScriptFile *>&1 > $LogFile
One person in this thread has the same issue.
Thank you for your help.
You're trying to run a file whose name contains a space as a command without proper quoting, so you're most likely getting an error like this in your log:
The term 'S:\Testie' is not recognized as the name of a cmdlet, function, script file, or operable program.
Either add proper quoting (and the call operator &, because your path is now a string):
powershell -Command "& '$ScriptFile'" *>&1 > $LogFile
or (better) use the -File parameter, as #CB. already suggested:
powershell -File $ScriptFile *>&1 > $LogFile
which has the additional advantage that the call will return the actual exit code of the script.
Edit: If you want to run the command as a scheduled task you'll need to use something like this:
powershell -Command "& 'S:\Testie Script.ps1' *>&1 > 'S:\ScriptLog.log'; exit $LASTEXITCODE"
because the redirection operators only work inside a PowerShell process.
try using -file parameter:
powershell -file $ScriptFile *>&1 > $LogFile

Different behavior when running ps1 Powershell script with Invoke-Expression vs Powershell -File

This is a new question stemming from a previous post at :
Run Powershell script from inside other Powershell script with dynamic redirection to file
I am running:
$logStreams = "2>&1>"
$command = '"C:\myscript.ps1" $_logStreams "C:\outputlog.txt"'
iex "& $command"
I observed that calling my script with iex "& $ command" is different than running it using Powershel -File "C:\myscript.ps1".
Myscript.ps1 calls a function Download (with some params) which creates and fills up a file $File1 then a second file $File2 (also it generates a third file from the previous two ones).
Then, in the next line in myscript.ps1 after calling Download(), I call another function Cleanup($File1, $File2) which deletes $File1 and $File2. All this works flawlessly with Powershell -File "C:\myscript.ps1" however when using iex "& $command" as above the Cleanup function complains it cannot bind $File1 and $File2 because they are null !
It is like iex executed the Download and Cleanup functions in parallel (call Download, do not wait for it to complete -> immediately call Cleanup). Is that an expected behavior of iex or am I missing something basic here ?