Windows Batch File, Route Output of EXE called in Batch File - windows

In my batch file, I call a EXE and would like the output to be redirected to a file. In the PowerShell command line, it would look something like this:
prog.exe file.txt | Out-File results\results.txt -Encoding ascii
The above works in the command line. In my batch file, I have written it as this:
prog.exe file.txt | powershell -Command "Out-File results\file.txt -Encoding ascii"
When I run the batch file, the results file gets created but contains zero content. How can write this to behave like I need it too?

The following should work in a batch file:
prog.exe file.txt > results\results.txt
If you want to redirect both stdout and stderr use:
prog.exe file.txt > results\results.txt 2>&1

kichik's helpful answer shows you an effective solution using batch-file features alone.
Unless you have a need to create files with an encoding other than ASCII or the active OEM code page, there's no need to get PowerShell involved - it'll only slow things down.
That said, you can choose a different code page via chcp in cmd.exe, but for output to a file only 65001 for UTF-8 really makes sense, but note that the resulting file will have no BOM - unlike when you use Out-File -Encoding utf8 in Windows PowerShell.
If you do need to use PowerShell - e.g., to create UTF-16LE ("Unicode") files or UTF-8 files with BOM - you'll have to use $Input with a PowerShell-internal pipe in your PowerShell command in order to access the stdin stream (i.e., what was piped in):
prog.exe file.txt | powershell -c "$Input | Out-File results\file.txt -Encoding ascii"
Note that only characters representable in the active code page (as reflected in chcp) will be recognized by PowerShell and can be translated into potentially different encodings.
Choosing -Encoding ascii would actually transliterate characters outside the (7-bit) ASCII range to literal ? characters, which would result in loss of information.

Related

Output Filenames in a Folder to a Text File

Using Windows Command Prompt or Windows PowerShell, how can I output all the file names in a single directory to a text file, without the file extension?
In Command Prompt, I was using:
dir /b > files.txt
Result
01 - Prologue.mp3
02 - Title.mp3
03 - End.mp3
files.txt
Desired Output
01 - Prologue
02 - Title
03 - End
Notice the "dir /b > files.txt" command includes the file extension and puts the filename at the bottom.
Without using a batch file, is there a clean Command Prompt or PowerShell command that can do what I'm looking for?
In PowerShell:
# Get-ChildItem (gci) is PowerShell's dir equivalent.
# -File limits the output to files.
# .BaseName extracts the file names without extension.
(Get-ChildItem -File).BaseName | Out-File files.txt
Note: You can use dir in PowerShell too, where it is simply an alias of Get-ChildItem. However, to avoid confusion with cmd.exe's internal dir command, which has fundamentally different syntax, it's better to use the PowerShell-native alias, gci. To see all aliases defined for Get-ChildItem, run Get-Alias -Definition Get-ChildItem
Note that use of PowerShell's > redirection operator - which is effectively an alias of the Out-File cmdlet - would also result in the undesired inclusion of the output, files.txt, in the enumeration, as in cmd.exe and POSIX-like shells such as bash, because the target file is created first.
By contrast, use of a pipeline with Out-File (or Set-Content, for text input) delays file creation until the cmdlet in this separate pipeline segment is initialized[1] - and because the file enumeration in the first segment has by definition already completed by that point, due to the Get-ChildItem call being enclosed in (...), the output file is not included in the enumeration.
Also note that property access .BaseName was applied to all files returned by (Get-ChildItem ...), which conveniently resulted in an array of the individual files' property values being returned, thanks to a feature called member-access enumeration.
Character-encoding note:
In Windows PowerShell, Out-File / > creates "Unicode" (UTF-16LE) files, whereas Set-Content uses the system's legacy ANSI code page.
In PowerShell (Core) 7+, BOM-less UTF-8 is the consistent default.
The -Encoding parameter can be used to control the encoding explicitly.
[1] In the case of Set-Content, it is actually delayed even further, namely until the first input object is received, but that is an implementation detail that shouldn't be relied on.

Replace string with unicode in text file via Windows batch file

