Powershell in Batch file: Errors and Commands not executing - powershell

Below you can find the content of the two example text files I will use, example1.txt and obf_example1.txt. The latter one contains the string of example1.txt at the end of the file but has some obfuscated strings before.
example1.txt:
adasdkasdaksdasdkjlasdjasndjasd.
obf_example1.txt:
ŠxpÃÒ²Ø-Gêÿ ój"f>ïí H€À(ø4$/+#6Ni9Pvü¶ |CF CÀ¾ý~ª-°à9ÉOÿ V[o¦.E…-Š ƒ9Ú\žê*D´ß()^“£¹ìÅjXÑÍ¥â(¨µ×d'«P|I*èSººº&)Ø|̉ òÔ®¥Ô$LÁ:9ŠLá{¶nZÒبNÙÀØŒ‹0õ´Sék›áÇÉîÆbËF§BЄƒöZKaÒR ²°ÅšDn?+¶()IªP›$ÇEv©¡k€[ßè¨×q-Ëk!µTóPA²—: A ?ÉEEEGÐJúÌ©ÒWµHB¡aäXû|ÓË BPÁwr„Ûi¥åܺÈQ÷ORàSb,Šv¢D ,Žb’(2 öb¢wtKzíĦ#ï¯u©²Ù aîR隬ëÌTbà÷¥3ÄtSGì´R$)X Šù
'¹¨D³ÞeOK3!{·‹¦cäиNÅô:Na1žAÇ1ø8 &Fuôë %¸T¯_òMå†C"ý¤F ™º„Iµºí4Ü¡ˆc!ì•+3 ‰‹M K#JÁ«8¢bsL†!Ù“à­šn·öMå•Œ&ýèvÀ}¨?¦hùÊò(É#Žf~5‰‘qØçþƒ‰Å²ÓÖÊJU•âNWÁ«L¼Y”$G¢ßè&§ÖÉØŒS‘WàË„°SØW Ð¨´_è%‚Å¢ø.ãÃð”#X^þ*1þ‚q85¡lÒ‚Ò>‘¸ÿ £ôQôz#ø¤ÎõÚªï|Xö%;åÍËûGú+îUƒö³‰›p U±Ò ðtÜGÜÿ  ð,åXÿ k8È I”ÿ “½¿Ð`¨u5=SÓqyFÈ É8ôã¨ð£è6’H#lÄI10‚Ö§ÑdµÖ?t¡]D†9Zj,¥EɺÜEq¤#,ìn—¢º‚´€bc·ú¨Lû£ÿ Ó×ÿÙ||adasdkasdaksdasdkjlasdjasndjasd.
When I ran the following powershell command for example.txt in a batch file, it works and I get the output of example.txt:
#echo off
for /f "delims=" %%a in ('powershell Get-Content .\example.txt') do set _output=%%a
echo %_output%
adasdkasdaksdasdkjlasdjasndjasd
Good so far.
However, when I ran the above powershell command for obf_example1.txt, it does not work and I get the following error message:
'¹¨D³ÃzeOK3!{·â?¹Â¦cäÃ?Â?¸Â?NÃ.ô:Na1žAÃ╬1ø8
The command "FuôëÂ" is either misspelled or could not be found.
The command "ýèvÃ?}¨?¦hùÃSÂ?ò" is either misspelled or could not be found.
Why? Never mind I thought: As I am only interested in the last n characters both in example1.txt and obf_example1.txt accordingly, my idea was to extract the last n characters and check if I can see the output of obf_example1.txt then. To check if my idea works, I run the following command for example1.txt to get the last 4 characters as an example:
#echo off
for /f "delims=" %%a in ('powershell $a=Get-Content .\example.txt; $a.substring^(0,$a.length-4^)') do set _output=%%a
echo.%_output%
It doesn't show me anything though. %_output% seems to be empty. How to fix that? And will the fixed version work for obf_example1.txt as well so that I get an output there instead of the above error message?

Apparently, the piece of text you are after is behind the ||.
With PowerShell you can easily get that by using
((Get-Content 'D:\Test\obf_example1.txt' -Raw) -split '\|\|')[-1]
Returns
adasdkasdaksdasdkjlasdjasndjasd
Isn't htis what you want?

