Kace email updates contain email header data
KACE (email) Monday, 23 November 2020 by paul

When Kace Service Desk tickets are updated via email the comments added contain email header data.

Issue is referenced on the ITNinja Q&A below. Kace email settings need to be reconfigured to use OAuth for authentication rather than basic auth.

https://www.itninja.com/question/tickets-submitted-to-service-desk-are-now-showing-some-header-code?source=itn_email&campaign=digest&medium=weekly&content=question_detail

Populate missing email address for Sharepoint users who are guests
Office 365 (SharePoint) Monday, 23 November 2020 by paul

There is an issue with SharePoint Guest users who are invited that already present in Exchange Online GAL as a contact. The email address does not get synchronised to the SharePoint user profile from Azure AD. This is a known issue but there is no fix. A workaround is to run the following Microsoft support PowerShell scripts to populate the missing email information.

Main script - Update-ExternalUsersWithNoUPAEmail.ps1

# ==========================================================================================================#
# This script uses Azure AD owerShell annd SPO CSOM to report on or update the WorkEmail Address in the UPA #
# ==========================================================================================================#

# This script requires the pre-installation of the Azure AD PowerShell tools: https://docs.microsoft.com/en-us/office365/enterprise/powershell/connect-to-office-365-powershell 
# This script requires the pre-installation of the SPO Client Components SDK: https://www.microsoft.com/en-gb/download/details.aspx?id=42038 

# Edit this line to point to your tenant SPO Admincenter URL
$SPOTenantAdminUrl="https://yourtenant-admin.sharepoint.com";

# Output file path - edit to point to where the outpuut files should be saved
$outputPath = "C:\temp\GuestUserEmailChangesRequired " + (get-date -format "dd MMM yyyy HH-mm-ss") + ".csv"

# This option should be set to $true in order to apply/sync the changes. When set to $false no changes to data will be made (the script will be Read Only)
$Sync=$true;

# Limits the number of fixes per running of the script.  $Sync needs to be to $true for this to have an effect.  Default is 10. 
$maxFixes = 1000

# This option should be set to $true in order to sync an email address when there are multiple entries in the Alternative Email Address field
$SyncMulti=$false;

# This option should be set to decided which position of Alternative Email Address should be sync'd when multiple values exist.  Zero (0) is the first item, one (1) would be the second value ect.
$SyncMultiPos = 0

# Choose this option output all Guest Users without email Addresses to the screen. Set the value to $true to show or $false to hide.
$FullResultsToScreen = $false

# Choose this option output all Guest Users that need to be synced to the screen. Set the value to $true to show or $false to hide.
$SyncNeededResultsToScreen = $true


# These credential properties can be left as empty and you will then be asked for credentials when you run the script.  It can be useful to add the admin account upn.
$SPOAdminUser = "";
$SPOAdminPassword = "";

Write-Host ""
Write-Host "###################"
Write-Host "Starting the script"
Write-Host "###################"
Write-Host ""

