I am having problems getting assembling this Json in Powershell
{
"totalCount": 1,
"list": [
{
"type": "ToggleLightingState",
"order": 1,
"delay": null,
"postDelay": null,
"name": "Toggle lighting state of light L-17E-611-KB-1",
"parameters": {
"relayIds": [],
"curveType": null,
"behavior": null,
"duration": null,
"useAssignedSpace": false,
"spaceIds": [],
"lightIds": [
2408
],
"spaceGroupIds": []
}
}
]
}
I am Iterating through an array using a for loop to fill in the values. I am just struggling to generate a list inside a list in JSON
$ActionList = #{
#(
#{
type = 'ToggleLightingState'
order = 1
delay = 'null'
postDelay = 'null'
name = $actionSets[$i][0]
}
)
}
ConvertTo-Json -InputObject $ActionList
You don't have the name of the array "list" inside the object. It looks like you can't have an unnamed array inside an object. I don't know what $actionsets is, so I took off the indexes. Plus fixing your syntax errors results in the below. Note that 'null' and $null are different things.
$ActionList = #{
list = #(
#{
type = 'ToggleLightingState'
order = 1
delay = 'null'
postDelay = 'null'
name = $actionSets
}
)
}
ConvertTo-Json -InputObject $ActionList
{
"list": [
{
"delay": "null",
"name": null,
"postDelay": "null",
"type": "ToggleLightingState",
"order": 1
}
]
}
Using this ConvertTo-Expression cmdlet:
$Json = #'
{
"totalCount": 1,
"list": [
{
"type": "ToggleLightingState",
"order": 1,
"delay": null,
"postDelay": null,
"name": "Toggle lighting state of light L-17E-611-KB-1",
"parameters": {
"relayIds": [],
"curveType": null,
"behavior": null,
"duration": null,
"useAssignedSpace": false,
"spaceIds": [],
"lightIds": [
2408
],
"spaceGroupIds": []
}
}
]
}
'#
$Json | ConvertFrom-Json |ConvertTo-Expression
[pscustomobject]#{
totalCount = 1
list = ,[pscustomobject]#{
type = 'ToggleLightingState'
order = 1
delay = $Null
postDelay = $Null
name = 'Toggle lighting state of light L-17E-611-KB-1'
parameters = [pscustomobject]#{
relayIds = #()
curveType = $Null
behavior = $Null
duration = $Null
useAssignedSpace = $False
spaceIds = #()
lightIds = ,2408
spaceGroupIds = #()
}
}
}
Or as hashtable:
$Json |ConvertFrom-Json -AsHashTable |ConvertTo-Expression
#{
totalCount = 1
list = ,#{
postDelay = $Null
parameters = #{
duration = $Null
spaceGroupIds = #()
relayIds = #()
spaceIds = #()
useAssignedSpace = $False
curveType = $Null
behavior = $Null
lightIds = ,2408
}
type = 'ToggleLightingState'
delay = $Null
order = 1
name = 'Toggle lighting state of light L-17E-611-KB-1'
}
}
I am looking for a Powershell function to convert XML into a PsCustomObject which can finally exported as JSON. For this I created this small XML Test object:
[xml]$Xml = #"
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
"#
This gives my an XML DocumentElement which I finally need to convert into the same object like the one from this call:
$Json = convertfrom-json #"
{
"Action": {
"name": "Test", "id": "1", "Text": "sample",
"sub": [
{"name": "s1","id": "2"},
{"name": "s2","id": "3"}
],
"End": {"details": "no"}
}
}
"#
Is there any smart way to get this done? I tested multiple functions from similar questions here but nothing really works as expected.
Because of the ambiguities, there is no standard way of converting XML to JSON. So you really have to roll your own function that interprets the XML in the way that matches your desired output.
Here is a generic solution:
Function ConvertFrom-MyXml( [xml.XmlNode] $node ) {
# Create an ordered hashtable
$ht = [ordered] #{}
# Copy the XML attributes to the hashtable
$node.Attributes.ForEach{ $ht[ $_.Name ] = $_.Value }
$node.ChildNodes.ForEach{
if( $_.FirstChild -is [xml.XmlText] ) {
# Add content of XML text node
Add-DictionaryArrayItem -Dict $ht -Key $_.LocalName -Value $_.FirstChild.InnerText
}
elseif( $_ -is [xml.XmlElement] ) {
# Add nested hashtable for the XML child elements (recursion)
Add-DictionaryArrayItem -Dict $ht -Key $_.LocalName -Value (ConvertFrom-MyXml $_)
}
}
$ht # Output
}
Function Add-DictionaryArrayItem( $Dict, $Key, $Value ) {
if( $Dict.Contains( $Key ) ) {
$curValue = $Dict[ $Key ]
# If existing value is not already a list...
if( $curValue -isnot [Collections.Generic.List[object]] ) {
# ...turn it into a list.
$curValue = [Collections.Generic.List[object]] #($curValue)
$Dict[ $Key ] = $curValue
}
# Add next value to the array. This updates the array in the hashtable,
# because $curValue is a reference.
$curValue.Add( $Value )
}
else {
# Key doesn't exist in the hashtable yet, so simply add it.
$Dict[ $Key ] = $Value
}
}
[xml]$Xml = #"
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
"#
ConvertFrom-MyXml $Xml | ConvertTo-Json -Depth 100
Output:
{
"Action": {
"name": "Test",
"id": "1",
"Text": "sample",
"sub": [
{
"name": "s1",
"id": "2"
},
{
"name": "s2",
"id": "3"
}
],
"end": {
"details": "no"
}
}
}
Function ConvertFrom-MyXml outputs an ordered hashtable. There is no need to convert to PSCustomObject as ConvertFrom-Json works with hashtables as well. So we can keep the code simpler.
ConvertFrom-MyXml loops over attributes and elements (recursively) of the given XML node. It calls the helper function Add-DictionaryArrayItem to create an array if a key already exists in the hashtable. Actually this is not a raw, fixed-size array (like #(1,2,3) creates), but a dynamically resizable List, which behaves very similar to an array but is much more efficient when adding many elements.
Note that a single sub element won't be turned into an array. If some elements should always be converted to arrays, you'd have to pass some kind of schema to the function (e. g. a list of element names) or add metadata to the XML itself.
As suggested by OP, here is an alternative version of the code, that consists of only a single function:
Function ConvertFrom-MyXml( [xml.XmlNode] $node ) {
$ht = [ordered] #{}
$node.Attributes.ForEach{ $ht[ $_.Name ] = $_.Value }
foreach( $child in $node.ChildNodes ) {
$key = $child.LocalName
$value = if( $child.FirstChild -is [xml.XmlText] ) {
$child.FirstChild.InnerText
} elseif( $child -is [xml.XmlElement] ) {
ConvertFrom-MyXml $child
} else {
continue
}
if( $ht.Contains( $Key ) ) {
$curValue = $ht[ $Key ]
if( $curValue -isnot [Collections.Generic.List[object]] ) {
$curValue = [Collections.Generic.List[object]] #($curValue)
$ht[ $Key ] = $curValue
}
$curValue.Add( $Value )
}
else {
$ht[ $Key ] = $Value
}
}
$ht # Output
}
Might not be exactly what you're looking for but I would personally do this with classes:
class Sub {
[string] $Name
[Int] $Id
Sub([string] $Name, [int] $Id) {
$this.Name = $Name
$this.Id = $Id
}
}
# Windows PowerShell will not like it named End :)
class End2 {
[string] $Details
End2 ([string] $Details) {
$this.Details = $Details
}
}
class Action {
[string] $Name
[int] $Id
[string] $Text
[Sub[]] $Sub
[End2] $End
Action () { }
Action ([string] $Name, [int] $Id, [string] $Text, [object[]] $Sub, [End2] $End) {
$this.Name = $Name
$this.Id = $Id
$this.Text = $Text
$this.Sub = #( $Sub )
$this.End = $End
}
[string] ToJson() {
return #{ Action = $this } | ConvertTo-Json -Depth 99
}
}
Now you can instantiate and convert to to Json your Action class like this:
[Action]::new(
'Test', 1, 'Sample',
#(
[Sub]::new('s1', 2)
[Sub]::new('s2', 3)
),
'No'
).ToJson()
Or like this:
([Action]#{
Name = 'Test'
Id = 1
Text = 'Sample'
Sub = #(
[Sub]::new('s1', 2)
[Sub]::new('s2', 3)
)
End = 'No'
}).ToJson()
Both would output the following Json:
{
"Action": {
"Name": "Test",
"Id": 1,
"Text": "Sample",
"Sub": [
{
"Name": "s1",
"Id": 2
},
{
"Name": "s2",
"Id": 3
}
],
"End": {
"Details": "No"
}
}
}
Look at this
may help
class sub {
[string] $name;
[int] $id;
}
class end {
[string] $details;
}
class Action {
[string] $Text;
[sub] $sub1;
[sub] $sub2;
[end] $end;
[string] $name;
[int] $id;
}
<#
<Action name="Test" id="1">
<Text>sample</Text>
<sub name="s1" id="2" />
<sub name="s2" id="3" />
<end details="no" />
</Action>
#>
$firstitem = [Action]#{
text = 'sample';
name = "test";
id = "1";
sub1=#{
name = "s1";
id = "2";}
sub2 = #{
name = "s2";
id = "3";}
end = #{
details = "no";}
}
$firstitem | ConvertTo-Json
<#
Output =
{
"Text": "sample",
"sub1": {
"name": "s1",
"id": 2
},
"sub2": {
"name": "s2",
"id": 3
},
"end": {
"details": "no"
},
"name": "test",
"id": 1
}
#>
I got a PS script to retrieve an AuditLog event from MS Graph. The script code is below. It gets the event details in JSON format.
# Create Authentication Token for MS Graph
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
}
Function Get-aAuditEvent
{
param
(
[Parameter(Mandatory=$true)]
$Tenant
)
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_3WOOD_3967500"
# $uri = "https://graph.microsoft.com/beta/auditlogs/directoryAudits"
Try {
$results = Invoke-RestMethod -Uri $uri –Headers $authHeader –Method Get
$results |ConvertTo-Json -depth 4
}
catch{
Write-Host "Error while retrieving report!" -ForegroundColor red
$auditReports = $_.Exception.Response
}
}
Get-aAuditEvent -Tenant "contoso.onmicrosoft.com"
The result of the code is as below. Notice the content of "modifiedProperties" is not in JSON format? It seems somehow the value of this property has converted to hashtable. However, I tried to put this value into a hashtable and it couldn't parse it properly anyway. Maybe because "newValue" is too long for a hash table?
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#auditLogs/directoryAudits/$entity",
"id": "Directory_3WOOD_3967500",
"category": "Core Directory",
"correlationId": "559450b1-d1e8-4020-a420-4c3c6234ba44",
"result": "success",
"resultReason": "",
"activityDisplayName": "Update user",
"activityDateTime": "2018-10-13T14:57:33.328183Z",
"loggedByService": null,
"initiatedBy": {
"app": null,
"user": {
"id": "9327abf7-93ea-4007-a15c-9b77b5360cc9",
"displayName": null,
"userPrincipalName": "tom-admin#contoso.onmicrosoft.com",
"ipAddress": "\u003cnull\u003e"
}
},
"targetResources": [
{
"#odata.type": "#microsoft.graph.targetResourceUser",
"id": "2a58e6ca-2207-4fc0-ba5d-210cd5de25dc",
"displayName": null,
"userPrincipalName": "tom.chen#contoso.com",
"modifiedProperties": [
"#{displayName=AssignedLicense; oldValue=[]; newValue=[\"[SkuName=ENTERPRISEPACK, AccountId=cdc4b90d-7fa9-4a12-8d58-c2872266673c, SkuId=6fd2c87f-b296-42f0-b197-1e91e994b900, DisabledPlans=[]]\"]}",
"#{displayName=AssignedPlan; oldValue=[]; newValue=[{\"SubscribedPlanId\":\"f0e58183-18c1-4fa6-939b-e78d050533b6\",\"ServiceInstance\":\"To-Do/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:
57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"c87f142c-d1e9-4363-8630-aaea9c4d9ae5\"},{\"SubscribedPlanId\":\"ea0d7e34-84a0-4329-910a-f38d7d4f2c00\",\"ServiceInstance\":\"OfficeForms/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"
2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"2789c901-c14e-48ab-a76a-be334d9d793a\"},{\"SubscribedPlanId\":\"0defa810-1846-4ebf-8c01-4b72f9dbec2c\",\"ServiceInstance\":\"MicrosoftStream/NA001\",\"CapabilityStatus\":0,\"Assi
gnedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"9e700747-8b1d-45e5-ab8d-ef187ceec156\"},{\"SubscribedPlanId\":\"e56c4814-73b8-4a12-ac13-bd2236e1c61c\",\"ServiceInstance\":\"Deskless/NA001\",\"CapabilityStatus
\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"8c7d2df8-86f0-4902-b2ed-a0458298f3b3\"},{\"SubscribedPlanId\":\"ef68b42e-5730-41b8-b119-a78dd199cd39\",\"ServiceInstance\":\"ProcessSimple/NA001\",\"
CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"76846ad7-7776-4c40-a281-a386362dd1b9\"},{\"SubscribedPlanId\":\"d69c693a-dfc8-49f8-9bd2-68b570bc3dd8\",\"ServiceInstance\":\"PowerApp
sService/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"c68f8d98-5534-41c8-bf36-22fa496fa792\"},{\"SubscribedPlanId\":\"b3e7a5a5-bfae-4ae6-887c-ce9665de0610\",\"ServiceIn
stance\":\"TeamspaceAPI/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"57ff2da0-773e-42df-b2af-ffb7a2317929\"},{\"SubscribedPlanId\":\"c9dbc746-7d1d-449f-9a2c-f80c99df11f
2\",\"ServiceInstance\":\"ProjectWorkManagement/PROD_OC_Org_Ring_010\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"b737dad2-2f6c-4c65-90e3-ca563267e8b9\"},{\"SubscribedPlanId\
":\"6aa67dd9-afd1-47c4-b81f-065ba3495692\",\"ServiceInstance\":\"Sway/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"a23b959c-7ce8-4e57-9140-b90eb88a9e97\"},{\"Subscribed
PlanId\":\"6d4d99fc-d0e1-4350-a4da-cb79cadd739e\",\"ServiceInstance\":\"YammerEnterprise/NA009\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"7547a3fe-08ee-4ccb-b430-5077c50416
53\"},{\"SubscribedPlanId\":\"ac1fca1c-7d64-476c-b1f8-1c336ccac213\",\"ServiceInstance\":\"RMSOnline/AP\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"bea4c11e-220a-4e6d-8eb8-8
ea15d019f90\"},{\"SubscribedPlanId\":\"2cc87a99-6c05-4bf2-a8a7-4a75e26a6afd\",\"ServiceInstance\":\"MicrosoftOffice/NorthAmerica\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"
43de0ff5-c92c-492b-9116-175376d08c38\"},{\"SubscribedPlanId\":\"97006162-e810-4814-98e7-3ae3745b28bc\",\"ServiceInstance\":\"MicrosoftCommunicationsOnline/Instance04-S\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\
"Capability\":null,\"ServicePlanId\":\"0feaeb32-d00e-4d66-bd5a-43b5b83db82c\"},{\"SubscribedPlanId\":\"10985cf4-2206-4e47-9910-426586912b1a\",\"ServiceInstance\":\"SharePoint/SPOS0017\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"Initi
alState\":null,\"Capability\":null,\"ServicePlanId\":\"e95bec33-7c88-4a70-8e19-b10bd9d0c014\"},{\"SubscribedPlanId\":\"e0592405-cc57-4152-8cc0-3f8e5651e47d\",\"ServiceInstance\":\"SharePoint/SPOS0017\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.16
83839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"5dbe027f-2339-4123-9542-606e4d348a72\"},{\"SubscribedPlanId\":\"552916d8-55f1-44be-a7e1-9a56b8086a9b\",\"ServiceInstance\":\"exchange/apcprd03-001-01\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2
018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"efb87545-963c-4e0d-99df-69c6916d9eb0\"}]}",
"#{displayName=Included Updated Properties; oldValue=; newValue=\"AssignedLicense, AssignedPlan\"}",
"#{displayName=TargetId.UserType; oldValue=; newValue=\"Member\"}"
]
}
],
"additionalDetails": [
{
"key": "UserType",
"value": "Member"
}
]
}
This is very odd, as when I retrieve the same event from MS Graph Explorer, I get different result, which is all in proper JSON foramt. Below is the output from MS Graph Explorer. As you can see, the "modifiedProperties" pair is still presented in JSON format.
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#auditLogs/directoryAudits/$entity",
"id": "Directory_3WOOD_3967500",
"category": "Core Directory",
"correlationId": "559450b1-d1e8-4020-a420-4c3c6234ba44",
"result": "success",
"resultReason": "",
"activityDisplayName": "Update user",
"activityDateTime": "2018-10-13T14:57:33.328183Z",
"loggedByService": null,
"initiatedBy": {
"app": null,
"user": {
"id": "9327abf7-93ea-4007-a15c-9b77b5360cc9",
"displayName": null,
"userPrincipalName": "tom-admin#contoso.onmicrosoft.com",
"ipAddress": "<null>"
}
},
"targetResources": [
{
"#odata.type": "#microsoft.graph.targetResourceUser",
"id": "2a58e6ca-2207-4fc0-ba5d-210cd5de25dc",
"displayName": null,
"userPrincipalName": "tom.chen#contoso.com",
"modifiedProperties": [
{
"displayName": "AssignedLicense",
"oldValue": "[]",
"newValue": "[\"[SkuName=ENTERPRISEPACK, AccountId=cdc4b90d-7fa9-4a12-8d58-c2872266673c, SkuId=6fd2c87f-b296-42f0-b197-1e91e994b900, DisabledPlans=[]]\"]"
},
{
"displayName": "AssignedPlan",
"oldValue": "[]",
"newValue": "[{\"SubscribedPlanId\":\"f0e58183-18c1-4fa6-939b-e78d050533b6\",\"ServiceInstance\":\"To-Do/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"c87f142c-d1e9-4363-8630-aaea9c4d9ae5\"},{\"SubscribedPlanId\":\"ea0d7e34-84a0-4329-910a-f38d7d4f2c00\",\"ServiceInstance\":\"OfficeForms/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"2789c901-c14e-48ab-a76a-be334d9d793a\"},{\"SubscribedPlanId\":\"0defa810-1846-4ebf-8c01-4b72f9dbec2c\",\"ServiceInstance\":\"MicrosoftStream/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"9e700747-8b1d-45e5-ab8d-ef187ceec156\"},{\"SubscribedPlanId\":\"e56c4814-73b8-4a12-ac13-bd2236e1c61c\",\"ServiceInstance\":\"Deskless/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"8c7d2df8-86f0-4902-b2ed-a0458298f3b3\"},{\"SubscribedPlanId\":\"ef68b42e-5730-41b8-b119-a78dd199cd39\",\"ServiceInstance\":\"ProcessSimple/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"76846ad7-7776-4c40-a281-a386362dd1b9\"},{\"SubscribedPlanId\":\"d69c693a-dfc8-49f8-9bd2-68b570bc3dd8\",\"ServiceInstance\":\"PowerAppsService/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"c68f8d98-5534-41c8-bf36-22fa496fa792\"},{\"SubscribedPlanId\":\"b3e7a5a5-bfae-4ae6-887c-ce9665de0610\",\"ServiceInstance\":\"TeamspaceAPI/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"57ff2da0-773e-42df-b2af-ffb7a2317929\"},{\"SubscribedPlanId\":\"c9dbc746-7d1d-449f-9a2c-f80c99df11f2\",\"ServiceInstance\":\"ProjectWorkManagement/PROD_OC_Org_Ring_010\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"b737dad2-2f6c-4c65-90e3-ca563267e8b9\"},{\"SubscribedPlanId\":\"6aa67dd9-afd1-47c4-b81f-065ba3495692\",\"ServiceInstance\":\"Sway/NA001\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"a23b959c-7ce8-4e57-9140-b90eb88a9e97\"},{\"SubscribedPlanId\":\"6d4d99fc-d0e1-4350-a4da-cb79cadd739e\",\"ServiceInstance\":\"YammerEnterprise/NA009\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"7547a3fe-08ee-4ccb-b430-5077c5041653\"},{\"SubscribedPlanId\":\"ac1fca1c-7d64-476c-b1f8-1c336ccac213\",\"ServiceInstance\":\"RMSOnline/AP\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"bea4c11e-220a-4e6d-8eb8-8ea15d019f90\"},{\"SubscribedPlanId\":\"2cc87a99-6c05-4bf2-a8a7-4a75e26a6afd\",\"ServiceInstance\":\"MicrosoftOffice/NorthAmerica\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"43de0ff5-c92c-492b-9116-175376d08c38\"},{\"SubscribedPlanId\":\"97006162-e810-4814-98e7-3ae3745b28bc\",\"ServiceInstance\":\"MicrosoftCommunicationsOnline/Instance04-S\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"0feaeb32-d00e-4d66-bd5a-43b5b83db82c\"},{\"SubscribedPlanId\":\"10985cf4-2206-4e47-9910-426586912b1a\",\"ServiceInstance\":\"SharePoint/SPOS0017\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"e95bec33-7c88-4a70-8e19-b10bd9d0c014\"},{\"SubscribedPlanId\":\"e0592405-cc57-4152-8cc0-3f8e5651e47d\",\"ServiceInstance\":\"SharePoint/SPOS0017\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"5dbe027f-2339-4123-9542-606e4d348a72\"},{\"SubscribedPlanId\":\"552916d8-55f1-44be-a7e1-9a56b8086a9b\",\"ServiceInstance\":\"exchange/apcprd03-001-01\",\"CapabilityStatus\":0,\"AssignedTimestamp\":\"2018-10-13T14:57:33.1683839Z\",\"InitialState\":null,\"Capability\":null,\"ServicePlanId\":\"efb87545-963c-4e0d-99df-69c6916d9eb0\"}]"
},
{
"displayName": "Included Updated Properties",
"oldValue": null,
"newValue": "\"AssignedLicense, AssignedPlan\""
},
{
"displayName": "TargetId.UserType",
"oldValue": null,
"newValue": "\"Member\""
}
]
}
],
"additionalDetails": [
{
"key": "UserType",
"value": "Member"
}
]
}
In fact both results (via PowerShell and Microsoft Graph Explorer) seems to be identical (except some formatting differences).
In both cases a valid JSON value is returned.
Now comes the turn of oldValue and newValue property values.
According to documentation, modifiedProperty property of targetResource resource
returns the collection of name, old value and new value which represented in JSON format like this:
{
"displayName": "String",
"newValue": "String",
"oldValue": "String"
}
meaning newValue and oldValue return the converted to string values.
Example
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#auditLogs/directoryAudits/$entity",
"id": "Directory_GIRJA_107870298",
//...
"targetResources": [
{
"#odata.type": "#microsoft.graph.targetResourceGroup",
//...
"modifiedProperties": [
{
"displayName": "foo",
"oldValue": "[]",
"newValue": "[\"bar\"]"
},
//...
{
"displayName": "json_value",
"oldValue": null,
"newValue": "[{\"first_name\":\"Jon\",\"last_name\":\"Doe\"}]"
}
]
}
],
"additionalDetails": []
}
Note: pay attention to the second modifiedProperty entry newValue property, which represents JSON value and is returned as a string: {"first_name":"Jon","last_name":"Doe"}
Using the following example newValue could be converted to JSON:
$uri = "https://graph.microsoft.com/beta/auditLogs/directoryAudits/{directory-id}"
$results = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
$results.targetResources | Select -ExpandProperty modifiedProperties | Select -ExpandProperty newValue | ConvertFrom-Json
I managed to solve the problem by putting the "modifiedProperties" section into a hashtable (Didn't do this properly last time). I use a function to convert the JSON result to Hashtable. The function code is copied from here.
Function ConvertTo-Hashtable {
[CmdletBinding()]
[OutputType('hashtable')]
param (
[Parameter(ValueFromPipeline)]
$InputObject
)
process {
## Return null if the input is null. This can happen when calling the function
## recursively and a property is null
if ($null -eq $InputObject) {
return $null
}
## Check if the input is an array or collection. If so, we also need to convert
## those types into hash tables as well. This function will convert all child
## objects into hash tables (if applicable)
if ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) {
$collection = #(
foreach ($object in $InputObject) {
ConvertTo-Hashtable -InputObject $object
}
)
## Return the array but don't enumerate it because the object may be pretty complex
Write-Output -NoEnumerate $collection
} elseif ($InputObject -is [psobject]) { ## If the object has properties that need enumeration
## Convert it to its own hash table and return it
$hash = #{}
foreach ($property in $InputObject.PSObject.Properties) {
$hash[$property.Name] = ConvertTo-Hashtable -InputObject $property.Value
}
$hash
} else {
## If the object isn't an array, collection, or other object, it's already a hash table
## So just return it.
$InputObject
}
}
}
$hashtable1 = #{}
$hashtable2 = #{}
$hashtable1 = Get-aAuditEvent -Tenant "contoso.onmicrosoft.com"|ConvertFrom-Json|ConvertTo-HashTable
$hashtable2 = $hashtable1.targetResources.modifiedProperties
$hashtable2[0].displayName
$hashtable2[0].oldValue
$hashtable2[0].newValue
The output of the code is below. I still need to workout how to parse "newValue" properly. But at least I can show what actions have been done and what have been changed.
AssignedLicense
[]
["[SkuName=ENTERPRISEPACK, AccountId=cdc4b90d-7fa9-4a12-8d58-c2872266673c, SkuId=6fd2c87f-b296-42f0-b197-1e91e994b900, DisabledPlans=[]]"]