Tag Archives: Graph Explorer

Microsoft Teams cmdlets are here!

‘Sup PSHomies,

Microsoft Teams has released the long anticipated Teams module! And with that a great blog to get you started.

Microsoft Teams is Microsoft’s version of Slack (Ok, I oversimplified that… I know). I’ve been following MSTeams development with Graph Explorer for some time now (Something you should definitely look into).

So I followed the blog’s instructions and everything works as expected!

The cmdlets support the pipeline.  (Get-Command -Name <cmdlet>).Parameterset will get you an overview of what’s supported and/or mandatory. Generallyspeaking, GroupId is mandatory and accepted from the pipeline.

TeamChannel supports value from pipeline

Here’s some code to help test drive the cmdlets.

#region Connect
Connect-MicrosoftTeams
#endregion
#region MSTeams cmdlets
#Get all cmdlets
Get-Command -Module *Teams*
#Only interested in Get-*?
Get-Command -Module *Teams* -Name Get*
#Find out what mandatory and/or accepts ValueFrom* for Get-TeamUser
(Get-Command -Name Get-TeamUser).ParameterSets
#endregion
#region Test drive cmdlets
#Get Team Displays all Teams (Ofcourse it does)
Get-Team
#Get Team Channels. GroupId ValueFromPipelineByPropertyName = True
Get-Team | Get-TeamChannel
#Group TeamChannels by Teams
Get-Team |
ForEach-Object{
$result = Get-TeamChannel -GroupId $_.GroupId
[PSCustomObject]@{
Team = $_.DisplayName
TeamChannel = $result
}
} -OutVariable TeamChannels
#Get Team Users. GroupId ValueFromPipelineByPropertyName = True
Get-Team | Get-TeamUser
#Get TeamUsers
Get-Team |
ForEach-Object{
$result = Get-TeamUser -GroupId $_.GroupId
[PSCustomObject]@{
Team = $_.DisplayName
Users = $result
}
} -OutVariable TeamUsers
#Get TeamMemberSettings
Get-Team |
ForEach-Object{
$result = Get-TeamMemberSettings -GroupId $_.GroupId
[PSCustomObject]@{
Team = $_.DisplayName
TeamMemberSettings = $result
}
} -OutVariable TeamMemberSettings
#endregion

So one thing I was hoping for, was to have a cmdlet to post to TeamChannels. For now posting can be done using Graph beta support for teams. Looking forward to having cmdlets for posting as well (fingers crossed!). Before the cmdlets you needed to do some pre-configuration in order to post using Graph, so the cmdlets definitely makes that step easier!

Well that’s it in a nutshell, happy Testing

Hope it’s worth something to you,

Ttyl,

Urv

 

Graph, the endpoint to end all endpoints

‘Sup PSHomies,

My first introduction to Graph was at the Microsoft Technical Summit here in the Netherlands at the RAI march 23,24 this year. It was actually the last session of the day. The intended audience was for developers… I thought to myself, why not? I might pick up a thing or two… It blew my mind!

Then at the PSConfEU at Hannover, Jeffrey Snover’s Keynote ‘State of Union’ really made me reassess my career, so much so that I left my previous employment of 23 years for a much smaller company, Methos! Methos is owned by Jeff Wouters aka “The scripting dutchman”. It’s like Jeffrey Snover said in his keynote: “With transformative change, you need to change the way you think about things.” Graph is one of those transformative thing… Here’s how I got started.

So Jeff came up with an idea:

Jeff : Say Urv, I got something I’d like you to look into…

Me: Sure, what’s up?

Jeff: Would it be possible to get a hierarchy of the entire company from Azure Active Directory?

Me: I don’t see why not?

Jeff: Once you have the data the next step is to visualize it!

Me: Like an organizational chart?

Jeff: Uhuh! (Grinning) Here’s a tip, look into Graph…

I should have known… 🙂 Now at Methos we don’t have an on-premise Active Directory so Azure AD it is. Now as part of my “transformative change” I asked for a Macbook pro. I thought: “Hey if you’re gonna go through the change (wait that doesn’t sound right, you know what I mean) might as well go big or go home! Jeff didn’t disagree, he only grinned and let out a subtle evil laugh… I got a sneaky suspicion that I’m in for a surprise… My other Transformative change: PowerShell Core!

I installed Azure CLI 2.0 as a first attempt. To get Azure AD users:

az ad user list

This gave me a JSON list with few attributes. Maybe I need to add a property list or something. Let do a quick help, Hmmm… Ok… Next approach.

Let’s install AADPreview Core. Say, Get-AzureADUser doesn’t have a -Properties attribute… Huh? So that’s why Jeff was grinning about… Well played Jeff…

So here’s the deal, I’m using PowerShell core, not all modules are applicable. The good thing is that I could login to Graph Explorer.  Graph explorer gives you the opportunity to explore the endpoint and browse around.

“Hey look at that, there’s a get manager query! Maybe there’s a way to get all the data and filter out what I need (Like I always do with PSCustomObject)”

I saw one of the examples use a $select option so I decided to give it a try.

$select=displayName, GivenName, surName, department, officeLocation, jobTitle, userPrincipalName, id, manager

I decided to give it a try. Ok that narrowed things down a bit still no manager in sight! Turns out manager is a special kind of property, a Navigation Property. You can extract it from the MetaData

$graphMetadata = [XML](Invoke-WebRequest -Uri 'https://graph.microsoft.com/v1.0/$metadata').Content
$userMetaData = $graphMetadata.Edmx.DataServices.Schema.EntityType.Where{ $_.Name -eq 'User' }
$userMetaData

