MSGraphAPI.psm1
Function Get-GraphAuthenticationToken { <# .SYNOPSIS Will get an authentication token for https://graph.microsoft.com .DESCRIPTION Will request the token from https://login.microsoftonline.com/Common/oauth2/token .EXAMPLE Get-GraphAuthenticationToken -TenantName 'MyTenant.onmicrosoft.com' -Credential (Get-Credential) This will get a token for the specified tenant using the credentials. Credentials can also be created using this code: $secpasswd = ConvertTo-SecureString "PASSWORD" -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ('USER@TENANT', $secpasswd) .PARAMETER TenantName Name of the tenant. Usually in the form of xxxxx.onmicrosoft.com .PARAMETER Credential Credential object. Can be generated with the code: $secpasswd = ConvertTo-SecureString "PASSWORD" -AsPlainText -Force $mycreds = New-Object System.Management.Automation.PSCredential ('USER@TENANT', $secpasswd) .PARAMETER Scopes Array of scopes. To be used when Office 365 support is rolled out. .PARAMETER clientid Client Id of the application used to contact Graph. To be used when Office 365 support is rolled out. .PARAMETER redirecturi Redirect URI of the application used to contact Graph. To be used when Office 365 support is rolled out .PARAMETER clientsecret Client secret of application used to contact Graph. To be used when Office 365 support is rolled out. .LINK https://github.com/Ryan2065/MSGraphCmdlets .NOTES Author: Ryan Ephgrave #> Param ( [Parameter(Position=0, Mandatory=$true)][string]$TenantName, [Parameter(Position=1, Mandatory=$true)][pscredential]$Credential, [Parameter(Position=2, Mandatory=$false)][string[]]$Scopes, [Parameter(Position=3, Mandatory=$false)][string]$clientid, [Parameter(Position=4, Mandatory=$false)][string]$redirecturi, [Parameter(Position=5, Mandatory=$false)][string]$clientsecret, [Parameter(Position=6, Mandatory=$false)][switch]$SkipClass ) $username = $Credential.UserName $password = $Credential.Password $Marshal = [System.Runtime.InteropServices.Marshal] $Bstr = $Marshal::SecureStringToBSTR($Password) $Password = $Marshal::PtrToStringAuto($Bstr) $Marshal::ZeroFreeBSTR($Bstr) if([string]::IsNullOrEmpty($Scopes)) { $PayLoad = "resource=https://graph.microsoft.com/&client_id=1950a258-227b-4e31-a9cf-717495945fc2&grant_type=password&username=$($UserName)&scope=user_impersonation&password=$($Password)" $response = '' $Response = Invoke-WebRequest -Uri "https://login.microsoftonline.com/$($TenantName)/oauth2/token" -Method POST -Body $PayLoad $ResponseJSON = $Response | ConvertFrom-Json $GraphAPIAuthenticationHeader = $null $GraphAPIAuthenticationHeader = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]" $GraphAPIAuthenticationHeader.Add("Authorization", "Bearer $($ResponseJSON.access_token)") $Global:GraphAuthenticationHash = @{ 'Parameters' = @{ 'TenantName' = $TenantName 'Credential' = $Credential 'SkipClass' = $SkipClass } 'Token' = $ResponseJSON.access_token 'Header' = $GraphAPIAuthenticationHeader } } else { if([string]::IsNullOrEmpty($clientid)) { $clientid = 'cb89a343-cd2e-463f-81cd-9527bdbda08d' } if([string]::IsNullOrEmpty($redirecturi)) { $redirecturi = 'urn:ietf:wg:oauth:2.0:oob' } $Authority = "https://login.microsoftonline.com/$($TenantName)/oauth2/token" $ResourceURI = 'https://graph.microsoft.com' $App = [Microsoft.Identity.Client.PublicClientApplication]::new($Authority, $clientid) $App.RedirectUri = $redirecturi $Result = ($app.AcquireTokenAsync($Scopes)).Result $GraphAPIAuthenticationHeader = $null $GraphAPIAuthenticationHeader = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]" $GraphAPIAuthenticationHeader.Add("Authorization", "Bearer $($Result.Token)") $Global:GraphAuthenticationHash = @{ 'Parameters' = @{ 'TenantName' = $TenantName 'Credential' = $Credential 'clientID' = $clientid 'redirecturi' = $redirecturi 'SkipClass' = $SkipClass } 'Token' = $Result.Token 'Header' = $GraphAPIAuthenticationHeader } } } Function Invoke-GraphMethod { <# .SYNOPSIS Will run specified graph query with REST. .DESCRIPTION Handles the authentication piece assuming Get-GraphAuthenticationToken was already called once before in the PowerShell session. .EXAMPLE Invoke-GraphMethod -Method 'Post' -Version 'beta' -query 'deviceAppManagement/mobileApps' -body $AppJSON -ContentType 'application/json' This will create an application in Graph. .EXAMPLE Invoke-GraphMethod -Query 'me/messages' -Search 'from:help@contoso.com' -Select 'from,subject' Searches all messages in the current authenticated user mailbox for ones from e-mail help@contoso.com. Only will return the properties from and subject .PARAMETER Query The the query parameter of the URI - For example, in https://graph.microsoft.com/v1.0/messages "messages" is the query. To call this, simply call Invoke-GraphMethod like this: Invoke-GraphMethod -Query "messages" .PARAMETER Version Not required - Used to specify v1.0 or beta. Defaults to v1.0 .PARAMETER Method REST method to use. .PARAMETER Body Content body for REST method .PARAMETER ContentType Type of content for body .PARAMETER Filter Filters the response based on a set of criteria. .PARAMETER Search A property and value pair separated by a colon. .PARAMETER Select Comma-separated list of properties to include in the response. .PARAMETER Expand Comma-separated list of relationships to expand and include in the response. .PARAMETER OrderBy Comma-separated list of properties that are used to sort the order of items in the response collection. .PARAMETER Top The number of items to return in a result set. .PARAMETER Skip The number of items to skip in a result set. .PARAMETER SkipToken Paging token that is used to get the next set of results. .PARAMETER Count A collection and the number of items in the collection. .LINK https://github.com/Ryan2065/MSGraphCmdlets .Notes Author: Ryan Ephgrave #> [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $query, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $Version = 'v1.0', [Parameter(Mandatory=$false)] [ValidateSet( 'Default', 'Delete', 'Get', 'Head', 'Merge', 'Options', 'Patch', 'Post', 'Put', 'Trace' )] $method = 'Get', [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $body, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $ContentType, [Parameter(Mandatory=$false)] $filter, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $search, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $select, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $expand, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $orderby, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [Nullable[int]]$top, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [Nullable[int]]$skip, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] $skipToken, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [Nullable[bool]]$count, [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [string[]]$scopes ) if ($null -ne $Global:GraphAuthenticationHash) { $Parameters = $Global:GraphAuthenticationHash['Parameters'] if(-not [string]::IsNullOrEmpty($Scopes)) { $Parameters['scopes'] = $Scopes } Get-GraphAuthenticationToken @Parameters } else { throw 'You must call Get-GraphAuthenticationToken first!' } $uri = "https://graph.microsoft.com/$($version)/$($query)?" if(-not [string]::IsNullOrEmpty($Filter)) { $uri = "$($uri)`$filter=$($Filter.replace(' ','%20').replace("'",'%27'))&" } if(-not [string]::IsNullOrEmpty($search)) { $uri = "$($uri)`$search=`"$($search.replace(' ','%20').replace("'",'%27'))`"&" } if(-not [string]::IsNullOrEmpty($select)) { $uri = "$($uri)`$select=$($select.replace(' ','%20').replace("'",'%27'))&" } if(-not [string]::IsNullOrEmpty($expand)) { $uri = "$($uri)`$expand=$($expand.replace(' ','%20').replace("'",'%27'))&" } if(-not [string]::IsNullOrEmpty($orderby)) { $uri = "$($uri)`$orderby=$($orderby.replace(' ','%20').replace("'",'%27'))&" } if(-not [string]::IsNullOrEmpty($top)){ $uri = "$($uri)`$top=$($top)&" } if(-not [string]::IsNullOrEmpty($skip)){ $uri = "$($uri)`$skip=$($skip)&" } if(-not [string]::IsNullOrEmpty($skipToken)) { $uri = "$($uri)`$skipToken=$($skip)&" } if($count) { $uri = "$($uri)`$count=true&" } $uri = ($uri.TrimEnd('&')).TrimEnd('?') $RestParams = @{ 'Method' = $method } if(-not [string]::IsNullOrEmpty($body)) { $RestParams['Body'] = $body } if(-not [string]::IsNullOrEmpty($ContentType)) { $RestParams['ContentType'] = $ContentType } $returned = Invoke-RestMethod -Uri $uri -Headers $Global:GraphAuthenticationHash['Header'] @RestParams if(-not [string]::IsNullOrEmpty($returned.'@odata.nextLink')){ Get-GraphNextLink -NextLink $returned.'@odata.nextLink' } if($returned.Value) { if($Global:GraphAuthenticationHash.Parameters.SkipClass) { $returned.Value } else { New-GraphClassMember -Context $returned.'@odata.context' -Data $returned.Value -Version $Version } } else { if($Global:GraphAuthenticationHash.Parameters.SkipClass) { $returned } else { New-GraphClassMember -Context $returned.'@odata.context' -Data $returned -Version $Version } } } Function Get-GraphNextLink { <# .SYNOPSIS Will get the next page of results if there are additional pages .DESCRIPTION Will get the next page of results if there are additional pages .EXAMPLE Get-GraphNextLink -NextLink $returned.'@odata.nextLink' .PARAMETER NextLink Returned through a query when the results are > 100. .LINK https://github.com/Ryan2065/MSGraphCmdlets .Notes Author: Ryan Ephgrave #> Param( $NextLink ) $returned = Invoke-RestMethod -Uri $NextLink -Headers $Global:GraphAuthenticationHash['Header'] if(-not [string]::IsNullOrEmpty($returned.'@odata.nextLink')){ Get-GraphNextLink -NextLink $returned.'@odata.nextLink' } if($returned.Value) { if($Global:GraphAuthenticationHash.Parameters.SkipClass) { $returned.Value } else { New-GraphClassMember -Context $returned.'@odata.context' -Data $returned.Value -Version $Version } } else { if($Global:GraphAuthenticationHash.Parameters.SkipClass) { $returned } else { New-GraphClassMember -Context $returned.'@odata.context' -Data $returned -Version $Version } } } Function Get-GraphMetadata { <# .SYNOPSIS Gets the graph metadata .DESCRIPTION Used to see what entities and properties are available in the graph tenant .EXAMPLE Get-GraphMetadata -Version 'beta' Will get all the graph metadata for beta .PARAMETER Version Graph version to query. Acceptible values are v1.0 or beta .LINK https://github.com/Ryan2065/MSGraphCmdlets .Notes Author: Ryan Ephgrave #> param( $Version = 'v1.0' ) (Invoke-RestMethod -Method Get -Uri "https://graph.microsoft.com/$($Version)/`$metadata" -Headers $Global:GraphAuthenticationHash['Header'] ).Edmx.DataServices.Schema } Function Show-GraphMetadataExplorer { <# .SYNOPSIS Shows a UI to easily browse Graph Metadata .DESCRIPTION Shows a WPF UI that will allow a user to see exactly what is in their environment. .EXAMPLE Show-GraphMetadata .LINK https://github.com/Ryan2065/MSGraphCmdlets/wiki/Show-GraphMetadataExplorer .Notes Author: Ryan Ephgrave #> ."$PSScriptRoot\MetadataExplorer\MetadataExplorer.ps1" } Function New-GraphClassMember { Param( $Context, $Data, $Version ) $EntityContainer = '' if(-not [string]::IsNullOrEmpty($Context)) { $type = ($Context.Split('#'))[1] $EntityContainer = ("microsoft_graph_$($type)_$($version)").Replace('.','_').Replace('#','') try { $test = New-Object $EntityContainer } catch { $type = $type.TrimEnd('s') $EntityContainer = ("microsoft_graph_$($type)_$($version)").Replace('.','_').Replace('#','') } } foreach($instance in $Data) { try { $NoteProperties = (Get-Member -InputObject $instance -MemberType NoteProperty).Name if(-not [string]::IsNullOrEmpty($instance.'@odata.type')) { $Type = ("$($instance.'@odata.type')_$($Version)").Replace('.','_').Replace('#','') $tempobj = New-Object -TypeName $Type $tempObjProperties = (Get-Member -InputObject $tempobj -MemberType Property).Name foreach($NoteProperty in $NoteProperties) { try{ $tempobj."$($NoteProperty)" = $instance."$($NoteProperty)" } catch { $tempobj.GraphAdditionalProperties[$NoteProperty] = $instance."$($NoteProperty)" } } $tempobj } else { if(-not [string]::IsNullOrEmpty($EntityContainer)) { $tempobj = New-Object -TypeName $EntityContainer foreach($NoteProperty in $NoteProperties) { try{ $tempobj."$($NoteProperty)" = $instance."$($NoteProperty)" } catch { $tempobj.GraphAdditionalProperties[$NoteProperty] = $instance."$($NoteProperty)" } } $tempobj } else { $instance } } } catch { $instance } } } Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process $PowerShellFiles = Get-ChildItem $PSScriptRoot -Recurse -Filter "*.ps1" Foreach($File in $PowerShellFiles) { If(-not $File.DirectoryName.EndsWith('MetadataExplorer')){ . $File.FullName } } $null = [System.Reflection.Assembly]::LoadFrom("$PSScriptRoot\Microsoft.Identity.Client\Microsoft.Identity.Client.Platform.dll") $null = [System.Reflection.Assembly]::LoadFrom("$PSScriptRoot\Microsoft.Identity.Client\Microsoft.Identity.Client.dll") |