Microsoft.Entra.CertificateBasedAuthentication.psm1

# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License. See License in the project root for license information.
# ------------------------------------------------------------------------------
Set-StrictMode -Version 5 


function Get-EntraUserCBAAuthorizationInfo {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'The unique identifier for the user (User Principal Name or UserId).')]
        [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({
                if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or 
                    $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') {
                    return $true
                }
                throw "UserId must be a valid email address or GUID."
            })]
        [string]$UserId,

        [Parameter(Mandatory = $false, HelpMessage = 'If specified, returns the raw response from the API.')]
        [Alias('RawResponse')]
        [switch]$Raw
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All, User.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    process {
        try {
            $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand
            # Determine if UserId is a GUID (ObjectId) or a UserPrincipalName
            $isGuid = $UserId -match "^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$"
            $filter = if ($isGuid) { "id eq '$UserId'" } else { "userPrincipalName eq '$UserId'" }
            
            # First look up the user to get the ID if not already a GUID
            $uri = "/v1.0/users?`$filter=$filter"
            $lookupCustomHeaders = @{} + $customHeaders + @{"ConsistencyLevel" = "eventual" }
            $userLookup = Invoke-MgGraphRequest -Uri $uri -Method GET -Headers $lookupCustomHeaders -ErrorAction Stop
            
            if ($userLookup.value.Count -eq 0) {
                throw "User '$UserId' not found in Entra ID"
            }
            
            $userId = $userLookup.value[0].id
            
            # Now fetch the authorization info
            $apiCallUrl = "/v1.0/users/$userId`?`$select=id,displayName,userPrincipalName,userType,authorizationInfo"
            $response = Invoke-MgGraphRequest -Uri $apiCallUrl -Method GET -Headers $customHeaders -ErrorAction Stop
            
            # If Raw switch is specified, return the raw response
            if ($Raw) {
                return $response
            }
            
            # Create a structured object for the certificate user IDs
            $certificateUserIds = @()
            
            if ($response.authorizationInfo -and $response.authorizationInfo.certificateUserIds) {
                foreach ($certId in $response.authorizationInfo.certificateUserIds) {
                    if ($certId -match 'X509:<([^>]+)>(.+)') {
                        $type = $matches[1]
                        $value = $matches[2]
                        
                        # Create a descriptive name for the certificate type
                        $typeName = switch ($type) {
                            "PN" { "PrincipalName" }
                            "S" { "Subject" }
                            "I" { "Issuer" }
                            "SR" { "SerialNumber" }
                            "SKI" { "SubjectKeyIdentifier" }
                            "SHA1-PUKEY" { "SHA1PublicKey" }
                            default { $type }
                        }
                        
                        $certificateUserIds += [PSCustomObject]@{
                            Type           = $type
                            TypeName       = $typeName
                            Value          = $value
                            OriginalString = $certId
                        }
                    }
                    else {
                        # For any ID that doesn't match the expected format
                        $certificateUserIds += [PSCustomObject]@{
                            Type           = "Unknown"
                            TypeName       = "Unknown"
                            Value          = $certId
                            OriginalString = $certId
                        }
                    }
                }
            }
            
            # Create a structured AuthorizationInfo object
            $authInfo = [PSCustomObject]@{
                CertificateUserIds   = $certificateUserIds
                RawAuthorizationInfo = $response.authorizationInfo
            }
            
            # Create a custom output object with the properties of interest
            $result = [PSCustomObject]@{
                Id                = $response.id
                DisplayName       = $response.displayName
                UserPrincipalName = $response.userPrincipalName
                UserType          = $response.userType
                AuthorizationInfo = $authInfo
            }
            
            return $result
        }
        catch {
            $errorDetails = $_.Exception.Message
            Write-Error "Failed to retrieve authorization info: $errorDetails"
            throw
        }
    }

    end {
        # Cleanup if needed
    }
}

Set-Alias -Name Get-EntraUserAuthorizationInfo -Value Get-EntraUserCBAAuthorizationInfo -Description "Gets a user's authorization information from Microsoft Entra ID" -Scope Global -Force

