1

I'm working on a config installer for a game. I want to make a menu for the user to choose from different colors for certain settings. To change those colors I use a PowerShell command in a batch file to find and replace the relevant text in a specific file. There is no problem with that alone.

In the replacement process, PowerShell also replaces the newline character found in the config file with a "?". That is not intended and I want to avoid that.

The character that gets replaced with a "?" is the following:

I want to exclude that character from getting replaced in the process.

My code looks like that:

powershell -command "& {($p=gc "path.txt");(gc $p\GameConfig\SpecificFile.txt).replace('<col:Default>','<col:Green>') | sc $p\GameConfig\SpecificFile.txt}"

I have already tried to exclude the character like so:

powershell -command "& {($p=gc "path.txt");(gc $p\GameConfig\SpecificFile.txt).replace[↵]::escape('<col:Default>','<col:Green>') | sc $p\GameConfig\SpecificFile.txt}"

That didn't work.

I also tried to revert the replacement process of the newline character like so:

powershell -command "& {($p=gc "path.txt");(gc $p\GameConfig\SpecificFile.txt).replace('<col:Default>','<col:Green>') | sc $p\GameConfig\SpecificFile.txt}"
powershell -command "& {($p=gc "path.txt");(gc $p\GameConfig\SpecificFile.txt).replace('>?<','>↵<') | sc $p\GameConfig\SpecificFile.txt}" 

That didn't work either.

I really need some help. Thanks in advance!

Cheers

leiseg
  • 105
  • 6
  • The font you are using doesn't support the character. Change the font. – jdweng Mar 11 '23 at 11:13
  • @jdweng Thank you for your fast reply! I'm pretty new to PowerShell. I researched what font would support that character [https://graphicdesign.stackexchange.com/questions/22128/what-font-and-characters-are-used-for-the-line-break-symbol-used-in-microsoft] (Source). Cambria could be one of those fonts. The game itself uses a modified version of Helvetica though. How do I set the font to Cambria with a command? And how can I make sure that this font is installed on the computers of other users? – leiseg Mar 11 '23 at 11:44
  • 1
    `sc -encoding utf8` – js2010 Mar 11 '23 at 16:50
  • As an aside: There's no reason to use `"& { ... }"` in order to invoke code passed to PowerShell's CLI via the `-Command` (`-c`) parameter - just use `"..."` directly. Older versions of the [CLI documentation](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pwsh) erroneously suggested that `& { ... }` is required, but this has since been corrected. – mklement0 Mar 11 '23 at 21:38

1 Answers1

1

tl;dr

Use the -Encoding parameter of Set-Content (whose built in alias is sc in Windows PowerShell) to specify a Unicode character encoding, to ensure that Unicode characters such as (DOWNWARDS ARROW WITH CORNER LEFTWARDS , U+21B5) are preserved; to use UTF-8 encoding, for instance, add -Encoding utf8:

powershell -command "$p=gc path.txt; (gc -Encoding utf8 $p\GameConfig\SpecificFile.txt).Replace('<col:Default>','<col:Green>') | sc -Encoding utf8 $p\GameConfig\SpecificFile.txt"

A streamlined reformulation that speeds up processing by reading the file as a whole rather than line by line, using Get-Content's -Raw switch as well as Set-Content's -NoNewLine switch:

powershell -command "$p=(gc path.txt)+'\GameConfig\SpecificFile.txt'; (gc -Raw -Encoding utf8 $p).Replace('<col:Default>','<col:Green>') | sc -Encoding utf8 -NoNewLine $p"

To instead use UTF-16LE ("Unicode") encoding, use -Encoding Unicode (sic).

