GraphAPI – Find Messages in a Mailbox in specific folders via PowerShell

Scenario: You want to pull a list of messages using GraphAPI via PowerShell for a specific Mailbox.

Prerequisites: You already have the following configured:
Registered App in Azure: An Azure Registered app to connect to with Application Permissions for Mail.Read, Mail.ReadWrite, Mail.ReadBasic.All, and Mail.Send. (Not all permissions listed may be necessary for the specific function below)
Bearer Authentication Token: A method for pulling back a bearer token and storing it to pass Authorization into your RestAPI package (See my previous post about get-accesstoken). The get-accesstoken authenticates against your Registered App in Azure.

Scriptlets in PowerShell:

#1. Define $mbx
$mbx = "steve@steveman.com"

#2. Build your $AppURI (Examples)
$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders/inbox/Messages"   #using common folder names
 
$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders/AAMkADY3ODhkMDNlLTRjM2YtNDJjYi04YTkzLTFmNjFhYTcyMjA2NwAuAAAAAAAM5kRh6DylRZ4XsImGGVClAQA8oulgK3qgQ659gFhlXH_UAAAAAAEMAAA=/Messages"  #Using Base64 naming for any folder in mailbox
            
$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders('RecoverableItemsDiscoveryHolds')/Messages"
            
$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders('RecoverableItemsPurges')/Messages"


#3. Run the following in a Do-While loop so it collects for than 10 messages at a time:
          #Create your Collection Variable
                $messages = @()
            #Run a Do-While Loop
            
                Do{
                    "Running $appUri"
            
                    $RestSplat = @{
                        URI = $appuri
                        Headers = $(get-accesstoken)
                        Method = 'GET'
                        ContentType = "application/json"
                    }
                
                    $Tempresults = Invoke-RestMethod @RestSplat
                    $messages += $tempresults.value
                    $appuri = $tempresults."@odata.NextLink"
                    }While($appuri -ne $null)

          #Display your Messages
                $Messages
Advertisement

Graph API – Pull a list of Folders for a Mailbox via PowerShell

Scenario – You need to pull a list of folders in a mailbox.

Prerequisites: You already have the following configured:
Registered App in Azure: An Azure Registered app to connect to with Application Permissions for Mail.Read, Mail.ReadWrite, Mail.ReadBasic.All, and Mail.Send. (Not all permissions listed may be necessary for the specific function below)
Bearer Authentication Token: A method for pulling back a bearer token and storing it to pass Authorization into your RestAPI package (See my previous post about get-accesstoken). The get-accesstoken authenticates against your Registered App in Azure.

PowerShell Scriptlets:

#Examples are below for common Folders and how to build the URI
#Notes: For common folders, you can use the name of the folder. For user created folders, or other non-common folders, you can use the Base64 ID

#1. Define $MBX
$mbx = "steve@steveman.com"                


#2. Build your #APPURI
$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders"   #to get a list of folders

$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders/inbox"   #using common folder names

$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders/AAMkADY3ODhkMDNlLTRjM2YtNDJjYi04YTkzLTFmNjFhYTcyMjA2NwAuAAAAAAAM5kRh6DylRZ4XsImGGVClAQA8oulgK3qgQ659gFhlXH_UAAAAAAEMAAA="  #Using Base64 naming for any folder in mailbox


#3. Build  your $RestSplat
$RestSplat = @{
                        URI = $appuri
                        Headers = $(get-accesstoken)
                        Method = 'GET'
                        ContentType = "application/json"
                    }


#4. Run the RestMethod to pull back the Folder(s)
$Folders = Invoke-RestMethod @RestSplat


#5. Display the Results
$Folders.Value



Note: GraphAPI only pulls back 10 items at a time.  If you need to pull back more than 10 items, run the following Do-While Loop:

#To find all Folders in a mailbox, run this:
                #Create your Collection Variable
                    $Folders = @()
                #Build your Starting URI
                    $appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders"   
                #Run a Do-While Loop
            
                Do{
                    "Running $appUri"
            
                    $RestSplat = @{
                        URI = $appuri
                        Headers = $(get-accesstoken)
                        Method = 'GET'
                        ContentType = "application/json"
                    }
                
                    $Tempresults = Invoke-RestMethod @RestSplat
                    $Folders += $tempresults.value
                    $appuri = $tempresults."@odata.NextLink"
                    }While($appuri -ne $null)

          #Display your Messages
                $Folders

        

Stuck at “Verify your account” when accessing Outlook Web

Scenario: When accessing Outlook Web in Exchange Online, a user is redirected to a CAPTCHA page asking to ‘Verify your account’. However the Captcha test never fully loads and you are unable to verify to access your mailbox in Outlook Web — it appears stuck.


Solution: Quickly, navigate to https://outlook.office.com/mail/options/calendar/calAccounts and remove any accounts that you may have connected to previously. It was a race before being redirected to the Captcha site. We had a user with a GMAIL account configured, and after removing it the use was unable to access Outlook Web. The user can access Gmail on Gmails site ;).

Error: The request was aborted: Could not create SSL/TLS secure channel

Scenario: You are trying to access or download from a URL within PowerShell and you receive this error message:

The request was aborted: Could not create SSL/TLS secure Channel


Solution: Use TLS1.2 in your PowerShell to initiate the download.

#verifies that TLS1.2 is available within your PowerShell
	[Enum]::GetNames([Net.SecurityProtocolType]) -contains 'Tls12'

#If True, Checks to see if TLS1.2 is in use with PS
	[System.Net.ServicePointManager]::SecurityProtocol.HasFlag([Net.SecurityProtocolType]::Tls12)

#If False Run the following to enable the use of TLS1.2
	[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12

#Check again for True
[System.Net.ServicePointManager]::SecurityProtocol.HasFlag([Net.SecurityProtocolType]::Tls12)

#Then attempt to initate the install
iex (New-Object Net.WebClient).DownloadString("https://gist.github.com/darkoperator/6152630/raw/c67de4f7cd780ba367cccbc2593f38d18ce6df89/instposhsshdev")

 Error:   Remove-ADUser : The directory service can perform the requested operation only on a leaf object. 

Scenario: When cleaning up Active Directory accounts, you receive the following error:

 Remove-ADUser : The directory service can perform the requested operation only on a leaf object. 

Solution: Our issue is caused by mobile devices being attached within these user accounts. Instead for using the Remove-ADUser commandlet, use the Remove-ADObject with a -recursive commandlet to get ad objects, such as mobile devices, that are attached.

Remove-ADObject “CN=buhbye,OU=Disabled,DC=domain,DC=com” -confirm:$false -recursive

 0x800f0954 – When adding AD Tools to your Windows 10 Computer

Scenario: When adding AD Tools to your Windows 10 computer, you receive the error: Add-WindowsCapability failed. Error code = 0x800f0954

Solution:
1. Go to GPEDIT.MSC
2. Computer Configuration –> Administrative Templates –>System
3. Locate: Specify settings for optional component installation and component repair
4. Select Enabled.
5. Run a GPUpdate /force in PowerShell/CommandLine
6. Attempt to add the AD Poweshell tools again: Add-WindowsCapability -Name ‘Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0’ -Online 

Notes on upgrading an Exchange On-Premises Certificate in a Exchange Online Hybrid Environment

Scenario: Here are some notes on upgrading an Exchange On-Premises Certificate in an Exchange Online Hybrid Environment.

Notes:

#After installing a new Exchange On-Premises Server, Check the following:
    


    #0. Renew the Cert(On-Prem EAC)

            #Create a req
            #Submit the req
            #Complete the Cert Request with your Cert Provider



    #1. Perform a fresh Export and Import of the Cert to all Servers
            #Do this via Exchange On-Premises EAC --> Servers --> Certificates.   Export the Certificate with a password, then turn around and import the certificate on all other servers.




    #2. Configure Services on the Cert
            #Find the thumbprint of the Cert on the new server
                Get-ExchangeCertificate -server <server> 
            #Move the services to the new Cert, #Note: If prompted, select yes or accept to move the SMTP from the old cert to the new cert.
                Enable-Exchangecertificate -thumbprint <thumbprint> -server <servername> -services IMAP,POP,IIS,SMTP

           
        



    #3. SMTP Routing:
            #Within Exchange On-Premises
            
                #a. Check and Set the Transport Server to the new cert:
                        Get-transportserver -identity <servername> | Select InternalTransportCertificateThumbprint
                    #If the thumbprint is not the new cert, move the SMTP Service, and any other service, to the new certificate
                        enable-exchangecertificate -thumbprint <thumbprint> -services SMTP 
                    #Notes: The new Exchange certificate needs to be registered to SMTP for TLS. If this is not done, message routing will break.


                    #For the next two, build the TLSCert Name in Issuer/Subject format:
                        $Cert = Get-ExchangeCertificate -Thumbprint <thumbprint of new certificate> -server <Exchange Server name>
                        $TLSCert = (‘<I>’+$cert.issuer+'<S>’+$cert.subject)

            #b. Check and Set the $TLSCert on the Send Connector to ExOnline
                        Get-SendConnector -identity <Office 365 send Connector> | Select TLSCertificateName
                    #If its not using the new cert,  run the following
                        Set-SendConnector -Identity <Office 365 send Connector> -TLSCertificateName $TLSCert
                    #Notes: You will not be able to send email from ExOnPrem to ExOnline until the new $TLSCert matches.  Messages will become Queued On-Premises.
    
            
            #c. Check and Set the $TLSCert the Receive Connector
                        Get-ReceiveConnector "<Servername>\Default Frontend <servername>" | Select TLSCertificateName
                    #If its not using the new cert,  run the following
                        Get-ReceiveConnector "<Servername>\Default Frontend <Servername>" | Set-ReceiveConnector -TlsCertificateName $TLSCert
                    #Notes: Until the $TLSCert is configured correctly, or matches, there may be a 2-minute delay in receiving messages From Exchange Online to Exchange On-Premises. There could potentially be a delay in message routing breaking completely if the older, expired cert is no longer on the server.

           
           #Within Exchange Online 
            
           #a. Verify the Exchange Online Hybrid Inbound connector (Connector labeled  'Inbound from <GUID>    FROM:  Your org    To: O365')
                    #Within EAC --> Mail Flow --> Connectors, select the inbound connector from 'Your Org' to 'O365' and make sure the $TLSCert matches the "Authenticating Sent Email" Cert name
            
            #b. Verify that the TLS properties of the Exchange On-Premises Hybrid Outbound Connector is using a namespace that is hosted as the Subject or Subject Alternative name, in your new certificate
                    #Within EAC --> Mail Flow --> Connectors, select the outbound connector from 'O365' to 'Your Org' and make sure it references namespace (mail.domain.com) that is listed in your certificate as the Subject, or Subject Alternative name.





    #4. Restart your On-Premises Services
         #a. Restart IIS, MSExchangePop*, MSExchangeImap*, MSExchangeTransport*

    


    #5. Azure App Proxy:  Upload and replace the Cert (from step 1) on Azure App Proxy (APP)

Graph API via PowerShell: Find Exchange Custom Attributes (or AD Extension Attributes) for a user

Scenario: Using Graph API via PowerShell, you can run the following to build and execute a URI to find the Exchange Custom Attributes (or AD Extension Attributes), or other information, for a user:

Scriptlet:
Note: Prerequisite: It performs a get-accesstoken function which can be found and loaded from this blog: Get an Access Token for Graph API via PowerShell – Ex-Shell

#Build the URI
$appuri = 'https://graph.microsoft.com/v1.0/users/SteveMan@SuperHero.com?$Select=id,displayname,mail,officeLocation,onPremisesExtensionAttributes'

$Execute the URI
$appuri = ([System.Uri]$appuri).AbsoluteUri
$header = get-accesstoken
$results = @()
$RestSplat = @{ 
    URI         = $appuri
    Headers     = $header
    Method      = 'GET' 
    ContentType = "application/json" 
} 
$Tempresults =  Invoke-RestMethod @RestSplat 


#Display the Results
$TempResults

#Display the ExtensionAttributes

$tempresults.onPremisesExtensionAttributes

Create a No-Forward Role Assignment Policy for OWA

Scenario: You want to prevent users from configuring forwarding within Outlook on the Web (OWA).

Solution: Run the following in Exchange PowerShell

To Create the Policy:

New-ManagementRole MyBaseOptions-NoForward -Parent MyBaseOptions
Set-ManagementRoleEntry MyBaseOptions-NoForward\Set-Mailbox -RemoveParameter -Parameters DeliverToMailboxAndForward, ForwardingSmtpAddress

Set-ManagementRoleEntry MyBaseOptions-NoForward\New-InboxRule -RemoveParameter -Parameters ForwardTo, RedirectTo, ForwardAsAttachmentTo

Set-ManagementRoleEntry MyBaseOptions-NoForward\Set-InboxRule -RemoveParameter -Parameters ForwardTo, RedirectTo, ForwardAsAttachmentTo

New-RoleAssignmentPolicy -Name PolicyWithNoEmailForward -Roles MyContactInformation, MyRetentionPolicies, MyMailSubscriptions, MyTextMessaging, MyVoiceMail, MyDistributionGroupMembership, MyDistributionGroups, MyProfileInformation, MyBaseOptions-NoForward -Description “User role assignment policy that restricts the assignees from being able to autoforward email outside the organization”

To set it:

get-mailboxplan | Set-mailboxplan -RoleAssignmentPolicy PolicyWithNoEmailForward

get-mailbox | Set-Mailbox -RoleAssignmentPolicy PolicyWithNoEmailForward



New-ApplicationAccessPolicy

Scenario: A registered App within Azure was created that has various ‘Application’ Exchange Permissions granted to it. You want to apply a scope to that registered app so the app only has permissions to specific mailbox, and not every mailbox by default

Scriptlet: Use the New-ApplicationAccessPolicy to Restrict Access

New-ApplicationAccessPolicy -AccessRight RestrictAccess -AppId “<client app id>” -PolicyScopeGroupId grp-app_Mbx_access -Description “Restrict this app to members of security group grp-app_MBX_access.”