function Get-EntraUserCertificateUserIdsFromCertificate {
    [CmdletBinding(DefaultParameterSetName = 'Default')]
    param (
        [Parameter(Mandatory = $false,
            HelpMessage = "Path to the certificate file. The file can be in .cer or .pem format.")]
        [string]$Path,

        [Parameter(Mandatory = $false,
            HelpMessage = "Certificate object. If provided, the Path parameter is ignored.")]
        [Alias('CertificateObject', 'Cert')]
        [System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate,

        [Parameter(Mandatory = $false,
            ParameterSetName = 'Default',
            HelpMessage = "The certificate mapping type to use. Valid values are: PrincipalName, RFC822Name, IssuerAndSubject, Subject, SKI, SHA1PublicKey, IssuerAndSerialNumber.")]
        [ValidateSet("PrincipalName", "RFC822Name", "IssuerAndSubject", "Subject",
            "SKI", "SHA1PublicKey", "IssuerAndSerialNumber")]
        [string]$CertificateMapping
    )

    function Get-Certificate {
        param (
            [string]$filePath
        )
        if ($filePath.EndsWith(".cer")) {
            return [System.Security.Cryptography.X509Certificates.X509Certificate]::new($filePath)
        }
        elseif ($filePath.EndsWith(".pem")) {
            $pemContent = Get-Content -Path $filePath -Raw
            $pemContent = $pemContent -replace "-----BEGIN CERTIFICATE-----", ""
            $pemContent = $pemContent -replace "-----END CERTIFICATE-----", ""
            $pemContent = $pemContent -replace "(\r\n|\n|\r)", ""
            $pemBytes = [Convert]::FromBase64String($pemContent)
            $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate]::new($pemBytes)

            return $certificate
        }
        else {
            throw "Unsupported certificate format. Please provide a .cer or .pem file."
        }
    }

    function Get-DistinguishedNameAsString {
        param (
            [System.Security.Cryptography.X509Certificates.X500DistinguishedName]$distinguishedName
        )

        $dn = $distinguishedName.Decode([System.Security.Cryptography.X509Certificates.X500DistinguishedNameFlags]::UseNewLines -bor [System.Security.Cryptography.X509Certificates.X500DistinguishedNameFlags]::DoNotUsePlusSign)

        $dn = $dn -replace "(\r\n|\n|\r)", ","
        return $dn.TrimEnd(',')
    }

    function Get-SerialNumberAsLittleEndianHexString {
        param (
            [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
        )

        $littleEndianSerialNumber = $cert.GetSerialNumber()

        if ($littleEndianSerialNumber.Length -eq 0) {
            return ""
        }

        [System.Array]::Reverse($littleEndianSerialNumber)
        $hexString = -join ($littleEndianSerialNumber | ForEach-Object { $_.ToString("x2") })
        return $hexString
    }

    function Get-SubjectKeyIdentifier {
        param (
            [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
        )
        foreach ($extension in $cert.Extensions) {
            if ($extension.Oid.Value -eq "2.5.29.14") {
                $ski = New-Object System.Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension -ArgumentList $extension, $false
                return $ski.SubjectKeyIdentifier
            }
        }

        return ""
    }

    # Function to generate certificate mapping fields
    function Get-CertificateMappingFields {
        param (
            [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
        )
        $subject = Get-DistinguishedNameAsString -distinguishedName $cert.SubjectName
        $issuer = Get-DistinguishedNameAsString -distinguishedName $cert.IssuerName
        $serialNumber = Get-SerialNumberAsLittleEndianHexString -cert $cert
        $thumbprint = $cert.Thumbprint
        $principalName = $cert.GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::UpnName, $false)
        $emailName = $cert.GetNameInfo([System.Security.Cryptography.X509Certificates.X509NameType]::EmailName, $false)
        $subjectKeyIdentifier = Get-SubjectKeyIdentifier -cert $cert
        $sha1PublicKey = $cert.GetCertHashString()

        return @{
            "SubjectName"          = $subject
            "IssuerName"           = $issuer
            "SerialNumber"         = $serialNumber
            "Thumbprint"           = $thumbprint
            "PrincipalName"        = $principalName
            "EmailName"            = $emailName
            "SubjectKeyIdentifier" = $subjectKeyIdentifier
            "Sha1PublicKey"        = $sha1PublicKey
        }
    }

    function Get-CertificateUserIds {
        param (
            [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert
        )

        $mappingFields = Get-CertificateMappingFields -cert $cert

        $certUserIDs = @{
            "PrincipalName"         = ""
            "RFC822Name"            = ""
            "IssuerAndSubject"      = "" 
            "Subject"               = ""
            "SKI"                   = ""
            "SHA1PublicKey"         = "" 
            "IssuerAndSerialNumber" = ""
        }

        if (-not [string]::IsNullOrWhiteSpace($mappingFields.PrincipalName)) {
            $certUserIDs.PrincipalName = "X509:<PN>$($mappingFields.PrincipalName)"
        }

        if (-not [string]::IsNullOrWhiteSpace($mappingFields.EmailName)) {
            $certUserIDs.RFC822Name = "X509:<RFC822>$($mappingFields.EmailName)"
        }

        if ((-not [string]::IsNullOrWhiteSpace($mappingFields.IssuerName)) -and (-not [string]::IsNullOrWhiteSpace($mappingFields.SubjectName))) {
            $certUserIDs.IssuerAndSubject = "X509:<I>$($mappingFields.IssuerName)<S>$($mappingFields.SubjectName)"
        }

        if (-not [string]::IsNullOrWhiteSpace($mappingFields.SubjectName)) {
            $certUserIDs.Subject = "X509:<S>$($mappingFields.SubjectName)"
        }

        if (-not [string]::IsNullOrWhiteSpace($mappingFields.SubjectKeyIdentifier)) {
            $certUserIDs.SKI = "X509:<SKI>$($mappingFields.SubjectKeyIdentifier)"
        }

        if (-not [string]::IsNullOrWhiteSpace($mappingFields.Sha1PublicKey)) {
            $certUserIDs.SHA1PublicKey = "X509:<SHA1-PUKEY>$($mappingFields.Sha1PublicKey)"
        }

        if ((-not [string]::IsNullOrWhiteSpace($mappingFields.IssuerName)) -and (-not [string]::IsNullOrWhiteSpace($mappingFields.SerialNumber))) {
            $certUserIDs.IssuerAndSerialNumber = "X509:<I>$($mappingFields.IssuerName)<SR>$($mappingFields.SerialNumber)"
        }

        return $certUserIDs
    }

    function Main {
        $cert = $Certificate
        if ($null -eq $cert) {
            $cert = Get-Certificate -filePath $Path
        }

        $mappings = Get-CertificateUserIds -cert $cert

        if ($CertificateMapping -eq "") {
            return $mappings
        }
        else {
            $value = $mappings[$CertificateMapping]
            return "$($value)"
        }
    }

    # Call main function
    return Main
}

function Set-EntraUserCBACertificateUserId {
    [CmdletBinding(DefaultParameterSetName = 'CertPath')]
    [OutputType([Microsoft.Graph.PowerShell.Models.MicrosoftGraphUser])]
    param (
        [Parameter(Mandatory = $true, 
            HelpMessage = 'The unique identifier for the user (User Principal Name or UserId).',
            Position = 0)]
        [Alias('ObjectId', 'UPN', 'Identity', 'UserPrincipalName')]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({
                if ($_ -match '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' -or 
                    $_ -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') {
                    return $true
                }
                throw "UserId must be a valid email address or GUID."
            })]
        [string]$UserId,

        [Parameter(Mandatory = $true, 
            ParameterSetName = 'CertPath',
            HelpMessage = "Path to the certificate file. The file can be in .cer or .pem format.")]
        [Alias('CertificatePath')]
        [ValidateScript({ Test-Path $_ -PathType Leaf })]
        [string]$CertPath,

        [Parameter(Mandatory = $true, 
            ParameterSetName = 'CertObject',
            HelpMessage = "Certificate object.")]
        [Alias('CertificateObject', 'Certificate')]
        [ValidateNotNull()]
        [System.Security.Cryptography.X509Certificates.X509Certificate2]$Cert,

        [Parameter(Mandatory = $true, 
            HelpMessage = "The certificate mapping type to use.")]
        [ValidateSet("PrincipalName", "RFC822Name", "IssuerAndSubject", "Subject", 
            "SKI", "SHA1PublicKey", "IssuerAndSerialNumber")]
        [ValidateNotNullOrEmpty()]
        [string[]]$CertificateMapping
    )

    begin {
        # Ensure connection to Microsoft Entra
        if (-not (Get-EntraContext)) {
            $errorMessage = "Not connected to Microsoft Graph. Use 'Connect-Entra -Scopes Directory.ReadWrite.All, User.ReadWrite.All' to authenticate."
            Write-Error -Message $errorMessage -ErrorAction Stop
            return
        }
    }

    process {
        try {
            # Define custom headers for the request
            $customHeaders = New-EntraCustomHeaders -Command $MyInvocation.MyCommand

            # Get certificate user IDs based on parameter set
            Write-Verbose "Retrieving certificate user IDs"
            if ($PSCmdlet.ParameterSetName -eq 'CertPath') {
                $allCertUserIds = Get-EntraUserCertificateUserIdsFromCertificate -Path $CertPath
                Write-Verbose "Certificate loaded from path: $CertPath"
            }
            else {
                $allCertUserIds = Get-EntraUserCertificateUserIdsFromCertificate -Certificate $Cert
                Write-Verbose "Certificate loaded from certificate object"
            }

            if (-not $allCertUserIds) {
                throw "Failed to extract certificate user IDs from the certificate"
            }

            # Filter the certificate user IDs based on the requested mappings
            $certUserIdObj = @()
            foreach ($mapping in $CertificateMapping) {
                if ($allCertUserIds.$mapping) {
                    $certUserIdObj += $allCertUserIds.$mapping
                    Write-Verbose "Added mapping type: $mapping"
                }
                else {
                    Write-Warning "Mapping type '$mapping' not found in the certificate"
                }
            }

            if ($certUserIdObj.Count -eq 0) {
                throw "No valid certificate mappings found for the specified mapping types"
            }

            # Check if user exists
            Write-Verbose "Verifying user exists: $UserId"
            
            # Determine if UserId is a UPN or GUID
            if ($UserId -match '^[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}$') {
                $userFilter = "id eq '$UserId'"
            }
            else {
                $userFilter = "userPrincipalName eq '$UserId'"
            }
            
            $userQuery = Invoke-MgGraphRequest -Method GET -Uri "/v1.0/users?`$filter=$userFilter&`$select=id" -ErrorAction Stop

            
            if (-not $userQuery.value -or $userQuery.value.Count -eq 0) {
                throw "User '$UserId' not found in Entra ID"
            }
            
            $userId = $userQuery.value[0].id
            Write-Verbose "User found with ID: $userId"

            # Prepare the request body
            $body = @{
                authorizationInfo = @{
                    certificateUserIds = $certUserIdObj
                }
            }
            
            $jsonBody = ConvertTo-Json -InputObject $body -Depth 10

            Write-Verbose "Updating certificate user IDs for user: $userId"

            $apiCallUrl = "/v1.0/users/$userId"
            $response = Invoke-MgGraphRequest -Uri $apiCallUrl -Method PATCH -Body $jsonBody -Headers $customHeaders -ErrorAction Stop

            Write-Verbose "Certificate User IDs successfully updated"

            return $response

        }
        catch {
            $errorDetails = $_.Exception.Message
            Write-Error "Failed to update certificate user IDs: $errorDetails"
            throw
        }
    }

    end {
        # Cleanup if needed
    }

}
Set-Alias -Name Update-EntraUserCBACertificateUserId -Value Set-EntraUserCBACertificateUserId -Description "Update certificate-based authentication for a user using a certificate file or object" -Scope Global -Force

Export-ModuleMember -Function @('Get-EntraUserCBAAuthorizationInfo', 'Get-EntraUserCertificateUserIdsFromCertificate', 'Set-EntraUserCBACertificateUserId')

# Typedefs
# ------------------------------------------------------------------------------
# Type definitions required for commands inputs
# ------------------------------------------------------------------------------

$def = @"
 
namespace Microsoft.Open.AzureAD.Graph.PowerShell.Custom
{
 
    using System.Linq;
            public enum KeyType{
            Symmetric = 0,
            AsymmetricX509Cert = 1,
        }
        public enum KeyUsage{
            Sign = 0,
            Verify = 1,
            Decrypt = 2,
            Encrypt = 3,
        }
}
 
namespace Microsoft.Open.AzureAD.Model
{
 
    using System.Linq;
    public class AlternativeSecurityId
    {
        public System.String IdentityProvider;
        public System.Byte[] Key;
        public System.Nullable<System.Int32> Type;
         
    }
    public class AppRole
    {
        public System.Collections.Generic.List<System.String> AllowedMemberTypes;
        public System.String Description;
        public System.String DisplayName;
        public System.String Id;
        public System.Nullable<System.Boolean> IsEnabled;
        public System.String Origin;
        public System.String Value;
    }
    public class AssignedLicense
    {
        public System.Collections.Generic.List<System.String> DisabledPlans;
        public System.String SkuId;
         
    }
    public class AssignedLicenses
    {
        public System.Collections.Generic.List<Microsoft.Open.AzureAD.Model.AssignedLicense> AddLicenses;
        public System.Collections.Generic.List<System.String> RemoveLicenses;
         
    }
    public class CertificateAuthorityInformation
    {
        public enum AuthorityTypeEnum{
            RootAuthority = 0,
            IntermediateAuthority = 1,
        }
        public System.Nullable<AuthorityTypeEnum> AuthorityType;
        public System.String CrlDistributionPoint;
        public System.String DeltaCrlDistributionPoint;
        public System.Byte[] TrustedCertificate;
        public System.String TrustedIssuer;
        public System.String TrustedIssuerSki;
         
    }
    public class CrossCloudVerificationCodeBody
    {
        public System.String CrossCloudVerificationCode;
        public CrossCloudVerificationCodeBody()
        {
        }
         
        public CrossCloudVerificationCodeBody(System.String value)
        {
            CrossCloudVerificationCode = value;
        }
    }
    public class GroupIdsForMembershipCheck
    {
        public System.Collections.Generic.List<System.String> GroupIds;
        public GroupIdsForMembershipCheck()
        {
        }
         
        public GroupIdsForMembershipCheck(System.Collections.Generic.List<System.String> value)
        {
            GroupIds = value;
        }
    }
    public class KeyCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.Nullable<System.DateTime> EndDate;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDate;
        public System.String Type;
        public System.String Usage;
        public System.Byte[] Value;
         
    }
    public class PasswordCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.Nullable<System.DateTime> EndDate;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDate;
        public System.String Value;
         
    }
    public class PasswordProfile
    {
        public System.String Password;
        public System.Nullable<System.Boolean> ForceChangePasswordNextLogin;
        public System.Nullable<System.Boolean> EnforceChangePasswordPolicy;
         
    }
    public class PrivacyProfile
    {
        public System.String ContactEmail;
        public System.String StatementUrl;
         
    }
    public class SignInName
    {
        public System.String Type;
        public System.String Value;
         
    }
}
 
