Graph send mail with attachment - powershell

I'm trying to send a e-mail with attachment with powershell, as soon as I add in the attachment, I get a 400 Bad Request error, while it works find without attachment. Hope someone has a clue...
Part added:
"attachments": [
{
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "attachment.txt",
"contentType": "text/plain",
"contentBytes": "SGVsbG8gV29ybGQh"
}
]
Full request:
$Subject = "Subject2"
$Message = "Message2"
$Recipient = "testemailaddress"
$SaveToSentItems = $false
$Request=#"
{
"Message": {
"Subject": $(Escape-StringToJson $Subject),
"Body": {
"ContentType": "HTML",
"Content": $(Escape-StringToJson $Message)
},
"ToRecipients": [
{
"EmailAddress": {
"Address": "$Recipient"
}
}
],
"attachments": [
{
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "attachment.txt",
"contentType": "text/plain",
"contentBytes": "SGVsbG8gV29ybGQh"
}
]
},
"SaveToSentItems": "$(if($SaveToSentItems){"true"}else{"false"})"
}
"#
# Convert to UTF-8 bytes
$Request_bytes = [system.Text.Encoding]::UTF8.getBytes($Request)
$headers = #{
"Authorization" = "Bearer $($attributes.EXO)"
"Accept" = "text/*, multipart/mixed, application/xml, application/json; odata.metadata=none"
"Content-Type" = "application/json; charset=utf-8"
"X-AnchorMailbox" = (Read-AADIntAccesstoken $attributes.EXO).upn
"Prefer" = 'exchange.behavior="ActivityAccess"'
}
$url="https://outlook.office.com/api/v2.0/me/sendmail"
Invoke-RestMethod -UseBasicParsing -Uri $Url -Method Post -Headers $headers -Body $Request_bytes
Error:
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:47 char:1
Invoke-RestMethod -UseBasicParsing -Uri $Url -Method Post -Headers $h ...
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

I use this for send attachs in mails with ms graph in powershell
$attach = "C:\file.pdf"
$fileName = (Get-Item -Path $attach).Name
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes($attach))
$message = '{
"message": {
"subject": "subject",
"body": {
"contentType": "HTML",
"content": "'+$body+'"
},
"importance": "high",
"toRecipients": [
{
"emailAddress": {
"address": "'+$mail+'"
}
}
],
"attachments": [
{
"#odata.type": "#microsoft.graph.fileAttachment",
"name": "'+$fileName+'",
"contentType": "text/plain",
"contentBytes": "'+$base64string+'"
}
],
},
"saveToSentItems": "true"
}'
$URL = "https://graph.microsoft.com/v1.0/users/xxxxxxxxxxxxxxxxxxxx/sendMail"
Invoke-RestMethod -Method POST -Uri $URL -Headers $headers -Body $message
Convert to Base64 string before insert in the request.
I guess you have your own "body"!
Regards.

Related

Using POST method to SHOPIFY with Powershell

I am trying to use the following code
$uri="https://everything.myshopify.com/admin/api/202104/orders/ordernum/fulfillments.json"
$order = #{
fulfillments= {
id= 'id',
fulfillment_status="fulfilled"
}
}
$apikey = "key"
$password = "password"
$headers = #{"Authorization" = "Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($apikey+":"+$password))}
$body = (ConvertTo-Json $order)
$body
$file = Invoke-RestMethod -Uri $uri -Method Put -Body $body -ContentType 'application/json' -Headers $headers -UseBasicParsing
To change the fulfillment status of an order.
It is erroring however erroring with the message
Invoke-RestMethod: C:\Powershell Scripts\test.ps1:9:9 Line | 9 | $file
= Invoke-RestMethod -Uri $uri -Method Post -Body $body -Content … | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | Response status code does not indicate success: 406 (Not Acceptable).
$Body =
{
"fulfillments": {
"Attributes": [],
"File": "C:\\Powershell Scripts\\test.ps1",
"IsFilter": false,
"IsConfiguration": false,
"Module": null,
"StartPosition": {
"Content": "{\r\n id= 'id',\r\n fulfillment_status=\"fulfilled\"\r\n }",
"Type": 19,
"Start": 140,
"Length": 78,
"StartLine": 3,
"StartColumn": 19,
"EndLine": 6,
"EndColumn": 6
},
"DebuggerHidden": false,
"Id": "6d564632-241c-4644-8ffd-8cb9c1a76daa",
"Ast": {
"Attributes": "",
"UsingStatements": "",
"ParamBlock": null,
"BeginBlock": null,
"ProcessBlock": null,
"EndBlock": "id= 'id',\r\n fulfillment_status=\"fulfilled\"",
"DynamicParamBlock": null,
"ScriptRequirements": null,
"Extent": "{\r\n id= 'id',\r\n fulfillment_status=\"fulfilled\"\r\n }",
"Parent": "{\r\n id= 'id',\r\n fulfillment_status=\"fulfilled\"\r\n }"
}
}
}
Any help appreciated

