Tag Archives: PowerShell

Active Directory recycle bin

I was under the impression I blogged about this years ago (while working on an Exchange 2010 –> 2016 migration) but I couldn’t find my own blog, so here it goes (again).

The Active Directory Recycle Bin saved my life a couple of times, not only my life but also my customer’s life. With the Active Directory Recycle Bin you can restore deleted object from Active Directory, and when using Azure AD Connect also automatically restore object in Azure Active Directory (assuming the deleted object was synchronized before the actual deletion of course).

 Too bad that’s it disabled by default, but enabling the Active Directory Recycle Bin to just a matter of start the Active Directory Administrative Center, select and right-click your root domain and select ‘Enable Recycle Bin…” as shown in the following screenshot:

Of course, it is also possible to enable this using PowerShell, just execute the following commands:

PS C:\> Import-Module ActiveDirectory
PS C:\> Enable-ADOptionalFeature "Recycle Bin Feature" -Scope ForestOrConfigurationSet -Target "ProExchangeAdmin.com"
WARNING: Enabling 'Recycle Bin Feature' on 'CN=Partitions,CN=Configuration,DC=ProExchangeAdmin,DC=com' is an irreversible action! You will not be able to disable 'Recycle Bin Feature' on 'CN=Partitions,CN=Configuration,DC=ProExchangeAdmin,DC=com' if you proceed.
 
Confirm
Are you sure you want to perform this action?
Performing the operation "Enable" on target "Recycle Bin Feature".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): y
PS C:\>

Wait until all Domain Controllers have replicated this change and you are all set.

But how does this work under the hood? Deleted object don’t stay in the recycle bin forever. By default, a deleted object continues to exist in Active Directory for 180 days, which is set on the msDS-deletedObjectLifetime attribute of the Directory Service object. On the object that is deleted, the isDeleted and isRecycled property come into play.

When a user object is deleted, the isDeleted property on the user is set to True. At this point it is logically deleted, but physically still available in Active Directory (in the Deleted Items container) and it can be restored. When the deleted object lifetime has passed, the isRecycled property is set to True and the Active Directory garbage collector knows it can remove this object from Active Directory (physically removed from the database).

This is graphically shown in the following figure.

It is possible to increase the deleted object lifetime by stamping a higher value on the msDS-DeletedObjectLifetime property. For example, to increase the default lifetime of 180 days to 2 years (=730 days) you can use the following PowerShell command:

PS C:\> Set-ADObject -Identity "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=ProExchangeAdmin,DC=COM" -Partition "CN=Configuration,DC=ProExchangeAdmin,DC=COM" -Replace:@{"msDS-DeletedObjectLifetime" = 730}

Restoring a deleted object from the recycle bin is easy. Open Active Directory Administrative Center, navigate to your domain and select deleted objects. Select and right-click the object and select Restore as shown in the following figure:

It is also possible to use PowerShell to restore a deleted object. For example, to find the user in the previous example we can use the following Powershell command:

PS C:\> Get-ADObject -Filter 'samaccountname -eq "Johns"' -IncludeDeletedObjects

Deleted           : True
DistinguishedName : CN=Labs | John Smith\0ADEL:7ee41efd-0034-46d7-9313-62360fff43fb,CN=Deleted Objects,DC=labs,DC=local
Name              : Labs | John Smith
                    DEL:7ee41efd-0034-46d7-9313-62360fff43fb
ObjectClass       : user
ObjectGUID        : 7ee41efd-0034-46d7-9313-62360fff43fb

PS C:\>

Pipe this output to the Restore-ADObject command and the deleted user will be restored.
Very simple and very useful, I always recommend enabling this.

Import-Module : The specified module ‘ExchangeOnlineManagement’ was not loaded

Such a simple problem, took me over an hour to find the simple solution…

When trying to use Exchange Online PowerShell I wanted to import the correct module using the Import-Module ExchangeOnlineManagement command. It failed with the following error:

Import-Module : The specified module 'ExchangeOnlineManagement' was not loaded because no valid module file was found in any module directory.

In the end it turned out to be some sort of typo…. Install-Module -Name ExchangeOnlineManagement works as expected. Sigh…. 🙂

Multiple mailbox users match identity “Mailbox1”

So I’m working on a nice Public Folder migration from Exchange 2016 to Exchange Online. Last week all preparations were performed and this morning I was planning to start the migrationbatch. Fourteen Public Folder mailboxes in Exchange 2016 to eighteen Public Folder mailboxes in Exchange Online. What could possibly go wrong….

Creating the new endpoint for the migrationbatch failed with an error saying “Multiple mailbox users match identity “PFMailbox1″. Specify a unique value” as shown in the following screenshot:

Or in plain text:

PS C:\PFScripts> $PfEndpoint = New-MigrationEndpoint -PublicFolder -Name PublicFolderEndpoint -RemoteServer $Source_RemoteServer -Credentials $Source_Credential
Multiple mailbox users match identity "Mailbox1". Specify a unique value.
    + CategoryInfo          : NotSpecified: (:) [New-MigrationEndpoint], MigrationPermanentException
    + FullyQualifiedErrorId : [Server=AM0PR09MB2402,RequestId=bccebc4f-d231-41d3-b8fe-a676311b3575,TimeStamp=22-8-2022 09:33:52] [FailureCategory=Cmdlet-MigrationPermanentException] 80069390,Microsoft.Exchange.Management.Migration. MigrationService.Endpoint.NewMigrationEndpoint
    + PSComputerName        : outlook.office365.com
PS C:\PFScripts>

This is strange since there’s no mailbox user named “Mailbox1”, there’s only one Public Folder mailbox named “Mailbox1” and that is holding the Public Folder hierarchy. But, last week I have been preparing the Public Folder migration, and one step was to create a Public Folder mailbox, just to see if it would work. I deleted the Public Folder mailbox, but it is a soft deleted state, and this conflicts with the creation of the Public Folder migration endpoint.

To find the Public Folder mailboxes including the soft deleted mailboxes, execute the following command against Exchange Online:

PS C:\PFScripts> Get-Recipient  -IncludeSoftDeletedRecipients -RecipientTypeDetails publicfoldermailbox | fl Name, OrganizationalUnit, DistinguishedName, ExchangeGuid

It will return a list of Public Folder mailboxes, including the ones in a soft deleted state. Clearly visible in the following screenshot is the soft deleted Public Folder mailbox:

Use the following command against Exchange Online to remove the soft deleted Public Folder mailbox:

[PS] C:\> Remove-Mailbox -PublicFolder "<ExchangeGuid>" -PermanentlyDelete

Wait some time for replication to happen in EXODS and try again to create the Public Folder migration endpoint. This time it succeeded.

Retrieve mailbox statistics in PowerShell for a large number of users

I’m currently working on a project where we are going to move 24,000 mailboxes from Exchange 2016 to Exchange Online. For planning purposes we would like to know the basic statistics, like the LastLogonTime and the number of items (both regular and deleted).

To retrieve this for my mailbox, you can use something like this:

[PS] C:\ >Get-Mailbox -Identity wesseliusj | Get-MailboxStatistics | Select DisplayName,LastLogonTime,ItemCount,TotalItemSize,DeletedItemsCount,TotalDeletedItemSize

DisplayName          : Wesselius, J
LastLogonTime        : 28-4-2022 11:24:46
ItemCount            : 1065
TotalItemSize        : 63.95 MB (67,060,296 bytes)
DeletedItemsCount    :
TotalDeletedItemSize : 5.421 MB (5,684,477 bytes)

The TotalItemSize and TotalDeletedItemSize are returned as text and not numeric. Since I want to export everything into a CSV file and import into Excel for further processing, it must be converted to a numeric value. This is called a calculated property and this is possible using the following option:

@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.ToBytes()}}

ToBytes() can also be ToKB(), ToMB() or ToGB() depending on your situation.

The previous command and output will now be something like this:

[PS] C:\>Get-Mailbox -Identity wesseliusj | Get-MailboxStatistics | Select DisplayName,LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.ToBytes()}},DeletedItemsCount,@{Name="TotalDeletedItemSizeMB";Expression={$_.TotalDeletedItemSize.Value.ToBytes()}}


DisplayName            : Wesselius, J
LastLogonTime          : 28-4-2022 11:24:46
ItemCount              : 1065
TotalItemSizeMB        : 67060293
DeletedItemsCount      :
TotalDeletedItemSizeMB : 5684477

Now use the Export-Csv command and we are good to go (you would hope 😊):

[PS] C:\>get-mailbox -ResultSize unlimited | Get-MailboxStatistics | Select DisplayName,LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.ToBytes()}},DeletedItemsCount,@{Name="TotalDeletedItemSizeMB";Expression={$_.TotalDeletedItemSize.Value.ToBytes()}} | export-csv -Path statistics.csv -nti