namespace Microsoft.Open.MSGraph.Model
{
 
    using System.Linq;
    public class AddIn
    {
        public System.String Id;
        public System.String Type;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.KeyValue> Properties;
         
    }
    public class ApiApplication
    {
        public System.Nullable<System.Boolean> AcceptMappedClaims;
        public System.Collections.Generic.List<System.String> KnownClientApplications;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.PreAuthorizedApplication> PreAuthorizedApplications;
        public System.Nullable<System.Int32> RequestedAccessTokenVersion;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.PermissionScope> Oauth2PermissionScopes;
         
    }
    public class AppRole
    {
        public System.Collections.Generic.List<System.String> AllowedMemberTypes;
        public System.String Description;
        public System.String DisplayName;
        public System.String Id;
        public System.Nullable<System.Boolean> IsEnabled;
        public System.String Origin;
        public System.String Value;
         
    }
    public class ConditionalAccessApplicationCondition
    {
        public System.Collections.Generic.List<System.String> IncludeApplications;
        public System.Collections.Generic.List<System.String> ExcludeApplications;
        public System.Collections.Generic.List<System.String> IncludeUserActions;
        public System.Collections.Generic.List<System.String> IncludeProtectionLevels;
         
    }
    public class ConditionalAccessApplicationEnforcedRestrictions
    {
        public System.Nullable<System.Boolean> IsEnabled;
        public ConditionalAccessApplicationEnforcedRestrictions()
        {
        }
         
