Office 365 Mailbox PST

General discussion of using Adaxes for Active Directory management and administration
Post Reply
will17
Posts: 7
Joined: Thu Jun 01, 2017 4:35 am

Office 365 Mailbox PST

Fri Aug 11, 2017 7:00 am

Hi All,


Weve switched to Office365 and Im using Adaxes to create users which is working really well. However lots of our users now have remote mailboxes which is all good except I can't run my deprovision any more as part of that process was to create a PST of the users mailbox and archive.

Is there any way to get adaxes to remote powershell and export mailboxes to PST somewhere within the office365 service so mailboxes can be stored even though the user will be removed from the users list.


Thanks,

Will

User avatar
Support
Site Admin
Posts: 2373
Joined: Thu Apr 23, 2009 2:28 am

Re: Office 365 Mailbox PST

Fri Aug 11, 2017 9:20 am

Hello Will,

Unfortunately, that can't be done with Office 365 mailboxes. The only way how you can export an Office 365 mailbox is to use Outlook. You can use PowerShell to export from on-premise Exchange servers, but apparently they haven't added this feature to Office 365. Actually, it has been requested a multitude of times already and hanging on Microsoft site as 'pending review' for ages (http://mymfe.microsoft.com/Microsoft%20 ... PageLayout).

We can provide a workaround if you have a hybrid Exchange setup. In this case, we can suggest first moving the mailbox to your on-premises Exchange Server, and then exporting it locally. However, it can take quite a lot of time and cause huge traffic between your organization and Office 365. If you are OK with such a solution, we will provide you the steps to achieve it.
Active Directory Identity Management

Follow Adaxes in social networks
Image Image Image

will17
Posts: 7
Joined: Thu Jun 01, 2017 4:35 am

Re: Office 365 Mailbox PST

Tue Aug 29, 2017 9:38 am

Thanks for the response, I feared this was the answer. If thats ok I'd like to look at that script and maybe test run it when we get hybrid in.


Thanks,

Will

ggallaway
Posts: 9
Joined: Wed Aug 31, 2016 3:34 pm

Re: Office 365 Mailbox PST

Fri Sep 01, 2017 8:52 am

Our solution may or may not work for you, we created a set of scripts that convert the de-provisioned users mailbox to a shared MB and add their manager to 'full access' permissions for 30 days, then remove the user/mailbox after that date. This is all automated through creation of scheduled tasks. If you are interested, I can share some of our scripts we use to accomplish this.

Maarten
Posts: 4
Joined: Fri Sep 22, 2017 10:56 am

Re: Office 365 Mailbox PST

Mon Sep 25, 2017 10:05 am

Hello ggallaway,

Could you share your scripts? We are also in the middle of creating something you have already accomplished :).

Thanks!

ggallaway
Posts: 9
Joined: Wed Aug 31, 2016 3:34 pm

Re: Office 365 Mailbox PST

Thu Oct 12, 2017 1:44 pm

So our process is made up of the following 4 'Steps':

We created the following business rule (Note: 'Deprovision Date' is an adm-customattributedate field that we renamed)
if the 'Provide Manager Access to MB (Home Folder always provided)' property has changed AND
the User is not located under the 'Previous Employee Mailboxes (stcu.local\STCU\Shared Mailboxes)' container AND
the 'Deprovision Date' property has changed then
action: Run Powershell script 'create a scheduled task to de-provision the user' for the user
action: Modify the User: set Account Expires to '%adm-customattributeDate1, +5m%'
action: send e-mail notification (user deactivation scheduled by %initiator%)
the Script within 'create a scheduled task to de-provision the user' is as follows:

Code: Select all

# Scheduled task settings
$containerName = "Deprovisioned User Processing" #must match a folder under scheduled tasks
$taskName = "Initial Deprovision - %username%" 
$taskDescription = "This will process the disabling of the user account and provide Manager with access" 
$deleteTaskAfterExecution = $True
$now = (Get-Date).addMinutes(5)

if("%adm-CustomAttributeDate1%" -lt $now){
    
    $ProcessTime = $now.addminutes(5)
    
}else {
    $ProcessTime = "%adm-CustomAttributeDate1%"
}

# Script for action
$scriptDescription = "Process Deprovisioning"
$scriptToExecute = {
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
Import-Module Adaxes

$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

$userDN = (Get-AdmUser -Identity "%objectGUID%" -AdaxesService "localhost").DistinguishedName
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)

$commandID = "{fb93226e-d3e7-4b97-afde-5262b3c2b931}" #This is a Custom Command (deprovision step 1) and the GUID will need to be changed to match your environment
$user.executecustomCommand($commandID)
}

function CheckNameForUnique($taskPath)
{
    try
    {
        $task = $Context.BindToObject($taskPath)
        return $False
    }
    catch
    {
        return $True
    }
}

# Bind to the Scheduled Tasks container
$scheduledTasksPath = $Context.GetWellKnownContainerPath("ScheduledTasks")
$scheduledTasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $scheduledTasksPath
$containerPath = $scheduledTasksPathObj.CreateChildPath("CN=$containerName")
$container = $Context.BindToObject($containerPath)

# If the task name is not unique, generate a unique one
$uniqueName = $taskName
for ($i = 1; $True; $i++)
{
    $taskPath = $containerPath.CreateChildPath("CN=$uniqueName")
    if (CheckNameForUnique $taskPath)
    {
        break
    }
    $uniqueName = "$taskName`_$i"
}

# Create a Scheduled Task
$task = $container.Create("adm-ScheduledTask", "CN=$uniqueName")

$task.ObjectType = "domainDNS"
$task.Description = $taskDescription
$task.Disabled = $False
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"
$task.DeleteTaskAfterExecution = $deleteTaskAfterExecution

$recurrencePattern = $task.GetRecurrencePattern()
$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_ONCE"
$recurrencePattern.PatternStartDateTime = $ProcessTime
$task.SetRecurrencePattern($recurrencePattern)

$task.SetInfo()

# Define actions and conditions

# Create a new set of actions and conditions
$actionsAndConditions = $task.ConditionedActions.Create()
$actionsAndConditions.ConditionsLogicalOperation = "ADM_LOGICALOPERATION_AND"
$actionsAndConditions.SetInfo()

