Windows – Unable to join domain. “An account with the same name exists in Active Directory. Re-using the account was blocked by security policy”

Scenario: The error below was received when joining a new computer to a domain (the computer object was pre-staged in AD by creating the computer object and resetting it).

Error: “An account with the same name exists in Active Directory. Re-using the account was blocked by security policy”

Solution: Add the following Reg Key:

Reg add HKLM\System\CurrentControlSet\Control\Lsa /v NetJoinLegacyAccountReuse /t REG_DWORD /d 1 /f

Error: 450 4.4.317 Cannot connect to remote server – 451 5.7.3 STARTTLS is required to send mail

Scenario: When attempting to send email from Exchange Online to Exchange On-Premises via Hybrid connectors, Exchange Online receives the following error message with a Defer Event: LED=450 4.4.317 Cannot connect to remote server [Message=451 5.7.3 STARTTLS is required to send mail]

This error means is that a certificate that supports TLS is present on the receiving (Exchange On-Premises) server, EXCEPT it cannot build a TLS connection because of an invalid configuration.

Solution: In our case, a new certificate that was recently installed on the Exchange On-Premises Server had a different TLS Certificate Name than what was configured on the Receive Connector. Setting the ‘TLSCertificateName’ on the receive connector with the NEW Certificate fixed the issue.

#Pull the Certificate
$Cert = Get-ExchangeCertificate -Thumbprint "<Thumbprint of server with SMTP Service>"

