<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Graph API Archives - the Sysadmin Channel</title>
	<atom:link href="https://thesysadminchannel.com/powershell/graph-api/feed/" rel="self" type="application/rss+xml" />
	<link>https://thesysadminchannel.com/powershell/graph-api/</link>
	<description>Documenting My Life as a System Administrator</description>
	<lastBuildDate>Fri, 01 Mar 2024 21:40:09 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
<site xmlns="com-wordpress:feed-additions:1">144174110</site>	<item>
		<title>Get Entra ID PIM Role Assignment Using Graph API</title>
		<link>https://thesysadminchannel.com/get-entra-id-pim-role-assignment-using-graph-api/</link>
					<comments>https://thesysadminchannel.com/get-entra-id-pim-role-assignment-using-graph-api/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Sun, 18 Feb 2024 00:32:39 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[active or eligible azure ad role]]></category>
		<category><![CDATA[azure ad role audit]]></category>
		<category><![CDATA[pim role assignment graph api]]></category>
		<category><![CDATA[Use PowerShell to get Entra ID PIM Role assignment]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=5023</guid>

					<description><![CDATA[<p>In a previous post I wrote a script to be able to get Entra ID Role assignments using the older Azure AD PowerShell module. However, with the addition of Graph API and seeing how that&#8217;s the way of the future,&#8230; <a href="https://thesysadminchannel.com/get-entra-id-pim-role-assignment-using-graph-api/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/get-entra-id-pim-role-assignment-using-graph-api/">Get Entra ID PIM Role Assignment Using Graph API</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In a <a href="https://thesysadminchannel.com/get-pim-role-assignment-status-for-azure-ad-using-powershell/" rel="noopener" target="_blank">previous post</a> I wrote a script to be able to get Entra ID Role assignments using the older Azure AD PowerShell module. However, with the addition of Graph API and seeing how that&#8217;s the way of the future, I wanted to share my updated script to use Graph API instead.  This will still require the Graph API PowerShell module since it uses some PowerShell cmdlets instead of the native REST calls, but it&#8217;s great to use and outputs the information we require.<br />
&nbsp;</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#pimrole">Get Entra ID PIM Role Assignment Using Graph API</a></li>
<ul>
<li><a href="#script">PowerShell Script</a></li>
<li><a href="#parameters">Script Parameters</a></li>
<li><a href="#examples">Examples and Usage</a></li>
</ul>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<p>&nbsp;</p>
<div id="requirements" style="scroll-margin-top: 10px;"></div>
<h2>Requirements</h2>
<p>In this article I am going to be sharing a script to get the Entra ID PIM Role eligibility and active assignments but there are a few things we will need in order to run the script successfully.  Let us list out what&#8217;s needed now.</p>
<ul>
<li><a href="https://www.powershellgallery.com/packages/Microsoft.Graph/" rel="noopener" target="_blank">Graph PowerShell SDK v1.0</a> and beta module</li>
<li>Entra ID P2 License</li>
<li>Graph API Scopes:</li>
<ul>
<li>Directory.Read.All</li>
<p>	       &#8211;OR&#8211;</p>
<li>RoleEligibilitySchedule.Read.Directory</li>
<li>RoleAssignmentSchedule.Read.Directory</li>
<li>RoleManagement.Read.Directory</li>
</ul>
</ul>
<p>&nbsp;</p>
<div id="pimrole" style="scroll-margin-top: 10px;"></div>
<h2>Get Entra ID PIM Role Assignment Using Graph API</h2>
<p>As mentioned above, we will need at least 1 Entra ID P2 license since that is what allows us to use PIM in our tenant.  We should also confirm we have the Graph PowerShell SDK v1.0 and beta modules.<br />
&nbsp;</p>
<p>Finally, I like to use PowerShell 7+ since that is better optimized for PowerShell as opposed to the default Windows PowerShell that comes pre-installed with Windows.  This is not a requirement but more of a personal preference.<br />
&nbsp;</p>
<div id="script" style="scroll-margin-top: 10px;"></div>
<h2>PowerShell Script</h2>
<p>Now let&#8217;s get to the reason why you checked this article.  Below is the PowerShell script to get PIM Role assignment using Graph API.</p>
<pre class="brush: powershell; title: ; notranslate">
Function Get-MgPimRoleAssignment {
&lt;#
.SYNOPSIS
    This will check if a user is added to PIM or standing access.

.LINK
    https://thesysadminchannel.com/get-entra-id-pim-role-assignment-using-graph-api -

.NOTES
    Name: Get-MgPimRoleAssignment
    Author: Paul Contreras
    Version: 2.4
    DateCreated: 2023-Jun-15
#&gt;

    [CmdletBinding()]
    param(
        [Parameter(
            Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'User',
            Position  = 0
        )]
        [Alias('UserPrincipalName')]
        [string[]]  $UserId,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'Role',
            Position  = 1
        )]
        [Alias('DisplayName')]
        [ValidateSet(
            'Application administrator',
            'Application developer',
            'Attack payload author',
            'Attack simulation administrator',
            'Attribute assignment administrator',
            'Attribute assignment reader',
            'Attribute definition administrator',
            'Attribute definition reader',
            'Authentication administrator',
            'Authentication policy administrator',
            'Azure AD joined device local administrator',
            'Azure DevOps administrator',
            'Azure Information Protection administrator',
            'B2C IEF Keyset administrator',
            'B2C IEF Policy administrator',
            'Billing administrator',
            'Cloud App Security Administrator',
            'Cloud application administrator',
            'Cloud device administrator',
            'Compliance administrator',
            'Compliance data administrator',
            'Conditional Access administrator',
            'Customer LockBox access approver',
            'Desktop Analytics administrator',
            'Directory readers',
            'Directory writers',
            'Domain name administrator',
            'Dynamics 365 administrator',
            'Edge administrator',
            'Exchange administrator',
            'Exchange recipient administrator',
            'External ID user flow administrator',
            'External ID user flow attribute administrator',
            'External Identity Provider administrator',
            'Global administrator',
            'Global reader',
            'Groups administrator',
            'Guest inviter',
            'Helpdesk administrator',
            'Hybrid identity administrator',
            'Identity Governance Administrator',
            'Insights administrator',
            'Insights Analyst',
            'Insights business leader',
            'Intune administrator',
            'Kaizala administrator',
            'Knowledge administrator',
            'Knowledge manager',
            'License administrator',
            'Lifecycle Workflows Administrator',
            'Message center privacy reader',
            'Message center reader',
            'Network administrator',
            'Office apps administrator',
            'Password administrator',
            'Permissions Management Administrator',
            'Power BI administrator',
            'Power platform administrator',
            'Printer administrator',
            'Printer technician',
            'Privileged authentication administrator',
            'Privileged role administrator',
            'Reports reader',
            'Search administrator',
            'Search editor',
            'Security administrator',
            'Security operator',
            'Security reader',
            'Service support administrator',
            'SharePoint administrator',
            'Skype for Business administrator',
            'Teams administrator',
            'Teams communications administrator',
            'Teams Communications Support Engineer',
            'Teams Communications Support Specialist',
            'Teams devices administrator',
            'Tenant Creator',
            'Usage summary reports reader',
            'User administrator',
            'Virtual Visits Administrator',
            'Windows 365 Administrator',
            'Windows update deployment administrator',
            'Yammer Administrator'
        )]
        [string]    $RoleName,


        [Parameter(
            Mandatory = $false
        )]
        [ValidateSet(
            'Eligibile',
            'Active'
        )]
        [string]    $PimAssignment,


        [Parameter(
            Mandatory = $false
        )]
        [string]    $TenantId,


        [Parameter(
            Mandatory = $false
        )]
        [switch]    $HideActivatedRoles
    )

    BEGIN {
        $ConnectionGraph = Get-MgContext
        $ConnectionGraph.Scopes = $ConnectionGraph.Scopes -replace &quot;write&quot;,&quot;&quot; | select -Unique
        'RoleEligibilitySchedule.Read.Directory', 'RoleAssignmentSchedule.Read.Directory', 'RoleManagement.Read.Directory' | ForEach-Object {
            if ($ConnectionGraph.Scopes -notcontains $_) {
                Connect-Graph -Scopes RoleEligibilitySchedule.Read.Directory, RoleAssignmentSchedule.Read.Directory, RoleManagement.Read.Directory -ErrorAction Stop
                continue
            }
        }

        if (-not ($PSBoundParameters.ContainsKey('TenantId'))) {
            $TenantId = $ConnectionGraph.TenantId
        }
    }

    PROCESS {
        $RoleDefinitions = Invoke-GraphRequest -Uri 'https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions' | select -ExpandProperty value

        $RoleHash   = @{}
        $RoleDefinitions | select id, displayname | ForEach-Object {$RoleHash.Add($_.DisplayName, $_.Id) | Out-Null}
        $RoleDefinitions | select id, displayname | ForEach-Object {$RoleHash.Add($_.Id, $_.DisplayName) | Out-Null}

        if ($PSBoundParameters.ContainsKey('UserId')) {
            foreach ($User in $UserId) {
                try {
                    [System.Collections.Generic.List[Object]]$RoleMemberList = @()
                    $PropertyList = 'DisplayName', 'UserPrincipalName', 'Id', 'AccountEnabled'
                    $AzUser = Get-MgUser -UserId $User -Property $PropertyList | select $PropertyList

                    if ($PSBoundParameters.ContainsKey('PimAssignment')) { #if active or eligible is selected, no need to get other option
                        if ($PSBoundParameters.ContainsValue('Active')) {
                            $AssignmentList = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter &quot;PrincipalId eq '$($AzUser.id)'&quot; -ExpandProperty Principal,DirectoryScope -All
                            $AssignmentList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Active&quot; -Force -PassThru | Out-Null
                            $AssignmentList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null
                            $AssignmentList | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                        }

                        if ($PSBoundParameters.ContainsValue('Eligibile')) {
                            $EligibleList = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter &quot;PrincipalId eq '$($AzUser.id)'&quot; -ExpandProperty Principal,DirectoryScope -All
                            $EligibleList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Eligibile&quot; -Force -PassThru | Out-Null
                            $EligibleList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null
                            $EligibleList | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                        }
                    } else {
                        $AssignmentList = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter &quot;PrincipalId eq '$($AzUser.id)'&quot; -ExpandProperty Principal,DirectoryScope -All
                        $AssignmentList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Active&quot; -Force -PassThru | Out-Null
                        $AssignmentList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null

                        $EligibleList = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter &quot;PrincipalId eq '$($AzUser.id)'&quot; -ExpandProperty Principal,DirectoryScope -All
                        $EligibleList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Eligibile&quot; -Force -PassThru | Out-Null
                        $EligibleList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null

                        $AssignmentList | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                        $EligibleList   | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                    }

                    if ($RoleMemberList) {
                        $Output = foreach ($RoleMember in $RoleMemberList) {
                            if ($RoleMember.DirectoryScopeId -eq '/') {
                                $DirectoryScope = 'Global'
                            }
                            elseif ($RoleMember.DirectoryScopeId -match 'administrativeUnits') {
                                $DirectoryScope = $RoleMember.DirectoryScope.AdditionalProperties.displayName
                            }
                            else {
                                $DirectoryScope = 'Unknown'
                            }

                            if ($RoleMember.ScheduleInfo.Expiration.Type -eq 'noExpiration') {
                                $DurationInMonths = 'Permanent'
                                $EndDate = 'Permanent'
                            } else {
                                $Days = ($RoleMember.ScheduleInfo.Expiration.EndDateTime) - ($RoleMember.ScheduleInfo.StartDateTime) | select -ExpandProperty TotalDays
                                $DurationInMonths = $Days / 30.4167 -as [int]
                                $EndDate = (Get-Date $RoleMember.ScheduleInfo.Expiration.EndDateTime).ToLocalTime()
                            }

                            if ($RoleMember.AssignmentScope -eq 'Active' -and $RoleMember.AssignmentType -eq 'Activated') {
                                $AssignmentScope = 'PimActivated'
                            } else {
                                $AssignmentScope = $RoleMember.AssignmentScope
                            }

                            if ($RoleMember.ScheduleInfo.StartDateTime -and $RoleMember.CreatedDateTime) {
                                $StartDateTime = (Get-Date $RoleMember.ScheduleInfo.StartDateTime).ToLocalTime()
                            } else {
                                $StartDateTime = (Get-Date 1/1/1999 -Hour 0 -Minute 0 -Millisecond 0)
                            }

                            [PSCustomObject]@{
                                UserPrincipalName   = $AzUser.UserPrincipalName
                                AzureADRole         = $RoleHash[$RoleMember.RoleDefinitionId]
                                PimAssignment       = $AssignmentScope
                                EndDateTime         = $EndDate
                                AccountEnabled      = $AzUser.AccountEnabled
                                DirectoryScope      = $DirectoryScope
                                DurationInMonths    = $DurationInMonths
                                MemberType          = $RoleMember.MemberType
                                AccountType         = $RoleMember.AccountType
                                StartDateTime       = $StartDateTime
                            }
                        }

                        if ($PSBoundParameters.ContainsKey('HideActivatedRoles')) {
                            $Output | Sort-Object PimAssignment, AzureADRole | Where-Object {$_.PimAssignment -ne 'PimActivated'}
                        } else {
                            $Output | Sort-Object PimAssignment, AzureADRole
                        }
                    }

                } catch {
                    Write-Error $_.Exception.Message
                }
            }
        } #end userid parameter set

        if ($PSBoundParameters.ContainsKey('RoleName')) {
            try {
                [System.Collections.Generic.List[Object]]$RoleMemberList = @()

                if ($PSBoundParameters.ContainsKey('PimAssignment')) {
                    if ($PSBoundParameters.ContainsValue('Active')) {
                        $AssignmentList = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter &quot;RoleDefinitionId eq '$($RoleHash[$RoleName])'&quot; -ExpandProperty Principal,DirectoryScope -All
                        $AssignmentList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Active&quot; -Force -PassThru | Out-Null
                        $AssignmentList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null
                        $AssignmentList | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                    }

                    if ($PSBoundParameters.ContainsValue('Eligibile')) {
                        $EligibleList = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter &quot;RoleDefinitionId eq '$($RoleHash[$RoleName])'&quot; -ExpandProperty Principal,DirectoryScope -All
                        $EligibleList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Eligibile&quot; -Force -PassThru | Out-Null
                        $EligibleList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null
                        $EligibleList | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                    }
                  } else {
                    $AssignmentList = Get-MgBetaRoleManagementDirectoryRoleAssignmentSchedule -Filter &quot;RoleDefinitionId eq '$($RoleHash[$RoleName])'&quot; -ExpandProperty Principal,DirectoryScope -All
                    $AssignmentList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Active&quot; -Force -PassThru | Out-Null
                    $AssignmentList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null

                    $EligibleList = Get-MgBetaRoleManagementDirectoryRoleEligibilitySchedule -Filter &quot;RoleDefinitionId eq '$($RoleHash[$RoleName])'&quot; -ExpandProperty Principal,DirectoryScope -All
                    $EligibleList | Add-Member -MemberType NoteProperty -Name AssignmentScope -Value &quot;Eligibile&quot; -Force -PassThru | Out-Null
                    $EligibleList | Add-Member -MemberType ScriptProperty -Name AccountType -Value {$this.Principal.AdditionalProperties.&quot;@odata.type&quot;.split('.')[2] } -Force -PassThru | Out-Null

                    $AssignmentList | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                    $EligibleList   | ForEach-Object {$RoleMemberList.Add($_) | Out-Null}
                }

                if ($RoleMemberList) {
                    $Output = foreach ($RoleMember in $RoleMemberList) {
                        if ($RoleMember.DirectoryScopeId -eq '/') {
                            $DirectoryScope = 'Global'
                        }
                        elseif ($RoleMember.DirectoryScopeId -match 'administrativeUnits') {
                            $DirectoryScope = $RoleMember.DirectoryScope.AdditionalProperties.displayName
                        }
                        else {
                            $DirectoryScope = 'Unknown'
                        }

                        if ($RoleMember.ScheduleInfo.Expiration.Type -eq 'noExpiration') {
                            $DurationInMonths = 'Permanent'
                            $EndDate = 'Permanent'
                        } else {
                            $Days = ($RoleMember.ScheduleInfo.Expiration.EndDateTime) - ($RoleMember.ScheduleInfo.StartDateTime) | select -ExpandProperty TotalDays
                            $DurationInMonths = $Days / 30.4167 -as [int]
                            $EndDate = (Get-Date $RoleMember.ScheduleInfo.Expiration.EndDateTime)#.ToString('yyyy-MM-dd')
                        }

                        if ($RoleMember.AssignmentScope -eq 'Active' -and $RoleMember.AssignmentType -eq 'Activated') {
                            $AssignmentScope = 'PimActivated'
                        } else {
                            $AssignmentScope = $RoleMember.AssignmentScope
                        }

                        if ($RoleMember.ScheduleInfo.StartDateTime -and $RoleMember.CreatedDateTime) {
                            $StartDateTime = (Get-Date $RoleMember.ScheduleInfo.StartDateTime).ToLocalTime()
                        } else {
                            $StartDateTime = (Get-Date 1/1/1999 -Hour 0 -Minute 0 -Millisecond 0)
                        }

                        switch ($RoleMember.AccountType) {

                            'User' {
                                [PSCustomObject]@{
                                    UserPrincipalName   = $RoleMember.Principal.AdditionalProperties.userPrincipalName
                                    AzureADRole         = $RoleHash[$RoleMember.RoleDefinitionId]
                                    PimAssignment       = $AssignmentScope
                                    EndDateTime         = $EndDate
                                    AccountEnabled      = $RoleMember.Principal.AdditionalProperties.accountEnabled
                                    DirectoryScope      = $DirectoryScope
                                    DurationInMonths    = $DurationInMonths
                                    MemberType          = $RoleMember.MemberType
                                    AccountType         = $RoleMember.AccountType
                                    StartDateTime       = $StartDateTime
                                }
                            }

                            'Group' {
                                $GroupMemberList = Get-MgGroupTransitiveMember -GroupId $RoleMember.PrincipalId
                                foreach ($GroupMember in $GroupMemberList) {
                                    [PSCustomObject]@{
                                        UserPrincipalName   = $GroupMember.AdditionalProperties.userPrincipalName
                                        AzureADRole         = $RoleHash[$RoleMember.RoleDefinitionId]
                                        PimAssignment       = $AssignmentScope
                                        EndDateTime         = $EndDate
                                        AccountEnabled      = $GroupMember.AdditionalProperties.accountEnabled
                                        DirectoryScope      = $DirectoryScope
                                        DurationInMonths    = $DurationInMonths
                                        MemberType          = $RoleMember.MemberType
                                        AccountType         = $GroupMember.AdditionalProperties.'@odata.type'.Split('.')[2]
                                        StartDateTime       = $StartDateTime
                                    }
                                }
                            }

                            'servicePrincipal' {
                                [PSCustomObject]@{
                                    UserPrincipalName   = $RoleMember.Principal.additionalproperties.displayName
                                    AzureADRole         = $RoleHash[$RoleMember.RoleDefinitionId]
                                    PimAssignment       = $AssignmentScope
                                    EndDateTime         = $EndDate
                                    AccountEnabled      = $RoleMember.Principal.AdditionalProperties.accountEnabled
                                    DirectoryScope      = $DirectoryScope
                                    DurationInMonths    = $DurationInMonths
                                    MemberType          = $RoleMember.MemberType
                                    AccountType         = $RoleMember.AccountType
                                    StartDateTime       = $StartDateTime
                                }
                            }
                        }
                    }

                    if ($PSBoundParameters.ContainsKey('HideActivatedRoles')) {
                        $Output | Sort-Object PimAssignment, AzureADRole | Where-Object {$_.PimAssignment -ne 'PimActivated'}
                    } else {
                        $Output | Sort-Object PimAssignment, AzureADRole
                    }
                }

            } catch {
                Write-Error $_.Exception.Message
            }
        } #end rolename parameter set
    }

    END {}

}
</pre>
<p>&nbsp;</p>
<div id="parameters" style="scroll-margin-top: 10px;"></div>
<h2>Script Parameters</h2>
<p>When using this script, you can use the following parameters to customize the output. Let&#8217;s go over those now.<br />
&nbsp;</p>
<h3>    -UserId</h3>
<p>DataType: string<br />
Description: Specify the UserId or UserPrincipalName of the principal you want to find active or eligible roles.<br />
&nbsp;</p>
<h3>    -RoleName</h3>
<p>DataType: string<br />
Description: Specify the Entra ID Role name to get all principals that are assigned that role.<br />
&nbsp;</p>
<h3>    -PimAssignment</h3>
<p>DataType: string<br />
Description: Specify either Active or Eligible to display those results..<br />
&nbsp;</p>
<h3>    -TenantId</h3>
<p>DataType: string<br />
Description: Specify the tenant Id to query that specific tenant. You must be authenticated to that tenant.<br />
&nbsp;</p>
<h3>    -HideActivatedRoles</h3>
<p>DataType: switch<br />
Description: When used, the results will hide all PIM activated roles.<br />
&nbsp;</p>
<div id="examples" style="scroll-margin-top: 10px;"></div>
<h3>Example 1: Specifying the UserId parameter</h3>
<pre class="brush: powershell; title: ; notranslate">
Get-MgPimRoleAssignment -UserId homer@thesysadminchannel.com

UserPrincipalName : homer@thesysadminchannel.com
AzureADRole       : Helpdesk Administrator
PimAssignment     : Eligibile
EndDateTime       : Permanent
AccountEnabled    : True
DirectoryScope    : Admin Unit
DurationInMonths  : Permanent
MemberType        : Direct
AccountType       : user
StartDateTime     : 2/19/2024 3:34:32 PM
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-userid-parameter.png"><img fetchpriority="high" decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-userid-parameter.png" alt="Pim Role assignment with userid parameter" width="829" height="309" class="aligncenter size-full wp-image-5032" srcset="https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-userid-parameter.png?v=1708401893 829w, https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-userid-parameter-768x286.png?v=1708401893 768w" sizes="(max-width: 829px) 100vw, 829px" /></a><br />
&nbsp;</p>
<h3>Example 2: Specifying the RoleName parameter that are eligible</h3>
<pre class="brush: powershell; title: ; notranslate">
Get-MgPimRoleAssignment -RoleName 'Helpdesk administrator' -PimAssignment Eligibile

UserPrincipalName : luke@thesysadminchannel.com
AzureADRole       : Helpdesk Administrator
PimAssignment     : Eligibile
EndDateTime       : Permanent
AccountEnabled    : True
DirectoryScope    : Global
DurationInMonths  : Permanent
MemberType        : Direct
AccountType       : user
StartDateTime     : 2/19/2024 3:43:16 PM

UserPrincipalName : homer@thesysadminchannel.com
AzureADRole       : Helpdesk Administrator
PimAssignment     : Eligibile
EndDateTime       : Permanent
AccountEnabled    : True
DirectoryScope    : Admin Unit
DurationInMonths  : Permanent
MemberType        : Direct
AccountType       : user
StartDateTime     : 2/19/2024 3:34:32 PM
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-rolename-parameter.png"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-rolename-parameter.png" alt="Pim Role assignment with rolename parameter" width="991" height="587" class="aligncenter size-full wp-image-5033" srcset="https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-rolename-parameter.png?v=1708402369 991w, https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-rolename-parameter-125x75.png?v=1708402369 125w, https://thesysadminchannel.com/wp-content/uploads/2024/02/Pim-Role-assignment-with-rolename-parameter-768x455.png?v=1708402369 768w" sizes="(max-width: 991px) 100vw, 991px" /></a><br />
&nbsp;</p>
<div id="conclusion" style="scroll-margin-top: 10px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to help you get Entra ID PIM Role Assignment Using Graph API.  With this script, you should be able to get all active, eligible AND eligible assignments that have been activated.<br />
&nbsp;</p>
<p>The post <a href="https://thesysadminchannel.com/get-entra-id-pim-role-assignment-using-graph-api/">Get Entra ID PIM Role Assignment Using Graph API</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/get-entra-id-pim-role-assignment-using-graph-api/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5023</post-id>	</item>
		<item>
		<title>Get Microsoft 365 License Usage Count Using PowerShell</title>
		<link>https://thesysadminchannel.com/get-microsoft-365-license-usage-count-using-powershell/</link>
					<comments>https://thesysadminchannel.com/get-microsoft-365-license-usage-count-using-powershell/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Sat, 11 Nov 2023 02:46:27 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Office365]]></category>
		<category><![CDATA[azure license count]]></category>
		<category><![CDATA[check my Office 365 license count]]></category>
		<category><![CDATA[get license count graph api]]></category>
		<category><![CDATA[Get Microsoft 365 License Usage Count Using PowerShell]]></category>
		<category><![CDATA[get-mguserlicensedetail]]></category>
		<category><![CDATA[How do I see all my Office Licenses]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4920</guid>

					<description><![CDATA[<p>Keeping an eye on the available licenses in your Microsoft tenant is essential to ensuring you and your users have what is needed to keep the business running. Whether you assign licenses directly or you use Group Based Licensing, if&#8230; <a href="https://thesysadminchannel.com/get-microsoft-365-license-usage-count-using-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/get-microsoft-365-license-usage-count-using-powershell/">Get Microsoft 365 License Usage Count Using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Keeping an eye on the available licenses in your Microsoft tenant is essential to ensuring you and your users have what is needed to keep the business running. Whether you assign licenses directly or you use <a href="https://thesysadminchannel.com/assign-group-based-licensing-in-azure-ad/" rel="noopener" target="_blank">Group Based Licensing</a>, if a user needs a specific license, there shouldn&#8217;t be any hiccups when assigning.  Today I am going to share a PowerShell script to get Microsoft 365 license usage count using PowerShell and Graph API.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#powershell">Get Microsoft 365 License Usage Count Using PowerShell</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 10px;"></div>
<h2>Requirements</h2>
<p>In order to query license information for your tenant, you will need the following API Scopes permitted.</p>
<ul>
<li>Microsoft.Graph or Microsoft.Graph.Beta PowerShell modules</li>
<li>Directory.Read.All or Organization.Read.All</li>
</ul>
<p>&nbsp;</p>
<div id="powershell" style="scroll-margin-top: 10px;"></div>
<h2>Get Microsoft 365 License Usage Count Using PowerShell</h2>
<p>Before we get into the PowerShell script, I wanted to point out that the Microsoft API&#8217;s don&#8217;t show the friendly display names for these licenses.  Instead, they use a SkuPartNumber to give you an idea of what the licenses is regarding.  The problem here is that you also won&#8217;t find the SkuPartNumber anywhere in the portal so it&#8217;s kind of a pain to make sure the license you&#8217;re targeting in the API is in fact the license in the Azure portal.<br />
&nbsp;</p>
<p>Luckily, there is a Microsoft Doc that has this information but it&#8217;s not always up to date.  The link to that doc is <a href="https://learn.microsoft.com/en-us/entra/identity/users/licensing-service-plan-reference" rel="noopener" target="_blank">https://learn.microsoft.com/en-us/entra/identity/users/licensing-service-plan-reference</a>.  There&#8217;s about 400+ Sku&#8217;s that are shown so it&#8217;s also nice that they have provided a csv file that we can use PowerShell to be able to pull these names into our Script.  </p>
<pre class="brush: powershell; title: ; notranslate">
$LicenseFile = 'C:\temp\m365license.csv'
$CutoffDate = (Get-Date).AddDays(-7)

if (Test-Path $LicenseFile) {
    $LastWriteTime = Get-ChildItem -Path $LicenseFile | select -ExpandProperty LastWriteTime

    if ($CutoffDate -gt $LastWriteTime) {
        #csv file is older than a week old.  Let us get a newer version
        Invoke-WebRequest -Uri 'https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv' -OutFile C:\temp\m365license.csv
    }
} else {
    #csv file was not found so let us download it now
    Invoke-WebRequest -Uri 'https://download.microsoft.com/download/e/3/e/e3e9faf2-f28b-490a-9ada-c6089a1fc5b0/Product%20names%20and%20service%20plan%20identifiers%20for%20licensing.csv' -OutFile C:\temp\m365license.csv
}

$csvList = Import-Csv C:\temp\m365license.csv
$LicenseHash = @{}

$csvList | ForEach-Object {
    if (-not $LicenseHash[$_.Guid]) {
        $LicenseHash.Add($_.GUID, $_.Product_Display_Name)
    }
}

$LicenseList = Get-MgSubscribedSku

#Uncomment if you only want to display licenses that are maxed out
foreach ($License in $LicenseList) {
    if ($License.PrepaidUnits.Enabled -ge 1) {
        #if ($License.ConsumedUnits -ge $License.PrepaidUnits.Enabled) {
            [PSCustomObject]@{
                LicenseName   = $LicenseHash[$License.SkuId]
                SkuPartNumber = $License.SkuPartNumber
                SkuId         = $License.SkuId
                Remaining     = $License.PrepaidUnits.Enabled - $License.ConsumedUnits
                Enabled       = $License.PrepaidUnits.Enabled
                Used          = $License.ConsumedUnits
            }
        #}
    }
}
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/License-Count-Usage-PowerShell-Graph-API.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/License-Count-Usage-PowerShell-Graph-API.png" alt="Microsoft 365 License Usage Count PowerShell Graph API" width="1019" height="416" class="aligncenter size-full wp-image-4929" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/License-Count-Usage-PowerShell-Graph-API.png?v=1699669161 1019w, https://thesysadminchannel.com/wp-content/uploads/2023/11/License-Count-Usage-PowerShell-Graph-API-768x314.png?v=1699669161 768w" sizes="(max-width: 1019px) 100vw, 1019px" /></a><br />
&nbsp;</p>
<p>As you can see from above, the Identity Governance P2 Step Up license has not been updated in the downloadable csv file so the license name shows up blank.</p>
<div id="conclusion" style="scroll-margin-top: 10px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to help you get Microsoft 365 License usage count using PowerShell and Graph API.  Sometimes we&#8217;re too busy to manually keep an eye on it so having this script along with an email alert would be helpful for preventing your licenses being maxed out.</p>
<p>The post <a href="https://thesysadminchannel.com/get-microsoft-365-license-usage-count-using-powershell/">Get Microsoft 365 License Usage Count Using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/get-microsoft-365-license-usage-count-using-powershell/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4920</post-id>	</item>
		<item>
		<title>Get Application Certificate and Secret Expiration with Graph API</title>
		<link>https://thesysadminchannel.com/get-application-certificate-and-secret-expiration-with-graph-api-powershell/</link>
					<comments>https://thesysadminchannel.com/get-application-certificate-and-secret-expiration-with-graph-api-powershell/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Tue, 17 Jan 2023 01:51:27 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[azure app cert expiration PowerShell]]></category>
		<category><![CDATA[get application cert expiration date graph api]]></category>
		<category><![CDATA[Get Application Certificate and Secret Expiration with Graph API]]></category>
		<category><![CDATA[get secret expiration date powershell]]></category>
		<category><![CDATA[get secrete expiration graph api]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4676</guid>

					<description><![CDATA[<p>In the world of Azure cloud automation we always need to ensure that our accounts are able to properly authenticate. Accounts with username and password might have Active Directory alert you when your password expires, however, what can we use&#8230; <a href="https://thesysadminchannel.com/get-application-certificate-and-secret-expiration-with-graph-api-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/get-application-certificate-and-secret-expiration-with-graph-api-powershell/">Get Application Certificate and Secret Expiration with Graph API</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In the world of Azure cloud automation we always need to ensure that our accounts are able to properly authenticate.  Accounts with username and password might have Active Directory alert you when your password expires, however, what can we use to ensure the secrets or certificates tied to an App registration aren&#8217;t nearing expiration ( or worse, already expired).  Today I am going to share a PowerShell script that shows you how to get application certificate and secret expiration with Graph API.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#azureportal">Check an App Registration for Expired Keys in Azure Portal</a></li>
<li><a href="#powershell">Get Application Certificate and Secret Expiration with Graph API</a></li>
<ul>
<li><a href="#powershellscript">PowerShell Script</a></li>
<li><a href="#scriptparameters">Script Parameters</a></li>
<li><a href="#examples">Examples and Usage</a></li>
</ul>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>In order to run this, there are a few things that need to be in place to ensure we don&#8217;t run into any errors. Let&#8217;s touch on those item now.<br />
&nbsp;</p>
<ul>
<li>Directory.Read.All Permissions</li>
<li>Application.Read.All Permissions</li>
<li>Microsoft.Graph PowerShell SDK Module</li>
</ul>
<div id="azureportal" style="scroll-margin-top: 15px;"></div>
<h2>Check an App Registration for Expired Keys in Azure Portal</h2>
<p>Before we get into the PowerShell script, let&#8217;s take a look at how to check this manually so we know exactly what to expect when looking at the results of the script.<br />
&nbsp;</p>
<p>Within Azure AD:</p>
<ul>
<li>Navigate to <a href="https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps" rel="noopener" target="_blank">App Registrations</a></li>
<li>Select an App that has a certificate or secret added</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Azure-portal-expired-keys.jpg" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/Azure-portal-expired-keys.jpg" alt="Azure portal expired keys" width="1108" height="352" class="aligncenter size-full wp-image-4684" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/Azure-portal-expired-keys.jpg?v=1673896287 1108w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Azure-portal-expired-keys-1024x325.jpg?v=1673896287 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Azure-portal-expired-keys-768x244.jpg?v=1673896287 768w" sizes="(max-width: 1108px) 100vw, 1108px" /></a><br />
&nbsp;</p>
<ul>
<li>Go to Certificates &#038; secrets blade</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificate-Expiration.jpg" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificate-Expiration.jpg" alt="Certificate Expiration" width="1059" height="294" class="aligncenter size-full wp-image-4685" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificate-Expiration.jpg?v=1673896397 1059w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificate-Expiration-1024x284.jpg?v=1673896397 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificate-Expiration-768x213.jpg?v=1673896397 768w" sizes="(max-width: 1059px) 100vw, 1059px" /></a><br />
&nbsp;</p>
<p>Here we can see the status of the certificate for this specific application. Specifically, we&#8217;re interested in the expiration date, certificate thumbprint and Key ID (certificate ID).<br />
&nbsp;</p>
<p>While the portal does give you a visual of when keys are expiring, it still requires you to take time out of your day to manually check.  Let&#8217;s take a look at how we can accomplish the same thing automatically using the PowerShell script I wrote.</p>
<div id="powershell" style="scroll-margin-top: 15px;"></div>
<h2>Get Application Certificate and Secret Expiration with Graph API PowerShell</h2>
<p>Now that we&#8217;ve gone over the manual method, let&#8217;s use PowerShell and Graph API to our advantage and show the same information in an automated fashion.  Since we know how to <a href="https://thesysadminchannel.com/automate-powershell-scripts-with-task-scheduler/" rel="noopener" target="_blank">automate Powershell Scripts With Task Scheduler</a>, we can schedule this on a daily basis and let it alert you without any additional effort on your end.<br />
&nbsp;</p>
<div id="powershellscript" style="scroll-margin-top: 15px;"></div>
<p>Now for the PowerShell script:</p>
<pre class="brush: powershell; title: ; notranslate">
Function Get-MgApplicationCertificateAndSecretExpiration {
&lt;#
.SYNOPSIS
    This will display all Applications that have certificates or secrets expiring within a certain timeframe


.NOTES
    Name: Get-MgApplicationCertificateAndSecretExpiration
    Author: Paul Contreras
    Version: 1.3
    DateCreated: 2022-Feb-8

.LINK
    https://thesysadminchannel.com/get-application-certificate-and-secret-expiration-with-graph-api-powershell -

.EXAMPLE
    Get-MgApplicationCertificateAndSecretExpiration

.EXAMPLE
    Get-MgApplicationCertificateAndSecretExpiration -ShowExpiredKeys
#&gt;

    [CmdletBinding(DefaultParameterSetName='Default')]
    param(
        [Parameter(
            Mandatory = $false,
            ParameterSetName = 'CertOnly'
        )]
        [switch]    $ShowOnlyCertificates,

        [Parameter(
            Mandatory = $false,
            ParameterSetName = 'SecretOnly'
        )]
        [switch]    $ShowOnlySecrets,


        [Parameter(
            Mandatory = $false
        )]
        [switch]    $ShowExpiredKeys,


        [Parameter(
            Mandatory = $false
        )]
        [ValidateRange(1,720)]
        [int]    $DaysWithinExpiration = 30,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [Alias('ApplicationId', 'ClientId')]
        [string]    $AppId
    )

    BEGIN {
        $ConnectionGraph = Get-MgContext
        if (-not $ConnectionGraph) {
            Write-Error &quot;Please connect to Microsoft Graph&quot; -ErrorAction Stop
        }
        #Adding an extra day to account for hour differences and offsets.
        $DaysWithinExpiration++
    }

    PROCESS {
        try {
            if ($PSBoundParameters.ContainsKey('AppId')) {
                $ApplicationList = Get-MgApplication -Filter &quot;AppId eq '$AppId'&quot; -ErrorAction Stop
                $AppFilter = $true
            } else {
                $ApplicationList = Get-MgApplication -All -Property AppId, DisplayName, PasswordCredentials, KeyCredentials, Id -PageSize 999 -ErrorAction Stop
            }

            #If certs are selected, show certs
            if ($PSBoundParameters.ContainsKey('ShowOnlyCertificates') -or

                #If neither Certs or Secrets are selected show both.
               (-not $PSBoundParameters.ContainsKey('ShowOnlyCertificates') -and
                -not $PSBoundParameters.ContainsKey('ShowOnlySecrets'))) {

                    $CertificateApps  = $ApplicationList | Where-Object {$_.keyCredentials}

                    $CertApp = foreach ($App in $CertificateApps) {
                        foreach ($Cert in $App.keyCredentials) {
                            if ( $Cert.endDateTime -le (Get-Date).AddDays($DaysWithinExpiration) -or ($AppFilter) ) {
                                [PSCustomObject]@{
                                    AppDisplayName      = $App.DisplayName
                                    AppId               = $App.AppId
                                    KeyType             = 'Certificate'
                                    ExpirationDate      = $Cert.EndDateTime
                                    DaysUntilExpiration = (($Cert.EndDateTime) - (Get-Date) | select -ExpandProperty TotalDays) -as [int]
                                    ThumbPrint          = [System.Convert]::ToBase64String($Cert.CustomKeyIdentifier)
                                    Id                  = $App.Id
                                    KeyId               = $Cert.KeyId
                                    Description         = $Cert.DisplayName
                                }
                            }
                        }
                    }

                    if ($PSBoundParameters.ContainsKey('ShowExpiredKeys')) {
                        $CertApp | Sort-Object DaysUntilExpiration
                    } else {
                        $CertApp | Sort-Object DaysUntilExpiration | Where-Object {$_.DaysUntilExpiration -ge 0}
                    }
            }

            #If secrets are selected, show secrets
            if ($PSBoundParameters.ContainsKey('ShowOnlySecrets') -or

                #If neither Certs or Secrets are selected show both.
               (-not $PSBoundParameters.ContainsKey('ShowOnlySecrets') -and
                -not $PSBoundParameters.ContainsKey('ShowOnlyCertificates'))) {

                    $ClientSecretApps = $ApplicationList | Where-Object {$_.passwordCredentials}

                    $SecretApp = foreach ($App in $ClientSecretApps){
                        foreach ($Secret in $App.PasswordCredentials) {
                            if ( $Secret.EndDateTime -le (Get-Date).AddDays($DaysWithinExpiration) -or ($AppFilter) ) {
                                [PSCustomObject]@{
                                    AppDisplayName      = $App.DisplayName
                                    AppId               = $App.AppId
                                    KeyType             = 'ClientSecret'
                                    ExpirationDate      = $Secret.EndDateTime
                                    DaysUntilExpiration = (($Secret.EndDateTime) - (Get-Date) | select -ExpandProperty TotalDays) -as [int]
                                    ThumbPrint          = 'N/A'
                                    Id                  = $App.Id
                                    KeyId               = $Secret.KeyId
                                    Description         = $Secret.DisplayName
                                }
                            }
                        }
                    }

                    if ($PSBoundParameters.ContainsKey('ShowExpiredKeys')) {
                        $SecretApp | Sort-Object DaysUntilExpiration
                    } else {
                        $SecretApp | Sort-Object DaysUntilExpiration | Where-Object {$_.DaysUntilExpiration -ge 0}
                    }
            }
        } catch {
            Write-Error $_.Exception.Message
        }
    }

    END {}
}
</pre>
<div id="scriptparameters" style="scroll-margin-top: 15px;"></div>
<h2>Script Parameters</h2>
<h3>    No Parameters</h3>
<p>DataType: N/A<br />
Description: Gather all apps and display the ones that have a secret or certificate expiring within 30 days.<br />
&nbsp;</p>
<h3>    -ShowOnlyCertificates</h3>
<p>DataType: switch<br />
Description: Only display certificates in the output. Expired keys and secrets will not be shown.<br />
&nbsp;</p>
<h3>    -ShowOnlySecrets</h3>
<p>DataType: switch<br />
Description: Only display secrets in the output. Expired keys and certificates will not be shown.<br />
&nbsp;</p>
<h3>    -ShowExpiredKeys</h3>
<p>DataType: switch<br />
Description: Display certificates or secrets are near expiration or have already expired.<br />
&nbsp;</p>
<h3>    -DaysWithinExpiration</h3>
<p>DataType: integer<br />
Description: Set the time frame to include expiring keys. This is defaulted to 30 days.<br />
&nbsp;</p>
<h3>    -AppId</h3>
<p>DataType: string<br />
Description: Specify an AppId (client Id) to see that specific applications keys.<br />
&nbsp;</p>
<div id="examples" style="scroll-margin-top: 15px;"></div>
<h3>Example 1 &#8211; Calling the script with no parameters</h3>
<p>Since this is a function, you&#8217;ll need to dot source it to load it into memory.  Assuming the file is your desktop you can run.</p>
<pre class="brush: powershell; title: ; notranslate">
. $Home\Desktop\Get-MgApplicationCertificateAndSecretExpiration.ps1
Get-MgApplicationCertificateAndSecretExpiration

</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/No-Parameters.jpg" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/No-Parameters.jpg" alt="No Parameters" width="902" height="603" class="aligncenter size-full wp-image-4692" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/No-Parameters.jpg?v=1673900545 902w, https://thesysadminchannel.com/wp-content/uploads/2023/01/No-Parameters-768x513.jpg?v=1673900545 768w" sizes="(max-width: 902px) 100vw, 902px" /></a><br />
&nbsp;</p>
<p>Using the default output, take a look at the KeyType, ExpirationDate, DaysUntilExpiration and ThumbPrint.  Certificates will display a thumbprint while secrets will not.<br />
&nbsp;</p>
<h3>Example 2 &#8211; Display Only Certificates that are expired or nearing expiration</h3>
<pre class="brush: powershell; title: ; notranslate">
Get-MgApplicationCertificateAndSecretExpiration -ShowOnlyCertificates -ShowExpiredKeys `
| Select-Object AppDisplayName, KeyType, ExpirationDate, DaysUntilExpiration, KeyId, ThumbPrint
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificates-and-Expired-Keys.jpg" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificates-and-Expired-Keys.jpg" alt="Certificates and Expired Keys" width="1015" height="466" class="aligncenter size-full wp-image-4694" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificates-and-Expired-Keys.jpg?v=1673901771 1015w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificates-and-Expired-Keys-768x353.jpg?v=1673901771 768w" sizes="(max-width: 1015px) 100vw, 1015px" /></a><br />
&nbsp;</p>
<p>If you recall <a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Certificate-Expiration.webp" rel="noopener" target="_blank">Portal screenshot above</a>, our &#8220;App Automation 1&#8221; application had an expired cert with the thumbprint starting in &#8220;2E8972E&#8221; and the Key ID (certificate ID) started with &#8220;6f395fd4&#8221;.  This is the same information we can pull in PowerShell<br />
&nbsp;</p>
<h3>Example 3 &#8211; Display Only secrets that are expiring within 5 days</h3>
<pre class="brush: powershell; title: ; notranslate">
Get-MgApplicationCertificateAndSecretExpiration -ShowOnlySecrets -DaysWithinExpiration 5
| Select-Object AppDisplayName, KeyType, ExpirationDate, DaysUntilExpiration
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Show-only-Secrets.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/Show-only-Secrets.png" alt="Show only Secrets" width="989" height="271" class="aligncenter size-full wp-image-4696" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/Show-only-Secrets.png?v=1673902300 989w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Show-only-Secrets-768x210.png?v=1673902300 768w" sizes="(max-width: 989px) 100vw, 989px" /></a></p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to show you get an application certificate and secret expiration with Graph API.  This is super useful to keep in your automation toolkit since the Azure world is now moving everything to Microsoft Graph.</p>
<p>The post <a href="https://thesysadminchannel.com/get-application-certificate-and-secret-expiration-with-graph-api-powershell/">Get Application Certificate and Secret Expiration with Graph API</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/get-application-certificate-and-secret-expiration-with-graph-api-powershell/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4676</post-id>	</item>
		<item>
		<title>Install Microsoft Graph Module for Azure Automation using PowerShell</title>
		<link>https://thesysadminchannel.com/install-microsoft-graph-module-for-azure-automation-using-powershell/</link>
					<comments>https://thesysadminchannel.com/install-microsoft-graph-module-for-azure-automation-using-powershell/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Fri, 06 Jan 2023 01:50:41 +0000</pubDate>
				<category><![CDATA[Azure Automation]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Install Graph API module azure automation]]></category>
		<category><![CDATA[Install Microsoft Graph Module for Azure Automation using PowerShell]]></category>
		<category><![CDATA[Microsoft Graph Module for Azure Automation]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4662</guid>

					<description><![CDATA[<p>If you&#8217;re familiar with Azure Automation and Graph API, you may have noticed that it may be a bit cumbersome to install the Microsoft.Graph PowerShell module in an Automation account. Since the Graph API module has over 30 sub modules&#8230; <a href="https://thesysadminchannel.com/install-microsoft-graph-module-for-azure-automation-using-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/install-microsoft-graph-module-for-azure-automation-using-powershell/">Install Microsoft Graph Module for Azure Automation using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>If you&#8217;re familiar with Azure Automation and Graph API, you may have noticed that it may be a bit cumbersome to install the Microsoft.Graph PowerShell module in an Automation account.  Since the Graph API module has over 30 sub modules it&#8217;s a bit of a pain to install the full set manually using the GUI.  Today we&#8217;re going to cover how to <strong>install the Microsoft Graph Module for Azure Automation using PowerShell</strong>.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#installmodule">Install Microsoft Graph Module for Azure Automation using PowerShell</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>Before I get to the script, there are a few things that need to be in place before we&#8217;re able to successfully install the module. Let&#8217;s cover that now:</p>
<ul>
<li>Az PowerShell Module</li>
<li>Permissions to install any module</li>
</ul>
<div id="installmodule" style="scroll-margin-top: 15px;"></div>
<h2>Install Microsoft Graph Module for Azure Automation using PowerShell</h2>
<p>Here is the script I wrote to be able to install and update the Microsoft.Graph module for an Automation account.  You can always manually check for the latest version on the <a href="https://www.powershellgallery.com/packages/Microsoft.Graph/" rel="noopener" target="_blank">PowerShell gallery</a>.</p>
<pre class="brush: powershell; title: ; notranslate">
#Before running the script, be sure you're on the right subscription
Set-AzContext -SubscriptionId $SubscriptionId
$ResourceGroup = 'rg-resourcegroupname'
$AutomationAccount = 'automationaccountname'
[System.Collections.Generic.List[Object]]$InstalledModules = @()

#Get top level graph module
$GraphModule = Find-Module Microsoft.Graph
$DependencyList = $GraphModule | select -ExpandProperty Dependencies | ConvertTo-Json | ConvertFrom-Json
$ModuleVersion = $GraphModule.Version

#Since we know the authentication module is a dependency, let us get that one first
$ModuleName = 'Microsoft.Graph.Authentication'
$ContentLink = &quot;https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion&quot;
New-AzAutomationModule -ResourceGroupName $ResourceGroup -AutomationAccountName $AutomationAccount -Name $ModuleName -ContentLinkUri $ContentLink -ErrorAction Stop | Out-Null
do {
    Start-Sleep 20
    $Status = Get-AzAutomationModule -ResourceGroupName $ResourceGroup -AutomationAccountName $AutomationAccount -Name $ModuleName | select -ExpandProperty ProvisioningState
} until ($Status -in ('Failed','Succeeded'))

if ($Status -eq 'Succeeded') {
    $InstalledModules.Add($ModuleName)

    foreach ($Dependency in $DependencyList) {
        $ModuleName = $Dependency.Name
        if ($ModuleName -notin $InstalledModules) {
            $ContentLink = &quot;https://www.powershellgallery.com/api/v2/package/$ModuleName/$ModuleVersion&quot;
            New-AzAutomationModule -ResourceGroupName $ResourceGroup -AutomationAccountName $AutomationAccount -ContentLinkUri $ContentLink -Name $ModuleName -ErrorAction Stop | Out-Null
            sleep 3
        }
    }

    $LoopIndex = 0
    do {
        foreach ($Dependency in $DependencyList) {
            $ModuleName = $Dependency.Name
            if ($ModuleName -notin $InstalledModules) {
                $Status = Get-AzAutomationModule -ResourceGroupName $ResourceGroup -AutomationAccountName $AutomationAccount -Name $ModuleName -ErrorAction SilentlyContinue | select -ExpandProperty ProvisioningState
                sleep 3
                if ($Status -in ('Failed','Succeeded')) {
                    if ($Status -eq 'Succeeded') {
                        $InstalledModules.Add($ModuleName)
                    }

                    [PSCustomObject]@{
                        Status           = $Status
                        ModuleName       = $ModuleName
                        ModulesInstalled = $InstalledModules.Count
                    }
                }
            }
        }
        $LoopIndex++
    } until (($InstalledModules.Count -ge $GraphModule.Dependencies.count) -or ($LoopIndex -ge 10))
}



</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Authentication-Module.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Authentication-Module.png" alt="Install Authentication Module" width="1200" height="438" class="aligncenter size-full wp-image-4666" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Authentication-Module.png 1200w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Authentication-Module-1024x374.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Authentication-Module-768x280.png 768w" sizes="(max-width: 1200px) 100vw, 1200px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules.png" alt="Microsoft Graph Module for Azure Automation" width="1383" height="675" class="aligncenter size-full wp-image-4668" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules.png 1383w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules-1024x500.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules-768x375.png 768w" sizes="(max-width: 1383px) 100vw, 1383px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules-Start-PowerShell.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules-Start-PowerShell.png" alt="Microsoft Graph Module for Azure Automation" width="1394" height="556" class="aligncenter size-full wp-image-4667" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules-Start-PowerShell.png 1394w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules-Start-PowerShell-1024x408.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/01/Install-Graph-Modules-Start-PowerShell-768x306.png 768w" sizes="(max-width: 1394px) 100vw, 1394px" /></a></p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>And just like that, we were able to install the Microsoft Graph Module for Azure Automation. One thing to note, This method only supports PowerShell version 5.1 at the moment so if you want to install the module for PowerShell 7 and later, you will still need to do that the manual way.<br />
&nbsp;</p>
<p>Since you&#8217;re now using Graph API with Azure Automation, here is a great article to <a href="https://thesysadminchannel.com/graph-api-using-a-managed-identity-in-an-automation-runbook/" rel="noopener" target="_blank">use Managed Identities in your Automation Runbooks</a> so you no longer have to worry about secrets or certificates in your code.</p>
<p>The post <a href="https://thesysadminchannel.com/install-microsoft-graph-module-for-azure-automation-using-powershell/">Install Microsoft Graph Module for Azure Automation using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/install-microsoft-graph-module-for-azure-automation-using-powershell/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4662</post-id>	</item>
		<item>
		<title>Graph API using a Managed Identity in an Automation Runbook</title>
		<link>https://thesysadminchannel.com/graph-api-using-a-managed-identity-in-an-automation-runbook/</link>
					<comments>https://thesysadminchannel.com/graph-api-using-a-managed-identity-in-an-automation-runbook/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Fri, 30 Dec 2022 23:47:54 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Azure Automation]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Connect to Graph API using a Managed Identity in an Automation Runbook]]></category>
		<category><![CDATA[Connect to Graph Automation Runbook]]></category>
		<category><![CDATA[Graph API managed identity]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4632</guid>

					<description><![CDATA[<p>In a previous post, I laid out detailed steps on how to connect to Microsoft Graph API using PowerShell. This is using the PowerShell SDK running on a machine that&#8217;s not in Azure. This method uses a client secret or&#8230; <a href="https://thesysadminchannel.com/graph-api-using-a-managed-identity-in-an-automation-runbook/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/graph-api-using-a-managed-identity-in-an-automation-runbook/">Graph API using a Managed Identity in an Automation Runbook</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In a previous post, I laid out detailed steps on <a href="https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/" rel="noopener" target="_blank">how to connect to Microsoft Graph API using PowerShell</a>.  This is using the PowerShell SDK running on a machine that&#8217;s not in Azure.  This method uses a client secret or certificate along with a App registration.  This is a solid method for this use case, however, managing certificates or especially secrets can be a bit of a pain. With that said, what if we wanted to take it a step further and not use secrets and/or certificates at all?  This article is going to focus on how to connect to Graph API using a Managed Identity in an Automation Runbook.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#managedidentity">What is a Managed Identity?</a></li>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#enableidentity">Enable a Managed Identity for Azure Automation</a></li>
<li><a href="#permissions">Grant Permissions to a Managed Identity</a></li>
<li><a href="#connectgraphapi">Connect to Graph API using a Managed Identity in an Automation Runbook</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="managedidentity" style="scroll-margin-top: 15px;"></div>
<h2>What is a Managed Identity?</h2>
<p>An Azure managed identity is a feature of Azure Active Directory that enables Azure services to authenticate to cloud resources securely. It eliminates the need for you to store and manage the credentials for your applications and services, and helps you to follow the principle of least privilege by providing just-in-time access to resources.<br />
&nbsp;</p>
<p>There are two types of managed identities:</p>
<li><strong>System-assigned managed identities</strong></li>
<ul>
	These identities are created when you enable the managed identity feature for an Azure resource and are tied to the lifecycle of that resource. When the resource is deleted, the managed identity is also deleted.
</ul>
<p>&nbsp;</p>
<li><strong>User-assigned managed identities</strong></li>
<ul>
These identities are created independently of an Azure resource and can be assigned to multiple resources. This allows you to manage the identity in a central location and reuse it across multiple resources.
</ul>
<p>&nbsp;</p>
<p>Using a managed identity can help you secure your application and make it easier to manage the authentication process since you no longer have to manage secrets or credentials in your code. For this article, we&#8217;re going to focus on using a system-assigned managed identity that&#8217;s created in the Azure Automation account.<br />
&nbsp;</p>
<p>Check out the Microsoft docs to learn more about <a href="https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview" rel="noopener" target="_blank">managed identities</a></p>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>In order to use an Azure managed identity, you need to ensure you meet the following requirements.</p>
<ul>
<li>An Azure subscription</li>
<li>A Resource Group with Owner or user access administrator roles</li>
<li>An Azure Automation Account</li>
<li>The managed identity must be in the same region as the Automation Runbook</li>
<ul>
<li>This also applies to other Azure resources as well</li>
</ul>
</ul>
<div id="enableidentity" style="scroll-margin-top: 15px;"></div>
<h2>Enable a Managed Identity for Azure Automation</h2>
<p>Now that we have the requirements in place, let&#8217;s go ahead and start the process to <strong>enable a managed identity for Azure Automation</strong>. We&#8217;re going to assume you have already created an Automation account in your subscription.</p>
<p>Within your automation account:</p>
<ul>
<li>Click on Identity on the left pane</li>
<li>Ensure the System assigned tab is selected</li>
<li>Toggle the status from &#8220;Off&#8221; to &#8220;On&#8221;</li>
<li>Copy the object (principal) Id to a notepad.  We&#8217;ll need it later</li>
<li>Click save</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/Enable-a-managed-identity-for-Azure-Automation.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/Enable-a-managed-identity-for-Azure-Automation.png" alt="Enable a managed identity for Azure Automation" width="1152" height="679" class="aligncenter size-full wp-image-4645" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/Enable-a-managed-identity-for-Azure-Automation.png?v=1672279715 1152w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Enable-a-managed-identity-for-Azure-Automation-1024x604.png?v=1672279715 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Enable-a-managed-identity-for-Azure-Automation-125x75.png?v=1672279715 125w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Enable-a-managed-identity-for-Azure-Automation-768x453.png?v=1672279715 768w" sizes="(max-width: 1152px) 100vw, 1152px" /></a></p>
<div id="permissions" style="scroll-margin-top: 15px;"></div>
<h2>Grant Permissions to a Managed Identity</h2>
<p>When a managed identity is created, it starts off with a clean slate and no permissions.  This means that you will need to grant permissions to the resources that it needs to interact with.<br />
&nbsp;</p>
<p>In our example, we need to grant the managed identity from our Automation account access to read as well as run jobs from the Azure Automation Runbook. We can do this from the &#8220;Azure role assignments&#8221; button on the Identity blade, but I like to use PowerShell because it&#8217;s a lot faster.<br />
&nbsp;</p>
<pre class="brush: powershell; title: ; notranslate">
  $ServicePrincipalId = '900d23ex-xxxx-xxxx-xxxx-xxxxxxxxxxxx' #Copied from the Identity blade above
  $ResourceGroupName = 'rg-azure-automation'
  New-AzRoleAssignment -ObjectId $ServicePrincipalId -ResourceGroupName $ResourceGroupName -RoleDefinitionName Reader
  New-AzRoleAssignment -ObjectId $ServicePrincipalId -ResourceGroupName $ResourceGroupName -RoleDefinitionName 'Automation Job Operator'
  New-AzRoleAssignment -ObjectId $ServicePrincipalId -ResourceGroupName $ResourceGroupName -RoleDefinitionName 'Automation Runbook Operator'
</pre>
<p>&nbsp;</p>
<p>More importantly, we need to know how to grant the managed identity permissions to Graph API (most common) or other app role resources that you may need.  Since Azure Automation Runbooks don&#8217;t require a secret or certificate to connect to Graph API, this is ideal and the most secured way since we&#8217;re letting Azure handle all the authentication process in the cloud.<br />
&nbsp;</p>
<pre class="brush: powershell; title: ; notranslate">
#New Service Principal Permissions using Azure AD module
$ServicePrincipalId = '900d23ex-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$GraphResource = Get-AzureADServicePrincipal -Filter &quot;AppId eq '00000003-0000-0000-c000-000000000000'&quot;
$Permission = $GraphResource.AppRoles | Where-Object {$_.value -eq 'User.Read.All'}
New-AzureADServiceAppRoleAssignment -ObjectId $ServicePrincipalId -PrincipalId $ServicePrincipalId -Id $Permission.Id -ResourceId $GraphResource.ObjectId


#New Service Principal Permissions using Graph API
$ServicePrincipalId = '900d23ex-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$GraphResource = Get-MgServicePrincipal -Filter &quot;AppId eq '00000003-0000-0000-c000-000000000000'&quot;
$Permission = $GraphResource.AppRoles | Where-Object {$_.value -eq 'User.Read.All'}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $ServicePrincipalId -PrincipalId $ServicePrincipalId -AppRoleId $Permission.Id -ResourceId $GraphResource.Id
</pre>
<p>&nbsp;</p>
<p>To view the permissions that are currently granted for a Service Principal, you can go to</p>
<ul>
<li>Azure AD</li>
<li>Enterprise Applications</li>
<li>Application Type == Managed Identity</li>
<li>select the Service Principal</li>
<li>select Permissions on the left scroll panel</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/Graph-API-permissions-for-managed-identity.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/Graph-API-permissions-for-managed-identity.png" alt="Graph API permissions for managed identity" width="1705" height="880" class="aligncenter size-full wp-image-4647" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/Graph-API-permissions-for-managed-identity.png?v=1672282758 1705w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Graph-API-permissions-for-managed-identity-1024x529.png?v=1672282758 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Graph-API-permissions-for-managed-identity-768x396.png?v=1672282758 768w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Graph-API-permissions-for-managed-identity-1536x793.png?v=1672282758 1536w" sizes="(max-width: 1705px) 100vw, 1705px" /></a></p>
<div id="connectgraphapi" style="scroll-margin-top: 15px;"></div>
<h2>Connect to Graph API using a Managed Identity in an Automation Runbook</h2>
<p>Alright folks!  We&#8217;ve added permissions to the managed identity to access resources in our resource group as well as added permissions to access/modify objects in Graph API.  All that&#8217;s left is actually connecting to Graph API.<br />
&nbsp;</p>
<p>To make this happen, we&#8217;ll first need to have the Microsoft.Graph PowerShell module added under the modules for your automation account. If you&#8217;re using a Hybrid worker account and running the script on-premises, you&#8217;ll need to install the module on the on-premises machine that&#8217;s running the script.<br />
&nbsp;</p>
<p>In your Automation Runbook, edit the page and add these few lines.  If you&#8217;re using parameters, be sure to add it after the param block. When you&#8217;re ready to publish, hit the publish button so it saves and publishes the script.</p>
<pre class="brush: powershell; title: ; notranslate">
try {
    #Get the token using a managed identity and connect to graph using that token
    Connect-AzAccount -Identity -ErrorAction Stop | Out-Null
    $AccessToken = Get-AzAccessToken -ResourceTypeName MSGraph -ErrorAction Stop | select -ExpandProperty Token
    Connect-Graph -AccessToken $AccessToken -ErrorAction Stop | Out-Null

    Select-MgProfile -Name Beta
    Get-MgUser -UserId buzz@thesysadminchannel.com | select DisplayName, UserPrincipalName, UserType, AccountEnabled
} catch {
    Write-Error $_.Exception.Message -ErrorAction Stop
}     

</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/Connect-to-Graph-API-using-a-Managed-Identity-in-an-Automation-Runbook-01.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/Connect-to-Graph-API-using-a-Managed-Identity-in-an-Automation-Runbook-01.png" alt="Connect to Graph API using a Managed Identity in an Automation Runbook" width="1145" height="361" class="aligncenter size-full wp-image-4651" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/Connect-to-Graph-API-using-a-Managed-Identity-in-an-Automation-Runbook-01.png?v=1672427916 1145w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Connect-to-Graph-API-using-a-Managed-Identity-in-an-Automation-Runbook-01-1024x323.png?v=1672427916 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Connect-to-Graph-API-using-a-Managed-Identity-in-an-Automation-Runbook-01-768x242.png?v=1672427916 768w" sizes="(max-width: 1145px) 100vw, 1145px" /></a><br />
&nbsp;</p>
<p>We&#8217;ve published the script so let&#8217;s trigger it.  You can trigger this by using the Start button in the Runbook, or trigger it from a Logic App. Either way, once it has completed running, it should display the output in the job details.<br />
&nbsp;</p>
<p>If you don&#8217;t see the output, be sure to check the Errors or Exception tabs to see where it failed.</p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/Automation-Runbook-output.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/Automation-Runbook-output.png" alt="Automation Runbook output" width="861" height="484" class="aligncenter size-full wp-image-4653" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/Automation-Runbook-output.png?v=1672429087 861w, https://thesysadminchannel.com/wp-content/uploads/2022/12/Automation-Runbook-output-768x432.png?v=1672429087 768w" sizes="(max-width: 861px) 100vw, 861px" /></a></p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to help you connect to Graph API using a Managed Identity in an Automation Runbook.  This method works great if you&#8217;re running the Runbook from Azure as well as a Hybrid Worker machine (on-premises machine).</p>
<p>The post <a href="https://thesysadminchannel.com/graph-api-using-a-managed-identity-in-an-automation-runbook/">Graph API using a Managed Identity in an Automation Runbook</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/graph-api-using-a-managed-identity-in-an-automation-runbook/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4632</post-id>	</item>
		<item>
		<title>New-MgGroup: Create A Group in Graph API</title>
		<link>https://thesysadminchannel.com/new-mggroup-create-a-group-in-graph-api/</link>
					<comments>https://thesysadminchannel.com/new-mggroup-create-a-group-in-graph-api/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Mon, 12 Dec 2022 18:08:54 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Create A Group in Graph API]]></category>
		<category><![CDATA[create azure ad group powershell]]></category>
		<category><![CDATA[create group graph api REST API]]></category>
		<category><![CDATA[New-MgGroup]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4518</guid>

					<description><![CDATA[<p>Groups are essential to the management of resources in any platform and it&#8217;s helpful to use them instead of using individual users. Today we&#8217;re going to cover how to create a group in Graph API using the PowerShell SDK for&#8230; <a href="https://thesysadminchannel.com/new-mggroup-create-a-group-in-graph-api/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/new-mggroup-create-a-group-in-graph-api/">New-MgGroup: Create A Group in Graph API</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Groups are essential to the management of resources in any platform and it&#8217;s helpful to use them instead of using individual users.  Today we&#8217;re going to cover <strong>how to create a group in Graph API</strong> using the PowerShell SDK for us IT Pros.  This specifically goes over the usage of <strong>New-MgGroup</strong> and the various ways you can use it.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#creategrouppowershell">Create A Group in Graph API with New-MgGroup</a></li>
<li><a href="#creategroupowner">Create A Security Group with an Owner</a></li>
<li><a href="#creategroupmember">Create A Group with an Owner and Members</a></li>
<li><a href="#createdyanmicgroup">Create A Dynamic Security Group with Membership Rules</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>In order to successfully create groups in Graph API, we&#8217;ll need to ensure we have the right permissions needed.  Let&#8217;s touch a bit on what those might be.</p>
<ul>
<li><strong>User Administrator</strong>, <strong>Groups Administrator</strong> or <strong>Global Administrator</strong> Azure AD Role(s)</li>
<li><strong>Microsoft.Graph</strong> PowerShell SDK Module (if not using the REST API)</li>
<li>Graph API Scopes:</li>
<ul>
<li>Delegated: Group.ReadWrite.All, Directory.ReadWrite.All</li>
<li>Application: Group.Create, Group.ReadWrite.All, Directory.ReadWrite.All</li>
</ul>
</ul>
<div id="creategrouppowershell" style="scroll-margin-top: 15px;"></div>
<h2>Create A Group in Graph API with New-MgGroup</h2>
<p>When creating groups in Azure AD, 99% of the time I create security enabled groups because I use them for providing access to specific resources. When I need to create groups with an email address, I use Distribution Lists (or Mail-enabled Security groups) in Exchange.  Personally, I am not a fan of M365 (unified groups) but that&#8217;s a topic for another day.<br />
&nbsp;</p>
<p>Let&#8217;s dig into the code for creating a security group in Azure AD using Graph API.</p>
<pre class="brush: powershell; title: ; notranslate">
$GroupParam = @{
     DisplayName = &quot;SG-SecurityNoOwnerNoMember&quot;
     GroupTypes = @(
     )
     SecurityEnabled     = $true
     IsAssignableToRole  = $false
     MailEnabled         = $false
     MailNickname        = (New-Guid).Guid.Substring(0,10)
}

New-MgGroup -BodyParameter $GroupParam
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMember-1.jpg" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMember-1.jpg" alt="SG-SecurityNoOwnerNoMember" width="906" height="399" class="aligncenter size-full wp-image-4527" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMember-1.jpg?v=1670439588 906w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMember-1-768x338.jpg?v=1670439588 768w" sizes="(max-width: 906px) 100vw, 906px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMemberProperties.jpg" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMemberProperties.jpg" alt="SG-SecurityNoOwnerNoMemberProperties" width="1025" height="583" class="aligncenter size-full wp-image-4529" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMemberProperties.jpg?v=1670439859 1025w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityNoOwnerNoMemberProperties-768x437.jpg?v=1670439859 768w" sizes="(max-width: 1025px) 100vw, 1025px" /></a></p>
<div id="creategroupowner" style="scroll-margin-top: 15px;"></div>
<h2>Create A Security Group with an Owner</h2>
<p>We got the basics of creating a security group by using the PowerShell SDK and Graph API, but let&#8217;s add on to this by adding an owner to the group.  You can add a Service Principal or a user account as an owner.<br />
&nbsp;</p>
<p>If you want to add a Service Principal, you&#8217;ll need to know the Service Principal Id so we can bind it to the parameters.  If you&#8217;re looking to add a user, you can use the UserPrincipalName, or UserId.  Let&#8217;s do this now.</p>
<pre class="brush: powershell; title: ; notranslate">
$GroupParam = @{
     DisplayName = &quot;SG-SecurityGroupWithOwner&quot;
     GroupTypes = @(
     )
     SecurityEnabled     = $true
     IsAssignableToRole  = $false
     MailEnabled         = $false
     MailNickname        = (New-Guid).Guid.Substring(0,10)
     &quot;Owners@odata.bind&quot; = @(
         &quot;https://graph.microsoft.com/v1.0/me&quot;,
         &quot;https://graph.microsoft.com/v1.0/users/luke@thesysadminchannel.com&quot;,
         &quot;https://graph.microsoft.com/v1.0/users/647e9c5e-xxxx-xxxx-xxxx-xxxxxxxxxxxx&quot;
         &quot;https://graph.microsoft.com/v1.0/servicePrincipals/50ded543-xxxx-xxxx-xxxx-xxxxxxxxxxxx&quot;
     )
}
PS C:\&gt; New-MgGroup -BodyParameter $GroupParam
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwner.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwner.png" alt="SG-SecurityGroupwithOwner" width="947" height="482" class="aligncenter size-full wp-image-4531" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwner.png?v=1670440938 947w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwner-768x391.png?v=1670440938 768w" sizes="(max-width: 947px) 100vw, 947px" /></a></p>
<div id="creategroupmember" style="scroll-margin-top: 15px;"></div>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerProperties.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerProperties.png" alt="SG-SecurityGroupwithOwnerProperties" width="852" height="389" class="aligncenter size-full wp-image-4532" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerProperties.png?v=1670441205 852w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerProperties-768x351.png?v=1670441205 768w" sizes="(max-width: 852px) 100vw, 852px" /></a></p>
<h2>Create A Group with an Owner and Members</h2>
<p>Next up, let&#8217;s create a group with owners and a couple of members.</p>
<pre class="brush: powershell; title: ; notranslate">
$GroupParam = @{
     DisplayName = &quot;SG-SecurityGroupWithOwnerAndMembers&quot;
     GroupTypes = @(
     )
     SecurityEnabled     = $true
     IsAssignableToRole  = $false
     MailEnabled         = $false
     MailNickname        = (New-Guid).Guid.Substring(0,10)
     &quot;Owners@odata.bind&quot; = @(
         &quot;https://graph.microsoft.com/v1.0/me&quot;,
         &quot;https://graph.microsoft.com/v1.0/users/luke@thesysadminchannel.com&quot;
     )
     &quot;Members@odata.bind&quot; = @(
         &quot;https://graph.microsoft.com/v1.0/me&quot;,
         &quot;https://graph.microsoft.com/v1.0/users/buzz@thesysadminchannel.com&quot;
     )
 }
New-MgGroup -BodyParameter $GroupParam
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerAndMembers.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerAndMembers.png" alt="SG-SecurityGroupwithOwnerAndMembers" width="981" height="518" class="aligncenter size-full wp-image-4537" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerAndMembers.png?v=1670442290 981w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerAndMembers-768x406.png?v=1670442290 768w" sizes="(max-width: 981px) 100vw, 981px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerAndMembersProperties.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-SecurityGroupwithOwnerAndMembersProperties.png" alt="SG-SecurityGroupwithOwnerAndMembersProperties" width="820" height="398" class="aligncenter size-full wp-image-4538" /></a></p>
<div id="createdyanmicgroup" style="scroll-margin-top: 15px;"></div>
<h2>Create A Dynamic Security Group with Membership Rules</h2>
<p>Last and certainly not least, let&#8217;s get started with creating dynamic groups to add members with specific criteria.  In my case, I am just going to add a statement where the account is enabled and the UPN is mine.</p>
<pre class="brush: powershell; title: ; notranslate">
$GroupParam = @{
     DisplayName = &quot;SG-DynamicSecurityGroup&quot;
     GroupTypes = @(
         'DynamicMembership'
     )
     SecurityEnabled     = $true
     IsAssignableToRole  = $false
     MailEnabled         = $false
     membershipRuleProcessingState = 'On'
     MembershipRule = '(user.accountEnabled -eq true) and (user.userPrincipalName -eq &quot;paul@thesysadminchannel.com&quot;)'
     MailNickname        = (New-Guid).Guid.Substring(0,10)
     &quot;Owners@odata.bind&quot; = @(
         &quot;https://graph.microsoft.com/v1.0/me&quot;
     )
 }

New-MgGroup -BodyParameter $GroupParam
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroup.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroup.png" alt="SG-DynamicSecurityGroup" width="1099" height="517" class="aligncenter size-full wp-image-4541" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroup.png?v=1670442984 1099w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroup-1024x482.png?v=1670442984 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroup-768x361.png?v=1670442984 768w" sizes="(max-width: 1099px) 100vw, 1099px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroupProperties.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroupProperties.png" alt="SG-DynamicSecurityGroupProperties" width="975" height="556" class="aligncenter size-full wp-image-4542" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroupProperties.png?v=1670443009 975w, https://thesysadminchannel.com/wp-content/uploads/2022/12/SG-DynamicSecurityGroupProperties-768x438.png?v=1670443009 768w" sizes="(max-width: 975px) 100vw, 975px" /></a></p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to show you how to create a group in Graph API using the New-MgGroup cmdlet that comes with the Microsoft.Graph PowerShell SDK.</p>
<p>The post <a href="https://thesysadminchannel.com/new-mggroup-create-a-group-in-graph-api/">New-MgGroup: Create A Group in Graph API</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/new-mggroup-create-a-group-in-graph-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4518</post-id>	</item>
		<item>
		<title>Check If An Email Was Read using Graph API PowerShell SDK</title>
		<link>https://thesysadminchannel.com/how-to-check-if-an-email-was-read-using-graph-api-powershell-sdk/</link>
					<comments>https://thesysadminchannel.com/how-to-check-if-an-email-was-read-using-graph-api-powershell-sdk/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Fri, 22 Jul 2022 23:36:41 +0000</pubDate>
				<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Check If An Email Was Read]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=3378</guid>

					<description><![CDATA[<p>With the growing number of people migrating from the Azure AD module to Microsoft Graph API, it&#8217;s great to see some features finally become available via the command line interface .aka. PowerShell. Today we&#8217;ll cover step by step on how&#8230; <a href="https://thesysadminchannel.com/how-to-check-if-an-email-was-read-using-graph-api-powershell-sdk/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/how-to-check-if-an-email-was-read-using-graph-api-powershell-sdk/">Check If An Email Was Read using Graph API PowerShell SDK</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>With the growing number of people migrating from the Azure AD module to Microsoft Graph API, it&#8217;s great to see some features finally become available via the command line interface .aka. PowerShell.  Today we&#8217;ll cover step by step on how to check if an email was read using Graph API PowerShell SDK.<br />
&nbsp;</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#getreadstatus">How To Check If An Email Was Read using Graph API PowerShell SDK</a></li>
<ul>
<li><a href="#powershellscript">Get-MSGraphMailReadStatus PowerShell Script</a></li>
<li><a href="#parameters">Script Parameters</a></li>
<li><a href="#examples">Examples and Usage</a></li>
</ul>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>The use case may vary, sometimes you might want to check how many people read a recent communication that was sent by the organization.  Other times you may need statistics for general read status.  Whatever the case may be, it can be helpful to get this kind of data.<br />
&nbsp;</p>
<p>In order to set this up and check to see if a specific email was read or not, there are certain requirements that need to be put in place in order to successfully query a mailbox.  Let&#8217;s cover those now.<br />
&nbsp;</p>
<ul>
<li>Microsoft.Graph PowerShell Module</li>
<li>EXACT subject line of the email you&#8217;re searching for</li>
<li>An Azure App Registration setup with following API permissions</li>
<ul>
<li>Directory.Read.All</li>
<li>Mail.ReadBasic.All</li>
</ul>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/07/Mail-Read-Status-Graph-API-Permissions.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/07/Mail-Read-Status-Graph-API-Permissions.png" alt="Mail Read Status Graph API Permissions" width="1028" height="220" class="aligncenter size-full wp-image-4319" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/07/Mail-Read-Status-Graph-API-Permissions.png?v=1658460616 1028w, https://thesysadminchannel.com/wp-content/uploads/2022/07/Mail-Read-Status-Graph-API-Permissions-1024x219.png?v=1658460616 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/07/Mail-Read-Status-Graph-API-Permissions-768x164.png?v=1658460616 768w" sizes="(max-width: 1028px) 100vw, 1028px" /></a><br />
&nbsp;</p>
<div id="blockquote1">
If you have never created an Azure App or need help getting started with Microsoft Graph API, please follow this guide on <a href="https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/" rel="noopener" target="_blank">how to Connect To Microsoft Graph API Using PowerShell</a>.  It will take you from zero knowledge to getting everything up and running in no time.
</div>
<div id="getreadstatus" style="scroll-margin-top: 15px;"></div>
<h2>How To Check If An Email Was Read using Graph API PowerShell SDK</h2>
<p>Now that we have the Azure App Registration and Service Principal created with the above permissions, let&#8217;s look at how we can start getting message read status for our mail items.<br />
&nbsp;</p>
<div id="powershellscript" style="scroll-margin-top: 15px;"></div>
<h2>Get-MSGraphMailReadStatus PowerShell Script</h2>
<p>To give you some insight, this script uses <code>Get-MgUserMessage</code> graph cmdlet under the hood to get the actual message.  There is also a parameter to see which folder the mail item is currently located.  This helps if a user says they&#8217;ve lost an email, when in reality they&#8217;ve accidently dragged it into another folder without realizing it.<br />
&nbsp;</p>
<pre class="brush: powershell; title: ; notranslate">

Function Get-MgMailReadStatus {
&lt;#
.SYNOPSIS
    Get Email read status for users using Graph Api. A session using Connect-Graph must be open as a requirement.

.NOTES
    Name: Get-MgMailReadStatus
    Author: Paul Contreras
    Version: 1.3

.EXAMPLE
    Get-MgMailReadStatus -UserId user1@domain.com, user2@domain.com -Subject 'Exact Subject Line'

.EXAMPLE
    Get-MgMailReadStatus -UserId user1@domain.com -Subject 'Exact Subject Line' -SenderAddress user3@domain.com -StartDate 5/25/2020 -EndDate 10/28/2022 -ShowMailFolder

.PARAMETER UserId
    Checks against this persons mailbox.

.PARAMETER Subject
    Queries the mailbox using the exact text specified

.PARAMETER SenderAddress
    Specify the 'From' Address in your search.  Format should be user@domain.com

.PARAMETER StartDate
    Specify the date when the query should start filtering for.  Format should be MM/DD/YYYY

.PARAMETER EndDate
    Specify the date when the query should end the filter.  Format should be MM/DD/YYYY

.PARAMETER ShowMailFolder
    When this switch is used, it will display what folder the email is currently located in. This makes the overall query slower so use only when needed.

.PARAMETER Top
    Defaulted to 1.  This is the limit of emails per mailbox that you would like to find
#&gt;

    [CmdletBinding()]
    param(
        [Parameter(
            Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Position = 0
        )]
        [Alias('UserPrincipalName')]
        [string[]]  $UserId,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false
        )]
        [string]  $Subject,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false
        )]
        [string]  $SenderAddress,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false
        )]
        [string]  $StartDate,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false
        )]
        [string]  $EndDate,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false
        )]
        [switch]  $ShowMailFolder,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false
        )]
        [int]  $Top = 1,


        [Parameter(
            Mandatory = $false,
            ValueFromPipeline = $false,
            ValueFromPipelineByPropertyName = $false
        )]
        [switch]    $IncludeRepliesandForwards
    )

    BEGIN {
        $ConnectionGraph = Get-MgContext
        if (-not $ConnectionGraph) {
            Write-Error &quot;Please connect to Microsoft Graph&quot; -ErrorAction Stop
        }

        if ($PSBoundParameters.ContainsKey('StartDate') -and -not $PSBoundParameters.ContainsKey('EndDate')) {
            Write-Error &quot;EndDate is required when a StartDate is entered&quot; -ErrorAction Stop
        }


        if ($PSBoundParameters.ContainsKey('EndDate') -and -not $PSBoundParameters.ContainsKey('StartDate')) {
            Write-Error &quot;StartDate is required when an EndDate is entered&quot; -ErrorAction Stop
        }

        if ($PSBoundParameters.ContainsKey('IncludeRepliesandForwards') -and -not $PSBoundParameters.ContainsKey('Subject')) {
            Write-Error &quot;A Subject is required to use IncludeRepliesandForwards&quot; -ErrorAction Stop
        }

        $Date = Get-Date -Format g
    }

    PROCESS {
        foreach ($User in $UserId) {
            try {
                $GraphUser = Get-MgUser -UserId $User -ErrorAction Stop | select Id, DisplayName, UserPrincipalName
                Write-Verbose &quot;Checking Status for $($GraphUser.DisplayName)&quot;

                #Building the filter query
                if ($PSBoundParameters.ContainsKey('Subject')) {
                    if ($Subject -match &quot;'&quot;) {
                        $Subject = $Subject -replace &quot;'&quot;,&quot;''&quot;
                    }

                    if (-not $PSBoundParameters.ContainsKey('IncludeRepliesandForwards')) {
                        $FilterQuery = &quot;Subject eq '$Subject'&quot;
                    }
                }


                if ($PSBoundParameters.ContainsKey('SenderAddress')) {
                    if ($FilterQuery) {
                        $FilterQuery = $FilterQuery + &quot; AND from/emailAddress/address eq '$SenderAddress'&quot;
                    } else {
                        $FilterQuery = &quot;from/emailAddress/address eq '$SenderAddress'&quot;
                    }
                }


                if ($PSBoundParameters.ContainsKey('StartDate') -and $PSBoundParameters.ContainsKey('EndDate')) {
                    $BeginDateFilter = (Get-Date $StartDate).AddDays(-1).ToString('yyyy-MM-dd') #Adding a day to either side to account for UTC time and MS operators.
                    $EndDateFilter = (Get-Date $EndDate).AddDays(1).ToString('yyyy-MM-dd')

                    if ($FilterQuery) {
                        $FilterQuery = $FilterQuery + &quot; AND ReceivedDateTime ge $BeginDateFilter AND ReceivedDateTime le $EndDateFilter&quot;
                    } else {
                        $FilterQuery = &quot;ReceivedDateTime ge $BeginDateFilter AND ReceivedDateTime le $EndDateFilter&quot;
                    }
                }


                if ($FilterQuery) {
                    if ($Top -gt 10) {
                        $Message = Get-MgUserMessage -UserId $User -Filter $FilterQuery -Top $Top -ErrorAction Stop | Sort-Object ReceivedDateTime -Descending
                      } else {
                        $Message = Get-MgUserMessage -UserId $User -Filter $FilterQuery           -ErrorAction Stop | Sort-Object ReceivedDateTime -Descending | select -First $Top
                    }

                    if ($PSBoundParameters.ContainsKey('IncludeRepliesandForwards')) {
                        $Message = $Message | Where-Object {$_.Subject -like &quot;* $Subject&quot;}
                    }
                } else {
                    $Message = Get-MgUserMessage -UserId $User -ErrorAction Stop | Sort-Object ReceivedDateTime -Descending | select -First $Top
                }


                #Building output object
                $Object = [Ordered]@{
                    RunDate            = $Date
                    MailboxDisplayName = $GraphUser.DisplayName
                    Mailbox            = $GraphUser.UserPrincipalName
                    UserId             = $GraphUser.Id
                    SenderAddress      = $null
                    SenderName         = $null
                    RecipientAddress   = $null
                    RecipientName      = $null
                    Subject            = $null
                    IsRead             = $null
                    HasAttachment      = $null
                    ReceivedDate       = $null
                    MessageId          = $null
                }

                if ($PSBoundParameters.ContainsKey('ShowMailFolder')) {
                    $Object.Add( 'MailFolder', $null )
                    $Object.Add( 'PSTypeName', 'GraphMailReadStatus.MailFolder')
                  } else {
                    $Object.Add( 'PSTypeName', 'GraphMailReadStatus')
                }

                if (-not $Message) {
                    Write-Verbose &quot;0 Messages with the subject: '$Subject' were found on Mailbox: '$($GraphUser.DisplayName)'&quot;

                    #Output object
                    [PSCustomObject]$Object

                } else {
                    Write-Verbose &quot;$($Message.Count) Message(s) with the subject: '$Subject' were returned on Mailbox: '$($GraphUser.DisplayName)'&quot;
                    foreach ($MailItem in $Message) {
                        $Object.SenderAddress      = $MailItem.sender.emailaddress | select -ExpandProperty Address
                        $Object.SenderName         = $MailItem.sender.emailaddress | select -ExpandProperty Name
                        $Object.RecipientAddress   = $MailItem.toRecipients.emailaddress | select -ExpandProperty Address
                        $Object.RecipientName      = $MailItem.toRecipients.emailaddress | select -ExpandProperty Name
                        $Object.Subject            = $MailItem.Subject
                        $Object.IsRead             = $MailItem.IsRead
                        $Object.HasAttachment      = $MailItem.HasAttachments
                        $Object.ReceivedDate       = $MailItem.ReceivedDateTime.ToLocalTime()
                        $Object.MessageId          = $MailItem.Id

                        if ($PSBoundParameters.ContainsKey('ShowMailFolder')) {
                            $MailFolder = Get-MgUserMailFolder -MailFolderId $MailItem.ParentFolderId -UserId $GraphUser.UserPrincipalName | select -ExpandProperty DisplayName

                            $Object.MailFolder = $MailFolder
                            $Object.PSTypeName = 'GraphMailReadStatus.MailFolder'

                          } else {
                            $Object.PSTypeName = 'GraphMailReadStatus'

                        }

                        [PSCustomObject]$Object

                        $Message    = $null
                        $MailItem   = $null
                        $MailFolder = $null
                    }
                }

            } catch {
                Write-Error $_.Exception.Message

            }

            #end foreach block
            $Object = $null
        }
    }

    END {}
}

</pre>
<div id="parameters" style="scroll-margin-top: 15px;"></div>
<h2>Script Parameters</h2>
<h3>    -UserId</h3>
<p>DataType: string/array<br />
Description: Checks against this persons mailbox.  Multiple UPNs/ObjectIds separated by a comma are acceptable.<br />
&nbsp;</p>
<h3>    -Subject</h3>
<p>DataType: string<br />
Description: Queries the mailbox using the EXACT text specified<br />
&nbsp;</p>
<h3>    -SenderAddress</h3>
<p>DataType: string<br />
Description: Specify the &#8216;From&#8217; Address in your search.  Format should be user@domain.com<br />
&nbsp;</p>
<h3>    -StartDate</h3>
<p>DataType: string<br />
Description: Specify the date when the query should start filtering for.  Format should be MM/DD/YYYY<br />
&nbsp;</p>
<h3>    -EndDate</h3>
<p>DataType: string<br />
Description: Specify the date when the query should end the filter.  Format should be MM/DD/YYYY<br />
&nbsp;</p>
<h3>    -ShowMailFolder</h3>
<p>DataType: switch<br />
Description: When this switch is used, it will display what folder the email is currently located in. This makes the overall query slower so use only when needed<br />
&nbsp;</p>
<h3>    -Top</h3>
<p>DataType: int<br />
Description: Defaulted to 1.  This is the limit of emails per mailbox that you would like to find<br />
&nbsp;</p>
<div id="examples" style="scroll-margin-top: 15px;"></div>
<h3>Example 1 &#8211; Specifying a user, a subject and the parent folder</h3>
<pre class="brush: powershell; gutter: false; title: ; notranslate">
PS C:\&gt; Get-MSGraphMailReadStatus -UserId paul@thesysadminchannel.com `
-Subject &quot;You’ve renewed your Office 365 E1 subscription&quot; -ShowMailFolder
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/07/Get-Mail-Read-Status-Example-1.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/07/Get-Mail-Read-Status-Example-1.png" alt="Get Mail Read Status Example 1" width="845" height="398" class="aligncenter size-full wp-image-4329" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/07/Get-Mail-Read-Status-Example-1.png?v=1658465834 845w, https://thesysadminchannel.com/wp-content/uploads/2022/07/Get-Mail-Read-Status-Example-1-768x362.png?v=1658465834 768w" sizes="(max-width: 845px) 100vw, 845px" /></a></p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to show you how to check if an email was read using Graph API PowerShell.  Since this utilizes Graph API, it supports PowerShell 7 and can be incredible fast when using Foreach-Object -Parallel.  I&#8217;ve used this several times in my environment and its great addition to my tool belt.</p>
<p>The post <a href="https://thesysadminchannel.com/how-to-check-if-an-email-was-read-using-graph-api-powershell-sdk/">Check If An Email Was Read using Graph API PowerShell SDK</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/how-to-check-if-an-email-was-read-using-graph-api-powershell-sdk/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3378</post-id>	</item>
		<item>
		<title>Reprocess User License Assignments using Graph API and PowerShell</title>
		<link>https://thesysadminchannel.com/reprocess-user-license-assignments-using-graph-api-and-powershell/</link>
					<comments>https://thesysadminchannel.com/reprocess-user-license-assignments-using-graph-api-and-powershell/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Thu, 24 Mar 2022 01:03:45 +0000</pubDate>
				<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Invoke-MgLicenseUser]]></category>
		<category><![CDATA[Reprocess User License Assignments]]></category>
		<category><![CDATA[reprocessLicenseAssignment]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=3812</guid>

					<description><![CDATA[<p>If you&#8217;ve followed along and are receptive to Microsoft best practices, you should be aware that using group based licensing in Azure AD is the go-to method for assigning licenses to your users in the cloud. I must say, group-based&#8230; <a href="https://thesysadminchannel.com/reprocess-user-license-assignments-using-graph-api-and-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/reprocess-user-license-assignments-using-graph-api-and-powershell/">Reprocess User License Assignments using Graph API and PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>If you&#8217;ve followed along and are receptive to Microsoft best practices, you should be aware that using <a href="https://thesysadminchannel.com/assign-group-based-licensing-in-azure-ad/" rel="noopener" target="_blank">group based licensing in Azure AD</a> is the go-to method for assigning licenses to your users in the cloud.  I must say, group-based licensing is definitely much easier to manage but it does have some draw backs.  I listed those in the article above, but today we&#8217;ll focus on learning how to reprocess user license assignments using Graph API and Powershell should an issue arise with conflicting licenses.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#reprocessgroup">Reprocess Users at the Group Level</a></li>
<li><a href="#reprocessuser">Reprocess User License Assignments using Graph API and PowerShell</a></li>
<ul>
<li><a href="#powershellsdk">Use the Microsoft.Graph Powershell SDK module</a></li>
<li><a href="#restapi">Use the REST API directly</a></li>
</ul>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>Since this will utilize Graph API to drive these requests, you&#8217;ll need the following rights on the Service Principal or account that&#8217;s making the modification.</p>
<ul>
<li>User.ReadWrite.All and Directory.ReadWrite.All Permissions</li>
<li>Azure AD P1/P2 is needed for Group Based Licensing</li>
</ul>
<p>&nbsp;</p>
<div id="blockquote1">
If you want to get started on learning how to use Microsoft Graph API, be sure to check out <a href="https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/" rel="noopener" target="_blank">How To Connect To Microsoft Graph API Using PowerShell</a>.</p>
<p>This should get you up and running with zero previous working knowledge.
</p></div>
<div id="reprocessgroup" style="scroll-margin-top: 15px;"></div>
<h2>Reprocess Users at the Group Level</h2>
<p>Before we get started, I should preface this by saying that I am well aware that there is a way to reprocess the licenses at the group level.  However,  if you work in a large organization with tens of thousands of users in a group, this may take more time than what&#8217;s needed.<br />
&nbsp;</p>
<p>Also, in the event that you only need to reprocess a handful of users instead of the masses that are in the group, this would tend to make more sense.</p>
<div id="attachment_3975" style="width: 973px" class="wp-caption aligncenter"><a href="https://thesysadminchannel.com/wp-content/uploads/2022/03/Reprocess-user-license.png" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3975" src="https://thesysadminchannel.com/wp-content/uploads/2022/03/Reprocess-user-license.png" alt="Reprocess License by Group" width="963" height="427" class="size-full wp-image-3975" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/03/Reprocess-user-license.png?v=1648003395 963w, https://thesysadminchannel.com/wp-content/uploads/2022/03/Reprocess-user-license-768x341.png?v=1648003395 768w" sizes="(max-width: 963px) 100vw, 963px" /></a><p id="caption-attachment-3975" class="wp-caption-text">Reprocessing done at the group level</p></div>
<p>&nbsp;</p>
<div id="reprocessuser" style="scroll-margin-top: 15px;"></div>
<h2>Reprocess User License Assignments using Graph API and PowerShell</h2>
<p>Now that we know how to connect to Graph API and opted to reprocess at the user level instead of the group level, let&#8217;s learn how to use Powershell so you can programmatically reprocess licenses on the user level.<br />
&nbsp;</p>
<p>This can be done using the Microsoft.Graph Powershell SDK module or calling the REST API directly. </p>
<div id="powershellsdk" style="scroll-margin-top: 15px;"></div>
<h3>Use the Microsoft.Graph Powershell SDK module</h3>
<p>When using the Microsoft.Graph Powershell SDK you only need to use a single cmdlet.</p>
<pre class="brush: powershell; title: ; notranslate">
Import-Module Microsoft.Graph.Users.Actions

Invoke-MgLicenseUser -UserId $userId
</pre>
<div id="restapi" style="scroll-margin-top: 15px;"></div>
<h3>Use the REST API directly</h3>
<p>If you want to call the REST API directly, you can simply do this.</p>
<pre class="brush: powershell; title: ; notranslate">
Invoke-MgGraphRequest -Uri &quot;https://graph.microsoft.com/v1.0/users/$userid/reprocessLicenseAssignment&quot; -Method POST -ContentType application/json -Body &quot;$null&quot;
</pre>
<p>&nbsp;</p>
<p>Since I&#8217;m a Powershell enthusiast and I love making scripts, I also wrote a wrapper before I knew the SDK command was available.  So, in the spirit of sharing, I&#8217;ll post that code here.</p>
<pre class="brush: powershell; title: ; notranslate">
Function Invoke-MsGraphReprocessLicenseAssignment {
&lt;#
.SYNOPSIS
    Reprocess a user's license assignment using Graph Api


.NOTES
    Name: Invoke-MsGraphReprocessLicenseAssignment
    Author: Paul Contreras
    Version: 1.0
    DateCreated: 2021-Jan-20


.EXAMPLE
    Invoke-MsGraphReprocessLicenseAssignment -UserId username@domain.com

.LINK
    https://thesysadminchannel.com/reprocess-user-license-assignments-using-graph-api-and-powershell/ -

#&gt;

    [CmdletBinding(
        SupportsShouldProcess,
        ConfirmImpact='Medium'
    )]
    param(
        [Parameter(
            Mandatory = $true,
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true
        )]
        [Alias('UserPrincipalName')]
        [string[]]  $UserId
    )

    BEGIN {}

    PROCESS {
        foreach ($User in $UserId) {
            try {
                $GraphUser = Get-MgUser -UserId $User | select -ExpandProperty Id

                if ($PSCmdlet.ShouldProcess(&quot;Reprocessing license assignments for: $User&quot;) ) {
                    $Reprocess = Invoke-MgGraphRequest -Uri &quot;https://graph.microsoft.com/v1.0/users/$GraphUser/reprocessLicenseAssignment&quot; -Method POST -ContentType application/json -Body &quot;$null&quot; -ErrorAction Stop

                    [PSCustomObject]@{
                        Id                = $Reprocess['id']
                        DisplayName       = $Reprocess['displayName']
                        UserPrincipalName = $Reprocess['userPrincipalName']
                        JobTitle          = $Reprocess['jobTitle']
                    }
                }

            } catch {
                Write-Error $_.Exception.Message

            }
        }
    }

    END {}
}
</pre>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to clearly show you how to reprocess user license assignments using Graph API and PowerShell.  It&#8217;s been a great help to be able to reprocess users on a individual level without having to shake the bucket for thousands of users when it&#8217;s not needed.</p>
<p>The post <a href="https://thesysadminchannel.com/reprocess-user-license-assignments-using-graph-api-and-powershell/">Reprocess User License Assignments using Graph API and PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/reprocess-user-license-assignments-using-graph-api-and-powershell/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3812</post-id>	</item>
		<item>
		<title>Get MFA Methods using MSGraph API and PowerShell SDK</title>
		<link>https://thesysadminchannel.com/get-mfa-methods-using-msgraph-api-and-powershell-sdk/</link>
					<comments>https://thesysadminchannel.com/get-mfa-methods-using-msgraph-api-and-powershell-sdk/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Tue, 15 Feb 2022 07:37:12 +0000</pubDate>
				<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[get mfa method graph api]]></category>
		<category><![CDATA[Get MFA Methods using MSGraph API]]></category>
		<category><![CDATA[Get-MgUserAuthenticationMethod example]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=3806</guid>

					<description><![CDATA[<p>With the recent announcement of the Azure AD API deprecation, I&#8217;ve made an effort to try and migrate all of my scripts to use Microsoft Graph API. Microsoft Graph API is the latest standard for managing everything Microsoft 365 and&#8230; <a href="https://thesysadminchannel.com/get-mfa-methods-using-msgraph-api-and-powershell-sdk/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/get-mfa-methods-using-msgraph-api-and-powershell-sdk/">Get MFA Methods using MSGraph API and PowerShell SDK</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>With the recent announcement of the Azure AD API deprecation, I&#8217;ve made an effort to try and migrate all of my scripts to use Microsoft Graph API.  Microsoft Graph API is the latest standard for managing everything Microsoft 365 and it is continuing to be developed for the foreseeable future. In this article, I&#8217;m going to share the script to <strong>Get MFA Methods using MSGraph API and PowerShell SDK</strong>.</p>
<p>Previously, I had to get this information using the old MSOnline (MSOL) module, however, since that is also deprecated, I thought it would be a good opportunity to freshen up my MSGraph skills and get this going.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#parameters">Script Parameters</a></li>
<li><a href="#powershellscript">Get MFA Methods using MSGraph API</a></li>
<li><a href="#examples">Script Examples</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>In order for this to work, there are a couple of requirements that need to be put in place prior to running the script.  While it is not a technical requirement, it would be ideal to have a basic understanding of Microsoft Graph API application and delegated permissions, scopes, apps, consent and maybe a sprinkle of Service Principals.<br />
&nbsp;</p>
<div id="blockquote1">
If you want to get started on learning how to use Microsoft Graph API, be sure to check out <a href="https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/" rel="noopener" target="_blank">How To Connect To Microsoft Graph API Using PowerShell</a>.</p>
<p>This will cover everything you need to know and get you up and running in no time.
</p></div>
<p>Now for the actual technical requirements:</p>
<ul>
<li>An App/Service Principal to connect to Graph API -or granted consent to connect to Graph API as yourself</li>
<li>Microsoft.Graph PowerShell Module</li>
<li>Graph API Scopes (Delegated or Application permissions)</li>
<ul>
<li>UserAuthenticationMethod.Read.All</li>
<li>Directory.Read.All</li>
<li>User.Read.All</li>
</ul>
</ul>
<div id="parameters" style="scroll-margin-top: 15px;"></div>
<h2>Script Parameters</h2>
<h4>
<ul> UserId</ul>
</h4>
<p>Specify the UserPrincipalName or Id for the user you want to check authentication methods for.  </p>
<h4>
<ul> MethodType</ul>
</h4>
<p>Specify the method type you would like to filter for.  </p>
<div id="powershellscript" style="scroll-margin-top: 15px;"></div>
<h2>Get MFA Methods using MSGraph API</h2>
<p>Now let&#8217;s get to the PowerShell script. As mentioned, this is a function that will gather all of the authentication methods a user has registered for their account.  All Auth methods except for &#8220;Password Authentication&#8221; are strong authentication methods.  Another note, this uses <strong>Get-MgUserAuthenticationMethod</strong> under the hood and formats everything in a way that&#8217;s human readable.</p>
<pre class="brush: powershell; title: ; notranslate">
Function Get-MsGraphAuthenticationMethod {
&lt;#
.SYNOPSIS
    List MFA Authentication Methods for users using Graph API. A session using Connect-Graph must be open as a requirement.


.NOTES
    Name: Get-MsGraphAuthenticationMethod
    Author: paul@thesysadminchannel.com
    Version: 1.1
    DateCreated: 2021-Jan-20


.EXAMPLE
    Get-MsGraphAuthenticationMethod -UserId user1@domain.com, user2@domain.com


.EXAMPLE
    Get-MsGraphAuthenticationMethod -UserId user1@domain.com, user2@domain.com -MethodType MicrosoftAuthenticatorApp, EmailAuthencation

.LINK
    https://thesysadminchannel.com/get-mfa-methods-using-msgraph-api-and-powershell-sdk/ -
#&gt;

    [CmdletBinding()]
    param(
        [Parameter(
            Mandatory = $true,
            Position = 0
            )]
        [Alias('UserPrincipalName')]
        [string[]]  $UserId,


        [Parameter(
            Mandatory = $false
        )]
        [ValidateSet('AuthenticatorApp', 'PhoneAuthentication', 'Fido2', 'WindowsHelloForBusiness', 'EmailAuthentication', 'TemporaryAccessPass', 'Passwordless', 'SoftwareOath')]
        [string[]]   $MethodType
    )

    BEGIN {
        $ConnectionGraph = Get-MgContext
        if (-not $ConnectionGraph) {
            Write-Error &quot;Please connect to Microsoft Graph&quot; -ErrorAction Stop
        }

    }

    PROCESS {
        foreach ($User in $UserId) {
            try {
                $DeviceList = Get-MgUserAuthenticationMethod -UserId $User -ErrorAction Stop
                $DeviceOutput = foreach ($Device in $DeviceList) {

                    #Converting long method to short-hand human readable method type.
                    switch ($Device.AdditionalProperties[&quot;@odata.type&quot;]) {
                        '#microsoft.graph.microsoftAuthenticatorAuthenticationMethod'  {
                            $MethodAuthType     = 'AuthenticatorApp'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;displayName&quot;]
                        }

                        '#microsoft.graph.phoneAuthenticationMethod'                   {
                            $MethodAuthType     = 'PhoneAuthentication'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;phoneType&quot;, &quot;phoneNumber&quot;] -join ' '
                        }

                        '#microsoft.graph.passwordAuthenticationMethod'                {
                            $MethodAuthType     = 'PasswordAuthentication'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;displayName&quot;]
                        }

                        '#microsoft.graph.fido2AuthenticationMethod'                   {
                            $MethodAuthType     = 'Fido2'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;model&quot;]
                        }

                        '#microsoft.graph.windowsHelloForBusinessAuthenticationMethod' {
                            $MethodAuthType     = 'WindowsHelloForBusiness'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;displayName&quot;]
                        }

                        '#microsoft.graph.emailAuthenticationMethod'                   {
                            $MethodAuthType     = 'EmailAuthentication'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;emailAddress&quot;]
                        }

                        '#microsoft.graph.temporaryAccessPassAuthenticationMethod'        {
                            $MethodAuthType     = 'TemporaryAccessPass'
                            $AdditionalProperties = 'TapLifetime:' + $Device.AdditionalProperties[&quot;lifetimeInMinutes&quot;] + 'm - Status:' + $Device.AdditionalProperties[&quot;methodUsabilityReason&quot;]
                        }

                        '#microsoft.graph.passwordlessMicrosoftAuthenticatorAuthenticationMethod' {
                            $MethodAuthType     = 'Passwordless'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;displayName&quot;]
                        }

                        '#microsoft.graph.softwareOathAuthenticationMethod' {
                            $MethodAuthType     = 'SoftwareOath'
                            $AdditionalProperties = $Device.AdditionalProperties[&quot;displayName&quot;]
                        }
                    }

                    [PSCustomObject]@{
                        UserPrincipalName      = $User
                        AuthenticationMethodId = $Device.Id
                        MethodType             = $MethodAuthType
                        AdditionalProperties   = $AdditionalProperties
                    }
                }

                if ($PSBoundParameters.ContainsKey('MethodType')) {
                    $DeviceOutput | Where-Object {$_.MethodType -in $MethodType}
                  } else {
                    $DeviceOutput
                }

            } catch {
                Write-Error $_.Exception.Message

            } finally {
                $DeviceList           = $null
                $MethodAuthType       = $null
                $AdditionalProperties = $null

            }
        }
    }

    END {}

}
</pre>
<div id="examples" style="scroll-margin-top: 15px;"></div>
<h2>Script Examples</h2>
<p>Get-MsGraphAuthenticationMethod -UserId pcontreras@thesysadminchannel.com, buzz@thesysadminchannel.com</p>
<p><div id="attachment_3827" style="width: 1110px" class="wp-caption aligncenter"><a href="https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-1.png" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3827" src="https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-1.png" alt="Get MFA Methods using MSGraph API and PowerShell SDK" width="1100" height="367" class="size-full wp-image-3827" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-1.png?v=1644899115 1100w, https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-1-1024x342.png?v=1644899115 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-1-768x256.png?v=1644899115 768w" sizes="(max-width: 1100px) 100vw, 1100px" /></a><p id="caption-attachment-3827" class="wp-caption-text">Display all authentication methods for both Paul and Buzz</p></div><br />
&nbsp;</p>
<p>Get-MsGraphAuthenticationMethod -UserId pcontreras@thesysadminchannel.com, buzz@thesysadminchannel.com -MethodType AuthenticatorApp, TemporaryAccessPass<br />
<div id="attachment_3828" style="width: 1051px" class="wp-caption aligncenter"><a href="https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-2.png" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3828" src="https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-2.png" alt="Get MFA Methods using MSGraph API and PowerShell SDK" width="1041" height="306" class="size-full wp-image-3828" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-2.png?v=1644899389 1041w, https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-2-1024x301.png?v=1644899389 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/02/Get-MFA-Methods-using-MSGraph-API-and-PowerShell-SDK-2-768x226.png?v=1644899389 768w" sizes="(max-width: 1041px) 100vw, 1041px" /></a><p id="caption-attachment-3828" class="wp-caption-text">Display only AuthenticatorApp and Temporary Access Pass method types</p></div></p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this script to Get MFA Methods using MSGraph API and PowerShell SDK would be useful to replace the legacy method of querying MSOnline to get the user&#8217;s strong auth methods.  Since this utilizes Microsoft Graph and REST APIs in the backend, it can work extremely fast with PowerShell 7 and Foreach-Object -Parallel.<br />
&nbsp;</p>
<p>I use this on a regular basis to see if a user has MFA enabled on their account.  The only downside so far is that it does not show the default method type, but I&#8217;m sure that&#8217;s somewhere down the pipeline.<br />
&nbsp;</p>
<p>If you liked this script and wanted to get more exposure to Graph API, I&#8217;ve just recently created the subreddit <a href="https://reddit.com/r/graphapi" rel="noopener" target="_blank">https://reddit.com/r/graphapi</a> for folks to who want to learn and ask questions.  I&#8217;m also going to be posting all my conversion scripts from the Azure AD module to GraphAPI so be sure check in time to time on our <a href="https://thesysadminchannel.com/powershell/graph-api/" rel="noopener" target="_blank">Graph API category posts</a></p>
<p>The post <a href="https://thesysadminchannel.com/get-mfa-methods-using-msgraph-api-and-powershell-sdk/">Get MFA Methods using MSGraph API and PowerShell SDK</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/get-mfa-methods-using-msgraph-api-and-powershell-sdk/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3806</post-id>	</item>
		<item>
		<title>How To Connect To Microsoft Graph API Using PowerShell</title>
		<link>https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/</link>
					<comments>https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Sat, 22 Jan 2022 01:28:11 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Graph API]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Configure API Permissions For The Application]]></category>
		<category><![CDATA[Configure Application Permissions To Use For Unattended Automation]]></category>
		<category><![CDATA[Configure Delegated Permissions To Use For Interactive Sessions]]></category>
		<category><![CDATA[Configure The App To Use Certificate Based Authentication]]></category>
		<category><![CDATA[Configure The App To Use Client Secret Based Authentication]]></category>
		<category><![CDATA[Connect to Microsoft Graph API Using Interactive Logon]]></category>
		<category><![CDATA[Connect To Microsoft Graph API Using PowerShell]]></category>
		<category><![CDATA[Connect Using A Service Principal and Certificate Based Authentication]]></category>
		<category><![CDATA[Connect Using A Service Principal Secret Based Authentication]]></category>
		<category><![CDATA[Creating an App Registration and Service Principal]]></category>
		<category><![CDATA[Download Microsoft.Graph Powershell Module]]></category>
		<category><![CDATA[How To Get The Scope of a Cmdlet]]></category>
		<category><![CDATA[How To Get The Scopes From The Current Session]]></category>
		<category><![CDATA[Import Self Signed Certificate to Azure AD]]></category>
		<category><![CDATA[Overview of Microsoft Graph API Scopes]]></category>
		<category><![CDATA[Powershell Graph API Examples]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=2553</guid>

					<description><![CDATA[<p>Microsoft has confirmed on multiple occasions that the Azure AD Graph Endpoint is deprecated and will be fully decommissioned in the future. This means that if you&#8217;re currently using the AzureAD (or AzureADPreview) Module(s) then after it&#8217;s deprecated, your scripts&#8230; <a href="https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/">How To Connect To Microsoft Graph API Using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Microsoft has confirmed on multiple occasions that the Azure AD Graph Endpoint is deprecated and will be fully decommissioned in the future. This means that if you&#8217;re currently using the AzureAD (or AzureADPreview) Module(s) then after it&#8217;s deprecated, your scripts will no longer work.  In order to avoid any issues, we&#8217;re going to go step by step as well as the multiple ways for <strong>how to connect to Microsoft Graph API using Powershell</strong>.</p>
<p>If you&#8217;re interested in learning more about the decommission of Azure AD Graph, here&#8217;s a doc from <a href="https://docs.microsoft.com/en-us/graph/migrate-azure-ad-graph-overview" rel="noopener" target="_blank">Microsoft</a>.  Below is snippet from that article.</p>
<div id="blockquote1">
Azure Active Directory (Azure AD) Graph is deprecated. Going forward, we will make no further investment in Azure AD Graph, and Azure AD Graph APIs have no SLA or maintenance commitment beyond security-related fixes. Investments in new features and functionalities will only be made in Microsoft Graph.</p>
<p>June 30, 2023 will mark the end of the three-year deprecation period for Azure AD Graph. Before June 30, 2023, existing applications using Azure AD Graph will not be impacted. After June 30, 2023, Azure AD Graph will enter its retirement phase where we will retire it in incremental steps to allow you sufficient time to migrate your applications to Microsoft Graph APIs
</p></div>
<div id="ConnectToGraph" style="scroll-margin-top: 15px;"></div>
<h2>How To Connect To Microsoft Graph API Using PowerShell</h2>
<p>This is going to be a pretty in-depth article on how to connect to Microsoft Graph API using PowerShell so hopefully it will give you a pretty good understanding of all the parts and pieces at play.</p>
<p>Feel free to use the table of contents to navigate through the individual topics.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#DownloadModule">Download Microsoft.Graph Powershell Module</a></li>
<li><a href="#Scopes">Overview of Microsoft Graph API Scopes</a></li>
<ul>
<li><a href="#CmdletScopes">How To Get The Scope of a Cmdlet</a></li>
<li><a href="#CurrentScopes">How To Get The Scopes From The Current Session</a></li>
</ul>
<li><a href="#InteractiveLogon">Connect to Microsoft Graph API Using Interactive Logon</a></li>
<li><a href="#ServicePrincipal">Creating an App Registration and Service Principal</a></li>
<ul>
<li><a href="#CertificateAuthentication">Configure The App To Use Certificate Based Authentication</a></li>
<ul>
<li><a href="#ImportSelfSignedCert">Import Self Signed Certificate to Azure AD</a></li>
</ul>
<li><a href="#SecretAuthentication">Configure The App To Use Client Secret Based Authentication</a></li>
<li><a href="#APIPermissions">Configure API Permissions For The Application</a></li>
<ul>
<li><a href="#ApplicationPermissions">Configure Application Permissions To Use For Unattended Automation</a></li>
<li><a href="#DelegatedPermissions">Configure Delegated Permissions To Use For Interactive Sessions</a></li>
</ul>
<li><a href="#ServicePrincipalCertificateAuthentication">Connect Using A Service Principal and Certificate Based Authentication</a></li>
<li><a href="#ServicePrincipalSecretAuthentication">Connect Using A Service Principal and Secret Based Authentication</a></li>
</ul>
<li><a href="#GraphProfile">Set Microsoft Graph Profile to use v1.0 or Beta Versions</a></li>
<li><a href="#MgContext">How To Get Your Current Permission Scope</a></li>
<li><a href="#Examples">Powershell Graph API Examples</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ul>
</div>
<div id="DownloadModule" style="scroll-margin-top: 15px;"></div>
<h2>Download Microsoft.Graph Powershell Module</h2>
<p>In order to get started with Using Microsoft Graph API in your Powershell session, the first thing we want to do is install the <strong>Microsoft.Graph</strong> Module.  This is more commonly known as the Microsoft Graph Powershell SDK and all the cmdlets in this module start with &#8220;Mg&#8221;.  Another thing that I absolutely love about this module is that it works great with Powershell 7.</p>
<p>In this article I&#8217;m going to use PS7 but if you&#8217;re using PS5.1, everything is pretty much the same.</p>
<pre class="brush: powershell; title: ; notranslate">
Install-Module Microsoft.Graph -Scope AllUsers -Force
Install-Module Microsoft.Graph.Beta -Scope AllUsers -Force
</pre>
<p><div id="attachment_3720" style="width: 859px" class="wp-caption aligncenter"><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Install-Microsoft-Graph-Api.png" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3720" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Install-Microsoft-Graph-Api.png" alt="Install Microsoft Graph API" width="849" height="329" class="size-full wp-image-3720" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Install-Microsoft-Graph-Api.png?v=1642476411 849w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Install-Microsoft-Graph-Api-768x298.png?v=1642476411 768w" sizes="(max-width: 849px) 100vw, 849px" /></a><p id="caption-attachment-3720" class="wp-caption-text">Note: -Scope AllUsers requires admin rights whereas -Scope CurrentUser does not.</p></div><br />
&nbsp;</p>
<div id="Scopes" style="scroll-margin-top: 15px;"></div>
<h2>Overview of Microsoft Graph API Scopes</h2>
<p>One very important topic to understand when dipping your toes into using Microsoft Graph API are Scopes. Understanding Scopes will definitely ease the transition and flatten the learning curve. I&#8217;m not going to lie when I first started using it, I ran into many challenges. Especially with documentation! Since this is still relatively new there&#8217;s not a ton of articles or examples at the ready.<br />
&nbsp;</p>
<p>As with anything, the more you practice and learn, the easier it becomes. With that said, Microsoft Graph API as a whole encompasses all of the APIs that are available in your tenant.  However under the hood, there&#8217;s an API for users, authentication methods, MS Teams, Azure Key Vault and many more but for simplicity sake it&#8217;s all referred to as Graph API.<br />
&nbsp;</p>
<p>Just because your account has permissions to a certain role, doesn&#8217;t mean it&#8217;s automatically granted that scope.  Here&#8217;s a real world example for you.<br />
&nbsp;</p>
<p>Buzz Lightyear has the &#8216;User Administrator&#8217; Azure AD Role which allows him to manage all aspects of users and groups, including resetting passwords for limited admins. However, if he only connects using the User.Read.All scope then it will not allow him to modify any properties on the account even though the underlying permissions are there.<br />
&nbsp;</p>
<p>A simple way to put it.  Scopes are permissions for the session, whereas roles are permissions for the account.  Hopefully that makes sense.</p>
<div id="CmdletScopes" style="scroll-margin-top: 15px;"></div>
<h3>How To Get The Scope of a Cmdlet</h3>
<p>It&#8217;s a good idea to only use the scopes that are applicable to the current session to ensure you&#8217;re not over-privileged at run-time.  But how exactly do we know what scopes are needed for the cmdlets we want to use?<br />
&nbsp;</p>
<p>To answer this question, I always turn to <a href="https://developer.microsoft.com/en-us/graph/graph-explorer" rel="noopener" target="_blank">Graph Explorer</a>.  It&#8217;s by far easier for me to quickly check here than read through the documentation.  if you prefer the documentation, by all means go ahead but this has typically worked well for me.</p>
<p>Let&#8217;s take a look at Graph Explorer to give a better example of what I&#8217;m talking about.<br />
<div id="attachment_3725" style="width: 1779px" class="wp-caption aligncenter"><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Consent-Graph-Api1.png" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3725" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Consent-Graph-Api1.png" alt="Grant Consent Graph Api" width="1769" height="813" class="size-full wp-image-3725" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Consent-Graph-Api1.png?v=1642480678 1769w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Consent-Graph-Api1-1024x471.png?v=1642480678 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Consent-Graph-Api1-768x353.png?v=1642480678 768w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Consent-Graph-Api1-1536x706.png?v=1642480678 1536w" sizes="(max-width: 1769px) 100vw, 1769px" /></a><p id="caption-attachment-3725" class="wp-caption-text">Note: I am signed in as myself to allow queries from Graph Explorer to be ran under my tenant and my actual data.  If you&#8217;re not signed in, sample data can be used.</p></div><br />
&nbsp;</p>
<p>In the screenshot above, I ran a sample query to list all of the items in my OneDrive.  We can also see on the upper right pane under <strong>Permissions</strong> what scopes are needed.  In this case, I should be good to go with &#8216;Files.Read.All&#8217; if I plan on using it for reading files outside my own account.<br />
&nbsp;</p>
<p>However, one important thing to take note on is the Status column.  All permissions require consent in order to run.  An administrator can grant consent on behalf of the entire organization if needed, or grant consent to the individual identity.  Once consent is granted, you will not need to reconsent on any future sessions since it stays tied to the identity. A lot of layers and restrictions are put in place so I see it as a security win!</p>
<div id="CurrentScopes" style="scroll-margin-top: 15px;"></div>
<h3>How To Get The Scopes From The Current Session</h3>
<p>Last but not least, if you&#8217;re connected and you want a reminder of what Scopes you&#8217;re currently using, you can always use the <code>Get-MgContext</code> cmdlet to display an output.<br />
<div id="attachment_3734" style="width: 1009px" class="wp-caption aligncenter"><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Get-MgContext-Example1.png" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3734" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Get-MgContext-Example1.png" alt="Get-MgContext Example" width="999" height="372" class="size-full wp-image-3734" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Get-MgContext-Example1.png?v=1642532977 999w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Get-MgContext-Example1-768x286.png?v=1642532977 768w" sizes="(max-width: 999px) 100vw, 999px" /></a><p id="caption-attachment-3734" class="wp-caption-text">I am signed in under delegated permissions using Interactive Logon.</p></div></p>
<div id="InteractiveLogon" style="scroll-margin-top: 15px;"></div>
<h2>Connect to Microsoft Graph API Using Interactive Logon</h2>
<p>The quickest and easiest way to connect to Microsoft Graph API using PowerShell is to use delegated permissions with interactive sign-in.  The screenshot above shows the aftermath, however, let&#8217;s look at how we can get there.</p>
<ul>
<li>Open Powershell where the module was downloaded</li>
<li>Type <strong>Connect-Graph</strong></li>
<li>Enter in the credentials in the browser that pops up</li>
<li>You should see <strong>authentication complete</strong></li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-Graph-API-using-Delegated-Authentication.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-Graph-API-using-Delegated-Authentication.png" alt="Connect Graph API using Delegated Authentication" width="978" height="572" class="aligncenter size-full wp-image-3733" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-Graph-API-using-Delegated-Authentication.png?v=1642532767 978w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-Graph-API-using-Delegated-Authentication-768x449.png?v=1642532767 768w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-Graph-API-using-Delegated-Authentication-300x175.png?v=1642532767 300w" sizes="(max-width: 978px) 100vw, 978px" /></a><br />
&nbsp;<br />
Something to note here is that simply calling Connect-Graph (Connect-MgGraph) is using the DEFAULT Graph PowerShell Application.  Some folks aren&#8217;t comfortable with using that because it has all of the delegated permissions added, however, there is a way to use your own app for a specific purpose.  This is useful so we&#8217;re not over-permissioning users.  The way to do that is to use the AppId (ClientId) and omit the key credentials (certificate or secret)</p>
<pre class="brush: powershell; title: ; notranslate">
Connect-Graph -AppId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -TenantId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
</pre>
<p>&nbsp;</p>
<p>There are some pros and cons with using interactive logon. The biggest drawback in my opinion is that this is in no way usable for automation, albeit, it&#8217;s also not intended for automation purposes.<br />
&nbsp;<br />
If you&#8217;re looking to setup an account for automated use, creating an App Registration and Service Principal is definitely the route to go.  Let&#8217;s continue along and go through the motions on how to set that up.</p>
<div id="ServicePrincipal" style="scroll-margin-top: 15px;"></div>
<h2>Creating an App Registration and Service Principal</h2>
<p>As mentioned, using an App Registration along with a Service Principal is definitely the way to go when you want to use it for automation.  This has really become my go-to because its quick, easy and removes a lot of the guess work.  It&#8217;s also great for security but we&#8217;ll touch on that a little later.<br />
&nbsp;</p>
<div id="blockquote2">
By default, when you create an application, a Service Principal is automatically created on your behalf and is named similarly to your application. The Service Principal however, is the identity that&#8217;s created for use with the application and it can be found under the <a href="https://portal.azure.com/#blade/Microsoft_AAD_IAM/StartboardApplicationsMenuBlade/AppAppsPreview/menuId/" rel="noopener" target="_blank">Enterprise Applications</a> blade in your tenant.</p>
<p>In short, <strong>the Service Principal is what&#8217;s actually logging into Azure and the application is setting the API permissions</strong> that it&#8217;s bound to.
</div>
<p>&nbsp;</p>
<p>That was kind of a lot to take in, so for now, let&#8217;s go through the steps to create an App Registration.</p>
<ul>
<li>In your Azure AD Tenant, navigate to <strong>AzureAD </strong>-> <strong>App registrations</strong></li>
<ul>
<li>Direct Link: <a href="https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps" rel="noopener" target="_blank">https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps</a></li>
</ul>
<li>Click on <strong>New registration</strong></li>
<li>Enter in the preferred <strong>name</strong>.  I&#8217;ll name mine &#8216;<strong>My Automation App</strong>&#8216;</li>
<li>Under supported account types: Choose <strong>Single tenant</strong></li>
<li>Under Redirect URI: choose web and set the URL address to http://localhost</li>
<li>Click Register</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Register-an-app-Microsoft-Graph-API.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Register-an-app-Microsoft-Graph-API.png" alt="Register an app Microsoft Graph API" width="1140" height="669" class="aligncenter size-full wp-image-3738" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Register-an-app-Microsoft-Graph-API.png?v=1642731497 1140w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Register-an-app-Microsoft-Graph-API-1024x601.png?v=1642731497 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Register-an-app-Microsoft-Graph-API-768x451.png?v=1642731497 768w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Register-an-app-Microsoft-Graph-API-300x175.png?v=1642731497 300w" sizes="(max-width: 1140px) 100vw, 1140px" /></a><br />
&nbsp;</p>
<p>Once that&#8217;s complete you should automatically be redirected back to App&#8217;s overview page.  While you&#8217;re there, be sure to jot down the Application (client) Id and the Directory (tenant) ID.  You&#8217;ll need this later when you&#8217;re making up your connection string but that&#8217;s it,  You&#8217;ve made an app in your tenant.</p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/App-registration-over-page.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/App-registration-over-page.png" alt="App registration over page" width="1019" height="430" class="aligncenter size-full wp-image-3740" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/App-registration-over-page.png?v=1642731860 1019w, https://thesysadminchannel.com/wp-content/uploads/2022/01/App-registration-over-page-768x324.png?v=1642731860 768w" sizes="(max-width: 1019px) 100vw, 1019px" /></a></p>
<div id="CertificateAuthentication" style="scroll-margin-top: 15px;"></div>
<h3>Configure The App To Use Certificate Based Authentication</h3>
<p>Now that we&#8217;ve talked a bit about Service Principals, it&#8217;s important to note that there are 2 methods to authenticating to your newly created application.  Those methods are using a certificate or a client secret. We&#8217;ll cover both ways in this article, but we&#8217;ll start with certificates first.<br />
&nbsp;</p>
<p>Azure allows you to use a either a self-signed certificate or a certificate from your PKI infrastructure.  The more secure route of these 2 options would definitely be your PKI infrastructure, but it&#8217;s also understandable that not every environment has one.  I don&#8217;t have a PKI infrastructure in my lab so I&#8217;m going to share the steps with using a self-signed certificate.  The end goal is have to a .pfx on the client machine and a .cer file that&#8217;s uploaded to Azure.</p>
<pre class="brush: powershell; title: ; notranslate">
#splatting for human readability
$CertParam = @{
    'KeyAlgorithm'      = 'RSA'
    'KeyLength'         = 2048
    'KeyExportPolicy'   = 'NonExportable'
    'DnsName'           = 'server.thesysadminchannel.com'
    'FriendlyName'      = 'GraphApi - My Automation App'
    'CertStoreLocation' = 'Cert:\CurrentUser\My\'
    'NotAfter'          = (Get-Date).AddYears(1)
}

#Creating self signed cert with parameters from above.
$Cert = New-SelfSignedCertificate @CertParam

</pre>
<div id="attachment_3746" style="width: 953px" class="wp-caption aligncenter"><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/New-Self-Signed-Cert-for-Azure-AD1.png" target="_blank" rel="noopener"><img decoding="async" aria-describedby="caption-attachment-3746" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/New-Self-Signed-Cert-for-Azure-AD1.png" alt="New Self Signed Cert for Azure AD" width="943" height="399" class="size-full wp-image-3746" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/New-Self-Signed-Cert-for-Azure-AD1.png?v=1642735776 943w, https://thesysadminchannel.com/wp-content/uploads/2022/01/New-Self-Signed-Cert-for-Azure-AD1-768x325.png?v=1642735776 768w" sizes="(max-width: 943px) 100vw, 943px" /></a><p id="caption-attachment-3746" class="wp-caption-text">Note: The DnsName should be the Server&#8217;s Fully Qualified Domain Name (FQDN)</p></div>
<div id="ImportSelfSignedCert" style="scroll-margin-top: 15px;"></div>
<h3>Import Self Signed Certificate to Azure AD</h3>
<p>Once the self signed certificate is created from above, we&#8217;ll need to export it to a .cer and upload that to Azure AD.  Since we&#8217;re already in Powershell, let&#8217;s export it using Powershell.</p>
<pre class="brush: powershell; title: ; notranslate">
#Since we captured the output to the $Cert variable in our previous step.  We'll use that to specify the cert parameter. 
#The .cer file will exported to the user's desktop.

Export-Certificate -Cert $Cert -FilePath $Home\Desktop\MyAutomationApp.cer
</pre>
<p>&nbsp;</p>
<p>Back in Azure AD:</p>
<ul>
<li>Navigate to Certificates &#038; secrets</li>
<li>Click the certificates tab</li>
<li>Click Upload certificate</li>
<li>Click the folder icon and browse to your desktop to select the exported cert</li>
<li>Click Add</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD.png" alt="Upload Certificate to Azure AD" width="1785" height="910" class="aligncenter size-full wp-image-3750" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD.png?v=1642743182 1785w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-1024x522.png?v=1642743182 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-768x392.png?v=1642743182 768w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-1536x783.png?v=1642743182 1536w" sizes="(max-width: 1785px) 100vw, 1785px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-Confirmation.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-Confirmation.png" alt="Upload Certificate to Azure AD Confirmation" width="1111" height="245" class="aligncenter size-full wp-image-3752" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-Confirmation.png?v=1642743546 1111w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-Confirmation-1024x226.png?v=1642743546 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Upload-Certificate-to-Azure-AD-Confirmation-768x169.png?v=1642743546 768w" sizes="(max-width: 1111px) 100vw, 1111px" /></a></p>
<p>We can confirm that the certificate is now uploaded to the Azure application.</p>
<div id="SecretAuthentication" style="scroll-margin-top: 15px;"></div>
<h3>Configure The App To Use Client Secret Based Authentication</h3>
<p>Our next option for authenticating to a Service Principal is being able to use a client secret.  Not to throw shade at using secrets, but personally, I prefer using a certificate because I can get a bit more control over it and can prioritize security above all else.<br />
&nbsp;</p>
<p>What do you mean by that you may ask?  Well, for one, a secret can be passed around and used anywhere just like a regular password can. Meaning a user/app owner can share this secret with other teammates and it&#8217;s up to the user to uphold the security measures.<br />
&nbsp;</p>
<p>Two, this introduces a chicken and egg scenario.  Say this application was used for some kind of unattended automation, you&#8217;re going to need a way to automatically grab this secret to pass into the connection string.  There are ways to programmatically retrieve this using Azure Key Vault or Secrets Management PowerShell Module but now you&#8217;ll need to store <em><strong>that</strong></em> password somewhere securely.  Again, security will most likely be left to the user so your best case scenario is everything is encrypted and stored securely in a vault.  </p>
<p>Or, worse case scenario the secret (along with the Appid and TenantId) are saved to that person&#8217;s personal github repo and has it open to the public.  So before you go down this path, think about how your users would likely treat it.</p>
<p>Now that I got that off my chest, let&#8217;s move forward with generating a secret for your app.<br />
&nbsp;</p>
<p>Back in Azure AD:</p>
<ul>
<li>Navigate to Certificates &#038; secrets</li>
<li>Click the Client Secrets tab</li>
<li>Click New client secret</li>
<li>Enter a useful description.  e.g TicketNumber and Person who&#8217;s primarily responsible for it</li>
<li>Set the expiration date to the recommended 6 months</li>
<li>Click Add</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Creating-a-client-secret-in-azure-ad.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Creating-a-client-secret-in-azure-ad.png" alt="Creating a client secret in azure ad" width="1793" height="873" class="aligncenter size-full wp-image-3757" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Creating-a-client-secret-in-azure-ad.png?v=1642746937 1793w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Creating-a-client-secret-in-azure-ad-1024x499.png?v=1642746937 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Creating-a-client-secret-in-azure-ad-768x374.png?v=1642746937 768w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Creating-a-client-secret-in-azure-ad-1536x748.png?v=1642746937 1536w" sizes="(max-width: 1793px) 100vw, 1793px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Confirm-creating-a-client-secret-in-azure-ad.png"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Confirm-creating-a-client-secret-in-azure-ad.png" alt="Confirm creating a client secret in azure ad" width="1122" height="224" class="aligncenter size-full wp-image-3758" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Confirm-creating-a-client-secret-in-azure-ad.png?v=1642747217 1122w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Confirm-creating-a-client-secret-in-azure-ad-1024x204.png?v=1642747217 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Confirm-creating-a-client-secret-in-azure-ad-768x153.png?v=1642747217 768w" sizes="(max-width: 1122px) 100vw, 1122px" /></a></p>
<p><strong>Important</strong>: Immediately copy the secret because once you leave the page it&#8217;s no longer accessible and you&#8217;ll have to generate a new one. Make sure it&#8217;s secured as well.</p>
<div id="APIPermissions" style="scroll-margin-top: 15px;"></div>
<h3>Configure API Permissions For The Application</h3>
<p>Moving along to our next topic which will be to provide an overview of the API permissions that are going to be granted for the application.  These permission sets can either be Application or Delegated.  The scenario for which the application is used will most likely dictate which sets are used but let&#8217;s give a brief overview and how to set them.</p>
<div id="ApplicationPermissions" style="scroll-margin-top: 15px;"></div>
<h3>Configure Application Permissions To Use For Unattended Automation</h3>
<p>If you want your application to 100% automated, choosing Application permissions is going to be your best bet since it doesn&#8217;t require any user interaction whatsoever. </p>
<p>Going back into your application:</p>
<ul>
<li>Navigate to API permissions</li>
<li>Choose Add a permission</li>
<li>Choose Microsoft Graph (since this is what is most commonly used)</li>
<li>Choose Application Permissions</li>
<li>Select the permissions that are required for this app</li>
<ul>
<li>To get started, choose Dirctory.Read.All and User.Read.All</li>
</ul>
<li>Click Add</li>
<li>Grant admin consent for your organization</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Add-Application-Permissions-to-Graph-API-app1.gif" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Add-Application-Permissions-to-Graph-API-app1.gif" alt="Add Application Permissions to Graph API app" width="1280" height="626" class="aligncenter size-full wp-image-3767" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Admin-consent.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Admin-consent.png" alt="Grant Admin consent" width="1153" height="250" class="aligncenter size-full wp-image-3770" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Admin-consent.png 1153w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Admin-consent-1024x222.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Grant-Admin-consent-768x167.png 768w" sizes="(max-width: 1153px) 100vw, 1153px" /></a></p>
<div id="DelegatedPermissions" style="scroll-margin-top: 15px;"></div>
<h3>Configure Delegated Permissions To Use For Interactive Sessions</h3>
<p>As you can see, delegated permissions are located in the same place that application permissions are so you&#8217;ll just need to select that instead of the app box.<br />
&nbsp;</p>
<p>The key take away between the 2 permissions are this:</p>
<ul>
<li><strong>Delegated Permissions:</strong> Used by apps that have a signed-in user present</li>
<li><strong>Application Permissions:</strong> Used by apps that run unattended automation. Application permissions can only be consented by an administrator</li>
</ul>
<p>Depending on the permissions applied, admin consent will also be needed for the permissions.  The Admin consent required column should notify you if consent is needed.</p>
<div id="ServicePrincipalCertificateAuthentication" style="scroll-margin-top: 15px;"></div>
<h3>Connect Using A Service Principal and Certificate Based Authentication</h3>
<p>We&#8217;re finally nearing the home stretch here and got our App registration and Service Principal created.  Now we just need to bring it all together to connect to Microsoft Graph API using Powershell. In this case we&#8217;re going to start off by connecting using a certificate.  Here&#8217;s how we do that.</p>
<pre class="brush: powershell; title: ; notranslate">
$AppId = &quot;90cb4cab-xxxx-xxxx-xxxx-xxxxxxxxxxxx&quot;
$TenantId = &quot;95cb1f18-xxxx-xxxx-xxxx-xxxxxxxxxxxx&quot;
$Certificate = Get-ChildItem Cert:\CurrentUser\My\180CE345F9XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Connect-Graph -TenantId $TenantId -AppId $AppId -Certificate $Certificate
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Cert-Auth.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Cert-Auth.png" alt="Connect To Microsoft Graph API using Powershell - Cert Auth" width="929" height="213" class="aligncenter size-full wp-image-3773" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Cert-Auth.png 929w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Cert-Auth-768x176.png 768w" sizes="(max-width: 929px) 100vw, 929px" /></a><br />
&nbsp;</p>
<p>If all is successful, you should see &#8220;Welcome To Microsoft Graph!&#8221;  Congrats, you&#8217;re now successfully connected to Microsoft Graph API using certificate based authentication!</p>
<div id="ServicePrincipalSecretAuthentication" style="scroll-margin-top: 15px;"></div>
<h3>Connect Using A Service Principal and Secret Based Authentication</h3>
<p>If you decided going the secret route was the better option for your application, let&#8217;s take a second to show you how to connect using this method.  To get started you will need to install the MSAL.PS Powershell module from the PSGallery.<br />
&nbsp;</p>
<p>This module allows you to create an access token which you will need to connect to MSGraph.</p>
<pre class="brush: powershell; title: ; notranslate">
#Install MSAL.PS module for all users (requires admin rights)
Install-Module MSAL.PS -Scope AllUsers -Force

#Generate Access Token to use in the connection string to MSGraph
$AppId = '90cb4cab-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$TenantId = '95cb1f18-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
$ClientSecret = 'app registration secret'

Import-Module MSAL.PS
$MsalToken = Get-MsalToken -TenantId $TenantId -ClientId $AppId -ClientSecret ($ClientSecret | ConvertTo-SecureString -AsPlainText -Force)

#Connect to Graph using access token
Connect-Graph -AccessToken $MsalToken.AccessToken

</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Secret-Auth.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Secret-Auth.png" alt="Connect-To-Microsoft-Graph-API-using-Powershell-Secret-Auth" width="1099" height="316" class="aligncenter size-full wp-image-3774" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Secret-Auth.png 1099w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Secret-Auth-1024x294.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Connect-To-Microsoft-Graph-API-using-Powershell-Secret-Auth-768x221.png 768w" sizes="(max-width: 1099px) 100vw, 1099px" /></a></p>
<p>If all is successful, you should see &#8220;Welcome To Microsoft Graph!&#8221;  Congrats, you&#8217;re now successfully connected to Microsoft Graph API using secret based authentication!</p>
<div id="GraphProfile" style="scroll-margin-top: 15px;"></div>
<h2>Set Microsoft Graph Profile to use v1.0 or Beta Versions</h2>
<p>Microsoft has 2 versions of Graph API that we&#8217;re able to send requests to. v1.0 which is all generally available endpoints and beta, which is the prerelease version.</p>
<p>It&#8217;s important to note that some items will only work in the beta profile so you might want to give that a try if you see something online and want to try it for yourself.  In any event, we can change profiles by using the Beta prefix on any cmdlet.  Here is a simple example.</p>
<ul>
<li>Get-MgUser -UserId username@thesysadminchannel.com</li>
<li>Get-MgBetaUser -UserId username@thesysadminchannel.com</li>
</ul>
<p>&nbsp;</p>
<p>Something to note when using the v1.0 and beta versions is that the beta returns more properties.  The v1.0 cmdlet typically returns the skeleton properties so the query can run faster.  Depending on what you&#8217;re querying, it is also a good idea to use the -Property parameter so you can get the attributes you need without having to call everything.  This is essential for larger environments.</p>
<div id="Examples" style="scroll-margin-top: 15px;"></div>
<h2>Powershell Graph API Examples</h2>
<p>Finally we&#8217;re at a point where we&#8217;re able to connect To Microsoft Graph API using PowerShell to send some requests.  I&#8217;ll get a user object and group object so you can see how quick and easy it is.</p>
<pre class="brush: powershell; title: ; notranslate">
#Search user by UserPrincipalName
PS C:\&gt; Get-MgUser -UserId buzz@thesysadminchannel.com | select UserPrincipalName, DisplayName

UserPrincipalName           DisplayName
-----------------           -----------
buzz@thesysadminchannel.com Buzz Lightyear

#Get Top 2 objects of Get-MgUser
PS C:\&gt; Get-MgUser -Top 2 | select UserPrincipalName, DisplayName

UserPrincipalName               DisplayName
-----------------               -----------
aaduser3@thesysadminchannel.com aaduser3
aaduser4@thesysadminchannel.com aaduser4

#Get all the groups with fakegroup in the DisplayName
PS C:\&gt; Get-MgGroup -Search &quot;DisplayName:fakegroup&quot; -ConsistencyLevel eventual | select DisplayName, Description

DisplayName    Description
-----------    -----------
SG - FakeGroup A group that's not real
FakeGroup

#Get group object by Id.
PS C:\&gt; Get-MgGroup -GroupId 51fb0824-5318-448c-8de6-ffc06c192b0d

Id                                   DisplayName    Description             GroupTypes
--                                   -----------    -----------             ----------
51fb0824-5318-448c-8de6-ffc06c192b0d SG - FakeGroup A group that's not real {}

PS C:\&gt;
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2022/01/Powershell-Graph-API-Examples.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2022/01/Powershell-Graph-API-Examples.png" alt="Powershell Graph API Examples" width="1099" height="632" class="aligncenter size-full wp-image-3776" srcset="https://thesysadminchannel.com/wp-content/uploads/2022/01/Powershell-Graph-API-Examples.png 1099w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Powershell-Graph-API-Examples-1024x589.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2022/01/Powershell-Graph-API-Examples-768x442.png 768w" sizes="(max-width: 1099px) 100vw, 1099px" /></a></p>
<div id="Conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>I&#8217;m hoping this deep dive on how to connect to Microsoft Graph API using PowerShell was informative enough to get your started.  As an IT Professional, this is something you can use to automate many of your Azure tasks.  If you&#8217;re a developer, this can be useful to interact with other applications in your wheelhouse.<br />
&nbsp;</p>
<p>If you&#8217;re looking for more Powershell content, be sure to check out our <a href="https://thesysadminchannel.com/powershell/" rel="noopener" target="_blank">category full of useful scripts</a>.  The same goes for <a href="https://thesysadminchannel.com/azure/" rel="noopener" target="_blank">Azure Active Directory</a>.  I&#8217;ll also be starting a new series of posts dedicated to Graph API so stay tuned.</p>
<p>The post <a href="https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/">How To Connect To Microsoft Graph API Using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/how-to-connect-to-microsoft-graph-api-using-powershell/feed/</wfw:commentRss>
			<slash:comments>14</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2553</post-id>	</item>
	</channel>
</rss>
