Update Ghost blogs and pages with PowerShell
In order to remove a bit of repetitive manual work from my schedule I wrote a little sync between my Scrum.org class schedule to this blog.
The samples provided by Ghost are in JavaScript, Curl and Python, all languages I'm not fluent in, so I set out to do the same from PowerShell or C#.
The hardest part turned out to be the code to create the correct JWT token to authenticate against Ghost. In their admin panel they provide a set of tokens, but it turns out you can't just use these tokens as-is.
The API key essentially makes up 2 parts:
- The Key Identifier, that's the part up to the
:
- The Secret, that's the part after the
:
In order to use this key, we first have to split it into its two parts:
$parts = $adminApiKey -split ":"
$id = $parts[0]
$secret = $parts[1]
We then need to construct a JWT token from this key. I relied on the Posh-JWT package for that part:
Install-Module -Name JWT -force
$key = [Convert]::FromHexString($secret) # only works in PowerShell Core
$jwttoken = New-Jwt `
-Header (
@{
"alg" = "HS256"
"kid" = $id
"typ" = "JWT"
} | ConvertTo-Json
) `
-PayloadJson (
@{
"exp" = ([DateTimeOffset](Get-Date).AddMinutes(2)).ToUnixTimeSeconds()
"iat" = ([DateTimeOffset](Get-Date)).ToUnixTimeSeconds()
"aud" = "/admin/"
} | ConvertTo-Json)
-Secret $key
With this token, you can then invoke the Ghost API.
$headers = @{
Authorization = "Ghost $jwttoken"
"Content-Type" = "application/json"
}
$baseUri = "https://scrumbug.ghost.io/ghost/api"
$result = Invoke-RestMethod `
-Uri "$baseUri/admin/pages/" `
-Method GET `
-Headers $headers
As I said, I used this code to automatically sync my Scrum.org classes to this blog. You can find the (private) Ghost update GitHub Action here. To keep my secrets secure I added a couple of extra lines of code to register my secrets with the runner:
Write-Output "::add-mask::$id"
...
Write-Output "::add-mask::$secret"
...
Write-Output "::add-mask::$key"
...
Write-Output "::add-mask::$jwttoken"
End result? My classes are automatically updated 🎉: