Read json value from the http response trigger by invoke-webrequest - powershell

I am trying to fetch a particular value from the JSON response of an invoke-web request. But the value is not capturing
Tried using the following script, where the $body contains the response.
$url = "http://localhost:9096/getMachineStatus"
$HTTP_Request = [System.Net.WebRequest]::Create($url)
$HTTP_Response = $HTTP_Request.GetResponse()
$HTTP_Status = [int]$HTTP_Response.StatusCode
$body = Invoke-WebRequest -Uri $url
The response of the above script:
{
"Name": "LocalTestMachine",
"Profile": "QA",
"Stacks": [
{
"Region": "Mumbai-1",
"State": "Stopped",
"StackName": "QA",
"StackCreationStatus": "CREATE_Success",
"Instances": [
{
"MachineName": "LocalMachine",
"IpAddress": "10.10.10.164",
"State": "stopped",
"InstanceId": "i-0777e90151b22da44",
"ImageId": "ami-0322ff2d8d099g56c",
"CustomImageName": "ubuntu-trusty-16.04",
"InstanceType": "m4.large",
"LaunchTime": "2019-09-04T02:42:36-04:00",
"AvailabilityZone": "Mumbai-1",
"Tags": [
{
"Key": "ProductLine",
"Value": "Cloud"
}]
}]
}]
}
I just want to retrieve the value associated with the object State which is Stopped.
I tried with
$currentVMState = $body | where {$_.State}
It is not working

To get the value of the first State item in the Stacks array, do this:
$json = $body | ConvertFrom-Json
$json.Stacks[0].State
returns
Stopped

First you need to convert the response to json:
$json = $body | ConvertFrom-Json
Then iterate the $json object to get the state value:
$json.stacks.instances | ForEach-Object { $_.State }

Related

Graph send mail with attachment

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.

Building a nested dictionary/hash tables in powershell displays "System.Collections.Hashtable"

I'm trying to create a body for a webrequest which is in the form of a nested dictionary.
$body +=#{}
$body["tables"] = #()
$body["tables"] += #{}
$body["tables"][0]["id"] += #{}
$body["tables"][0]["id"]["columnId"] = "1"
$body["tables"][0]["id"]["fieldType"] = "1"
$body["tables"][0]["textFilter"] = #{"value" = "123"}
$body2Json = ConvertTo-Json $body
When I try to print this, I get the following:
{
"tables": [
{
"id": "System.Collections.Hashtable",
"textFilter": "System.Collections.Hashtable"
}
]
}
Not sure what am I doing wrong here, still new to powershell
You created a pretty complex, multi-node PowerShell object, but the ConvertTo-Json cmdlet only converts the first two levels of depth before it stops.
Fortunately, You can control this behavior with the -Depth parameter like so:
ConvertTo-Json $body -Depth 5
{
"tables": [{
"id": {
"columnId": "1",
"fieldType": "1"
},
"textFilter": {
"value": "123"
}
}]
}

Why is only the first youtube playlist updated, when sending in two youtube playlist updates?

When running the code example below, only the first YouTube playlist ($YouTubePlaylistId1) is updated with an added video ($YouTubeVideoId).
While no update occurs for the second YouTube playlist ($YouTubePlaylistId2).
I don't receive any errors, but could there still be an issue with the json body below? Or is it something else I've missed here?
I've tried to switch around the playlistid, but it's always the first one defined that get's updated.
There's no difference if it's the same playlist id set in both variables: $YouTubePlaylistId1, $YouTubePlaylistId2, with a unique video ($YouTubeVideoId).
Tried multiple variations of the json body ($YouTubePlaylistVideoBody), but that usually ends with an error complaining about the format of the json.
# Set the first yt playlist id
$YouTubePlaylistId1 = "DummyPlaylistId1"
# Set the second yt playlist id
$YouTubePlaylistId2 = "DummyPlaylistId2"
# Set the yt video id
$YouTubeVideoId = "dQw4w9WgXcQ"
# Set access token provided by https://developers.google.com/oauthplayground
$GoogleAccessToken = "DummyAccessToken"
# Set the rest method to yt playlistitems
$YouTubePlaylistVideoUri = "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet"
# Set the JSON body
$YouTubePlaylistVideoBody = #"
{
"snippet": {
"playlistId": "$YouTubePlaylistId1",
"resourceId": {
"kind": "youtube#video",
"videoId": "$YouTubeVideoId"
}
},
"snippet": {
"playlistId": "$YouTubePlaylistId2",
"resourceId": {
"kind": "youtube#video",
"videoId": "$YouTubeVideoId"
}
}
}
"#
# Create new header object
$HeaderValue = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
# Append the Google access token in $GoogleAccessToken
$HeaderValue.Add("Authorization", "Bearer $GoogleAccessToken")
# Invoke rest command
Invoke-RestMethod -Headers $HeaderValue -Uri $Uri -Method "POST" -Body
$YouTubePlaylistVideoBody -ContentType "application/json"
Expected result is that both youtube playlists are updated with an video.
Actual result is that only the first playlist (defined in $YouTubePlaylistVideoBody) is being updated, without any errors reported back.
Edit: Attempted to use two different JSON arrays as below, but they all ends with error "(400) Bad Request":
$YouTubePlaylistVideoBody = #"
{
"snippet": [
"playlistId": "$YouTubePlaylistId1",
"resourceId": {
"kind": "youtube#video",
"videoId": "$YouTubeVideoId"
},
"playlistId": "$YouTubePlaylistId2",
"resourceId": {
"kind": "youtube#video",
"videoId": "$YouTubeVideoId"
}
]
}
"#
$YouTubePlaylistVideoBody = #"
[
"snippet": {
"playlistId": "$YouTubePlaylistId1",
"resourceId": {
"kind": "youtube#video",
"videoId": "$YouTubeVideoId"
}
},
"snippet": {
"playlistId": "$YouTubePlaylistId2",
"resourceId": {
"kind": "youtube#video",
"videoId": "$YouTubeVideoId"
}
}
]
"#

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
}

Query MSGraph API with PowerShell Invoke-RestMethod does not return same amount of details as MSGraph Explorer

I used MSGraph Explorer and PowerShell Invoke-RestMethod to query the same MSGraph API, but MSGraph Explorer returns way more details than the PowerShell command. Could this be a permission issue or I missed something in the PowerShell command.
Here is the URI, it is to retrieve the audit log for a particular directory change.
https://graph.microsoft.com/beta/auditLogs/directoryAudits/Directory_029A8_49125229
This is the output from MSGraph Explorer:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#auditLogs/directoryAudits/$entity",
"id": "Directory_029A8_49125229",
"category": "Core Directory",
"correlationId": "d534994f-61f4-4015-8040-c16f728ec8b3",
"result": "success",
"resultReason": "",
"activityDisplayName": "Update user",
"activityDateTime": "2018-10-04T05:41:19.9668303Z",
"loggedByService": null,
"initiatedBy": {
"app": null,
"user": {
"id": "1f5c2159-f515-4cea-a99c-11c6ce1f7a5e",
"displayName": null,
"userPrincipalName": "tom-admin#contoso.onmicrosoft.com",
"ipAddress": "<null>"
}
},
"targetResources": [
{
"#odata.type": "#microsoft.graph.targetResourceUser",
"id": "498b3884-f723-444c-9c01-b75ec2c0ef08",
"displayName": null,
"userPrincipalName": "Tom.Real#contoso.com",
"modifiedProperties": [
{
"displayName": "AssignedLicense",
"oldValue": "[\"[SkuName=ENTERPRISEPACK, AccountId=cdc4b90d-7fa9-4a, SkuId=6f94b900, DisabledPlans=[]]\"]",
"newValue": "[]"
},
{
"displayName": "AssignedPlan",
"oldValue": "[{\"SubscribedPlanId\":..., \"ServicePlanId\":\"50e68c76-46c6-4674-81f9-75456511b170\"}]",
"newValue": "[{\"SubscribedPlanId\":... 50e68c76-46c6-4674-81f9-75456511b170\"}]"
},
{
"displayName": "Included Updated Properties",
"oldValue": null,
"newValue": "\"AssignedLicense, AssignedPlan\""
},
{
"displayName": "TargetId.UserType",
"oldValue": null,
"newValue": "\"Member\""
}
]
}
],
"additionalDetails": [
{
"key": "UserType",
"value": "Member"
}
]
}
This is the output from Invoke-RestMethod:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#auditLogs/directoryAudits/$entity",
"id": "Directory_029A8_49125229",
"category": "Core Directory",
"correlationId": "d534994f-61f4-4015-8040-c16f728ec8b3",
"result": "success",
"resultReason": "",
"activityDisplayName": "Update user",
"activityDateTime": "2018-10-04T05:41:19.9668303Z",
"loggedByService": null,
"initiatedBy": {
"app": null,
"user": {
"id": "1f5c2159-f515-4cea-a99c-11c6ce1f7a5e",
"displayName": null,
"userPrincipalName": "tom-admin#contoso.onmicrosoft.com",
"ipAddress": "\u003cnull\u003e"
}
},
"targetResources": [
{
"#odata.type": "#microsoft.graph.targetResourceUser",
"id": "498b3884-f723-444c-9c01-b75ec2c0ef08",
"displayName": null,
"userPrincipalName": "Tom.Real#contos.com",
"modifiedProperties": " "
}
],
"additionalDetails": [
{
"key": "UserType",
"value": "Member"
}
]
}
As you can see Invoke-RestMethod does not return any details under "additionalDetails".
This is my PowerShell script
Function GetAuthToken
{
param
(
[Parameter(Mandatory=$true)]
$TenantName
)
Import-Module Azure
$clientId = "ef9bcdf0-a675-4cd5-9ec3-fa549f9ee4cf"
$redirectUri = "https://RedirectURI.com"
$resourceAppIdURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$TenantName"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$Credential = Import-Clixml -Path "C:\MIMA\tom_admin_cred.xml"
$AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $credential.UserName,$credential.Password
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId,$AADCredential)
return $authResult
}
if($Version -eq $null) {$Version='Beta'}
#------Get the authorization token------#
$token = GetAuthToken -TenantName $tenant
#------Building Rest Api header with authorization token------#
$authHeader = #{
'Content-Type'='application\json'
'Authorization'=$token.CreateAuthorizationHeader()
}
$uri = "https://graph.microsoft.com/beta/auditlogs/directoryAudits/Directory_029A8_49125229"
$results = Invoke-RestMethod -Uri $uri –Headers $authHeader –Method Get
$results |ConvertTo-Json
I believe everything is fine with your query and permissions, the results are different since for ConvertTo-Json cmdlet by default 2 levels of contained objects are included in the JSON representation.
So, if you want directoryAudit all properties to be included in result, Depth parameter needs to be specified explicitly, for example:
$results |ConvertTo-Json -Depth 3 #at least 3 levels for directoryAudit entry