        public ConditionalAccessApplicationEnforcedRestrictions(System.Nullable<System.Boolean> value)
        {
            IsEnabled = value;
        }
    }
    public class ConditionalAccessCloudAppSecurity
    {
        public enum CloudAppSecurityTypeEnum{
            McasConfigured = 0,
            MonitorOnly = 1,
            BlockDownloads = 2,
        }
        public System.Nullable<CloudAppSecurityTypeEnum> CloudAppSecurityType;
        public System.Nullable<System.Boolean> IsEnabled;
         
    }
    public class ConditionalAccessConditionSet
    {
        public Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition Applications;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition Users;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessPlatformCondition Platforms;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessLocationCondition Locations;
        public enum ConditionalAccessRiskLevel{
            Low = 0,
            Medium = 1,
            High = 2,
            Hidden = 3,
            None = 4,
            UnknownFutureValue = 5,
        }
        public System.Collections.Generic.List<ConditionalAccessRiskLevel> SignInRiskLevels;
        public enum ConditionalAccessClientApp{
            All = 0,
            Browser = 1,
            MobileAppsAndDesktopClients = 2,
            ExchangeActiveSync = 3,
            EasSupported = 4,
            Other = 5,
        }
        public System.Collections.Generic.List<ConditionalAccessClientApp> ClientAppTypes;
         
    }
    public class ConditionalAccessGrantControls
    {
        public System.String _Operator;
        public enum ConditionalAccessGrantControl{
            Block = 0,
            Mfa = 1,
            CompliantDevice = 2,
            DomainJoinedDevice = 3,
            ApprovedApplication = 4,
            CompliantApplication = 5,
            PasswordChange = 6,
        }
        public System.Collections.Generic.List<ConditionalAccessGrantControl> BuiltInControls;
        public System.Collections.Generic.List<System.String> CustomAuthenticationFactors;
        public System.Collections.Generic.List<System.String> TermsOfUse;
         
    }
    public class ConditionalAccessLocationCondition
    {
        public System.Collections.Generic.List<System.String> IncludeLocations;
        public System.Collections.Generic.List<System.String> ExcludeLocations;
         
    }
    public class ConditionalAccessPersistentBrowser
    {
        public enum ModeEnum{
            Always = 0,
            Never = 1,
        }
        public System.Nullable<ModeEnum> Mode;
        public System.Nullable<System.Boolean> IsEnabled;
         
    }
    public class ConditionalAccessPlatformCondition
    {
        public enum ConditionalAccessDevicePlatforms{
            Android = 0,
            IOS = 1,
            Windows = 2,
            WindowsPhone = 3,
            MacOS = 4,
            All = 5,
        }
        public System.Collections.Generic.List<ConditionalAccessDevicePlatforms> IncludePlatforms;
        public System.Collections.Generic.List<ConditionalAccessDevicePlatforms> ExcludePlatforms;
         
    }
    public class ConditionalAccessSessionControls
    {
        public Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationEnforcedRestrictions ApplicationEnforcedRestrictions;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessCloudAppSecurity CloudAppSecurity;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency SignInFrequency;
        public Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser PersistentBrowser;
         
    }
    public class ConditionalAccessSignInFrequency
    {
        public enum TypeEnum{
            Days = 0,
            Hours = 1,
        }
        public System.Nullable<TypeEnum> Type;
        public System.Nullable<System.Int32> Value;
        public System.Nullable<System.Boolean> IsEnabled;
         
    }
    public class ConditionalAccessUserCondition
    {
        public System.Collections.Generic.List<System.String> IncludeUsers;
        public System.Collections.Generic.List<System.String> ExcludeUsers;
        public System.Collections.Generic.List<System.String> IncludeGroups;
        public System.Collections.Generic.List<System.String> ExcludeGroups;
        public System.Collections.Generic.List<System.String> IncludeRoles;
        public System.Collections.Generic.List<System.String> ExcludeRoles;
         
    }
        public enum CountriesAndRegion{
            AD = 0,
            AE = 1,
            AF = 2,
            AG = 3,
            AI = 4,
            AL = 5,
            AM = 6,
            AN = 7,
            AO = 8,
            AQ = 9,
            AR = 10,
            AS = 11,
            AT = 12,
            AU = 13,
            AW = 14,
            AX = 15,
            AZ = 16,
            BA = 17,
            BB = 18,
            BD = 19,
            BE = 20,
            BF = 21,
            BG = 22,
            BH = 23,
            BI = 24,
            BJ = 25,
            BL = 26,
            BM = 27,
            BN = 28,
            BO = 29,
            BQ = 30,
            BR = 31,
            BS = 32,
            BT = 33,
            BV = 34,
            BW = 35,
            BY = 36,
            BZ = 37,
            CA = 38,
            CC = 39,
            CD = 40,
            CF = 41,
            CG = 42,
            CH = 43,
            CI = 44,
            CK = 45,
            CL = 46,
            CM = 47,
            CN = 48,
            CO = 49,
            CR = 50,
            CU = 51,
            CV = 52,
            CW = 53,
            CX = 54,
            CY = 55,
            CZ = 56,
            DE = 57,
            DJ = 58,
            DK = 59,
            DM = 60,
            DO = 61,
            DZ = 62,
            EC = 63,
            EE = 64,
            EG = 65,
            EH = 66,
            ER = 67,
            ES = 68,
            ET = 69,
            FI = 70,
            FJ = 71,
            FK = 72,
            FM = 73,
            FO = 74,
            FR = 75,
            GA = 76,
            GB = 77,
            GD = 78,
            GE = 79,
            GF = 80,
            GG = 81,
            GH = 82,
            GI = 83,
            GL = 84,
            GM = 85,
            GN = 86,
            GP = 87,
            GQ = 88,
            GR = 89,
            GS = 90,
            GT = 91,
            GU = 92,
            GW = 93,
            GY = 94,
            HK = 95,
            HM = 96,
            HN = 97,
            HR = 98,
            HT = 99,
            HU = 100,
            ID = 101,
            IE = 102,
            IL = 103,
            IM = 104,
            IN = 105,
            IO = 106,
            IQ = 107,
            IR = 108,
            IS = 109,
            IT = 110,
            JE = 111,
            JM = 112,
            JO = 113,
            JP = 114,
            KE = 115,
            KG = 116,
            KH = 117,
            KI = 118,
            KM = 119,
            KN = 120,
            KP = 121,
            KR = 122,
            KW = 123,
            KY = 124,
            KZ = 125,
            LA = 126,
            LB = 127,
            LC = 128,
            LI = 129,
            LK = 130,
            LR = 131,
            LS = 132,
            LT = 133,
            LU = 134,
            LV = 135,
            LY = 136,
            MA = 137,
            MC = 138,
            MD = 139,
            ME = 140,
            MF = 141,
            MG = 142,
            MH = 143,
            MK = 144,
            ML = 145,
            MM = 146,
            MN = 147,
            MO = 148,
            MP = 149,
            MQ = 150,
            MR = 151,
            MS = 152,
            MT = 153,
            MU = 154,
            MV = 155,
            MW = 156,
            MX = 157,
            MY = 158,
            MZ = 159,
            NA = 160,
            NC = 161,
            NE = 162,
            NF = 163,
            NG = 164,
            NI = 165,
            NL = 166,
            NO = 167,
            NP = 168,
            NR = 169,
            NU = 170,
            NZ = 171,
            OM = 172,
            PA = 173,
            PE = 174,
            PF = 175,
            PG = 176,
            PH = 177,
            PK = 178,
            PL = 179,
            PM = 180,
            PN = 181,
            PR = 182,
            PS = 183,
            PT = 184,
            PW = 185,
            PY = 186,
            QA = 187,
            RE = 188,
            RO = 189,
            RS = 190,
            RU = 191,
            RW = 192,
            SA = 193,
            SB = 194,
            SC = 195,
            SD = 196,
            SE = 197,
            SG = 198,
            SH = 199,
            SI = 200,
            SJ = 201,
            SK = 202,
            SL = 203,
            SM = 204,
            SN = 205,
            SO = 206,
            SR = 207,
            SS = 208,
            ST = 209,
            SV = 210,
            SX = 211,
            SY = 212,
            SZ = 213,
            TC = 214,
            TD = 215,
            TF = 216,
            TG = 217,
            TH = 218,
            TJ = 219,
            TK = 220,
            TL = 221,
            TM = 222,
            TN = 223,
            TO = 224,
            TR = 225,
            TT = 226,
            TV = 227,
            TW = 228,
            TZ = 229,
            UA = 230,
            UG = 231,
            UM = 232,
            US = 233,
            UY = 234,
            UZ = 235,
            VA = 236,
            VC = 237,
            VE = 238,
            VG = 239,
            VI = 240,
            VN = 241,
            VU = 242,
            WF = 243,
            WS = 244,
            YE = 245,
            YT = 246,
            ZA = 247,
            ZM = 248,
            ZW = 249,
        }
    public class DefaultUserRolePermissions
    {
        public System.Nullable<System.Boolean> AllowedToCreateApps;
        public System.Nullable<System.Boolean> AllowedToCreateSecurityGroups;
        public System.Nullable<System.Boolean> AllowedToReadOtherUsers;
        public System.Collections.Generic.List<System.String> PermissionGrantPoliciesAssigned;
         
    }
    public class DelegatedPermissionClassification
    {
        public enum ClassificationEnum{
            Low = 0,
            Medium = 1,
            High = 2,
        }
        public System.Nullable<ClassificationEnum> Classification;
        public System.String Id;
        public System.String PermissionId;
        public System.String PermissionName;
         
    }
    public class EmailAddress
    {
        public System.String Name;
        public System.String Address;
         
    }
    public class ImplicitGrantSettings
    {
        public System.Nullable<System.Boolean> EnableIdTokenIssuance;
        public System.Nullable<System.Boolean> EnableAccessTokenIssuance;
         
    }
    public class InformationalUrl
    {
        public System.String TermsOfServiceUrl;
        public System.String MarketingUrl;
        public System.String PrivacyStatementUrl;
        public System.String SupportUrl;
        public System.String LogoUrl;
         
    }
    public class InvitedUserMessageInfo
    {
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.Recipient> CcRecipients;
        public System.String CustomizedMessageBody;
        public System.String MessageLanguage;
         
    }
    public class IpRange
    {
        public System.String CidrAddress;
        public IpRange()
        {
        }
         
