14

I am trying to echo 3 plain-text lines to a file using Powershell:

echo "#Generated" > psftp.scp echo "put test.txt" >> psftp.scp echo "quit" >> psftp.scp 

I then use psftp.exe batch mode to run the file (executes the commands in SFTP), but psftp errors out seeing an invalid character:

psftp: unknown command " ■#" 

What am I missing? I can manually type up the file in Windows Notepad and it (psftp) works. No matter what I change the first line to (#Generated) it gets this error with the block symbol in the first part.

I've tried viewing the file in NotePad++ w/ "Show All Symbols" on, but only saw CR & LF at the end of lines which is normal.

5
  • 5
    Someone else can verify this, but it may be a bom character or something that windows includes after the strings. If you use Out-File you can use -Append to add text and -Encoding to specify the correct encoding. Commented Mar 15, 2013 at 18:05
  • fwiw, the characters are 0xFF, 0xFE, then the letters, but with 0x00 between them.(I don't think that's unicode) Commented Jul 20, 2016 at 18:19
  • And the comment by @FrodeF. works. Without the -encoding ascii, it still has the weird characters at the beginning of the file. Commented Jul 20, 2016 at 18:34
  • Does anyone know why Powershell's redirect behaves so obnoxiously? It seems like something that should be easily fixed to behave more similarly to bash and not insert random characters. I am assuming there is some reason. Commented Aug 2, 2018 at 15:22
  • @mbourgon, it is a Unicode encoding, namely UTF-16LE (mistakenly called "Unicode" in PowerShell). Commented Feb 3, 2023 at 18:02

4 Answers 4

10

Try using set/add-content instead of redirection. You might also need to set the encoding.

"#Generated" | set-content psftp.scp -Encoding Ascii "put test.txt" | add-content psftp.scp -Encoding Ascii "quit" | add-content psftp.scp -Encoding Ascii 
Sign up to request clarification or add additional context in comments.

4 Comments

I ended up doing "Default" encoding and it was fine.
Do you know why powershell behaves like this? Why does it insert seemingly random characters when redirecting a cmdline string to a file?
I can confirm that for me it didn't work to set the encoding as utf8, but "Default" worked
NotePad++ = UTF-8 -- PowerShell UTF8 = UTF-8-BOM -- PowerShell Default = UTF-8 -- Settings confirmed in Notepad++
1

Like Out-File, the default encoding of ">" and ">>" in Powershell 5 is UTF16LE ("Unicode"). I guess psftp can't read that? "FF FE" is the encoding signature or "BOM". How are you running psftp?

format-hex psftp.scp Path: C:\Users\me\psftp.scp 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00000000 FF FE 23 00 47 00 65 00 6E 00 65 00 72 00 61 00 .þ#.G.e.n.e.r.a. 00000010 74 00 65 00 64 00 0D 00 0A 00 70 00 75 00 74 00 t.e.d.....p.u.t. 00000020 20 00 74 00 65 00 73 00 74 00 2E 00 74 00 78 00 .t.e.s.t...t.x. 00000030 74 00 0D 00 0A 00 71 00 75 00 69 00 74 00 0D 00 t.....q.u.i.t... 00000040 0A 00 .. 

Set the default encoding for ">", ">>" and out-file in powershell 5.1:

$PSDefaultParameterValues = @{'Out-File:Encoding' = 'Ascii'} 

Comments

1

Many years later, an attempt at a systematic overview:

  • In the modern, cross-platform PowerShell (Core) edition (v6 and above), it is now fine to use > and >> as they now create BOM-less UTF-8 files (as all file-writing cmdlets now do consistently).

    • Given that many modern programs expect this character encoding, your code will likely work as-is.
    • If you need a different encoding, call a cmdlet with -Encoding, as discussed next.
  • In the legacy Windows PowerShell edition (whose latest and final version is v5.1), > and >> default to UTF-16LE (which PowerShell incorrectly calls Unicode), which few external programs understand, and which is the cause of your problem.[1]

    • > and >> are in effect alias of Out-File and Out-File -Append, and specifying a different encoding requires calling them explicitly with an -Encoding argument.

    • However, with string input, you may use Set-Content and Add-Content, which default to Default, representing the system's active ANSI code page, such as Windows-1252 on US-English systems.

      # `-Encoding Default` implied. # OK with ASCII-only characters, otherwise only if the program # expects ANSI encoding. # If you use -Encoding ASCII, any non-ASCII characters become # *literal ?* chars., i.e. information is *lost*. # (That can also happen for `-Encoding Default` for Unicode chars. # outside the character set of the active ANSI code page.) '#Generated' | Set-Content psftp.scp 'put test.txt' | Add-Content psftp.scp 'quit' | Add-Content psftp.scp 
    • It gets tricky if you want BOM-less UTF-8, because Windows PowerShell's cmdlets do not support creating such files - -Encoding utf8 invariably creates files with a BOM (unlike in PowerShell (Core), where you conversely must use -Encoding utf8bom to explicitly request a BOM). Curiously, New-Item does create BOM-less UTF-8 files, so it can be used to create the file, which allows subsequent Add-Content calls to use -Encoding utf8 safely, because they won't add a BOM to existing file content.

      # New-Item, curiously, creates BOM-less UTF-8 files. # The string must be passed via -Value (or as a *single* pipeline input), # and a trailing newline must be added explicitly. $null = New-Item -Force psftp.scp -Value "#Génerated`n" 'put test.txt' | Add-Content -Encoding utf8 psftp.scp 'quit' | Add-Content -Encoding utf8 psftp.scp 

[1] UTF-16LE files created by PowerShell always have a BOM (Byte Order Mark, which is the 2-byte sequence 0xFF, 0xFE, and characters / surrogate-pair halves are represented as 16-bit code units, i.e. as two bytes, with ASCII-range characters having 0x0 (NUL) as the second byte in their two-byte sequence.

Comments

0

In my case, I was piping a .ps1 into powershell in a .cmd file

type script.ps1 | powershell -ExecutionPolicy Bypass 

Although the script had no errors when run in other ways, when run this way, it would throw a syntax error on the first row (a comment row) due to invalid characters.

I found out that if I saved the .ps1 file with the wScite editor, the default was "UTF-8 with BOM". I changed it to just "UTF-8", and after that piping the script to powershell worked fine.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.