How to provide the json request body in azure powershell script task

Hi I am running REST API call using the powershell task in Azure pipeline, how do i pass the $body value to the below API endpoint
Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Headers $header -Body $body
Reference of the below request body,
It seems you are trying to move a file, check the sample below:
Param(
[string]$organisation = "organisation",
[string]$repositoryId = "f2aa1d87-xxxx-48df-xxxx-6505ffxxxxf9",
[string]$keepForever = "true",
[string]$user = "user",
[string]$token = "token" )
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$postresults = "https://dev.azure.com/$organisation/_apis/git/repositories/$repositoryId/pushes?api-version=6.0"
$body = '{
"refUpdates": [
{
"name": "refs/heads/master",
"oldObjectId": "6e3c1f07d12eaf805a16db1352771816148c24b5"
}
],
"commits": [
{
"comment": "Moving activetasks.md to a new folder.",
"changes": [
{
"changeType": "rename",
"sourceServerItem": "/activetasks.md",
"item": {
"path": "/tasks/content/activetasks.md"
}
}
]
}
]
}'
$result = Invoke-RestMethod -Uri $postresults -Method Post -Body $body -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}

Format for json via powershell

I'm trying to use powershell to send json to DevOps API. I can't seem to figure out how to properly format this so powershell will take it. I keep getting this error. Any advice? I'm able to use the same json in Postman without any issues. Thanks
$URI= "https://vsaex.dev.azure.com/$ClientOrg/_apis/userentitlements?api-version=5.1-preview.2" $AzureDevOpsAuthenicationHeader = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($PAT)")) }
Invoke-RestMethod -uri $URI -Method POST -Headers $AzureDevOpsAuthenicationHeader -Body $a -ContentType "application/json"
$a= ConvertFrom-JSON #'
{
"accessLevel": {
"licensingSource": "msdn",
"accountLicenseType": "enterprise",
"msdnLicenseType": "enterprise"
},
"extensions": [
{
"id": "ms.feed"
}
],
"user": {
"principalName": "email#mail.com",
"subjectKind": "user"
},
"projectEntitlements": [
{
"group": {
"groupType": "projectAdministrator"
},
"projectRef": {
"id": "0685a10e"
}
}
]
}
'#
Invoke-RestMethod : {"$id":"1","innerException":null,"message":"Value cannot be null.\r\nParameter name: userEntitlement","typeName":"System.ArgumentNullException,
mscorlib","typeKey":"ArgumentNullException","errorCode":0,"eventId":0}
At line:4 char:1
+ Invoke-RestMethod -uri $URI -Method POST -Headers $AzureDevOpsAutheni ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Your body should be the JSON string itself and not an object built from the JSON.
$a= #'
{
"accessLevel": {
"licensingSource": "msdn",
"accountLicenseType": "enterprise",
"msdnLicenseType": "enterprise"
},
"extensions": [
{
"id": "ms.feed"
}
],
"user": {
"principalName": "email#mail.com",
"subjectKind": "user"
},
"projectEntitlements": [
{
"group": {
"groupType": "projectAdministrator"
},
"projectRef": {
"id": "0685a10e"
}
}
]
}
'#
Invoke-RestMethod -uri $URI -Method POST -Headers $AzureDevOpsAuthenicationHeader -Body $a -ContentType "application/json"

Invoke-RESTMethod PowerShell

I am trying to use the Invoke-Restmethod to call a set of API's, but it fails with the below error, i have also posted the same json format, can some let me know what could be wrong ?
### Ignore TLS/SSL errors
add-type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}}
"#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
#Create URL string for Invoke-RestMethod
$urlsend = 'https://' + 'vrslcm-01a.corp.local/lcm/api/v1/' + '/login'
#Credential
$Username = "admin#localhost"
$password = "VMware1!"
$basicAuth = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($Username):$Password"))
$headers = #{
"description"= "Testing Authentication"
}
$body = #{
$raw= '{\n\t\"username\": \"admin#localhost\",\n\t\"password\": \"vmware\"\n}'
"mode"= $raw
}
Invoke-RestMethod -Method POST -uri $urlsend -Headers $headers -Body $body -ContentType 'application/json'
Here is the sample jSON which iam trying to invoke via powershell, it consists of the header and the body. I need to understand how we could call the same jSON POSTMAN example via the PowerShell Invoke-RestMethod
"item": [
{
"name": "authorization",
"description": "",
"item": [
{
"name": "Login",
"event": [
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
"var response=JSON.parse(responseBody)",
"postman.setEnvironmentVariable(\"token\", response.token)"
]
}
}
],
"request": {
"url": "{{Server}}/lcm/api/v1/login",
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"description": ""
}
],
"body": {
"mode": "raw",
"raw": "{\n\t\"username\": \"admin#localhost\",\n\t\"password\": \"vmware\"\n}"
},
"description": ""
},
"response": []
},
{
"name": "Logout",
"request": {
"url": "{{Server}}/lcm/api/v1/logout",
"method": "POST",
"header": [
{
"key": "x-xenon-auth-token",
"value": "{{token}}",
"description": ""
}
],
"body": {},
"description": ""
},
"response": []
}
]
},
make $raw to a hashtable like
$raw = #{
username=$Username
password=$Password
}
add this hashtable to the $body hashtable
$body = #{
mode= $raw
}
but now it still is a hashtable the api cannot use. thus convert it to json like
$jsonBody = $body | ConvertTo-Json
using $jsonBody should then work when used like
Invoke-RestMethod -Method POST -uri $urlsend -Headers $headers -Body $jsonBody -ContentType 'application/json'
Like the error states, the problem is your hash definition.
A null key is not allowed in a hash literal.
PowerShell tries to evaluate $raw as a hash table key. Since it hasn't been defined before it is null and fails because null is not allowed. Try it like this:
$raw= '{\n\t\"username\": \"admin#localhost\",\n\t\"password\": \"vmware\"\n}'
$body = #{
"mode"= $raw
}