        public IpRange(System.String value)
        {
            CidrAddress = value;
        }
    }
    public class KeyCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.String DisplayName;
        public System.Nullable<System.DateTime> EndDateTime;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDateTime;
        public System.String Type;
        public System.String Usage;
        public System.Byte[] Key;
         
    }
    public class KeyValue
    {
        public System.String Key;
        public System.String Value;
         
    }
    public class MsDirectoryObject
    {
        public System.String Id;
        public System.String OdataType;
    }
 
    public class MsRoleMemberInfo
    {
       public System.String Id;
    }
 
    public class OptionalClaim
    {
        public System.String Name;
        public System.String Source;
        public System.Nullable<System.Boolean> Essential;
        public System.Collections.Generic.List<System.String> AdditionalProperties;
         
    }
    public class OptionalClaims
    {
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> IdToken;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> AccessToken;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.OptionalClaim> Saml2Token;
         
    }
    public class ParentalControlSettings
    {
        public enum LegalAgeGroupRuleEnum{
            Allow = 0,
            RequireConsentForPrivacyServices = 1,
            RequireConsentForMinors = 2,
            RequireConsentForKids = 3,
            BlockMinors = 4,
        }
        public System.Nullable<LegalAgeGroupRuleEnum> LegalAgeGroupRule;
        public System.Collections.Generic.List<System.String> CountriesBlockedForMinors;
         
    }
    public class PasswordCredential
    {
        public System.Byte[] CustomKeyIdentifier;
        public System.Nullable<System.DateTime> EndDateTime;
        public System.String DisplayName;
        public System.String KeyId;
        public System.Nullable<System.DateTime> StartDateTime;
        public System.String SecretText;
        public System.String Hint;
         
    }
    public class PermissionScope
    {
        public System.String AdminConsentDescription;
        public System.String AdminConsentDisplayName;
        public System.String Id;
        public System.Nullable<System.Boolean> IsEnabled;
        public System.String Type;
        public System.String UserConsentDescription;
        public System.String UserConsentDisplayName;
        public System.String Value;
         
    }
    public class PreAuthorizedApplication
    {
        public System.String AppId;
        public System.Collections.Generic.List<System.String> DelegatedPermissionIds;
         
    }
    public class PublicClientApplication
    {
        public System.Collections.Generic.List<System.String> RedirectUris;
        public PublicClientApplication()
        {
        }
         
        public PublicClientApplication(System.Collections.Generic.List<System.String> value)
        {
            RedirectUris = value;
        }
    }
    public class Recipient
    {
        public Microsoft.Open.MSGraph.Model.EmailAddress EmailAddress;
        public Recipient()
        {
        }
         
        public Recipient(Microsoft.Open.MSGraph.Model.EmailAddress value)
        {
            EmailAddress = value;
        }
    }
    public class RequiredResourceAccess
    {
        public System.String ResourceAppId;
        public System.Collections.Generic.List<Microsoft.Open.MSGraph.Model.ResourceAccess> ResourceAccess;
         
    }
    public class ResourceAccess
    {
        public System.String Id;
        public System.String Type;
         
    }
    public class RolePermission
    {
        public System.Collections.Generic.List<System.String> AllowedResourceActions;
        public System.String Condition;
         
    }
    public class SetVerifiedPublisherRequest
    {
        public System.String VerifiedPublisherId;
        public SetVerifiedPublisherRequest()
        {
        }
         
        public SetVerifiedPublisherRequest(System.String value)
        {
            VerifiedPublisherId = value;
        }
    }
    public class User
    {
        public System.String Id;
        public System.String OdataType;
         
    }
    public class WebApplication
    {
        public System.String HomePageUrl;
        public System.String LogoutUrl;
        public System.Collections.Generic.List<System.String> RedirectUris;
        public Microsoft.Open.MSGraph.Model.ImplicitGrantSettings ImplicitGrantSettings;
         
    }
}
"@


