PowerShell - 批量更改文件编码为UTF-8

dar*_*ong 9 powershell encoding batch-file utf-8

我正在尝试做一个简单的事情:将文件编码从任何东西更改为UTF-8而不使用BOM.我找到了几个执行此操作的脚本,唯一真正适合我的脚本就是这个:https://superuser.com/questions/397890/convert-text-files-recursively-to-utf-8-in-powershell#回答-397915.

它按预期工作,但我需要生成的文件没有BOM.所以我尝试稍微修改脚本,添加给出这个问题的解决方案:使用PowerShell以UTF-8编写一个没有BOM的文件

这是我的最终剧本:

foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    get-content $i | out-file -encoding $Utf8NoBomEncoding -filepath $dest
}
Run Code Online (Sandbox Code Playgroud)

问题是,对于System.Text.UTF8Encoding($False)线路,powershell返回一个错误,抱怨参数不正确:

无法验证"编码"参数的参数.参数"System.Text.UTF8Encoding"不属于ValidateSet属性指定的组"unicode,utf7,utf8,utf32,ascii".

我想知道我是否遗漏了一些东西,比如powershell版本或类似的东西.我以前从未编写过Powershell脚本,所以我完全迷失了.而且我需要更改这些文件编码,其中有数百个,我不想一个接一个地自己做.

实际上我正在使用Windows 7附带的2.0版本.

提前致谢!

编辑1

我尝试了以下代码,由@LarsTruijens和其他帖子建议:

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    $content = get-content $i
    [System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
}
Run Code Online (Sandbox Code Playgroud)

这给了我一个异常,抱怨WriteAllLines的一个参数:"Exception on calling 'WriteAllLines' with 3 arguments. The value can't be null". Parameter name: contents.但是,该脚本会创建所有文件夹.但他们都是空的.

编辑2

关于此错误的一个有趣的事情是"content"参数不为null.如果我输出$ content变量的值(使用Write-host),则存在行.那么为什么它传递给WriteAllLines方法时变为null?

编辑3

我已经为变量添加了内容检查,因此脚本现在看起来像这样:

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    $content = get-content $i

    if ( $content -ne $null ) {

        [System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
    }
    else {
        Write-Host "No content from: $i"
    }
}
Run Code Online (Sandbox Code Playgroud)

现在每次迭代都返回"No content from:$ i"消息,但该文件不为空.还有一个错误:Get-content: can't find the path 'C:\root\FILENAME.php' because it doesn't exists.它似乎试图在根目录而不是子文件夹中找到文件.它似乎能够从子文件夹中获取文件名,但尝试从root读取它.

编辑4 - 最终工作版本

经过一番挣扎并遵循我来到这里的建议,特别是来自@LarsTruijens和@AnsgarWiechers,我终于成功了.我不得不改变从$ PWD获取目录的方式,并为文件夹设置一些固定名称.在那之后,它完美地运作.

在这里,对于任何可能感兴趣的人:

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
$source = "path"
$destination = "some_folder"

foreach ($i in Get-ChildItem -Recurse -Force) {
    if ($i.PSIsContainer) {
        continue
    }

    $path = $i.DirectoryName -replace $source, $destination
    $name = $i.Fullname -replace $source, $destination

    if ( !(Test-Path $path) ) {
        New-Item -Path $path -ItemType directory
    }

    $content = get-content $i.Fullname

    if ( $content -ne $null ) {

        [System.IO.File]::WriteAllLines($name, $content, $Utf8NoBomEncoding)
    } else {
        Write-Host "No content from: $i"   
    }
}
Run Code Online (Sandbox Code Playgroud)

Lar*_*ens 5

您没有遵循此处的完整答案。您忘记了 WriteAllLines 部分。

$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding($False)
foreach ($i in Get-ChildItem -Recurse) {
    if ($i.PSIsContainer) {
        continue
    }

    $dest = $i.Fullname.Replace($PWD, "some_folder")

    if (!(Test-Path $(Split-Path $dest -Parent))) {
        New-Item $(Split-Path $dest -Parent) -type Directory
    }

    $content = get-content $i 
    [System.IO.File]::WriteAllLines($dest, $content, $Utf8NoBomEncoding)
}
Run Code Online (Sandbox Code Playgroud)