Powershell upload a pdf file using boundary MIME to RightFax Web Service - powershell

I am trying to upload a pdf file into Right fax via the RightFax Web Api. I can do this via PostMan and I am able to send the attachment afterwards. When I try do upload via PowerShell an I send my attachment I only get the Object Name in the actual fax ex. System.Net.Http.StreamContent. Here is my borrowed powershell code:
Add-Type -AssemblyName System.Net.Http
$AuthURL = "http://" + $RESTAPIServer + "/RightFax/API"
$BaseURL = "http://" + $RESTAPIServer + "/RightFax/API/SendJobs"
$AttachURL = "http://" + $RESTAPIServer + "/RightFax/API/Attachments"
$Base = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($RESTAPIUser+":"+$RESTAPIPassword))
$vCenterSessionURL = $BaseAuthURL
$Header = #{"Authorization" = "Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($RESTAPIUser+":"+$RESTAPIPassword))}
$TARGET_FOLDER_PATH = "\\SomeFolderPath\"
$TokenUri = "http://" + $RESTAPIServer + "/RightFax/API/Login?rememberMe={rememberMe}"
$Token = Invoke-RestMethod -Method GET -Headers $Header -Uri $TokenUri
Get-ChildItem $TARGET_FOLDER_PATH -Filter *.pdf |
Foreach-Object {
$TARGET_FILE_NAME = $_.Name
$LDA_TARGET_FILE_NAME = $TARGET_FOLDER_PATH + $TARGET_FILE_NAME
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $Base")
$fileName = $TARGET_FILE_NAME
$uri = $AttachURL
$filePath = $LDA_TARGET_FILE_NAME
$FileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open)
$fileContent = [System.Net.Http.StreamContent]::new($FileStream)
$boundary = [System.Guid]::NewGuid().ToString()
$LF = "`r`n"
$bodyLines = (
"--$boundary",
"Content-Disposition: attachment; name=`"$fileName`"; filename=`"$filePath`"",
"Content-Type: application/octet-stream",
"Content-Transfer-Encoding: base64$LF",
$fileContent,
"--$boundary--$LF"
) -join $LF
$Attach = Invoke-RestMethod -Uri $uri -Headers $headers -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines #-InFile $filePath
write-host $Attach
$FileStream.Dispose()
$fileContent.Dispose()
}

I figured it out. I needed to encode the file. For those of you who are here to actually get help and not here to play police for other users posts but neglect to add any actual positive helpful comments.... Here is the code for RightFax add attachments to a fax.
$AttachURL = "http://" + $RESTAPIServer + "/RightFax/API/Attachments"
$Base = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($RESTAPIUser+":"+$RESTAPIPassword))
$vCenterSessionURL = $BaseAuthURL
$Header = #{"Authorization" = "Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($RESTAPIUser+":"+$RESTAPIPassword))}
$TARGET_FOLDER_PATH = "\\SomeFolderPath\"
$TokenUri = "http://" + $RESTAPIServer + "/RightFax/API/Login?rememberMe={rememberMe}"
$Token = Invoke-RestMethod -Method GET -Headers $Header -Uri $TokenUri
Get-ChildItem $TARGET_FOLDER_PATH -Filter *.pdf |
Foreach-Object {
$TARGET_FILE_NAME = $_.Name
$LDA_TARGET_FILE_NAME = $TARGET_FOLDER_PATH + $TARGET_FILE_NAME
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $Base")
$fileName = $TARGET_FILE_NAME
$uri = $AttachURL
$filePath = $LDA_TARGET_FILE_NAME
$fileRead = [IO.File]::ReadAllBytes($filePath)
$enc = [System.Text.Encoding]::GetEncoding("iso-8859-1")
$fileEnc = $enc.GetString($fileRead)
$boundary = [System.Guid]::NewGuid().ToString()
$LF = "`r`n"
$bodyLines = (
"--$boundary",
"Content-Disposition: form-data; name=`"$fileName`"; filename=`"$ResultFilePath`"", # filename= is optional
"Content-Type: application/pdf$LF",
$fileEnc,
"--$boundary--$LF"
) -join $
$Attach = Invoke-RestMethod -Uri $uri -Headers $headers -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -TimeoutSec 20 -Body $bodyLines
Write-host $Attach
}

I'm setting up a different fax service (SRFax) that needs the attachments in base64.
$file = [IO.File]::ReadAllBytes("C:\Users\Path\To\File.pdf")
$filebase64 = [System.Convert]::ToBase64String($file)

Related

File upload via Pipedrive API

