27 August 2020

How to Send Email with Office365 and PowerShell

This is nice and handy.
I came across this at Adam the Automator, it's 2 ways to send mail with PowerShell.

One is with authenticated send the other with direct send.

The authenticated way:

# Get the credential            
$credential = Get-Credential            
            
## Define the Send-MailMessage parameters            
$mailParams = @{            
    SmtpServer                 = 'smtp.office365.com'            
    Port                       = '587' # or '25' if not using TLS            
    UseSSL                     = $true ## or not if using non-TLS            
    Credential                 = $credential            
    From                       = 'sender@yourdomain.com'            
    To                         = 'recipient@yourdomain.com', 'recipient@NotYourDomain.com'            
    Subject                    = "SMTP Client Submission - $(Get-Date -Format g)"            
    Body                       = 'This is a test email using SMTP Client Submission'            
    DeliveryNotificationOption = 'OnFailure', 'OnSuccess'            
}            
            
## Send the message            
Send-MailMessage @mailParams
The direct send way:
## Build parameters            
$mailParams = @{            
    SmtpServer                 = '.mail.protection.outlook.com'            
    Port                       = '25'            
    UseSSL                     = $true               
    From                       = 'sender@yourdomain.com'            
    To                         = 'recipient@yourdomain.com'            
    Subject                    = "Direct Send $(Get-Date -Format g)"            
    Body                       = 'This is a test email using Direct Send'            
    DeliveryNotificationOption = 'OnFailure', 'OnSuccess'            
}            
            
## Send the email            
Send-MailMessage @mailParams
See the full blogpost here

21 August 2020

Messages that are sent by using the "Send As" and "Send on behalf" permissions are copied only to the Sent Items folder of the sender

UPDATED 21-08-2020 - Added Exchange Online method


This is something I didn't know existed but keeps popping up as a frequent question in our organization.

An outlook user with access to a shared mailbox, send as or send on behalf of rights sends an email from the shared mailbox, but the sent email doesn't get saved in the shared mailbox sent items folder but in the users sent items folder.

Since Exchange server 2010 SP2 update roll-up 4 it's possible to specify where the sent emails will be saved. This also goes for Exchange server 2013 CU9 and up.

First check the current settings for a shared mailbox:
Get-MailboxSentItemsConfiguration -Identity sharedmailboxname            
            
RunspaceId                  : 2d911aef-3416-42f9-9900-531d0fcdea94            
SendAsItemsCopiedTo         : Sender            
SendOnBehalfOfItemsCopiedTo : Sender            
Identity                    :            
IsValid                     : True
As you can see the "SendasItemsCopiedTo" and "SendOnBehalfOfItemsCopiedTo" is set to "Sender"
There are 2 settings to choose from: "Sender" "SenderAndFrom".

To set it to save in both mailboxes use:
Set-MailboxSentItemsConfiguration -Identity sharedmailboxname -SendAsItemsCopiedTo `
senderandfrom -SendOnBehalfOfItemsCopiedTo SenderAndFrom
Check to be sure:
Get-MailboxSentItemsConfiguration -Identity sharedmailboxname            
            
RunspaceId                  : 2d911aef-3416-42f9-9900-531d0fcdea94            
SendAsItemsCopiedTo         : SenderAndFrom            
SendOnBehalfOfItemsCopiedTo : SenderAndFrom            
Identity                    :            
IsValid                     : True
Set it to all shared mailboxes in a nice one liner for Exchange 2010:
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails sharedmailbox | Set-MailboxSentItemsConfiguration `
-SendAsItemsCopiedTo SenderandFrom -SendOnBehalfOfItemsCopiedTo SenderAndFrom
Set it to all shared mailboxes in a nice one liner for Exchange 2013:
Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails sharedmailbox | Set-Mailbox `
-MessageCopyForSendOnBehalfEnabled $True -MessageCopyForSentAsEnabled $True
For Exchange Online there are two ways of doing this, in is in the Office 365 Admin portal and the other is in PowerShell.

In the Portal go to Groups - Shared Mailboxes

Then find the Shared mailbox you want to edit and edit "Sent Items"

And here you will see the two toggles to choose you options

With PowerShell:

After loggin in to Exchange Online Check the shared mailbox you want to modify:

Get-EXOMailbox -Identity sharedmailbox@domain.com | FL

These are the attributes that we triggered from the GUI toggle within the Office365 Admin Center earlier:

MessageCopyForSentAsEnabled : True
MessageCopyForSendOnBehalfEnabled : True

Set these attributes for a single mailbox:
Set-EXOMailbox -Identity sharedmailbox@domain.com -MessageCopyForSendOnBehalfEnabled $true -MessageCopyForSentAsEnabled $true

Enable these settings on all your shared mailboxes in your environment:
Get-EXOMailbox -RecipientTypeDetails shared | Where-Object {$_.messagecopyforsentasenabled -eq "" }

If you have to return all shared mailboxes that has the Sent Items Copy enabled:
Get-EXOMailbox -RecipientTypeDetails shared | Where-Object {$_.messagecopyforsentasenabled -eq "true" }

Take the selection of the shared mailboxes that don’t have the Sent Items Copy enabled yet and combine that with the Set-Mailbox command that enables both Sent Items Copy attributes:

Get-EXOMailbox -RecipientTypeDetails shared | Where-Object{$_.messagecopyforsentasenabled -eq ""} | Set-EXOMailbox -MessageCopyForSendOnBehalfEnabled $true -MessageCopyForSentAsEnabled $true


20 August 2020

Bulk create certificates from .CSR to .CER with root and intermediate included with PowerShell (quick and dirty)

This script was born after I needed to create over 200 certificates requested by .csr files.

The regular way of pasting the content of the .csr into the certsrv site was to time consuming, boring and repetitive to do by hand.

But I couldn't find a script or method that would work for what I needed.

I had hoped that the famous PSPKI module by Vadims Podāns (https://www.pkisolutions.com/tools/pspki/) could help me out, and in a way it could but not entirely how I wanted it. Turned out the "foreach" I tried couldn't pass trough the "Submit-CertificateRequest" commandlet.

So this is what I came up with it requires some Notepad++ find and replace, it's a bit quick and dirty but does the job.

If somebody knows how to make this better, please drop a message.

It requires the PSPKI, found here or from PowerShell: 

Install-Module -Name PSPKI

The script:
Import-Module pspki            
            
cd C:\Scripts\Get-CertificateFromCSR\csr            
            
$PKI = "YourCAServer.domain.lan"            
$OutPath = "C:\Scripts\Get-CertificateFromCSR\IssuedCertificates"            
            
$status = Submit-CertificateRequest -path "C:\Scripts\Get-CertificateFromCSR\CSR\Certificate01.csr" -CA $PKI -Attribute "CertificateTemplate:Webserver"             
$ReqID = $status.requestid            
Get-IssuedRequest -RequestID $reqID -CertificationAuthority $PKI | Receive-Certificate -Path $OutPath\Certificate01 -Force            
cd $outpath\Certificate01            
$item = ls            
Rename-Item -path $item -newname Certificate01.cer            
$status = Submit-CertificateRequest -path "C:\Scripts\Get-CertificateFromCSR\CSR\Certificate02.csr" -CA $PKI -Attribute "CertificateTemplate:Webserver"             
$ReqID = $status.requestid            
Get-IssuedRequest -RequestID $reqID -CertificationAuthority $PKI | Receive-Certificate -Path $OutPath\Certificate02 -Force            
cd $outpath\Certificate02            
$item = ls            
Rename-Item -path $item -newname Certificate02.cer

Etc, etc, etc

04 June 2020

How to create key file and certificate file from pfx - Openssl

Install the Windows version of Openssl from:
https://slproweb.com/download/Win64OpenSSL-3_1_2.msi

Open a command prompt window in c:\Program Files\OpenSSL\Bin
(or even better, add Openssl to your Path)

Then type:

For the key file:
openssl pkcs12 -in [yourfile.pfx] -nocerts -out [keyfile-encrypted.key]
Example:
openssl pkcs12 -in c:\temp\mycertificate.pfx -nocerts -out c:\temp\keyfile-mycertificate.key

You will be asked for the pfx password (import password), and then asked to enter a password for the .key file (PEM pass phrase)

For the certificate:
openssl pkcs12 -in [yourfile.pfx] -clcerts -nokeys -out [certificate.crt]
Example:
openssl pkcs12 -in c:\temp\mycertificate.pfx -clcerts -nokeys -out c:\temp\certificate-mycertificate.crt

You will only be asked for the pfx password (import password) since the private key will not be exported.

And for .pfx to .pem

openssl pkcs12 -in file.pfx -out file.nokey.pem -nokeys 

openssl pkcs12 -in file.pfx -out file.withkey.pem

Convert x509 to PEM

openssl x509 -in certificatename.cer -outform PEM -out certificatename.pem



Convert PEM to DER

openssl x509 -outform der -in certificatename.pem -out certificatename.der



Convert DER to PEM

openssl x509 -inform der -in certificatename.der -out certificatename.pem

Convert PEM to P7B

Note: The PKCS#7 or P7B format is stored in Base64 ASCII format and has a file extension of .p7b or .p7c.
A P7B file only contains certificates and chain certificates (Intermediate CAs), not the private key. The most common platforms that support P7B files are Microsoft Windows and Java Tomcat.

openssl crl2pkcs7 -nocrl -certfile certificatename.pem -out certificatename.p7b -certfile CACert.cer



Convert PKCS7 to PEM

openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.pem



Convert pfx to PEM

Note: The PKCS#12 or PFX format is a binary format for storing the server certificate, intermediate certificates, and the private key in one encryptable file. PFX files usually have extensions such as .pfx and .p12. PFX files are typically used on Windows machines to import and export certificates and private keys.

openssl pkcs12 -in certificatename.pfx -out certificatename.pem



Convert PFX to PKCS#8
Note: This requires 2 commands

STEP 1: Convert PFX to PEM

openssl pkcs12 -in certificatename.pfx -nocerts -nodes -out certificatename.pem



STEP 2: Convert PEM to PKCS8

openSSL pkcs8 -in certificatename.pem -topk8 -nocrypt -out certificatename.pk8



Convert P7B to PFX
Note: This requires 2 commands

STEP 1: Convert P7B to CER

openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.cer



STEP 2: Convert CER and Private Key to PFX

openssl pkcs12 -export -in certificatename.cer -inkey privateKey.key -out certificatename.pfx -certfile  cacert.cer
Or:
openssl pkcs12 -export -out domain.name.pfx -inkey domain.name.key -in domain.name.crt
Or with intermediate and root:
openssl pkcs12 -export -out domain.name.pfx -inkey domain.name.key -in domain.name.crt -in intermediate.crt -in rootca.crt

27 May 2020

How to create a shared mailbox from hybrid Exchange directly in Exchange Online but also visible in on-premises Active directory

How to create a shared mailbox from hybrid Exchange directly in Exchange Online but also visible in on-premises Active directory
Now that's a mouthful, but a question that's asked often.
And that's not strange at all, because after moving most of your mailboxes to Exchange Online, the inevitable new shared mailbox request will pop up.

Only to find out that if created in the old way you need to manually move it Exchange Online.

And if you create shared mailbox in the ECP you will soon find that you problably made the wrong choice and the new mailbox is not visible in your on-premises Active Directory.

There's where this script comes to the recue.
It creates a remote shared mailbox, a distribution group for full access and send-as rights, adds that group to the mailbox, hides the distribution group because we only use it for access rights.
Then login to Exchange Online, disable POP, IMAP, Activesync and OWA, and resets the proxy settings if neccesary.

This can also be used to create usermailboxes, just tweak it to your needs.
It's also on my Github: https://github.com/brenkster/New-RemoteSharedMailbox

param ($Alias,$DisplayName)

#	Show countdown timer
           
Function Start-Countdown
{
    Param(
        [Int32]$Seconds = 600,
        [string]$Message = "Waiting for 10 minutes"
    )
    ForEach ($Count in (1..$Seconds))
    {   Write-Progress -Id 1 -Activity $Message -Status "Waiting for $Seconds seconds, `
$($Seconds - $Count) left" -PercentComplete (($Count / $Seconds) * 100)
        Start-Sleep -Seconds 1
    }
    Write-Progress -Id 1 -Activity $Message -Status "Completed" -PercentComplete 100 -Completed
}



#	Load Exchange Powershell module
#add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
add-pssnapin Microsoft.Exchange.Management.PowerShell.SnapIn
#	Load Active Directory Powershell module
import-module activedirectory
            
# Setup variables
$DomainController="servername.domain.lan"
$OU='domain.lan/Groups/Mail/Shared Mailboxes'
$OU2='domain.lan/Groups/Mail/Shared Mailbox Groups'
$UPNdomain = "@domain.nl"
$UPNRemoteDomain = "@domain.onmicrosoft.com"



if ($Alias)
{
    if ($Alias.Contains('@')) { $Alias = $Alias.Substring(0,$Alias.IndexOf('@')) }
    $AliasMailbox = Get-Mailbox $Alias -ErrorAction SilentlyContinue
    $AliasMailUser = Get-MailUser $Alias -ErrorAction SilentlyContinue
    if ($AliasMailbox -or $AliasMailUser)
    {
        Write-Host "The Alias specified already exists" -ForegroundColor red
        $Alias = $null
    }
}
while (!$Alias)
{
    $Alias = Read-Host -Prompt "Alias (max 20 caracters)"
    if ($Alias)
    {
        if ($Alias.Contains('@')) { $Alias = $Alias.Substring(0,$Alias.IndexOf('@')) }
        $AliasMailbox = Get-Mailbox $Alias -ErrorAction SilentlyContinue
        $AliasMailUser = Get-MailUser $Alias -ErrorAction SilentlyContinue
        if ($AliasMailbox -or $AliasMailUser)
        {
            Write-Host "The Alias specified already exists" -ForegroundColor red
            $Alias = $null
        }
    }
}