try {
    Add-Type -TypeDefinition $def -ErrorAction SilentlyContinue
} catch {
    # No error message will be displayed, and type will be added if it doesn't exist
}


# ------------------------------------------------------------------------------
# End of Type definitions required for commands inputs
# ------------------------------------------------------------------------------


# SIG # Begin signature block
# MIIoUgYJKoZIhvcNAQcCoIIoQzCCKD8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBc0N/GNtjNZs+5
# 4Jcd2j9xn4QUr2a0WAisVUrRmtKfx6CCDYUwggYDMIID66ADAgECAhMzAAAEA73V
# lV0POxitAAAAAAQDMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTEzWhcNMjUwOTExMjAxMTEzWjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQCfdGddwIOnbRYUyg03O3iz19XXZPmuhEmW/5uyEN+8mgxl+HJGeLGBR8YButGV
# LVK38RxcVcPYyFGQXcKcxgih4w4y4zJi3GvawLYHlsNExQwz+v0jgY/aejBS2EJY
# oUhLVE+UzRihV8ooxoftsmKLb2xb7BoFS6UAo3Zz4afnOdqI7FGoi7g4vx/0MIdi
# kwTn5N56TdIv3mwfkZCFmrsKpN0zR8HD8WYsvH3xKkG7u/xdqmhPPqMmnI2jOFw/
# /n2aL8W7i1Pasja8PnRXH/QaVH0M1nanL+LI9TsMb/enWfXOW65Gne5cqMN9Uofv
# ENtdwwEmJ3bZrcI9u4LZAkujAgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU6m4qAkpz4641iK2irF8eWsSBcBkw
# VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
# dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwMjkyNjAfBgNVHSMEGDAW
# gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx
# XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB
# AFFo/6E4LX51IqFuoKvUsi80QytGI5ASQ9zsPpBa0z78hutiJd6w154JkcIx/f7r
# EBK4NhD4DIFNfRiVdI7EacEs7OAS6QHF7Nt+eFRNOTtgHb9PExRy4EI/jnMwzQJV
# NokTxu2WgHr/fBsWs6G9AcIgvHjWNN3qRSrhsgEdqHc0bRDUf8UILAdEZOMBvKLC
# rmf+kJPEvPldgK7hFO/L9kmcVe67BnKejDKO73Sa56AJOhM7CkeATrJFxO9GLXos
# oKvrwBvynxAg18W+pagTAkJefzneuWSmniTurPCUE2JnvW7DalvONDOtG01sIVAB
# +ahO2wcUPa2Zm9AiDVBWTMz9XUoKMcvngi2oqbsDLhbK+pYrRUgRpNt0y1sxZsXO
# raGRF8lM2cWvtEkV5UL+TQM1ppv5unDHkW8JS+QnfPbB8dZVRyRmMQ4aY/tx5x5+
# sX6semJ//FbiclSMxSI+zINu1jYerdUwuCi+P6p7SmQmClhDM+6Q+btE2FtpsU0W
# +r6RdYFf/P+nK6j2otl9Nvr3tWLu+WXmz8MGM+18ynJ+lYbSmFWcAj7SYziAfT0s
# IwlQRFkyC71tsIZUhBHtxPliGUu362lIO0Lpe0DOrg8lspnEWOkHnCT5JEnWCbzu
# iVt8RX1IV07uIveNZuOBWLVCzWJjEGa+HhaEtavjy6i7MIIHejCCBWKgAwIBAgIK
# YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV
# BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm
# aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw
# OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD
# VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la
# UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc
# 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D
# dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+
# lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk
# kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6
# A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd
# X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL
# 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd
# sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3
# T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS
# 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI
# bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL
# BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD
# uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv
# c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf
# MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF
# BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h
# cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA
# YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn
# 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7
# v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b
# pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/
# KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy
# CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp
# mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi
# hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb
# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL
# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX
# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGiMwghofAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAQDvdWVXQ87GK0AAAAA
# BAMwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIF1R
# j26Ldyi9kABi5oz8ZgEmLwTP35e4lXdPZYtlhqafMEIGCisGAQQBgjcCAQwxNDAy
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20wDQYJKoZIhvcNAQEBBQAEggEASvsmeG042ESyd0HNkRgLek3Cnmte6lFqWkE3
# GuZINS/ptKv5GwbZ1GwHjn30KtHErvyqgc8IcnOM/fgGSA+SA9p1bC/qAkj6SJ9X
# LMkuhIeiG/qlkE9hpvk6JQML6YVQYeLdrKRmAOit6tg5/A/r2VN09yDqUCFqgEwr
# Rd/mnldU6sHUft/xCY5GDlxFMpEvVmjqkRRXPUsyhrY28zZj9aQp912pVwTxd3hR
# iKtjT1bdmjJenzwYUBJnD0S3fblWYT46IHZl6kQ3H5oI89xvkPfxoWG9zD9csr0F
# wjs83FmbOg4k0JVD7+XuQT1cHDMp7u8/jbDD8xqTmg4pjmW/F6GCF60wghepBgor
# BgEEAYI3AwMBMYIXmTCCF5UGCSqGSIb3DQEHAqCCF4YwgheCAgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGE
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCAVggl8p92zG6sKb660t6f2PnWd2aoZG56j
# VNlalfJ7sQIGZ+0mLTR6GBMyMDI1MDQxNDE2MjgwMi42NDdaMASAAgH0oIHZpIHW
# MIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQL
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsT
# Hm5TaGllbGQgVFNTIEVTTjo1MjFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z
# b2Z0IFRpbWUtU3RhbXAgU2VydmljZaCCEfswggcoMIIFEKADAgECAhMzAAACAAvX
# qn8bKhdWAAEAAAIAMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMB4XDTI0MDcyNTE4MzEyMVoXDTI1MTAyMjE4MzEyMVowgdMxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jv
# c29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVs
# ZCBUU1MgRVNOOjUyMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt
# ZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
# r1XaadKkP2TkunoTF573/tF7KJM9Doiv3ccv26mqnUhmv2DM59ikET4WnRfo5biF
# IHc6LqrIeqCgT9fT/Gks5VKO90ZQW2avh/PMHnl0kZfX/I5zdVooXHbdUUkPiZfN
# XszWswmL9UlWo8mzyv9Lp9TAtw/oXOYTAxdYSqOB5Uzz1Q3A8uCpNlumQNDJGDY6
# cSn0MlYukXklArChq6l+KYrl6r/WnOqXSknABpggSsJ33oL3onmDiN9YUApZwjnN
# h9M6kDaneSz78/YtD/2pGpx9/LXELoazEUFxhyg4KdmoWGNYwdR7/id81geOER69
# l5dJv71S/mH+Lxb6L692n8uEmAVw6fVvE+c8wjgYZblZCNPAynCnDduRLdk1jswC
# qjqNc3X/WIzA7GGs4HUS4YIrAUx8H2A94vDNiA8AWa7Z/HSwTCyIgeVbldXYM2Bt
# xMKq3kneRoT27NQ7Y7n8ZTaAje7Blfju83spGP/QWYNZ1wYzYVGRyOpdA8Wmxq5V
# 8f5r4HaG9zPcykOyJpRZy+V3RGighFmsCJXAcMziO76HinwCIjImnCFKGJ/IbLjH
# 6J7fJXqRPbg+H6rYLZ8XBpmXBFH4PTakZVYxB/P+EQbL5LNw0ZIM+eufxCljV4O+
# nHkM+zgSx8+07BVZPBKslooebsmhIcBO0779kehciYMCAwEAAaOCAUkwggFFMB0G
# A1UdDgQWBBSAJSTavgkjKqge5xQOXn35fXd3OjAfBgNVHSMEGDAWgBSfpxVdAF5i
# XYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jv
# c29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENB
# JTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRp
# bWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1Ud
# JQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsF
# AAOCAgEAKPCG9njRtIqQ+fuECgxzWMsQOI3HvW7sV9PmEWCCOWlTuGCIzNi3ibdL
# ZS0b2IDHg0yLrtdVuBi3FxVdesIXuzYyofIe/alTBdV4DhijLTXtB7NgOno7G12i
# O3t6jy1hPSquzGLry/2mEZBwIsSoS2D+H+3HCJxPDyhzMFqP+plltPACB/QNwZ7q
# +HGyZv3v8et+rQYg8sF3PTuWeDg3dR/zk1NawJ/dfFCDYlWNeCBCLvNPQBceMYXF
# RFKhcSUws7mFdIDDhZpxqyIKD2WDwFyNIGEezn+nd4kXRupeNEx+eSpJXylRD+1d
# 45hb6PzOIF7BkcPtRtFW2wXgkjLqtTWWlBkvzl2uNfYJ3CPZVaDyMDaaXgO+H6Di
# rsJ4IG9ikId941+mWDejkj5aYn9QN6ROfo/HNHg1timwpFoUivqAFu6irWZFw5V+
# yLr8FLc7nbMa2lFSixzu96zdnDsPImz0c6StbYyhKSlM3uDRi9UWydSKqnEbtJ6M
# k+YuxvzprkuWQJYWfpPvug+wTnioykVwc0yRVcsd4xMznnnRtZDGMSUEl9tMVneb
# YRshwZIyJTsBgLZmHM7q2TFK/X9944SkIqyY22AcuLe0GqoNfASCIcZtzbZ/zP4l
# T2/N0pDbn2ffAzjZkhI+Qrqr983mQZWwZdr3Tk1MYElDThz2D0MwggdxMIIFWaAD
# AgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD
# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3Nv
# ZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIy
# MjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5
# vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64
# NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhu
# je3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl
# 3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPg
# yY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I
# 5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2
# ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/
# TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy
# 16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y
# 1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6H
# XtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMB
# AAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQW
# BBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30B
# ATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
# L0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYB
# BAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMB
# Af8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBL
# oEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
# TWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggr
# BgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNS
# b29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1Vffwq
# reEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27
# DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pv
# vinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9Ak
# vUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWK
# NsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2
# kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+
# c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep
# 8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+Dvk
# txW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1Zyvg
# DbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/
# 2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDVjCCAj4CAQEwggEBoYHZpIHW
# MIHTMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQL
# EyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsT
# Hm5TaGllbGQgVFNTIEVTTjo1MjFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9z
# b2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUAjJOfLZb3ivip
# L3sSLlWFbLrWjmSggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAx
# MDANBgkqhkiG9w0BAQsFAAIFAOundewwIhgPMjAyNTA0MTQxMTU0MjBaGA8yMDI1
# MDQxNTExNTQyMFowdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA66d17AIBADAHAgEA
# AgIpnjAHAgEAAgITLjAKAgUA66jHbAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgor
# BgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUA
# A4IBAQB0EgowEBAV0x5wvKEwcBCYuW1AT2IANt6TUkn7k6MUCE1CB+P1dmDZClAa
# Tc/UYbtedkcLnF6YgwSlSU+BFWEGnhqdelc2KQsczCH67k9tH9CzezIW1etgvbez
# fBtN0OIgbfLuA84RHd222okrrFtbIuCiqzMmt1HaQqmz7nXaZPFpTo1Dd+y79rG5
# Vi36mBuFVh0uAmjHhE+KaW0H1OZ2qcn+YhgJ15ZUf5bWzSSLY1kY9kT0o+ddYuZP
# ZwtoauGEmkR6zVscjvmJEbD4QbttMPTMBlyuVIdjdRq2gAkbnU8F/qYKGFIYiuRd
# Z4FVFelsIlGlr3M1D7yQptIghy1UMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTACEzMAAAIAC9eqfxsqF1YAAQAAAgAwDQYJYIZIAWUD
# BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B
# CQQxIgQgUOfbLLT4fmMpLKygD9H+77LLxabYazpc9Ea0Yzw0nywwgfoGCyqGSIb3
# DQEJEAIvMYHqMIHnMIHkMIG9BCDUyO3sNZ3burBNDGUCV4NfM2gH4aWuRudIk/9K
# Ak/ZJzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAC
# AAvXqn8bKhdWAAEAAAIAMCIEIFTRPgL6l5gBm/IBGujWH/7hIdLcoq0Vap6oHryL
# hYsRMA0GCSqGSIb3DQEBCwUABIICABB8dJItwA/JwEYGB9vVlaILWgOs/qYskVs5
# xgMq86wGSHiWuBInh8ydDW1eF42I7/oFu/pbtqNQQCwS4oBFoPjJvfkmDr+SgKX3
# bnSxmkhHIbaWyWdq+wGBRMHxWOPPbg+/To2eClccLzB1rohxUiJOcqhDLERJJMNO
# XX94x++1lJA0o4LyBPhdEob4UfBcTfb6gtMGQJukhpo4EfujT3BW63ovOEo4pOoh
# U2XW0R0aMWfFgErX9kXwXDTFm/f9gSsjzmA4XEAh9MYiHfl/Pp6WYeNUl5ITce36
# Ryne56ovnhTkB+yh9TJFXFb5PRVHaht7DPlMKMnXA/wfGnfdtwJA+qvcyUMncgZr
# 8pog7DGg2C3N4L/oLubYdGTmzbDAQ5PJMkBNBRAw0xmLoOTXFoR0d2qSBcTXy9cl
# K4PiRoCxODY+pjbTAP0gH/zwDgNjt6Frp5XIY+sK76IFV6jqq8uVKH3chQqp1Ua9
# suK2huUMGk9xrKbQvvl8ok5c1CTq9tnf8NDnBQ3Zo3JKkt5VXB+q5n6U1mLpc1A7
# 80Bi+Ge8x9MvCWA8HiWS7Qo4s0UFfanFKNia+9YhPaAMZ0UkFmBFLHkQAd+RnSfQ
# ozh2r5zdL2CmVe2UeBczbglss2soNIjQ6LDwai1tiSofV+elx2zuFkYtetICm9gP
# 3rHKqKg7
# SIG # End signature block