I need to include the lead_id in the body with the file content. The file uploads well when I use
$data = Invoke-RestMethod -Uri $URL -Method 'Post' -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $BodyLines.
Naturally the file is not attached to the lead. When I use
$data = Invoke-RestMethod -Uri $URL -Method 'Post' -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $Body
I always get error 400. Specification of $Body is wrong, but how?
#URL for Deal listing with your $company_domain and $api_token variables
$URL = 'https://' + $company_domain + '.pipedrive.com/api/v1/files?api_token=' + $api_token
$URL
#
$FilePath = $LOCALpath + "\webtilaus\Tarjouspyynto_2023-02-03_09-50-44.txt"
$data =#()
$fileBytes = [System.IO.File]::ReadAllBytes($FilePath);
$fileEnc = [System.Text.Encoding]::GetEncoding('UTF-8').GetString($fileBytes);
$boundary = [System.Guid]::NewGuid().ToString();
$LF = "`r`n";
""
$BodyLines = (
"--$boundary",
"Content-Disposition: form-data; name=`"file`"; filename=`"temp.txt`"",
"Content-Type: application/octet-stream$LF",
$fileEnc,
"--$boundary--"+ $LF
) -join $LF
$Body = #{
"deal_id" = "25"
"file" = $bodyLines
}
$data = Invoke-RestMethod -Uri $URL -Method 'Post' -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $BodyLines # This uploads
$data = Invoke-RestMethod -Uri $URL -Method 'Post' -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $Body # This gives error 400`

InvalidOperation in PowerShell RestMethod API Call using Bearer sending Body as HASHTABLE

In PowerShell using Invoke-RestMetjhod to call different API´s I am stuck getting an InvalidOperation error when trying to pass both header and body information to the POST call.
My script is:
Set-StrictMode -Version Latest
$ApiToken = Get-Content ‘C:\APIEnergiNet\api_token.txt’
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer $ApiToken")
$response = Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/token' -Method 'GET' -Headers $headers
$GetMetringPointID = Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/meteringpoints/meteringpoints?includeAll=true' -Headers #{ Authorization = "Bearer " + $response.result }
foreach($result in $GetMetringPointID){
$CurrentMeteringID = $GetMetringPointID.result.meteringPointId
foreach($Currentresult in $CurrentMeteringID){
$MeterID = $Currentresult
$GetCharges = Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/MeteringPoints/MeteringPoint/GetCharges' -Method 'POST' -Headers #{ Authorization = "Bearer " + $response.result } -Body #{ meteringPoints = #( #{meteringPoint = "$Currentresult" } ) }
$GetCharges
}
}
The API needs the following sent in the body :
{
"meteringPoints": {
"meteringPoint": [
"string"
]
}
}
if I create variable $postParams containing the data like this:
$postParams = #{
meteringPoints = #(
#{meteringPoint = "$MeterID" }
)
}
$postParams
it returns:
meteringPoints {System.Collections.Hashtable}
The API has a swagger here https://api.eloverblik.dk/customerapi/index.html
Can anyone help me why I get this error and how to fix it?
Best Regards
Stig :-)
UPDATE WITH LATEST CODE BELOW:
Set-StrictMode -Version Latest
$ApiToken = Get-Content ‘C:\APIEnergiNet\api_token.txt’
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer $ApiToken")
$response = Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/token' -Method 'GET' -Headers $headers
$GetMetringPointID = Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/meteringpoints/meteringpoints?includeAll=true' -Headers #{ Authorization = "Bearer " + $response.result }
foreach ($result in $GetMetringPointID)
{
$CurrentMeteringID = $GetMetringPointID.result.meteringPointId
foreach ($Currentresult in $CurrentMeteringID)
{
$MeterID = $Currentresult
$postParams = #{
meteringPoints = #(
#{ meteringPoint = "$MeterID" }
)
} | ConvertTo-Json
$resultlist = Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/MeteringPoints/MeteringPoint/GetCharges' -Method 'POST' -ContentType 'application/json' -Headers #{ Authorization = "Bearer " + $response.result } -Body #{ $postParams }
$resultlist
}
}
ERROR I NOW GET:
ParserError: C:\APIEnergiNet\api.ps1:31:245
Line |
31 | … Authorization = "Bearer " + $response.result } -Body #{ $postParams }
| ~
| Missing '=' operator after key in hash literal.
I've made this little PS for you based on yours
$Path = "C:\EnergiNet\"
$TokenFile = $Path + "token.txt"
$JSON_ResponseFile = $Path + "Response.json"
$XML_ResponseFile = $Path + "Response.xml"
$ApiToken = Get-Content $TokenFile
# Get Auth token #
$response = Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/token' -Method 'GET' -Headers #{ Authorization = "Bearer " + $ApiToken }
$Auth_Token = $response.result
$body = '{ "meteringPoints": {"meteringPoint": ["571313174xxxxxxxxxxx","571313174xxxxxxxxxxx","571313174xxxxxxxxxxx"] }}'
$headers = #{
'Authorization' = "Bearer " + $response.result
'Accept' = 'application/json'
}
Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/meterdata/gettimeseries/2023-01-01/2023-02-01/Quarter' -Method 'POST' -ContentType 'application/json' -Headers $headers -Body $body | ConvertTo-Json -Depth 100 | out-file $JSON_ResponseFile
$headers = #{
'Authorization' = "Bearer " + $response.result
'Accept' = 'application/xml'
}
(Invoke-RestMethod 'https://api.eloverblik.dk/customerapi/api/meterdata/gettimeseries/2023-01-01/2023-02-01/Quarter' -Method 'POST' -ContentType 'application/json' -Headers $headers -Body $body).outerXml | out-file $XML_ResponseFile