You could try reading the last 4 bytes, if you really are taking text characters from what is clearly not a text file. (My guess is that it is text hidden inside a binary file, probably a graphic file).
#For /F Delims^=^ EOL^= %%G In (
'%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoP^
"$f=[IO.File]::OpenRead('C:\Users\Ferit\Desktop\obf_example1.txt');"^
"$f.Seek(-4,[System.IO.SeekOrigin]::End)|Out-Null;$buffer=new-object Byte[] 4;"^
"$f.Read($buffer,0,4)|Out-Null;$f.Close();"^
"[System.Text.Encoding]::UTF8.GetString($buffer)"')Do #Set "_output=%%G"
#Set _output 2>NUL&&Pause
Don't forget to modify the text file path, (on line 3), and the three instances of 4 if you want more or less bytes. The last line is included just to show you the output, (you would obviously replace that with your own code).

The following works for me to get the "clear-text" part after || (from your example):
for /f "delims=" %%a in (.\obf_example1.txt) do set "_output=%%a"
set _output
echo testing last 10: %_output:~-10%
set "_output=%_output:*||=%"
set _output
echo %_output%
(it might not work with different encodings of the text file)
(Consider Powershell - cmd has a limit on line length and can easily be overwhelmed)

Related

Why does Powershell get executed 2 or 4 times?

I am making a API for Batch. One of its functions is a colortext, which uses PowerShell (and findstr if PowerShell is not supported on the machine) to do its work. (It simply converts the batch color given, like 3C, converts it to PowerShell-friendly names, like DarkCyan and Red, and prints the text given in color using more things.)
However, when I try to set the foreground as F (White), for some reason it tries to execute it 2 or 4 times (depending if I have Delayed Expansion enabled or not).
It sometimes fails on the last run/try showing the same thing if the supposed %fcn% and %bcn% never were applied. (this also depends if I have Delayed Expansion enabled or not).
I only want this to execute one time (and not fail for whatever reason), but it's executing 2 or 4 times for some reason. How would I do/fix this program?
Here's the minimal code needed to reproduce this problem, assuming %bcn%, %fcn% and %text% are already set (let's say Cyan as %bcn% and White as %fcn%, and Should not happen as %text%):
#echo off
set bcn=Cyan
set fcn=White
set text="This should not work"
setlocal EnableDelayedExpansion
set script=write-host %text% -ForegroundColor %fcn% -BackgroundColor %bcn%
if EXIST colortest.ps1 ( del colortest.ps1 )
echo %script% >> colortest.ps1
#echo on
#powershell -executionpolicy remotesigned -file colortest.ps1
#echo off
The output of this becomes:
If I do a color that works (like CD), with the same text:
EDIT: Since no one seems to say "Hey it's working perfectly", I meant about the second bogus execution, I know this works fine, I'm just trying to get rid of the bogus second execution.
Here is the entire code of the batch file (save it as bapi.bat and try to run "bapi colortext "This should not work" BF") in a pastebin:
http://pastebin.com/WyayVUVS
The problem can't be reproduced with the posted batch code and the values for the environment variables.
However some suggestions as partly also posted by aschipfl in his comment.
1. Deletion of a single file
The deletion of a single file can be done with either
if exist colortest.ps1 del colortest.ps1
or with
del colortest.ps1 2>nul
The first command line checks first if the file to delete exists and runs command DEL only if the file really exists.
The second command line runs the command DEL and redirects an error message written to handle STDERR to device NUL to suppress it. Command DEL outputs an error message if the file to delete does not exist at all.
On running just a single command after an IF or in a FOR loop it is really not necessary to write this command line in round brackets which define a command block. FOR and IF are designed for execution of a single command and using ( ... ) which defines a command block is just an extension of Windows command processor to be able to run multiple commands where a single command is expected by design.
2. Redirection to file with overwriting existing file
It is possible here to use just > instead of >> to create or overwrite colortest.ps1. This avoids the need to separately delete the file before.
See also the Microsoft article Using command redirection operators.
3. Space character between output text and redirection operator
On the command line
echo %script% >> colortest.ps1
there is a space character between environment variable reference %script% and redirection operator >>. This space character is also output by command ECHO and therefore also written into the file as trailing space.
This does not matter here, but often trailing spaces are not wanted in produced file. One solution is removing the space character and use:
echo %script%>> colortest.ps1
But this can result in an unexpected behavior if the string of environment variable script ends with a space and a single digit number in range of 1 to 9 as this results after preprocessing this command line before execution in 1>> colortest.ps1 or 2>> colortest.ps1, ... which is a redirection of handle 1 to 9 to file colortest.ps1 instead of printing 1 to 9 to handle STDOUT and finally to the file.
The solution is writing the redirection first and next the command
>>colortest.ps1 echo %script%
or use delayed expansion which would be here even better in case of script PowerShell script line contains special characters.
echo !script!>>colortest.ps1
The space character between >> and file name colortest.ps1 is ignored by Windows command interpreter.
4. Quoting parameter strings with special characters
The environment variable text could hold a text which requires double quoting this parameter string for correct processing by Windows command interpreter and by PowerShell. A space character (delimiter on command line) and the characters &()[]{}^=;!'+,`~<>| require often enclosing the entire parameter string in double quotes for being interpreted completely as literal text.
set "script=write-host "!text!" -ForegroundColor %fcn% -BackgroundColor %bcn%"
See also answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? why set "script=script line" is used instead of just set script=script line and why it does not matter how many double quotes are specified in the script line on assigning it to the environment variable.
5. Double quotes to output in text in PowerShell script file
To output also text containing 1 or more double quotes by the PowerShell script it is necessary to escape each double quote character with one more " before writing the text string into the script file colortest.ps1.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "bcn=Cyan"
set "fcn=White"
set "text="This should not happen^^!""
set "text=!text:"=""!"
set "script=write-host "!text!" -ForegroundColor %fcn% -BackgroundColor %bcn%"
echo !script!>colortest.ps1
echo on
#powershell -executionpolicy remotesigned -file colortest.ps1
#echo off
endlocal
It can be seen here on this example that with delayed expansion already enabled on definition of text with a string containing also an exclamation mark to output as character additionally to the also to output two double quotes that the exclamation mark must be escaped with two caret characters ^^ for assigning the exclamation mark as literal character to environment variable text. That would not be necessary on definition of text before enabling delayed expansion.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "text="This should not happen!""
setlocal EnableDelayedExpansion
set "bcn=Cyan"
set "fcn=White"
set "text=!text:"=""!"
set "script=write-host "!text!" -ForegroundColor %fcn% -BackgroundColor %bcn%"
echo !script!>colortest.ps1
endlocal
echo on
#powershell -executionpolicy remotesigned -file colortest.ps1
#echo off
endlocal
For details about the commands SETLOCAL and ENDLOCAL see this answer which explains in detail how these two commands work.
This is because, for some random reason which didn't happen to the rest, the call command executed 2 times, the second without setting any %fcn% and %bcn% parameters, when something like call :label was used.
However, this does not happen with goto label.