# Add Run PowerShell Script action
$action = $actionsAndConditions.Actions.CreateEx("adm-RunScriptAction")
$action.ExecutionOptions = "ADM_ACTIONEXECUTIONOPTIONS_SYNC"
$scriptAction = $action.GetAction()
$scriptAction.ScriptType = "ADM_SCRIPTTYPE_POWERSHELL"
$scriptAction.ScriptDescription = $scriptDescription
$scriptAction.Script = $scriptToExecute.ToString()
$action.SetAction($scriptAction)
$action.SetInfo()
$actionsAndConditions.Actions.Add($action)

# Add the set to the Scheduled Task
$task.ConditionedActions.Add($actionsAndConditions)

# Set the scope of activity to All Objects
$scopeItem = $task.ActivityScopeItems.Create()
$scopeItem.BaseObject = $NULL
$scopeItem.Type = "ADM_SCOPEBASEOBJECTTYPE_ALL_DIRECTORY"
$scopeItem.Inheritance = "ADS_SCOPE_SUBTREE"
$scopeItem.Exclude = $False
$scopeItem.SetInfo()

$task.ActivityScopeItems.Add($scopeItem)
The Custom Command deprovision user step 1 is configured as follows:
If the User is not located under the 'Previous Employee Mailboxes ([domainpath to location to house 'old mailboxes']\)' container then
Action:Execute custom command 'Convert Mailbox to Shared (Sub-routines)' for the User

Code: Select all

 
         $mailboxType = "Shared" # TODO: uncomment the type you need
# $mailboxType = "Room"
# $mailboxType = "Equipment"

# Get the object ID in Office 365
try
{
    $objectId = [Guid]$Context.TargetObject.Get("adm-O365ObjectId")
}
catch
{
    $Context.LogMessage("The user doesn't have an Office 365 account", "Warning")
    return
}

try
{
    # Connect to Exchange Online
    $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $Context.GetOffice365Credential() -Authentication Basic -AllowRedirection
    Import-PSSession $session -AllowClobber -DisableNameChecking
    
    # Change mailbox type
    
    
    Set-Mailbox $objectId.ToString() -Type $mailboxType
    
    
}
catch
{
    $Context.LogMessage($_.Exception.Message, "Warning")
}
finally
{
    # Close the remote session and release resources
    Remove-PSSession $session
}
Action:Move the User to 'Previous Employee Mailboxes ([domainpath to location to house 'old mailboxes']\)'
Action:Reset password for the User
Action:Modify the User: disable the account
Action:Deactivate Office 365 account of the User: revoke all licenses
Action:Run PowerShell script 'Remove User from All Groups' for the User

Code: Select all

# E-mail message settings
$to = "helpdeskemail@company.com" # TODO: modify me
$subject = "List of groups user '%name%' has been removed from" # TODO: modify me
$reportHeader = "<b>User {0} has been removed from the following groups:</b><br/>" # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me

# Get the default Web Interface address
$webInterfaceAddress = "%adm-WebInterfaceUrl%"
if ([System.String]::IsNullOrEmpty($webInterfaceAddress))
{
    $Context.LogMessage("Default web interface address not set for Adaxes service. For details, see http://www.adaxes.com/help/?HowDoI.ManageService.RegisterWebInterface.html", "Warning")
}

# Add link to user
$userGuid = [Guid]$Context.TargetObject.Get("objectGuid")
$reportHeader = [System.String]::Format($reportHeader, "<a href='$webInterfaceAddress`ViewObject.aspx?guid=$userGuid'>%name%</a>")

# Get all groups user is a direct member of
$groupGuidsBytes = $Context.TargetObject.GetEx("adm-DirectMemberOfGuid")
$totalRemovedGroups = $groupGuidsBytes.Length - 1
if ($totalRemovedGroups -eq 0)
{
    $Context.LogMessage("This user is a member only the primary group", "Information")
    return
}

# Get the Primary Group ID
$primaryGroupId = $Context.TargetObject.Get("primaryGroupID")

$reportHeader += "<ol>"
foreach ($groupGuidBytes in $groupGuidsBytes)
{
    # Bind to the group
    $groupGuid = [Guid]$groupGuidBytes
    $groupPath = "Adaxes://<GUID=$groupGuid>"
    $group = $Context.BindToObject($groupPath)
   
    # Skip the group if it is the user's Primary Group
    if ($group.Get("primaryGroupToken") -eq $primaryGroupId)
    {
        continue
    }

    # Remove user from the group
    $group.Remove($Context.TargetObject.AdsPath)
    
    # Add group to the report
    $groupDisplayName = [Softerra.Adaxes.Utils.ObjectNameHelper]::GetObjectName($groupPath, "IncludeParentPath")
    $reportHeader += "<li><a href='$webInterfaceAddress`ViewObject.aspx?guid=$groupGuid'>$groupDisplayName</a></li>"
}
$reportHeader += "</ol>"

# Build report
$htmlReport = $reportHeader + "<br/>Total remove groups:$totalRemovedGroups" + $reportFooter

# Send mail
$Context.SendMail($to, $subject, $NULL, $htmlReport)
Action:Execute custom command 'Copy Users Home folder to manager (Sub-routines)' for the User

Code: Select all

[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

$userDN = "%distinguishedName%"
$managerUserName = "%adm-ManagerUserName%"
$managerUserName = $managerUserName.Split("@")
$destDir = "\\somenetworkshare\$($managerUserName[0])\PreviousEmployeeData" #TODO Modify Me
$archivePath = "$destDir\%username%\%username%.zip"
$compressionLevel = 1

#Create Backup folder if not exist
If (!(Test-Path $destDir)) {
 
   New-Item -Path $destDir -ItemType Directory
}
If (!(Test-Path -Path "$destDir\%username%")){
    
   New-Item -Path "$destDir\%username%" -ItemType Directory
}

# Connect to Adaxes service
$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

# Bind to the user
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)

