Tag: json

Querying Microsoft Graph with Powershell, the easy way

Microsoft Graph is a very powerful tool to query organization data, and it’s also really easy to do using Graph explorer but it’s not built for automation.
While the concept I’m presenting in this blogpost isn’t something entirely new, I believe my take on it is more elegant and efficient than what I’ve seen other people use.

So, what am I bringing to the table?

  • Zero dependancies to Azure modules, .net Core & Linux compatibility!
  • Recursive/paging processing of Graph data (without the need for FollowRelLink, currently only available in powershell 6.0)
  • Authenticates using an Azure AD Application/service principal
  • REST compatible (Get/Put/Post/Patch/Delete)
  • Supports json-batch jobs
  • Supports automatic token refresh. Used for extremely long paging jobs
  • Accepts Application ID & Secret as a pscredential object, which allows the use of Credential stores in Azure automation or use of Get-Credential instead of writing credentials in plaintext

Sounds great, but what do I need to do in order to query the Graph API?

First things first, create a Azure AD application, register a service principal and delegate Microsoft Graph/Graph API permissions.
Plenty of people has done this, so I won’t provide an in-depth guide. Instead we’re going to walk through how to use the functions line-by-line.

When we have an Azure AD Application we need to build a credential object using the service principal appid and secret.

Then we aquire a token, here we require a tenantID in order to let Azure know the context of the authorization token request.

Once a token is aquired, we are ready to call the Graph API. So let’s list all users in the organization.

In the response, we see a value property which contains the first 100 users in the organization.
At this point some of you might ask, why only 100? Well that’s the default limit on graph queries, but this can be expanded by using a $top filter on the uri which allows you to query up to 999 users at the same time.

The cool thing with my function is that it detects if your query doesn’t return all the data (has a follow link) and gives a warning in the console.

So, we just add $top=999 and use the recursive parameter to get them all!

What if I want to get $top=1 (wat?) users, but recursive? Surely my token will expire after 15 minutes of querying?

Well, yes. That’s why we can pass a tokenrefresh and credentials right into the function and never worry about tokens expiring!

What if I want to delete a user?

That works as well. Simply change the method (Default = GET) to DELETE and go!

Deleting users is fun and all, but how do we create a user?

Define the user details in the body and use the POST method.

What about json-batching, and why is that important?

Json-batching is basically up to 20 unique queries in a single call. Many organizations have thousands of users, if not hundreds of thousands of users, and that adds up since much of the queries need to be run against individual users. And that takes time. Executing jobs with json-batching that used to take 1 hour now takes about 3 minutes to run. 8 hours long jobs now takes about 24 minutes. If you’re not already sold on json-batching then I have no idea why you’re still reading this post.

This can be used statically by creating a body with embedded queries, or as in the example below, dynamically. We have all users flat in a $users variable. Then we determine how many times we need to run the loop and build a $body json object with 20 requests in a single query, then we run the query using the $batch operation and POST method and put them into a $responses array and tada! We’ve made the querying of Graph 20x more efficient.

Sounds cool, what more can I do?

Almost anything related to the Office 365 suite. Check out the technical resources and documentation for more information. Microsoft is constantly updating and expanding the api functionality. Scroll down for the functions, should work on Powershell 4 and up!

Technical resources:

Creating an Azure AD application
https://www.google.com/search?q=create+azure+ad+application

Graph API
https://docs.microsoft.com/en-gb/graph/use-the-api

About batch requests
https://docs.microsoft.com/en-gb/graph/json-batching

Known issues with Graph API
https://docs.microsoft.com/en-gb/graph/known-issues

Thanks to:
https://blogs.technet.microsoft.com/cloudlojik/2018/06/29/connecting-to-microsoft-graph-with-a-native-app-using-powershell/
https://medium.com/@mauridb/calling-azure-rest-api-via-curl-eb10a06127

Functions



Publicera RDP Proxy-länk via StoreFront

Sedan ett tag tillbaka har NetScaler Gateway inte bara möjlighet att agera ICA Proxy för XenApp och XenDesktop, utan kan även agera RDP Proxy åt Remote Desktop Session Hosts.

För att dra nytta av detta har man antingen behövt publicera länken via Clientless-portalen som finns i NetScaler Gateway alternativt länka till den på något annat sätt. Jag hittade ett enkelt sätt att få in denna länk tillgänglig via StoreFront, så användarna kan starta sitt Remote Desktop via RDP Proxy på samma ställe de har sina publicerade skrivbord och applikationer från XenApp/XenDesktop. Värt att notera är att jag bara fått det att fungera via webläsaren och inte via Citrix Receiver, samt att detta inte är något som är supporterat från Citrix så finns möjlighet att det ställer till problem (men enkelt att inaktivera). Jag har testat det med StoreFront 3.0 och 3.5, men mycket möjligt att det kan behöva göras om för äldre/nyare versioner.

Utan att gå in något djupare på hur allt fungerar så skickar StoreFront en lista till webläsaren med alla tillgängliga applikationer. Det vi gör är att vi skriver om denna lista med hjälp av NetScalerns rewrite-funktion och infogar en ytterligare applikation på ungefär samma sätt som “content” kunde bli publicerat i XenApp 6.5.

Först behöver vi inaktivera encoding så vi kan skriva om innehållet, jag gjorde det på följande sätt och applicerade det till den virtuella servern jag har för lastdelning av StoreFront:

Beskrivning av ovan:

  1. Skapa en rewrite action för att ta bort headern “Accept-Encoding” från requesten som kommer från webläsaren till StoreFront-servern
  2. Skapa en rewrite policy som applicerar vår action när headern X-Citrix-Via är “nsgw.xenit.se” (alltså endast när trafiken kommer via NetScaler Gateway, byt ut nsgw.xenit.se till ditt FQDN), när path är “Citrix/StoreWeb/Resources/List” (byt ut StoreWeb till din StoreFront stores namn) samt när trafiken inte kommer från Citrix Receiver
  3. Bind policyn mot den virtuella servern för StoreFront

Nästa steg, utför själva omskrivningen av svaret från StoreFront till webläsaren:

Beskrivning av ovan:

  1. Skapa en rewrite action som infogar det nya innehållet (i JSON-format) efter “resources”:[. Se till att byta ut FQDN för NetScaler Gateway samt RDPProxy-länken (i mitt fall 10.20.30.40) samt peka om URL till ikonen, samt välj ett namn och ID som passar.
  2. På samma sätt som innan, skapa en rewrite policy
  3. På samma sätt som innan, bind policyn mot den virtuella servern för StoreFront

Detta går att använda för fler typer av länkar, säg siter som är skyddade av AAA eller länk till någon hjälpsida. När jag testade mig fram till detta med hjälp av XenApp 6.5 och publicering av content fanns det en del andra parametrar som publicerades förutom dem jag infogar, men vad jag sett har det fungerat utan – men kan vara så att de behövs vid något speciellt scenario.

Hoppas detta kan vara till hjälp för någon som bygger en Unified Gateway med vill använda StoreFront som den enda portal att komma åt alla resurser. Förhoppningsvis kommer något liknande detta vara inbyggt i framtiden, så vi inte behöver göra det manuellt.