Invoke-WebRequest in an own function with arguments

I am trying to run an Invoke-WebRequest command on PowerShell Core 6.3 on a Ubuntu system with the following settings to create a forwarder:
$userLocalMailPart = "user"
$userGlobalMailPart = "Hotmail.com"
$address = "Some Address"
$pair = $login + ":" + $password
$bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
$base64 = [System.Convert]::ToBase64String($bytes)
$basicAuthValue = "Basic $base64"
$url = "https://" + $server + ":" + $port + "/Domain/ObjectList.html"
$headers = #{"Authorization" = $basicAuthValue;
"Referer" = $url
}
$body = #{
"NewForwarderName" = $userLocalMailPart ;
"NewForwarderAddress" = $address;
"CreateForwarder" = "Create Forwarder"
}
$result = Invoke-WebRequest `
-Uri $url `
-SkipCertificateCheck `
-Method 'POST' `
-Headers $headers `
-Body $body
This runs perfectly. No error and the forwarder is successfully created.
Now I want to use a function like this:
[Web]::requestHeaderContent($url, $headers, (ConvertTo-Json($body)), 'POST')
[object] static requestHeaderContent([String] $url, [hashtable] $headers, [Object] $body, [String] $meth) {
Invoke-WebRequest `
-Uri $url `
-SkipCertificateCheck `
-Method $meth `
-Headers $headers `
-Body $body
}
The variables like headers and body are the same. I also tried it with ConvertTo-Json but it just don’t work. I also receive a Success 200 Code but the forwarder is not created. I guess my problem are the parameters. Any idea what I am doing wrong?
Thanks
Stephan

Azure DevOps how to edit Wiki page via REST API