try
{
# Archive the user's home folder
$user.ArchiveHomeDirectory($archivePath, $compressionLevel)
}
catch
{
    $Context.LogMessage("Archive Home Directory Failed", "Error") 
}
Action:Modify the User: clear msRTCSIP-PrimaryHomeServer, clear msRTCSIP-UserEnabled, clear msRTCSIP-OptionFlags, clear msRTCSIP-PrimaryUserAddress
Action:Modify the User: set Account Expires to '%accountExpires,+31d%'
Action:Delete the home directory of the User
Action:Run PowerShell script 'Set Manager Notification Scheduled Task' for the User

Code: Select all

# Scheduled task settings
$containerName = "Deprovisioned User Processing" #must match a folder under scheduled tasks
$taskName = "Notify Manager 10days to deprovision - %username%" 
$taskDescription = "This will process the disabling of the user account and provide Manager with access" 
$deleteTaskAfterExecution = $True
$ProcessTime = (Get-Date).adddays(20)

# Script for action
$scriptDescription = "Notify Manager of impending user deletion" # TODO: modify me
$scriptToExecute = {
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
Import-Module Adaxes

$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

$userDN = (Get-AdmUser -Identity "%objectGUID%" -AdaxesService "localhost").DistinguishedName
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)
$commandID = "{b4b66610-be71-403a-a6b7-8bcf51d200ef}" #Custom Command GUID Deprovision step 2 TODO: Change Me
$user.executecustomCommand($commandID)
}

function CheckNameForUnique($taskPath)
{
    try
    {
        $task = $Context.BindToObject($taskPath)
        return $False
    }
    catch
    {
        return $True
    }
}

# Bind to the Scheduled Tasks container
$scheduledTasksPath = $Context.GetWellKnownContainerPath("ScheduledTasks")
$scheduledTasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $scheduledTasksPath
$containerPath = $scheduledTasksPathObj.CreateChildPath("CN=$containerName")
$container = $Context.BindToObject($containerPath)

# If the task name is not unique, generate a unique one
$uniqueName = $taskName
for ($i = 1; $True; $i++)
{
    $taskPath = $containerPath.CreateChildPath("CN=$uniqueName")
    if (CheckNameForUnique $taskPath)
    {
        break
    }
    $uniqueName = "$taskName`_$i"
}

# Create a Scheduled Task
$task = $container.Create("adm-ScheduledTask", "CN=$uniqueName")

$task.ObjectType = "domainDNS"
$task.Description = $taskDescription
$task.Disabled = $False
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"
$task.DeleteTaskAfterExecution = $deleteTaskAfterExecution

$recurrencePattern = $task.GetRecurrencePattern()
$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_ONCE"
$recurrencePattern.PatternStartDateTime = $ProcessTime
$task.SetRecurrencePattern($recurrencePattern)

$task.SetInfo()

# Define actions and conditions

# Create a new set of actions and conditions
$actionsAndConditions = $task.ConditionedActions.Create()
$actionsAndConditions.ConditionsLogicalOperation = "ADM_LOGICALOPERATION_AND"
$actionsAndConditions.SetInfo()

# Add Run PowerShell Script action
$action = $actionsAndConditions.Actions.CreateEx("adm-RunScriptAction")
$action.ExecutionOptions = "ADM_ACTIONEXECUTIONOPTIONS_SYNC"
$scriptAction = $action.GetAction()
$scriptAction.ScriptType = "ADM_SCRIPTTYPE_POWERSHELL"
$scriptAction.ScriptDescription = $scriptDescription
$scriptAction.Script = $scriptToExecute.ToString()
$action.SetAction($scriptAction)
$action.SetInfo()
$actionsAndConditions.Actions.Add($action)

# Add the set to the Scheduled Task
$task.ConditionedActions.Add($actionsAndConditions)

# Set the scope of activity to All Objects
$scopeItem = $task.ActivityScopeItems.Create()
$scopeItem.BaseObject = $NULL
$scopeItem.Type = "ADM_SCOPEBASEOBJECTTYPE_ALL_DIRECTORY"
$scopeItem.Inheritance = "ADS_SCOPE_SUBTREE"
$scopeItem.Exclude = $False
$scopeItem.SetInfo()

$task.ActivityScopeItems.Add($scopeItem)
Action:Send e-mail notification (User has been deactivated)

If the 'Provide Manager Access to MB (Home Folder always provided)' property equals 'True' AND
If the 'Manager' property is not empty AND
If the User has an Exchange mailbox then
Action:Modify mailbox settings for the User: modify Mailbox Rights (add '%manager% (allow 'Full mailbox access')')
Action:Modify mailbox settings for the User: set Hide from Exchange address lists to 'True'
Action:Send e-mail notification (User Deactivation)

If the 'Provide Manager Access to MB (Home Folder always provided)' property equals 'False' AND
If the 'Manager' property is not empty then
Action: Send e-mail notification (User Deactivation)
Custom Command Step 2 is as follows:
If the 'Provide Manager Access to MB (Home Folder always provided)' property equals 'True' then
Action: Send e-mail notification (User Deactivation)

Always
Action: Run PowerShell script 'Delete User (send to helpdesk for approval)' for the User

Code: Select all

# Scheduled task settings
$containerName = "Deprovisioned User Processing" #must match a folder under scheduled tasks
$taskName = "Send to Helpdesk to confirm delete - %username%" 
$taskDescription = "This will process the disabling of the user account and provide Manager with access" 
$deleteTaskAfterExecution = $True
$ProcessTime = (Get-Date).AddDays(11)

# Script for action
$scriptDescription = "Delete Account and send to helpdesk for confirmation" # TODO: modify me
$scriptToExecute = {
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
Import-Module Adaxes

$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

$userDN = (Get-AdmUser -Identity "%objectGUID%" -AdaxesService "localhost").DistinguishedName
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)
$commandID = "{918f9c02-a91b-428e-88f7-6d4a6e3d5ae2}" #Custom Command GUID deprovision Step 3 TODO:Modify Me
$user.executecustomCommand($commandID)
}

function CheckNameForUnique($taskPath)
{
    try
    {
        $task = $Context.BindToObject($taskPath)
        return $False
    }
    catch
    {
        return $True
    }
}

