How can I modify a group of jpg files in a directory to Base64, as a group

Viewed 68

Although not a developer, I've been finding answers to problems via StackOverflow for a while now, and feel like I owe a lot of y'all a cold beer or two.

I've run into an issue that I can't seem to wrap my head around.
I would like to be able to run the following, to convert a group of jpg files to Base64 for submission to a regulatory agency that requires this format:

[Convert]::ToBase64String((Get-Content C:\temp\168211_wheels.jpg -Encoding Byte)) >> c:\temp\Pictest.txt

I will run this against a group of jpg files, all in the same directory.
My first, fairly tragic, attempt was this:

Get-ChildItem -Path ' C:\testimages\*' -Include '*.jpg' | ForEach-Object {
    [Convert]::ToBase64String((Get-Content C:\testimages\*.jpg -Encoding Byte)) >> } c:\temp\Pictest.txt

I receive the following Error Message:

**At line:1 char:152
+ ... e64String((Get-Content C:\testimages\*.jpg -Encoding Byte))>>}c:\temp ...
+                                                                  ~
Missing file specification after redirection operator.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingFileSpecification**

Any guidance or suggestions are very welcomed, as this is only my second attempt at working in Powershell.

Regards,
Darren

2 Answers
[System.IO.Directory]::EnumerateFiles('S:\SCRIPTS\GC', '*.exe', [System.IO.SearchOption]::AllDirectories) |
    ForEach-Object { 
        return [PSCustomObject]@{
            SourceFile = $_
            TargetFile = [System.IO.Path]::ChangeExtension($_, 'j64')
        }
    } |
    ForEach-Object {
        $content = $null
        $content = [System.IO.File]::ReadAllBytes($_.SourceFile)
        $encodedContent = $null
        $encodedContent = [System.Convert]::ToBase64String($content, [System.Base64FormattingOptions]::InsertLineBreaks)
        [System.IO.File]::WriteAllText($_.TargetFile, $encodedContent, [System.Text.Encoding]::ASCII)
        Write-Host "Processed $($_.SourceFile)"
    }

Using [System.IO.Directory]::EnumerateFiles(...) is faster on huge amount of files because it returns only full file names without any other properties.

It can be replaced by Get-ChildItem -Path 'S:\SCRIPTS\GC' -Filter '*.exe' -File | Select -ExpandProperty 'FullName' if you want in this case.


[System.IO.File]::ReadAllBytes(...) and [System.IO.File]::WriteAllText(...) is just more obivious in this case, in my opinion.


And please, avoid redirection operators like '>>' and '>' using powershell. They create problems quite often.

Assuming you want one base64 encoded file per jpg file, this is how you could do it:

Get-ChildItem -Path 'C:\testimages\*' -Filter *.jpg | ForEach-Object {
    
    $fileName = "{0} - Base64Encoded.txt" -f $_.BaseName
    $path = Join-Path $_.Directory -ChildPath $fileName
    $content = Get-Content $_.FullName -Encoding Byte -Raw
    [Convert]::ToBase64String($content) | Out-File $path -NoNewline

}

Which will output one txt file with the same name as the original file followed by - Base64Encoded.

Then if you want to convert the files to their original format you can decode them like this:

Get-ChildItem -Path 'C:\testimages\*' -Filter *Base64Encoded* | ForEach-Object {
    
    $fileName = "{0} - Decoded.jpg" -f $_.BaseName
    $path = Join-Path $_.Directory -ChildPath $fileName
    $content = Get-Content $_.FullName -Raw
    [convert]::FromBase64String($content) | Set-Content $path -Encoding Byte

}
Related