Setting up Office 365 using Azure DNS

Do you use Azure DNS? Azure DNS provide hosting of your DNS zones in the Azure infrastructure meaning that not only do you get the fault-tolerance, audit logging and SLA (99.99%) but you can also manage your DNS zones using Powershell. I recommend you read about it on including the FAQ and pricing information.

Implementing Office 365 requires a bit of DNS changes, and using Powershell this is very, very easy in Azure DNS. You need an account in Azure with admin-rights for Azure DNS, the name of the zone and the resource group it belongs to.

Change the input values to match the your environment and run this script from an editor (Powershell ISE or Visual Studio Code)

# This script automatically configures Azure DNS for O365
# Written by Per-Torben Sørensen (
# Version: 1.0
# Input values below
$azureadmin = “” # admin user in azure portal with DNS rights
$ttl = “600” # TTL for all records (in seconds)
$rgname = “testazuredns” # Use Get-AzureRmDnsZone after login to find this
$proofvalue = “MS=ms12345678” # Proof of ownership from the Office 365 portal
# Variables below
$cred = Get-Credential -Message “Log on” -UserName $azureadmin
$runscript = $false # Failsafe for accidental running
if ($runscript -eq $false)
Write-Host -ForegroundColor Red “Do NOT run this script non-interactively! Run from editor”
# Log on Azure RM and set DNS variable
Login-AzureRmAccount -Credential $cred
$dnszone = Get-AzureRmDnsZone -Name $zonename -ResourceGroupName $rgname
# Creating first TXT record (Proof of domain ownership)
New-AzureRmDnsRecordSet -Zone $dnszone -Name “@” -RecordType TXT -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -Value “$($proofvalue)”)
# Create CNAME records
New-AzureRmDnsRecordSet -Zone $dnszone -Name “autodiscover” -RecordType CNAME -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -cname “”)
New-AzureRmDnsRecordSet -Zone $dnszone -Name “sip” -RecordType CNAME -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -cname “”)
New-AzureRmDnsRecordSet -Zone $dnszone -Name “lyncdiscover” -RecordType CNAME -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -cname “”)
New-AzureRmDnsRecordSet -Zone $dnszone -Name “msoid” -RecordType CNAME -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -cname “”)
New-AzureRmDnsRecordSet -Zone $dnszone -Name “enterpriseregistration” -RecordType CNAME -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -cname “”)
New-AzureRmDnsRecordSet -Zone $dnszone -Name “enterpriseenrollment” -RecordType CNAME -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -cname “”)
# Modifies the existing TXT record
$txtrecord = Get-AzureRmDnsRecordSet -Zone $dnszone -Name “@” -RecordType TXT
Add-AzureRmDnsRecordConfig -RecordSet $txtrecord -Value “v=spf1 -all”
Set-AzureRmDnsRecordSet -RecordSet $txtrecord
# Create SRV records
New-AzureRmDnsRecordSet -Zone $dnszone -Name “_sip._tls” -RecordType SRV -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -Priority 100 -Weight 1 -Port 443 -Target
New-AzureRmDnsRecordSet -Zone $dnszone -Name “_sipfederationtls._tcp” -RecordType SRV -Ttl $ttl -DnsRecords (New-AzureRmDnsRecordConfig -Priority 100 -Weight 1 -Port 5061 -Target
$exchadr = ($zonename -replace “\.”,”-“)
$exchadr +=””
$mxrecords = @()
$mxrecords = New-AzureRmDnsRecordConfig -Exchange $exchadr -Preference 0
New-AzureRmDnsRecordSet -Zone $dnszone -Name “@” -RecordType MX -Ttl $ttl -DnsRecords $mxrecords
# This line allows you to select one or several DNS records and delete them from zone
Get-AzureRmDnsRecordSet -Zone $dnszone | Out-GridView -Title “Select record to delete” -OutputMode Multiple | Remove-AzureRmDnsRecordSet

RDGW access with Powershell

Hello everyone.

I’ve worked a bit with a redundant Remote desktop Gateway (RDGW) solution where we have 2 RDGW servers in NLB, providing a redundant access to various Remote Desktop collection. RDGW provides access without the need for VPN as it encapsulates RDP into HTTPS packets.

RDGW defines access through Client Access Policy (CAP) and Resource Access Policy (RAP). The CAP states the requirement (smart card/group membership) in order to connect through the RDGW. RAP states which resources internally are available to whom, based on group membership. RAP can provide access to either members of an AD group, members of a RDGW-defined computer group, or all resources on the network. So for a user to connect to a resource, we need both a CAP and RAP which both allows him/her access to use the RDGW and to access the resource respectively.

So when you have a redundant RDGW implementation with 2 or more RDGW servers, you need to make sure all servers have the same CAP and RAP configuration or you will have seemingly random connectivity issues for the end users. Once again Powershell saves the day.

The following script connects to each RDGW server specified and creates CAP and RAP and RDGW-computer group (if needed). It is still a work with progress with room for tuning and expanding, and as always copy with pride. The script is available here




File and DFS migration script

Currently I am in a project which will migrate several users in a large AD environment from one site to another as the current site is being decommissioned. This involves (among other things) migrating files and DFS Namespace to another file server and domain controllers and since this is a repetitive task for each department, I’ve made myself a sort of workbook in Powershell that I’d like to share with you.

This is a script which I load into an elevated PowerShell ISE, and change the input variables in the top and save a copy for each department. Then I can load the script I need, run all parameters and just mark and run selection (F8 hotkey) depending on the task at hand. The script is divided into 11 parts for tasks during preparation and during cut over. I’ve used comments to clearly divide the tasks.

To put it in perspective: The script linked will handle:

  • The department “Billing”
  • Short-reference “Bill”
  • Currently has a share named “Billing$” on the old file server
  • Linked to the DFS Namespace “\\\Bill” which is used for drive mapping.

The script will check and perform the different tasks needed to move their data to another file server and update both DFS Root Targets to the new domain controllers (which will host the namespace itself).and Folder Targets which points to the new file server.

The script can be downloaded here

Personally I found this makes it a lot easier, as the project goes on, to handle several ongoing migration jobs either in preparation or at cut over phase. It also makes sure the result is consistent and reduces the risk for failure.

As always feel free to use and customize to meet your own requirements

Removing mail stuck in retry queue in Exchange

Everyone working with mail has seen this, messages and NDRs stuck in retry queues mostly thanks to spam and malware.

These fine lines of Powershell will remove all messages from retry queues without sending NDR for each message.

# Empty Exchange retry queues without NDR
# Written by Per-Torben Sørensen (
# Version: 1.0
# Change the settings below
$Servers = "CAS01","CAS02" # Enter the name of all CAS servers
# Variables below
add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
foreach ($server in $servers)
$retryqueues = get-queue -Server $server -filter {Status -eq "Retry"}
foreach ($queue in $retryqueues)
Get-Message -Queue $queue.identity | Remove-Message -WithNDR $false -Confirm:$false

Import missing VM into Hyper-V

I want to share a little story which once again proved to me how easier IT is when you learn a little Powershell.

I recently had an outage on my Hyper-V server (Windows 10 server build 9841 btw) which hold my lab environment at home. The server lost connection with an SSD drive (E:\) containing almost 15 VMs, but this was luckily fixed my reattaching the SATA-cable to the drive.

However, when the server booted and my E:\ drive had returned, all the VMs on the drive was missing. Both in the Hyper-V management console and in powershell when I ran “Get-VM”. The files and VHDs was intact so it was only a matter of importing them to Hyper-V.

So here I had two choices:

  1. Import the VMs one by one in a 5-click wizard
  2. Import the VMs with Powershell

After fiddling around with sending the configuration files for each VM into a foreach loop, and still not making it work I tried something simpler. All I needed was a 1-liner which listed the config files and piped them into the import-vm cmdlet and the following line imported all the VMs on my E: drive into Hyper-V and I could start the VMs with no need to change any kind of configuration.

Get-ChildItem E:\Hyper-V -Recurse *.vmcx | Import-VM

Once again Powershell proves to be an amazing tool.