# Bind to the Scheduled Tasks container
$scheduledTasksPath = $Context.GetWellKnownContainerPath("ScheduledTasks")
$scheduledTasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $scheduledTasksPath
$containerPath = $scheduledTasksPathObj.CreateChildPath("CN=$containerName")
$container = $Context.BindToObject($containerPath)

# If the task name is not unique, generate a unique one
$uniqueName = $taskName
for ($i = 1; $True; $i++)
{
    $taskPath = $containerPath.CreateChildPath("CN=$uniqueName")
    if (CheckNameForUnique $taskPath)
    {
        break
    }
    $uniqueName = "$taskName`_$i"
}

# Create a Scheduled Task
$task = $container.Create("adm-ScheduledTask", "CN=$uniqueName")

$task.ObjectType = "domainDNS"
$task.Description = $taskDescription
$task.Disabled = $False
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"
$task.DeleteTaskAfterExecution = $deleteTaskAfterExecution

$recurrencePattern = $task.GetRecurrencePattern()
$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_ONCE"
$recurrencePattern.PatternStartDateTime = $ProcessTime
$task.SetRecurrencePattern($recurrencePattern)

$task.SetInfo()

# Define actions and conditions

# Create a new set of actions and conditions
$actionsAndConditions = $task.ConditionedActions.Create()
$actionsAndConditions.ConditionsLogicalOperation = "ADM_LOGICALOPERATION_AND"
$actionsAndConditions.SetInfo()

# Add Run PowerShell Script action
$action = $actionsAndConditions.Actions.CreateEx("adm-RunScriptAction")
$action.ExecutionOptions = "ADM_ACTIONEXECUTIONOPTIONS_SYNC"
$scriptAction = $action.GetAction()
$scriptAction.ScriptType = "ADM_SCRIPTTYPE_POWERSHELL"
$scriptAction.ScriptDescription = $scriptDescription
$scriptAction.Script = $scriptToExecute.ToString()
$action.SetAction($scriptAction)
$action.SetInfo()
$actionsAndConditions.Actions.Add($action)

# Add the set to the Scheduled Task
$task.ConditionedActions.Add($actionsAndConditions)

# Set the scope of activity to All Objects
$scopeItem = $task.ActivityScopeItems.Create()
$scopeItem.BaseObject = $NULL
$scopeItem.Type = "ADM_SCOPEBASEOBJECTTYPE_ALL_DIRECTORY"
$scopeItem.Inheritance = "ADS_SCOPE_SUBTREE"
$scopeItem.Exclude = $False
$scopeItem.SetInfo()

$task.ActivityScopeItems.Add($scopeItem)
Custom Command deprovision step 3 is as follows:
Always
Action: Execute custom command 'Remove all Future appointments created by a user (Sub-routines)' for the User

Code: Select all

$startDateProperty = "adm-CurrentDateTime" # Delete meetings starting today.
$endDateProperty = "$NULL" # Delete All Future Meetings
$exchangeWebServiceDllPath = "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"

Import-Module $exchangeWebServiceDllPath

function GetDates ($property, $addDays)
{
    try
    {
        $value = $Context.TargetObject.Get($property)
        if ($value -is [Softerra.Adaxes.Adsi.AdsLargeInteger])
        {
            $value = [DateTime]::FromFiletime([Int64]::Parse($value))
        }
        $value = New-Object "System.Datetime" $value.Year, $value.Month, ($value.Day + $addDays), 0, 0, 0, ([System.DateTimeKind]::Local)
    }
    catch
    {
        $value = $NULL
    }
    
    return $value
}

function ClearProperties ($propertiesName)
{
    foreach ($name in $propertiesName)
    {
        if (($name -eq $NULL) -or 
            ($name -eq "adm-CurrentDateTime"))
        {
            continue
        }
        
        $Context.TargetObject.Put($name, $NULL)
        $Context.TargetObject.SetInfoEx(@($name))
    }
}