#http://blogs.msdn.com/b/powershell/archive/2007/06/19/get-scriptdirectory.aspx
function Get-ScriptDirectory
{
 $Invocation = (Get-Variable MyInvocation -Scope 1).Value
 if ($Invocation.MyCommand.Path)
 {
    Split-Path $Invocation.MyCommand.Path
 }
 else
 {
    (Get-Item -Path ".\" -Verbose).FullName
 }
}

$path = Join-Path (Get-ScriptDirectory) CSOM_Helper.ps1
. $path

# Get the user credentials
$cred = Get-Credential -Message "Enter username/password for $SPOTenantAdminUrl." -UserName $SPOAdminUser
$credentials = New-Object System.Management.Automation.PSCredential($cred.UserName, $cred.password)

$connectError = @()
Connect-MsolService -Credential $credentials -ErrorVariable connectError -ErrorAction SilentlyContinue
 if ($connectError.count -ne 0 ) {
    Write-Error "Error connecting to MSOLService - $connectError"   
    return
}

$numberNeedsSync = 0
$numberSynced = 0
$searchResults = @()
$searchResultsNeedsSync = @()

$externalusers =  Get-MsolUser -all | Where {$_.UserType -eq 'Guest' -and -not($_.ProxyAddresses -like "*")}         # This finds the Guest Users that do not have a Primary SMTP Address
Write-Host ""
Write-Host "Found $($externalusers.Count) External users in Azure AD that do not have a entry in the ProxyAddresses Property." -ForegroundColor Green

Write-Host ""
Write-Host "'maxFixes' is set to $($maxFixes) so only the first $($maxFixes) Guest Users missing a WorkEmail in the UPA will be checked." -ForegroundColor Green


# Check that there are enough users to process up to the maxFixes value
if ($externalusers.Count -le $maxFixes)
{
    $maxFixes = $externalusers.Count
    Write-Host ""
    Write-Host "The number of External Users found is less than the 'maxFixes' value - setting the 'maxFixes' value to " $($externalusers.Count) -ForegroundColor Yellow
}


#  Just adding some output
if ($Sync -eq $false -and $FullResultsToScreen)
    {
        Write-Host ""
        Write-Host "Here are all the current values for Guest user in Azure AD and the UPA inc status:" -ForegroundColor Green
    }
    elseif($Sync -eq $false -and $SyncNeededResultsToScreen)
    {
        Write-Host ""
        Write-Host "Here are the current values for Guest users that need to sync the WorkEmail address:" -ForegroundColor Green
    }

# Set up the loop for maxFixes

$i = 0
$j = 0
$finished = $false

# Loop while there are external users left to process and $maxFixes is not reached
While ($i -le $externalusers.Count -and $finished -eq $false)   
{
    if ($j -le $maxFixes - 1)
    
    { 
        $user = $externalusers[$i]
    
        # Creates the results object
        $extUserDetails = New-Object PSObject
        $extUserDetails | Add-Member -MemberType NoteProperty -Name UPN -Value $($user.UserPrincipalName) -Force
        $extUserDetails | Add-Member -MemberType NoteProperty -Name AAD_ProxyAddresses -Value $($user.ProxyAddresses) -Force
        $extUserDetails | Add-Member -MemberType NoteProperty -Name AAD_AlternateEmailAddresses -Value $($user.AlternateEmailAddresses) -Force


        # Uses CSOM to get the WorkEmail value from the User Profile
        
        $ctx = (Get-context $SPOTenantAdminUrl -username $credentials.UserName -password $credentials.Password)
        $peopleManager = New-Object Microsoft.SharePoint.Client.UserProfiles.PeopleManager($ctx)
        $accountName = 'i:0#.f|membership|' + $user.UserPrincipalName
        $UPAProfile = $peopleManager.GetPropertiesFor($accountName)
        $UPAProfile.Context.Load($UPAProfile)
        $UPAProfile.Context.ExecuteQuery()
    

        # Checks if a Profile for the user exists in the UPA
        if ($UPAProfile.ServerObjectIsNull)
        {
            # No Profile exists in UPA
            Write-Warning "No profile exists in UPA for user $accountName"
            $extUserDetails | Add-Member -MemberType NoteProperty -Name AAD_AlternateEmailAddresses -Value $null -Force
            $extUserDetails | Add-Member -MemberType NoteProperty -Name UPA_WorkEmail -Value $null -Force
            $extUserDetails | Add-Member -MemberType NoteProperty -Name NeedsSynced -Value $null -Force
        }
        else
        {
            $emailPropertyName = "WorkEmail"
            $extUserDetails | Add-Member -MemberType NoteProperty -Name UPA_WorkEmail -Value $($UPAProfile.UserProfileProperties[$emailPropertyName]) -Force
            $UPAEmailNeedsSynced = $false
            if (($user.ProxyAddresses.Count -eq 0) -and $($UPAProfile.UserProfileProperties[$emailPropertyName]).Contains('#EXT#') -or ([System.String]::IsNullOrEmpty($($UPAProfile.UserProfileProperties[$emailPropertyName]))))
            {
                # Proxy Address is blank (most likely due to another object in Azure AD with same email) AND Email is not set in UPA
                $UPAEmailNeedsSynced = $true
                $j++
            }
            $extUserDetails | Add-Member -MemberType NoteProperty -Name NeedsSynced -Value $UPAEmailNeedsSynced -Force
        
            # Checks if $Sync is set to true and if so it will update the value in the UPA
            if ($UPAEmailNeedsSynced -and $Sync)
            {
                if ($user.AlternateEmailAddresses.Count -eq 1)
                {
                    if (-not [System.String]::IsNullOrEmpty($($user.AlternateEmailAddresses[0])))
                    {
                        $peopleManager.SetSingleValueProfileProperty($accountName,$emailPropertyName,$user.AlternateEmailAddresses[0])
                        $peopleManager.Context.ExecuteQuery()
                        Write-Host ""
                        Write-Host "Successfully set WorkEmail in UPA for user $accountName to $($user.AlternateEmailAddresses[0])" -ForegroundColor Cyan
                        Write-Host ""
                        $extUserDetails | Add-Member -MemberType NoteProperty -Name NeedsSynced -Value "Has been Synced" -Force
                        $extUserDetails | Add-Member -MemberType NoteProperty -Name UPA_WorkEmail -Value $($user.AlternateEmailAddresses[0]) -Force
                        $numberSynced++
                    }
                    else
                    {
                        Write-Warning "AlternateEmailAddresses is not set for user $($user.UserPrincipalName) in Azure AD. Please reinvite the external user or set manually using Set-MSOLUser -AlternateEmailAddresses"
                    }
                
                }
                Elseif ($user.AlternateEmailAddresses.Count -gt 1 -and $SyncMulti)
                {
                    if (-not [System.String]::IsNullOrEmpty($($user.AlternateEmailAddresses[$SyncMultiPos])))
                    {
                        $peopleManager.SetSingleValueProfileProperty($accountName,$emailPropertyName,$user.AlternateEmailAddresses[$SyncMultiPos])
                        $peopleManager.Context.ExecuteQuery()
                        Write-Host "Multiple Alternative Email Addresses found for user $accountName. Successfully set WorkEmail in UPA to $($user.AlternateEmailAddresses[$SyncMultiPos])"
                        $numberSynced++
                    }
                    else
                    {
                        Write-Warning "AlternateEmailAddresses is not set for user $($user.UserPrincipalName) in Azure AD. Please reinvite the external user or set manually using Set-MSOLUser -AlternateEmailAddresses"
                    }
                }
                else
                {
                    Write-Host ""
                    Write-Warning "Found multiple AlternateEmailAddresses set in Azure AD for user $($user.UserPrincipalName). Email will not be synced (Decision needed on which email address to Sync)."
                    Write-Host -NoNewline "Email addresses are: "
                    for ($k=0; $k -le $user.AlternateEmailAddresses.Count - 1; $k++) 
                    {
                        Write-Host -NoNewline $user.AlternateEmailAddresses[$k] "  "
                    }
                    Write-Host ""
                    $numberNeedsSync ++
                }
            }
        }
        if ($Sync -eq $false -and $UPAEmailNeedsSynced)  # Add results only if $sync is false and Sync is Needed
        {
            $searchResultsNeedsSync += $extUserDetails
            $numberNeedsSync ++
        }

        # Add to current results set
        $searchResults += $extUserDetails

        if ($Sync -eq $false -and $FullResultsToScreen)
        {
            # Writes details to the screen
            $extUserDetails
        }

        if ($Sync -eq $false -and $SyncNeededResultsToScreen)
        {
            if ($UPAEmailNeedsSynced)
            {
                # Writes details to the screen
                $extUserDetails
            }
        }

        if ($j -eq $maxFixes)
        {
            $finished = $true
        }
    }
    $i++
}

$searchResults | Export-Csv -Path $outputPath -NoTypeInformation -Append

if(!$sync)
{
    Write-Host ""
    Write-Host "The number of Guest users in this batch that require a sync of the WorkEmail address is: " $numberNeedsSync -ForegroundColor Green
    Write-Host ""
}

if($sync)
{
    Write-Host ""
    Write-Host "The number of Guest users in this batch that were synced is: " $numberSynced -ForegroundColor Green
    Write-Host ""
}
Write-Host "Output file has been written to " $outputPath
Write-Host ""
Write-Host "Script completed executing at " $(Get-Date)-ForegroundColor Green
Write-Host ""

Called by previous script - CSOM_Helper.ps1

#Definition of the function that gets the list of site collections in the tenant using CSOM



function Load-AzureADModule
{
    $moduleerror=@()
    Write-Host "Importing module MSOnline"
    Import-module MSOnline -ErrorAction SilentlyContinue -ErrorVariable moduleerror
    if ($moduleerror.count -ne 0 ) {
	    Write-Host "Attempting to import MSOnline module from default install location 'C:\Windows\System32\WindowsPowerShell\v1.0\Modules\MSOnline'"
	    Import-module "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\MSOnline"	-ErrorAction SilentlyContinue -ErrorVariable moduleerror
	    if ($moduleerror.count -ne 0 ) {
		    Write-Error $moduleerror
		    return;
	    }
    }
}

function Load-SPOModule
{
    $moduleerror=@()
    Write-Host "Importing module Microsoft.Online.SharePoint.PowerShell"
    Import-module Microsoft.Online.SharePoint.PowerShell  -ErrorAction SilentlyContinue -ErrorVariable moduleerror
    if ($moduleerror.count -ne 0 ) {
	    Write-Host "Attempting to import Microsoft.Online.SharePoint.PowerShell module from default install location 'C:\Program Files\SharePoint Online Management Shell\'"
	    Import-module "C:\Program Files\SharePoint Online Management Shell\Microsoft.Online.SharePoint.PowerShell"	-ErrorAction SilentlyContinue -ErrorVariable moduleerror
	    if ($moduleerror.count -ne 0 ) {
		    Write-Error $moduleerror
		    return;
	    }
    }
}

function Load-CSOMModule
{
    $loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
    if ($loadInfo1 -eq $null) {
        Write-Warning "SharePoint Online client components and/or powershell 3.0 are missing."
        write-host "Please download SPO management shell and client components and re-run the script:`r`n`r`nhttp://www.microsoft.com/en-us/download/details.aspx?id=35588`r`nhttp://www.microsoft.com/en-in/download/details.aspx?id=42038"
        return;
    }
    $loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
    if ($loadInfo2 -eq $null) {
        Write-Warning "SharePoint Online client components and/or powershell 3.0 are missing."
        write-host "Please download SPO management shell and client components and re-run the script:`r`n`r`nhttp://www.microsoft.com/en-us/download/details.aspx?id=35588`r`nhttp://www.microsoft.com/en-in/download/details.aspx?id=42038"
        return;
    }
    
    #$loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Online.SharePoint.Client.Tenant")
    #if ($loadInfo3 -eq $null) {
    #    Write-Warning "SharePoint Online client components and/or powershell 3.0 are missing."
    #    write-host "Please download SPO management shell and client components and re-run the script:`r`n`r`nhttp://www.microsoft.com/en-us/download/details.aspx?id=35588`r`nhttp://www.microsoft.com/en-in/download/details.aspx?id=42038"
    #    return;
    #}
    $loadInfo4 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.UserProfiles")
    if ($loadInfo4 -eq $null) {
        Write-Warning "SharePoint Online client components and/or powershell 3.0 are missing."
        write-host "Please download SPO management shell and client components and re-run the script:`r`n`r`nhttp://www.microsoft.com/en-us/download/details.aspx?id=35588`r`nhttp://www.microsoft.com/en-in/download/details.aspx?id=42038"
        return;
    }
}


function Get-SPOTenantSiteCollections
{
    param ($sSiteUrl,$sUserName,$sPassword)
    try
    {    
        Write-Host "----------------------------------------------------------------------------"  -foregroundcolor Green
        Write-Host "Getting the Tenant Site Collections" -foregroundcolor Green
        Write-Host "----------------------------------------------------------------------------"  -foregroundcolor Green
     
        #REQUIREMENTS - # SharePoint 2013 Client Components SDK - http://www.microsoft.com/en-us/download/details.aspx?id=35585
        $loadInfo1 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
        $loadInfo2 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")
        $loadInfo3 = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Online.SharePoint.Client.Tenant")
        #$loadInfo4 = [System.Reflection.Assembly]::LoadFile("C:\Program Files\SharePoint Client Components\16.0\Assemblies\Microsoft.Online.SharePoint.Client.Tenant.dll")

        #SPO Client Object Model Context
        $spoCtx = New-Object Microsoft.SharePoint.Client.ClientContext($sSiteUrl) 
        $spoCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($sUserName, $sPassword)  
        $spoCtx.Credentials = $spoCredentials
        $spoTenant= New-Object Microsoft.Online.SharePoint.TenantAdministration.Tenant($spoCtx)
        $spoTenantSiteCollections=$spoTenant.GetSiteProperties(0,$true)
        $spoCtx.Load($spoTenantSiteCollections)
        $spoCtx.ExecuteQuery()
        
        return $spoTenantSiteCollections
        #We need to iterate through the $spoTenantSiteCollections object to get the information of each individual Site Collection
        #foreach($spoSiteCollection in $spoTenantSiteCollections){
            
        #    Write-Host "Url: " $spoSiteCollection.Url " - Template: " $spoSiteCollection.Template " - Owner: "  $spoSiteCollection.Owner
        #}
        $spoCtx.Dispose()
    }
    catch [System.Exception]
    {
        write-host -f red $_.Exception.ToString()   
    }    
}


#region Globals
$global:allwebs = @()
#endregion

#region Functions
function Get-Context
{
	[CmdletBinding()]
	param
	(
		[Parameter(Mandatory = $true)]
		[string]$siteurl,

        [Parameter(Mandatory=$false)]
        [string]$username = "",

        [Parameter(Mandatory=$false)]
        $password
	)
	
	[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
	[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime")

    Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
    Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.UserProfiles.dll"
    Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
    #Add-Type -Path "C:\Program Files\WindowsPowerShell\Modules\SharePointPnPPowerShellOnline\3.26.2010.0\Microsoft.SharePoint.Client.dll"
    #Add-Type -Path "C:\Program Files\WindowsPowerShell\Modules\SharePointPnPPowerShellOnline\3.26.2010.0\Microsoft.SharePoint.Client.UserProfiles.dll"
    #Add-Type -Path "C:\Program Files\WindowsPowerShell\Modules\SharePointPnPPowerShellOnline\3.26.2010.0\Microsoft.SharePoint.Client.Runtime.dll"

	$ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteurl)

    if (([System.String]::IsNullOrEmpty($username)) -or ([System.String]::IsNullOrEmpty($password)))
    {
        
        $cred = Get-Credential -Message "Enter username/password for $siteurl." -UserName $username
        $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($cred.UserName, $cred.password)
    }
    else
    {
        if ($password.GetType() -eq [System.Security.SecureString])
        {
            $password_secure = $password
        }
        else
        {
            $password_secure = ConvertTo-SecureString $password -AsPlainText -Force
        }
        $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $password_secure)
        #$credentials = New-Object System.Management.Automation.PSCredential($username, $password_secure)
    }

	$ctx.Credentials = $credentials
	$ctx.RequestTimeOut = 5000*60*10
	return $ctx
}
function Get-siteFromContext
{
	[CmdletBinding()]
	param
	(
		[Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
		$ctx
	)
	
	$site = $ctx.site
	$result = $ctx.load($site)
	$result = $ctx.executequery()
	return $site
}
function Get-allSubwebs
{
	[CmdletBinding()]
	param
	(
        [Parameter(Mandatory = $true)]
		$parentweb
	)

    $nextlevelWebs = @()	

	$subwebs = $parentweb.webs
    $result = $parentweb.Context.load($subwebs)
	$result = $parentweb.Context.load($parentweb)
	$result = $parentweb.Context.executequery()
    $nextlevelWebs += $parentweb;
	if ($subwebs.Count -gt 0)
	{
		foreach ($subweb in $subwebs)
		{
			$nextlevelWebs += Get-allwebsFromRootWeb -ctx $ctx -thisweb $subweb    
		}
	}
    return $nextlevelWebs;
}

function Get-rootweb
{
	[CmdletBinding()]
	param
	(
		$site
	)
	
	$rootweb = $site.rootweb
	$result = $site.Context.load($rootweb)
	$result = $site.Context.executequery()
	return $rootweb
}

function Get-allListsInWeb
{
	[CmdletBinding()]
	param
	(
        [Parameter(Mandatory = $true)]
        $web
	)
	
	$lists = $web.lists
	$result = $web.Context.load($lists)
	$result = $web.Context.executequery()
	return $lists
}

function Get-allLibraries
{
	[CmdletBinding()]
	param
	(
        [Parameter(Mandatory = $true)]
        $web
	)
	
	$doclibsinfo = [Microsoft.SharePoint.Client.Web]::GetDocumentLibraries($web.Context,$web.Url)
	$result = $web.Context.ExecuteQuery()
	return $doclibsinfo
}

function Get-List
{
	[CmdletBinding()]
	param
	(
        [Parameter(Mandatory = $true)]
		$web,
        [Parameter(Mandatory = $true)]
        $listUrl
	)
	
	$list = $web.GetList($listurl)
	$result = $web.Context.load($list)
	$result = $web.Context.executequery()
	return $list
}

function Get-ListByTitle
{
	[CmdletBinding()]
	param
	(
        [Parameter(Mandatory = $true)]
		$web,
        [Parameter(Mandatory = $true)]
        $listTitle
	)
	
	$list = $web.Lists.GetByTitle($listTitle)
	$result = $web.Context.load($list)
	$result = $web.Context.executequery()
	return $list
}

function Get-allContentTypesInList
{
	[CmdletBinding()]
	param
	(
        [Parameter(Mandatory = $true)]
		$list
	)
	
	$ctypes = $list.contenttypes
	$result = $list.Context.load($ctypes)
	$result = $list.Context.executequery()
	return $ctypes
}

function Get-listFieldById
{
	[CmdletBinding()]
	param
	(
		$list,
		$fieldId
		
	)
	
	$field = $null
	$field = $list.fields.GetById($fieldId)
	$list.Context.load($field)
	$list.Context.executequery()
	return $field
}

#endregion

Prerequisite is to have SharePoint Client Components installed: https://www.microsoft.com/en-us/download/details.aspx?id=51679

After running the script the SharePoint users should be updated.

Thanks to Microsoft's Nigel Swain and Joel Santos for writing the scripts.

Create archive for all Exchange Online mailboxes
Office 365 (Exchange) Monday, 23 November 2020 by paul

The following PowerShell script will check for Exchange Online mailboxes not provisioned with an Online Archive and enable archiving.

# Enable archive on all mailboxes

write-host "Connecting to Exchange Online Powershell.."	

$UserCredential = Get-Credential 
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection 
Import-PSSession $Session -AllowClobber

# Get list of user/shared mailboxes without Archiving enabled
$MissingArchive = Get-Mailbox -Resultsize Unlimited -Filter {ArchiveStatus -ne "Active" -AND (RecipientTypeDetails -eq "UserMailbox" -OR RecipientTypeDetails -eq "SharedMailbox")}

# Enable archive for those mailboxes
$MissingArchive | Enable-Mailbox -Archive 

# Kick off archiving process
$MissingArchive | ForEach {Start-ManagedFolderAssistant $_.Identity} 

This does not work for some mailboxes migrated and synchronised with on-prem AD. The following script will update the AD user account to ensure the archive is enabled in Exchange Online.

# Enable online archive for shared mailbox migrated from on-premise

# Get user whose status is migrated but not with archive
$users = get-aduser -filter {msExchRemoteRecipientType -eq 97 -or msExchRemoteRecipientType -eq 1}

# Enable migrated with archive type
$users | ForEach {set-aduser $_.DistinguishedName -replace @{msExchRemoteRecipientType=6}} 

# then sync users. online archive will then be create automatically

 

Mobicontrol Android Enterprise enrolment issue
Mobicontrol (mobicontrol) Friday, 20 November 2020 by paul

The enrolment problem is a known issue with the current version of Android Mobicontrol Agent (v14.4.1) in the play store (released 12th November). They will produce a new agent but will probably take weeks before updated in play store.

Workaround until then is to install older agent to enrol the devices using following steps.

  1. On first screen where it says “Let’s Go” tap anywhere on the screen multiple times until the camera comes up.
  2. Snap the attached QR code (it contains instructions to install old agent).