I have now got 30+ Blog posts, all of which I would want to share via Twitter on a repetitive basis, say for example 3 times a week.
Yes, I could use TweetDeck or potentially another third-party tool but this is manual configuration as to what Tweet to send and when, I just want to post a random blog post several times a week without any interaction.
For this, I have decided to create an Azure Function and post a random Blog Post from data stored in Azure Table Storage. For both, it is literally pence per month to have both running – sounds good? Lets get configuring!
To start, familiarise yourself with three previous Blog Posts I created in line with this:-
- PowerShell Function – WordPress.com retrieve blog data using API
- Azure Functions:- Creating a PowerShell Function using Azure CLI
- Azure Functions – PowerShell Hashtable to apply App Settings using AzureCLI
As mentioned, Azure Table storage will be used to hold some data that I will pull from the WordPress.com API using Powershell. Azure Table storage is a No-SQL keyvalue store offering, super cheap! Microsoft snippet describes it well “Use Azure Table storage to store petabytes of semi-structured data and keep costs down”
I will be created two Functions:-
- Function1: AddBlogPosts
- Function2: BlogPostToTwitter
What does each Function do?
Function1: AddBlogPosts
- Function will be ran weekly
- Uses WordPress API to take blog data and store in Azure Table Storage
- Blog data will be both URL and Title, allowing the second function to take this data and upload a random Tweet to Twitter
- Additional columns will be populated with each new blog post being updated to a row “Tweeted = No” and “PartitionKey = twitterPartKey”
- On a weekly basis reviews what is on each TableRow against current about of WordPress blogs, if there is a difference it will add in the missing.
Function2: BlogPostToTwitter
- Function will be ran three times a week (Monday, Wednesday and Friday)
- Takes a random row from the Table Storage and uses this to post a blog to Twitter
- Each time it does this, it updates the column in row Tweeted to Yes, if no available rows left with No – it will update all rows to No and continue with Tweeting
- Posts Tweet in format: “From the Blog:”WordPress Blog Post Title,
WordPress Blog Post URL,”#Microsoft #Azure #AzureFamily #Blog“
Some Pre-Requisites
- Create a Resource Group & Storage Account Table
#Create Resource Group & Storage Account Table
$ResourceGroupName = "tamopsFunctionsTwitter"
$StorageAccountName = "tamopsfunctionstwittersa"
$TableName = "tamopsFuncTableBlog"
az group create --name $ResourceGroupName --location eastus
az storage account create --name $StorageAccountName --resource-group $ResourceGroupName --location eastus --sku Standard_LRS
$saContext = (Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName).Context
New-AzureStorageTable –Name $tableName –Context $saContext
2. Create a Service Principle within AzureAD to reference the Azure Table Storage inside Azure Function, for this example I have also applied Contributor role to the service principle
#Create a service principle within AzureAD
$AzureAdAppPassword = ConvertTo-SecureString '<PASSWORD>' -AsPlainText -Force
$AzureAdApp = New-AzureRmADApplication -DisplayName "TamOpsFuncADApp" -Password $AzureAdAppPassword -HomePage "https://www.thomasthornton.cloud" -IdentifierUris "https://www.thomasthornton.cloud"
# Create new service principle and apply permissions
New-AzureRmADServicePrincipal -ApplicationId $AzureAdApp.ApplicationId | New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $AzureAdApp.ApplicationId.Guid
Next create the Function App with runtime PowerShell
# Create Function App Service and change to version 1
$FunctionName = "tamopsfunctwitter"
$ResourceGroupName = "tamopsFunctionsTwitter"
$StorageAccountName = "tamopsfunctionstwittersa"
$region = "eastus"
az functionapp create -n $FunctionName -g $ResourceGroupName --consumption-plan-location $region --storage-account "$StorageAccountName" --runtime powershell
Now update the Function App Application settings with a list of environment variables that will be referenced in both Functions
$ResourceGroupName = "tamopsFunctionsTwitter"
$FunctionName = "tamopsfunctwitter"
$AppSettingsHash = @{
ResourceGroupName = $ResourceGroupName
StorageAccountName = "tamopsfunctionstwittersa"
AzureTableName = "tamopsFuncTable"
partitionKey = "twitterPartKey"
BlogSiteName = "thomasthornton.cloud"
twitterID= "tamstar1234"
twitterAccessToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
twitterAccessTokenSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
twitterAPIKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
twitterAPISecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AzureADTenantId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AzureADAppUser = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AzureADAppPassword = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AzureTableAzureTablePartitionKey = "twitterPartKey"
}
foreach ($AppSettingAdd in $AppSettingsHash.GetEnumerator()) {
az functionapp config appsettings set --resource-group $ResourceGroupName --name $FunctionName --settings "$($AppSettingAdd.Name) = $($AppSettingAdd.Value)"
}
Twitter access for the below variables are generated by created by Twitter Access Tokens, I used this tutorial to create an app within the Twitter API
twitterAccessToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
twitterAccessTokenSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
twitterAPIKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
twitterAPISecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
The AzureAD References are:-
- AzureADTenantId :- The Azure AD Tenant ID of the subscription
- AzureADAppUser :- Created above -IdentifierUris
- AzureADAppPassword :- Created above
AzureADTenantId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AzureADAppUser = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
AzureADAppPassword = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Azure Storage Tables use Partition Keys to assist with uniquely identifying every entity within a table. For this, I have used “twitterPartKey”
AzureTableAzureTablePartitionKey = "twitterPartKey"
You can see within the Function App settings these environment variables