# Check whether the user has mailbox in Exchange Online
if (-not($Context.TargetObject.RecipientType -eq "ADM_EXCHANGERECIPIENTTYPE_MAILBOXENABLED" -and `
    $Context.TargetObject.RecipientLocation -eq "ADM_EXCHANGERECIPIENTLOCATION_OFFICE365"))
{
    return
}

# Get search parameters
$startDate = GetDates $startDateProperty 0
$endDate = GetDates $endDateProperty 1

# Get primary SMTP Address
$mailboxParams = $Context.TargetObject.GetMailParameters()
$emailAddresses = $mailboxParams.EmailAddresses
$primarySMTPAddress = $NULL

for ($i = 0; $i -lt $emailAddresses.Count; $i++)
{
    $emailAddress = $emailAddresses.GetAddress($i,[ref]"ADS_PROPERTY_NONE")
    if ($emailAddress.IsPrimary -and $emailAddress.Prefix -eq "smtp")
    {
        $primarySMTPAddress = $emailAddress.Address
        break
    }
}

if ([System.String]::IsNullOrEmpty($primarySMTPAddress))
{
    $Context.LogMessage("Cannot remove meetings scheduled by the user because the user's mailbox doesn't have a primary SMTP address.", "Warning")
    return
}

# Connect to Exchange Online via the Exchange Web Services API
$exchangeWebService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
$office365Cred = $Context.GetOffice365Credential()
$exchangeWebService.Credentials = New-Object System.Net.NetworkCredential($office365Cred.Username, $office365Cred.GetNetworkCredential().Password)
$exchangeWebService.Url = "https://outlook.office365.com/EWS/Exchange.asmx"

# Get the user's calendar
$calendarFolderId = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar, $primarySMTPAddress)
$calendarFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeWebService, $calendarFolderId)
$itemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(500)
    
$propertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet(
    [Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, 
    [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Organizer)

do
{
    $searchResult = $calendarFolder.FindItems($itemView)
    foreach ($item in $searchResult.Items)
    {
        if (!($item.IsMeeting))
        {
            continue # Not a meeting
        }
        
        $item.Load($propertySet)
        
        if ($startDate -eq $NULL -and $endDate -eq $NULL)
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
        elseif (($startDate -eq $NULL) -and
            ($item.Start -lt $endDate))
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
        elseif (($endDate -eq $NULL) -and 
            ($item.Start -ge $startDate))
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
        elseif (($startDate -ne $NULL) -and 
            ($endDate -ne $NULL) -and 
            ($item.Start -ge $startDate) -and 
            ($item.Start -lt $endDate))
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
    }
    
    $itemView.Offset = $searchResult.NextPageOffset
}
while($searchResult.MoreAvailable -eq $True)

# Clear date properties
ClearProperties @($startDateProperty, $endDateProperty)
Action: Delete the User

Julian S.
Posts: 1
Joined: Thu Oct 18, 2018 1:29 am

Re: Office 365 Mailbox PST

Thu Oct 18, 2018 1:30 am

ggallaway wrote:
Thu Oct 12, 2017 1:44 pm
So our process is made up of the following 4 'Steps':

We created the following business rule (Note: 'Deprovision Date' is an adm-customattributedate field that we renamed)
if the 'Provide Manager Access to MB (Home Folder always provided)' property has changed AND
the User is not located under the 'Previous Employee Mailboxes (stcu.local\STCU\Shared Mailboxes)' container AND
the 'Deprovision Date' property has changed then
action: Run Powershell script 'create a scheduled task to de-provision the user' for the user
action: Modify the User: set Account Expires to '%adm-customattributeDate1, +5m%'
action: send e-mail notification (user deactivation scheduled by %initiator%)
the Script within 'create a scheduled task to de-provision the user' is as follows:

Code: Select all

# Scheduled task settings
$containerName = "Deprovisioned User Processing" #must match a folder under scheduled tasks
$taskName = "Initial Deprovision - %username%" 
$taskDescription = "This will process the disabling of the user account and provide Manager with access" 
$deleteTaskAfterExecution = $True
$now = (Get-Date).addMinutes(5)

if("%adm-CustomAttributeDate1%" -lt $now){
    
    $ProcessTime = $now.addminutes(5)
    
}else {
    $ProcessTime = "%adm-CustomAttributeDate1%"
}

# Script for action
$scriptDescription = "Process Deprovisioning"
$scriptToExecute = {
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
Import-Module Adaxes

$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

$userDN = (Get-AdmUser -Identity "%objectGUID%" -AdaxesService "localhost").DistinguishedName
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)

$commandID = "{fb93226e-d3e7-4b97-afde-5262b3c2b931}" #This is a Custom Command (deprovision step 1) and the GUID will need to be changed to match your environment
$user.executecustomCommand($commandID)
}

function CheckNameForUnique($taskPath)
{
    try
    {
        $task = $Context.BindToObject($taskPath)
        return $False
    }
    catch
    {
        return $True
    }
}

# Bind to the Scheduled Tasks container
$scheduledTasksPath = $Context.GetWellKnownContainerPath("ScheduledTasks")
$scheduledTasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $scheduledTasksPath
$containerPath = $scheduledTasksPathObj.CreateChildPath("CN=$containerName")
$container = $Context.BindToObject($containerPath)

# If the task name is not unique, generate a unique one
$uniqueName = $taskName
for ($i = 1; $True; $i++)
{
    $taskPath = $containerPath.CreateChildPath("CN=$uniqueName")
    if (CheckNameForUnique $taskPath)
    {
        break
    }
    $uniqueName = "$taskName`_$i"
}

# Create a Scheduled Task
$task = $container.Create("adm-ScheduledTask", "CN=$uniqueName")

$task.ObjectType = "domainDNS"
$task.Description = $taskDescription
$task.Disabled = $False
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"
$task.DeleteTaskAfterExecution = $deleteTaskAfterExecution

$recurrencePattern = $task.GetRecurrencePattern()
$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_ONCE"
$recurrencePattern.PatternStartDateTime = $ProcessTime
$task.SetRecurrencePattern($recurrencePattern)

$task.SetInfo()

# Define actions and conditions

# Create a new set of actions and conditions
$actionsAndConditions = $task.ConditionedActions.Create()
$actionsAndConditions.ConditionsLogicalOperation = "ADM_LOGICALOPERATION_AND"
$actionsAndConditions.SetInfo()

# Add Run PowerShell Script action
$action = $actionsAndConditions.Actions.CreateEx("adm-RunScriptAction")
$action.ExecutionOptions = "ADM_ACTIONEXECUTIONOPTIONS_SYNC"
$scriptAction = $action.GetAction()
$scriptAction.ScriptType = "ADM_SCRIPTTYPE_POWERSHELL"
$scriptAction.ScriptDescription = $scriptDescription
$scriptAction.Script = $scriptToExecute.ToString()
$action.SetAction($scriptAction)
$action.SetInfo()
$actionsAndConditions.Actions.Add($action)

# Add the set to the Scheduled Task
$task.ConditionedActions.Add($actionsAndConditions)

# Set the scope of activity to All Objects
$scopeItem = $task.ActivityScopeItems.Create()
$scopeItem.BaseObject = $NULL
$scopeItem.Type = "ADM_SCOPEBASEOBJECTTYPE_ALL_DIRECTORY"
$scopeItem.Inheritance = "ADS_SCOPE_SUBTREE"
$scopeItem.Exclude = $False
$scopeItem.SetInfo()

$task.ActivityScopeItems.Add($scopeItem)
The Custom Command deprovision user step 1 is configured as follows:
If the User is not located under the 'Previous Employee Mailboxes ([domainpath to location to house 'old mailboxes']\)' container then
Action:Execute custom command 'Convert Mailbox to Shared (Sub-routines)' for the User

Code: Select all

 
         $mailboxType = "Shared" # TODO: uncomment the type you need
# $mailboxType = "Room"
# $mailboxType = "Equipment"

# Get the object ID in Office 365
try
{
    $objectId = [Guid]$Context.TargetObject.Get("adm-O365ObjectId")
}
catch
{
    $Context.LogMessage("The user doesn't have an Office 365 account", "Warning")
    return
}

try
{
    # Connect to Exchange Online
    $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $Context.GetOffice365Credential() -Authentication Basic -AllowRedirection
    Import-PSSession $session -AllowClobber -DisableNameChecking
    
    # Change mailbox type
    
    
    Set-Mailbox $objectId.ToString() -Type $mailboxType
    
    
}
catch
{
    $Context.LogMessage($_.Exception.Message, "Warning")
}
finally
{
    # Close the remote session and release resources
    Remove-PSSession $session
}
Action:Move the User to 'Previous Employee Mailboxes ([domainpath to location to house 'old mailboxes']\)'
Action:Reset password for the User
Action:Modify the User: disable the account
Action:Deactivate Office 365 account of the User: revoke all licenses
Action:Run PowerShell script 'Remove User from All Groups' for the User

Code: Select all

# E-mail message settings
$to = "helpdeskemail@company.com" # TODO: modify me
$subject = "List of groups user '%name%' has been removed from" # TODO: modify me
$reportHeader = "<b>User {0} has been removed from the following groups:</b><br/>" # TODO: modify me
$reportFooter = "<hr /><p><i>Please do not reply to this e-mail, it has been sent to you for notification purposes only.</i></p>" # TODO: modify me

# Get the default Web Interface address
$webInterfaceAddress = "%adm-WebInterfaceUrl%"
if ([System.String]::IsNullOrEmpty($webInterfaceAddress))
{
    $Context.LogMessage("Default web interface address not set for Adaxes service. For details, see http://www.adaxes.com/help/?HowDoI.ManageService.RegisterWebInterface.html", "Warning")
}

# Add link to user
$userGuid = [Guid]$Context.TargetObject.Get("objectGuid")
$reportHeader = [System.String]::Format($reportHeader, "<a href='$webInterfaceAddress`ViewObject.aspx?guid=$userGuid'>%name%</a>")

# Get all groups user is a direct member of
$groupGuidsBytes = $Context.TargetObject.GetEx("adm-DirectMemberOfGuid")
$totalRemovedGroups = $groupGuidsBytes.Length - 1
if ($totalRemovedGroups -eq 0)
{
    $Context.LogMessage("This user is a member only the primary group", "Information")
    return
}

# Get the Primary Group ID
$primaryGroupId = $Context.TargetObject.Get("primaryGroupID")

$reportHeader += "<ol>"
foreach ($groupGuidBytes in $groupGuidsBytes)
{
    # Bind to the group
    $groupGuid = [Guid]$groupGuidBytes
    $groupPath = "Adaxes://<GUID=$groupGuid>"
    $group = $Context.BindToObject($groupPath)
   
    # Skip the group if it is the user's Primary Group
    if ($group.Get("primaryGroupToken") -eq $primaryGroupId)
    {
        continue
    }

    # Remove user from the group
    $group.Remove($Context.TargetObject.AdsPath)
    
    # Add group to the report
    $groupDisplayName = [Softerra.Adaxes.Utils.ObjectNameHelper]::GetObjectName($groupPath, "IncludeParentPath")
    $reportHeader += "<li><a href='$webInterfaceAddress`ViewObject.aspx?guid=$groupGuid'>$groupDisplayName</a></li>"
}
$reportHeader += "</ol>"

# Build report
$htmlReport = $reportHeader + "<br/>Total remove groups:$totalRemovedGroups" + $reportFooter

# Send mail
$Context.SendMail($to, $subject, $NULL, $htmlReport)
Action:Execute custom command 'Copy Users Home folder to manager (Sub-routines)' for the User

Code: Select all

[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")

$userDN = "%distinguishedName%"
$managerUserName = "%adm-ManagerUserName%"
$managerUserName = $managerUserName.Split("@")
$destDir = "\\somenetworkshare\$($managerUserName[0])\PreviousEmployeeData" #TODO Modify Me
$archivePath = "$destDir\%username%\%username%.zip"
$compressionLevel = 1

#Create Backup folder if not exist
If (!(Test-Path $destDir)) {
 
   New-Item -Path $destDir -ItemType Directory
}
If (!(Test-Path -Path "$destDir\%username%")){
    
   New-Item -Path "$destDir\%username%" -ItemType Directory
}

# Connect to Adaxes service
$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

# Bind to the user
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)

try
{
# Archive the user's home folder
$user.ArchiveHomeDirectory($archivePath, $compressionLevel)
}
catch
{
    $Context.LogMessage("Archive Home Directory Failed", "Error") 
}
Action:Modify the User: clear msRTCSIP-PrimaryHomeServer, clear msRTCSIP-UserEnabled, clear msRTCSIP-OptionFlags, clear msRTCSIP-PrimaryUserAddress
Action:Modify the User: set Account Expires to '%accountExpires,+31d%'
Action:Delete the home directory of the User
Action:Run PowerShell script 'Set Manager Notification Scheduled Task' for the User

Code: Select all

# Scheduled task settings
$containerName = "Deprovisioned User Processing" #must match a folder under scheduled tasks
$taskName = "Notify Manager 10days to deprovision - %username%" 
$taskDescription = "This will process the disabling of the user account and provide Manager with access" 
$deleteTaskAfterExecution = $True
$ProcessTime = (Get-Date).adddays(20)

# Script for action
$scriptDescription = "Notify Manager of impending user deletion" # TODO: modify me
$scriptToExecute = {
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
Import-Module Adaxes

$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

$userDN = (Get-AdmUser -Identity "%objectGUID%" -AdaxesService "localhost").DistinguishedName
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)
$commandID = "{b4b66610-be71-403a-a6b7-8bcf51d200ef}" #Custom Command GUID Deprovision step 2 TODO: Change Me
$user.executecustomCommand($commandID)
}