ForEach Invoke-RestMethod

I'm trying to make a request to the AccessPointsDetails endpoint of the Cisco Prime API and then loop through that to get all URL objects for the AccessPoints so I can get data on each of them.
I get the following output:
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3373245; $=3373245}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3413720; $=3413720}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3432295; $=3432295}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3432310; $=3432310}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3462672; $=3462672}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3497980; $=3497980}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3497993; $=3497993}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3512621; $=3512621}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/3526872; $=3526872}
VERBOSE: Making request to: #{#type=AccessPointDetails; #url=https://cpist/webacs/api/v3/data/AccessPointDetails/16162527426; $=16162527426}
#type #url $
----- ---- -
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3373245 3373245
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3413720 3413720
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3432295 3432295
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3432310 3432310
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3462672 3462672
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3497980 3497980
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3497993 3497993
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3512621 3512621
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/3526872 3526872
AccessPointDetails https://cpist/webacs/api/v3/data/AccessPointDetails/16162527426 16162527426
Here is the response JSON for one store as well:
{
"queryResponse": {
"#last": 9,
"#first": 0,
"#count": 10,
"#type": "AccessPointDetails",
"#requestUrl": "https://cpist/webacs/api/v3/data/AccessPointDetails?.group=0026",
"#responseType": "listEntityIds",
"#rootUrl": "https://cpist/webacs/api/v3/data",
"entityId": [
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3373245",
"$": "3373245"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3413720",
"$": "3413720"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3432295",
"$": "3432295"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3432310",
"$": "3432310"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3462672",
"$": "3462672"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3497980",
"$": "3497980"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3497993",
"$": "3497993"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3512621",
"$": "3512621"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3526872",
"$": "3526872"
},
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/16162527426",
"$": "16162527426"
}
]
}
}
I feel I may be a bit burnt and making a silly oversight?
Solution Code (See Accepted Answer):
Function allAP {
Write-Verbose "Getting all APs for Store $Store"
$storeApReq = "https://cpist/webacs/api/v3/data/AccessPointDetails.json?.group=$Store"
Write-Verbose "Making request to $storeApReq"
$Global:apIdListReq = Invoke-RestMethod -uri $storeApReq -method Get -ContentType 'application/json' -headers #{ Authorization = $auth }
$Global:apIdList = $apIdListReq.queryResponse.entityId
$Global:apIdCount = $apIdListReq.queryResponse."#count"
Write-Verbose "Found $siteAPCount APs in Sites Database. $apIdCount out of $siteAPCount APs found."
Write-Verbose "Response Received: $apIdList"
$Global:apIdURL = $apIdListReq.queryResponse.entityId
$Global:apURL = $apIdUrl.'#url'
Write-Verbose "Starting a loop."
ForEach($apIdURL in $apIdList) {
Invoke-RestMethod -uri $apURL -method Get -ContentType 'application/json' -headers #{ Authorization = $auth }
Write-Verbose "Making request to: $apURL"
$apURL
}
}
The biggest issue you're having is accessing the members of your returned object incorrectly. The Invoke-RestMethod is returning a pscustomobject representation of the JSON the application returns to you. Your example JSON looked like this:
{
"queryResponse": {
"#last": 9,
"#first": 0,
"#count": 10,
"#type": "AccessPointDetails",
"#requestUrl": "https://cpist/webacs/api/v3/data/AccessPointDetails?.group=0026",
"#responseType": "listEntityIds",
"#rootUrl": "https://cpist/webacs/api/v3/data",
"entityId": [
{
"#type": "AccessPointDetails",
"#url": "https://cpist/webacs/api/v3/data/AccessPointDetails/3373245",
"$": "3373245"
},
...
]
}
}
This gets transformed into pscustomobject:
[pscustomobject]#{
'queryResponse' = [pscustomobject]#{
'#last' = 9
'#first' = 0
'#count' = 10
'#type' = 'AccessPointDetails'
'#requestUrl' = 'https://cpist/webacs/api/v3/data/AccessPointDetails?.group=0026'
'#responseType' = 'listEntityIds'
'#rootUrl' = 'https://cpist/webacs/api/v3/data'
'entityId' = #(
[pscustomobject]#{
'#type' = 'AccessPointDetails'
'#url' = 'https://cpist/webacs/api/v3/data/AccessPointDetails/3373245'
'$' = '3373245'
}
...
)
}
}
I'm unsure why accessing .'#url' isn't working for you. Below is a working implementation of what you're trying to do.
function Get-AccessPoint
{
param
(
[Parameter(Position = 0, Mandatory)]
[ValidateNotNullOrEmpty()]
[string]
$Store
)
# function is accessing above-scope variables $auth and $siteAPCount
Write-Verbose "Retrieving APs for store $Store"
$uri = "https://cpist/webacs/api/v3/data/AccessPointDetails.json?.group=$Store"
Write-Verbose "Request: $uri"
$global:apIdListReq = Invoke-RestMethod -Uri $uri -ContentType application/json -Headers #{Authorization = $auth}
$global:apIdList = $apIdListReq.queryResponse.entityId
$global:apIdCount = $apIdListReq.'#count'
Write-Verbose "Found $siteAPCount APs in Sites Database. $apIdCount out of $siteAPCount APs found."
foreach ($entity in $apIdList)
{
Write-Verbose "Making request to $($entity.'#url')"
Invoke-RestMethod -Uri $entity.'#url' -ContentType application/json -Headers #{Authorization = $auth}
}
}