{"id":1020,"date":"2021-01-31T20:08:58","date_gmt":"2021-01-31T19:08:58","guid":{"rendered":"http:\/\/www.vatland.no\/?p=1020"},"modified":"2021-04-11T06:48:51","modified_gmt":"2021-04-11T05:48:51","slug":"import-user-licenses-from-csp-using-csp-api-and-graph","status":"publish","type":"post","link":"https:\/\/www.vatland.no\/index.php\/import-user-licenses-from-csp-using-csp-api-and-graph\/","title":{"rendered":"Import user licenses from CSP using CSP api and graph."},"content":{"rendered":"<p>Hi,there.<br \/>This is also quiet simple. I want to get all users and what licenses they have been assigned. All this should do, is retrieve information using a csp token.<br \/>After some attempts this is my best one. The &#8220;goodlooking&#8221; argument will not work when run from ISE.<br \/>I&#8217;am still using the same database. The table is called usersextended and you will be given the sql command to create it in a while.<br \/>This function basically fetch a user and all the attributes from M365, licenses skus are joined to a csv and all are added to as a record in the table.<br \/>PLEASE remember I am so lacy so almost all fields are varchar.<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: powershell; title: ; notranslate\" title=\"\">\n\nfunction update-tenantusersindb {\n\n&#x5B;CmdletBinding()]\nparam(\n&#x5B;switch]$includeexternal,\n&#x5B;switch]$goodlooking\n)\nDynamicParam {\n$ParameterName = &quot;tenant&quot;\n$RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary\n$AttributeCollection = New-Object System.Collections.ObjectModel.Collection&#x5B;System.Attribute]\n\n# Create and set the parameters&#039; attributes\n$ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute\n$ParameterAttribute.Mandatory = $false\n$ParameterAttribute.Position = 1\n\n# Add the attributes to the attributes collection\n$AttributeCollection.Add($ParameterAttribute)\n# Generate and set the ValidateSet\n# Add the ValidateSet to the attributes collection\n$SQLInstance = &quot;localhost\\SQLExpress&quot;\n$SQLDatabase = &quot;Microsoft365&quot;\n$sqlqr = &quot;select * from &#x5B;Microsoft365].&#x5B;dbo].&#x5B;tenants] where active=&#039;1&#039;&quot;\n$customers = invoke-sqlcmd -query $sqlqr -ServerInstance $SQLInstance -Database $SQLDatabase\n$ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($Customers | Select-Object -ExpandProperty tenantname)\n\n$AttributeCollection.Add($ValidateSetAttribute)\n\n# Create and return the dynamic parameter\n$RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, &#x5B;string], $AttributeCollection)\n$RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)\nreturn $RuntimeParameterDictionary\n}\nbegin {\n\n# Bind the parameter to a friendly variable\n$Kunde = $PsBoundParameters&#x5B;$ParameterName]\nif ( -not $kunde) {\n$filter = &#039;&#039;\n}\nelse {\n$filter = &#039;?Size=0&amp;filter={&quot;Field&quot;:&quot;Domain&quot;,&quot;Value&quot;:&quot;&#039; + $($kunde) + &#039;&quot;,&quot;Operator&quot;:&quot;starts_with&quot;}&#039;\n}\n}\nprocess {\nif ($goodlooking) {\nClear-Host\n$ui = (get-host).ui\n$rui = $ui.RawUI\n$xx = &#x5B;math]::round(($rui.MaxWindowSize.Width)\/2)\n\n}\n$tid = &quot;&quot;\n$appid = &quot;&quot;\n$SQLInstance = &quot;localhost\\SQLExpress&quot;\n$SQLDatabase = &quot;Microsoft365&quot;\n$SQLUsername = &quot;&quot;\n$SQLPassword = &quot;&quot;\n$tokentime = get-date\n$k = (get-storedcredential -user $appid).password\n$token = (get-storedcredential -user cspuser).getnetworkcredential().password\n$app = New-Object System.Management.Automation.PSCredential -ArgumentList $appid, $k\n$partneraccesstoken = New-PartnerAccessToken -RefreshToken $token -Credential $app -Tenant $tid -Scopes &#039;https:\/\/api.partnercenter.microsoft.com\/user_impersonation&#039; -ServicePrincipal -ApplicationId $appid # -Resource &quot;https:\/\/api.partnercenter.microsoft.com&quot;\nif ($partneraccesstoken) {\nWrite-Output &quot;Got accesstoken&quot;\nupdate-storedcredential -user cspuser -secret ($partneraccesstoken.RefreshToken | ConvertTo-SecureString -AsPlainText -Force)\n$tokentime = get-date\n}\nelse { throw &quot;Error getting accesstoken&quot; }\n$baseurl = &quot;https:\/\/api.partnercenter.microsoft.com\/&quot;\n$apiversion = &quot;v1&quot;\n$endpoint = &quot;\/customers&quot;\n$url = $baseurl + $apiversion + $endpoint + $filter\n$tenants = Invoke-RestMethod -Headers @{Authorization = &quot;Bearer $($partneraccesstoken.AccessToken)&quot; } -Uri $url -Method Get\n\n$cb = $tenants.indexof(&#039;{&#039;) # Find first occurance of &#039;{&#039;\n$tenants = $tenants.Substring($cb) | convertfrom-json # Trim start, remove garble and convert from json\n$filter = &#039;&#039;\nforeach ($tenant in $tenants.items) {\n\n$users = $()\n$customerTenant = $tenant.id #$customer.customerid\n$customerAccessTokenUri = &quot;https:\/\/login.windows.net\/$customerTenant\/oauth2\/token&quot;\n\n$params = @{\nresource = &quot;https:\/\/graph.microsoft.com&quot;;\ngrant_type = &quot;refresh_token&quot;;\nclient_secret = $app.GetNetworkCredential().password;\nclient_id = $appid;\nscope = &quot;openid&quot;;\nrefresh_token = $token\n}\n$graphAccess = Invoke-RestMethod -Uri $customerAccessTokenUri -Method POST -Body $params\n$url = &quot;https:\/\/graph.microsoft.com\/beta\/users&quot;\n$result = $null\n$users = $null\ndo {\ntry {\n$result = Invoke-RestMethod -Uri $url -Headers @{Authorization = &quot;Bearer &quot; + $graphAccess.access_token }\n$url = $result.&#039;@odata.nextLink&#039;\n$users += $result.value\n}\ncatch {\n$url = $null\n$users = $null\n}\n} while ($url)\n\n$totalusers = ($users | Where-Object { $_.userprincipalname -notlike &quot;*#EXT#*&quot; }).count\nif ($includeexternal) { $totalusers += ($users | Where-Object { $_.userprincipalname -like &quot;*#EXT#*&quot; }).count }\n$usersdone = 0\n$totaltime = 0\nif ($goodlooking) { &#x5B;console]::SetCursorPosition(0, 1) }\nif ($goodlooking) {\nWrite-Host &quot;Tenant : &quot; -NoNewline\nWrite-host -ForegroundColor Yellow &quot;$($tenant.companyprofile.Domain),$($tenant.companyprofile.companyName),$($tenant.id) - User count : $($totalusers)&quot;\n}\nelse {\nWrite-Host &quot;Tenant : $($tenant.companyprofile.Domain),$($tenant.companyprofile.companyName),$($tenant.id) - User count : $($totalusers) &quot;\n}#set users as inactive in database.\nInvoke-Sqlcmd -Query &quot;update usersextended set active=&#039;0&#039; where active &lt; &#039;10&#039; and tenantid like &#039;$($tenant.id)&#039;&quot; -ServerInstance $SQLInstance -Database $SQLDatabase foreach ($user in $users &lt;#.items #&gt;) {\nif ($user.userPrincipalName -like &quot;*#EXT#*&quot; -and (-not $includeexternal)) {\n# Skip external user if not specified\n# Write-host &quot;Skipping external user : $($user.userPrincipalName)&quot;\n}\nelse {\n$t = Measure-Command {\n$assignedskus = $user.assignedlicenses | join-string -property skuid -separator &#039;,&#039;\n# Write-Output &quot;$($user.displayname) - sku : $($assignedskus)&quot;\nif ($goodlooking) {\n&#x5B;console]::SetCursorPosition(0, 2)\nwrite-host &quot; &quot;\n&#x5B;console]::SetCursorPosition(0, 2)\nWrite-host -ForegroundColor Green &quot;Inserting user($($usersdone+1)):$($user.Displayname) &quot; -NoNewline\n}\nelse {\nWrite-host &quot;Inserting user($($usersdone+1)):$($user.Displayname) &quot; -NoNewline\n\n}\n$displayname = if ($user.displayname -ne $null) { $user.displayname.Replace(&quot;&#039;&quot;, &quot;&#039;&#039;&quot;) }\n$givenname = if ($user.givenname -ne $null) { $user.givenname.Replace(&quot;&#039;&quot;, &quot;&#039;&#039;&quot;) }\n$surname = if ($user.surname -ne $null) { $user.surname.Replace(&quot;&#039;&quot;, &quot;&#039;&#039;&quot;) }\n$userUPN = if ($user.userprincipalname -ne $null) { $user.userprincipalname.Replace(&quot;&#039;&quot;, &quot;&#039;&#039;&quot;) }\n\nswitch ($user.accountenabled) {\n&#039;Active&#039; { $userstate = 1 }\ndefault { $userstate = 0 }\n}\n\n$insertsql = &quot;insert into usersextended (tenantid,userid,displayname,userprincipalname,givenname,surname,skus,usagelocation,accountEnabled,active,city,companyname,streetaddress,country) values (&#039;$($tenant.id)&#039;,&#039;$($user.ID)&#039;,&#039;$($DisplayName)&#039;,&#039;$($userUPN)&#039;,&#039;$($givenname)&#039;,&#039;$($surname)&#039;,&#039;$($assignedskus)&#039;,&#039;$($user.usagelocation)&#039;,&#039;$($userstate)&#039;,&#039;1&#039;,&#039;$($user.city)&#039;,&#039;$($user.companyName)&#039;,&#039;$($user.streetAddress)&#039;,&#039;$($user.country)&#039;)&quot;\n$er = Invoke-Sqlcmd -Query $insertsql -ServerInstance $SQLInstance -Database $SQLDatabase -ErrorVariable ierr -ErrorAction SilentlyContinue\n#Write-Host &quot;$($ierr)&quot;\nif ($ierr) {\n# User exists -&gt; update.\nif ($goodlooking) {\nWrite-host -ForegroundColor DarkGreen &quot;User exists.... updating. &quot; -NoNewline\n}\nelse {\nWrite-host &quot;User exists.... updating. &quot; -NoNewline\n}\n$updatesql = &quot;update usersextended set skus=&#039;$($assignedskus)&#039;,usagelocation=&#039;$($user.usagelocation)&#039;,tenantid=&#039;$($tenant.id)&#039;,active=&#039;1&#039;,companyname=&#039;$($user.companyName)&#039;,city=&#039;$($user.city)&#039;,streetaddress=&#039;$($user.streetAddress)&#039;,country=&#039;$($user.country)&#039; where userid = &#039;$($user.id)&#039;&quot;\nInvoke-Sqlcmd -Query $updatesql -ServerInstance $SQLInstance -Database $SQLDatabase -ErrorVariable updterr\nif ($updterr) {\nWrite-host &quot;$($updatesql)&quot;\n}\n}\n}\n$usersdone++\n$totaltime += $t\nif ($goodlooking) {\n&#x5B;console]::SetCursorPosition(80, 2)\nWrite-Host -ForegroundColor Gray &quot;Time left ~ $((($totaltime.totalSeconds\/$usersdone)*($totalusers-$usersdone)).tostring(&quot;#.#&quot;)) seconds &quot;\n# Last user took:$(($t.totalseconds).tostring(&quot;#.#&quot;)) -\n}\nelse {\nWrite-Host &quot;Last user took:$(($t.totalseconds).tostring(&quot;#.#&quot;)) - Time left ~ $((($totaltime.totalSeconds\/$usersdone)*($totalusers-$usersdone)).tostring(&quot;#.#&quot;)) seconds &quot;\n}\n}\n}\n}\n}\n}\n<\/pre><\/div>\n\n\n<p>Here is the database script:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nUSE &#x5B;Microsoft365]\nGO\n\n\/****** Object: Table &#x5B;dbo].&#x5B;usersextended]\nSET ANSI_NULLS ON\nGO\n\nSET QUOTED_IDENTIFIER ON\nGO\n\nCREATE TABLE &#x5B;dbo].&#x5B;usersextended](\n&#x5B;tenantid] &#x5B;varchar](255) NOT NULL,\n&#x5B;userid] &#x5B;varchar](255) NOT NULL,\n&#x5B;accountEnabled] &#x5B;int] NULL,\n&#x5B;ageGroup] &#x5B;varchar](255) NULL,\n&#x5B;assignedlicenses] &#x5B;varchar](255) NULL,\n&#x5B;assignedplans] &#x5B;varchar](255) NULL,\n&#x5B;businessPhones] &#x5B;varchar](255) NULL,\n&#x5B;city] &#x5B;varchar](255) NULL,\n&#x5B;companyName] &#x5B;varchar](255) NULL,\n&#x5B;consentProviderForMinor] &#x5B;varchar](255) NULL,\n&#x5B;country] &#x5B;varchar](255) NULL,\n&#x5B;createddatetime] &#x5B;datetime] NULL,\n&#x5B;creationtype] &#x5B;varchar](255) NULL,\n&#x5B;deleteddatetime] &#x5B;datetime] NULL,\n&#x5B;department] &#x5B;varchar](255) NULL,\n&#x5B;devicekeys] &#x5B;varchar](255) NULL,\n&#x5B;displayname] &#x5B;varchar](255) NULL,\n&#x5B;employeehiredate] &#x5B;datetime] NULL,\n&#x5B;employeeid] &#x5B;varchar](255) NULL,\n&#x5B;employeeorgdata] &#x5B;varchar](255) NULL,\n&#x5B;employeetype] &#x5B;varchar](255) NULL,\n&#x5B;externaluserstate] &#x5B;varchar](255) NULL,\n&#x5B;externaluserstatechangedatetime] &#x5B;datetime] NULL,\n&#x5B;faxnumber] &#x5B;varchar](255) NULL,\n&#x5B;givenname] &#x5B;varchar](255) NULL,\n&#x5B;id] &#x5B;varchar](255) NULL,\n&#x5B;identities] &#x5B;varchar](255) NULL,\n&#x5B;imaddresses] &#x5B;varchar](255) NULL,\n&#x5B;infocatalogs] &#x5B;varchar](255) NULL,\n&#x5B;ismanagementrestricted] &#x5B;varchar](255) NULL,\n&#x5B;isresourceaccount] &#x5B;varchar](255) NULL,\n&#x5B;jobtitle] &#x5B;varchar](255) NULL,\n&#x5B;legalagegroupclassification] &#x5B;varchar](255) NULL,\n&#x5B;mail] &#x5B;varchar](255) NULL,\n&#x5B;mailnickname] &#x5B;varchar](255) NULL,\n&#x5B;mobilephone] &#x5B;varchar](255) NULL,\n&#x5B;officelocation] &#x5B;varchar](255) NULL,\n&#x5B;onpremisesDistinguishedname] &#x5B;varchar](255) NULL,\n&#x5B;onpremisesedomainname] &#x5B;varchar](255) NULL,\n&#x5B;onpremisesextensionattributes] &#x5B;varchar](255) NULL,\n&#x5B;onpremisesimmutableid] &#x5B;varchar](255) NULL,\n&#x5B;onpremiseslastsyncdatetime] &#x5B;datetime] NULL,\n&#x5B;onpremisesprovisioningerrors] &#x5B;varchar](255) NULL,\n&#x5B;onpremisessamaccountname] &#x5B;varchar](255) NULL,\n&#x5B;onpremisessecurityidentifier] &#x5B;varchar](255) NULL,\n&#x5B;onpremisessyncenabled] &#x5B;int] NULL,\n&#x5B;onpremisesuserprincipalname] &#x5B;varchar](255) NULL,\n&#x5B;othermails] &#x5B;varchar](255) NULL,\n&#x5B;passwordpolicies] &#x5B;varchar](255) NULL,\n&#x5B;passwordprofile] &#x5B;varchar](255) NULL,\n&#x5B;postalcode] &#x5B;varchar](255) NULL,\n&#x5B;preferreddatalocation] &#x5B;varchar](255) NULL,\n&#x5B;preferredlanguage] &#x5B;varchar](255) NULL,\n&#x5B;provisionedplans] &#x5B;varchar](255) NULL,\n&#x5B;proxyaddresses] &#x5B;varchar](255) NULL,\n&#x5B;refreshtokenvalidfromdaterime] &#x5B;datetime] NULL,\n&#x5B;showinaddresslist] &#x5B;varchar](255) NULL,\n&#x5B;signinsessionsvalidfromdatetime] &#x5B;datetime] NULL,\n&#x5B;state] &#x5B;varchar](255) NULL,\n&#x5B;streetaddress] &#x5B;varchar](255) NULL,\n&#x5B;surname] &#x5B;varchar](255) NULL,\n&#x5B;usagelocation] &#x5B;varchar](255) NULL,\n&#x5B;userprincipalname] &#x5B;varchar](255) NULL,\n&#x5B;usertype] &#x5B;varchar](255) NULL,\n&#x5B;skus] &#x5B;varchar](512) NULL,\n&#x5B;active] &#x5B;int] NULL,\nCONSTRAINT &#x5B;PK_usersextended] PRIMARY KEY CLUSTERED\n(\n&#x5B;userid] ASC\n)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON &#x5B;PRIMARY]\n) ON &#x5B;PRIMARY]\nGO\n<\/pre><\/div>\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi,there.This is also quiet simple. I want to get all users and what licenses they have been assigned. All this should do, is retrieve information using a csp token.After some attempts this is my best one. The &#8220;goodlooking&#8221; argument will not work when run from ISE.I&#8217;am still using the same database. The table is called &hellip; <a href=\"https:\/\/www.vatland.no\/index.php\/import-user-licenses-from-csp-using-csp-api-and-graph\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Import user licenses from CSP using CSP api and graph.<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Import user licenses from CSP using CSP api and graph.","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-1020","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"jetpack-related-posts":[{"id":975,"url":"https:\/\/www.vatland.no\/index.php\/log-tenants-from-office-365-to-local-db\/","url_meta":{"origin":1020,"position":0},"title":"Log tenants from office 365 to local Db","author":"Atle","date":"January 3, 2021","format":false,"excerpt":"Hi, I like to keep control of how many licenses our cutomers use versus how many\u00a0 have been purchased. Here is 1st part\u00a0 my PS script to copy the info from csp to the DB. I will start creating a database and table to keep a list of all the\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1010,"url":"https:\/\/www.vatland.no\/index.php\/add-tenant-licenses-from-csp-to-database\/","url_meta":{"origin":1020,"position":1},"title":"Add tenant licenses from csp to database.","author":"Atle","date":"January 17, 2021","format":false,"excerpt":"This is a followup from previus post. In this post I will populate the database with what licenses a tenant has aquired. This will add records of what aquired skus and 'usage'. For me this is how many license are bought versus how many are assigned. This does not account\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/uncategorized\/azure-uncategorized\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":957,"url":"https:\/\/www.vatland.no\/index.php\/hash-tables-in-powershell\/","url_meta":{"origin":1020,"position":2},"title":"Hash tables in powershell","author":"Atle","date":"March 23, 2020","format":false,"excerpt":"We all have the need to store data in some kind of arrays. I use hashtables a lot. Preferred use is as a lookup table, I can use 'contains' instead of looping through each item or reference an object by name instead of index number. Lookup table for licenses is\u2026","rel":"","context":"In &quot;CSP&quot;","block_context":{"text":"CSP","link":"https:\/\/www.vatland.no\/index.php\/category\/csp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1043,"url":"https:\/\/www.vatland.no\/index.php\/list-user-and-license-in-database\/","url_meta":{"origin":1020,"position":3},"title":"List users and licenses in Database","author":"Atle","date":"March 26, 2021","format":false,"excerpt":"Now that we have a database containing user, tenant and license it would be nice to have a function\/command to list this. Took me a while to figure it out but thanks to Bing, I prefer Bing before google. I sync my database on a schedule once a day. This\u2026","rel":"","context":"In &quot;CSP&quot;","block_context":{"text":"CSP","link":"https:\/\/www.vatland.no\/index.php\/category\/csp\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":902,"url":"https:\/\/www.vatland.no\/index.php\/csp-access-to-tenants-using-powershell-part-3\/","url_meta":{"origin":1020,"position":4},"title":"CSP access to tenants using powershell. Part 3","author":"Atle","date":"September 23, 2019","format":false,"excerpt":"In this part 3 of CSP and powershell I will show how you can connect to azureAD of a customer tenant using your CSP app credentials and refreshtoken. This is almost the same procedure as we use to connect to az. We will start with the same variables as in\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":875,"url":"https:\/\/www.vatland.no\/index.php\/csp-access-to-tenants-using-powershell-part-1\/","url_meta":{"origin":1020,"position":5},"title":"CSP access to tenants using powershell. Part 1","author":"Atle","date":"September 18, 2019","format":false,"excerpt":"A short explanation of how to access customer tenant using a CSP tenant SPN credential connectiong to AzureAD and AZ. Have been struggling for a while to manage all our customers tenants using powershell scripts. It can be complicated to organize all the credentials, tenant domain, tenant id's password expiry.\u2026","rel":"","context":"In &quot;Azure&quot;","block_context":{"text":"Azure","link":"https:\/\/www.vatland.no\/index.php\/category\/azure\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/1020","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/comments?post=1020"}],"version-history":[{"count":8,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/1020\/revisions"}],"predecessor-version":[{"id":1070,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/posts\/1020\/revisions\/1070"}],"wp:attachment":[{"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/media?parent=1020"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/categories?post=1020"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vatland.no\/index.php\/wp-json\/wp\/v2\/tags?post=1020"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}