function CheckNameForUnique($taskPath)
{
    try
    {
        $task = $Context.BindToObject($taskPath)
        return $False
    }
    catch
    {
        return $True
    }
}

# Bind to the Scheduled Tasks container
$scheduledTasksPath = $Context.GetWellKnownContainerPath("ScheduledTasks")
$scheduledTasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $scheduledTasksPath
$containerPath = $scheduledTasksPathObj.CreateChildPath("CN=$containerName")
$container = $Context.BindToObject($containerPath)

# If the task name is not unique, generate a unique one
$uniqueName = $taskName
for ($i = 1; $True; $i++)
{
    $taskPath = $containerPath.CreateChildPath("CN=$uniqueName")
    if (CheckNameForUnique $taskPath)
    {
        break
    }
    $uniqueName = "$taskName`_$i"
}

# Create a Scheduled Task
$task = $container.Create("adm-ScheduledTask", "CN=$uniqueName")

$task.ObjectType = "domainDNS"
$task.Description = $taskDescription
$task.Disabled = $False
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"
$task.DeleteTaskAfterExecution = $deleteTaskAfterExecution

$recurrencePattern = $task.GetRecurrencePattern()
$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_ONCE"
$recurrencePattern.PatternStartDateTime = $ProcessTime
$task.SetRecurrencePattern($recurrencePattern)