Sending data to a remote command failed with the following error message: [ClientAccessServer=EXCH2016,BackEndServer=exch2016.labs.local,RequestId=c0430cd6-6f4d-48a5-8434-d59ebcd91887,TimeStamp=28-4-2022 10:03:54] [FailureCategory=W
SMan-Others] The total data received from the remote client exceeded the allowed maximum. The allowed maximum is 524288000. For more information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo          : OperationStopped: (exch2016.labs.local:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : JobFailure
    + PSComputerName        : exch2016.labs.local

[PS] C:\>

Unfortunately, the Get-Mailbox command retrieves all 24,000 mailboxes in one run and then tries to use this as input for the Get-MailboxStatistics command. While this works for just a few mailboxes, it runs out of memory for a large set of mailboxes.

The solutions here (or one of the solutions) is to import all mailboxes into a variable, and loop through all mailboxes in this variable combined with the Get-MailboxStatistics command:

[PS] C:\> $Mailboxes = Get-Mailbox -Resultsize Unlimited
[PS] C:\> ForEach ($Mailbox in $Mailboxes) {Get-MailboxStatistics $Mailbox | Select  DisplayName,LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.ToBytes()}},DeletedItemsCount,@{Name="TotalDeletedItemSizeMB";Expression={$_.TotalDeletedItemSize.Value.ToBytes()}} | export-csv -Path statistics.csv -nti}

One last question I got is to add a UPN or alias of the user to the CSV file. UPN and alias are not in the object that’s returned by Get-MailboxStatistics, but are returned by the Get-Mailbox command. To get these properties in the output, again a calculated property must be used, similar to the size properties that were used earlier.

To retrieve the UPN, use something similar to the following:

@{Name = "UPN"; Expression={$Mailbox.UserPrincipalName}}

This will take the UserPrincipalName property of the first command (Get-Mailbox) and parse it into the output. The entire command will be:

[PS] C:\>ForEach ($Mailbox in $Mailboxes) {Get-MailboxStatistics $Mailbox | Select  DisplayName, @{Name = "UPN"; Expression={$Mailbox.UserPrincipalName}},LastLogonTime,ItemCount,@{Name="TotalItemSizeMB";Expression={$_.TotalItemSize.Value.To
Bytes()}},DeletedItemsCount,@{Name="TotalDeletedItemSizeMB";Expression={$_.TotalDeletedItemSize.Value.ToBytes()}}}

DisplayName            : Wesselius, J
UPN                    : j.wesselius@Exchangelabs.nl
LastLogonTime          : 29-4-2022 14:22:03
ItemCount              : 1098
TotalItemSizeMB        : 68714749
DeletedItemsCount      :
TotalDeletedItemSizeMB : 5822787

[PS] C:\>

This will create a proper CSV file with all the information I need, ready to import into Excel 😊

More information regarding working with large number of users (in Office 365) please check the following article: Running PowerShell cmdlets for large numbers of users in Office 365 – Microsoft Tech Community

Send from Alias in Exchange Online

A bit later than planned, but I was attending a training last week, but a long-awaited feature in Exchange is sending mail from another email address that is stamped on a user, a so called alias. In a typical environment, a mailbox has a primary SMTP address and this address is used to send an receive email. This can be something like j.wesselius@exchangelabs.nl. Besides this primary SMTP address there can be more SMTP addresses that can be used to receive mail, for example Mr.Exchange@exchangelabs.nl or MasterOfDisaster@exchangelabs.nl. In Exchange on-premises and Exchange Online, these Aliasses are only used to receive email, not to send email. Up until now that is (for Exchange Online, no idea if they want to enable this for Exchange on-premises).

Microsoft has started to roll out the Send From Alias in Exchange Online starting in January 2022 (it was already announced back in April 2021) and it is available in Outlook on the Web and Outlook for iOS and Outlook for Android. Outlook for the PC will follow, according to Microsoft in Q2, 2022.

To enable the Send from Alias in Exchange Online, execute the following command in Exchange Online PowerShell:

[PS] C:\> Set-OrganizationConfig -SendFromAliasEnabled $True

It takes some time before effective, in my case it worked the next day.

All SMTP proxy addresses on a mailbox are available for this. When you logon as a user and go to settings | Mail | Compose and Reply you can check which aliases you want to use. + Addresses are also shown and so are the mail.onmicrosoft.com addresses. Don’t know who thought this was useful, in my opinion you don’t want to use these (internal) addresses at all:

Now when you write a new email in Outlook on the Web and select the From option, you can select the email address that you checked in the previous step.

The proxy addresses that are selected in the first step (the OWA settings) will automatically available in Outlook for Android and Outlook for iOS.

When you send an email using one of these aliases as a from address, it will automatically be visible in the recipient mailbox, in this example in Gmail:

I don’t expect much use of this feature until Outlook for the desktop will offer it, but it’s a nice add-on (finally).