We need to be able to programatically POST to the MS Graph API in order to bulk assign users to Access Packages, e.g.: https://learn.microsoft.com/en-us/graph/api/accesspackageassignmentrequest-post?view=graph-rest-beta&tabs=http#examples
I am trying things like this:
Invoke-RestMethod 'https://graph.microsoft.com/beta/identityGovernance/entitlementManagement/accessPackageAssignmentRequests' -Method POST -ContentType 'application/json' -Body #{
"requestType": "AdminAdd",
"accessPackageAssignment":{
"targetId":"xxx",
"assignmentPolicyId":"xxx",
"accessPackageId":"xxx"
}
}
Unfortunately though I get errors like this:
At line:2 char:29
+ "requestType": "AdminAdd",
+ ~
Missing '=' operator after key in hash literal.
At line:2 char:29
+ "requestType": "AdminAdd",
+ ~
The hash literal was incomplete.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEqualsInHashLiteral
Does anyone know how I should be doing it please?
Additionally, we have MFA enforced so the standard $Cred = Get-Credential will not work. What should I use instead?
Thanks
There are several errors on the object syntax of your example:
In Powershell properties are assigned with =
Property names must not be quoted
Property assignments are separated with semicolon
The correct command would look like:
Invoke-RestMethod 'https://graph.microsoft.com/beta/identityGovernance/entitlementManagement/accessPackageAssignmentRequests' -Method POST -ContentType 'application/json' -Body #{
requestType = "AdminAdd";
accessPackageAssignment = {
targetId = "xxx";
assignmentPolicyId = "xxx";
accessPackageId = "xxx"
}
}
Regarding MFA, you need to either use AppTokens or OAuth.
I wanted to call Graph API endpoints through PowerShell as well. This was the script I ended up with:
Install-Module -Name MSAL.PS -RequiredVersion 4.2.1.3
Import-Module MSAL.PS
$clientId = "YOURCLIENTID"
$clientSecret = "YOURCLIENTSECRET"
$tenantId = "YOURTENANTID"
$ConfidentialClientOptions = New-Object Microsoft.Identity.Client.ConfidentialClientApplicationOptions -Property #{ ClientId = $clientId; ClientSecret = $clientSecret; TenantId = $tenantId }
$ConfidentialClient = $ConfidentialClientOptions | New-MsalClientApplication
$tokenObj = Get-MsalToken -Scope 'https://graph.microsoft.com/.default' -ConfidentialClientApplication $ConfidentialClient
$apiUrl = "https://graph.microsoft.com/beta/users?filter=signInActivity/lastSignInDateTime le 2021-06-21T00:00:00Z&`$select=userPrincipalName,displayName,mail,signInActivity"
$res = Invoke-RestMethod -Headers #{Authorization = "Bearer $($tokenObj.AccessToken)"} -Uri $apiUrl -Method Get
$res.value | select userPrincipalName, displayName, mail, #{L="LastSignInDateTime";E={$_.signInActivity.lastSignInDateTime}} | Sort-Object -Property LastSignInDateTime
I wrote a blog post about it as well: https://engineerer.ch/2021/07/01/how-to-use-powershell-to-call-graph-api-endpoints/
Related
I am following this link to connect to Microsoft Teams using Access Tokens:
https://learn.microsoft.com/en-us/MicrosoftTeams/teams-powershell-application-authentication
Here is the code:
$ClientSecret = 'xxxxx~xx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$ApplicationID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$TenantID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$graphtokenBody = #{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $ApplicationID
Client_Secret = $ClientSecret
}
$graphToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Method POST -Body $graphtokenBody | Select-Object -ExpandProperty Access_Token
$teamstokenBody = #{
Grant_Type = "client_credentials"
Scope = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"
Client_Id = $ApplicationID
Client_Secret = $ClientSecret
}
$teamsToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Method POST -Body $teamstokenBody | Select-Object -ExpandProperty Access_Token
Connect-MicrosoftTeams -AccessTokens #("$graphToken", "$teamsToken")
The application is registered in Azure AD and has been assigned the API permissions as mentioned in the article. I have assigned Teams administrator role to the application as well. Tokens get populated correctly.
Running the code produces the following error:
Connect-MicrosoftTeams : Object reference not set to an instance of an object.
At line:29 char:1
+ Connect-MicrosoftTeams -AccessTokens #("$graphToken", "$teamsToken")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : AuthenticationError: (:) [Connect-MicrosoftTeams], NullReferenceException
+ FullyQualifiedErrorId : Connect-MicrosoftTeams,Microsoft.TeamsCmdlets.Powershell.Connect.ConnectMicrosoftTeams
Connect-MicrosoftTeams : Object reference not set to an instance of an object.
At line:29 char:1
+ Connect-MicrosoftTeams -AccessTokens #("$graphToken", "$teamsToken")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Connect-MicrosoftTeams], NullReferenceException
+ FullyQualifiedErrorId : System.NullReferenceException,Microsoft.TeamsCmdlets.Powershell.Connect.ConnectMicrosoftTeams
If someone had this issue and have successfully resolved it or have some tips on how to resolve it, please help.
I tried to reproduce the same in my environment and got the same error as below:
The error usually occurs if the version of Microsoft teams you are trying to connect is older than 4.7.1-preview version.
To resolve the error, try updating the Microsoft teams PowerShell version to 4.7.1-preview or later and this type of authentication is supported only in commercial environments.
Get-InstalledModule -Name MicrosoftTeams
Update-Module -Name MicrosoftTeams
After updating the PowerShell Module, I am able to connect to Microsoft Teams successfully like below:
$ClientSecret = "ClientSecret"
$ApplicationID = "AppID"
$TenantID = "TenantID"
$graphtokenBody = #{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
Client_Id = $ApplicationID
Client_Secret = $ClientSecret
}
$graphToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Method POST -Body $graphtokenBody | Select-Object -ExpandProperty Access_Token
$teamstokenBody = #{
Grant_Type = "client_credentials"
Scope = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239/.default"
Client_Id = $ApplicationID
Client_Secret = $ClientSecret
}
$teamsToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token" -Method POST -Body $teamstokenBody | Select-Object -ExpandProperty Access_Token
Connect-MicrosoftTeams -AccessTokens #("$graphToken", "$teamsToken")
Reference:
PowerShell Gallery | MicrosoftTeams 4.9.1
I'm working on a PowerShell script to assign users office 365 license based on group (security group). So, i have created app registration and assigned the required API permissions.
When I try to run my script, i get the error below
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:1 char:1
+ Invoke-RestMethod -Uri $uri -Body $body -ContentType "application/jso ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Below is the entire script
$connectiondetails = #{
# This ids and secret are present in the overview and certificate & secret page of our application in azure AD
# Tenant ID here
'tenantid' = ""
# Application (client) ID here
'clientid' = ""
# Secret id here
'ClientSecret' = "" | ConvertTo-SecureString -AsPlainText -Force
}
$token = Get-MsalToken #connectiondetails
$tokenid_ = $token.AccessToken
# $uri = "https://graph.microsoft.com/v1.0/groups"
# $grp = Invoke-RestMethod -Uri $uri -Headers #{Authorization=("bearer {0}" -f $tokenid_)}
# $grp
$uri = "https://graph.microsoft.com/v1.0/groups/ffbabc6f-aa87-40f3-8665-9d140e4a7adb/assignLicense"
$body = "{""SkuId"":""cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46""}"
# assign license call
Invoke-RestMethod -Uri $uri -Body $body -ContentType "application/json" -Method post -Headers #{Authorization=("bearer {0}" -f $tokenid_)}
Permissions assigned to the app
I need assistance to know what am doing wrong. Thank you.
Solutions tried
The body for the request to add license requires addLicenses property with permissions Group.ReadWrite.All and Directory.ReadWrite.All.
{
"addLicenses": [
{
"skuId": "cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46"
}
],
"removeLicenses": []
}
PS
$uri = "https://graph.microsoft.com/v1.0/groups/ffbabc6f-aa87-40f3-8665-9d140e4a7adb/assignLicense"
# create json object
$data = #{
"addLicenses" = #(
#{
"skuId" = "cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46"
}
)
"removeLicenses" = #()
}
# convert to JSON-formatted string
$body = $data | ConvertTo-Json
# assign license call
Invoke-RestMethod -Uri $uri -Body $body -ContentType "application/json" -Method post -Headers #{Authorization=("bearer {0}" -f $tokenid_)}
Resources:
Group - assign licenses
This article seems to explain the script building in detail
Create MS Graph scripts with AAD App
I'm trying to call a PowerBI GETinfo Scanner API using PowerShell. One of the requirements is to pass multiple workspaces to get the info. Here is the MS doc link :\
https://learn.microsoft.com/en-us/rest/api/power-bi/admin/workspace-info-post-workspace-info#example
However, I'm not able to pass below syntax for API body in PowerShell.
The below syntax to call multiple workspaces in API body is not working :
$auth_body =#{
"workspaces": [
"97d03602-4873-4760-b37e-1563ef5358e3",
"67b7e93a-3fb3-493c-9e41-2c5051008f24"
]
}
I'm only able to pass single workspace and below syntax works :
$auth_body =#{'workspaces' ="3b7e9b1c-bdac-4e46-a39d-1b3d24a0e122"}
Please help me to form the syntax for multiple workspaces. Seems I'm not able to form key value pair inside PowerShell for multiple workspaces
Updated Code after applying MathiasR.Jessen suggestion:
$authority = 'https://login.microsoftonline.com/oauth2/'+ $tenantID
$authResult = Get-AdalToken -Authority $authority -Resource $resourceAppIdURI -ClientID $UId -Clientsecret $password -TenantID $tenantID
$Token=$authResult.AccessToken
#Write-Output "Token: $Token"
$auth_header = #{
'Accept' = "application/json";
'Authorization' = 'Bearer ' +$Token
}
$auth_body = #{
"workspaces" =
#("50c4bd8e-fc75-433e-a0cd-755f9329515e","97d03602-4873-4760-b37e-1563ef5358e3")
}
$uri = "https://api.powerbi.com/v1.0/myorg/admin/workspaces/getInfo"
$all_workspace = (Invoke-RestMethod -Uri $uri –Headers $auth_header -Body $auth_body –Method Post)
And Error Message :
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
+ ... rkspace1 = (Invoke-RestMethod -Uri $uri –Headers $auth_header -Body $ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
However, It works perfectly if I provide single workspace.
You're mixing PowerShell and JSON syntax.
To define an array in PowerShell, use the #() array subexpression operator:
$auth_body = #{
"workspaces" = #(
"97d03602-4873-4760-b37e-1563ef5358e3",
"67b7e93a-3fb3-493c-9e41-2c5051008f24"
)
}
I need to attach the file either xlsx or CSV to a particular incident via SNOW REST API using PowerShell script. I have tried with the below code:
if (!$script:ServiceNowCreds) {
$script:ServiceNowCreds = Get-Credential
}
$snow_url = 'https://dev652xx.service-now.com/api/now/table/incident'
$Body = #{
'number' = 'INC00xx059'
}
$result = Invoke-RestMethod -Uri $snow_url -Credential $script:ServiceNowCreds -Body $Body -ContentType "application/json"
$result.result | select sys_id, number | ForEach-Object {
$Upload_snow_url ='https://dev652xx.servicenow.com/api/now/attachment/upload'
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Content-Type','text/csv')
$headers.Add('Accept','*/*')
$sys_id = $_.sys_id
$incident_number = $_.number
$UploadBody = #{
'table_name'='incident';
'table_sys_id'=$sys_id;
'file_name' = 'C:\Users\suganthanraj.p\Documents\Servers.csv'
}
$uploadParam = $UploadBody | ConvertTo-JSon
Write-Host $sys_id
Write-Host $incident_number
$UploadResult = Invoke-RestMethod -Uri $Upload_snow_url -Credential $script:ServiceNowCreds -Body $uploadParam -Method Post -Headers $headers
$UploadResult
}
When I execute the above script I am getting the below error:
Invoke-RestMethod : The remote server returned an error: (415) Unsupported
Media Type.
At C:\Users\suganthanraj.p\Desktop\SNOW-UploadAttachment.ps1:39 char:21
+ ... oadResult = Invoke-RestMethod -Uri $Upload_snow_url -Credential $scr ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
Try changing you content type to "multipart/form-data"
$headers.Add('Content-Type','multipart/form-data')
$UploadBody = #{
'table_name'='incident';
'record_sys_id'=$sys_id;
'uploadFile' = 'C:\Users\suganthanraj.p\Documents\Servers.csv'
}
The error says "The remote server returned an error: (415) Unsupported
Media Type."
Doco on the api can be found here:
https://docs.servicenow.com/bundle/geneva-servicenow-platform/page/integrate/inbound_rest/reference/r_AttachmentAPI-POSTmultipart.html
Your best option would be leverage the OOB Attachment API in ServiceNow. You will need to make a post call from powershell. Powershell has two options for this Invoke-RestMethod and Invoke-WebRequest. I have had better luck with the latter when trying to POST. You might also first build your rest call in Postman make sure you can get the attachment into ServiceNow, then worry about writing your PS.
$Body = #{
User = 'jdoe'
password = 'P#S$w0rd!'
}
$LoginResponse = Invoke-WebRequest 'http://www.contoso.com/login/' - SessionVariable 'Session' -Body $Body -Method 'POST'
$Session
$ProfileResponse = Invoke-WebRequest 'http://www.contoso.com/profile/' -`WebSession $Session $ProfileResponse`
Finally i found answer from the below link
https://community.servicenow.com/community?id=community_question&sys_id=d3707023dbaceb8023f4a345ca961949 and below is the code:
# Eg. User name="admin", Password="admin" for this code sample.
$user = "admin"
$pass = "XXX"
# Build auth header
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user, $pass)))
# Set proper headers
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add('Authorization',('Basic {0}' -f $base64AuthInfo))
$headers.Add('Accept','application/json')
$headers.Add('Content-Type','application/json')
# Specify endpoint uri
$uri = "https://dev652XX.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=850XXXXX2200e0ef563dbb9a71c1&file_name=TreeSizeReport.csv"
# Specifiy file to attach
$fileToAttach = "C:\Users\suganthanraj.p\Desktop\TreeSizeReport.csv"
# Specify HTTP method (POST, PATCH, PUT)
$method = "POST"
# Send HTTP request
$response = Invoke-WebRequest -Headers $headers -Method $method -Uri $uri -InFile $fileToAttach
# Print response
$response.RawContent
In PowerShell, I was able to log in using HTTP Basic authentication For Mail Chimp.
$acctname = 'thisismyusername'
$password = 'thisismyapikey'
$params = #{
Uri = 'https://us14.api.mailchimp.com/3.0/';
Method = 'Get'; #(or POST, or whatever)
Headers = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($acctname):$($password)"));} #end headers hash table
} #end $params hash table
$var = Invoke-RestMethod #params
$var
When I try to get basic info on list thats id is "d3a7a4432d".
$URL = "https://us14.api.mailchimp.com/3.0/"
$Endpoint = "/lists/d3a7a4432d"
$URLMailChimp = "$URL$Endpoint"
$gist = Invoke-RestMethod -Method Get -Uri $URLMailChimp
I get this error message:
Invoke-RestMethod : {
"type":"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/",
"title":"API Key Missing",
"status":401,
"detail":"Your request did not include an API key.",
"instance":""
}
At line:7 char:9
+ $gist = Invoke-RestMethod -Method Get -Uri $URLMailChimp
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I don't understand how to pass it my API key again. I thought by logging it it solved the issue.
I don't use MailChimp, but unless the first invocation provides you with an access token (and the documentation as well as your error message don't look like it would) you need to provide the authentication header with every request.
$acctname = 'thisismyusername'
$password = 'thisismyapikey'
$URL = 'https://us14.api.mailchimp.com/3.0/'
$listID = 'd3a7a4432d'
$auth = #{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${acctname}:${password}"))}
$gist = Invoke-RestMethod -Method Get -Uri "$URL/lists/$listID" -Headers $auth