$task.SetInfo()

# Define actions and conditions

# Create a new set of actions and conditions
$actionsAndConditions = $task.ConditionedActions.Create()
$actionsAndConditions.ConditionsLogicalOperation = "ADM_LOGICALOPERATION_AND"
$actionsAndConditions.SetInfo()

# Add Run PowerShell Script action
$action = $actionsAndConditions.Actions.CreateEx("adm-RunScriptAction")
$action.ExecutionOptions = "ADM_ACTIONEXECUTIONOPTIONS_SYNC"
$scriptAction = $action.GetAction()
$scriptAction.ScriptType = "ADM_SCRIPTTYPE_POWERSHELL"
$scriptAction.ScriptDescription = $scriptDescription
$scriptAction.Script = $scriptToExecute.ToString()
$action.SetAction($scriptAction)
$action.SetInfo()
$actionsAndConditions.Actions.Add($action)

# Add the set to the Scheduled Task
$task.ConditionedActions.Add($actionsAndConditions)

# Set the scope of activity to All Objects
$scopeItem = $task.ActivityScopeItems.Create()
$scopeItem.BaseObject = $NULL
$scopeItem.Type = "ADM_SCOPEBASEOBJECTTYPE_ALL_DIRECTORY"
$scopeItem.Inheritance = "ADS_SCOPE_SUBTREE"
$scopeItem.Exclude = $False
$scopeItem.SetInfo()

$task.ActivityScopeItems.Add($scopeItem)
Action:Send e-mail notification (User has been deactivated)

If the 'Provide Manager Access to MB (Home Folder always provided)' property equals 'True' AND
If the 'Manager' property is not empty AND
If the User has an Exchange mailbox then
Action:Modify mailbox settings for the User: modify Mailbox Rights (add '%manager% (allow 'Full mailbox access')')
Action:Modify mailbox settings for the User: set Hide from Exchange address lists to 'True'
Action:Send e-mail notification (User Deactivation)

If the 'Provide Manager Access to MB (Home Folder always provided)' property equals 'False' AND
If the 'Manager' property is not empty then
Action: Send e-mail notification (User Deactivation)
Custom Command Step 2 is as follows:
If the 'Provide Manager Access to MB (Home Folder always provided)' property equals 'True' then
Action: Send e-mail notification (User Deactivation)

Always
Action: Run PowerShell script 'Delete User (send to helpdesk for approval)' for the User

Code: Select all

# Scheduled task settings
$containerName = "Deprovisioned User Processing" #must match a folder under scheduled tasks
$taskName = "Send to Helpdesk to confirm delete - %username%" 
$taskDescription = "This will process the disabling of the user account and provide Manager with access" 
$deleteTaskAfterExecution = $True
$ProcessTime = (Get-Date).AddDays(11)

# Script for action
$scriptDescription = "Delete Account and send to helpdesk for confirmation" # TODO: modify me
$scriptToExecute = {
[Reflection.Assembly]::LoadWithPartialName("Softerra.Adaxes.Adsi")
Import-Module Adaxes

$admNS = New-Object "Softerra.Adaxes.Adsi.AdmNamespace"
$admService = $admNS.GetServiceDirectly("localhost")

$userDN = (Get-AdmUser -Identity "%objectGUID%" -AdaxesService "localhost").DistinguishedName
$user = $admService.OpenObject("Adaxes://$userDN", $NULL, $NULL, 0)
$commandID = "{918f9c02-a91b-428e-88f7-6d4a6e3d5ae2}" #Custom Command GUID deprovision Step 3 TODO:Modify Me
$user.executecustomCommand($commandID)
}

function CheckNameForUnique($taskPath)
{
    try
    {
        $task = $Context.BindToObject($taskPath)
        return $False
    }
    catch
    {
        return $True
    }
}

# Bind to the Scheduled Tasks container
$scheduledTasksPath = $Context.GetWellKnownContainerPath("ScheduledTasks")
$scheduledTasksPathObj = New-Object "Softerra.Adaxes.Adsi.AdsPath" $scheduledTasksPath
$containerPath = $scheduledTasksPathObj.CreateChildPath("CN=$containerName")
$container = $Context.BindToObject($containerPath)

# If the task name is not unique, generate a unique one
$uniqueName = $taskName
for ($i = 1; $True; $i++)
{
    $taskPath = $containerPath.CreateChildPath("CN=$uniqueName")
    if (CheckNameForUnique $taskPath)
    {
        break
    }
    $uniqueName = "$taskName`_$i"
}

# Create a Scheduled Task
$task = $container.Create("adm-ScheduledTask", "CN=$uniqueName")

$task.ObjectType = "domainDNS"
$task.Description = $taskDescription
$task.Disabled = $False
$task.ExecutionMoment = "ADM_BUSINESSRULEEXECMOMENT_BEFORE"
$task.OperationType = "none"
$task.DeleteTaskAfterExecution = $deleteTaskAfterExecution

$recurrencePattern = $task.GetRecurrencePattern()
$recurrencePattern.RecurrenceType = "ADM_RECURRENCEPATTERNTYPE_ONCE"
$recurrencePattern.PatternStartDateTime = $ProcessTime
$task.SetRecurrencePattern($recurrencePattern)

$task.SetInfo()

# Define actions and conditions

# Create a new set of actions and conditions
$actionsAndConditions = $task.ConditionedActions.Create()
$actionsAndConditions.ConditionsLogicalOperation = "ADM_LOGICALOPERATION_AND"
$actionsAndConditions.SetInfo()

