Juan M
Juan M

Reputation: 11

Use Powershell to extract PEM file lines add quotes to beginning and end and make it one line

How do I take the contents of a .PEM that looks like this:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ6AMIIBCgKCAQEAse68c1suNUQr0d79VudK
XgmNxggQoaqR9fZoCrUz/gRS5XZm9wDL9HHxjYjEhZsuXQw1SZpYggjRQuqE+7Nx
mhgn6DXXjWiTZ2b/ScE9mu+RQyh4hWEk9u+uUD2MZ9oPUZi2tN43InH9Qduza1Fe
jQeh6OW6Bg+fTsBXtPJWawF/3oMCdWVfZ8Iel0ilP+61B5ldkw7g//QMf5mqzvkQ
HK5/gKPCfGUylRDtJOxOriM5XqCjgtw6Sye8hgql5DGOCZTrXAahNbnw0bGm5TYW
qosD+B2Rh/Xa600j/X0JAABQ8Pi1b0PAycGdMW7HPQ1YAp5Q7PbQQxlmlWeHQEgO
wwIDAQAB
-----END PUBLIC KEY-----

To make it look like this as one line:

"k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ6AMIIBCgKCAQEAse68c1suNUQr0d79VudK" "XgmNxggQoaqR9fZoCrUz/gRS5XZm9wDL9HHxjYjEhZsuXQw1SZpYggjRQuqE+7Nx" "mhgn6DXXjWiTZ2b/ScE9mu+RQyh4hWEk9u+uUD2MZ9oPUZi2tN43InH9Qduza1Fe" "jQeh6OW6Bg+fTsBXtPJWawF/3oMCdWVfZ8Iel0ilP+61B5ldkw7g//QMf5mqzvkQ" "HK5/gKPCfGUylRDtJOxOriM5XqCjgtw6Sye8hgql5DGOCZTrXAahNbnw0bGm5TYW" "qosD+B2Rh/Xa600j/X0JAABQ8Pi1b0PAycGdMW7HPQ1YAp5Q7PbQQxlmlWeHQEgO" "bwIDAQAB"

I'm able to remove the Begin and End lines using the following:

    $File = "C:\pathto\some.pem"
    $content = Get-Content $file
    $contents =  $content
    
    $Complete = [regex]::split($contents, "-----BEGIN PUBLIC KEY-----(.*?)-----END PUBLIC KEY-----")
    
    for($i = 1; $i -lt $Complete.Length; $i =$i+2){
        $Complete[$i] -replace " ","`r`n"
    }

Upvotes: 1

Views: 138

Answers (1)

mclayton
mclayton

Reputation: 10075

First, some caveats:

  • As noted in comments, the quotes in your expected output appear to be mismatched - you’ve got one at the start of the string ("k=rsa) which is closed by the one at the end of the first p value (p=MIIB...VudK"). I'm not sure if this is a typo or if this is the expected output, so I'm going to take it at face value and assume it's the expected output. You might need to adapt this answer slightly if it's a typo.

  • Also the last line of your PEM data in the question is wwIDAQAB but your example output ends with "bwIDAQAB" - one starts with w and the other starts with b - I'm going to assume this is a typo and I'll use the value starting with b to match the expected output.


Answer

Get-Content returns an array of strings which is equivalent to this:

$content = @(
    "-----BEGIN PUBLIC KEY-----",
    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ6AMIIBCgKCAQEAse68c1suNUQr0d79VudK",
    "XgmNxggQoaqR9fZoCrUz/gRS5XZm9wDL9HHxjYjEhZsuXQw1SZpYggjRQuqE+7Nx",
    "mhgn6DXXjWiTZ2b/ScE9mu+RQyh4hWEk9u+uUD2MZ9oPUZi2tN43InH9Qduza1Fe",
    "jQeh6OW6Bg+fTsBXtPJWawF/3oMCdWVfZ8Iel0ilP+61B5ldkw7g//QMf5mqzvkQ",
    "HK5/gKPCfGUylRDtJOxOriM5XqCjgtw6Sye8hgql5DGOCZTrXAahNbnw0bGm5TYW",
    "qosD+B2Rh/Xa600j/X0JAABQ8Pi1b0PAycGdMW7HPQ1YAp5Q7PbQQxlmlWeHQEgO",
    "bwIDAQAB",
    "-----END PUBLIC KEY-----"
);