I want to edit a Azure DevOps wiki page over the REST API (Azure DevOps Server 2019.0.1).
When I run this PowerShell script:
#VARIABLES
$api = "api-version=5.0"
$root = "http://136.202.18.216:8070/Samples"
$personalToken = "uwawlzqp6j7i1nd5dasspwkwp63tr2w2sxb5563zrla2bivynbza"
#AUTHORIZATION
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalToken)"))
$headers = #{
"Authorization" = ('Basic {0}' -f $token)
"If-Match" = '*'
}
#PROJECT VARIABLES
$project = "Framework%20A"
$pageToUpdate = "/Seite2"
#BODY
$body = #"
{
"content": "Hello"
}
"#
#GET
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&includeContent=True&$api"
$content = Invoke-RestMethod -Uri $url -Method Get -ContentType "application/json" -Headers $headers
Write-Host "$($content.path) = $($content.content)" -ForegroundColor Yellow
#PUT
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&$api"
$update = Invoke-RestMethod -Uri $url -Method Put -ContentType "application/json" -Headers $header -Body $body -Verbose
Write-Host $update.content -ForegroundColor Yellow
exit(0)
The consolen output is:
/Seite2 = Seite 2 Content
AUSFÜHRLICH: PUT http://136.202.18.216:8070/Samples/Framework A/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=/Seite2&api-version=5.0 with -1-byte payload
Invoke-RestMethod: {"$ id": "1", "innerException": null, "message": "The required \" IfMatch \ "header specified in the request is an invalid page version Version of the
Wiki page as \ "IfMatch \" header for the request. \ R \ nParameterName: IfMatch "," typeName ":" Microsoft.TeamFoundation.SourceControl.WebServer.InvalidArgumentValueException,
Microsoft.TeamFoundation.SourceControl.WebServer "," TypeKey ":" InvalidArgumentValueException "," error code ": 0," eventId ": 0}
In C:\Users\mkober\Desktop\Azure DevOps Skripte (Bearbeitung)\WikiAPI.ps1:34 Zeichen:11
+ $update = Invoke-RestMethod -Uri $url -Method Put -ContentType "appli ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
The first line /Seite2 = Seite 2 Content is the result of a successful get request from the page I want to edit. The put request occures the error. What am I doing wrong here?
UPDATE: (Working Example)
#VARIABLES
$api = "api-version=5.0"
$root = "http://136.202.18.216:8070/Samples"
$personalToken = "uwawlzqp6j7i1nd5dasspwkwp63tr2w2sxb5563zrla2bivynbza"
#AUTHORIZATION
$token = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($personalToken)"))
$headers = #{
"Authorization" = ('Basic {0}' -f $token)
"If-Match" = '{0}'
}
#PROJECT VARIABLES
$project = "Framework%20A"
$pageToUpdate = "/Seite2"
#BODY
$body = #"
{
"content": "Hello"
}
"#
#---------------------------------------------------------------------------------------------------------------------------
#GET
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&includeContent=True&$api"
$content = Invoke-WebRequest -Uri $url -Method Get -ContentType "application/json" -Headers $headers
$etag = $content.Headers.ETag
$headers.'If-Match' = $headers.'If-Match' -f $etag
Write-Host "$($content.path) = $($content.content)" -ForegroundColor Yellow
#PUT
$url = "$root/$project/_apis/wiki/wikis/2e887fde-ce76-4180-aa8d-f26ed4799eb3/pages?version=wikiMaster&path=$pageToUpdate&$api"
$update = Invoke-RestMethod -Uri $url -Method Put -ContentType "application/json" -Headers $headers -Body $body -Verbose
Write-Host $update.content -ForegroundColor Yellow
exit(0)
#---------------------------------------------------------------------------------------------------------------------------
In the If-Match header you can't just put '*', you need to put there the ETag of the page.
How do you get it? in your first GET call use Invoke-WebRequest (instaed of Invoke-RestMethod), now in the response you will get also headers response and there the ETag exist:
$page = Invoke-WebRequest -Uri $url ...........
$etag = $page.Headers.ETag
$headers = #{
"Authorizaion = ....."
"If-Match" = $etag
}
Now the second Invoke-RestMethod will work to update the page.

Upload file with Powershell

I'm trying to create a command in Powershell that is an equivalent of
curl -u username:abcd -i -F name=files -F filedata=#employees.csv https://myservice.com/v1/employees/csv
I need to have file name in the request. So in Powershell
$FilePath = 'employees.csv'
$FieldName = 'employees.csv'
$ContentType = 'text/csv'
$username = "user"
$password = "..."
$FileStream = [System.IO.FileStream]::new($filePath, [System.IO.FileMode]::Open)
$FileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new('form-data')
$FileHeader.Name = $FieldName
$FileHeader.FileName = Split-Path -leaf $FilePath
$FileContent = [System.Net.Http.StreamContent]::new($FileStream)
$FileContent.Headers.ContentDisposition = $FileHeader
$FileContent.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse($ContentType)
$MultipartContent = [System.Net.Http.MultipartFormDataContent]::new()
$MultipartContent.Add($FileContent)
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($username):$($password)" ))
$Response = Invoke-WebRequest -Headers #{Authorization = "Basic $base64AuthInfo" } -Body $MultipartContent -Method 'POST' -Uri 'https://myservice.com/v1/employees/csv'
Is there a better (shorter) way of doing this so I have a file name in Content Disposition?
$body = get-content employees.csv -raw
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("user:pass" ))
Invoke-RestMethod -Headers #{Authorization = "Basic $base64AuthInfo" } -uri url -Method Post -body $body -ContentType 'text/csv
# a flag -ContentDispositionFileName would be great
Taking a guess with what your endpoint will accept, but here's an example of your curl request in powershell:
$u, $p = 'username', 'password'
$b64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${u}:$p"))
$invokerestmethodParams = #{
'Uri' = 'https://myservice.com/v1/employees/csv'
'Method' = 'POST'
'Headers' = #{ Authorization = "Basic $b64" }
'InFile' = 'C:\path\to\employees.csv'
'SessionVariable' = 's' # use $s to view content headers, etc.
}
$output = Invoke-RestMethod #invokerestmethodParams