0

I am trying to change the encoding of multiple files to UTF8, read the files with findstr and once read change the encoding back to unicode (UTF16-LE).

This is my powershell command I am trying to run within my batch file:

powershell -command "$apb=(gc config\_temp\path.txt)+'\APBGame\Localization\GER\'; Get-ChildItem $apb\ -Filter *.GER -recurse | Foreach-Object {Get-Content $_.FullName | Set-Content -Encoding utf8 ($_.FullName)}"

Running that command gives me this error:

Set-Content : The process cannot access the file 'E:\SteamLibrary\steamapps\common\APB Reloaded\APBGame\Localization\GER\FILE.GER'
because it is being used by another process.
At line:1 char:150
+ ...  {Get-Content $_.FullName | Set-Content -Encoding utf8 ($_.FullName)}
+                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Set-Content], IOException
    + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.SetContentCommand

I get this error for every file.

I have already used Process Explorer to identify possible processes that could've used the .GER files by searching for the handle ".GER". No matches were found.

I run multiple powershell commands within my batch file but this one is the only one using the variable $apb incase that's important.

leiseg
  • 105
  • 6
  • 1
    You cannot pipe the lines being read with Get-Content back to the **same** file with Set-Content. Make sure Get-Content is completely finished before piping the content. Easiest way is to enclose it in brackets: `(Get-Content $_.FullName -Raw) | Set-Content ..` – Theo May 07 '23 at 14:58

1 Answers1

0

I found a way that doesn't give me the error. I use this command now:

powershell -command "$apb=(gc config\_temp\path.txt)+'\APBGame\Localization\GER\'; get-childitem $apb\* -recurse -include *.GER | foreach-object {$content = $_ | gc -encoding UTF8; sc -passthru $_.FullName $content -encoding ASCII -force} | out-null"

It changes the encoding to BOM-less UTF8.

Once I am done with my findstr section I use the following command to change the encoding to UTF-16LE (Unicode) again:

powershell -command "$apb=(gc config\_temp\path.txt)+'\APBGame\Localization\GER\'; get-childitem $apb\* -recurse -include *.GER | foreach-object {$content = $_ | gc -encoding UTF8; sc -passthru $_.FullName $content -encoding Unicode -force} | out-null"
leiseg
  • 105
  • 6
  • 2
    Ascii not utf8. But that only matters with foreign characters, etc. – js2010 May 07 '23 at 15:03
  • 1
    As implied by js2010's comment, while `-encoding ASCII` creates a _BOM-less_ file, its content supports only characters in the 7-bit ASCII sub-range of Unicode, with other characters, such as _accented_ characters - e.g. `ü` - getting "lossily" translated to _literal_ `?` characters. See [this answer](https://stackoverflow.com/a/66553739/45375) for how to create BOM-less UTF-8 files in _Windows PowerShell_ ([_PowerShell (Core) 7+_](https://github.com/PowerShell/PowerShell/blob/master/README.md) creates such files _by default_). – mklement0 May 07 '23 at 22:55
  • 1
    As an aside: Remove `-PassThru` from the `sc` (`Set-Content`) call, then you won't need `| out-null` – mklement0 May 07 '23 at 22:55
  • @mklement0 Thank you for your reply! How do I use the UTF8-BOM-less workaround for any .GER file? My command looks like `powershell -command "$apb=(gc config\_temp\path.txt)+'\APBGame\Localization\GER\'; $null = new-item -force $apb\*.GER -value (get-childitem $apb\* -recurse -include *.GER | foreach-object {$content = $_ | (gc -raw -encoding UTF8); sc $_.FullName $content -encoding UTF8 -force})"` now which gives me the error new-item : Illegal characters in path. Also, is there a way to make changing file encoding faster? – leiseg May 08 '23 at 09:21
  • 1
    Use `Get-Content -Raw` to read each file _as a whole_ into memory, which is much faster. The `New-Item` workaround requires calling `New-Item` _instead_ of `Set-Content`, as described in the linked answer. Here's a quick example (not adapted to your scenario): `Get-ChildItem *.txt | ForEach-Object { $null = New-Item -Force $_.FullName -Value ($_ | Get-Content -Raw) }` If you still have questions, please create a new question post. – mklement0 May 08 '23 at 15:34