PS: Rest APIs
Description:
So as I move more into Automation, I’m finding that many software vendors build their software with Rest API first, then CLI, then a web UI on top. This post is a way to interact with Rest API’s from Powershell. I usually use this in combination with PostMan when trying to code workflows in vRealize Orchestrator.
When interacting with REST API’s, you have multiple parts of a request but the main two are headers and body. For a GET
request, you usually just need headers because you are just requesting information and not providing information. For PUT
and POST
requests, you almost always need something in the body. Body’s can be JSON or x-www-form-urlencoded or other types. A good way to learn this is to play around with different software in your environment that offers Rest API’s and use PostMan as a client on your machine.
Either way, in Powershell, you should mostly use not hashtables like you would think, but a System.Collections.Generic.Dictionary
object which is very similar:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Connect-AzureAD
$d = Get-AzureADUser -ObjectId "user@domain.com"
$d | Select -ExpandProperty ExtensionProperty
# type is System.Collections.Generic.Dictionary, so we reference like a hashtable
$d.ExtensionProperty["employeeUniqueId"]
# to create one from scratch
$d = New-Object 'system.collections.generic.dictionary[string,string]'
$d.gettype()
# IsPublic IsSerial Name BaseType
# -------- -------- ---- --------
# True True Dictionary`2 System.Object
# to add a key
$d["foo"] = "bar"
$d | Format-Table -auto
# Key Value
# --- -----
# foo bar
# as usual, see your different options by running `$d | gm`
Anyways, here are some examples:
To Resolve
-
To just interact with a web service, do something like:
1
$text = ((Invoke-Webrequest -Uri "https://uselessfacts.jsph.pl/random.json?language=en" -UseBasicParsing).content | ConvertFrom-Json).text
-
To interact with a web service and pass a parameter, you can do something like (assuming you want 5 responses):
1
$text = ((Invoke-Webrequest -Uri "https://uinames.com/api/?amount=5" -UseBasicParsing).content | ConvertFrom-Json).name
-
Both of these work well since you don’t have to have any headers in your request. Most APIs require authentication. In order to do that, they will have different standards. Here is an example with Basic Authentication which is real common:
1 2 3 4 5 6 7 8 9 10
$user = 'myUser' $pass = 'seeKeypass' $pair = "$($user):$($pass)" $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair)) $basicAuthValue = "Basic $encodedCreds" $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Authorization", $basicAuthValue) [Net.ServicePointManager]::SecurityProtocol = "Tls12, Tls11, Tls, Ssl3" $req = Invoke-RestMethod -Method GET -Uri "https://test.service-now.com/api/now/table/sc_request?sysparm_query=short_description%3DAccess%20Request&sysparm_limit=100&state=1" -Headers $headers $req | ConvertTo-Json
- This is will return a JSON object from service now using the credentials for the user
myUser
and the password ofseeKeypass
- This is will return a JSON object from service now using the credentials for the user
-
What you will see more often is Oauth 2.0 REST API’s. They provide two main things in their response: an
access_token
and arefresh_token
. I still need to read more on their meanings but for accessing them via code, use the following:- So Step 1 is to get a token:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Function New-MSGraphAPIToken { <# .SYNOPSIS Acquire authentication token for MS Graph API .DESCRIPTION If you have a registered app in Azure AD, this function can help you get the authentication token from the MS Graph API endpoint. Each token is valid for 60 minutes. .PARAMETER ClientID This is the registered ClientID in AzureAD .PARAMETER ClientSecret This is the key of the registered app in AzureAD .PARAMETER TenantID This is your Office 365 Tenant Domain .EXAMPLE $graphToken = New-MSGraphAPIToken -ClientID <ClientID> -ClientSecret <ClientSecret> -TenantID <TenantID> The above example gets a new token using the ClientID, ClientSecret and TenantID combination .NOTES General notes #> param( [parameter(mandatory = $true)] [string]$ClientID, [parameter(mandatory = $true)] [string]$ClientSecret, [parameter(mandatory = $true)] [string]$TenantID ) $body = @{grant_type = "client_credentials"; scope = "https://graph.microsoft.com/.default"; client_id = $ClientID; client_secret = $ClientSecret } $oauth = Invoke-RestMethod -Method Post -Uri https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token -Body $body $token = @{'Authorization' = "$($oauth.token_type) $($oauth.access_token)" } Return $token } $ClientSecret = 'seeKeypass' $ClientID = 'your-application-client-id' $TenantID = 'your-tenant-in-azure' $token = New-MSGraphAPIToken -clientID $clientID -clientSecret $clientSecret -tenantID $tenantID -Username "myUser@domain.com" -Password $password
- Next, use the
$token
variable ( a System.Collections.Generic.Dictionary object) to make one or more requests:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# example - adding user to group in Azure AD via Rest API $posturi = "https://graph.microsoft.com/v1.0/groups/$groupID/members/" + '$ref' $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Authorization", $token["Authorization"]) $headers.Add("Content-Type", "application/json") $jsonBody = @{ "@odata.id" = "https://graph.microsoft.com/v1.0/users/$userID" } | ConvertTo-Json Try { Invoke-RestMethod -Method Post -Uri $posturi -Headers $headers -Body $jsonBody Write-output "Adding user to group: Succeeded - $groupID" } Catch { Write-Output "Unable to complete the request" }
- Finally, when reading the WSDL for a REST API, check and see if you have to
revoke
an API token after each call as well. This is not that uncommon, for example:
1 2 3 4 5 6 7 8
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Content-Type", "application/x-www-form-urlencoded") $refreshToken = "a;sdlfkjalk;dfja;lksf" $clientId = "myClient" $clientSecret = "mySecret" $body = "token=$refreshToken&client_id=$clientId&client_secret=$clientSecret" $response = Invoke-RestMethod 'https://some.endpoint.com/api/auth/oauth2/revoke' -Method 'POST' -Headers $headers -Body $body $response | ConvertTo-Json
- Usually you will only have to request a token and then make one or more calls, but sometimes you may have to revoke it after each call as well if you are running API calls very often.
-
I have another example here
Comments