Graph-NavigationProperty

Ah, that’s why manager is omitted, it isn’t part of the collection! My next challenge was to retrieve the JSON payload. That’s where I ran into the accessToken dilemma.

 

AccessToken

From the online resources I inspected, authentication is the key to access (see what I did there?). I found Mark Kraus’s module PSMSGraph quite useful to follow his trail of thoughts. It didn’t work for me because I’m using PowerShell core. Now it’s time to read the document! When all else fails RTFM!

I ran into some snags with my application registration, so my next step was to reach out to the Graph team! They are on twitter just no tweets… yet! That got me in contact with Dmitry Pimenov, the PM of Microsoft Graph! I explained him my dilemma and he showed me an easy way to get the accesstoken for proto-type purposes. Finally! I can get some data to play with!

#region Get Access token from Grap Explore Session
$accessToken = #Get the AccessTokenquick & Dirty using developers tool trick by Dan Silver https://twitter.com/dansilver82/status/872520061843415040
#endregion
#region Format request Header
$requestHeader = @{
"Authorization" = "Bearer " + $accessToken #For now get AccessToken from Developers tools console
"Content-Type" = "application/json"
}
#endregion
#region Get Users Tenant properties to query with Graph
$userProperties = @(
'displayName'
'GivenName'
'surName'
'department'
'officeLocation'
'jobTitle'
'userPrincipalName'
'id'
)
$iwrUsersParams = @{
Uri = "https://graph.microsoft.com/v1.0/users?`$select=$($userProperties -join ',')"
Method = 'Get'
Headers = $requestHeader
}
$iwrUsersResults = Invoke-WebRequest @iwrUsersParams
$iwrUsersObjects = $iwrUsersResults.Content | ConvertFrom-Json
$iwrUsersObjects.value
#endregion
#region Get Manager per Object ID
$iwrUsersObjects.value |
ForEach-Object {
try {
$obj = $_
$iwrManagerParams = @{
Uri = 'https://graph.microsoft.com/v1.0/users/{0}/manager' -f $obj.ID
Method = 'Get'
Headers = $requestHeader
}
$userManager = Invoke-WebRequest @iwrManagerParams
$iwrManagerObject = $userManager.Content | ConvertFrom-Json
[PSCustomObject]@{
ObjectID = $obj.Id
UserPrincipalName = $obj.userPrincipalName
DisplayName = $obj.DisplayName
GivenName = $obj.givenName
SurName = $obj.surname
JobTitle = $obj.jobTitle
Department = $obj.department
Manager = $iwrManagerObject.displayName
}
}
Catch {
[PSCustomObject]@{
ObjectID = $obj.Id
UserPrincipalName = $obj.userPrincipalName
DisplayName = $obj.DisplayName
GivenName = $obj.givenName
SurName = $obj.surname
JobTitle = $obj.jobTitle
Department = $obj.department
Manager = $null
}
}
}
#endregion
#region Get Access token from Grap Explore Session
$accessToken = $null
#endregion
#region Format request Header
$requestHeader = @{
"Authorization" = "Bearer " + $Accesstoken #For now get AccessToken from Developers tools console
"Content-Type" = "application/json"
}
#endregion
$iwrUsersParams = @{
Uri = "https://graph.microsoft.com/beta/users?`$expand=Manager"
Method = 'Get'
Headers = $requestHeader
}
$iwmUserResults = Invoke-RestMethod @iwrUsersParams
$iwmUserResults.value |
ForEach-Object {
[PSCustomObject]@{
DisplayName = $_.displayname
GivenName = $_.givenname
SurName = $_.surname
JobTitle = $_.jobtitle
Department = $_.department
Manager = $_.manager.displayname
}
}

My first attempt was straight forward: get the user, get the manger for each user and then create a PSCustomObject. This isn’t optimal ofcourse. So I sent Dmitry a DM asking what is the optimal way of retrieving manager in an ODATA query. That’s when he explained that the Beta version supports the $expand option in the ODATA query.

Quick side step: Microsoft Graph supports ODATA queries, not all queries are supported yet, it’s a work in progress. ODATA is definitely something to look into… Here’s a link to get you started… Transformative change… 😉

Alright, so the /Beta returned  quite a bit more than I bargained for, but at least I didn’t have to do multiple queries. That’s when I decided to trying something new… JMESPath Query!

JMESPath

While using az I noticed a link to JMESpath query, what’s that?  JMESPath is a query language for JSON. With it, you can extract and transform elements from a JSON document… Sweet! Kinda like what we do with PSCustomObject, just on JSON. Here’s where having a Mac wasn’t a liability after all… I even found a vscode extension for jmespath queries! Many ways to Rome… Transformative change… (Jeffrey Snover was right, you need to rethink the way you think about things)

Using this query on the JSON document gave me the following results:

value[].{DisplayName: displayName, GivenName: givenName, SurName: surname, Department: department, JobTitle: jobTitle, Manager:manager.displayName, Location:officeLocation}

JSOn-ManagerResults

Alright! Prototyping mission accomplished! What I thought was straight forward had quite a few curves, but I wouldn’t have it any other way!

Take away:

Learn to love Graph! Be open to learning new and interesting way to accomplish tasks in a new way. Transformative change  won’t be easy, but it’ll be worth it!!!

Hope it’s worth something to you…

Ttyl,

Urv