Note:

  • In Window PowerShell, the legacy, ships-with-Windows Windows-only PowerShell edition you're using, this invariably creates a UTF-8 file with a BOM.

    • If that is undesired, you need a workaround - see this answer.

    • Note that if / once your input files are BOM-less UTF-8 files, you also need to use -Encoding utf8 for reading them properly with Get-Content (whose built-in alias is gc), as used in the command above; without that, the file would be misinterpreted as ANSI-encoded in Windows PowerShell (see next point).

  • By default, Windows PowerShell's Set-Content cmdlet uses ANSI encoding, i.e. the fixed-width 8-bit character encoding associated with your system's legacy system locale (aka language for non-Unicode programs), such as Windows-1252 on US-English systems.

    • Trying to save a Unicode character such as that cannot be represented in such an encoding results in an (ASCII-range) ? character getting saved instead, which is what you saw.

    • Note that the PowerShell (Core) 7+ edition now fortunately consistently defaults to (BOM-less) UTF8.

  • Generally, note that PowerShell's pipelines are not raw byte conduits: text file contents as well as output from external programs are invariably decoded into .NET strings before further processing, so that a Get-Content ... | Set-Content ... pipeline never preserves the original character encoding and instead uses Set-Content's default encoding on writing (unless the -Encoding parameter is used); see this answer for background information.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 1
    Including the BOM workaround my code looks like this now: `powershell -command "& {($p=gc "path.txt");$null=new-item -force $p\Game\Config\SpecificFile.txt -value ((gc $p\Game\Config\SpecificFile.txt).replace('','') | out-string)}"` And it works! Thank you very much. – leiseg Mar 11 '23 at 14:54
  • I had some testers now and apparently there are some of them that get the `↵` replaced with `ââ€<0xa0>µ`. I had them test both commands: `powershell -command "& {($p=gc "path.txt");(gc $p\Game\Config\SpecificFile.txt).replace('','') | sc -Encoding utf8 $p\Game\Config\SpecificFile.txt}"` and `powershell -command "& {($p=gc "path.txt");$null=new-item -force $p\Game\Config\SpecificFile.txt -value ((gc $p\Game\Config\SpecificFile.txt).replace('','') | out-string)}"`. Both commands caused that issue for them. Do you know a fix for that? – leiseg Mar 11 '23 at 16:19
  • I tested more and noticed that the first sequence runs just fine and doesn't replace the `↵` character. I got 3 sequences to run though and after the 2nd one the `↵` gets replaced with `↵` and after the last sequence `↵` gets replaced with `ââ€<0xa0>µ` . Is there a way to avoid that? I use your command with the BOM workaround for every sequence. @mklement0 – leiseg Mar 11 '23 at 19:26
  • 1
    @leiseg, use `gc -Encoding utf8` to ensure that the file are also _read_ as UTF-8. Once you have BOM-less UTF-8 files, Windows PowerShell will misinterpret them as ANSI-encoded. – mklement0 Mar 11 '23 at 20:09
  • Alright, that worked once again! Thank you a lot for your help and the explanations! – leiseg Mar 11 '23 at 20:21
  • 1
    My pleasure, @leiseg. Note that the need for using `-Encoding utf8` with `gc` suggests that your files _originally_ were UTF-8 encoded _with_ a BOM (or used another Unicode encoding, such as UTF-16LE, which _always_ requires a BOM). – mklement0 Mar 11 '23 at 20:38
  • I already ran into that problem @mklement0. The `↵` is present in the file but in the game it shows the previous mentioned characters `↵`. Is there a workaround for that? – leiseg Mar 11 '23 at 21:20
  • 1
    @leiseg, it sounds like you may need the BOM after all, so re-save them with `sct -encoding utf8` and see if that helps. – mklement0 Mar 11 '23 at 21:23
  • If I try to implement `sct -encoding utf8` into my code, I get an error saying that `sct` is not recognized as the name of a cmdlet, function, script file or operable program. Can you give me an example to implement that into my code? This is the code I'm using: `powershell -command "& {($p=gc "path.txt");$null=new-item -force $p\Game\Config\SpecificFile.txt -value ((gc $p\Game\Config\SpecificFile.txt).replace('','') | out-string)}"` @mklement0 – leiseg Mar 11 '23 at 21:32
  • 1
    @leiseg, sorry, I meant `sc`, not `sct` (`sct` is my custom, cross-platform alias for `Set-Content`). Please see the updated command in my answer. – mklement0 Mar 11 '23 at 21:38
  • I tried it but unfortunately that didn't work either @mklement0. I really want to use powershell for that but if there's no other way I will use some third party find text and replace tool. – leiseg Mar 11 '23 at 22:16
  • 1
    @leiseg, PowerShell can definitely get you there, but you need to be clear on the requirements: (a) What specific character encoding does your _original_ `...\Game\Config\SpecificFile.txt` file use? If it isn't property decoded by `Get-Content` _by default_, you must pass an `-Encoding` argument. (b) To _preserve_ that encoding after performing your string replacement and on re-saving the file, you must use pass the _same_ `-Encoding` argument to `Set-Content` (`sc`) - _except_ if the encoding is _BOM-less_ UTF-8, in which case you need the `New-Item` workaround (in Windows PowerShell). – mklement0 Mar 11 '23 at 22:25
  • Alright, I found out that the original file is encoded as UTF16LE. If I use the commands you provided, it get's encoded as UTF8. UTF8 is needed to save the `↵` character though. Is there a way to encode the file as UTF16LE again? @mklement0 – leiseg Mar 11 '23 at 23:18
  • 1
    @leiseg, yes, use `-Encoding Unicode` – mklement0 Mar 11 '23 at 23:19
  • 1
    This finally works! Thanks for the third time now. My problem is solved! @mklement0 – leiseg Mar 11 '23 at 23:46