I have a file with this simple contents:
test.txt (ASCII encoded)
Baby, you can drive my :car:
Via a Windows batch file, I need to change :car: to 🚗 (https://unicode-table.com/en/1F697/)
I'd like to avoid installing new software on the client's server, so I'm trying to do it using PowerShell or something native.
So far I've tried a ton of suggestions (https://www.generacodice.com/en/articolo/30745/How-can-you-find-and-replace-text-in-a-file-using-the-Windows-command-line-environment?), but nothing works for me. Either it doesn't get replaced, or \u1F697 shows up literally. I've tried changing the inbound file's encoding to Unicode and that isn't working either.
Non-working example:
powershell -Command "(gc test.txt) -replace ':car:', '🚗' | Out-File -encoding Unicode test.txt"
Does anyone have any tips?
Edit: I've determined how to reproduce it.
If I run this line via command line, it works:
powershell -Command "(gc test.txt) -replace ':car:', '🚗' | Out-File -encoding utf8 test-out.txt"
If I put the same line of code inside replace.bat and then execute it, test-out.txt is corrupt.
The batch file is set to UTF-8 encoding. Should something be different?
I don't think a .bat file can have non-ascii encoding. If you're willing to have a file.ps1 file:
(gc test.txt) -replace ':car:', '🚗' | Out-File -encoding utf8 test-out.txt
The file has to be saved as utf8 with bom in notepad, not just utf8.
Then your .bat file would be:
powershell -file file.ps1
The powershell ise is a nice way to test this.
cmd /c file.bat
type test-out.txt
🚗
Windows .bat script interpreter does not understand any Unicode encoding (e.g. utf-8 or utf-16 or utf-16); the simplest principle is:
You have to save the batch file with OEM encoding. How to do this
varies depending on your text editor. The encoding used in that case
varies as well. For Western cultures it's usually CP850.
To use any Unicode character (above ASCII range) as a part of string passed to PowerShell command then (instead of '🚗') apply the .NET method Char.ConvertFromUtf32(Int32); in terms of PowerShell syntax [char]::ConvertFromUtf32(0x1F697)
Being in ASCII it does not contradicts with above .bat encoding rule, and PowerShell would evaluate it to the 🚗 character…
Then, your line could be as follows:
powershell -Command "(gc test.txt) -replace ':car:', [char]::ConvertFromUtf32(0x1F697) | Out-File -encoding Unicode test.txt"

CMD: 'â– m' is not recognized as an internal or external command

I am trying to get a batch file to work. Whenever I attempt to run a .bat the command line returns 'â– m' is not recognized... error, where "m" is the first letter of the file. For example:
md c:\testsource
md c:\testbackup
Returns
C:>"C:\Users\Michael\Dropbox\Documents\Research\Media\Method Guide\Program\test
.bat"
C:>â– m
'â– m' is not recognized as an internal or external command,
operable program or batch file.
Things I have tried:
Changing Path variables, rebooting, etc.
Changing file directory (i.e. run from C:)
Running example files from web (like above) to check for syntax errors.
Thanks
What text editor are you writing this in? It seems like your text editor may save the file as UTF-16 encoded text, which cmd.exe can't handle. Try setting the "coding"/"file encoding" to "ANSI" when saving the file.
This results in the first byte being a byte-order-mark (telling other editors how to process the file), and cmd.exe can't deal with this.
In addition to the approved answer I would add the case where is a PowerShell command the one that creates the file... PowerShell comes by default with the UTF-16 encoding.
To solve your problem then, force the file encoding lie this: | out-file foo.txt -encoding utf8
Answer based on this other answer.
In windows 10 I had the same issue.
Changing the character set to UTF-8 made it worse.
It worked correctly when I selected Encoding as UTF-8-NO BOM.

How to use cmd type pipe (/piping) in PowerShell?

In cmd (and bash), pipe "|" pushes output to another command in the original format of the first command's output (as string).
In PowerShell, everything that comes out the pipe is an object (even a string is a string object).
Because of that, some commands fail when run in a PowerShell command window as opposed to a Windows command window.
Example:
dir c:\windows | gzip > test.gz
When this command is run in the Windows command prompt window it works properly - directory listing of C:\windows gets compressed into test.gz file.
The same command in PowerShell fails, because PowerShell does not use cmd-style pipe and replaces it with PowerShell pipe (working with array of file system items).
Q. How do you disable the default piping behavior in PowerShell to make traditional Windows commands work identically in PowerShell?
I tried using the escape character "`" before the pipe "`|", but it didn't work. I also tried invoke-expression -command "command with | here", but it also failed.
if you want to send strings down the pipeline you can use the cmdlet "out-string"
For Example:
get-process | out-string
If you are specifically looking for a PowerShell way to zip up files, check out the PowerShell Community Extensions. there are a bunch of cmdlets to zip and unzip all kinds of files.
http://pscx.codeplex.com
If you can pipe the output of (CMD) dir into gzip, then gzip apparently knows how to parse dir output. The (string) output from the PowerShell dir command (aka Get-ChildItem) doesn't look the same, so gzip likely would not be able to parse it. But, I'd also guess that gzip would be happy to take a list of paths, so this would probably work:
dir c:\windows | select -ExpandProperty FullName | gzip > test.gz
No warrantees express or implied.
If you really need to use the old school DOS pipe system in PowerShell, it can be done by running a command in a separate, temporary DOS session:
& cmd /c "dir c:\windows | gzip > test.gz"
The /c switch tells cmd to run the command then exit. Of course, this only works if all the commands are old school DOS - you can't mix-n-match them with PowerShell commands.
While there are PowerShell alternatives to the example given in the question, there are lots of DOS programs that use the old pipe system and will not work in PowerShell. svnadmin load is one that I've the pleasure of having to deal with.
You can't. PowerShell was designed to pass objects down a pipeline, not text. There isn't a backwards-compatability mode to DOS.

Batch file encoding

I would like to deal with filename containing strange characters, like the French é.
Everything is working fine in the shell:
C:\somedir\>ren -hélice hélice
I know if I put this line in a .bat file, I obtain the following result:
C:\somedir\>ren -hÚlice hÚlice
See ? é have been replaced by Ú.
The same is true for command output. If I dir some directory in the shell, the output is fine. If I redirect this output to a file, some characters are transformed.
So how can I tell cmd.exe how to interpret what appears as an é in my batch file, is really an é and not a Ú or a comma?
So there is no way when executing a .bat file to give an hint about the codepage in which it was written?
You have to save the batch file with OEM encoding. How to do this varies depending on your text editor. The encoding used in that case varies as well. For Western cultures it's usually CP850.
Batch files and encoding are really two things that don't particularly like each other. You'll notice that Unicode is also impossible to use there, unfortunately (even though environment variables handle it fine).
Alternatively, you can set the console to use another codepage:
chcp 1252
should do the trick. At least it worked for me here.
When you do output redirection, such as with dir, the same rules apply. The console window's codepage is used. You can use the /u switch to cmd.exe to force Unicode output redirection, which causes the resulting files to be in UTF-16.
As for encodings and code pages in cmd.exe in general, also see this question:
What encoding/code page is cmd.exe using
EDIT: As for your edit: No, cmd always assumes the batch file to be written in the console default codepage. However, you can easily include a chcp at the start of the batch:
chcp 1252>NUL
ren -hélice hélice
To make this more robust when used directly from the commandline, you may want to memorize the old code page and restore it afterwards:
#echo off
for /f "tokens=2 delims=:." %%x in ('chcp') do set cp=%%x
chcp 1252>nul
ren -hélice hélice
chcp %cp%>nul
I was having trouble with this, and here is the solution I found. Find the decimal number for the character you are looking for in your current code page.
For example, I'm in codepage 437 (chcp tells you), and I want a degree sign, . http://en.wikipedia.org/wiki/Code_page_437 tells me that the degree sign is number 248.
Then you find the Unicode character with the same number.
The Unicode character at 248 (U+00F8) is .
If you insert the Unicode character in your batch script, it will display to the console as the character you desire.
So my batch file
echo
prints
°
I created the following block, which I put at the beginning of my batch files:
set Filename=%0
IF "%Filename:~-8%" == "-850.bat" GOTO CONVERT_CODEPAGE_END
rem Converting code page from 1252 to 850.
rem My editors use 1252, my batch uses 850.
rem We create a converted -850.bat file, and then launch it.
set File850=%~n0-850.bat
PowerShell.exe -Command "get-content %0 | out-file -encoding oem -filepath %File850%"
call %File850%
del %File850%
EXIT /b 0
:CONVERT_CODEPAGE_END
I care about three concepts:
Output Console Encoding
Command line internal encoding (that changed with chcp)
.bat Text Encoding
The easiest scenario to me: I will have the first two mentioned in the same encoding, say CP850, and I will store my .bat in that same encoding (in Notepad++, menu Encoding → Character sets → Western European → OEM 850).
But suppose someone hands me a .bat in another encoding, say CP1252 (in Notepad++, menu Encoding* → Character sets → Western European → Windows-1252)
Then I would change the command line internal encoding, with chcp 1252.
This changes the encoding it uses to talk with other processes, neither the input device nor output console.
So my command line instance will effectively send characters in 1252 through its STDOUT file descriptor, but gabbed text appears when the console decodes them out as 850 (é is Ú).
Then I modify the file as follows:
#echo off
perl -e "use Encode qw/encode decode/;" -e "print encode('cp850', decode('cp1252', \"ren -hlice hlice\n\"));"
ren -hlice hlice
First I turn echo off so the commands don't output unless explicitly doing either echo... or perl -e "print..."
Then I put this boilerplate each time I need to output something
perl -e "use Encode qw/encode decode/;" -e "print encode('cp850', decode('cp1252', \"ren -hélice hélice\n\"));"
I substitute the actual text I'll show for this: ren -hélice hélice.
And also I could need to substitute my console encoding for cp850 and other side encoding for cp1252.
And just below I put the desired command.
I did broke the problematic line into the output half and the real command half.
The first I make for sure: The "é" is interpreted as an "é" by means of transcoding. It is necessary for all the output sentences since the console and the file are at different encodings.
The second, the real command (muttered with #echo off), knowing we have the same encoding both from chcp and the .bat text is enough to ensure a proper character interpretation.
I had polish signs inside the code in R (eg. ą, ę, ź, ż etc.) and had the problem while running this R script with .bat file (in the output file .Rout instead of those signs there were signs like %, &, # etc. and the code didn't run to the end).
My solution:
Save R script with encoding: File > Save with encoding > CP1250
Run .bat file
It worked for me but if there is still the problem, try to use the other encodings.
In Visual Studio Code, click on the encoding at the bottom, choose Save with encoding, then DOS(CP437).

Resources