if ($DisplayName)
{
    $DisplayNameMailbox = Get-Mailbox $DisplayName -ErrorAction SilentlyContinue
    $DisplayNameMailUser = Get-MailUser $DisplayName -ErrorAction SilentlyContinue
    if ($DisplayNameMailbox -or $DisplayNameMailUser)
    {
        Write-Host "The Display Name specified already exists" -ForegroundColor red
        $DisplayName = $null
    }
}
while (!$DisplayName)
{
    $DisplayName = Read-Host -Prompt "Display Name (As many caracters as you like)"
    if ($DisplayName)
    {
        $DisplayNameMailbox = Get-Mailbox $DisplayName -ErrorAction SilentlyContinue
        $DisplayNameMailUser = Get-MailUser $DisplayName -ErrorAction SilentlyContinue
        if ($DisplayNameMailbox -or $DisplayNameMailUser)
        {
            Write-Host "The Display Name specified already exists" -ForegroundColor red
            $DisplayName = $null
        }
    }
}

# Setup more variables
$Alias=$Alias.ToLower()
$UPN=$Alias + $UPNDomain
$UPNRemoteRoutingAddress = $Alias + $UPNRemoteDomain

Sleep 10
# Create the SharedMailbox
Write-Host "Creating Shared Mailbox" -ForegroundColor green            
New-RemoteMailbox -RemoteRoutingAddress "$UPNRemoteRoutingAddress" -Shared -UserPrincipalName "$UPN" `
-OnPremisesOrganizationalUnit $OU -Alias $alias -Name $alias -DisplayName $displayname `
-PrimarySmtpAddress $UPN -SamAccountName $alias -DomainController $domaincontroller            
Write-Host "Created Shared Mailbox" -ForegroundColor green            
            
