AlIways HyPe

(a.k.a. Hailey - spoiler

alert: it’s just me guys!)

Latest blog <----

Allways HyPe is in your extended network

TLDR: I love talking nerdy with people! ;)

New Hailey Phillips New Hailey Phillips

Microsoft Graph: a Practical Guide - Part 2

From one-off to repeatable functions

Last time, I showed how to connect to Microsoft Graph with just the Microsoft.Graph.Authentication module and just using Invoke-MgGraphRequest. Using just the one Microsoft Graph SDK module dramatically lessens the Graph module overhead and simplifies authentication - win win!

This time, let’s talk about turning those Graph calls into small, reusable PowerShell fuctions (spoiler, the same ones that I use for my Intune automation projects).

These functions already are available in my public GitHub repo:

I’m not changing any of these scripts, but want to talk about why they are setup the way that they are and how you can build your own.

The Pattern

 

1.Keep auth simple ‧₊˚🖇️✩ ₊˚🎧⊹ ♡


Everything starts with Connect-ToGraph.ps1.

It’s small on purpose. Import the auth module, define the scopes you need (I have it set to .default since I want to use the scopes of the OIDC connection I’m using for my repo), and connect. I like to explicitly set my Graph version to beta, but your milage may vary.

Keeping the the Graph endpoint version the same is helpful in minimizing the “it worked yesterday, now it doesn’t” moments.


2.One function per endpoint ✩°。🎧 ✩°。⋆⸜


Each function does one job.

To save myself the headache, I don’t do anything clever with wrappers and hiding the URL. I want to make sure that it’s easy for me to debug and figure out what I was doing 6 months from now.

  • Policy/deviceManagement/deviceConfigurations

  • Assignments/deviceManagement/deviceConfigurations/{id}/assignments

  • Status/deviceManagement/deviceConfigurations/{id}/deviceStatuses

It’s the same pattern every time. Defined resource path, a $GraphApiVersion variable, and Invoke-MgGraphRequest.

How I find those paths is by using Graph Explorer, confirm that the path it works, and then paste it into PowerShell. I want readers (and future me) to see exactly what’s happening - visible, testable, and repeatable.


3.Return data, not decoration ✩ ♬₊.⋆☾⋆⁺₊✧✩♬

These functions are meant to return objects.

If you want formatting, pipe it!

Get-DeviceConfigurationPolicy | Select displayName, id

This keeps the function reusable. Feed it to reports, filters, GitHub Actions… without editing it.

 

Why this works

It’s lightweight, readable, and consistent.


You see the exact Graph endpoint, and you can test it in the same way Microsoft documents it.
That transparency helps when you’re debugging or teaching others how the Graph API actually behaves.

This approach also scales naturally. Once you understand the pattern, you can build your own functions for compliance policies, remediation scripts, or Intune assignments — same structure, same repeatable logic.

As you can see, relatively straightforward and something that you can build off of without needing to import the many, many, many Microsoft Graph modules.


Common Gotchas

  • Portal vs v1.0: Intune endpoints are a mix between v1.0 and beta. If your results don’t match what you see in the portal, check your API version first and validate with Graph Explorer.

  • Paging: Graph responses with @odata.nextlink need to a loop. Build a one reusable paging helper and move on.

  • Status confusion: Device and user statuses are separate endpoints, similar to policy endpoints. Be clear about which you’re calling.

 

Closing thoughts

I’ve heard so many iterations of Intune can’t be treated like infrastructure-as-code because “we only have one tenant.”

But once you structure your Graph calls similar to this - modular - this is one of the building blocks for version control, CI/CD, and creating your on promotion gates and criteria.

This is the foundation for what became IntuneStack: testing, promotion, and compliance gates built on the same lightweight Graph functions.

┊˚➶ 。˚ ☁

Read More
Hailey Phillips Hailey Phillips

Microsoft Graph: a Practical Guide

Why another Graph post?

If you’ve tried working with Microsoft Graph, I can probably guess that it maybe took a bit of time to appreciate all of its capabilities. I’ve heard MS Graph described as trying to build the car that you need to use to drive to work. For some, that might be up your alley, but for the rest of us, it can be a bit daunting.

Authentication, proper permissions, pagination, incorrect query structure… these are just a few of the examples of the complexities that can come from initially looking at MS Graph. All of that complexity, I’m sure, encouraged you to instead just download the SDK. You can just get up and go, right? You probably wouldn’t be reading this post if that were the case…

 

Power of Reframe

 

Building Blocks instead of Roadblocks

Rather than seeing all of these hurdles as roadblocks, I want to encourage you to consider them instead as building blocks. Instead of just trying to make today’s script work, you’re learning:

  • How APIs behave

  • How authentication works

  • Thinking in data structures, not just outputs

These skills compound. They’re not just about “getting Graph to work.” They’re what make you faster and more confident when you move on to building larger scale automation, working with other APIs, and CI/CD.

 

Building Blocks ‧₊˚🖇️✩ ₊˚🎧⊹ ♡


Rather than just using the Microsoft Graph SDK or moving fully to Invoke-Restmethod, let’s work on the building blocks that give exposure without too much overwhelm. The best part, this is all you’ll need:

Install-Module Microsoft.Graph.Authentication
Connect-MgGraph
Invoke-MgGraphRequest
  • Microsoft.Graph.Authetication PowerShell module that handles the authentication

  • Connect-MgGraph establishes the session

  • Invoke-MgGraphRequest universal request command that hits MSGraph endpoints.

How to Start

How I like to think about writing a script to do anything in Graph is:

  1. What am I trying to do? Am I looking for a device policy, a user, a group? That’s the starting point.

  2. Find the endpoint. I’ll typically start with Graph Explorer or I’ll use Merill’s Graph Xray. If I can see the output I’m expecting in Graph Explorer, I at least know that the data is there.

  3. Bring it into PowerShell. I’ll set a variable with Invoke-MgGraphRequest and store the response.

  4. Do something with the output. Perform whatever task I’m trying to do.

Only once I’ve addressed the above steps do I think about scale. Pagination, batching, etc those are all things that absolutely matter and should be considered, but not as step one.

This approach keeps me moving forward without drowning in complexity.

Example: Grabbing a config profile

Here’s what it looks like end-to-end: from importing the module to running in VS Code.

Import-Module Microsoft.Graph.Authentication

# Connect to Graph
Connect-MgGraph -NoWelcome

# Target the beta endpoint
$graphApiVersion = "beta"
$DCP_resource = "deviceManagement/deviceConfigurations"
$name = "Skip User ESP"

# Build the URI with a filter
$uri = "https://graph.microsoft.com/$graphApiVersion/$($DCP_resource)?`$filter=displayName eq '$name'"

# Run the query
(Invoke-MgGraphRequest -Uri $uri -Method Get -OutputType PSObject).value

As you can see, relatively straightforward and something that you can build off of without needing to import the many, many, many Microsoft Graph SDK modules.

 

Closing thoughts

This was post Block 1: MSGraph authentication to getting output you can use.

In the next post, we’ll talk about how to grow this into reusable functions and why modular patterns matter. That’s also where we’ll start talking about Git and how source control and modularity set you up for larger-scale automation.

┊˚➶ 。˚ ☁

Read More

My IT "Top 8"

My IT "Top 8" •

My IT Toolbox

My current “Top 8” when it comes to IT resources…


…catch ‘em all! ;)

MMS