#Build the TLSCert String that will be used to compare and set
$TLSCert = (‘<I>’+$cert.issuer+'<S>’+$cert.subject)

#Check and compare the TLSCertificateName on the Receive Connector with $TLSCert
Get-ReceiveConnector "<Servername>\Default Frontend <Servername>" | Select TLSCertificateName
$TLSCert

#If the CertName is different, set the Receive Connector with $TLSCert
Get-ReceiveConnector "<Servername>\Default Frontend <Servername>" | Set-ReceiveConnector -TlsCertificateName $TLSCert

Renewing Certificate in a Hybrid Exchange On-Premises Environment (Concern of the SMTP Service)

Scenario: The third-party certificate is expiring and needs to be renewed on multiple Exchange On-Premises server that hosts IIS, SMTP, POP, and IMAP. There is concern about the hybrid components for successful SMTP Routing between Exchange On-Premises and Exchange Online since we are moving the SMTP Service to a different certificate.

Solution: The components below will walk you through creating the renewal and the components to look at:


1. Create a Cert request off of the expiring Cert Req (and then hand off to third party cert provider)

#Variable
$ExpiringCert = "<thumbprint of cert>"
$Req = "\\ExServer\c$\temp\cert\CertRenewal.req"
$Server = "ExServer"

#Run the command to get the .req
$txtrequest = Get-ExchangeCertificate -Thumbprint $ExpiringCert -server $Server | New-ExchangeCertificate -GenerateRequest -privatekeyexportable:$true

[System.IO.File]::WriteAllBytes($req, [System.Text.Encoding]::Unicode.GetBytes($txtrequest))

2. Complete the Pending Exchange Server Request (After downloading the cert from the third party vendor)

#Variable
$server = "ExServer"
$Renewed_Cert = "\\ExServer\c$\temp\cert\NewCert.crt"
$Renewed_Cert
Import-ExchangeCertificate -FileData ([System.IO.File]::ReadAllBytes($Renewed_Cert))  -Server $Server  -privatekeyexportable:$true 

3. Export the new cert (pfx) package so it contains the private and public key/components

#Variables
$c = "<new cert thumbprint"
$Password = "Batman"
$PFX =  "\\ExServer\c$\temp\cert\NewCert.pfx"
$server = "ExServer"



$cert = Export-ExchangeCertificate -Thumbprint $c -BinaryEncoded -Password (ConvertTo-SecureString -String $Password -AsPlainText -Force) -server $server
[System.IO.File]::WriteAllBytes($PFX, $cert.FileData)

4. Import the Certificate onto multiple servers

$ExchangeServers = get-exchangeserver
$Password = "Batman"
$ExchangeServers.name | %{
"Running on $_"
Import-ExchangeCertificate -FileData ([System.IO.File]::ReadAllBytes($PFX)) -Password (ConvertTo-SecureString -String $Password -AsPlainText -Force) -server $_
}

5. Moving Services

#Variables
      $New_Thumbprint = "<new cert thumbprint>"
      $ExchangeServers = Get-exchangeserver

 #Enable the IMAP,POP,IIS,and SMTP Services to the new cert
 $ExchangeServers.name | %{
     "Enabling Services on $_"
     Enable-Exchangecertificate -thumbprint $New_Thumbprint -server $_ -services IMAP,POP,IIS,SMTP -confirm:$false -force
}

6. Restarting Each Service

#Variables
$ExchangeServers = Get-exchangeserver      

#Restart the Services for IIS, IMAP, POP, and SMTP 
$ExchangeServers.name | %{
   "Restarting IIS on $_"
   iisreset $_

   "Restarting MSExchangeTransport on $_"
   Get-Service msexchangetransport -ComputerName $_ | Restart-service

   "Restarting IMAP and POP on $_"
   Get-Service msexchangeimap* -ComputerName $_ | Restart-service
   Get-Service msexchangepop* -ComputerName $_ | Restart-service
}

7. Check Outbound Connector in Exchange Online

#Notes: Our Subjectname didnt change, so we didnt have to do anything here

#Validate "Outbound_To_OnPremises" is configured with the subjectname in the Certificate/SAN

#Log into EAC --> Mail Flow --> Connectors --> Select the "<Outbound_To_OnPremises>" connector --> Edit "Security Restrictions" section if necessary.  The value should reflect a domain name or another identifiable piece of info in the new cert'.

8. Check Exchange On-Premises Receive Connectors

#Notes: We had to fix this one because the new $TLSCert was different than the TLSCertificateName on each Receive Connector; each connector still referenced the original cert.  Fixed by:  Set-ReceiveConnector "$_\Default Frontend $_" -tlsCertificateName $TLSCert

#Variables: 
$New_Thumbprint = "<new cert thumbprint>"
$New_Cert = Get-ExchangeCertificate -Thumbprint $New_Thumbprint -server "ExServer"
$TLSCert = (‘<I>’+$cert.issuer+'<S>’+$cert.subject)
$ReceiveConnectors = @()

#Check the TLSCertificateName on all Receive Connectors and compare to $TLSCert
$ExchangeServers.name | %{$ReceiveConnectors += Get-ReceiveConnector "$_\Default Frontend $_" | Select Identity, TLSCertificateName}

#To fix:    
$ExchangeServers.name | %{Set-ReceiveConnector "$_\Default Frontend $_" -tlsCertificateName $TLSCert}

9. Check the Exchange On-Premises Transport Service

#Notes: This should be done automatically

#Variables
$ExchangeServers = Get-exchangeserver   
$TransportService_Cert = @()

#Loop
#$ExchangeServers.name | %{$TransportService_Cert +=  get-transportservice $_  |Select Name,InternalTransportCertificateThumbprint}; $TransportService_Cert

10. Check the Exchange On-Premises Hybrid Send Connector “<Outbound to Office 365>”

#Notes: You may need to set this

#Variables
$SC = "Outbound to Office 365"
$New_Thumbprint = "new cert thumbprint"
$New_Cert = Get-ExchangeCertificate -Thumbprint $New_Thumbprint -server "ExServer"
$New_TLSCertificateName = (‘<I>’+$New_Cert.issuer+'<S>’+$New_cert.subject)

#Verify the TLSCertificateName on the SendConnector
$SendConnector_TLSCertificateName = Get-SendConnector -identity  $SC | Select TLSCertificateName

#Does the $SendConnector_TLSCertificateName match the NEW_TLSCertificateName? If Not, you may need to run the following:
Set-SendConnector "Outbound to Office 365"  -TlsCertificateName $New_TLSCertificateName

11. Check the ExOnline Inbound Connector “Inbound from …”

#Notes: We did need to fix this

#Variables
$New_Thumbprint = "<thumbprint of new cert>"
$New_Cert = Get-ExchangeCertificate -Thumbprint $New_Thumbprint -server "ExServer"
$New_TLSCertificateName = (‘<I>’+$New_Cert.issuer+'<S>’+$New_cert.subject)

#Set the Inbound Connector with the $New_TLSCertificateName value of the new Cert
  #Connect to Exchange Online PowerShell or the EAC GUI
  #If PowerSHell:
        $ExOnline_TLSSenderCertificateName = Get-InboundConnector "Inbound from ..." | Select TLSSenderCertificateName

#If GUI: Log into EAC --> Mail Flow --> Connectors --> Select the "Inbound from ..." connector --> Edit the "How to identify email sent from your email server" section. 


#To Fix:
#PowerShell: set-InboundConnector "Inbound from ..." -TlsSenderCertificateName $New_TLSCertificateName
#EAC:  Edit the "How to identify email sent from your email server" section with the #New_TLSCertificateNameValue

Configure a Distribution Group to send a reply message every time (Not an Out-of-Office Message)

Scenario: You need a distribution group to send a ‘specific’ reply message back to the sender, every time a sender sends to it. An Out-of-Office message will not do because it will only send a reply one time.

Note: Distribution Groups do not have this functionality, however there is a work around with using a shared mailbox.

Solution:
1. Create a Shared Mailbox that will host sending the reply messages. We will call it: ReplyMessage@steveman.com

2. Log into an Outlook client as the shared mailbox and create the following inbox rule:

“Apply this rule after the message arrives
have server reply using “blah blah blah


3. Even though this is a Inbox Rule, set your Distribution Group so it allows sending Out-of-Office (OOF) messages which is turned off by default. This is required for return messages:

Set-DistributionGroup DL01@steveman.com -SendOofMessageToOriginatorEnabled:$true

4. Create a Transport Rule OR add that shared mailbox to your distribution list. I chose the Transport Rule because it is cleaner to the end users — they wont start asking questions about this new account. We are using the AnyOfToCCHeader to trigger the rule if it the Distribution list is sent to.

New-TransportRule -name “BCC_Reply” -AnyOfToCCHeader DL01@steveman.com -blindcopyto ReplyMessage@steveman.com

Mailbox Dumpster (aka TotalDeletedItemSize aka RecoverableItems) hit the 100GB size quota due to a bloated recurring meeting

Scenario: You have a mailbox that is similar to the following scenario:

-On a Hold: A mailbox is protected by a hold such as a Litigation Hold, eDiscovery/In-Place Hold, SCC Compliance Hold, etc.

-Hit the Quota: The mailbox has either already hit, or is approaching, the mailbox dumpster 100GB quota

-Item Count to Size Ratio doesnt make sense, at first: When you run the following command you notice that there are very few items in the folder that is at or near the quota — it would seem that the item count and folder size doesn’t make sense for 200 items to equal 99GB. Command: get-mailboxfolderstatistics <name> -folderscope recoverable | Select Name, ItemsInFolder, FolderSize

-Symptoms experienced by the user: Users have a issue deleting email items OR may experience issues with calendaring events.

Investigation: We discovered that there is a long-lasting recurring meeting that the impacted user/mailbox was an attendee for. The organizer of the meeting would edit single occurrences of the meeting series to post meeting agendas and attachments (this is where the size bloat comes from). It appears there is a conflict with this user being on a hold, and retaining a collective buildup of all edited occurrences of the meeting series. There was around 200 individual meeting ocurrences of thise meeting series, and each item is now ballooned in size to just under 200MB each. This contributes to the size of the dumpster folder, and the overall dumpster quota.

Solution: There is a command that we can run that will cleanup all the duplicate calendar items in the dumpster, even when a mailbox is on a Hold:

start-managedfolderassistant <name> -holdcleanup.

However, in our scenario the email items lived in the Purges recoverable items folder and the command did not work in that folder. Using MFCMapi we had to do a Move (in MFCMapi language a Copy –> Paste with the move option selected) and put all those items into the Versions folder. When the messages were moved into the Versions folder, the command worked and within the hour all the duplicate messages that were ballooned in size were now gone AND the dumpster was well under quota.

Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send

Scenario:  You receive the following error when you attempt to Invoke-WebRequest from PowerShell:
Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send.

Solution: Run the following in PowerShell to make sure it uses TLS1.2

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12


GraphAPI – Move messages in a mailbox folder to another folder

Scenario: You want to move messages from one mailbox folder to another

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:

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

#2. Build your $AppURI of the source location of the mailbox folder items
#Multiple Examples:
$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders/inbox/Messages"   

$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders/AAMkADY3ODhkMDNlLTRjM2YtNDJjYi04YTkzLTFmNjFhYTcyMjA2NwAuAAAAAAAM5kRh6DylRZ4XsImGGVClAQA0fvQp6d6ET6JezCAd8xOWAAFrER8_AAA=/Messages"
                                
$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. Find All messages in that source folder
 $messages = @()
                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 if you want to see
                $Messages

#4. Move the messages you found in the step above to the destination folder
#Build a $Params Variable with the folderID we want to pass to
#You can use a Base64 ID
$params = @{
	                    DestinationId = "AAMkADY3ODhkMDNlLTRjM2YtNDJjYi04YTkzLTFmNjFhYTcyMjA2NwAuAAAAAAAM5kRh6DylRZ4XsImGGVClAQA0fvQp6d6ET6JezCAd8xOWAAFrER8_AAA="
                    } | Convertto-Json

#Or use the name of a common folder 
                    $params = @{
	                    DestinationId = "Inbox"
                    } | Convertto-Json

#Move the Messages
            $c = 0
            $T = $messages.id.count
            $messages.id | %{
                $m = $_
                $c++
                "$c / $t : Moving $M"
                $appuri = "https://graph.microsoft.com/v1.0/users/$mbx/messages/$m/move"
                        $RestSplat = @{ 
                            URI         = $appuri
                            Headers     = $(get-accesstoken)
                            Method      = 'POST' 
                            ContentType = "application/json" 
                            Body = $params 
                            }
                $move = Invoke-RestMethod @RestSplat 
            }

GraphAPI – Creating a Mailbox Folder via PowerShell

Scenario: You want to create mailbox folders using GraphAPI via PowerShell

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:

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

#2. Build your AppURI
$appuri = "https://graph.microsoft.com/v1.0/users/$mbx/mailfolders"

#3. Build your $params to include the new Folder Name and if it should be hidden
                $params = @{
        	         DisplayName = "TestGraphAPI"
	                 IsHidden = $false
                     } | ConvertTo-Json

#4. Build your RestSplat package
#Build your URI Package to POST
                $RestSplat = @{ 
                    URI         = $appuri
                    Headers     = $(get-accesstoken)
                    Method      = 'POST' 
                    ContentType = "application/json" 
                    Body = $params 
                }        

#5. Execute the RestSplat package
Invoke-RestMethod @RestSplat                       

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

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