Sleep 10            
# Set the description for the SharedMailbox            
Write-Host "Set Description" -ForegroundColor green            
Set-ADUser $Alias -Description "Shared Mailbox t.b.v. $Displayname"            
Write-Host "Description set" -ForegroundColor green            
            
Sleep 10            
# Create the distributiongroup for security use            
Write-Host "Creating Office365 Distributiongroup" -ForegroundColor green            
New-DistributionGroup  -DisplayName "SM.$alias" -Type Security -Alias "SM.$alias" -Name "SM.$alias" -Organizationalunit $OU2            
Write-Host "Office365 Distributiongroup created" -ForegroundColor green            
            
Sleep 10            
# Hide distributiongroup            
Write-Host "Set Office365 distributiongroup hidden" -ForegroundColor green            
Set-DistributionGroup -Identity "SM.$alias" -HiddenFromAddressListsEnabled:$true            
Write-Host "Office365 distributiongroup set to hidden" -ForegroundColor green            
            
Sleep 30            
# Sync AADConnect and wait for the account to show up online            
Write-Host "Starting Adsynccycle now" -ForegroundColor red            
Invoke-Command -ComputerName servername.domain.lan -Port 5986 -UseSSL -ScriptBlock { Start-ADSyncSyncCycle -PolicyType Delta }            
Write-Host "Adsynccycle has run" -ForegroundColor green            
            
Write-Host "Waiting for AzureAD sync" -ForegroundColor green            
#Start-Countdown -Seconds 600 -Message "Waiting for 10 minutes"            
            
$Time = 600            
$i = 0            
Do {            
    $i++            
    Write-Progress -Activity 'Waiting for 10 minutes' -Status 'Status' -PercentComplete (($i/$Time)*100) -SecondsRemaining ($Time-$i)            
    Start-Sleep 1            
} Until ($i -eq $Time)            
            
# Set the PowerShell session to use the proxy            
netsh winhttp set proxy proxy.domain.lan:8080            
Write-Host "Proxy Set" -ForegroundColor green            
            
# Connect to ExchangeOnline PowerShell            
Connect-ExchangeOnline -ShowProgress $true            
Write-Host "Connected to ExchangeOnline" -ForegroundColor green            
            
# Disable Mailbox features            
Write-Host "Disabeling OWA, POP, IMAP, ActiveSync" -ForegroundColor green            
Set-CASMailbox -Identity $Alias -imapenabled $false -owaenabled $false `
-OWAforDevicesEnabled $false -popEnabled $false -ActiveSyncEnabled $false -PopUseProtocolDefaults $false -ImapUseProtocolDefaults $false            
Write-Host "OWA, POP, IMAP, ActiveSync disabled" -ForegroundColor green            
            
Sleep 10            
# Add the distributiongroup to the sharedmailbox with Full Access            
Write-Host "Setting Mailbox Full Access Permissions" -ForegroundColor green            
Add-MailboxPermission –Identity: $Alias –AccessRights:FullAccess –user:"SM.$Alias"
Write-Host "Full Access Permissions set" -ForegroundColor green

Sleep 10

# Add the distributiongroup to the sharedmailbox with Send-as
Write-Host "Setting Mailbox Send-as Permissions" -ForegroundColor green
Add-ADPermission –Identity "$Alias" –user "SM.$Alias" –ExtendedRights 'Send-as' -DomainController $DomainController            
Write-Host "Send-as Permissions set" -ForegroundColor green            
            
Sleep 10            
            
# Reset proxy to direct access            
netsh winhttp reset proxy            
Write-Host "Proxy Set to default" -ForegroundColor green            
Write-Host "Script Finished" -ForegroundColor green            
Write-Host "Close this window " -ForegroundColor Red