Hi all, I’m trying to craft a media upload and post script in powershell.
Using postman, the upload works. Using the code snippet for powershell postman produces doesn’t work.
I have tried other methods, but always receive
{"errors":[{"code":32,"message":"Could not authenticate you."}]}
My code is below:
#######################################
# generate variables for image upload #
#######################################
Add-Type -AssemblyName System.Security
$nonce = [System.Convert]::ToBase64String(([System.Text.Encoding]::ASCII.GetBytes("$([System.DateTime]::Now.Ticks.ToString())12345"))).Replace('=', 'g')
$EpochTimeNow = [System.DateTime]::UtcNow - [System.DateTime]::ParseExact("01/01/1970", "dd/MM/yyyy", $null)
$timestamp = [System.Convert]::ToInt64($EpochTimeNow.TotalSeconds).ToString();
$SignatureBase = "$([System.Uri]::EscapeDataString($HttpEndPoint))&"
$SignatureParams = @{
'oauth_consumer_key' = $ApiKey;
'oauth_token' = $AccessToken;
'oauth_signature_method' = 'HMAC-SHA1';
'oauth_timestamp' = $Timestamp;
'oauth_nonce' = $Nonce;
'oauth_version' = '1.0';
}
$Message = "test message"
$Username = "digitalfixjimmy"
$SignatureParams.GetEnumerator() | Sort-Object name | ForEach-Object {
Write-Host "Adding '$([System.Uri]::EscapeDataString(`"$($_.Key)=$($_.Value)&`"))' to signature string"
$SignatureBase += [System.Uri]::EscapeDataString("$($_.Key)=$($_.Value)&".Replace(',','%2C').Replace('!','%21'))
}
$SignatureBase = $SignatureBase.TrimEnd('%26')
$SignatureBase = 'POST&' + $SignatureBase
Write-Host "Base signature generated '$SignatureBase'"
## Create the hashed string from the base signature
$SignatureKey = [System.Uri]::EscapeDataString($ApiSecret) + "&" + [System.Uri]::EscapeDataString($AccessTokenSecret);
$hmacsha1 = new-object System.Security.Cryptography.HMACSHA1;
$hmacsha1.Key = [System.Text.Encoding]::ASCII.GetBytes($SignatureKey);
$OauthSignature = [System.Convert]::ToBase64String($hmacsha1.ComputeHash([System.Text.Encoding]::ASCII.GetBytes($SignatureBase)));
Write-Host "Using signature '$OauthSignature'"
## Build the authorization headers using most of the signature headers elements. This is joining all of the 'Key=Value' elements again
## and only URL encoding the Values this time while including non-URL encoded double quotes around each value
$AuthorizationParams = $SignatureParams
$AuthorizationParams.Add('oauth_signature', $OauthSignature)
$AuthorizationString = 'OAuth '
$AuthorizationParams.GetEnumerator() | Sort-Object name | ForEach-Object { $AuthorizationString += $_.Key + '="' + [System.Uri]::EscapeDataString($_.Value) + '", ' }
$AuthorizationString = $AuthorizationString.TrimEnd(', ')
Write-Host "Using authorization string '$AuthorizationString'"
$Body = "status=$Message"
Write-Host "Using POST body '$Body'"
$HttpEndPoint = "https://upload.twitter.com/1.1/media/upload.json?media_category=tweet_image"
$multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
$multipartFile = $file
$FileStream = [System.IO.FileStream]::new($multipartFile, [System.IO.FileMode]::Open)
$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$fileHeader.Name = "media"
$fileHeader.FileName = $file
$fileContent = [System.Net.Http.StreamContent]::new($FileStream)
$fileContent.Headers.ContentDisposition = $fileHeader
$multipartContent.Add($fileContent)
$stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$stringHeader.Name = "media_category"
$stringContent = [System.Net.Http.StringContent]::new("tweet_image")
$stringContent.Headers.ContentDisposition = $stringHeader
$multipartContent.Add($stringContent)
$body = $multipartContent
$response = Invoke-RestMethod -URI $HttpEndPoint -Method post -Headers @{ 'Authorization' = $AuthorizationString } -Body $body -ContentType "multipart/form-data"
$FileStream.Close()
$response | ConvertTo-Json
‘oauth_consumer_key’ = $ApiKey;
‘oauth_token’ = $AccessToken;
‘oauth_signature_method’ = ‘HMAC-SHA1’;
‘oauth_timestamp’ = $Timestamp;
‘oauth_nonce’ = $Nonce;
‘oauth_version’ = ‘1.0’;
I think these have to be sorted alphabetically according to OAuth spec. Creating a signature | Docs | Twitter Developer Platform
There might be other stuff too Authorizing a request | Docs | Twitter Developer Platform but i don’t know powershell well enough to spot it
1 Like
Thanks, I’ll reorder them and give that a go
Jimmy White
Ok that didnt work 
In forming my string, the uri is
https://upload.twitter.com/1.1/media/upload.json
My auth headers (key values changed for privacy) looks like this:
Name : Authorization
Value : OAuth include_entities="true", oauth_consumer_key="xxxxxxx", oauth_nonce="xxxxxxxxxxxxx",
oauth_signature="xxxxxxxxxxxxxxx%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1618560747",
oauth_token="xxxxxxxxxxxxx", oauth_version="1.0"
and my body looks like this
Headers
-------
{[Content-Disposition, System.String[]]}
{[Content-Type, System.String[]], [Content-Disposition, System.String[]]}