This walkthrough will expose you to the key capabilities of AutoGraphPS and the Microsoft Graph. It is certainly not exhaustive, but should be enough for you understand how to use AutoGraphPS in your work, where it falls short, and how you might remedy any omissions with your own contributions to the project.
The walkthrough assumes you are familiar with PowerShell and basic usage of the object pipeline, and that you are familiar with REST concepts.
After you've installed the module, invoke AutoGraphPS cmdlets from any PowerShell session.
AutoGraphPS cmdlets allow you to explore the graph. Before using the cmdlets, you must establish a connection to the graph by signing in. If you have not already done this using Connect-GraphApi
, that's ok -- any commands that need a connection will request one before communicating with the graph. After that, any subsequent commands will re-use that same connection, so you won't have to sign in again.
Here's a really simple command you can execute -- if it asks you to sign-in, please do so:
Get-GraphResource me
After you respond to authentication prompts, Get-GraphResource
returns a PowerShell object representing MS Graph's view of the me
entity, i.e. the entity that represents your user object:
id : 82f53da9-b996-4227-b268-c20564ceedf7
officeLocation : 7/3191
@odata.context : https://graph.microsoft.com/v1.0/$metadata#users/$entity
surname : Okorafor
mail : starchild@mothership.io
jobTitle : Professor
givenName : Starchild
userPrincipalName : starchild@mothership.io
businessPhones : +1 (313) 360 3141
displayName : Starchild Okorafor
Since the first execution of Get-GraphResource
establishes a logical "session," you can continue to execute cmdlets without being asked to re-authenticate, e.g. a subsequent invocation like
PS> Get-GraphResource organization
will not prompt for credentials but immediately return details about your organization:
id : fb6df3ba-c5f5-43dd-b108-a921f1a7e759
businessPhones : {206 881 8080}
city : Seattle
displayName : Akana
postalCode : 98144
state : Washington
street : 101 23rd Avenue Suite X
The commands above are trivial demonstrations of Graph. In particular, they only require the Graph permission known as User.Read
. More interesting explorations of the Graph require that you request additional permissions when you connect to the Graph.
Here's how you can request the Files.Read,
Mail.Read
, and Contacts.Read
permissions in addition to User.Read
-- the additional permissions enable you to access those parts of the Graph for reading information about user files from OneDrive, your mail, and your list of personal contacts:
Connect-GraphApi -Permissions User.Read, Files.Read, Mail.Read, Contacts.Read
This will prompt you to authenticate again and consent to allow the application to acquire these permissions. Note that it is generally not obvious what permissions are required to access different functionality in the Graph; future updates to AutoGraphPS will attempt to address this. For now, consult the Graph permissions documentation whenever you're accessing a new part of the Graph.
Note that there are more than 500 permissions (and counting). If you're not sure which permission you need to request with
Connect-GraphApi
, (i.e.Files.Read
,Mail.Read
, etc.), you can use theFind-GraphPermissions
to find permissions and their descriptions by specifying a search keyword.
Now you can issue commands to read contacts, mail, and files. In addition to the Get-GraphResource
cmdlet which returns data as a series of flat lists, you can use Get-GraphResourceWithMetadata
or its alias gls
to retrieve your personal contacts:
PS> Get-GraphResourceWithMetadata me/contacts
Email DisplayName Phone Address
----- ---------- ----- -------
cosmo@soulsonic.org Cosmo Jones Mobile: (313) 555-7334 Home: 1075 Chalfonte
aks@bee.org Akeelah Smith Home: 8760 Lafayette
jhenry@legend.net John Henry Work: (206) 882-9000 Work: One Turing Way
deandre@skynet.org Deandre George Mobile: (404) 200-1024 Home: 200 OK Drive
The Get-GraphResourceWithMetatdata
combines the response from Graph with type metadata that allows it to recognize the response as a contact
, and since it so happens that the command "knows" how to provide user-friendly output for the contact
type, it applies specific formatting to improve readability.
Get-GraphResourceWithMetadata
only knows about certain fairly popular types, so if the response does not confirm to a type with formatting logic, the command applies default formatting. The default format view is called GraphItem
, and you can override any formatting by using Format-Table
with the View
parameter:
PS> Get-GraphResourceWithMetadata me/contacts | Format-Table -View GraphItem
Info Type Preview Name
---- ---- ------- ----
t +> contact Cosmo Jones XMKDFX1
t +> contact Akeelah Smith XMKDFX2
t +> contact John Henry XMKDFX4
t +> contact Deandre George XMKDFX8
The Preview
column shows data returned from Graph that Get-GraphResourceWithMetadata
deems to be most human-readable -- in this case, the displayName
of the contact
entity.
Items with a +
in the Info
field returned by Get-GraphResourceWithMetadata
contain content. The actual content, i.e. data that would be returned by Get-GraphResource
is not displayed by default, but you can use the Select
alias of PowerShell to retrieve the Content
property of each row. In this way Get-GraphResourceWithMetadata
returns a superset of the data returned from Get-GraphResource
. The use of Get-GraphResource
below
Get-GraphResource me/contacts/XMKDFX1
returns the contact with id
XMKDFX1
. The same object may also be retrieved through the sequence below through Get-GraphResourceWithMetadata
(alias gls
) using the First
parameter :
PS> gls me -First 1
Email DisplayName Phone Address
----- ---------- ----- -------
cosmo@soulsonic.org Cosmo Jones Mobile: (313) 555-7334 Home: 1075 Chalfonte
You can also use the Format-List
to make the output look the same as Get-GraphResource (ggr)
:
gls me/contacts | Format-List
ggr me/contacts
As with any PowerShell cmdlet that returns a value, the Get-GraphResource
, Get-GraphResourceWithMetadata
, Get-GraphChildItem
cmdlets can be assigned to a variable for use with other commands or simply to allow you to dump properties of objects and their child objects:
$mycontacts = gls me/contacts
However, even if you neglect to make such an assignment, the results of the last invoked Get-*Item
cmdlet is available in the $LASTGRAPHITEMS
variable:
PS> gls me/drive
Info Type Preview Name
---- ---- ------- ----
t +> drive OneDrive drive
n* > driveItem items
n > list list
n > driveItem root
n* > driveItem special
PS> $LASTGRAPHITEMS[0].content.lastModifiedDateTime
2017-06-12T03:12:33Z
This makes ad-hoc exploration of the Graph less expensive -- you don't have to query the Graph again with another cmdlet to examine the objects you just recently retrieved. They are available in $LASTGRAPHITEMS
.
IMPORTANT NOTE: The example above illustrates an import aspect behavior of Get-GraphResourceWithMetadata
:
- When the Uri argument for the cmdlet references a collection, the result is simply the items in the collection. This is actual data from Graph.
- But when the Uri references a single entity AND the URI is not empty AND is not the value
.
, only that entity is returned. - If the URI references a single entity and is either not specified or is the value
.
, the returned elements are the allowed segments (if any) that can immediately follow the entity in a valid Uri for Graph. This is metadata about Graph that reveals its structure. - This contrasts with
Get-GraphResource
which only exhibits the behavior in (1).
Note that Get-GraphChildItem
is similar to Get-GraphResourceWithMetadata
, except it does not exhibit the behavior in (2) above, it always exhibits both (1) and (3) at the same time.
This makes the Get-GraphResourceWithMetadata
/ gls
and Get-GraphChildItem
commands effective ways to recursively discover the Uris for both Graph data and structure (metadata).
You may have noticed that after the first time you invoked gls
, your PowerShell prompt displayed some additional information:
[starchild@mothership.io] /v1.0:/
PS>
By default, AutoGraphPS automatically adds this to your path on your first use of the exploration-oriented cmdlets Get-GraphResourceWithMetadata
, Get-GraphChildItem
and Set-GraphLocation
(alias gcd
). The text in square brackets denotes the user identity with which you've logged in. The next part before the :
tells you what Graph API version you're using, in this case the default of v1.0
. The part following this is your location within that API version. Any Uris specified to Get-GraphResourceWithMetadata
, Get-GraphChildItem
, Get-GraphResource
, or Set-GraphLocation
are interpreted as relative to the current location, in very much the same way that file-system oriented shells like bash
and PowerShell interpret paths specified to commands as relative to the current working directory. In this case, your current location in the Graph is /
, the root of the graph.
With AutoGraphPS, you can traverse the Graph using gls
and gcd
just the way you'd traverse your file system using ls
to "see" what's in and under the current location and "move" to a new location. Here's an example of exploring the /drive
entity, i.e. the entity that represents your OneDrive
files:
gcd /me/drive/root/children
[starchild@mothership.io] /v1.0:/me/drive/root/children
PS> gls
Graph Location: /v1.0:/me/drive/root/children
CreatedBy LastModifiedDateTime Size Name
--------- -------------------- ---- ----
cosmo@soulsonic.org 2017-10-24 21:36 612440 Recipes
cosmo@soulsonic.org 2018-06-18 12:38 7581 Pyramid.js
cosmo@soulsonic.org 2021-05-20 12:50 221260 Panther.md
cosmo@soulsonic.org 2017-01-04 14:06 34400953 Spacetime
If you'd like to know what's "inside" of Recipes, you can gcd
and gls
again:
[starchild@mothership.io] /v1.0:/me/drive/root/children
PS> gcd me/drive/root/children/Recipes
[starchild@mothership.io] /v1.0:/me/drive/root/children/Recipes
PS> gls
Graph Location: /me/drive/root/children/Recipes
Info Type Preview Name
---- ---- ------- ----
t +> driveItem Recipes candidates
n* > driveItem children
n > listItem listItem
n* > permission permissions
n* > thumbnailSet thumbnails
n* > driveItemVersion versions
n > workbook workbook
PS> gcd children
[starchild@mothership.io] /v1.0:/me/drive/root/children/Recipes/children
PS> gls
Graph Location: /v1.0:/me/drive/root/children/Recipes/children
CreatedBy LastModifiedDateTime Size Name
--------- -------------------- ---- ----
cosmo@soulsonic.org 2001-10-25 12:03 17831 SweetPotatoPie.md
cosmo@soulsonic.org 2008-11-04 21:14 84003 Gumbo.md
Note that as in the file system case, you can save yourself a lot of typing of long Uri's by using gcd
and taking advantage of the ability to use shorter Uri's relative to the current location.
Of course, you can always use absolute URI's that are independent of your current location, just start the Uri with /
, e.g.
gls /me/contacts
which returns the same result regardless of your current location, for which you can also query using get-graphlocation
, aka gwd
(like pwd
in the file system):
gwd
Path
----
/v1.0:/me/drive/root/children/candidates/children
The Microsoft Graph supports a rich set of query capabilities through its OData support. You can learn the the specifics of MS Graph and OData query specification as part of MS Graph REST Uri's via Graph's query documentation, the OData query tutorial, or simply by using the Graph Explorer.
AutoGraphPS's query capabilities are exposed in the Get-GraphResource
Get-GetGraphItemWithMetadata
(ggr
and gls
aliases respectively), and Get-GraphChildItem
commands. To use them, you don't need to construct query Uri's as you might if you were making direct use of OData. And in most cases you will not need to know very much about OData.
The one area of AutoGraphPS usage in which it is helpful to understand OData is the filtering language. The -Filter
option on Get-GraphResource
and Get-GraphChildItem
allows you to specify an OData query to limit the result set from Graph to items that satisfy certain conditions much like a SQL where
clause. The query is performed by the Graph service, so your network and AutoGraphPS don't have to waste time processing results that don't match the criteria you specified:
gls me/people -Filter "department eq 'Ministry of Funk'"
In the example above we've retrieved all people related to me
whose department
property is equal to Ministry of Funk
. Note that single quotes are used to delimit strings in the OData query syntax, and eq
is an equality operator. OData supports many other operators, including mathematical and logical operators as well as additional operators related to strings, such as startsWith
:
gls /users -Filter "startsWith(mail, 'pfunk')"
This example returns all the users whose mail
property (i.e. their e-mail address) starts with pfunk
.
Complex expressions combining multiple operators using logical operators like and
, or
, and not
allow for far more complicated queries involving multiple predicates. For more details on OData filter queries, consult Microsoft Graph documentation for $filter
.
While the filter syntax is powerful and flexible at the expense of learning the query language syntax, SimpleMatch
requires no syntax. Just supply the term you want to search for -- SimpleMatch
will try to "fuzzy" matches against commonly used fields. The command
gls /users -SimpleMatch pfunk
will return the same results as the previous query since the startsWith
is one of the filters it applies. In many casual interactive cases, SimpleMatch
will get the job done without the need to recall OData filter syntax.
Another way to avoid excessive traffic between AutoGraphPS and Graph is to use the -First
and -Skip
options, which are PowerShell standard parameters for paging. These options are implemented as analogs to the $top
and $skip
options in OData syntax. For example:
gls me/contacts -first 3
returns the first 3 items in your contacts list.
Note that by default Graph will limit the number of results returned even when you don't specify -first
to avoid performance issues with the service. If you have 200 contacts and would like to retrieve them all with one command, you'll need to specify -all
to get them as Graph currently defaults to returning only 10 at a time:
# If I have hunreds of contacts contacts, this ensures I get them all :)
gls me/contacts -All
You can also skip ahead -- perhaps you want the last elements of a sorted collection or you've already read some number of previous items:
gls me/contacts -Skip 3 -First 3
By default, Graph does not return all properties of an object -- it returns those deemed most likely to be useful without retrieving every field to avoid excessive network traffic. For example, the query below for a given user is missing the department
property in the response:
ggr /users/starchild@mothership.io
id : 82f53da9-b996-4227-b268-c20564ceedf7
officeLocation : 7/3191
@odata.context : https://graph.microsoft.com/v1.0/$metadata#users/$entity
surname : Okorafor
mail : starchild@mothership.io
jobTitle : Professor
givenName : Starchild
userPrincipalName : starchild@mothership.io
businessPhones : +1 (313) 360 3141
displayName : Starchild Okorafor
To fix this, use -Property
to project the exact set of fields you're interested in. This has the benefit of allowing you to reduce network consumption as well, which is most useful when handling large result sets:
ggr me -property displayName, department, mail, officeLocation
@odata.context : https://graph.microsoft.com/v1.0/$metadata#users(displayName,department,mail,officeLocation)
/$entity
department : Ministry of Funk
displayName : Starchild Okorafor
officeLocation : 7/3191
mail : starchild@mothership.io
For a better understanding of how and when OData services like Graph can project properties, see the Microsoft Graph documentation for $select
.
Particularly when retrieving large result sets, it is important to be able to specify the order in which items are returned. For an e-mail inbox with 1000 messages for instance, you may only want to retreive the first 50 or so after sorting by descending date (the most recent messages). In other cases you may want to sort on multiple fields.
The following example uses the -Sort
option to retrieve the 10 oldest messages -- note that we use PowerShell's client-side select cmdlet to limit the displayed fields:
ggr /me/messages -first 10 -Sort receivedDateTime | select ReceivedDateTime, Importance, Subject
However, to retrieve the 10 newest high-importance items, you should specify the -Descending
option, which means that all fields specified through OrderBy
will have a descending order by default:
ggr /me/messages -first 10 -Sort receivedDateTime, importance -Descending | select ReceivedDateTime, Importance, Subject
What if you want to sort using ascending order for one field, and descending for another? You can specify a PowerShell HashTable
to identify sort directions for specific fields. This lets you find the oldest high-importance items:
ggr /me/messages -first 10 -Sort @{receivedDateTime=$false;importance=$true} | select ReceivedDateTime, Importance, Subject
The $false
assignment in the hash table means that the field will use ascending sort order, and $true
means descending order.
AutoGraphPS isn't just an excellent browsing experience, it features commands for modifying the Graph as well:
New-GraphItem
Set-GraphItem
New-GraphObject
New-GraphItemRelationship
Remove-GraphItem
The following examples demonstrate common usage of these commands in creating and editing Graph resources. Unlike the read-only cases we've explored so far, you're likely to need some light research before jumping in with these command, i.e. you might want to read the actual Graph API documentation first. In particular, you'll need to have some basic answers in mind for the following questions before using write-operation commands:
- When creating a resource
- What is the name of the resource you want to create / modify? E.g.
user
,group
,message
, etc. - Alternatively do you know the resource's parent URI, e.g.
users
foruser
,me/contacts
forcontact
, etc. - What properties of the resource are required and must be set at creation time? You can find this information in the searchable / browseable Graph API reference; you can use the
Show-GraphHelp
command to quickly access the documentation for a resource if you know its name (e.g.Show-GraphHelp contact
). - What are the other (non-required) properties you'd like to configure? The commands will automatically complete the property name parameters if you've already specified the resource name or URI to help you find them. You can also use
Get-GraphType <resourcename> -Members
to get a list of the property names and their data types.
- What is the name of the resource you want to create / modify? E.g.
- When modifying an existing resource
- As in create, what is the name of the resource you want to modify?
- And alternatively, what is the resource's URI, e.g.
users/user@domain.com
for a user,me/contacts/<contactid>
for a contact - What are the names of the properties you want to modify and what are their types? Just like the create use case, parameter completion,
Get-GraphType -Members
andShow-GraphHElp
to find out.
With this information, you can use a single command to create or update the resource -- just supply it with
- For create: resource name and required property values OR parent URI and required property values
- For modify: resource name and ID and the property values to update OR resource URI and the property values
Lastly, while in many cases the property values are simple "primitive" types like strings and integers that can be easily expressed as command parameters, they may also themselves be nested "complex" data structures that contain their own properties. If you've obtained the type name of that property from the documentation (remember Show-GraphHelp
) or Get-GraphType
, you can specify that name to the New-GraphObject
command with the TypeClass Complex
parameter, i.e.:
# This command also lets you specify properties -- if you don't, it creates
# an object with empty values for all top-level properties
$ipRange = New-GraphObject ipv6Range
You can then set the properties of the $ipRange
variable as desired, and specify that variable as one of the property values to New-GraphItem
or Set-GraphItem
.
Now this preamble may seem rather lengthy compared to our near zero-knowledge approach of read-only use cases, but all of this really boils down to the need to know what you're going to change before you make an update, which isn't unreasonable for these more "dangerous" write use-cases. Fortunately, the answers to all of those questions are a few tab-completions or Get-GraphType
/ Show-GraphHelp
invocations away.
Now let's see concrete examples of these commands in action.
Our earlier examples were read-only operations. For write-operations to succeed, you'll need to request specific write permissions, so execute this command before you try the examples:
Connect-GraphApi User.ReadWrite.All, Group.ReadWrite.All, Contacts.ReadWrite
A few notes are in order:
- As long as you sign in with the same account used to execute the command above, you'll only need to run it once -- even if you start a new PowerShell session and sign in without executing that command, Entra ID (formerly known as AAD) will continue to grant those permissions to AutoGraphPS until you take an explicit action to revoke your consent to those permissions.
- These write permissions are typically not available to ordinary users in an Entra ID tenant; for the Entra ID-only scenarios, you'll need to be highly-privileged. If this isn't the case for you in your standard usage, you should use an alternate tenant, potentially one acquired through a developer program or trial Azure subscription.
This example uses the New-GraphItem
command to creates a new Entra ID security group:
PS> $newGroup = New-GraphItem group -Property mailNickName, displayName, mailEnabled, securityEnabled -Value Group7Access, 'Group 7 Access', $false, $true
The example specifies the following parameters for New-GraphItem
:
- The first (unnamed) parameter
group
specifies that the type of the resource to create isgroup
- The
Property
parameter specifies the properties that must be set for the new resource - The
Value
parameter specifies the values to which those properties must be set
Note that the choice of properties to specify was not arbitrary; the Graph documentation for the user resource states that for our use case the mailNickName
, displayName
, mailEnabled
, and securityEnabled
properties are mandatory. Additional properties may also be specified so that the resulting resource object has those properties configured to desired values, but the properties given in this example are the minimum set required for the user
resource.
When the command is issued, a request is made to Graph to create the security group, and Graph returns the serialized representation of the Group, the same representation that would be returned if that group were retrieved from Graph through Get-GraphResource
.
Since the value was assigned to the variable $newGroup
, it can be used in subsequent script operations, or as in the remainder of this example, inspected simply by evaluating it:
PS> $newGroup | select createdDateTime, displayName, mailNickname
createdDateTime displayName mailNickname
--------------- ----------- ------------
2020-04-22T01:27:41Z Group 7 Access Group7Access
The example specifies the following parameters for New-GraphItem
:
- The first (unnamed) parameter
group
specifies that the type of the resource to create isgroup
- The
Property
parameter specifies the properties that must be set for the new resource - The
Value
parameter specifies the values to which those properties must be set
Additionally, following the invocation of New-GraphItem
that creates the new security group, the example assigns the result of the creation to the variable $newGroup
, and then outputs 3 columns of the variable to the console for inspection.
Creating a group was easy. Let's create a user. Before doing so, a quick consultation of the user resource's documentation via Show-GraphHelp user
indicates that we need to specify the following properties at creation time: mailNickName
, userPrincipalName
, displayName
, accountEnabled
, and passwordProfile
. The first four are simple types (string
, string
, string
, and bool
respectively) that we know how to specify via command line arguments, but according to the documentation (and also Get-GraphType user
), the last is of type passswordProfile
, how do we specify that?
We can use the New-GraphObject
command to create the data structures as PowerShell objects (or optionally as JSON
text). New-GraphObject
does not issue requests or otherwise interact with Graph, but the local objects it creates can be can be specified to commands like New-GraphItem
, Set-GraphItem
, etc., that must submit such objects in requests. The parameters of New-GraphObject
have similar naming and semantics to thsoe of New-GraphItem
when it comes to types and properties, so after consulting the documentation for passwordProfile
we see that we can create the passwordProfile
object with this command:
$passwordProfile = New-GraphObject passwordprofile -Property forceChangePasswordNextSignIn, password -value $true, (Get-Credential user).GetNetworkCredential().Password
Note that we could have directly specified the password property value via the Value
parameter, but we chose to use Get-Credential
which provides an interactive UX for you to type the password. This approach prevents anyone nearby from seeing the password and also keeps it out of your PowerShell command history (however, it is now unencrypted in memory because it must be passed this way to Graph, hence care must be taken when configuring symmetric keys like this via Graph -- certificates are a much safer form of credential for instance).
Now we're ready to actually make the request to Graph that creates the user:
# This assumes you set `$passwordProfile` using the earlier `New-GraphObject` example
$newUser = New-GraphItem user -Property mailNickname, userPrincipalName, displayname, accountEnabled, passwordProfile -Value treejack, treejack@newnoir.org, 'Treemonisha Jackson', $true, $passwordProfile
We can see that the user has been successfully created by issuing a request to the Graph to get the new user using a command like the following:
PS> $newUser | Get-GraphItem
Graph Location: /users
Id DisplayName Job Title UserPrincipalName
-- ----------- --------- -----------------
8618a75d-a209-44f3-b2f8-2423cb211eed Treemonisha Jackson Director treejack@newnoir.org
In this example, a new contact
(i.e. e-mail or phone contact; requires either a free Microsoft account or non-trial Entra ID subscription) for the signed-in user is created. Here's a first attempt:
PS> $newContact = New-GraphItem contact
foreach : Exception calling "InvokeMethod" with "2" argument(s): "Unable to find URI for type 'contact' -- explicitly specify the target URI and retry."
Unfortunately, that didn't work. The exception and resulting error message indicating we should specify the target URI and retry means that New-GraphItem
could not translate our request to create a contact to a REST URI for Graph. Unlike the user case, there is no well-known request URI at which to create a contact (for user
it is a URI like https://graph.microsoft.com/v1.0/users
) because contact
is the type of object that exists only in relation to another object, not as a standalone instance.
Actually reviewing the REST documentation for contact shows that the use case for creating a contact is accomplished via POST
to the resource URI https://graph.microsoft.com/v1.0/me/contacts
. Conveniently, New-GraphItem
supports a Uri
parameter that allows you to specify the URI (me
since AutoGraphPS commands abstract the earlier parts of the URI), so after searching for additional documentation about contact
and experimenting to make up for the fact that as of this writing the documentation lacks details about which properties are required at creation time, we can execute the following commands to create a contact
:
# Create the emailAddress object that is required at creation time as an array
$emailAddress = New-GraphObject emailAddress -Property name, address -Value Work, cleo@soulsonic.org
$newContact = New-GraphItem -uri /me/contacts -Property givenName, emailAddresses -Value 'Cleopatra Jones', @($emailAddress)
# Dump the returned item to the console
PS> $newContact | select createdDateTime, displayname, emailAddresses
createdDateTime displayName emailAddresses
--------------- ----------- --------------
2020-04-22T04:20:11Z Cleopatra Jones @{name=Work; address=cleo@soulsonic.org}
You can confirm that it really exists in the Graph by invoking a command such as
Get-GraphResource -Uri /me/contacts | where displayName -eq $newContact.displayName
which will issue a request to Graph to retrieve all contacts, and then filter the results with where
to find the new contact by its display name and output it.
To modify an existing Graph resource, use the Set-GraphItem
command. You can pipe in the result of a previous Get-GraphItem
, Get-GraphResource
, New-GraphItem
, etc., invocation as the object to modify:
$newGroup | Set-GraphItem -Property displayName, description -Value 'Group 7 Access Level', 'All users with Group 7 access'
This changes the group's display name to Group 7 Access Level and updates the description as well. This example takes the object to modify from the pipeline. Since this command has analogs of parameters from New-GraphItem
and New-GraphObject
, you can also specify commands using the following syntax:
Set-GraphItem group $newGroup.Id -Property displayName, description -Value 'Group 7 Access Level', 'All users with Group 7 access'
And there are still more equivalent syntaxes, using the PropertyTable
or TemplateObject
parameters. PropertyTable
is just a more concise way to specify the Property
and Value
parameters via a HashTable
:
$newGroup | Set-GraphItem -PropertyTable @{displayName='Group 7 Access Level'; description='All users with Group 7 access'}
The TeamplateObject
parameter allows the these properties and values to be specified in the form of an object, such as one returned by New-GraphObject
or even from the Graph itself via Get-GraphResource
or gls
:
$modifiedGroup = New-GraphObject group description 'Just the description'
$newGroup | Set-GraphItem -TemplateObject $modifiedGroup
$newGroup | gls | select displayname, description
displayName description
----------- -----------
Group 7 Access Level Just the description
Both the TemplateObject
and PropertyTable
parameters can be specified simultaneously -- this could be useful for copying parts of one object as a "template" while adding additional properties:
$existingGroup = Get-GraphItem group 4e5701ac-92b2-42d5-91cf-45f4865d0e70
$existingGroup | gls | select description, displayName
mailNickname displayName description
------------ ----------- -----------
Unused Unassigned group
$templateGroup = Get-GraphItem group 0b828d58-2f7d-4ec5-92fb-20f0f88aa1a2 -Property displayName, description
$existingGroup | Set-GraphItem -TemplateObject $templateGroup -PropertyTable @{mailNickName='dorateam'}
$existingGroup | gls | select description, displayName
mailNickname displayName description
------------ ----------- -----------
dorateam Team group Standard team collaboration group
Finally, an object returned from the Graph may be "edited" locally and then resubmitted so that the local changes are reflected in the Graph. In this case,
the GraphItem
parameter supplied to the pipeline is both the target item to update and the source of data to modify:
$existingGroup = Get-GraphItem group 4e5701ac-92b2-42d5-91cf-45f4865d0e70
$existingGroup.displayName += ' - ' + [DateTime]::now
$existingGroup | Set-GraphItem
$existingGroup | gls | select description, displayName
description displayName
----------- -----------
Standard team collaboration group Team group - 05/16/2019 15:14:41
Note that Set-GraphItem
includes an ExcludeObjectProperty
parameter that allows you to ignore properties specified through TemplateObject
and GraphItem
which is useful when the object contains read-only properties that may have been returned as part of an object from a previously executed command.
The Graph is not just about individual resources, its power comes from the relationships between those resources. With groups and users for example, the fact that users are members of a group is modeled by a relationship property called members
. This means that by modifying the members
relationship property, we can modify which users are members of a group.
To modify a relationship, the New-GraphItemRelationship
command may be used:
New-GraphItemRelationship -FromItem $newGroup -ToItem $newUser -Relationship members
Relationship TargetId FromUri TargetUri
------------ -------- ------- ---------
members 71edbed4-a7e7-4b46-8e2f-a28e9135ca54 /groups/f8418e85-e865-45ba-bec6-d16b6dc44045 /directoryObjects/e510d45c-aec3-4026-ba8e-317480ae7bc5
This adds a directional relationship between the group and the user "group is related to user" through the members
relationship. In accordance with the API documentation for group, the interpretation of this relationship is that the user is now a member of the group.
To see the new relationship, but not the related items themselves, use the Get-GraphItemRelationship
command:
$newGroup | Get-GraphRelatedItem -WithRelationship members
To see the actual items from the relationships (e.g. the members of a group and not just their id's), use the Get-GraphRelatedItem
command:
$newGroup | Get-GraphRelatedItem -WithRelationship members
Graph Location: /v1.0:/groups/053850da-691d-4605-9bda-6b3d74c7addb/members
Info Type Preview Id
---- ---- ----------- --
t +> user Treemonisha Jackson 8618a75d-a209-44f3-b2f8-2423cb211eed
Another useful syntax for New-GraphItemRelationship
is to supply the items on the "to" side of the relatinoship via the pipeline -- this exploits PowerShell pipeline idioms to simplify operating on sets of objects:
# Create passwords for some new users
$passwordProfile1 = New-GraphObject passwordprofile -Property forceChangePasswordNextSignIn, password -Value $true, (Get-Credential user).GetNetworkCredential().Password
$passwordProfile2 = New-GraphObject passwordprofile -Property forceChangePasswordNextSignIn, password -Value $true, (Get-Credential user).GetNetworkCredential().Password
# Create the actual users
$newUser1 = New-GraphItem user -Property mailNickname, userPrincipalName, displayname, accountEnabled, passwordProfile -Value vashford, vashford@newnoir.org, 'Val Ashford', $true, $passwordProfile1
$newUser2 = New-GraphItem user -Property mailNickname, userPrincipalName, displayname, accountEnabled, passwordProfile -Value nsimpson, nsimpson@newnoir.org, 'Nick Simpson', $true, $passwordProfile2
# Create a new group for the users
$teamGroup = New-GraphItem group mailNickName, displayName, mailEnabled, securityEnabled Group7AccessT1, 'Group 7 Access 2', $false, $true
# Add the users to the group
$newUser1, $newUser2 | New-GraphItemRelationship $teamGroup members | out-null
# Display the group's updated membership with the new users
$teamGroup | Get-GraphRelatedItem -WithRelationship members
Graph Location: /v1.0:/groups/c436312c-4f6e-4963-ac05-bf68b98d7475/members
Info Type Preview Id
---- ---- ------- --
t +> user Val Ashford d126df35-b441-472e-a3d1-2de370cbbbb7
t +> user Nick Simpson aafbc281-cce2-450b-9409-7113033d2f62
The inverse of the New-GraphItemRelationship
command is Remove-GraphItemRelationship
. In this example the user with id 36d3e3d4-55f2-405f-a601-fd522b7998f4
is removed from the group with id 51a617a1-9174-4836-9a8c-d1cee804bc61
:
Remove-GraphItemRelationship -FromType group -FromId 51a617a1-9174-4836-9a8c-d1cee804bc61 -Relationship members -Id 36d3e3d4-55f2-405f-a601-fd522b7998f4
A syntax that supports an object rather than identifier for the subject or object of the relationship or both is also available:
Remove-GraphItemRelationship -FromItem $existingGroup -Relationship members -ToId 36d3e3d4-55f2-405f-a601-fd522b7998f4
And the pipeline is also supported -- these example removse all members from the group $teamGroup
:
$teamGroup | Get-GraphItemRelationship -WithRelationship members | Remove-GraphItemRelationship
Lastly, the resources we've created can all be deleted using the Remove-GraphItem
command. This example deletes the group with the id c436312c-4f6e-4963-ac05-bf68b98d7475
:
Remove-GraphItem group c436312c-4f6e-4963-ac05-bf68b98d7475
The command also takes an object returned by Get-GraphItem
or Get-GraphResource
, etc., which is useful for deleting resources accessible only through a relationship with another resource, such as contact
:
# If you have a variable containing the contact retrieved by an AutoGraphPS
# command such as Get-GraphResource, New-GraphItem, gls, etc., you can easily
# delete it by passing it to Remove-GraphItem
$oldContact | Remove-GraphItem
- Use
Show-GraphHelp
to get the documentation for the Graph resource in which you're interested. - Use
Get-GraphType -Members
to view the properties of the type or structure you're updating - Use parameter completion with commands like
New-GraphObject
,New-GraphItem
,Set-GraphItem
, etc. to ease your workflow and avoid the need to refer to documentation - Pay attention to error messages from Graph -- these messages will often give useful information about missing or invalid properties so that you can try again, or at least help you navigate a particular help topic.
- Look for opportunities to use the PowerShell pipeline with AutoGraphPS command for concise, efficient, and scalable automation of Graph resource management.
We've covered the ways in which data can be created, updated, queried, and deleted. Graph also supports capabilities beyond those circumscribed by such CRUD
operations through methods. Graph methods, not to be confused with methods like PUT
, GET
, et. al. of the HTTP protocol upon which the Graph protocol is layered, can perform arbitrary operations. These Graph methods are very much like methods in the object-oriented sense, i.e. they are named units of computation that operate on state within the scope of some object. Methods in Graph have the following characteristics:
- Methods are scoped to an entity type, e.g.
user
,group
,drive
, etc. - Methods have a name that can be used to invoke them -- examples are
sendMail
on the user object,assignLicense
on the group object, orsearch
on the drive object. - To invoke a method, you need to be able directly or indirectly space the
id
of the entity and the name of the method
Within the framework of the Graph's REST protocol, invoking a method involves constructing the appropriate URI just as in the case of all the CRUD
operations. The URI in this case will refer to both a particular instance of an entity, typically using an id
but potentially using a singleton such as me
.
AutoGraphPS provides the Invoke-GraphMethod
command to make it easy to invoke methods. Here's an example that performs a search of the user's drive, using the search
method of the calling user's drive
and passing the query string in the method's q
parameter:
Invoke-GraphMethod /me/drive/search q 'name:docx powershell'
Info Type Preview Id
---- ---- ------- --
t +> driveItem Exploring the Microsoft Graph.docx AX893842
t +> driveItem PowerShell user experience for Graph.docx ZZ8972ZR
t +> driveItem DevOps and PowerShell use cases.docx KSJFLAJ3
t +> driveItem Analysis of PowerShell and REST API usability K8JRAJZE
The method returned a set of driveItem
objects that satisfied the query name:docx powershell
, the intent of which was to return any content on the drive that contained the keyword powershell
in items with a name
containing docx
.
Since the URI given as the first parameter is relative to the current location, the following invocation would produce the same result:
gcd /me/drive
Invoke-GraphMethod search q 'name:docx powershell'
In the next example, Invoke-GraphMethod
is used to send an email message. In this case, we construct the email message to send using New-Graphobject
and New-GraphMethodParameterObject
before passing it as a parameter to Invoke-GraphMethod
:
$me = gls me
$recipientEmail = new-graphobject emailAddress address katwe@newnoir.org
$recipient = new-graphobject recipient emailAddress $recipientEmail
$sendMailParameters = New-GraphMethodParameterObject user sendMail
$sendMailParameters.SaveToSentItems = $true
$sendMailParameters.Message = $sendMailParameters.Message | select subject, body, toRecipients
$sendMailParameters.Message.toRecipients = @($recipient)
$sendMailParameters.Message.Subject = 'What time is it?'
$sendMailParameters.Message.Body.ContentType = 'text'
$sendMailParameters.Message.Body.Content = "The time is $([DateTime]::now), so it's time to Wake Up! --Love, $($me.Content.givenName)"
$me | Invoke-GraphMethod -methodname sendmail -ParameterObject $sendMailParameters
In this case, we invoke the method sendMail
on the previously retrieved $me
object by passing $me
in the pipeline. The constructed parameters are specified by the ParameterObject
parameter of Invoke-GraphMethod
.
All of the rich Microsoft Graph operations described here, even simple read operations, require you to have some minimum amount of knowledge, e.g. the URI or the "type" of the resource you'd like to access. You will find all of the required information in the Microsoft Graph documentation. Fortunately, you don't have to spend your time poring over manuals: AutoGraph provides the tools that often eliminate the need to leave PowerShell to read documentation, or at least help you find the right docs for your scenario.
The commands described below are very useful when you know you want to use Microsoft Graph to do something, but you're not sure where to start.
In the Microsoft Graph documentation, the term "resource" is used to refer to any aspect of the Graph that is addressable by an identifier (whether a URI or non-URI) and that is capable of relating to or being related to by other resources. The OData specification upon which Microsoft Graph is currently defined at the protocol level refers to this same resource concept as an "entity type," and this latter terminology is mostly what you'll find in AutoGraphPS. Either way, resources / entity types are the key concepts exposed by Graph that form a cohesive model within and across the problem domains (e.g. security, communication, document management, etc.) that you understand. Once you understand the resource for your use case, you've unlocked your comprehension of a meaningful chunk of the Graph.
Let's say you want to find a security group that has a specific name. Since you know you want to do something with a "group," you can look for resources related to "group" using the Find-GraphType
command:
Find-GraphGype group
TypeClass TypeId Criteria MatchedTerms
--------- ------ -------- ------------
Entity microsoft.graph.group {Name} {microsoft.graph.calendargroup microsoft.graph.group microso...
Entity microsoft.graph.grouplifecyclepolicy {Name} {microsoft.graph.calendargroup microsoft.graph.group microso...
Entity microsoft.graph.schedulinggroup {Name} {microsoft.graph.calendargroup microsoft.graph.group microso...
The output of Find-GraphType
in this case is a list of types deemed "relevant" to the supplied search term group
. The results are sorted by relevance, so the first item in the list can be treated as most likely to be the one you're looking for. The command contains several parameters that allow you to customize the criteria used to identify matches as well as the "fuzziness" of those matches.
The Show-GraphHelp
command launches a web browser with the web page displaying help for a resource specified by URI, an object returned as a response from the Graph API, and also the name of a type, i.e. Graph resource. Since the command takes input from the pipeline, the type can be supplied by the output of the Find-GraphType
command we demonstrated above:
Find-GraphGype group | Select-Object -First 1 | Show-GraphHelp
This command shows the help page for the first result in the output of the search for group
, the result for microsoft.graph.group
. Now you can read about the group
resource to confirm that it is indeed the resource you need, and also find out more details about the operations that can be performed on the resource.
The documentation for the resource should contain information describing the permissions you need to perform specific operations on the resource. If you don't already have the web-based documentation for the relevant operation in view, you can look for this information within your PowerShell session via the Find-GraphPermission
command:
Find-GraphPermission group
Type ConsentType Name Description
---- ----------- ---- -----------
Delegated Admin Group.Read.All Allows the app to list groups, and to read their prope...
Delegated Admin Group.ReadWrite.All Allows the app to create groups and read all group pro...
AppOnly Admin Group.Read.All Allows the app to read group properties and membership...
AppOnly Admin Group.ReadWrite.All Allows the app to create groups, read all group proper...
Using this output which includes a description of the permission, you can determine which permission applies to your scenario. Do you need write access, or just read? Are you accessing the resource using interactive delegated sign-in, or as part of a non-interactive background application? Once you've used those answers to narrow the list down to the least-privileged permission required for your scenario, you can request that permission using the Connect-GraphApi
command so that your application is able to access the resource.
Currently, the resource's rich documentation, including examples, is available only the web browser and can be accessed via the Show-GraphHelp
command. However, in many cases your focus is on understanding the structural properties, methods, or relationships between resources. This information about the types is available within PowerShell via several commands: Get-GraphType
, Get-GraphMember
, and Get-GraphMethod
. For example, here is the output of Get-GraphType
for the group
resource identified earlier:
Get-GraphType group
Graph TypeId: microsoft.graph.group
TypeClass : Entity
BaseType : microsoft.graph.directoryObject
DefaultUri : /groups
Relationships : {appRoleAssignments, createdOnBehalfOf, memberOf, members...}
Properties : {assignedLabels, assignedLicenses, classification, createdDateTime...}
Methods : {subscribeByMail, validateProperties, unsubscribeByMail, resetUnseenCount...}
GraphName : v1.0
The resulting object contains information such as the "default" URI, this case /groups
, under which instances of the group
resource may be found. You can use Select-Object
to project the Relationships
field that shows the connections with other resources, the Properties
field which gives the structure of the object, and the Methods
field which returns all of the methods available to the object.
Yes -- the Get-GraphMember
command which is similar to the widely utilized core PowerShell command Get-Member
emits output that provides a streamlined representation of all of the members, including Property
, Relationship
, and Method
members. To view just the structural properties, the MemberType
parameter can be specified with the value Property
:
Get-GraphMember group -MemberType Property
MemberType: Property (microsoft.graph.group)
Name MemberType TypeId IsCollection DefiningTypeId
---- ---------- ------ ------------ --------------
allowExternalSenders Property Edm.Boolean False microsoft.graph.group
assignedLabels Property microsoft.graph.assignedLabel True microsoft.graph.group
assignedLicenses Property microsoft.graph.assignedLicense True microsoft.graph.group
...
theme Property Edm.String False microsoft.graph.group
unseenCount Property Edm.Int32 False microsoft.graph.group
visibility Property Edm.String False microsoft.graph.group
For each property name the data type is given as well as whether it's a collection, and can save you a trip to the web browser.
In the example above, the properties that are named without the Edm
prefix are actually structured to definitions present in the API schema. They are typically nested structures, and you can simply use Get-GraphMember
again along with the associated resource name (TypeId
in acccordance to the output of Get-GraphMember
) to find it:
Get-GraphMember assignedLicense -MemberType Property
MemberType: Property (microsoft.graph.assignedLicense)
Name MemberType TypeId IsCollection DefiningTypeId
---- ---------- ------ ------------ --------------
disabledPlans Property Edm.Guid True microsoft.graph.assignedLicense
skuId Property Edm.Guid False microsoft.graph.assignedLicense
This is useful both in understanding what to expect in terms of responses and also what you may need to supply in submitting requests that include these types. Note that simply using New-GraphObject
to create an "empty" object can allow you to inspect an object representing the resource directly:
$sample = New-GraphObject group -Recurse -SetDefaultValues
$sample.licenseProcessingState
state
-----
It should be noted that when constructing resources to submit requests that create new resource instances or update them, the commands that do this actually simplify the specification of the structure. It's often unnecessary to know about every single property of a resource. See the earlier examples for New-GraphItem
, Set-GraphItem
, and New-GraphObject
for more details on how you can efficiently specify just the properties required to submit a resource as part of a request to Graph.
If you are using PowerShell to browse resources exposed by the Graph, the documentation will explain the URIs under which you might find them. The Get-GraphType
command exposes a DefaultUri
field that provides a possible location where you might find the type, though not all types have a "default" URI:
Get-GraphType group | Select-Object DefaultUri
DefaultUri
----------
/groups
gcd /groups
gls
The Get-GraphMember
command's MemberType
can be specified as Relationship
to enumerate all of the relationships from this resource to other resources:
Get-GraphMember group -MemberType Relationship
MemberType: Relationship (microsoft.graph.group)
Name MemberType TypeId IsCollection DefiningTypeId
---- ---------- ------ ------------ --------------
acceptedSenders Relationship microsoft.graph.directoryObject True microsoft.graph.group
appRoleAssignments Relationship microsoft.graph.appRoleAssignment True microsoft.graph.group
calendar Relationship microsoft.graph.calendar False microsoft.graph.group
...
threads Relationship microsoft.graph.conversationThread True microsoft.graph.group
transitiveMemberOf Relationship microsoft.graph.directoryObject True microsoft.graph.group
transitiveMembers Relationship microsoft.graph.directoryObject True microsoft.graph.group
You can use Get-GraphMember
again to view just Method
members, but the specialized Get-GraphMethod
command provides more focused output:
Get-GraphMethod group
TypeId: group
Name MethodType ReturnType IsCollection DefiningTypeId
---- ---------- ---------- ------------ --------------
addFavorite Action False microsoft.graph.group
assignLicense Action microsoft.graph.group False microsoft.graph.group
checkMemberGroups Action Edm.String True microsoft.graph.directoryObject
restore Action microsoft.graph.directoryObject False microsoft.graph.directoryObject
...
subscribeByMail Action False microsoft.graph.group
unsubscribeByMail Action False microsoft.graph.group
validateProperties Action False microsoft.graph.group
When you've identified a useful method, the next question is what parameters do you need to feed it? Get-GraphMethod
has a Parameter
option that lists just the parameters for a method:
Get-GraphMethod group assignLicense -Parameters
Method: assignLicense
ParameterName TypeId IsCollection
------------- ------ ------------
addLicenses microsoft.graph.assignedLicense True
removeLicenses Edm.Guid True
By making use of these "type" introspection commands, you can easily find your way to detailed web-based documentation when you need it, and otherwise get focused, relevant reference information within the comfortable and efficient environment of PowerShell.
AutoGraphPS provides commands to manage Entra ID application identities, including the ability to manage permission consent for the applications. These commands are useful for provisioning any application or service for your organization, and may also be used to create new identities for which to execute AutoGraphPS-based scripts. And because application management commands are built-in to the module, AutoGraphPS is a self-contained Graph automation solution; there is no need jump outside to other command-line or graphical tools / portals if you need to provision an application identity dedicated to automation since AutoGraphPS itself can perform the provisioning.
By default, AutoGraphPS uses a particular multi-tenant application identity to allow you to sign in to your organization and execute all of the AutoGraphPS commands that access the Graph API. This application was provisioned by the maintainer of AutoGraphPS. Alternatively, you may use a different application with AutoGraphPS, one that you have provisioned and over which you have complete and sole control.
The New-GraphApplication
command provisions a new public client application for interactive sign-in -- the application is granted the specific delegated permissions User.Read
and Group.Read.All
in this invocation:
$newApp = New-GraphApplication 'Custom Graph PowerShell App' -DelegatedUserPermissions User.Read, Group.Read.All -ConsentForAllUsers
Connect-GraphApi -AppId $newApp.AppId
AppId ConnectionName Organization AuthType
----- -------------- ------------ --------
32a7262b-492a-4ad2-bb96-2ff8ff6cf680 (Unnamed) 24775524-ce1d-42ec-8aba-0b5763695729 Delegated
$groups = Get-GraphResource /groups
The New-GraphApplication
command issued a request through the Graph API to create a new public client Entra ID application. Anyone in the organization can sign in to the application. Since the optional ConsentForAllUsers
parameter was also specified, consent has been granted to the application for all users in the organization; they will not get prompted for consent when using it. By default, any delegated permissions specified to the command will be consented only for the user issuing the New-GraphApplication
command, not the entire organization.
The subsequent use of the Connect-GraphApi
command with the AppId
parameter shown above allows users to sign in with this (or any other) application by specifying the application's identifier. Once signed in, AutoGraphPS commands may be issue just as they are when using the default AutoGraphPS application; the commands will be authorized by the Graph API based on the permissions granted to this application at sign-in.
In general, consent can be managed outside of application creation by using commands such as Set-GraphApplicationConsent
, Get-GraphApplicationConsent
, and Remove-GraphapplicationConsent
The built-in application identity for AutoGraphPS requires a user to sign-in before commands can be issued against the Graph. The requirement for human interaction won't work for fully automated scenarios such as running AutoGraphPS PowerShell scripts as background jobs or in other unattended contexts. To address this, you can use New-GraphApplication
to provision a confidential client application that authenticates without human intervention:
# In addition to creating the app identity with Graph, this commmand
# creates a certificate in the local certificate store for unattended
# authentication
$newApp = New-GraphApplication 'Daily user information stats background app' -Confidential -ApplicationPermissions User.Read.All -NewCredential
# This command requires no user interaction because a certificate in the local
# certificate store is being used
Connect-GraphApi -AppId $newapp.AppId -NoninteractiveAppOnlyAuth -TenantId natossa@ether.org
AppId ConnectionName Organization AuthType
----- -------------- ------------ --------
3ea110e5-80e1-48a6-b67f-a3c5dc108b96 (Unnamed) AppOnly
$users = Get-GraphResource users
In this example, New-GraphApplication
creates a new confidential client application identity and provisions it with User.Read.All
. However, if the AutoGraphPS script is executed from the Windows OS, then by default New-GraphApplication
also creates a certificate in the local certificate store specific to this application and configures Entra ID to enable that certificate as a credential for the identity.
The example continues by using the newly created application to sign in to Graph using Connect-GraphApi
. In addition to specifying the new application's identifier using the AppId
parameter, the Confidential
parameter must be supplied to direct the command to require credentials for the application itself and not just a user's credentials, AND the NonInteractiveAppOnlyAuth
parameter must be supplied so that only the application credential is required (no user interaction is desired in this case). Additionally, the TenantId
parameter must be specified using either the domain name of the tenant as in this case or the the tenant identifer. This allows the command to direct the sign-in to the correct tenant.
Connect-GraphApi
then searches for a certificate for the application in the local certificate store, and will find the one created by New-GraphApplication
and use it to authenticate.
After authentication succeeds, the example retrieves all of the users in the tenant by invoking Get-GraphResource
against the users
URI.
The following considerations related to non-interactive authentication should be noted:
- The automatic certificate provisioning in the local certificate store by
New-GraphApplication
is optional, and indeed only occurs on the Windows platform - The certificates created by
New-GraphApplication
and related commands can be enumerated using theFind-GraphLocalCertificate
command and filtered by the application identifier. New-GraphApplication
allows for certificates from other sources such as files to be specified instead of allowingNew-GraphApplication
to create the certificate. The latter approach is fully supported for non-Windows platforms.Set-GraphApplicationCertificate
can be used to update the application credentials outside of the context application creation. This is useful for periodic certificate rotations prior to the expiration of the certificate for instance. In general it can be used set pre-existing certificates as application credentials (fully supported for non-Windows PowerShell environments)Remove-GraphApplicatinCertificate
removes the association of a certificate from an application -- this is also useful as part of a certificate rotation process. It does not impact the actual certificate itself, even if it is stored on the local system.New-GraphApplicationCertificate
can be used to create a new certificate as an object, in the file system, or in the local certificate store (Windows-only) and sets that certificate as a credential for the application.- As is the case with the applications using delegated permissions, the
Set-GraphApplicationConsent
,Get-GraphApplicationConsent
, andRemove-GraphApplication
consent commands may be used to manage application permissions outside of the application creation flow - Certificates used as credentials for applications are secrets and must be treated as such; they must be secured from discovery and made available only on trusted systems for authorized uses.
The parameters of all of these commands allow for additional scenarios beyond those described here, so be sure to explore the commands further in evaluating identity provisioning and sign-in capabilities against your needs.
Whether it's due to coding defects in scripts or typos during your exploration of the Graph, you'll inevitably encounter errors. The cmdlet Get-GraphError
will show you the last error returned by the Microsoft Graph API during your last cmdlet invocation:
Get-GraphResourceWithMetadata /users -Filter "startwith(userPrincipalName, 'pfunk')"
This results in an error:
foreach : Exception calling "InvokeMethod" with "2" argument(s): "Exception calling "InvokeMethod" with "2" argument(s): "The remote server returned an
error: (400) Bad Request.""
At C:\Users\adamed\src\autographps\.devmodule\scriptclass\0.20.2\src\scriptobject\dsl\MethodDsl.ps1:37 char:16
+ $objects | foreach {
+ ~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ForEach-Object], MethodInvocationException
+ FullyQualifiedErrorId : ScriptMethodRuntimeException,Microsoft.PowerShell.Commands.ForEachObjectCommand
The 400
is a fairly generic error -- to debug it, we'd like to see the response body from the server. Get-GraphError
exposes it along with other useful information. For the error above, the message
field of the ErrorResponse
JSON property gives a hint at what was wrong with the request: Invalid filter clause
:
Get-GraphError
RequestTimestamp : 10/12/2021 22:03:15 PM -07:00
Status : 400
ErrorResponse : {"error":{"code":"BadRequest","message":"Invalid filter clause","innerError":{"date":"2021-10-14T03:38:07","request-id":"25343cc1
-84b7-47ce-aec6-cc64cad83ecd","client-request-id":"956d2a74-268f-45fd-8359-febe38edcc66"}}}
Method : GET
Uri : https://graph.microsoft.com/v1.0/users?$filter=startwith(userPrincipalName, 'pfunk')
RequestBodySize : 0
ClientElapsedTime : 00:00:00.0962222
RequestHeaders : {Authorization, Content-Type, client-request-id, ConsistencyLevel}
ClientRequestId : 956d2a74-268f-45fd-8359-febe38edcc66
AppId : a8d7de53-99f6-4542-834b-b4185eb366fc
TenantId :
UserUpn :
UserObjectId :
AuthType : AppOnly
ResourceUri : users
Query : ?$filter=startwith(userPrincipalName,%20'pfunk')
ResponseTimestamp : 10/12/2021 22:03:15 PM -07:00
ResponseClientRequestId : 956d2a74-268f-45fd-8359-febe38edcc66
ResponseHeaders : {x-ms-ags-diagnostic, Transfer-Encoding, request-id, Content-Type...}
ResponseContentSize :
ResponseRawContentSize :
A close look at the filter clause shows that startwith
is missing an s
after start
-- the corrected command below will succeed with a 200
:
Get-GraphResourceWithMetadata /users -Filter "startswith(userPrincipalName, 'pfunk')"
Graph Location: /v1.0_10:/users
Id DisplayName Job Title UserPrincipalName
-- ----------- --------- -----------------
83dd3dbb-d7f3-44d3-a4a1-b92971ba7379 Sir Nose devoidof@funk.org
30285b8b-70ba-42e0-9bd9-fbcee5d1ce64 PFunk 4Life Verbalizer pfunk@funk.org
You can inspect the various properties and object returned by Get-GraphError
to find additional details that help you debug a failure.
AutoGraphPS records a log of every request and response to Graph issued by AutoGraphPS commands. To view the contents of the log, invoke the Get-GraphLog
command. In the example below, Get-GraphLog
is invoked immediately following an attempt to create a new security group using New-GraphItem
$newGroup = New-GraphItem group -Property mailNickName, displayName, mailEnabled -Value ReportViewers, 'Report Viewers', $false
Get-GraphLog
RequestTimestamp StatusCode Method Uri
---------------- ---------- ------ ---
2/26/2021 10:08:38 PM -08:00 400 POST https://graph.microsoft.com/v1.0/groups
2/26/2021 10:01:07 PM -08:00 204 DELETE https://graph.microsoft.com/v1.0/groups/7330583a-d3e5-494b-800c-8e4b67be8460
2/26/2021 10:01:07 PM -08:00 200 GET https://graph.microsoft.com/v1.0/groups/7330583a-d3e5-494b-800c-8e4b67be8460
2/26/2021 10:00:57 PM -08:00 201 POST https://graph.microsoft.com/v1.0/groups
2/26/2021 9:58:56 PM -08:00 200 GET https://graph.microsoft.com/v1.0/organization
2/26/2021 9:55:28 PM -08:00 200 GET https://graph.microsoft.com/v1.0/users?$search=johnson
2/26/2021 9:47:23 PM -08:00 200 GET https://graph.microsoft.com/v1.0/groups?$search=ashford
TIP: You can pipe the output of Get-GraphLog to the Format-GraphLog command and use its
View
parameter to provide output optimized for scenarios such as investigating timing or authentication issues.
The log shows information about the underlying REST protocol request issued by the commands, sorted with the most recent requests first. The StatusCode
column shows that the most recent request was a failed request because its value of 400
is outside the 2xx
success range. There are many more diagnostic fields such as HTTP request and response headers available outside of the default tabular view for the command -- use the Get-Member
command on the output of Get-GraphLog
to learn more.
You can use commands like Clear-Log
and Set-GraphLogOption
to manage the log's data and the module's logging behaviors including retention and level of detailed logging:
- By default, AutoGraphPS logs information such as the HTTP request URI, request and response headers, and status code, but omits the request and reponse body to protect the privacy of users and organizations using AutoGraphPS.
- Headers known to contain secrets such as the
Authorization
header used to communicate the access token are always redacted -- the actual value of the header is never logged - To completely disable logging which is enabled by default, use the command
Set-GraphLogOption -LogLevel None
- To erase previously logged data, issue the
Clear-Log
command - Currently the log persists only in-memory, so when the PowerShell session ends or the AutoGraphPS-SDK module is unloaded, the log contents are completely erased.
The log allows for the full range of protocol debugging and can help diagnose connectivity issues or problems with intermediate gateways between AutoGraphPS and the Graph API service. When used in conjunction with standard network diagnostic tools you'll be able to narrow down just about any issue.
In addition, the logs are a great way to learn about Microsoft Graph at the REST protocol level; with each command, you can see the resulting REST requests and responses to gain an understanding of the Graph API protocol.
In the example above, the most recent command was
$newGroup = New-GraphItem group -Property mailNickName, displayName, mailEnabled -Value ReportViewers, 'Report Viewers', $false
which failed with a 400 Bad Request
error. We can get more information on the failure by looking in more detail at the most recent log entry, which has the same output as Get-GraphError
:
Get-GraphLog -Newest 1 | Format-List *
RequestTimestamp : 2/27/2021 1:15:23 AM -08:00
Status : 400
ErrorResponse : {"error":{"code":"Request_BadRequest","message":"A value is required for property 'securityEnabled' of resource 'Group'.","innerE
rror":{"date":"2021-02-27T09:14:50","request-id":"2f2f9077-1c5b-46f1-a7a1-c706924b2ba3","client-request-id":"f8e1b815-cd69-4431-b
362-554d901c4019"}}}
Method : POST
Uri : https://graph.microsoft.com/v1.0/groups
RequestBodySize : 110
ClientElapsedTime : 00:00:00.2353523
RequestHeaders : {Authorization, Content-Type, client-request-id, ConsistencyLevel}
ClientRequestId : 87572233-f11d-41db-bfa7-dd172fd2a03f
AppId : ac70e3e2-a821-4d19-839c-b8af4515254b
TenantId :
UserUpn :
UserObjectId :
AuthType : AppOnly
ResourceUri : groups
Query :
ResponseTimestamp : 2/27/2021 1:15:23 AM -08:00
ResponseClientRequestId : 87572233-f11d-41db-bfa7-dd172fd2a03f
ResponseHeaders : {x-ms-ags-diagnostic, Transfer-Encoding, request-id, Content-Type...}
ResponseContentSize :
ResponseRawContentSize :
Note that the ErrorResponse
field provides the detail needed to resolve the issue: A value is required for property 'securityEnabled' of resource 'Group'.
The request did not include an explicit value for the securityEnabled
property of the group; Graph requires this property be specified at creation time. The fix then is simple -- the original command can be modified to include the required property and re-invoked as followed:
$newGroup = New-GraphItem group -Property mailNickName, displayName, mailEnabled, securityEnabled -Value ReportViewers, 'Report Viewers', $false $true
This modified command now succeeds.
To ensure the privacy of Graph data accessed by AutoGraphPS, by default the module does not log the body of a request or response. These elements of the protocol can contain sensitive information such as the actual contents of a document or e-mail, as well as the title or subject of such communication. This safe default behavior can be overridden when the need arises using the Set-GraphLogOption
command:
$newGroup = New-GraphItem group -Property mailNickName, mailEnabled, securityEnabled -Value Group7Access, $false, $true
# This command generates no output because the request body
# is not emitted to the log by default
Get-Graphlog -Newest 1 | Select-Object -ExpandProperty RequestBody
# Issue this command to enable full logging of request and response body
Set-GraphLogOption -LogLevel Full
# Now retry the scenario
$newGroup = New-GraphItem group -Property mailNickName, mailEnabled, securityEnabled -Value Group7Access, $false, $true
# Now the JSON request body from the retried command is emitted:
Get-Graphlog -Newest 1 | Select-Object -ExpandProperty RequestBody
{
"mailEnabled": false,
"securityEnabled": true,
"displayName": "Group 7 Access",
"mailNickname": "Group7Access"
}
The ability to view the full request and response enhances debugging scenarios, aids users learning about the Graph API protocol, and provides an easy way to generate REST protocol sequences for use in developing non-PowerShell applications that make direct use of REST to access the Graph API.
Full logging enabled by Set-GraphLogOption
will remain in effect for the duration of the PowerShell session until the Basic
logging level is restored by another invocation of Set-GraphLogOption
. Note that changing the log level does not affect the content of previous logs, so to remove any full request or response data in the log, use Clear-Log
to erase it once it is no longer needed, or simply close the PowerShell session.
All AutoGraphPS cmdlets support the PowerShell standard option -verbose
and the associated $VerbosePreference
preference variable. When using cmdlets such as Get-GraphResource
and Get-GraphChildItem
, specifying -verbose
will output not only the http
verb and uri
used to access the Graph, but also the request headers and for responses the response body and headers.
By default, the response body is truncated after a certain length, though the behavior can be overridden by setting GraphVerboseOutputPreference
to High
.
Microsoft Graph requires callers to obtain specific authorization for applications like AutoGraphPS to access particular capabilities of the Graph. Because the mapping of required permissions to functionality is currently only available through human-readable documentation, it's easy for developers and other human users of applications including AutoGraphPS to encounter errors due to insufficient permissions.
Often, users and developers remedy the error by reading the documentation, and updating the application to request the missing permissions. AutoGraphPS tries to hasten such fixes by surfacing authorization failures with a warning encouring the user to request additional permissions as in the example below where the caller tries to access me/people
to get information about the people with whom she has been interacting:
PS> gls me/people
WARNING: Graph endpoint returned 'Unauthorized' accessing 'me/people'. Retry after re-authenticating via the
'Connect-GraphApi' cmdlet and requesting appropriate permissions. See this location for documentation on
permissions that may apply to this part of the Graph:
'https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference'.
WARNING: {
"error": {
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again.",
"innerError": {
"request-id": "bfcd8509-1a0e-4e8b-8b15-435bb413003b",
"date": "2018-07-07T30:43:14"
}
}
}
The warning message in the AutoGraphPS output includes a link to the permissions documentation and suggestion to use Connect-GraphApi
to grant AutoGraphPS additional permissions. Consultation of the documentation may lead the user to conclude that AutoGraphPS is missing the 'People.Read' scope, and a retry of the original attempt after using Connect-GraphApi
to request People.Read
will succeed:
# This will prompt the user to re-authenticate and grant People.Read
# to AutoGraphPS
Connect-GraphApi People.Read
gls me/people
Info Type Preview Name
---- ---- ------- ----
t +> person Cosmo Jones X8FF834
t +> person Minerva Smith X8FF835
t +> person Rufus Chang X8FF332
The concepts and commands below are described briefly as their usage is (currently) less common. In cases where they prove to cover important scenarios, simpler cmdlets will eventually be added for those uses.
The -Query
parameter for several commands lets you directly specify the Uri query parameters for the Graph call made by AutoGraphPS. It must conform to OData specifications. The option is provided to allow you to overcome limitations in AutoGraphPS's simpler query options. For example the two commands below are equivalent:
gls /users -Filter "startsWith(mail, 'p')" -top 20
gls /users -Query "`$filter=startsWith(mail, 'p')&`top=20"
Note that -Query
requires you to understand how to combine multiple query options via '&' and also how to make correct use of PowerShell escape characters so that OData tokens like $top
which are preceded by the $
character which is reserved as a variable prefix in PowerShell are taken literally instead of as the value of a PowerShell variable.
While -Query
may be more complicated to use, when AutoGraphPS's other query options do not support a particular Graph query feature, you still have a way to use Graph's full capabilities.
For more details on how to construct this parameter, see the MS Graph REST API documentation for queries.
The Invoke-GraphApiRequest
cmdlet supports all of the functionality of Get-GraphResource
, and exceeds it in a key aspect: where Get-GraphResource
only enables APIs that support the GET
http
method, Invoke-GraphApiRequest
supports all http methods, including PUT
, POST
, PATCH
, and DELETE
.
This means you can use Invoke-GraphApiRequest
for not just read operations as with the Get-Graph*Item
cmdlets, but write operations as well. In fact, any behavior supported by Microsoft Graph is accessible through this command. However such invocations are typically far more cumbersome to issue than those of the other dedicated commands which abstract many concepts and automatically generate or interpret complex JSON structure that must be specified explicitly when using Invoke-GraphApiRequest
.
Still, the generic capability of Invoke-GraphApiRequest
means that even if AutoGraphPS
does not expose a specific command for some feature of Microsoft Graph, you can still use that feature by doing some research into the REST protocol for the capability and then invoking Invoke-GraphApiRequest
according to the protocol.
Note: The requirements for write operations vary among the different entities exposed by the Graph -- consult the Microsoft Graph documentation for information on creating, updating, and deleting objects in the Graph.
In this example, we create a new contact. This will require we specify data in a structure that can be serialized into JSON format, and fortunately this is fairly simple as PowerShell has easy-to-use support for JSON:
$contactData = @{givenName='Cleopatra Jones';emailAddresses=@(@{name='Work';Address='cleo@soulsonic.org'})}
Invoke-GraphApiRequest me/contacts -Method POST -Body $contactData
This will return the newly created contact object (you can inspect it further by accessing $LASTGRAPHITEMS[0]
).
The contactData
variable was assigned to a structure that would result in the JSON required for the Graph type contact
whose JSON representation can be found in the Graph documentation. The rules for creating such an object are roughly as follows:
- For key-value pairs of a Javascript object, simply use a PowerShell
HashTable
that contains all the keys and values. You can use the@{}
syntax for the PowerShellHashTable
. - If there are values that are also Javascript objects (i.e. they are not strings, numbers, etc.), those themselves can be PowerShell
HashTable
instances with their own keys and values. Thus, you'll likely end up with one or more levels of nestedHashTable
instances - If a value is an array, express the array using PowerShell's
Array
type via the@()
syntax. The elements of the array can be any type as well, includingHashTable
instances that represent Javascript objects, other arrays expressed via@()
syntax, and of course simple types like numbers and strings. - If it isn't clear, the
HashTable
instances can contain arrays.
The ability of PowerShell to express mutual nesting of arrays and HashTable
instances via compact @()
and @{}
syntax makes it fairly intuitive and readable to express any object that can be expressed as JSON.
Simple manual construction of JSON serializable objects is feasible with PowerShell syntax, however the process still requires human understanding of the detailed correspondence between JSON format and PowerShell data types with mistake-free rendering of the object.
Fortunately, AutoGraphPS provides the New-GraphObject
command which correctly renders the object according to the API schema and removes the source of much of the human error. For example, the, following sequence of commands can be used to create a contact just as in the previous contact
example:
$emailAddress = New-GraphObject -TypeClass Complex emailAddress -Property name, address -Value Work, cleo@soulsonic.org
$contactData = New-GraphObject contact -Property givenName, emailAddresses -Value 'Cleopatra Jones', @($emailAddress)
Invoke-GraphApiRequest me/contacts -Method POST -Body $contactData
While this command takes 3 lines instead of 2, its lack of @()
and @{}
syntax makes its intent more plain. The Property
parameter allows you to specify which properties of the object you'd like to include. The optional Value
property lets you specify the value of the property -- each element of the Value
parameter corresponds to the desired value of the property named by an element at the same position in the list specified to Property
. The command will keep you honest by throwing an error if you specify a property that does not exist on the object; this error checking is not available with the shorter 2 line version -- rather than finding out your error sooner with an explicit error message, the failure occurs when making the request to Graph, and the error message may not always be explicit about which property is set incorrectly.
Note that the Value
parameter is not mandatory, and in fact does not require the same cardinality as Property
-- any properties without a corresponding value are simply set to a default value.
One difficulty is that Graph defines to kinds of composite types, the Entity
and Complex
types of OData. To avoid the potentially incorrect asssumption that type names are unique across Entity
and Complex
types, you must specify the TypeClass
parameter with the value Complext
to override the default type class of Entity
that New-GraphObject
uses to build the object.
The PropertyTable
argument combines the approaches above, allowig you to use the HashTable
@{}
syntax to specify each property and value as keys and vlaues in a HashTable
object using the {}
syntax. Because this expresses properties and values in one pair rather than as part of two separate lists which must be carefully arranged to align the right value to the desired property, it is less error-prone. Since the HashTable
may be specified with a multi-line syntax, this can be a very readable way to express the object:
$emailAddress = New-GraphObject -TypeClass Complex emailAddress -PropertyTable @{
name = 'Work'
address = 'cleo@soulsonic.org'
}
$contactData = New-GraphObject contact -PropertyTable @{
givenName = 'Cleopatra Jones'
emailAddresses = @($emailAddress)
}
Invoke-GraphApiRequest me/contacts -Method POST -Body $contactData
This approach, while certainly using more lines than the others, is even more readable and easier to express correctly than the parallel lists.
You can use Get-GraphUriInfo
to get information about whether a given Uri is valid, what entity type it represents, and what Uri segments may follow it. Its functionality is based on data retrieved from the Graph endpoint's $metadata
response.
Here are some examples:
# Get basic type information about the uri '/me/drive/root'
Get-GraphUriInfo /me/drive/root
Info Type Preview Name
---- ---- ------- ----
n > driveItem root
# Use format-list to see all fields
Get-GraphUriInfo /me/drive/root
ParentPath : /me/drive
Info : n >
Relation : Direct
Collection : False
Class : NavigationProperty
Type : driveItem
Name : root
Namespace : microsoft.graph
Uri : https://graph.microsoft.com/v1.0/me/drive/root
GraphUri : /me/drive/root
Path : /v1.0:/me/drive/root
FullTypeName : microsoft.graph.driveItem
Version : v1.0
Endpoint : https://graph.microsoft.com/
IsDynamic : False
Parent :
Details : @{ScriptClass=; isDynamic=False; graphUri=/me/drive/root; type=NavigationProperty; parent=;
isVirtual=False; isInVirtualPath=False; name=root; leadsToVertex=False; graphElement=;
decoration=; PSTypeName=GraphSegment}
Content :
Preview :
PSTypeName : GraphSegmentDisplayType
# View information about the full uri
Get-GraphUriInfo /me/drive/root | select -expandproperty uri
In the above example, Get-GraphUriInfo
parsed the Uri in order to generate the returned information. If you were to give a Uri that is not valid for the current graph, you'd receive an error like the one below:
Get-GraphUriInfo /me/idontexist
Uri '/me/idontexist' not found: no matching child segment 'idontexist' under segment 'me'
At C:\users\myuser\Documents\WindowsPowerShell\modules\autographps\0.14.0\src\metadata\segmentparser.ps1:140 char:21
+ ... throw "Uri '$($Uri.tostring())' not found: no matching ch ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Uri '/me/idonte...er segment 'me':String) [], RuntimeExcept
ion
+ FullyQualifiedErrorId : Uri '/me/idontexist' not found: no matching child segment 'idontexist' under s
egment 'me'
The Get-GraphUriInfo
cmdlet also allows you to determine the set of parent (predecessor) segments of the Uri, as well as all segments immediately following the Uri, that is the children (successors):
# These are all the segments that precede /me/drive/root
Get-GraphUriInfo /me/drive/root -Parents
Info Type Preview Name
---- ---- ------- ----
/ > root /
s > user me
n > drive drive
n > driveItem root
# And these are all the children
Get-GraphUriInfo /me/drive/root -Children
Info Type Preview Name
---- ---- ------- ----
n* > driveItem children
a scalar copy
a scalar createLink
a scalar createUploadSession
f driveItem delta
a scalar invite
n > listItem listItem
n* > permission permissions
f driveItem search
n* > thumbnailSet thumbnails
n* > driveItemVersion versions
n > workbook workbook
The presence of workbook
in the list of children suggests that the following Uri is valid, which indeed it is:
/me/drive/root/workbook
As for what it does, the "Type" column indicates that a GET
for that Uri should return an entity of type workbook
. The "Info" column consists of four symbols with the following meaning
- Column 0: This is the segment class from OData's Entity Data Model (EDM). It can be one of the following:
- 'a' - Action: An action method invoked through a
POST
method that potentially changes the state of the entity - 'e' - EntitySet: A collection of every instance of a particular kind of entity type
- 'f' - Function: A function method that does not alter the entity but does return a value related to it
- 'n' - NavigationProperty: A link from one entity to one or more entities of a particular type
- 's' - Singleton: A single instance of a particular entity type with a unique name across the entire EDM
- 't' - EntityType instance: An instance of an entity type, i.e. actual data returned from Graph that describes users, computers, etc.
- 'a' - Action: An action method invoked through a
- Column 1: The collection column -- it contains
*
if the item is a collection and is empty if not - Column 2: The data column -- it contains a
+
if the item is one or more entities returned from Graph, is empty otherwise - Column 3: The locatable column: this column has a
>
character if it can be followed by an entity and is empty otherwise
Tip: Use the command Get-GraphUriInfo /
to see all of the segments that may legally start a Uri.
Get-GraphUriInfo
doesn't just parse static Uris, but any that are syntactically valid, i.e.
Get-GraphResource /me/drive/root/children/myfile.txt | fl *
returns the following whether or not that Uri (and the OneDrive file this particular path represents) exists in the Graph:
ParentPath : /me/drive/root/children
Info : t >
Relation : Data
Collection : False
Class : EntityType
Type : driveItem
Name : myfile.txt
Namespace : microsoft.graph
Uri : https://graph.microsoft.com/v1.0/me/drive/root/children/myfile.txt
GraphUri : /me/drive/root/children/myfile.txt
Path : /v1.0:/me/drive/root/children/myfile.txt
FullTypeName : microsoft.graph.driveItem
Version : v1.0
Endpoint : https://graph.microsoft.com/
IsDynamic : True
Parent :
Details : @{ScriptClass=; isDynamic=True; graphUri=/me/drive/root/children/myfile.txt; type=EntityType;
parent=; isVirtual=False; isInVirtualPath=False; name=myfile.txt; leadsToVertex=False;
graphElement=; decoration=; PSTypeName=GraphSegment}
Content :
Preview :
PSTypeName : GraphSegmentDisplayType
The purpose of this cmdlet is to let you know what's syntactically valid, not what is actually valid.
Note that it will even "make up" hypothetical Uri's for you when -Children
with the -IncludeVirtualChildren
option:
Get-GraphResourceWithMetadata /me/drive/root/children -children -IncludeVirtualChildren | select uri
Uri
---
https://graph.microsoft.com/v1.0/me/drive/root/children/{driveItem}
The {driveItem}
segment tells you format of a hypothetical segment that could follow children
, as well as the type (driveItem
), allowing tools provide developers hints about possible queries and the data they can return.
When using tools like Postman or Fiddler to troubleshoot or test the Graph, you'll need to acquire a token. Token acquisition continues to be one of the biggest barriers to using Graph, so use AutoGraphPS's Get-GraphToken
cmdlet to automate it:
Get-GraphToken
This cmdlet will retrieve a token for the current Graph. Running the command above will write the token to the display so that it can be cut and pasted into tools like Fiddler and Postman. To avoid displaying it, assign it to a variable or better yet just pipe it to the clipboard using the clip.exe
command built into Windows:
Get-GraphToken | clip
You can then simply paste it into your tool of choice without having to highlight text or click buttons.