Any advice or assistance would be greatly appreciated.
I am writing a simple base64 encoder for windows so I can encode strings faster when required.
The encoding happens in CMD and then the script opens a PowerShell in order to cat out the encoded string in the terminal.
For easier reading I am trying to change the color of the string that is retrieved with cat but am having a hard time achieving this. Here is a snippet of the code that is problematic:
certutil -encode data.txt tmp.b64 && findstr /v /c:- tmp.b64 > secret.b64
powershell.exe -Command "Write-Host Your secret is: -ForegroundColor Green";cat secret.b64
PAUSE
When the information is retrieved; "Your secret is: " is green as intended in the code but I cannot seem to find a way to color the "cat secret.b64" command.
As far as the original request goes, I suppose you wanted something like:
powershell -command "$i = cat secret.b64; Write-Host Your secret is: $i -ForegroundColor Green"
You can however skip powershell and do batch-file only.
#echo off
for /F %%a in ('echo prompt $E ^| cmd') do set "cl=%%a"
(certutil -encode data.txt tmp.b64 && findstr /v /c:- tmp.b64)>secret.b64
set /p secr=<secret.b64
echo Your secret is: %cl%[92m%secr%%cl%[0m
pause
Do it entirely in PowerShell; PS can call any console executables that CMD can. To take the stdout of a console executable and use it as string input to a PS cmdlet or function, either enclose the entire console executable's command in parens (e.g., $foocontent = (cat.exe foo)), or pipe it to a parameter of the PS cmdlet/function that accepts pipeline input (e.g., cat foo | Format-Table)
(Note that in PowerShell under Windows, cat is generally aliased to the PowerShell cmdlet Get-Content.)
Related
I was trying to use the return from myPowershellScript.ps1 to use as a variable in my batch file.
myPowershellScript.ps1
function GetLatestText
{
return "Hello World"
}
I was trying to use the For /F function. There may be a better way.
myBatch.bat
for /f "delims=" %%a in (' powershell -command "\\Rossi2\Shared\myPowershellScript.ps1" ') do set "var=%%a"
echo %var%
Desired output, would be to have 'Hello World' output in the cmd window.
I was trying to use the batch file as some old processes use them. For newer processes I do everything in PowerShell and it works fine.
The current output is blank.
Your syntax for trying to capture output from a PowerShell script from a batch file is correct (assuming single-line output from the script),[1] except that it it is more robust to use the -File parameter of powershell.exe, the Windows PowerShell CLI than the -Command parameter.
See this answer for when to use -File vs. -Command.
Your problem is with the PowerShell script itself:
You're defining function Get-LatestText, but you're not calling it, so your script produces no output.
There are three possible solutions:
Place an explicit call to Get-LatestText after the function definition; if you want to pass any arguments received by the script through, use Get-LatestText #args
Don't define a function at all, and make the function body the script body.
If your script contains multiple functions, and you want to call one of them, selectively: in your PowerShell CLI call, dot-source the script file (. <script>), and invoke the function afterwards (this does require -Command):
for /f "delims=" %%a in (' powershell -Command ". \"\\Rossi2\Shared\myPowershellScript.ps1\"; Get-LatestText" ') do set "var=%%a"
echo %var%
[1] for /f loops over a command's output line by line (ignoring empty lines), so with multiline output only the last line would be stored in %var% - more effort is needed to handle multiline output.
You can combine the batch and the powershell in single file (save this as .bat ):
<# : batch portion
#echo off & setlocal
for /f "tokens=*" %%a in ('powershell -noprofile "iex (${%~f0} | out-string)"') do set "result=%%a"
echo PS RESULT: %result%
endlocal
goto :EOF
: end batch / begin powershell #>
function GetLatestText
{
return "Hello World"
}
write-host GetLatestText
I'd like to learn to execute a PowerShell command from another shell or language, e.g. Python os.system(). What I want to achieve is the following:
Execute the PowerShell command
Tee the output to both the console and a file
Return the command exit code
I think this gives an idea of what I would like to achieve, assuming to use cmd.exe as the caller environmnet:
powershell -NoProfile -command "& { cat foo.txt | Tee-Object ps-log.txt; exit $LASTEXITCODE }"
echo %errorlevel%
There are some problems here. First, I cannot use quotations in the command, e.g. :
powershell -NoProfile -command "& { cat `"foo bar.txt`" | Tee-Object ps-log.txt; exit $LASTEXITCODE }"
The cat argument seems to be passed unquoted and so cat looks for a 'bar.txt' parameter.
I think $LASTEXITCODE is expanded soon, that is before cat is executed.
& is inconvenient to use, because it does not accept a single command line string including arguments. An alternative to & is iex, however I cannot use it from cmd.exe. In fact:
powershell -NoProfile -command {iex cat foo.txt}
returns:
iex cat foo.txt
From cmd.exe, use the following (-c is short for -Command):
C:\>powershell -NoProfile -c "Get-Content \"foo bar.txt\" | Tee-Object ps-log.txt; exit -not $?"
There's no reason to use & { ... } in a string passed to -Command - just use ... instead.
Escape embedded " chars. as \" (PowerShell (Core) 7+ also accepts "").
Alternatively, as marsze's helpful answer points out, you can use '...' (single-quoting) inside the "..." string passed to -Command / -c, assuming that no string interpolation is required.
Since only PowerShell-native commands are involved in the command (on Windows, cat is simply an alias of Get-Content), $LASTEXITCODE is not set, as it only reflects the exit code of external programs. Instead, the automatic $? variable applies, which is a Boolean that indicates whether any errors were emitted by the commands in the most recently executed pipeline.
Negating this value with -not means that $true is converted to $false and $false to $true, and these values are converted to integers for the outside, with $false mapping to 0 and $true to 1.
Powershell supports single quotes, which saved me in such situations quite a lot of times. The good thing about it: They are unambiguous and easy to read. But mind that variable expansion won't work inside single-quoted strings.
powershell -NoProfile -command "cat 'foo bar.txt' | tee ps-log.txt"
Apart from that, have a look at the useful advice in mklement0's answer.
This question already has an answer here:
Displaying SET variable
(1 answer)
Closed 3 years ago.
I am attempting to pass a number of variables processed by my batch file to a Powershell script. The problem I face is that firstly the entire results from the batch file come up in command prompt and next to the variables I intend to pass are not passed to the Powershell Script. Additionally, the variable I have to output the contents of the log file in just send the command back to the screen.
I have tried the following links and these links got me as far as I am now:
Batch file to execute a Powershell script
Pass variable from batch to powershell
Pass parameter from a batch file to a PowerShell script
Pass batch variables with spaces in them to powershell script?
Batch File side
set LOG_FILE = "GDGAGnklasj;oks;fk;dkf lkl;"
set oName = Name
set oStart = "%YYYY%%MM%%DD% %TIME%"
set oStatus = 0
set oEnd = "%YYYY%%MM%%DD% %TIME%"
set oDateRan = %YYYY%%MM%%DD%
set oLog =for /f "delims=" %%i in (%LOG_FILE%) do set content=%content% %%i
echo Updating Database >> %LOG_FILE% 2>&1
cmd /S powershell.exe -ExecutionPolicy Bypass -File "C:\Reporting\updateTool.ps1" "%oName%" "%DateRan%" "%oStart%" "%oEnd%" "%oStatus "%oLog%
PowerShell Script
param (
[string]$oName
)
"This is $oName"
My intent is to set the variables within the batch file then send them to Powershell for processing.
Be very careful of spaces.
set oName=taco
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '.\ScriptName.ps1' -oName '%oName%' "
Oh Easy-Peasy, I do this for my Power shells that we need CMD wrappers for quite a bit.
I have to run to the train so this is going to be a bit meh at the moment I will firm it up in a bit, right now just going to paste in some example code so I can make it your code
Okay, what, umm, what did you intend for this Particular code to.l do ? I can't seem to figure out what you were intending with this, is it just some dummy code?
set oLog =for /f "delims=" %%i in (%LOG_FILE%) do set content=%content% %%i
echo Updating Database >> %LOG_FILE% 2>&1
Okay on further review I think you want to read the log into a couple of sttring variables in CMD, then use one of them in your call of the script..... but, why?
The strings will append to each other and you will be limited to 8191 characters max, and PowerShell can easily read the content of the log file because you pass the name to Powershell.
That seems like a better plan, no?
All your code where you have YYYY MM DD those are variables you will need to define before using, not sure if that is understood if so all good.
.CMD Script:
#(
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OFF
SET "_PSScript=C:\Reporting\UpdateTool.ps1"
REM SET "_DebugPreference=Continue"
SET "_DebugPreference="SilentlyContinue"
SET "_LOG_FILE=GDGAGnklasj;oks;fk;dkf lkl;"
SET "_oName=Name."
SET "_oStart=%YYYY%%MM%%DD% %TIME: =0%"
SET /a "_Status=0"
SET "_oEnd=%YYYY%%MM%%DD% %TIME: =0%"
SET "_oDateRan=%YYYY%%MM%%DD%"
)
SET "_PSCMD=Powershell "%_PSScript%" -DebugPreference "%_DebugPreference%" -LOG_FILE "%_LOG_FILE%" -oName "%_oName%" -oStart "%_oStart%" -Status %_Status% -oEnd "%_oEnd%" -oDateRan "%_oDateRan%" "
%_PSCMD% 2>&1 >> "_LOG_FILE"
PS1:
## Script: UpdateTool.ps1
#
param(
[String]$LOG_FILE = 'c:\admin\default.log',
[String]$oName = 'default name'
[String]$oStart = $(Get-date -F "yyyyMMdd HH:mm:ss.ms"),
[Int]$oStatus = 0,
[String]$oEnd = $(Get-date -F "yyyyMMdd HH:mm:ss.ms"),
[String]$oDateRan = $(Get-date -F "yyyyMMdd"),
$DebugPreference = "SilentlyContinue"
)
I have a simple question. I would like to assign a command to a variable and execute it with extra parameters, like:
C:\test.exe /q /v
But when I do:
$path=C:\test.exe
$path /q /v
It doesn't work.. Any idea?
The most canonical way to do this is to use the call operator on the variable that contains the "name" of the command e.g.:
& $path /q /v
This is actually required when the path to the command (ie native exe) contains spaces.
Command as string:
With Invoke-Expression cmdlet you execute an arbitrary string as a piece of code. It takes the string, compiles it, and executes it.
So you do:
$path='C:\test.exe';
Invoke-Expression "$path /q /v";
As a side note: When you do $path=C:\test.exe without the quotes, you are actually assigning the STDOUT of test.exe to the variable $path. You have to make clear to PowerShell that it is actually a string you wish to execute later.
Command as script object:
If you are concerned with performance, you could also try converting your command to a compiled scriptblock, and execute it with the & call operator.
$path='C:\test.exe';
$cmd = [scriptblock]::Create("$path /q /v");
& $cmd;
I would like to output variables and values out in a PowerShell script by setting up flags and seeing the data matriculate throughout the script.
How would I do this?
For example, what would be the PowerShell equivalent to the following PHP code?
echo "filesizecounter: " . $filesizecounter
There are several ways:
Write-Host: Write directly to the console, not included in function/cmdlet output. Allows foreground and background colour to be set.
Write-Debug: Write directly to the console, if $DebugPreference set to Continue or Stop.
Write-Verbose: Write directly to the console, if $VerbosePreference set to Continue or Stop.
The latter is intended for extra optional information, Write-Debug for debugging (so would seem to fit in this case).
Additional: In PSH2 (at least) scripts using cmdlet binding will automatically get the -Verbose and -Debug switch parameters, locally enabling Write-Verbose and Write-Debug (i.e. overriding the preference variables) as compiled cmdlets and providers do.
Powershell has an alias mapping echo to Write-Output, so you can use:
echo "filesizecounter : $filesizecounter"
PowerShell interpolates, does it not?
In PHP
echo "filesizecounter: " . $filesizecounter
can also be written as:
echo "filesizecounter: $filesizecounter"
In PowerShell something like this should suit your needs:
Write-Host "filesizecounter: $filesizecounter"
Write-Host "filesizecounter : " $filesizecounter
By far the easiest way to echo in powershell, is just create the string object and let the pipeline output it:
$filesizecounter = 8096
"filesizecounter : $filesizecounter"
Of course, you do give up some flexibility when not using the Write-* methods.
echo is alias to Write-Output although it looks the same as Write-Host.
It isn't What is the difference between echo and Write-Host in PowerShell?.
echo is an alias for Write-Output, which writes to the Success output stream. This allows output to be processed through pipelines or redirected into files. Write-Host writes directly to the console, so the output can't be redirected/processed any further.
The Write-host work fine.
$Filesize = (Get-Item $filepath).length;
Write-Host "FileSize= $filesize";
It should also be mentioned, that Set-PSDebug is similar to the old-school echo on batch command:
Set-PSDebug -Trace 1
This command will result in showing every line of the executing script:
When the Trace parameter has a value of 1, each line of script is traced as it runs. When the parameter has a value of 2, variable assignments, function calls, and script calls are also traced. If the Step parameter is specified, you're prompted before each line of the script runs.
PowerShell has aliases for several common commands like echo. Type the following in PowerShell:
Get-Alias echo
to get a response:
CommandType Name Version Source
----------- ---- ------- ------
Alias echo -> Write-Output
Even Get-Alias has an alias gal -> Get-Alias. You could write gal echo to get the alias for echo.
gal echo
Other aliases are listed here:
https://learn.microsoft.com/en-us/powershell/scripting/learn/using-familiar-command-names?view=powershell-6
cat dir mount rm cd echo move rmdir chdir erase popd sleep clear h ps sort cls history pushd tee copy kill pwd type del lp r write diff ls ren
I don't know if it's wise to do so, but you can just write
"filesizecounter: " + $filesizecounter
And it should output:
filesizecounter: value
Try Get-Content .\yourScript.PS1 and you will see the content of your script.
also you can insert this line in your scrip code:
get-content .\scriptname.PS1
script code
script code
....