Correcting hybrid routing addresses after updating SAMAccountName

I just recently got into a situation where customer with hybrid Exchange had to change many users SAMAccountName, which led to a whole bunch weird stuff due to hybrid routing addresses. So, quick script here to localize the users with Proxyaddresses that doesn’t match the SAMAccountName@tenantname.onmicrosoft.com and make sure that they get the correct address.

Remember that I’m no way responsible for what happens if you run this script. You shouldn’t run any script you find in a live environment, without knowing what it does.

# Variables, get all users and define your tenantname. Feel free to customize the $users variable to get a more accurate result for your domain
$users = Get-ADUser -Filter * -Properties proxyaddresses -SearchBase "OU=Users,DC=domain,DC=local"
$tenant = "tenantName"

# Now, for each object find...
$users | ForEach-Object {
    ## The correct routing address: SAMAccountName@tenant.mail.onmicrosoft.com
    $routingMail = "smtp:" + $_.samaccountname + "@" + $tenant + ".mail.onmicrosoft.com"
    ## The users proxyaddresses
    $proxy = $_.proxyaddresses
    ## Then, if the user doesn't have the correct routing address, either replace the wrong one or just add a new one if there wasn't one
    if ($proxy -notcontains $routingMail) {
        ### First, we find the bad proxyaddresses and make sure we take a not of it
        $proxy | ForEach-Object {
            switch -wildcard ($_) {
                "smtp:*@$tenant.mail.*" { $wrongProxy = $_ }
            }
        }
        ### Then, we try to remove the wrong proxy. If there was no proxy present, this will fail but we'll make sure we don't see any of that nonsense
        Write-host -ForegroundColor Red "Removing $wrongProxy"
        Set-ADUser -Identity $_.SamAccountName -remove @{proxyAddresses=$wrongProxy} -ErrorAction SilentlyContinue
        ### Lastly, we'll add the correct address.
        Write-host -ForegroundColor Green "Adding $routingMail"
        Write-host $routingMail
        Set-ADUser -Identity $_.SamAccountName -add @{proxyAddresses=$routingMail} -ErrorAction SilentlyContinue
    }
}

read more

Working with Azure and Terraform, the basics

Working with Azure and Terraform, the basics

There are a couple of ways off running Terraform code with Azure depending on how your workflow is designed. If you are running Terraform on your local machine, you can connect to Azure through PowerShell or Azure CLI and run the Terraform commands locally. This works fine for demo and development scenarios but when moving into production it is recommended to use a CI/CD pipeline.

When you run Terraform, you generate a state file that stores the current state of your managed infrastructure, configuration and metadata. You can read up on why Terraform uses a state file here but the short answer is: It enables Terraform to work with several cloud vendors and makes Terraform perform much better. The file usually resides on the machine you run your code on, but for teams working together it would be preferable to store it remotely.

FYI; Everything that I’m going to mention is readily available in the official Terraform docs so if you prefer to learn everything the hard way, or you just don’t like me rambling, feel free to dive straight into the nitty-gritty. I’m also currently reading Terraform: Up and Running, so if you’re into book-learning then that’s the one I recommend on this subject.

Running the Terraform in your favorite shell

Now that you’re sold on the idea of using Terraform to manage your infrastructure, you’d want to cut to the chase and run some code towards Azure. But hold on to your claws, Bub! First, we need to authenticate. When you’re starting out, you can get everything up and running by connecting to Azure with PowerShell or Azure CLI in the same terminal window as you are planning to run Terraform in.

You can connect to Azure by running the following Cmdlet in PowerShell or Azure CLI command, then follow the instructions:

# PowerShell
Connect-AzAccount

# Azure CLI
az login

For more information, read up on how to connect to Azure with PowerShell and Azure CLI in the Microsoft Docs.

After you have connected your shell to Azure, you can now run your Terraform config files directly towards Azure.

Working with a Service Principal

So far we have authenticated within a shell to run Terraform but there comes a time where you have to either run Terraform on a shared server or better yet through a CI/CD pipeline. When that time comes, you want Terraform to be able to authenticate so you or the people you work with don’t have to authenticate all the time.

You can define a Service Principal and secret as Environment variables, or directly in the configuration file. The first one is highly recommended as the alternative is to store sensitive information in plain text. You could also use a service principal with a client certificate.

To set up a service principal, you would need a Client ID (Application ID), Client Secret, your subscription ID, and tenant ID.

There is no reason to invent the wheel over again, so for the setup itself, I’ll just refer to the Terraform docs. However, I prefer to use PowerShell for all things, and they tend to use bash and Azure CLI in their examples so here are the steps that they refer to Azure CLI but the PowerShell counterpart.

# Connect to Azure
Connect-AzAccount

# Connect to Azure if using China, Germany or Government Cloud
Connect-AzAccount -Environment <AzureChinaCloud|AzureGermanCloud|AzureUSGovernment>

# Fetch your subscription, which also gives you the tenant ID where it resides
Get-AzSubscription