How to write STDOUT/STDIN via RedMon/cmd.exe to file?

I am trying to redirect a PS output to a file and process it further.
For this I am using the Printer Port Redirection RedMon which is sending the output to CMD.exe
C:\Windows\system32\cmd.exe
As arguments I expected that something like the following should work, but it does not. "%1" contains the user input for filename.
/c >"%1"
or
/c 1>"%1"
or
/c |"%1"
or
/c > "%1" 2>&1
What almost works if I send the output to a batch file which writes it then to file.
/c WriteOutput.bat "%1"
However, the batch file is somehow altering the file (skipping empty lines, and ignoring exclamation marks and so on...)
If possible I want to avoid a batch file. Is there a way to get it "directly" to a file?
Select "Print to FILE" in the printer options is not an option for me. I want the same end result but via cmd.exe being able to process it further.
Any ideas?
Edit:
Well, that's the batch file I used. It neglects empty lines and space at the beginning.
#echo off
setlocal
set FileName=%1
echo(>%FileName%.ps
for /F "tokens=*" %%A in ('more') do (
echo %%A>>%FileName%.ps
)
Well, so far I still haven't found a direct way to write STDIN via RedMon via CMD.exe to a file. As #aschipfl wrote, all the versions with for /F will skip lines and ignore certain characters.
However, with the following batch script (via RedMon) I end up with a "correct looking" file on disk.
C:\Windows\system32\cmd.exe /c WritePS.bat "%1"
"%1" contains the user input for filename without extension.
The Batch-File WritePS.bat looks as simple as this:
#echo off & setlocal
set FileName=%1.ps
more > "%FileName%"
However,
the resulting Postscript file is different from a file which I "Print to FILE" via the Postscript-Printer setup. I am pretty sure that all the printer settings which I can set are the same in both cases.
If anybody has an idea why there might be a difference, please let me know.

Remove Carriage Return from String Field in File Windows Command Line

I have a file that is ouput with | as the delimiter. However, one of the fields is a description field from the source system which contains carriage returns. This is an issue when trying to read the file as it breaks it on to a new line. What I would like to do is remove all CF/LF that aren't preceeded by a |.
I feel like this should be possible on command line but haven't been able to come up with it.
Sample data
|A|Testing CF/LF
This|CF/LF
Expected Output
|A|Testing This|CF/LF
#ECHO Off
SETLOCAL
SET "line="
(
FOR /f "delims=" %%a IN (q26895698.txt) DO (
CALL :generate "%%a"
)
)>newfile.txt
TYPE newfile.txt
GOTO :EOF
:generate
SET "line=%line%%~1"
IF "%line:~-1%"=="|" SET "line="&FOR %%x IN ("%line%") DO ECHO(%%~x
GOTO :eof
I used a file named q26895698.txt containing your data (such as it was) for my testing.
Produces newfile.txt
Can't help but get the impression that you'd be better off with SED thouh - google "GNU SED" for details...

how to rename files using command line

I want to rename 2 files "Data1.txt" to "Log1.rtf" and "Data2.txt" to "Log2.rtf"
I am currently using this code
#ECHO OFF
FOR %%I IN ("%~dp0*.txt") DO (
SET "ext=%%~xI"
SETLOCAL EnableDelayedExpansion
RENAME "%%I" "%%~nI!Log.rtf"
ENDLOCAL
)
But it give output "data1log.rtf" and "data2log.rtf"
of course:
RENAME "%%I" "%%~nI!Log.rtf"
But it give output data1log.rtf and data2log.rtf
btw. what do you try to achive with setlocal delayedexpansion and that single ! ?
EDIT: if you insist in doing it with for (because perhaps, you have many files to rename):
#echo off
setlocal enabledelayedexpansion
for %%i in (*.txt) do (
set file=%%i
set file=!file:Data=Log!
set file=!file:.txt=.rtf!
echo ren %%i !file!
)
the first set sets the variable file to the filename
the second one replaces Data with Log
the third one replaces .txt with .rtf
then rename original filename (%%i) to the changed filename (!file!)
(the echo is there to just show the command on screen instead of really renaming files. Good for testing. If you are sure, that the code does, what you want, just remove the echo)
the setlocal enabledelayedexpansion is needed to use a variable, that is changed inside a block (between ( and )) inside the same block. Therefore you have to use the variable as !var! instead of %var%
Note: of course this code could be improved, but as a beginner: keep it as simple (and readable) as possible. For example, this code will replace Data, but not data or DATA, it will not handle spaces in filenames, ...
It might work better if you used separate code to rename each of the files, or does that defeat the object?
this website shows how to rename a file using command line:
http://www.sevenforums.com/tutorials/56013-file-folder-rename-command-prompt.html
for %%a in ("%~dp0data*.txt"
) do for /f "delims=DdAaTt" %%b in ("%%~na"
) do echo ren "%%~fa" "log%%b.rtf"
It just iterates over the indicated list of files, and for each filename, uses the unnecesary characters as delimiters for an aditional for loop. That way only the number is left and used to rename the file.
Commands to rename are echoed to console. If output is correct, remove the echo command to rename the files.
User mv command to rename files in windows (Using CLI)
As mentioned in above answer, mv command can be used in windows as well to rename the filename. I tried rename and ren commands s suggested, but I was getting error: bash: ren: command not found.
Use below to change the filename:
mv filename new_filename

Search and replace with a batch file

I am writing a batch file script using Windows command and want to change each occurrence of some blank space with "," What is the simplest way to do that?
If your users are a list of words on one line in a text file, separated by spaces, eg:
one two three four
Create a batch file SpaceToComma.bat as follows:
#echo off
setlocal
for /F "tokens=* delims= " %%a in (%1) do #set data=%%a
echo %data: =,%
endlocal
Then run it, you'll get the words separated by commas. Is this what you want?
C:\>SpaceToComma.bat data.txt
one,two,three,four
If you have a multi-line file, then this will do it:
data.txt
one two three four
five six seven
SpaceToComma.bat
#echo off
setlocal
for /F "tokens=* delims= " %%a in (%1) do #call :processaline %%a
endlocal
goto :eof
:processaline
setlocal
set data=%*
echo %data: =,%
endlocal
goto:eof
Output
C:\>SpaceToComma.bat data.txt
one,two,three,four
five,six,seven
(There's probably a clever way of doing this without the subroutine, using the !data! syntax for delayed variable expansion, but I couldn't get it to work with the substitution syntax.)
If this is not what you want, then please explain and I can try to help.
(PS: I delight in using batch files where people insist it can't be done.)
You could download sed.exe from http://unxutils.sourceforge.net/ and run this command:
sed -e "s/ /,/" infile.txt >outfile.txt
Well it will depend a lot on how you are getting the data, but you may be able to finagle something with a For-Do construct. Make the field seperator be a space then build the string back in the do with a , between each token. Might I suggest a more robust scripting language? You should have VBScript on just about any relatively modern windows bow.