(note I've changed the last data line to bwIDAQAB to match your expected output).

And just for completeness here's your expected output:

$expected = '"k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ6AMIIBCgKCAQEAse68c1suNUQr0d79VudK" "XgmNxggQoaqR9fZoCrUz/gRS5XZm9wDL9HHxjYjEhZsuXQw1SZpYggjRQuqE+7Nx" "mhgn6DXXjWiTZ2b/ScE9mu+RQyh4hWEk9u+uUD2MZ9oPUZi2tN43InH9Qduza1Fe" "jQeh6OW6Bg+fTsBXtPJWawF/3oMCdWVfZ8Iel0ilP+61B5ldkw7g//QMf5mqzvkQ" "HK5/gKPCfGUylRDtJOxOriM5XqCjgtw6Sye8hgql5DGOCZTrXAahNbnw0bGm5TYW" "qosD+B2Rh/Xa600j/X0JAABQ8Pi1b0PAycGdMW7HPQ1YAp5Q7PbQQxlmlWeHQEgO" "bwIDAQAB"'

This snippet will do what you're after (with the above caveats):

$complete = @(
    "`"k=rsa; p=",
    ($content[1..($content.Length - 2)] -join "`" `""),
    "`""
) -join ""

$complete -eq $expected
# True

which basically:

  • starts with a "k=rsa; p= prefix
  • throws away the first and last line of the PEM input
  • joins the remaining lines with a literal " " separator
  • adds a " suffix

to give:

"k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ6AMIIBCgKCAQEAse68c1suNUQr0d79VudK" "XgmNxggQoaqR9fZoCrUz/gRS5XZm9wDL9HHxjYjEhZsuXQw1SZpYggjRQuqE+7Nx" "mhgn6DXXjWiTZ2b/ScE9mu+RQyh4hWEk9u+uUD2MZ9oPUZi2tN43InH9Qduza1Fe" "jQeh6OW6Bg+fTsBXtPJWawF/3oMCdWVfZ8Iel0ilP+61B5ldkw7g//QMf5mqzvkQ" "HK5/gKPCfGUylRDtJOxOriM5XqCjgtw6Sye8hgql5DGOCZTrXAahNbnw0bGm5TYW" "qosD+B2Rh/Xa600j/X0JAABQ8Pi1b0PAycGdMW7HPQ1YAp5Q7PbQQxlmlWeHQEgO" "bwIDAQAB"

If you prefer not ro use the range operator (..) you can do it with select-object instead:

$complete = @(
    "`"k=rsa; p=",
    (($content | select-object -Skip 1 -First ($content.Length - 2)) -join "`" `""),
    "`""
) -join ""

$complete -eq $expected
# True

which is a slightly more verbose way of doing the same thing.


Bonus Content

Your line:

$Complete = [regex]::split($contents, "-----BEGIN PUBLIC KEY-----(.*?)-----END PUBLIC KEY-----")

is coercing the $contents array of strings into a single string because that's what [regex]::Split expects, which you can see if you execute [regex]::Split in a PowerShell session:

PS> [regex]::Split

OverloadDefinitions
-------------------
static string[] Split(string input, string pattern)
static string[] Split(string input, string pattern, System.Text.RegularExpressions.RegexOptions options)
static string[] Split(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, timespan matchTimeout)

The first parameter in all three overloads is string input.

The default behaviour in PowerShell when "stringifying" an array of values is to concatenate their .ToString() results using a space separator. E.g.

PS> "$content"
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ6AMIIBCgKCAQEAse68c1suNUQr0d79VudK XgmNxggQoaqR9fZoCrUz/gRS5XZm9wDL9HHxjYjEhZsuXQw1SZpYggjRQuqE+7Nx mhgn6DXXjWiTZ2b/ScE9mu+RQyh4hWEk9u+uUD2MZ9oPUZi2tN43InH9Qduza1Fe jQeh6OW6Bg+fTsBXtPJWawF/3oMCdWVfZ8Iel0ilP+61B5ldkw7g//QMf5mqzvkQ HK5/gKPCfGUylRDtJOxOriM5XqCjgtw6Sye8hgql5DGOCZTrXAahNbnw0bGm5TYW qosD+B2Rh/Xa600j/X0JAABQ8Pi1b0PAycGdMW7HPQ1YAp5Q7PbQQxlmlWeHQEgO bwIDAQAB -----END PUBLIC KEY-----

and that's what you're passing into the regex, in case you were wondering :-)...

Upvotes: 1

Related Questions