# Create Service Principal
New-AzADServicePrincipal -DisplayName "Terraform-Auth" -Role Contributor -Scope "/subscriptions/SUBSCRIPTION_ID"

# After following the steps in the Terraform Docs
# storing the credentials as environment variables
New-Item -Path "Env:\" -Name ARM_CLIENT_ID -Value "00000000-0000-0000-0000-000000000000"
New-Item -Path "Env:\" -Name ARM_CLIENT_SECRET -Value "00000000-0000-0000-0000-000000000000"
New-Item -Path "Env:\" -Name ARM_SUBSCRIPTION_ID -Value "00000000-0000-0000-0000-000000000000"
New-Item -Path "Env:\" -Name ARM_TENANT_ID -Value "00000000-0000-0000-0000-000000000000"

read more

PowerShell and how to work with network settings

This one seems confusing for most, as it might be the area where most Windows sysadmins rely on the GUI. If you ask (almost) any sysadmin how to change the IP on a server, they are going to answers how to get to the network adapters in the settings. Things like this seem to be to be one of the reasons why people are afraid of adapting Server Core.

Figuring that it’s time to inform the people and make sure that anyone can handle networking, even if they can only access the shell. Let’s summarize how to do most network related tasks in PowerShell.

Any requests?

Enable and Disable NIC

# List all network adapters
Get-NetAdapter

# Disable a specific network adapter, for instance the Wi-Fi adapter
# First by name, then by piping a specific adapter
Disable-NetAdapter -Name "Wi-Fi"
Get-NetAdapter -InterfaceIndex 5 | Disable-NetAdapter

# Activate a specific network adapter
# Again by name and then by piping a specific adapter
Enable-NetAdapter -Name "Wi-Fi"
Get-NetAdapter -InterfaceIndex 5 | Enable-NetAdapter

Get and set IP address

# Get the IP-address of a specific adapter
Get-NetIPAddress -InterfaceIndex 5

# Get just the IPv4-address
Get-NetIPAddress -InterfaceIndex 5 -AddressFamily IPv4

# Just the address itself
(Get-NetIPAddress -InterfaceIndex 5 -AddressFamily IPv4).IPAddress
# Set IPv4-address, using splatting for better readability
$ipParameter = @{
    InterfaceIndex = 22
    IPAddress = "10.0.0.22"
    PrefixLength = 24
    AddressFamily = "IPv4"
}
New-NetIPAddress @ipParameter

# Set the adapter to DHCP
Set-NetIPInterface -InterfaceIndex 22 -Dhcp Enabled

Set DNS server for NIC and reset DNS Cache

# Set DNS-server addresses on a specific NIC
$dnsParameter = @{
    InterfaceIndex = 5
    ServerAddresses = ("8.8.8.8","8.8.4.4")
}
Set-DnsClientServerAddress @dnsParameter

# Clear DNS cache 
Clear-DnsClientCache

read more

What is Azure Lighthouse

Working at an MSP / CSP have taught me many things. Mainly that keeping track of credentials is a bitch. I jest, but not really. Some features of the partner dashboard that Microsoft provides makes it easier, lets you jump into a customers tenant but it’s flawed. You would have to go through the Partner Dashboard, find the customer and then select a link to whatever service you want to manage. Microsoft realized that it’s a struggle and have created Azure Lighthouse, a cross-customer management solution. The service itself is free, but if you use other services with it you have to pay for those, obviously.

What you get in Azure Lighthouse <figcaption>What you get in Azure Lighthouse</figcaption></figure>

With Azure Lighthouse, any management service provider will be able to have one view of their entire customer base. Monitoring, compliance and security, all in one portal. This makes working with customers so much better, and eventually, make the experience better for end users.

I recommend reading up on the service on the Azure Lighthouse product page, but also take a look at this demonstration video.

read more

Using PowerShell to gather information from XML

Making a long backstory short, I was checking one of our local weather sites during one of the few warm summer days here in Northern-Norway. For most people, it ends there but I obviously started thinking that it would be so much easier to write a function that could check the weather for me. I head off to check their API and it turns out that they are working on a modern API but is serving out XML files based on location.

I have never worked with XML before, so the journey to extract the information I wanted was kind of interesting. I noted everything, so let’s take a look at how one can go about extracting the information one needs from XML and use it in PowerShell. Feel free to follow the lines of code.

Turns out my example Yr (a weather service in Norway) has changed a lot in it’s XML structure. The example still applies, but I’ll update this as soon as possible with new example data.

# Load the file, define it as XML.
$URL = "https://www.yr.no/sted/Norge/postnummer/9024/varsel.xml"
[xml]$file = Invoke-webrequest -uri $URL
# Check the result.
$file
# Check the property "weatherdata".
$file.weatherdata
# We want real time data, so let's continue with observations.
$file.weatherdata.observations
# Closing in at something. Checking out our options by using Get-Member...
$file.weatherdata.observations | Get-Member
# And now, weatherstation?
$file.weatherdata.observations.weatherstation
# Bingo.

read more