Public/string/ConvertFrom-MisencodedString.ps1

#Requires -Version 5.1

function ConvertFrom-MisencodedString {
    <#
        .SYNOPSIS
            Converts a misencoded string by reinterpreting bytes from a source encoding
 
        .DESCRIPTION
            Fixes encoding issues where text was incorrectly interpreted using the wrong
            character encoding. The function takes the string, converts it to bytes using
            the source encoding (default: Cyrillic), then reinterprets those bytes as
            ASCII or another target encoding.
 
            This is commonly needed when text was stored or transmitted using one encoding
            but displayed or processed as another, resulting in garbled characters.
 
            Note: PowerShell converts null input to an empty string before parameter
            validation runs, so passing -String $null is equivalent to -String ''.
 
        .PARAMETER String
            The misencoded string to convert. Accepts input from the pipeline.
            Empty strings are allowed and will be returned unchanged.
            Note: null values are automatically converted to empty strings by PowerShell.
 
        .PARAMETER SourceEncoding
            The encoding that was incorrectly applied to the original text.
            Default is 'Cyrillic' (windows-1251). Common values include 'Cyrillic',
            'windows-1252', 'iso-8859-1', 'utf-8'.
 
        .PARAMETER TargetEncoding
            The encoding to use when reinterpreting the bytes.
            Default is 'ASCII'. Use 'utf-8' for broader character support.
 
        .EXAMPLE
            ConvertFrom-MisencodedString -String 'portal'
 
            Converts a Cyrillic-misencoded string back to readable ASCII text.
            Returns the corrected string.
 
        .EXAMPLE
            'portal', 'server' | ConvertFrom-MisencodedString
 
            Pipeline example: processes multiple misencoded strings and returns
            the corrected versions.
 
        .EXAMPLE
            ConvertFrom-MisencodedString -String 'cafe' -SourceEncoding 'windows-1252' -TargetEncoding 'utf-8'
 
            Fixes a string where UTF-8 characters were misinterpreted as Windows-1252.
            Returns 'cafe' in proper UTF-8 encoding.
 
        .EXAMPLE
            Get-Content -Path 'C:\Logs\misencoded.txt' | ConvertFrom-MisencodedString
 
            Reads misencoded lines from a file and converts each line to the correct encoding.
 
        .OUTPUTS
            System.String
            The re-encoded string with correct character rendering.
 
        .NOTES
            Author: Franck SALLET
            Version: 1.0.2
            Last Modified: 2026-03-11
            Requires: PowerShell 5.1+
            Permissions: None required
            Module: PSWinOps
 
        .LINK
            https://github.com/k9fr4n/PSWinOps
 
        .LINK
            https://learn.microsoft.com/en-us/dotnet/api/system.text.encoding
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [AllowEmptyString()]
        [string]$String,

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$SourceEncoding = 'Cyrillic',

        [Parameter(Mandatory = $false)]
        [ValidateNotNullOrEmpty()]
        [string]$TargetEncoding = 'ASCII'
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand)] Starting conversion - PowerShell $($PSVersionTable.PSVersion)"

        try {
            $sourceEncoder = [System.Text.Encoding]::GetEncoding($SourceEncoding)
            Write-Verbose "[$($MyInvocation.MyCommand)] Source encoding: $($sourceEncoder.EncodingName)"
        }
        catch {
            Write-Error "[$($MyInvocation.MyCommand)] Invalid source encoding '$SourceEncoding': $_"
            throw
        }

        try {
            $targetEncoder = [System.Text.Encoding]::GetEncoding($TargetEncoding)
            Write-Verbose "[$($MyInvocation.MyCommand)] Target encoding: $($targetEncoder.EncodingName)"
        }
        catch {
            Write-Error "[$($MyInvocation.MyCommand)] Invalid target encoding '$TargetEncoding': $_"
            throw
        }
    }

    process {
        # Handle empty strings without attempting conversion
        if ($String.Length -eq 0) {
            Write-Verbose "[$($MyInvocation.MyCommand)] Empty string - returning unchanged"
            return ''
        }

        try {
            Write-Verbose "[$($MyInvocation.MyCommand)] Processing: '$String'"

            $bytes = $sourceEncoder.GetBytes($String)
            $result = $targetEncoder.GetString($bytes)

            Write-Verbose "[$($MyInvocation.MyCommand)] Converted successfully (Length: $($String.Length) --> $($result.Length))"

            $result
        }
        catch [System.Text.EncoderFallbackException] {
            Write-Error "[$($MyInvocation.MyCommand)] Encoding fallback error for '$String': $_"
            return
        }
        catch [System.ArgumentException] {
            Write-Error "[$($MyInvocation.MyCommand)] Invalid characters in string for encoding '$SourceEncoding': $_"
            return
        }
        catch {
            Write-Error "[$($MyInvocation.MyCommand)] Conversion failed for string '$String': $_"
            return
        }
    }

    end {
        Write-Verbose "[$($MyInvocation.MyCommand)] Completed"
    }
}