<?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>the Sysadmin Channel</title>
	<atom:link href="https://thesysadminchannel.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://thesysadminchannel.com/</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.9.4</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>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;5023&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;1&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (1 vote)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Get Entra ID PIM Role Assignment Using Graph API&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (1 vote)    </div>
    </div>
<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>VMware vCenter SSO Integration with Azure AD</title>
		<link>https://thesysadminchannel.com/vmware-vcenter-sso-integration-with-azure-ad/</link>
					<comments>https://thesysadminchannel.com/vmware-vcenter-sso-integration-with-azure-ad/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Sun, 26 Nov 2023 00:45:38 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[VMware]]></category>
		<category><![CDATA[How to connect vCenter to Azure Active Directory]]></category>
		<category><![CDATA[vcenter 8 azure sso]]></category>
		<category><![CDATA[vcenter azure ad authentication]]></category>
		<category><![CDATA[vcenter azure sso]]></category>
		<category><![CDATA[vmware vcenter azure ad authentication]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4922</guid>

					<description><![CDATA[<p>It&#8217;s finally here! VMware finally allows you to leverage Azure AD as a primary Identity Provider (IdP). Today we are going to cover the steps to setup VMware vCenter SSO Integration with Azure AD (Entra ID). Using Azure AD as&#8230; <a href="https://thesysadminchannel.com/vmware-vcenter-sso-integration-with-azure-ad/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/vmware-vcenter-sso-integration-with-azure-ad/">VMware vCenter SSO Integration with Azure AD</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>It&#8217;s finally here!  VMware finally allows you to leverage Azure AD as a primary Identity Provider (IdP).  Today we are going to cover the steps to setup VMware vCenter SSO Integration with Azure AD (Entra ID).  Using Azure AD as an IdP allows you to now have vCenter in scope of conditional access policies as well as authentication methods native to Azure AD such as Windows Hello for Business or Fido2 security keys.  </p>
<p>&nbsp;<br />
<em>For the purposes of this article we will use the Azure AD Portal, not the Entra ID portal</em></p>
<div id="blockquote1">
<strong>IMPORTANT</strong>: When upgrading to vCenter 8 from a previous version, you&#8217;re no longer able to use an on-premises Active Directory Identity Source so be sure to TEST this in a lab before moving to production.
</div>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#oidcapp">Create the Azure AD OIDC App Registration</a></li>
<li><a href="#vcenteridp">vCenter Identity Source Configuration</a></li>
<li><a href="#appproxy">Setting up an Azure App Proxy</a></li>
<ul>
<li><a href="#vcentercertificate">Trusting vCenter Root Certificate on the Connector Service Machine</a></li>
</ul>
<li><a href="#identityservice">Create the VMware Identity Service App from the Gallery</a></li>
<ul>
<li><a href="#scimprovisioning">Setup SCIM Provisioning to Sync Users to vCenter</a></li>
</ul>
<li><a href="#vcenterpermissions">Integrating Permissions for VMware vCenter</a></li>
<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 order to make this work there are a few requirements/prerequisites needed so you can successfully use Azure AD as the Identity Provider.  Let&#8217;s touch on those requirements now.</p>
<ul>
<li>VMware Administrator Role</li>
<li>VMware vCenter 8.0 U2 or later</li>
<li>VMware Identity Services from Azure Enterprise App Gallery</li>
<li>Azure Application Administrator or Global Administrator Role</li>
<li>Azure App Registration with OpenID Connect (OIDC) scope</li>
<li>Publicly accessible vCenter endpoint (We will use an Azure App Proxy for this)</li>
<li>A group or users to sync to vCenter</li>
</ul>
<p>&nbsp;</p>
<div id="oidcapp" style="scroll-margin-top: 10px;"></div>
<h2>Create the Azure AD OIDC App Registration</h2>
<p>As mentioned in the prerequisites, you will need to create an app registration in Azure AD so you can use this as the authentication endpoint. This app will need to have the <code>openid</code> API permission so let&#8217;s walk through setting that up now.<br />
&nbsp;</p>
<p>Within Azure AD:</p>
<ul>
<li>Navigate to App Registration → New Registration</li>
<ul>
<li>Direct Link: <a href="https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/CreateApplicationBlade/quickStartType~/null/isMSAApp~/false" rel="noopener" target="_blank">https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/CreateApplicationBlade/quickStartType~/null/isMSAApp~/false</a></li>
</ul>
<li>Name the app: <strong>vCenter 8 OIDC</strong></li>
<li>Leave the Organizational directory to <strong>Single Tenant</strong></li>
<li>Leave the Redirect URI blank for now</li>
<li>Click Register to create the app</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration.png" alt="Create vCenter 8 OIDC App registration" width="1008" height="692" class="aligncenter size-full wp-image-4937" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration.png?v=1700264341 1008w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration-768x527.png?v=1700264341 768w" sizes="(max-width: 1008px) 100vw, 1008px" /></a><br />
&nbsp;</p>
<p>Next we&#8217;ll want to add the API permissions so we can tie this Azure app to vCenter.<br />
Within the vCenter 8 OIDC App:</p>
<ul>
<li>Navigate to API Permissions</li>
<li>Select Add a permission</li>
<li>Choose Microsoft Graph → Delegated → enable the 4 listed below</li>
<li>Grant Consent for good measure</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration-api-scopes.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration-api-scopes.png" alt="Create vCenter 8 OIDC App registration api scopes" width="1230" height="672" class="aligncenter size-full wp-image-4938" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration-api-scopes.png?v=1700265543 1230w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration-api-scopes-1024x559.png?v=1700265543 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-vCenter-8-OIDC-App-registration-api-scopes-768x420.png?v=1700265543 768w" sizes="(max-width: 1230px) 100vw, 1230px" /></a></p>
<p><em>Leave this tab open for now, we will come back to it later.</em></p>
<p>&nbsp;</p>
<div id="vcenteridp" style="scroll-margin-top: 10px;"></div>
<h2>vCenter Identity Source Configuration</h2>
<p>We&#8217;re one step closer now that we have have the OIDC app created. Next we need to configure vCenter itself so we can change the Identity Provider from the local embedded provider to Azure AD.<br />
&nbsp;</p>
<p>Within the vCenter Server:</p>
<ul>
<li><strong>Login to vCenter 8</strong> using administrator@vsphere.local since we won&#8217;t have any other providers available</li>
<li>Navigate to <strong>Administration</strong> → <strong>single sign on</strong> → <strong>configuration</strong> → <strong>Identity Provider</strong> → <strong>Identity Sources</strong></li>
<li>Click <strong>Change Provider</strong> → <strong>Azure AD</strong></li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Change-Identity-Provider.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Change-Identity-Provider.png" alt="VMware Change Identity Provider" width="1338" height="634" class="aligncenter size-full wp-image-4949" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Change-Identity-Provider.png?v=1700275438 1338w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Change-Identity-Provider-1024x485.png?v=1700275438 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Change-Identity-Provider-768x364.png?v=1700275438 768w" sizes="(max-width: 1338px) 100vw, 1338px" /></a><br />
&nbsp;</p>
<ul>
<li>Next, click run prechecks</li>
<li>Check the box to confirm</li>
<li>Click Next</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-IdP-Prereq-checks.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-IdP-Prereq-checks.png" alt="VMware IdP Prereq checks" width="1149" height="580" class="aligncenter size-full wp-image-4950" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-IdP-Prereq-checks.png?v=1700275698 1149w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-IdP-Prereq-checks-1024x517.png?v=1700275698 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-IdP-Prereq-checks-768x388.png?v=1700275698 768w" sizes="(max-width: 1149px) 100vw, 1149px" /></a><br />
&nbsp;</p>
<ul>
<li>Under Directory Name enter <strong>Azure AD</strong></li>
<li>Enter the domain(s) and click the &#8220;+&#8221; to add it</li>
<ul>
<li>If you have multiple UPN suffixes, add them domain names here.</li>
</ul>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-add-domain-config.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-add-domain-config.png" alt="VMware add domain config" width="1149" height="580" class="aligncenter size-full wp-image-4951" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-add-domain-config.png?v=1700276067 1149w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-add-domain-config-1024x517.png?v=1700276067 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-add-domain-config-768x388.png?v=1700276067 768w" sizes="(max-width: 1149px) 100vw, 1149px" /></a><br />
&nbsp;</p>
<ul>
<li>Set the token lifetime</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-User-provision-lifetime-token.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-User-provision-lifetime-token.png" alt="VMware User provision lifetime token" width="1140" height="576" class="aligncenter size-full wp-image-4953" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-User-provision-lifetime-token.png?v=1700276375 1140w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-User-provision-lifetime-token-1024x517.png?v=1700276375 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-User-provision-lifetime-token-768x388.png?v=1700276375 768w" sizes="(max-width: 1140px) 100vw, 1140px" /></a><br />
&nbsp;</p>
<p>Earlier I mentioned to keep the tabs open because we&#8217;re going to need them later. Now is that time where we are going to use need them. </p>
<ul>
<li>Copy the redirect URI from the vCenter wizard</li>
<li>Navigate back to the vCenter 8 OIDC app → Authentication tab</li>
<li>Add a platform → Select Web</li>
<li>Paste the Redirect URI into the redirect URI in the Azure app</li>
<li>Click configure</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Web-URI-Redirect.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Web-URI-Redirect.png" alt="VMware Web URI Redirect" width="1336" height="899" class="aligncenter size-full wp-image-4955" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Web-URI-Redirect.png?v=1700277829 1336w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Web-URI-Redirect-1024x689.png?v=1700277829 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Web-URI-Redirect-768x517.png?v=1700277829 768w" sizes="(max-width: 1336px) 100vw, 1336px" /></a><br />
&nbsp;</p>
<ul>
<li>Copy the AppId (ClientId) from the Azure OIDC app and paste it to the client identifier in vCenter</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-AppId.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-AppId.png" alt="VMware AppId" width="784" height="379" class="aligncenter size-full wp-image-4958" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-AppId.png?v=1700278777 784w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-AppId-768x371.png?v=1700278777 768w" sizes="(max-width: 784px) 100vw, 784px" /></a><br />
&nbsp;</p>
<ul>
<li>Create a secret and paste it in vCenter</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Shared-Secret.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Shared-Secret.png" alt="VMware Shared Secret" width="881" height="643" class="aligncenter size-full wp-image-4961" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Shared-Secret.png?v=1700279440 881w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-Shared-Secret-768x561.png?v=1700279440 768w" sizes="(max-width: 881px) 100vw, 881px" /></a><br />
&nbsp;</p>
<ul>
<li>In the overview page of the OIDC App</li>
<li>Click on EndPoints</li>
<li>Copy the OpenID Connect metadata document URL and paste it in vCenter</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-OpenID-configuration-update.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-OpenID-configuration-update.png" alt="VMware OpenID configuration-update" width="1254" height="537" class="aligncenter size-full wp-image-4965" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-OpenID-configuration-update.png?v=1700280460 1254w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-OpenID-configuration-update-1024x439.png?v=1700280460 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/VMware-OpenID-configuration-update-768x329.png?v=1700280460 768w" sizes="(max-width: 1254px) 100vw, 1254px" /></a></p>
<ul>
<li>Review the configuration and proceed</li>
</ul>
<p>&nbsp;</p>
<div id="appproxy" style="scroll-margin-top: 10px;"></div>
<h2>Setting up an Azure App Proxy</h2>
<p>One of the requirements to use Azure AD as the Identity source is to make sure we are able to publicly access vCenter from Azure.  I am NOT a fan of exposing your network and poking a hole in your firewall so we&#8217;ll use the next best thing. In order to satisfy this requirement, we will use an Azure app proxy which will publish an endpoint that sits behind Azure.<br />
&nbsp;</p>
<p>The idea is that we will use the app proxy&#8217;s public endpoint to route to the internal endpoint so Azure is able to talk to vCenter on-premises.  An app proxy requires you to install the connector service on an on-premises server that has line of sight to your vCenter server. I would suggest you have the app proxy agent installed on 2 machines so you can have some sort of redundancy when you need to do maintenance on the servers.<br />
&nbsp;</p>
<p>Let&#8217;s walk through the setup now.<br />
Within Azure AD, open a NEW tab:</p>
<ul>
<li>Navigate to Azure AD → Application Proxy</li>
<ul>
<li>Direct Link: <a href="https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/AppProxy" rel="noopener" target="_blank">https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/AppProxy</a></li>
</ul>
<li>Download and install the connector service</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/Download-Azure-app-proxy.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/Download-Azure-app-proxy.png" alt="Download Azure app proxy" width="979" height="249" class="aligncenter size-full wp-image-4977" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/Download-Azure-app-proxy.png?v=1701027374 979w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Download-Azure-app-proxy-768x195.png?v=1701027374 768w" sizes="(max-width: 979px) 100vw, 979px" /></a></p>
<p>The install is pretty straight forward so get it installed on 2 machines and go back into the Azure portal.<br />
&nbsp;</p>
<p>Once the connector is installed, you should see the hostname and public IP show up in the Azure proxy section.  From here, click on <strong>configure an app</strong>.<br />
<a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-an-app.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-an-app.png" alt="Azure app proxy configure an app" width="1129" height="384" class="aligncenter size-full wp-image-4979" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-an-app.png?v=1701027765 1129w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-an-app-1024x348.png?v=1701027765 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-an-app-768x261.png?v=1701027765 768w" sizes="(max-width: 1129px) 100vw, 1129px" /></a><br />
&nbsp;</p>
<p>Next you should be taken to the app proxy configuration settings.</p>
<ul>
<li>Copy the <strong>vCenter Tenant URL</strong> and paste it into the <strong>app proxy Internal URL</strong> field</li>
<li>Ensure the dropdown is set to <strong>https://</strong></li>
<li>Enter in a name for your app proxy (vcenter8appproxy or something similar is fine)</li>
<li>Set the domain drop to which ever makes sense for you. Leaving the default is fine</li>
<li>Set the <strong>pre authentication method</strong> to <strong>passthrough</strong></li>
<li><strong>Set the connector group</strong> accordingly.  If you have multiple connector groups, make sure it is set on the App proxy blade AND the Enterprise app settings</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-tenant-url.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-tenant-url.png" alt="Azure app proxy configure tenant url" width="928" height="460" class="aligncenter size-full wp-image-4982" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-tenant-url.png?v=1701029995 928w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Azure-app-proxy-configure-tenant-url-768x381.png?v=1701029995 768w" sizes="(max-width: 928px) 100vw, 928px" /></a><br />
&nbsp;</p>
<div id="vcentercertificate" style="scroll-margin-top: 10px;"></div>
<h2>Trusting vCenter Root Certificate on the Connector Service Machine</h2>
<p>If you&#8217;re using a publicly trusted certificate for vCenter than you can skip this part.  However, if you&#8217;re using the default certificate that comes pre-loaded with vCenter you will need to do this.  An easy way to find out, is go to your vCenter URL and if you&#8217;re getting <strong>Your connection is not private</strong> then you&#8217;re not using a trusted cert.<br />
&nbsp;</p>
<p>Let&#8217;s go back to the machine(s) that you installed the service connector on because that&#8217;s where we will need to have the cert be trusted. These steps need to be done on EACH server that has the connector agent.</p>
<p>On a NEW tab:</p>
<ul>
<li>Navigate to https://&lt;your vcenter url&gt;/certs/download.zip</li>
<li>Right click and save as a zip file</li>
<li>Open the zip file → certs → win</li>
<li>Double click on the crt file to install it on the local machine</li>
<li>Install it under the <strong>local machine</strong> context</li>
<li>Place it under the <strong>Trusted Root Certification Authorities</strong></li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority.png" alt="vCenter trusted root cert authority" width="918" height="520" class="aligncenter size-full wp-image-4986" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority.png?v=1701031595 918w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority-768x435.png?v=1701031595 768w" sizes="(max-width: 918px) 100vw, 918px" /></a><br />
&nbsp;</p>
<ul>
<li>You can verify this by opening mmc.exe on the service connector machine</li>
<li>Certificates → Local machine → Trusted root certification authorities</li>
<li>Seeing the CA cert there</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority-verification.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority-verification.png" alt="vCenter trusted root cert authority verification" width="1043" height="551" class="aligncenter size-full wp-image-4988" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority-verification.png?v=1701032133 1043w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority-verification-1024x541.png?v=1701032133 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-trusted-root-cert-authority-verification-768x406.png?v=1701032133 768w" sizes="(max-width: 1043px) 100vw, 1043px" /></a><br />
&nbsp;</p>
<div id="identityservice" style="scroll-margin-top: 10px;"></div>
<h2>Create the VMware Identity Service App from the Gallery</h2>
<p>Next on the list, we&#8217;ll need to create the VMware Identity Service app from the Azure App gallery to allow us to use SCIM provisioning.</p>
<p>Within Azure AD on a NEW tab:</p>
<ul>
<li>Navigate to Enterprise Application → New Application</li>
<ul>
<li>Direct Link: <a href="https://portal.azure.com/#view/Microsoft_AAD_IAM/AppGalleryBladeV2" rel="noopener" target="_blank">https://portal.azure.com/#view/Microsoft_AAD_IAM/AppGalleryBladeV2</a></li>
</ul>
<li>Search for &#8220;VMware Identity&#8221; to install the <strong>VMware Identity Service</strong></li>
<li>Name it <strong>vCenter 8 SCIM Provisioning</strong></li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-SCIM-Application.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-SCIM-Application.png" alt="Create SCIM Application" width="1204" height="642" class="aligncenter size-full wp-image-4942" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-SCIM-Application.png?v=1700270606 1204w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-SCIM-Application-1024x546.png?v=1700270606 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/11/Create-SCIM-Application-768x410.png?v=1700270606 768w" sizes="(max-width: 1204px) 100vw, 1204px" /></a></p>
<p>&nbsp;</p>
<div id="scimprovisioning" style="scroll-margin-top: 10px;"></div>
<h2>Setup Provisioning to Sync Users to vCenter</h2>
<p>Here is where the rubber meets the road and we can finally start syncing users from Azure AD to vCenter. </p>
<ul>
<li>Navigate to the Enterprise Application → vCenter 8 SCIM Provisioning → Provisioning</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-blade.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-blade.png" alt="vCenter 8 SCIM Provisioning blade" width="1011" height="519" class="aligncenter size-full wp-image-4992" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-blade.png?v=1701034026 1011w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-blade-768x394.png?v=1701034026 768w" sizes="(max-width: 1011px) 100vw, 1011px" /></a><br />
&nbsp;</p>
<ul>
<li>Click on Provisioning and set the mode to automatic</li>
<li>Copy the External URL from the Azure app proxy and paste it here under Tenant URL</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-External-URL.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-External-URL.png" alt="vCenter 8 SCIM Provisioning External URL" width="870" height="588" class="aligncenter size-full wp-image-4994" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-External-URL.png?v=1701035281 870w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-External-URL-768x519.png?v=1701035281 768w" sizes="(max-width: 870px) 100vw, 870px" /></a><br />
&nbsp;</p>
<ul>
<li><strong>Create a secret from vCenter 8</strong> configuration and paste it here under <strong>Secret Token</strong></li>
<li>Click <strong>Test Connection</strong>.  If everything is configured correctly, it should work.
<li>Save the configuration</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Secret-Token.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Secret-Token.png" alt="vCenter 8 SCIM Provisioning Secret Token" width="861" height="408" class="aligncenter size-full wp-image-4995" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Secret-Token.png?v=1701035718 861w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Secret-Token-768x364.png?v=1701035718 768w" sizes="(max-width: 861px) 100vw, 861px" /></a><br />
&nbsp;</p>
<p>Once the setting is saved, refresh the tab so the other settings can kick in.  Another option is to close out of the blade and go back into the provisioning section.</p>
<ul>
<li>From here within the provisioning blade → Users and groups</li>
<li>Set the users and/or groups you want to sync to vCenter</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Add-users-and-groups.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Add-users-and-groups.png" alt="vCenter 8 SCIM Provisioning Add users and groups" width="917" height="465" class="aligncenter size-full wp-image-4998" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Add-users-and-groups.png?v=1701103172 917w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-Add-users-and-groups-768x389.png?v=1701103172 768w" sizes="(max-width: 917px) 100vw, 917px" /></a><br />
&nbsp;</p>
<p>Once we&#8217;re happy with the users and/or groups we want to add, we&#8217;ll need to start the provisioning cycle so the objects can sync to vCenter 8.</p>
<ul>
<li>Go to the overview page</li>
<li>Click on start provisioning to start the sync engine</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-start-provisioning.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-start-provisioning.png" alt="vCenter 8 SCIM Provisioning start provisioning" width="876" height="450" class="aligncenter size-full wp-image-4999" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-start-provisioning.png?v=1701103429 876w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-SCIM-Provisioning-start-provisioning-768x395.png?v=1701103429 768w" sizes="(max-width: 876px) 100vw, 876px" /></a><br />
&nbsp;</p>
<div id="vcenterpermissions" style="scroll-margin-top: 10px;"></div>
<h2>Integrating Permissions for VMware vCenter</h2>
<p>At this point you should now have your users and/or groups syncing to VMware vCenter 8.  The last step here is to actually add these users to the permissions that you want to grant. VMware has these steps pretty well documented so it&#8217;s a quick search away.  However,  we&#8217;ll do a quick overview to ensure we add our users to the admin role so we can manage vCenter and all its resources.<br />
&nbsp;</p>
<p>Within vCenter 8 UI:</p>
<ul>
<li>Navigate to <strong>Administration</strong> → <strong>single sign on</strong> → <strong>Users and Groups</strong> → <strong>Groups</strong> → <strong>Administrators</strong></li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-administrator.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-administrator.png" alt="vCenter 8 Users and group administrator" width="1023" height="569" class="aligncenter size-full wp-image-5006" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-administrator.png?v=1701110226 1023w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-administrator-768x427.png?v=1701110226 768w" sizes="(max-width: 1023px) 100vw, 1023px" /></a><br />
&nbsp;</p>
<ul>
<li>Click <strong>Edit</strong> to modify the members</li>
<li>Next to Add a member, click the drop down to <strong>add your domain</strong></li>
<li><strong>Search for the group</strong> that is synced from Azure AD provisioning</li>
<li>Click <strong>Save</strong> to save the keep the settings</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-add-admin.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-add-admin.png" alt="vCenter 8 Users and group add admin" width="860" height="584" class="aligncenter size-full wp-image-5008" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-add-admin.png?v=1701111186 860w, https://thesysadminchannel.com/wp-content/uploads/2023/11/vCenter-8-Users-and-group-add-admin-768x522.png?v=1701111186 768w" sizes="(max-width: 860px) 100vw, 860px" /></a><br />
&nbsp;</p>
<div id="conclusion" style="scroll-margin-top: 10px;"></div>
<h2>Conclusion</h2>
<p>So there you have it, a full step by step guide on how to setup VMware vCenter SSO Integration with Azure AD.  This method is especially helpful because this allows you to have vCenter in scope of conditional access policies and phishing resistance MFA methods such as Windows Hello for Business and Fido 2 security keys.</p>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4922&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;2&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (2 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;VMware vCenter SSO Integration with Azure AD&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (2 votes)    </div>
    </div>
<p>The post <a href="https://thesysadminchannel.com/vmware-vcenter-sso-integration-with-azure-ad/">VMware vCenter SSO Integration with Azure AD</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/vmware-vcenter-sso-integration-with-azure-ad/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4922</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>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4920&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;7&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (7 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Get Microsoft 365 License Usage Count Using PowerShell&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (7 votes)    </div>
    </div>
<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>Find Empty Groups in Active Directory using PowerShell</title>
		<link>https://thesysadminchannel.com/find-empty-groups-in-active-directory-using-powershell/</link>
					<comments>https://thesysadminchannel.com/find-empty-groups-in-active-directory-using-powershell/#comments</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Tue, 03 Oct 2023 01:30:46 +0000</pubDate>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Find Empty Groups]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4912</guid>

					<description><![CDATA[<p>Whether it&#8217;s time for spring cleaning or you&#8217;re just doing some general cleanup, it&#8217;s important to maintain a proper lifecycle around Active Directory groups. Many organizations love creating groups however, some (most?), don&#8217;t really like to do cleanup because they&#8217;re&#8230; <a href="https://thesysadminchannel.com/find-empty-groups-in-active-directory-using-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/find-empty-groups-in-active-directory-using-powershell/">Find Empty Groups in Active Directory using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Whether it&#8217;s time for spring cleaning or you&#8217;re just doing some general cleanup, it&#8217;s important to maintain a proper lifecycle around Active Directory groups. Many organizations love creating groups however, some (most?), don&#8217;t really like to do cleanup because they&#8217;re scared it might break something.  While this is true, it&#8217;s still a good thing to keep a tight ship and have some automation around cleanup.  Today we&#8217;re going to go over the query to find empty groups in Active Directory using PowerShell.<br />
&nbsp;</p>
<p>I previously wrote a post about using the ActiveDirectory module with Get-ADUser.  The idea was to <a href="https://thesysadminchannel.com/get-aduser-find-active-directory-users-using-powershell-ultimate-deep-dive/" rel="noopener" target="_blank">find AD users using PowerShell</a> and went over several advanced topics.  Feel free to check that to get familiar with the overall commands since Get-ADGroup is going to use something similar.<br />
&nbsp;</p>
<p>Here, the Get-ADGroup cmdlet is going to be used to filter all groups that have no members and move them to a separate OU for further processing.  Since we are a little cautious when it comes to making bulk changes like this, I would suggest moving them to a staging OU where they can be left there for 30-60 days.  Since these groups are empty, chances are no one is going to be missing them but it&#8217;s a good idea to separate them first, then move forward with deleting.<br />
&nbsp;</p>
<p>Before we delete anything, I would strongly recommend you <a href="https://techcommunity.microsoft.com/t5/ask-the-directory-services-team/the-ad-recycle-bin-understanding-implementing-best-practices-and/ba-p/396944" rel="noopener" target="_blank">enable the AD recycle bin</a> so you can recover objects without hesitation.<br />
&nbsp;</p>
<h2>Find Empty Groups in Active Directory using PowerShell</h2>
<pre class="brush: powershell; title: ; notranslate">
#Get All empty groups in the entire domain. Be careful with Exchange and other built-in groups.
$AllEmptyGroupList = Get-ADGroup -Filter {Members -notlike &quot;*&quot; } -Properties Members, WhenChanged, WhenCreated

#Get all empty groups that have not been touched in longer than 6 months. Be careful with Exchange and other built-in groups.
$CutOffDate = (Get-Date).AddMonths(-6)
$SixMonthEmptyGroupList = Get-ADGroup -Filter {Members -notlike &quot;*&quot; -and WhenChanged -lt $CutOffDate} -Properties Members, WhenChanged, WhenCreated

#Get all stale groups from a specific OU (Preferred)
$EmptyGroupList = Get-ADGroup -Filter {Members -notlike &quot;*&quot; -and WhenChanged -lt $CutOffDate} -Properties Members, WhenChanged, WhenCreated -SearchBase 'OU=My Groups,DC=contoso,DC=com'
</pre>
<p>&nbsp;</p>
<p>Hopefully, you were able to understand how to find empty groups in Active Directory using PowerShell to better manage your group lifecycle.  If a group is empty and hasn&#8217;t been modified in over 6 months, it&#8217;s a pretty good sign that it is no longer needed and can be purged.<br />
&nbsp;</p>
<p>Again, I would highly recommend you enable the recycle bin but with this you should be able to start off slowly and decommissioning in whatever approach you feel necessary.</p>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4912&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;6&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (6 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Find Empty Groups in Active Directory using PowerShell&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (6 votes)    </div>
    </div>
<p>The post <a href="https://thesysadminchannel.com/find-empty-groups-in-active-directory-using-powershell/">Find Empty Groups in Active Directory using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/find-empty-groups-in-active-directory-using-powershell/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4912</post-id>	</item>
		<item>
		<title>Block Unmanaged Devices Using Conditional Access</title>
		<link>https://thesysadminchannel.com/block-unmanaged-devices-using-conditional-access/</link>
					<comments>https://thesysadminchannel.com/block-unmanaged-devices-using-conditional-access/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Mon, 25 Sep 2023 02:21:20 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Office365]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[block unmanaged devices conditional access]]></category>
		<category><![CDATA[conditional access block sharepoint but not teams]]></category>
		<category><![CDATA[restrict m365 apps in browser]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4839</guid>

					<description><![CDATA[<p>For most, the days of working off an entire on-premises environment where you have to connect to VPN in order to access email or your files is long gone. The world has shifted to hybrid or cloud only environments and&#8230; <a href="https://thesysadminchannel.com/block-unmanaged-devices-using-conditional-access/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/block-unmanaged-devices-using-conditional-access/">Block Unmanaged Devices Using Conditional Access</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>For most, the days of working off an entire on-premises environment where you have to connect to VPN in order to access email or your files is long gone.  The world has shifted to hybrid or cloud only environments and with that, it&#8217;s important to ensure your data is only accessible to devices that only you authorize. Today we are going to go over the methods on how to limit access when using a browser as well as the methods to <strong>block unmanaged devices using conditional access</strong>.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#unmanageddevice">What Classifies an Unmanaged Device</a></li>
<li><a href="#limitaccess">Limit Browser Access on Unmanaged Devices for M365 Apps</a></li>
<ul>
<li><a href="#limitspo">Limited Browser Access for SharePoint Online</a></li>
<ul>
<li><a href="#limitspopersite">Apply on a Per-Site Basis</a></li>
<li><a href="#limitspotenant">Apply at the Tenant Level</a></li>
</ul>
<li><a href="#limitexo">Limited Browser Access for Exchange Online</a></li>
<ul>
<li><a href="#limitexopermailbox">Apply on a Per-Mailbox Basis</a></li>
<li><a href="#limitexotenant">Apply at the Tenant Level</a></li>
</ul>
</ul>
<li><a href="#blockaccess">Block Unmanaged Devices Using Conditional Access</a></li>
<li><a href="#restrictaccess">Restrict Browser Access on Unmanaged Devices Using Conditional Access</a></li>
<li><a href="#extensions">Incognito Mode and Browser Extensions</a></li>
<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>Before we go into the details on how to set this up, we first need to ensure that we have everything in place so everything works as expected. Here&#8217;s what is needed.</p>
<ul>
<li>Azure AD P1 or P2 license for conditional access</li>
<li>Security Administrator, Conditional Access Administrator or Global Administrator</li>
<li>SharePoint Administrator or Global Administrator</li>
<li>Exchange Administrator or Global Administrator</li>
<li>Microsoft.Online.SharePoint.PowerShell PowerShell Module</li>
<li>ExchangeOnlineManagement PowerShell Module</li>
</ul>
<p>&nbsp;</p>
<p>To touch a bit on these requirements, we need to ensure we have an Azure AD P1 or P2 license so we can have access to use conditional access policies.  This is going to be the foundation of what we&#8217;re going to use to either limit or block unmanaged devices from accessing anything in the cloud.  Also as of today, Security Administrator, Conditional Access Administrator or Global Administrator are the only roles that are able to modify CA policies. So we will need at least one of those.<br />
&nbsp;</p>
<p>Exchange Administrator and SharePoint Administrators are needed to be able to set the respective platform policies to limited access.  A bit more on that later.</p>
<div id="unmanageddevice" style="scroll-margin-top: 10px;"></div>
<h2>What Classifies as an Unmanaged Device</h2>
<p>An unmanaged device is typically a device that is not issued by your organization.  It is often synonymous with BYOD (Bring Your Own Device) and can be anything from a personal computer or phone to a machine that you use to access emails while at grandma&#8217;s house.  The point here is that it doesn&#8217;t have any policies and it is not properly governed by the IT department.<br />
&nbsp;</p>
<div id="limitaccess" style="scroll-margin-top: 10px;"></div>
<h2>Limit Browser Access on Unmanaged Devices for M365 Apps</h2>
<p>If you don&#8217;t want to put a full stop on users accessing M365 resources, you do have the ability to limit what they can do while signed in from an unmanaged device.  Simply put, we can enforce policies so users can still sign in using the web only methods, however, they will be blocked from downloading anything to the local machine.<br />
&nbsp;</p>
<p>For most, this is a great happy medium because it still keeps your data secure to a certain extent and users can access their documents if they don&#8217;t have their company issued device around.<br />
&nbsp;</p>
<p>This is in fact a two-step process so we&#8217;ll target SharePoint/OneDrive and Exchange Online now.  Then we will finish it off with the CA Policies.</p>
<div id="limitspo" style="scroll-margin-top: 10px;"></div>
<h2>Limited Browser Access for SharePoint Online</h2>
<p>If you want to take this in incremental steps you definitely can.  Being able to set limited access on specific sites is supported so it&#8217;s definitely recommended you take that approach first. In my opinion it will be a good test to set limited access on a few SharePoint sites as well as a few OneDrive sites.<br />
&nbsp;</p>
<p>Let&#8217;s connect to SharePoint Online using the <a href="https://www.powershellgallery.com/packages/Microsoft.Online.SharePoint.PowerShell/" rel="noopener" target="_blank">Microsoft.Online.SharePoint.PowerShell</a> PowerShell Module.</p>
<pre class="brush: powershell; title: ; notranslate">
Import-Module Microsoft.Online.SharePoint.PowerShell -WarningAction SilentlyContinue
$adminURL = 'https://&lt;tenantname&gt;-admin.sharepoint.com'
Connect-SPOService -Url $adminURL -WarningAction SilentlyContinue
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Connect-SharePoint-Online.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Connect-SharePoint-Online.png" alt="Connect-SharePoint Online" width="861" height="215" class="aligncenter size-full wp-image-4848" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Connect-SharePoint-Online.png?v=1695425407 861w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Connect-SharePoint-Online-768x192.png?v=1695425407 768w" sizes="(max-width: 861px) 100vw, 861px" /></a><br />
&nbsp;</p>
<div id="limitspopersite" style="scroll-margin-top: 10px;"></div>
<h4>Apply on a Per-Site Basis</h4>
<p>Next, let&#8217;s take a look at the conditional access property within the <strong><em>Get-SPOSite</em></strong> cmdlet.  This is what we&#8217;ll use to be able to limit access on specific SharePoint (or OneDrive) sites before we deploy this on the tenant level. By default, this should be set to allow full access.  Meaning anyone can access this SharePoint site from anywhere and there wouldn&#8217;t be any restrictions in place.</p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-SPO-Site-PowerShell.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-SPO-Site-PowerShell.png" alt="Get SPOSite PowerShell" width="860" height="265" class="aligncenter size-full wp-image-4851" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-SPO-Site-PowerShell.png?v=1695486802 860w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-SPO-Site-PowerShell-768x237.png?v=1695486802 768w" sizes="(max-width: 860px) 100vw, 860px" /></a><br />
&nbsp;</p>
<p>With that out of the way, let&#8217;s change the access to allow limited, web only access for this site as well as a OneDrive site. To accomplish this we&#8217;re going to use the <strong><em>Set-SPOSite</em></strong> cmdlet along with the <strong><em>-ConditionalAccessPolicy</em></strong> Parameter.<br />
&nbsp;</p>
<p>This parameter supports the following inputs:</p>
<ul>
<li>AllowFullAccess: Allows full access from desktop apps, mobile apps, and the web</li>
<li>AllowLimitedAccess: Allows limited, web-only access</li>
<li>BlockAccess: Blocks Access</li>
<li>AuthenticationContext: Assign an Azure AD authentication context. Must add the AuthenticationContextName</li>
</ul>
<pre class="brush: powershell; title: ; notranslate">
$SiteURL = 'https://thesysadminchannel.sharepoint.com/sites/someproject'
$OneDriveURL = 'https://thesysadminchannel-my.sharepoint.com/personal/buzz_thesysadminchannel_com'

Set-SPOSite -Identity $SiteURL -ConditionalAccessPolicy AllowLimitedAccess
Set-SPOSite -Identity $OneDriveURL -ConditionalAccessPolicy AllowLimitedAccess

$SiteURL, $OneDriveURL | ForEach-Object {Get-SPOSite -Identity $_ | select Title, ConditionalAccessPolicy}

Title          ConditionalAccessPolicy
-----          -----------------------
SomeProject         AllowLimitedAccess
Buzz Lightyear      AllowLimitedAccess
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-SPOSite-Conditional-Access-Block.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-SPOSite-Conditional-Access-Block.png" alt="Set SPOSite Conditional Access Block" width="1040" height="387" class="aligncenter size-full wp-image-4855" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-SPOSite-Conditional-Access-Block.png?v=1695488188 1040w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-SPOSite-Conditional-Access-Block-1024x381.png?v=1695488188 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-SPOSite-Conditional-Access-Block-768x286.png?v=1695488188 768w" sizes="(max-width: 1040px) 100vw, 1040px" /></a><br />
&nbsp;</p>
<p>Before you start checking the sites you set the limited access on, note that nothing is limited until we configure the CA policies.  It is strongly recommended that you do thorough testing before enabling this at the tenant level. Once you&#8217;ve done that and you&#8217;re ready to set it as the default, you can do that with another cmdlet.  That cmdlet is <strong><em>Set-SPOTenant</em></strong><br />
&nbsp;</p>
<div id="limitspotenant" style="scroll-margin-top: 10px;"></div>
<h4>Apply at the Tenant Level</h4>
<p>Now that you&#8217;re ready to enable this as the default on the tenant level, there is one thing we need to decide on.  That one thing is whether we want to enforce these restrictions on adhoc recipients. What exactly does that mean you say?<br />
&nbsp;</p>
<p>When the feature is enabled, all external users are going to be in scope of the restrictions and users who are accessing SharePoint Online files with a pass code are going to be blocked.<br />
&nbsp;</p>
<div id="blockquote1">
IMPORTANT:  By default when you set this at the tenant level, a conditional access policy is automatically created and scoped to ALL USERS. If you&#8217;re going to roll this out in stages (e.g. by department) I would suggest you immediately disable that policy and create a new CA policy that is finetuned to your liking.
</div>
<pre class="brush: powershell; title: ; notranslate">
Set-SPOTenant -ConditionalAccessPolicy AllowLimitedAccess -ApplyAppEnforcedRestrictionsToAdHocRecipients: $false
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/SharePoint-Limited-Access-PowerShell.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/SharePoint-Limited-Access-PowerShell.png" alt="SharePoint Limited Access PowerShell" width="860" height="214" class="aligncenter size-full wp-image-4863" /></a><br />
&nbsp;</p>
<p>When completed, we can also check the SharePoint Admin center to see the same thing.<br />
<a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/SharePoint-Limited-Access-gui.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/SharePoint-Limited-Access-gui.png" alt="SharePoint Limited Access gui" width="1356" height="604" class="aligncenter size-full wp-image-4866" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/SharePoint-Limited-Access-gui.png?v=1695492603 1356w, https://thesysadminchannel.com/wp-content/uploads/2023/09/SharePoint-Limited-Access-gui-1024x456.png?v=1695492603 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/09/SharePoint-Limited-Access-gui-768x342.png?v=1695492603 768w" sizes="(max-width: 1356px) 100vw, 1356px" /></a><br />
&nbsp;</p>
<p>Finally, since doing this will automatically create a conditional access policy on our behalf, I would recommend disabling that and crafting one by hand so we can fine tune it to our liking.<br />
<a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Block-Unmanaged-Device-Conditional-Access-Policy.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Block-Unmanaged-Device-Conditional-Access-Policy.png" alt="Block Unmanaged Device Conditional Access Policy" width="1053" height="194" class="aligncenter size-full wp-image-4873" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Block-Unmanaged-Device-Conditional-Access-Policy.png?v=1695493643 1053w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Block-Unmanaged-Device-Conditional-Access-Policy-1024x189.png?v=1695493643 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Block-Unmanaged-Device-Conditional-Access-Policy-768x141.png?v=1695493643 768w" sizes="(max-width: 1053px) 100vw, 1053px" /></a></p>
<div id="limitexo" style="scroll-margin-top: 10px;"></div>
<h2>Limited Browser Access for Exchange Online</h2>
<p>Much like the SharePoint Online scenario, we can also limit browser access for users who are trying to access their email when on an unmanaged device. This setting is done using the OwaMailboxPolicy and is configurable for specific mailboxes or at the tenant level.  Before we take a look at each one, we need to connect to Exchange Online via PowerShell.</p>
<pre class="brush: powershell; title: ; notranslate">
Connect-ExchangeOnline -UserPrincipalName user@domain.com -ShowBanner: $false
</pre>
<p>&nbsp;</p>
<div id="limitexopermailbox" style="scroll-margin-top: 10px;"></div>
<h4>Apply on a Per-Mailbox Basis</h4>
<p>Again, it&#8217;s always a great idea to test on a few people to ensure you&#8217;re able to get the results you want.  There&#8217;s nothing worse than enabling a policy and having to revert back because of incidents that could have very well been avoided if it was properly tested.<br />
&nbsp;</p>
<p>To set the limited access on a few mailboxes we&#8217;re going to need to create a new OwaMailboxPolicy and then set the same conditional access parameter to readonly.<br />
&nbsp;<br />
In case you&#8217;re interested, here is what the supported inputs are for that parameter:</p>
<ul>
<li>Off: No conditional access policy is applied to Outlook on the web. This is the default value</li>
<li>ReadOnly: Users can&#8217;t download attachments to their local computer, and can&#8217;t enable Offline Mode on non-compliant computers. They can still view attachments in the browser</li>
<li>ReadOnlyPlusAttachmentsBlocked: All restrictions from ReadOnly apply, but users can&#8217;t view attachments in the browser</li>
</ul>
<p>&nbsp;</p>
<pre class="brush: powershell; title: ; notranslate">
$OwaPolicy = New-OwaMailboxPolicy -Name LimitAccess
Set-OwaMailboxPolicy -Identity LimitAccess -ConditionalAccessPolicy ReadOnly
Get-OwaMailboxPolicy | select Name, IsDefault, ConditionalAccessPolicy

Name                     IsDefault ConditionalAccessPolicy
----                     --------- -----------------------
OwaMailboxPolicy-Default      True Off
LimitAccess                  False ReadOnly
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy.png" alt="Set OwaMailboxPolicy" width="860" height="249" class="aligncenter size-full wp-image-4876" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy.png?v=1695495316 860w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-768x222.png?v=1695495316 768w" sizes="(max-width: 860px) 100vw, 860px" /></a><br />
&nbsp;</p>
<p>With the OwaMailboxPolicy now created, let&#8217;s apply that policy to a few users so we can do our testing.  To apply we will use the <strong><em>Set-CASMailbox</em></strong> cmdlet.</p>
<pre class="brush: powershell; title: ; notranslate">
Set-CASMailbox darth -OwaMailboxPolicy LimitAccess
Get-CASMailbox darth | select DisplayName, OwaMailboxPolicy

DisplayName OwaMailboxPolicy
----------- ----------------
Darth Vader LimitAccess
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-mailbox.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-mailbox.png" alt="Set OwaMailboxPolicy on mailbox" width="853" height="264" class="aligncenter size-full wp-image-4878" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-mailbox.png?v=1695496064 853w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-mailbox-768x238.png?v=1695496064 768w" sizes="(max-width: 853px) 100vw, 853px" /></a><br />
&nbsp;</p>
<div id="limitexotenant" style="scroll-margin-top: 10px;"></div>
<h4>Apply at the Tenant Level</h4>
<p>After we&#8217;ve tested for a bit, we can now apply this as the default setting at the tenant level.  To accomplish this, we will use the <strong><em>Set-OwaMailboxPolicy</em></strong> and and modify the &#8220;OwaMailboxPolicy-Default&#8221; to use the readonly conditional access policy.<br />
&nbsp;</p>
<pre class="brush: powershell; title: ; notranslate">
Set-OwaMailboxPolicy -Identity OwaMailboxPolicy-Default -ConditionalAccessPolicy ReadOnly
Get-OwaMailboxPolicy | select Name, IsDefault, ConditionalAccessPolicy

Name                     IsDefault ConditionalAccessPolicy
----                     --------- -----------------------
OwaMailboxPolicy-Default      True ReadOnly
LimitAccess                  False ReadOnly
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-Tenant.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-Tenant.png" alt="Set OwaMailboxPolicy on Tenant" width="899" height="231" class="aligncenter size-full wp-image-4880" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-Tenant.png?v=1695578800 899w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Set-OwaMailboxPolicy-on-Tenant-768x197.png?v=1695578800 768w" sizes="(max-width: 899px) 100vw, 899px" /></a><br />
&nbsp;</p>
<div id="blockaccess" style="scroll-margin-top: 10px;"></div>
<h2>Block Unmanaged Devices Using Conditional Access</h2>
<p>If you&#8217;re wondering why nothing has changed after setting the SharePoint or Exchange settings, it&#8217;s because your conditional access policies are the tools that are going to be enforcing these restrictions.  The platform settings are the underlying scoping policies, however the conditional access policies are the overlying restriction setting.  Since we ended up setting both platform restrictions at the tenant level, the users we add (and ONLY those users) in the conditional access policy should have this setting enforced.  Hopefully that clears up any confusion.<br />
&nbsp;</p>
<p>Similar to the default SharePoint policies that were automatically created, there are 2 policies we need to create so we can block unmanaged devices as well as restrict browser access if they&#8217;re not on an IT issued device.  We can use those as rough templates to get us started.<br />
&nbsp;</p>
<p>Within Azure AD:</p>
<ul>
<li>Navigate to Security → Conditional Access → Policies → New Policy</li>
<ul>
<li>Direct Link: <a href="https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/Policies" rel="noopener" target="_blank">Conditional Access Blade</a>
    </ul>
<li><strong>Name</strong>: CA015: Block Unmanaged Devices for All Users</li>
<li>Under Users:</li>
<ul>
<li><strong>Include</strong>: All Users (or smaller groups for testing)</li>
<li><strong>Exclude</strong>: Break glass account, MFA exclude group and all Guest users</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment.png" alt="CA Policy User Assignment" width="959" height="648" class="aligncenter size-full wp-image-4883" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment.png?v=1695584729 959w, https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment-768x519.png?v=1695584729 768w" sizes="(max-width: 959px) 100vw, 959px" /></a></p>
<li>Under Target Resources:</li>
<ul>
<li><strong>Include</strong>: All Cloud Apps (or M365 Apps for testing)</li>
<li><strong>Exclude</strong>: None</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-App-Assignment.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-App-Assignment.png" alt="CA Policy App Assignment" width="959" height="648" class="aligncenter size-full wp-image-4884" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-App-Assignment.png?v=1695584755 959w, https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-App-Assignment-768x519.png?v=1695584755 768w" sizes="(max-width: 959px) 100vw, 959px" /></a></p>
<li>Under Conditions: No Changes needed (or exclude iOS and Android Devices for testing)</li>
<li>Under Grant:</li>
<ul>
<li><strong>Require device to be marked as compliant</strong>: Checked</li>
<li><strong>Require Hybrid Microsoft Entra joined device</strong>: Checked</li>
<li><strong>Require one of the selected controls</strong>: Is selected</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Grant-Control.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Grant-Control.png" alt="CA Policy Grant Control" width="959" height="648" class="aligncenter size-full wp-image-4885" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Grant-Control.png?v=1695584779 959w, https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Grant-Control-768x519.png?v=1695584779 768w" sizes="(max-width: 959px) 100vw, 959px" /></a></p>
<li>Under Sessions: No Changes needed</li>
</ul>
<p>&nbsp;</p>
<div id="restrictaccess" style="scroll-margin-top: 10px;"></div>
<h2>Restrict Browser Access on Unmanaged Devices Using Conditional Access</h2>
<p>Earlier we setup the policies on Exchange Online and SharePoint to be able to limit browser access while using an unmanaged device.  The policy on that platform is set, however, as mentioned earlier, we need to be able to enforce this using conditional access policies.  Let&#8217;s do that now.<br />
&nbsp;</p>
<p>Within Azure AD:</p>
<ul>
<li>Navigate to Security → Conditional Access → Policies → New Policy</li>
<ul>
<li>Direct Link: <a href="https://portal.azure.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/Policies" rel="noopener" target="_blank">Conditional Access Blade</a>
    </ul>
<li><strong>Name</strong>: CA016: Restrict Browser Access to Unmanaged Devices for All Users</li>
<li>Under Users:</li>
<ul>
<li><strong>Include</strong>: All Users (or smaller groups for testing)</li>
<li><strong>Exclude</strong>: Break glass account, MFA exclude group and all Guest users</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment-Restriction.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment-Restriction.png" alt="CA Policy User Assignment Restriction" width="959" height="648" class="aligncenter size-full wp-image-4890" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment-Restriction.png?v=1695601587 959w, https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-User-Assignment-Restriction-768x519.png?v=1695601587 768w" sizes="(max-width: 959px) 100vw, 959px" /></a></p>
<li>Under Target Resources:</li>
<ul>
<li><strong>Include</strong>: Office 365</li>
<li><strong>Exclude</strong>: None</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Target-Resource-Restriction.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Target-Resource-Restriction.png" alt="CA Policy Target Resource Restriction" width="959" height="648" class="aligncenter size-full wp-image-4899" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Target-Resource-Restriction.png?v=1695604471 959w, https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Target-Resource-Restriction-768x519.png?v=1695604471 768w" sizes="(max-width: 959px) 100vw, 959px" /></a></p>
<li>Under Conditions: </li>
<ul>
<li><strong>Client Apps → Browser</strong>: Checked</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Conditions-Client-App-Restriction.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Conditions-Client-App-Restriction.png" alt="CA Policy Conditions Client App Restriction" width="959" height="648" class="aligncenter size-full wp-image-4900" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Conditions-Client-App-Restriction.png?v=1695604502 959w, https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Conditions-Client-App-Restriction-768x519.png?v=1695604502 768w" sizes="(max-width: 959px) 100vw, 959px" /></a></p>
<li>Under Grant: No changes needed</li>
<li>Under Sessions:</li>
<ul>
<li><strong>Use app enforced restrictions</strong>: Checked</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Session-App-Enforced-Restriction.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Session-App-Enforced-Restriction.png" alt="CA Policy Session App Enforced Restriction" width="959" height="648" class="aligncenter size-full wp-image-4901" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Session-App-Enforced-Restriction.png?v=1695604537 959w, https://thesysadminchannel.com/wp-content/uploads/2023/09/CA-Policy-Session-App-Enforced-Restriction-768x519.png?v=1695604537 768w" sizes="(max-width: 959px) 100vw, 959px" /></a>
</ul>
<p>&nbsp;</p>
<div id="extensions" style="scroll-margin-top: 10px;"></div>
<h2>Incognito Mode and Browser Extensions</h2>
<p>One important item to call out is that your users can continue to have issues even though their device is compliant or Hybrid Azure AD Joined.  This is because certain browsers don&#8217;t have the functionality built-in to send the device payload so the CA policy can properly evaluate it.<br />
&nbsp;</p>
<ul>
<li>Edge: Functionality is built-in so testing with Edge is always recommended</li>
<li>Chrome: <a href="https://chrome.google.com/webstore/detail/windows-accounts/ppnbnpeolgkicgegkbkbjmhlideopiji" rel="noopener" target="_blank">Windows 10 accounts extension</a> is required for Chrome v111+</li>
<li>FireFox: <a href="https://support.mozilla.org/en-US/kb/windows-sso" rel="noopener" target="_blank">FireFox Windows SSO</a> is required</li>
<li>Incognito Mode: extensions should be abled for incognito mode as well</li>
</ul>
<p>If you&#8217;re STILL having issues after ensure your device is in the proper state and you have the proper extensions installed, one thing that I&#8217;ve learned is clear the cache and cookies and that resolves most of the issues.<br />
&nbsp;</p>
<div id="conclusion" style="scroll-margin-top: 10px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article on how to limit or restrict browser access to Microsoft 365 apps as well as block unmanaged devices using conditional access was insightful.  This should help add a bit more strength to your overall security posture so that&#8217;s always a good thing.<br />
&nbsp;</p>
<p>This policy is very powerful so you need to make sure you do some thorough testing before enabling the policy globally.  Another policy I would highly recommend is to <a href="https://thesysadminchannel.com/how-to-enable-authentication-strengths-using-azure-ad-conditional-access-policy/" rel="noopener" target="_blank">Enable Authentication Strengths Using Conditional Access</a> so you can set higher profile apps to use phishing resistant MFA.</p>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4839&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;8&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (8 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Block Unmanaged Devices Using Conditional Access&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (8 votes)    </div>
    </div>
<p>The post <a href="https://thesysadminchannel.com/block-unmanaged-devices-using-conditional-access/">Block Unmanaged Devices Using Conditional Access</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/block-unmanaged-devices-using-conditional-access/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4839</post-id>	</item>
		<item>
		<title>Find Account That Sent Emails From Shared Mailbox using PowerShell</title>
		<link>https://thesysadminchannel.com/find-account-that-sent-emails-from-shared-mailbox-using-powershell/</link>
					<comments>https://thesysadminchannel.com/find-account-that-sent-emails-from-shared-mailbox-using-powershell/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Fri, 15 Sep 2023 00:50:54 +0000</pubDate>
				<category><![CDATA[Exchange Online]]></category>
		<category><![CDATA[check who sent email from shared mailbox]]></category>
		<category><![CDATA[Find User Who Sent Email From Shared Mailbox]]></category>
		<category><![CDATA[how to see who sent an email from a shared mailbox]]></category>
		<category><![CDATA[shared mailbox sendas permission audit]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4678</guid>

					<description><![CDATA[<p>In a world where email is one of our main methods of communication for business use, having the ability to send emails as a &#8220;generic user&#8221; or shared mailbox helps us hide behind a proxy when needed. While this is&#8230; <a href="https://thesysadminchannel.com/find-account-that-sent-emails-from-shared-mailbox-using-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/find-account-that-sent-emails-from-shared-mailbox-using-powershell/">Find Account That Sent Emails From Shared Mailbox using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In a world where email is one of our main methods of communication for business use, having the ability to send emails as a &#8220;generic user&#8221; or shared mailbox helps us hide behind a proxy when needed.  While this is great in most cases, sometimes we need to know who is the actual person that is sending emails as the shared mailbox.  Today we&#8217;re going to go over the method on how to find the account that sent emails from shared mailbox.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#permissions">Get Recipient Permissions to See Who Has Access</a></li>
<li><a href="#findaccount">Find Account That Sent Emails From Shared Mailbox</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 have successful results, you will need the following.</p>
<ul>
<li>Exchange Administrator Permissions -or Global Administrator Permissions</li>
<li>Audit Logs Enabled.  Specifically Mailbox Audit logs</li>
<li>Exchange Online Management PowerShell Module</li>
</ul>
<p>&nbsp;</p>
<div id="permissions" style="scroll-margin-top: 15px;"></div>
<h2>Get Recipient Permissions to See Who Has Access</h2>
<p>Before we dive deep into the logs, I always like to narrow down my search by simply seeing who has access to send as that specific account.  If there are only 1-2 users who have access, this narrows things down pretty well.  If there are a dozen or more, then things might get a little tricky and we&#8217;ll need to go into logs.<br />
&nbsp;</p>
<p>Let&#8217;s check to see who has permissions and see if we get lucky.  To find this, we&#8217;re going to use the <a href="https://learn.microsoft.com/en-us/powershell/module/exchange/get-recipientpermission?view=exchange-ps" rel="noopener" target="_blank">Get-RecipientPermission</a> cmdlet from the ExchageOnlineManagement module. </p>
<pre class="brush: powershell; title: ; notranslate">
Get-RecipientPermission testmailbox -AccessRights SendAs | Where-Object {$_.Trustee -ne 'NT AUTHORITY\SELF'}

Identity     Trustee                     AccessControlType AccessRights Inherited
--------     -------                     ----------------- ------------ ---------
Test Mailbox paul@thesysadminchannel.com Allow             {SendAs}     False
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-Recipient-Permissions.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-Recipient-Permissions.png" alt="Get Recipient Permissions" width="1097" height="229" class="aligncenter size-full wp-image-4824" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-Recipient-Permissions.png?v=1694735770 1097w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-Recipient-Permissions-1024x214.png?v=1694735770 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Get-Recipient-Permissions-768x160.png?v=1694735770 768w" sizes="(max-width: 1097px) 100vw, 1097px" /></a><br />
&nbsp;</p>
<p>In some scenarios it very well may be possible that the account itself sent the email, but for the sake of this article we&#8217;re going to assume someone sent an email with the sendas permissions.  Therefore we added the where clause to not include SELF.</p>
<div id="findaccount" style="scroll-margin-top: 15px;"></div>
<h2>Find Account That Sent Emails From Shared Mailbox</h2>
<p>In the example above, we can see that only one account has access to send as the shared mailbox so it&#8217;s pretty much a no brainer in this scenario.  However, as I mentioned before, some shared mailboxes (or regular mailboxes for that matter) can have multiple people with this access right.<br />
&nbsp;</p>
<p>In order to find the exact user, let&#8217;s look to the logs and see what they say.  Logs never lie!</p>
<pre class="brush: powershell; title: ; notranslate">
$SendAs = Search-MailboxAuditLog -Identity testmailbox -Operations SendAs -ShowDetails
$Sendas | select LogonUserDisplayName, ClientProcessName, ItemSubject, OperationResult, LastAccessed


LogonUserDisplayName : Paul Contreras
ClientProcessName    :
ItemSubject          : The Force
OperationResult      : Succeeded
LastAccessed         : 9/14/2023 8:37:38 PM
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/09/Search-Mailbox-Audit-Log.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/09/Search-Mailbox-Audit-Log.png" alt="Search Mailbox Audit Log - Sent Emails From Shared Mailbox" width="988" height="249" class="aligncenter size-full wp-image-4827" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/09/Search-Mailbox-Audit-Log.png?v=1694736549 988w, https://thesysadminchannel.com/wp-content/uploads/2023/09/Search-Mailbox-Audit-Log-768x194.png?v=1694736549 768w" sizes="(max-width: 988px) 100vw, 988px" /></a><br />
&nbsp;</p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>In this case the recipient permissions pretty much gave it away as I was the only one with permissions.  However, being able to search in the mailbox audit logs will show us EXACTLY which was the account that sent this email.  Hopefully this was informative for you and you&#8217;re able to find out who sent emails from shared mailbox.</p>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4678&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;4&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (4 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Find Account That Sent Emails From Shared Mailbox using PowerShell&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (4 votes)    </div>
    </div>
<p>The post <a href="https://thesysadminchannel.com/find-account-that-sent-emails-from-shared-mailbox-using-powershell/">Find Account That Sent Emails From Shared Mailbox using PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/find-account-that-sent-emails-from-shared-mailbox-using-powershell/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4678</post-id>	</item>
		<item>
		<title>Get Synced OU Configuration in Azure AD Connect PowerShell</title>
		<link>https://thesysadminchannel.com/get-synced-ou-configuration-in-azure-ad-connect-powershell/</link>
					<comments>https://thesysadminchannel.com/get-synced-ou-configuration-in-azure-ad-connect-powershell/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Sun, 28 May 2023 19:27:56 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[OU Configuration in Azure AD Connect]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4805</guid>

					<description><![CDATA[<p>If you manage a hybrid environment, chances are you&#8217;ve had to manage Azure AD Connect. Getting the configuration settings via the GUI is pretty nice to get, but opening the wizard prevents you from syncing so sometimes it may not&#8230; <a href="https://thesysadminchannel.com/get-synced-ou-configuration-in-azure-ad-connect-powershell/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/get-synced-ou-configuration-in-azure-ad-connect-powershell/">Get Synced OU Configuration in Azure AD Connect PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>If you manage a hybrid environment, chances are you&#8217;ve had to manage Azure AD Connect. Getting the configuration settings via the GUI is pretty nice to get, but opening the wizard prevents you from syncing so sometimes it may not be possible.  Today we&#8217;re going to show you a snippet so you can export the OU Configuration in Azure AD Connect in your environment.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#ouconfig">Get Synced OU Configuration in Azure AD Connect using PowerShell</a></li>
<li><a href="#attributeconfig">Get Synced Attributes 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>In order for you to get all of the synced organizational units as well as the synced attributes, there are a few things you must have in place.  First things first, you need to have a supported version of Azure AD Connect installed.  Since AAD Connect should be in a tier 0 security configuration, you may need to run this locally on the machine itself.</p>
<div id="ouconfig" style="scroll-margin-top: 15px;"></div>
<h2>Get Synced OU Configuration in Azure AD Connect using PowerShell</h2>
<p>If you have an Active Directory OU structure that&#8217;s pretty dense it may be challenging to figure out what exactly is being synced and what is not.  My lab is pretty simple and straight forward but here are the organizational units that are synced and what&#8217;s shown from the GUI.</p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-GUI.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-GUI.png" alt="Get Synced OU Configuration in Azure AD Connect GUI" width="880" height="620" class="aligncenter size-full wp-image-4811" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-GUI.png?v=1685299311 880w, https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-GUI-768x541.png?v=1685299311 768w" sizes="(max-width: 880px) 100vw, 880px" /></a></p>
<p>&nbsp;<br />
Let&#8217;s get this same information from PowerShell.  Remember you will need to be logged in to the active AAD Connect server since that&#8217;s what is actually being synced to Azure AD.</p>
<pre class="brush: powershell; title: ; notranslate">
#Get Connect information for your on-premises domain.
$SyncConnector = Get-ADSyncConnector | Where-Object {$_.Name -notmatch ' - aad'}

#Get OU inclusion list
$SyncConnector.Partitions.ConnectorPartitionScope.ContainerInclusionList

#Get OU exclusion list
$SyncConnector.Partitions.ConnectorPartitionScope.ContainerExclusionList
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-PowerShell.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-PowerShell.png" alt="Get Synced OU Configuration in Azure AD Connect PowerShell" width="850" height="356" class="aligncenter size-full wp-image-4813" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-PowerShell.png?v=1685299521 850w, https://thesysadminchannel.com/wp-content/uploads/2023/05/Get-Synced-OU-Configuration-in-Azure-AD-Connect-PowerShell-768x322.png?v=1685299521 768w" sizes="(max-width: 850px) 100vw, 850px" /></a><br />
&nbsp;</p>
<p>As you can see from the images above, the only OU I am syncing to Azure AD is the &#8220;Home&#8221; OU.  I do have a few sub organizational units that are excluded from sync and that&#8217;s also shown in the PowerShell image.  Hopefully this will paint a pretty picture when you need to see which OUs are synced.</p>
<div id="attributeconfig" style="scroll-margin-top: 15px;"></div>
<h2>Get Synced Attributes using PowerShell</h2>
<p>If you need to get what attributes are syncing, there&#8217;s a way to get that information using PowerShell as well.  Not all attributes will show with an Azure AD attribute, but this is a good start to see what&#8217;s there and what&#8217;s not.<br />
&nbsp;</p>
<p>It is important to note that attributes syncing from your on-premises Active Directory will not show up exactly the same in Azure AD.  Therefore, we will show the on-premises sync connector as well as the Azure AD sync connector.  This is key if you have custom mappings or have enabled directory extension attributes to use for custom claims.</p>
<pre class="brush: powershell; title: ; notranslate">
#Get attributes syncing from on-premises Active Directory
$SyncConnector = Get-ADSyncConnector | Where-Object {$_.Name -notmatch ' - aad'}
$SyncConnector.AttributeInclusionList


#Get attributes syncing to Azure Active Directory
$SyncConnector = Get-ADSyncConnector | Where-Object {$_.Name -match ' - aad'}
$SyncConnector.AttributeInclusionList
</pre>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Onprem.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Onprem.png" alt="Attribtue Configuration in Azure AD Connect Onprem" width="854" height="336" class="aligncenter size-full wp-image-4815" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Onprem.png?v=1685301017 854w, https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Onprem-768x302.png?v=1685301017 768w" sizes="(max-width: 854px) 100vw, 854px" /></a></p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Cloud.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Cloud.png" alt="Attribtue Configuration in Azure AD Connect Cloud" width="850" height="336" class="aligncenter size-full wp-image-4816" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Cloud.png?v=1685301027 850w, https://thesysadminchannel.com/wp-content/uploads/2023/05/Attribtue-Configuration-in-Azure-AD-Connect-Cloud-768x304.png?v=1685301027 768w" sizes="(max-width: 850px) 100vw, 850px" /></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 get synced OU configuration in Azure AD Connect PowerShell as well as the attributes that are currently synced.  This is pretty handy because when you open up the Azure AD Connect application, sync is temporarily disabled until the wizard is closed.<br />
&nbsp;</p>
<p>Being able to gather this information using PowerShell helps solve that problem so you can run it at anytime.  If you would like to see more sysadmin content, be sure to check out our <a href="https://www.youtube.com/c/theSysadminChannel" rel="noopener" target="_blank">YouTube Channel</a></p>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4805&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;5&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (5 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Get Synced OU Configuration in Azure AD Connect PowerShell&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (5 votes)    </div>
    </div>
<p>The post <a href="https://thesysadminchannel.com/get-synced-ou-configuration-in-azure-ad-connect-powershell/">Get Synced OU Configuration in Azure AD Connect PowerShell</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/get-synced-ou-configuration-in-azure-ad-connect-powershell/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4805</post-id>	</item>
		<item>
		<title>Create Custom Extensions in Entra Identity Governance</title>
		<link>https://thesysadminchannel.com/create-custom-extensions-in-identity-governance/</link>
					<comments>https://thesysadminchannel.com/create-custom-extensions-in-identity-governance/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Fri, 31 Mar 2023 22:28:13 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Logic Apps]]></category>
		<category><![CDATA[azure ad custom extensions]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4629</guid>

					<description><![CDATA[<p>Microsoft recently released a feature to create custom extensions in Entra Identity Governance that can allow users to kick off custom processes using Logic Apps. If you&#8217;re not familiar with what a Logic App is, it is a low code/no&#8230; <a href="https://thesysadminchannel.com/create-custom-extensions-in-identity-governance/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/create-custom-extensions-in-identity-governance/">Create Custom Extensions in Entra Identity Governance</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Microsoft recently released a feature to create custom extensions in Entra Identity Governance that can allow users to kick off custom processes using Logic Apps. If you&#8217;re not familiar with what a Logic App is, it is a low code/no code integration automation platform that allows you to run processes on a server-less framework.<br />
&nbsp;</p>
<p>This is great because Logic Apps can provide an endless possibility of automation workflows using built-in connectors. If you prefer to run code to handle the automation, there&#8217;s a connector for Azure Automation and even Function Apps.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#createextension">Create A Custom Extension for a Catalog</a></li>
<li><a href="#importextension">Import an Existing Custom Extension on a Different Catalog</a></li>
<li><a href="#viewlogicapp">View The Logic App And Create A Workflow</a></li>
<li><a href="#applyextension">Apply the Extension to an Access Package</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ul>
</div>
<div id="requirements" style="scroll-margin-top: 15px;"></div>
<h2>Requirements</h2>
<p>Whether you&#8217;re creating the very first custom extension or adding additional extensions to your catalog, there are a few things in place you will need so everything runs smoothly.  Let&#8217;s touch on those items now.<br />
&nbsp;</p>
<p>First things first, you&#8217;ll need to have an Azure Resource Group created so you can host your newly created Logic Apps. It would be preferred to be an owner of that RG so you can grant permissions to the Managed Identities you will eventually create with your LA.<br />
&nbsp;</p>
<p>If you prefer to use Logic Apps as the conduit to other automation platforms like Azure Automation or Function Apps, the Logic App Managed Identity will need the appropriate permissions to that resource.  For these use cases, I personally like to have my Logic Apps, Function Apps and automation runbooks under the same resource group.</p>
<div id="createextension" style="scroll-margin-top: 15px;"></div>
<h2>Create The First Custom Extension</h2>
<p>If this is the first time you&#8217;ve ever created a custom extension for an Entitlement Management access package then you&#8217;re definitely in luck.  We&#8217;ll walk through the steps on exactly how to do that.<br />
&nbsp;<br />
Within the Catalog:</p>
<ul>
<li>Click on Custom extensions</li>
<li>Add a new custom extension</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-1.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-1.png" alt="Custom Extension 1" width="1324" height="492" class="aligncenter size-full wp-image-4759" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-1.png?v=1679797995 1324w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-1-1024x381.png?v=1679797995 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-1-768x285.png?v=1679797995 768w" sizes="(max-width: 1324px) 100vw, 1324px" /></a><br />
&nbsp;</p>
<ul>
<li>Enter a name and description that best describes what the custom extension will be doing</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-2.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-2.png" alt="Custom Extension 2" width="1255" height="609" class="aligncenter size-full wp-image-4760" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-2.png?v=1679798103 1255w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-2-1024x497.png?v=1679798103 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-2-768x373.png?v=1679798103 768w" sizes="(max-width: 1255px) 100vw, 1255px" /></a><br />
&nbsp;</p>
<ul>
<li>Select the option if you want to run the request workflow or pre-expiration</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_3.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_3.png" alt="Custom Extension_3" width="951" height="545" class="aligncenter size-full wp-image-4765" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_3.png?v=1679798862 951w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_3-768x440.png?v=1679798862 768w" sizes="(max-width: 951px) 100vw, 951px" /></a><br />
&nbsp;</p>
<ul>
<li>Select the option if you want to launch and continue or launch and wait</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-4.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-4.png" alt="Custom Extension 4" width="1292" height="582" class="aligncenter size-full wp-image-4762" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-4.png?v=1679798333 1292w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-4-1024x461.png?v=1679798333 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-4-768x346.png?v=1679798333 768w" sizes="(max-width: 1292px) 100vw, 1292px" /></a><br />
&nbsp;</p>
<ul>
<li>Select Yes to create a logic app</li>
<li>Select the Azure subscription and resource group</li>
<li>Enter a name that describes the process (I like to have the same name as the extension)</li>
<li>Click create a logic app</li>
<li>Click next to review and create</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-5.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-5.png" alt="Custom Extension 5" width="1255" height="687" class="aligncenter size-full wp-image-4763" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-5.png?v=1679798537 1255w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-5-1024x561.png?v=1679798537 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-5-768x420.png?v=1679798537 768w" sizes="(max-width: 1255px) 100vw, 1255px" /></a><br />
&nbsp;</p>
<div id="importextension" style="scroll-margin-top: 15px;"></div>
<h2>Importing a Custom Extension on a Different Catalog</h2>
<p>Organizing your catalogs by processes or by teams is important for keeping everything in order, but what if you wanted to use the same workflow on a different catalog?  By default there is not an &#8220;import&#8221; button that can magically create the same custom extension on a different catalog, however it is possible by simply creating a new extension on the catalog you want to run that Logic App in.<br />
&nbsp;</p>
<p>The steps to accomplish that are pretty much the same as above.  You&#8217;ll need to create a custom extension, populate the fields just as you did before.  The difference is in the details.  Let&#8217;s take that a step further.</p>
<p>In the new catalog, under the details tab:</p>
<ul>
<li>Select no to create a logic app</li>
<li>Select the same subscription and resource group that the Logic App is hosted in</li>
<li>Under the Logic App drop down menu, select the previously created LA</li>
<li>Select next to review and create</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-7.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-7.png" alt="Custom Extension 7" width="1043" height="621" class="aligncenter size-full wp-image-4769" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-7.png?v=1679808597 1043w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-7-1024x610.png?v=1679808597 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-7-125x75.png?v=1679808597 125w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-7-768x457.png?v=1679808597 768w" sizes="(max-width: 1043px) 100vw, 1043px" /></a></p>
<div id="viewlogicapp" style="scroll-margin-top: 15px;"></div>
<h2>View The Logic App And Create A Workflow</h2>
<p>Now that we know how to create and import an existing custom extension created by Entitlement Management, let&#8217;s look into accessing it so we can outline what exactly we want it to do.<br />
&nbsp;</p>
<p>On the custom extensions page, click on the link to the Logic App.<br />
<a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-6-.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-6-.png" alt="" width="1292" height="465" class="aligncenter size-full wp-image-4783" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-6-.png?v=1680293592 1292w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-6--1024x369.png?v=1680293592 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-6--768x276.png?v=1680293592 768w" sizes="(max-width: 1292px) 100vw, 1292px" /></a><br />
&nbsp;</p>
<p>This should take you to the Logic App itself where you can modify everything as needed.  We won&#8217;t cover the details of the logic app workflow here since that&#8217;s a whole another platform to discuss, however, I will note that there have been significant improvements for the overall process.<br />
&nbsp;</p>
<p>Not only is it much more secure (we&#8217;ll touch on that in a bit), but there are also many more properties available in the payload going to the logic app. An example of this is if you&#8217;re asking questions in the package, the answers are now available by default.<br />
<a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_9.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_9.png" alt="Custom Extension 9" width="1032" height="643" class="aligncenter size-full wp-image-4790" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_9.png?v=1680296636 1032w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_9-1024x638.png?v=1680296636 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension_9-768x479.png?v=1680296636 768w" sizes="(max-width: 1032px) 100vw, 1032px" /></a><br />
&nbsp;</p>
<p>Regarding the security improvements, this is fantastic because it now uses an Azure AD Proof-of-Possession token that mitigates against token theft.  Here is a snippet from the <a href="https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Proof-Of-Possession-(PoP)-tokens" rel="noopener" target="_blank">GitHub Page</a><br />
<a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Proof-of-possession-token-snippnet.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Proof-of-possession-token-snippnet.png" alt="Proof of possession token snippet" width="911" height="295" class="aligncenter size-full wp-image-4785" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Proof-of-possession-token-snippnet.png 911w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Proof-of-possession-token-snippnet-768x249.png 768w" sizes="(max-width: 911px) 100vw, 911px" /></a><br />
&nbsp;</p>
<p>If you click on the Authorization page on the left pane, you can see how it&#8217;s setup. Here&#8217;s an outline of what mine looks like. <em>Note: This is added by default so no need to modify anything 🙂</em><br />
<a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-10.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-10.png" alt="Custom Extension 10" width="1047" height="630" class="aligncenter size-full wp-image-4792" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-10.png?v=1680297137 1047w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-10-1024x616.png?v=1680297137 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-10-125x75.png?v=1680297137 125w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-10-768x462.png?v=1680297137 768w" sizes="(max-width: 1047px) 100vw, 1047px" /></a></p>
<div id="applyextension" style="scroll-margin-top: 15px;"></div>
<h2>Apply the Logic App to an Access Package</h2>
<p>Assuming you&#8217;ve already done the work to update the logic app to your liking, we&#8217;re now in a place where we can apply the the custom extension to an access package so let&#8217;s touch on how to do that.<br />
&nbsp;</p>
<p>First, You&#8217;ll need to create an access package along with the assignment policy under the catalog where you&#8217;ve created/imported your logic app.  At the end of the wizard you should see the option to add a custom extension.</p>
<p>Those specific stages are:</p>
<ul>
<li>Request is created</li>
<li>Request is approved</li>
<li>Assignment is granted</li>
<li>Assignment is about to expire in 14 days</li>
<li>Assignment is about to expire in 1 day</li>
<li>Assignment is removed</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-11.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-11.png" alt="Custom Extension 11" width="845" height="649" class="aligncenter size-full wp-image-4794" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-11.png?v=1680298381 845w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Custom-Extension-11-768x590.png?v=1680298381 768w" sizes="(max-width: 845px) 100vw, 845px" /></a><br />
&nbsp;</p>
<p>Each stage has its purpose so you definitely have the flexibility extend a process around a specific stage.  In my sample above, I set the action to run EM Cool Process to run when assignment has been granted.</p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully you now have a great understanding on how to create custom extensions in Entra Identity Governance. As someone who uses this in the real world, this is one of the features I love the most about Azure AD because it&#8217;s so versatile and allows you to implement a self service framework without the hassle of maintaining a frontend or backend.  It&#8217;s built into the tool.</p>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4629&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;5&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (5 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Create Custom Extensions in Entra Identity Governance&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (5 votes)    </div>
    </div>
<p>The post <a href="https://thesysadminchannel.com/create-custom-extensions-in-identity-governance/">Create Custom Extensions in Entra Identity Governance</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/create-custom-extensions-in-identity-governance/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4629</post-id>	</item>
		<item>
		<title>Securely Reduce MFA Prompts in Azure AD</title>
		<link>https://thesysadminchannel.com/reduce-mfa-prompts-in-azure-ad/</link>
					<comments>https://thesysadminchannel.com/reduce-mfa-prompts-in-azure-ad/#respond</comments>
		
		<dc:creator><![CDATA[Paul Contreras]]></dc:creator>
		<pubDate>Sun, 05 Mar 2023 04:24:08 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Azure MFA keeps prompting your users]]></category>
		<category><![CDATA[MFA prompt frequency best practices]]></category>
		<category><![CDATA[Office 365 MFA prompts every time]]></category>
		<category><![CDATA[Reduce MFA prompts in Azure AD]]></category>
		<guid isPermaLink="false">https://thesysadminchannel.com/?p=4709</guid>

					<description><![CDATA[<p>In this day and age, it is imperative that organizations enforce MFA to enhance their security posture. As threat actors become equipped with more sophisticated tools, we need to ensure we enforce strong authentication requirements for all users, all the&#8230; <a href="https://thesysadminchannel.com/reduce-mfa-prompts-in-azure-ad/" class="more-link">Continue Reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://thesysadminchannel.com/reduce-mfa-prompts-in-azure-ad/">Securely Reduce MFA Prompts in Azure AD</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>In this day and age, it is imperative that organizations enforce MFA to enhance their security posture.  As threat actors become equipped with more sophisticated tools, we need to ensure we enforce strong authentication requirements for all users, all the time. However, more MFA prompts does not equate to better security.  In fact it is quite the opposite, but we&#8217;ll touch on that later.  Today we&#8217;re going to cover how to <strong>securely reduce MFA Prompts in Azure AD</strong>.</p>
<div id="tableofcontents">
<h2>Table Of Contents</h2>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#whatnottodo">The Don’ts. What NOT to do if Azure MFA Keeps Prompting</a></li>
<li><a href="#analytics">Authentication Prompts Analysis: See Whos Is Getting Prompted for MFA</a></li>
<li><a href="#reduceprompts">How to Reduce MFA Prompts in Azure AD</a></li>
<ul>
<li><a href="#wh4b">Windows Hello for Business</a></li>
<li><a href="#chromeextension">Windows 10 Accounts Chrome extension</a></li>
<li><a href="#macsso">Enterprise SSO for Apple Devices</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>If you&#8217;ve implemented MFA across the entire org or you&#8217;re just about to go down that path it is important to know there are tools and licenses you should have in place to make the experience a much better one.  Let&#8217;s touch on those a bit now.<br />
&nbsp;</p>
<p>While Azure AD P2 licenses are preferred, having a P1 license will grant you access to conditional policies, Log Analytics and other Azure AD features. Technically all you need is a single P2 license to enable these features however, all users that are using the features should be licensed for it.</p>
<div id="whatnottodo" style="scroll-margin-top: 15px;"></div>
<h2>What NOT to do if Azure MFA Keeps Prompting</h2>
<p>Before we go into detail on what MFA prompt frequency best practices are and what we can do suppress them, let&#8217;s take some time to discuss what we should NOT be doing.  These &#8220;don&#8217;ts&#8221; are called out because of the security implications it can have on your AAD environment.<br />
&nbsp;</p>
<p>I see it time and time again when scrolling through Twitter, Reddit or other articles, people recommend whitelisting their office public IP addresses as a way to bypass MFA.  After all, if you&#8217;re in a building that probably requires a badge to gain access, we should be good right?  WRONG!<br />
&nbsp;</p>
<p>Tailgating does happen in the wild and if you set policies to bypass MFA for people in the office, you have effectively punched security holes into your environment.  Aside from that, many office buildings have guest wi-fi networks for their visitors that someone can easily connect to. If the guest network is configured to use the same outbound public IP as the corporate network, you&#8217;ve just opened yourself up to a potential world of hurt. If that still doesn&#8217;t convince you, figuring out how to spoof a public IP address is just a Google search away so these methods should be avoided at all costs.<br />
&nbsp;</p>
<p>Another setting we want to avoid is to keep the &#8220;remember multi-factor authentication on trusted device&#8221; setting enabled in the <a href="https://account.activedirectory.windowsazure.com/UserManagement/MfaSettings.aspx" rel="noopener" target="_blank">legacy Azure service settings portal</a>. While it does what it says and reduces the number of MFA prompts you will get, it is not the best approach for what we are trying to accomplish.  Microsoft also calls this out on their documentation.</p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/remember-my-device-mfa-setting.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/remember-my-device-mfa-setting.png" alt="remember my device mfa setting to reduce MFA Prompts in Azure AD" width="888" height="392" class="aligncenter size-full wp-image-4717" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/remember-my-device-mfa-setting.png 888w, https://thesysadminchannel.com/wp-content/uploads/2023/03/remember-my-device-mfa-setting-768x339.png 768w" sizes="(max-width: 888px) 100vw, 888px" /></a><br />
&nbsp;</p>
<p>I should also mention that requiring an MFA prompt for every sign in, or otherwise purposely overly prompting for MFA can be just as bad.  When someone is constantly getting prompted for MFA, they tend to become numb to the process and mindlessly hit approve. There are ways to mitigate MFA fatigue attacks by implementing MFA number matching but the point still stands.  More MFA prompts does not equate to more security.<br />
&nbsp;</p>
<p>To summarize, here is what we should NOT be doing to reduce MFA prompts in Azure AD:</p>
<ul>
<li>Do NOT whitelist public IPs to bypass MFA</li>
<li>Do NOT enable remember multi-factor authentication on trusted device</li>
<li>Do NOT purposely over prompt for MFA</li>
</ul>
<div id="analytics" style="scroll-margin-top: 15px;"></div>
<h2>Authentication Prompts Analysis: See Whos Is Getting Prompted for MFA</h2>
<p>Azure AD is a platform that can be used as a 100% cloud only solution for your users, or a hybrid solution if you&#8217;re still maintaining an On-Premises environment.  With that said, it also comes equipped with its own audit logging and monitoring tools (when you have Azure AD P1/P2 licenses) so we can use Azure AD workbooks to get insights on who is actually getting prompted for MFA and what applications are prompting them.<br />
&nbsp;</p>
<p>Azure AD has done all of the hard work for you and conveniently created an authentication prompts analysis workbook.<br />
To access it:</p>
<ul>
<li>Navigate to Azure AD → Workbooks</li>
<li>Select Authentication Prompts Analysis workbook</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-Analysis-workbook.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-Analysis-workbook.png" alt="Authentication Prompts Analysis workbook" width="1634" height="645" class="aligncenter size-full wp-image-4719" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-Analysis-workbook.png 1634w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-Analysis-workbook-1024x404.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-Analysis-workbook-768x303.png 768w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-Analysis-workbook-1536x606.png 1536w" sizes="(max-width: 1634px) 100vw, 1634px" /></a><br />
&nbsp;</p>
<p>If you have time I would highly suggest you take a look at the data.  My only suggestion for the workbook would be that they remove &#8220;Windows Sign In&#8221; attempts since that can kind of skew the data.  Windows Sign In is when a user signs in their Windows device so this will not require MFA. However, the workbook lays out several categories for prompts. </p>
<p>Those include:</p>
<ul>
<li>Authentication prompts by authentication method</li>
<li>Authentication prompts by device</li>
<li>Authentication prompts by user</li>
<li>Authentication prompts by application</li>
<li>Authentication prompts by process detail</li>
</ul>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-by-Application.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-by-Application.png" alt="Authentication Prompts by Application" width="1100" height="485" class="aligncenter size-full wp-image-4722" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-by-Application.png 1100w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-by-Application-1024x451.png 1024w, https://thesysadminchannel.com/wp-content/uploads/2023/03/Authentication-Prompts-by-Application-768x339.png 768w" sizes="(max-width: 1100px) 100vw, 1100px" /></a></p>
<div id="reduceprompts" style="scroll-margin-top: 15px;"></div>
<h2>How to Reduce MFA Prompts in Azure AD</h2>
<p>Now that we&#8217;ve covered who is getting prompted for MFA and more importantly, what NOT to do, let&#8217;s focus on what we should be doing and the <strong>best practices for how to reduce MFA prompts in Azure AD</strong>. Remember, Azure AD is the Identity Provider (IdP) so this applies to all Azure AD cloud applications.  If Office 365 MFA prompts every time, this will ensure the prompts are significantly lowered when implemented successfully.</p>
<div id="wh4b" style="scroll-margin-top: 15px;"></div>
<h3>Windows Hello for Business</h3>
<p>If you&#8217;re looking for best practices to reduce MFA Prompts in Azure AD, Windows Hello for Business is by far the BEST way to securely accomplish this. With Windows Hello for Business enabled, you&#8217;re always using strong authentication and the MFA claims are satisfied automatically.<br />
&nbsp;</p>
<p>This is because when you sign in with WH4B, a Primary Refresh Token (PRT) gets generated at that initial sign in and is presented to all other Azure AD applications when they&#8217;re accessed. This allows for a truly seamless SSO experience and even better, it provides a fantastic user experience. If you&#8217;ve never heard of a PRT, I would highly suggest you take the time to learn more about <a href="https://learn.microsoft.com/en-us/azure/active-directory/devices/concept-primary-refresh-token" rel="noopener" target="_blank">Primary Refresh Tokens</a>. The documentation for this is phenomenal.<br />
&nbsp;</p>
<div id="blockquote1">
If you manage a hybrid environment, be sure to take a look at our guide on <a href="https://thesysadminchannel.com/how-to-enable-windows-hello-for-business-cloud-trust/" rel="noopener" target="_blank">How To Enable Windows Hello for Business Cloud Trust</a>.
</div>
<div id="chromeextension" style="scroll-margin-top: 15px;"></div>
<h3>Windows 10 Accounts Chrome extension</h3>
<p>While Edge handles this capability natively in the browser, It strongly recommended that those hard chargers using Google Chrome have the Windows 10 Accounts Chrome extensions deployed on their machine.  If you are NOT using Windows Hello for Business, you will need to MFA to that initial application which will create a PRT that can be used on any subsequent applications.<br />
&nbsp;</p>
<p>If you ARE using WH4B, you will still need to deploy this plugin because Chrome doesn&#8217;t natively support a Primary Refresh Token. As an optional step, you can enable this in incognito mode so users can continue to use their PRT while in private-mode.  Again, Microsoft Edge handles this natively but this is good to know.<br />
&nbsp;</p>
<p>Finally, and probably more importantly, in order to successfully create PRT, the devices will need to be at a minimum Azure AD registered. Non registered devices will not be given a PRT so those devices will continue to be prompted.</p>
<div id="macsso" style="scroll-margin-top: 15px;"></div>
<h3>Enterprise SSO for Apple Devices</h3>
<p>We&#8217;ve covered what to do for Windows devices, but what is the recommendation for MacOS and iOS devices?  After all, it is quite common to see an organization operate with a mix of Apple, Windows and Linux devices in their environment. The answer is <a href="https://learn.microsoft.com/en-us/azure/active-directory/develop/apple-sso-plugin" rel="noopener" target="_blank">Enterprise SSO for Apple devices</a>. There a few requirements that are listed in the documentation so we&#8217;ll summarize that here.<br />
&nbsp;</p>
<p><a href="https://thesysadminchannel.com/wp-content/uploads/2023/03/MDM-requirements.png" target="_blank" rel="noopener"><img decoding="async" src="https://thesysadminchannel.com/wp-content/uploads/2023/03/MDM-requirements.png" alt="MDM requirements Reduce MFA Prompts in Azure AD for Apple devices" width="906" height="241" class="aligncenter size-full wp-image-4729" srcset="https://thesysadminchannel.com/wp-content/uploads/2023/03/MDM-requirements.png 906w, https://thesysadminchannel.com/wp-content/uploads/2023/03/MDM-requirements-768x204.png 768w" sizes="(max-width: 906px) 100vw, 906px" /></a><br />
&nbsp;</p>
<p>An important item to note is if your primary MDM solution is not Microsoft Intune, you will need to deploy the SSO extension AND ensure your device is enrolled in Intune.  It doesn&#8217;t have to be managed by Intune, but it must be enrolled so Azure can see the device.</p>
<div id="conclusion" style="scroll-margin-top: 15px;"></div>
<h2>Conclusion</h2>
<p>Hopefully this article was able to provide useful insight on how to reduce the number of MFA prompts using secure best practices. Remember, the goal is to require strong authentication all the time, on every application.  However, the trick is to use these methods listed above so MFA requirements are satisfied and you&#8217;re no longer being prompted.<br />
&nbsp;</p>
<p>I personally use Windows Hello for Business and I am prompted once every several months on my standard account because my MFA requirement is already satisfied by claim in the token.</p>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4709&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;5&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (5 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Securely Reduce MFA Prompts in Azure AD&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (5 votes)    </div>
    </div>
<p>The post <a href="https://thesysadminchannel.com/reduce-mfa-prompts-in-azure-ad/">Securely Reduce MFA Prompts in Azure AD</a> appeared first on <a href="https://thesysadminchannel.com">the Sysadmin Channel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://thesysadminchannel.com/reduce-mfa-prompts-in-azure-ad/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">4709</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>


<div class="kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom"
    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;4676&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;6&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;Rate this post&quot;,&quot;legend&quot;:&quot;5\/5 - (6 votes)&quot;,&quot;size&quot;:&quot;20&quot;,&quot;title&quot;:&quot;Get Application Certificate and Secret Expiration with Graph API&quot;,&quot;width&quot;:&quot;122.5&quot;,&quot;_legend&quot;:&quot;{score}\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>
            
<div class="kksr-stars">
    
<div class="kksr-stars-inactive">
            <div class="kksr-star" data-star="1" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="2" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="3" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="4" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" data-star="5" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
    
<div class="kksr-stars-active" style="width: 122.5px;">
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
            <div class="kksr-star" style="padding-right: 5px">
            

<div class="kksr-icon" style="width: 20px; height: 20px;"></div>
        </div>
    </div>
</div>
                

<div class="kksr-legend" style="font-size: 16px;">
            5/5 - (6 votes)    </div>
    </div>
<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>
	</channel>
</rss>