# Add Run PowerShell Script action
$action = $actionsAndConditions.Actions.CreateEx("adm-RunScriptAction")
$action.ExecutionOptions = "ADM_ACTIONEXECUTIONOPTIONS_SYNC"
$scriptAction = $action.GetAction()
$scriptAction.ScriptType = "ADM_SCRIPTTYPE_POWERSHELL"
$scriptAction.ScriptDescription = $scriptDescription
$scriptAction.Script = $scriptToExecute.ToString()
$action.SetAction($scriptAction)
$action.SetInfo()
$actionsAndConditions.Actions.Add($action)

# Add the set to the Scheduled Task
$task.ConditionedActions.Add($actionsAndConditions)

# Set the scope of activity to All Objects
$scopeItem = $task.ActivityScopeItems.Create()
$scopeItem.BaseObject = $NULL
$scopeItem.Type = "ADM_SCOPEBASEOBJECTTYPE_ALL_DIRECTORY"
$scopeItem.Inheritance = "ADS_SCOPE_SUBTREE"
$scopeItem.Exclude = $False
$scopeItem.SetInfo()

$task.ActivityScopeItems.Add($scopeItem)
Custom Command deprovision step 3 is as follows:
Always
Action: Execute custom command 'Remove all Future appointments created by a user (Sub-routines)' for the User

Code: Select all

$startDateProperty = "adm-CurrentDateTime" # Delete meetings starting today.
$endDateProperty = "$NULL" # Delete All Future Meetings
$exchangeWebServiceDllPath = "C:\Program Files\Microsoft\Exchange\Web Services\2.0\Microsoft.Exchange.WebServices.dll"

Import-Module $exchangeWebServiceDllPath

function GetDates ($property, $addDays)
{
    try
    {
        $value = $Context.TargetObject.Get($property)
        if ($value -is [Softerra.Adaxes.Adsi.AdsLargeInteger])
        {
            $value = [DateTime]::FromFiletime([Int64]::Parse($value))
        }
        $value = New-Object "System.Datetime" $value.Year, $value.Month, ($value.Day + $addDays), 0, 0, 0, ([System.DateTimeKind]::Local)
    }
    catch
    {
        $value = $NULL
    }
    
    return $value
}

function ClearProperties ($propertiesName)
{
    foreach ($name in $propertiesName)
    {
        if (($name -eq $NULL) -or 
            ($name -eq "adm-CurrentDateTime"))
        {
            continue
        }
        
        $Context.TargetObject.Put($name, $NULL)
        $Context.TargetObject.SetInfoEx(@($name))
    }
}

# Check whether the user has mailbox in Exchange Online
if (-not($Context.TargetObject.RecipientType -eq "ADM_EXCHANGERECIPIENTTYPE_MAILBOXENABLED" -and `
    $Context.TargetObject.RecipientLocation -eq "ADM_EXCHANGERECIPIENTLOCATION_OFFICE365"))
{
    return
}

# Get search parameters
$startDate = GetDates $startDateProperty 0
$endDate = GetDates $endDateProperty 1

# Get primary SMTP Address
$mailboxParams = $Context.TargetObject.GetMailParameters()
$emailAddresses = $mailboxParams.EmailAddresses
$primarySMTPAddress = $NULL

for ($i = 0; $i -lt $emailAddresses.Count; $i++)
{
    $emailAddress = $emailAddresses.GetAddress($i,[ref]"ADS_PROPERTY_NONE")
    if ($emailAddress.IsPrimary -and $emailAddress.Prefix -eq "smtp")
    {
        $primarySMTPAddress = $emailAddress.Address
        break
    }
}

if ([System.String]::IsNullOrEmpty($primarySMTPAddress))
{
    $Context.LogMessage("Cannot remove meetings scheduled by the user because the user's mailbox doesn't have a primary SMTP address.", "Warning")
    return
}

# Connect to Exchange Online via the Exchange Web Services API
$exchangeWebService = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
$office365Cred = $Context.GetOffice365Credential()
$exchangeWebService.Credentials = New-Object System.Net.NetworkCredential($office365Cred.Username, $office365Cred.GetNetworkCredential().Password)
$exchangeWebService.Url = "https://outlook.office365.com/EWS/Exchange.asmx"

# Get the user's calendar
$calendarFolderId = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Calendar, $primarySMTPAddress)
$calendarFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeWebService, $calendarFolderId)
$itemView = New-Object Microsoft.Exchange.WebServices.Data.ItemView(500)
    
$propertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet(
    [Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, 
    [Microsoft.Exchange.WebServices.Data.AppointmentSchema]::Organizer)

do
{
    $searchResult = $calendarFolder.FindItems($itemView)
    foreach ($item in $searchResult.Items)
    {
        if (!($item.IsMeeting))
        {
            continue # Not a meeting
        }
        
        $item.Load($propertySet)
        
        if ($startDate -eq $NULL -and $endDate -eq $NULL)
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
        elseif (($startDate -eq $NULL) -and
            ($item.Start -lt $endDate))
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
        elseif (($endDate -eq $NULL) -and 
            ($item.Start -ge $startDate))
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
        elseif (($startDate -ne $NULL) -and 
            ($endDate -ne $NULL) -and 
            ($item.Start -ge $startDate) -and 
            ($item.Start -lt $endDate))
        {
            $item.Delete([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete)
        }
    }
    
    $itemView.Offset = $searchResult.NextPageOffset
}
while($searchResult.MoreAvailable -eq $True)

# Clear date properties
ClearProperties @($startDateProperty, $endDateProperty)
Action: Delete the User


What kind of type is your Business Rule and how do you trigger it?

ggallaway
Posts: 9
Joined: Wed Aug 31, 2016 3:34 pm

Re: Office 365 Mailbox PST

Thu Jul 11, 2019 7:52 am

With the new ability to create parameters for your custom commands we no longer use a business rule to kick this process off. We just pass the deprovisioning date as a custom command parameter and trigger the first step in the process.

Post Reply
  • Information
  • Who is online

    Users browsing this forum: No registered users and 4 guests