Lets create the Functions, starting with AddBlogPosts the function app structure within the app service will be (each function will have its own folder):
tamopsfunctwitter
| –AddBlogPosts
| | -function.json
| | -AddBlogPosts.ps1
| | -Modules
| –BlogPostToTwitter
| | -function.json
| | -BlogPostToTwitter.ps1
| | -Modules
AddBlogPosts Function
Both Functions will be the same format as below, modules can be downloaded from GitHub Repo

function.json (Note:- cron configured to run weekly on Monday at 9.30am)
{
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 30 9 * * 1"
}
],
"disabled": false
}
AddBlogPosts.ps1
$Username = $env:AzureADAppUsername
$AzureADTenantId = $env:AzureTenantId
$AzureADAppPassword = ConvertTo-SecureString $env:AzureADAppPassword -AsPlainText -Force
$Credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username, $AzureADAppPassword
Login-AzureRmAccount -ServicePrincipal -Credential $Credential -TenantId $AzureADTenantId
$BlogSiteName = $env:BlogSiteName
$ResourceGroupName = $env:ResourceGroupName
$StorageAccountName = $env:StorageAccountName
$AzureTableName = $env:AzureTableName
$AzureTableAzureTablePartitionKey = $env:AzureTableAzureTablePartitionKey
#Get Storage Context to add Blog URL/details to
$saContext = (Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName).Context
$TableContext = Get-AzureStorageTable -Name $AzureTableName -Context $saContext
## Adds Blogs to Table Storage
$BlogPostsSearch = Invoke-RestMethod -uri "https://public-api.wordpress.com/rest/v1/sites/$BlogSiteName/posts/?number=100"
foreach ( $BlogPostsAdd in $BlogPostsSearch.posts) {
$urlcheck = $BlogPostsAdd.URL
$CheckURLColumn = Get-AzureStorageTableRowByCustomFilter -table $TableContext -customFilter "(URL eq '$urlcheck')"
if ($CheckURLColumn -eq $null){
Write-Output "Adding Blog Post: $urlcheck"
Add-StorageTableRow -table $TableContext -partitionKey $AzureTableAzureTablePartitionKey -rowKey ([guid]::NewGuid().tostring()) -property @{"Update"=$BlogPostsAdd.Title;"URL"=$BlogPostsAdd.URL;"Tweeted"="No"}
}
}
Zip the folder and upload the Function App Service
# Compress folder and deploy to Function App
$FunctionName = "tamopsfunctwitter"
$ResourceGroupName = "tamopsFunctionsTwitter"
Compress-Archive -Path * -DestinationPath AddBlogPosts.zip
az functionapp deployment source config-zip -n $FunctionName -g $ResourceGroupName --src ./AddBlogPosts.zip
BlogPostToTwitter Function
function.json (Note:- cron configured to run Monday,Wednesday and Friday at 11am)
{
"bindings": [
{
"name": "myTimer",
"type": "timerTrigger",
"direction": "in",
"schedule": "0 11 * * 1,3,5"
}
],
"disabled": false
}
BlogPostToTwitter .ps1
$AzureADTenantId = $env:AzureTenantId
$Username = $env:AzureADAppUsername
$AzureADTenantId = $env:AzureTenantId
$AzureADAppPassword = ConvertTo-SecureString $env:AzureADAppPassword -AsPlainText -Force
$Credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $Username, $AzureADAppPassword
Login-AzureRmAccount -ServicePrincipal -Credential $Credential -TenantId $AzureADTenantId
$ResourceGroupName = $env:ResourceGroupName
$StorageAccountName = $env:StorageAccountName
$AzureTableName = $env:AzureTableName
$twitterID = $env:twitterID
$twitterAccessToken = $env:twitterAccessToken
$twitterAccessTokenSecret = $env:twitterAccessTokenSecret
$twitterAPIKey = $env:twitterAPIKey
$twitterAPISecret = $env:twitterAPISecret
#Get Storage Context to add Blog URL/details to
$saContext = (Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroupName -Name $StorageAccountName).Context
$TableContext = Get-AzureStorageTable -Name $AzureTableName -Context $saContext
#Check for Available Tweets
$AvailableTweets = Get-AzureStorageTableRowByCustomFilter -table $TableContext -customFilter "(Tweeted eq 'No')"
if ($AvailableTweets -eq $null){
$AvailableTweetsCHECK = Get-AzureStorageTableRowByCustomFilter -table $TableContext -customFilter "(Tweeted eq 'Yes')"
foreach ($tweetedReplace in $AvailableTweetsCHECK) {
"No Available Tweets, refreshing tweeted column to No"
$tweetedReplace.tweeted = "No"
$tweetedReplace | Update-AzureStorageTableRow -table $TableContext
}
}
#Blog Post To Twitter
$TweetUpdate = Get-AzureStorageTableRowAll -table $TableContext
$TweetToSend = $TweetUpdate | ?{$_.tweeted -ne 'Yes'} | get-random
$IDtoChange = $TweetToSend.URL
$IDChange = Get-AzureStorageTableRowByCustomFilter -table $TableContext -customFilter "(URL eq '$IDtoChange')"
$IDChange.tweeted = "Yes"
$IDChange | Update-AzureStorageTableRow -table $TableContext
# Setup Twitter OAuth Hashtable
$TwitterOAuthConfig = @{ 'ApiKey' = $twitterAPIKey; 'ApiSecret' = $twitterAPISecret; 'AccessToken' = $twitterAccessToken; 'AccessTokenSecret' = $twitterAccessTokenSecret}
if($TwitterPost.length -le 230) {
$CombineTweet = ("From the Blog:",$TweetToSend.Update,$TweetToSend.URL,"#Microsoft #Azure #AzureFamily #Blog")
Write-Output "Posting Tweet: $CombineTweet"
$Parameters = @{ 'status' = $CombineTweet}
Invoke-TwitterRestMethod -ResourceURL 'https://api.twitter.com/1.1/statuses/update.json' -RestVerb 'POST' -Parameters $Parameters -OAuthSettings $TwitterOAuthConfig
}
You should now have two folders “AddBlogPosts” and “BlogPostsToTwitter”, create a .zip with both these folders inside
Please note that when you upload this to a function using below CLI, whatever is not in the folder will be removed.
# Compress folder and deploy to Function App
$FunctionName = "tamopsfunctwitter"
$ResourceGroupName = "tamopsFunctionsTwitter"
az functionapp deployment source config-zip -n $FunctionName -g $ResourceGroupName --src ./upload.zip
Once upload has been completed, these functions will now be viewable within Azure Portal

Lets run a test!
Running Function: AddBlogPosts….
Select AddBlogPosts Function and select Run and view Log Output:-

Review the Azure Storage Table, you can see it is now populated

That’s it, you now have Two Azure Functions to post a random Blog post from your WordPress Blog to Twitter!
Running Function: BlogPostToTwitter….
Select BlogPostToTwitter Function select Run and view Log Output:-

Lets check Twitter

Now check the Table Row to see if Tweeted has been updated to Yes

All working 🙂
Success!
You will have two Functions to assist you in posting your WordPress Blogs!
No editing is required for the Functions to work, all you need to ensure is all your Application settings are correct
Thanks for MeshkDevs for the Twitter PowerShell Module
Hello again Thomas. I spent all day yesterday trying to replicate this Twitter function – without luck.Would you be able to share the contents of the hosts.json file from your function with me? Cheers. Jason.
Which part is causing issue Jason?
I’ve DM’d you on Twitter. Cheers.