Skip to content

2025

Outlook logging into Office 365 Error

If you get an error 4usqa / 3399614475 when trying to log in to Office 365 from Outlook (desktop or mobile) all of a sudden as especially if it's multiple users, try the following:

  1. Go to the Entra home page: https://entra.microsoft.com/
  2. Sign in as a tenant admin
  3. Search for Microsoft Information Protection API
  4. Go to "Properties"
  5. Select Yes for "Enabled for users to sign in?"

The solution was found on this Microsoft answers page.

Teeth Straightening

Back in 2023, I dedcided to get my teeth straighened. I did this for a couple of reasons:

  1. Let's be honest, it looks better!
  2. Straighter, non-overlapping teeth are easier to clean and maintain, which makes my life easier and helps keep the dentist bills down!

A few friends had recently been going through the process and were using Invisalign and, given my dentist was a provider, I decided to go with them too.

The process was as follows:

  1. Initial consultation with the dentist to discuss the process and get prices
  2. Initial scan of my teeth to create a 3D model and show a simulation of the potential end result (this cost about £350)
  3. A few weeks later, I had a follow-up appointment to discuss the simulation and decide if I wanted to proceed, which I obviously did - total cost was about £4,000
  4. I had an initial 29 week run and then a subsequent 14 week run with the option of more phases if I wanted to do some more "tweaking"
  5. You then wear the retainers for a further few months to help the teeth settle into their new positions before switching to only wearing them at night
  6. As part of the "package", you also get an included whitening treatment which you do once you get the retainers

The results

Before

Before

Week 2

This was taken shortly after starting, i.e. when the attachments were first attaching to my teeth. This photo shows the bottom tooth's overlapping more too.

Week 2

After

After

Pros and Cons

Pros

  • Once you sign up, you don't pay any more - i.e. you're not paying for one round of aligners, you're paying for the whole process, however many rounds that takes
  • You can take them out to eat, drink and clean your teeth, which is a lot easier than braces
  • They are far less visible than braces - most people didn't even notice I was wearing them

Cons

  • Retainers are a just the same as the aligners - due to the extremely tight fit, the lower aligner from my first set broke due to plastic fatigue of taking them out
  • Replacement retainers - sold as a pack of 3 pairs - are about £350, which is a lot for basically hitting print on a printer!
  • At week 15 of the initial set of aligners, I raised concerns that certain teeth hadn't moved as expected (i.e. based on the aligners I was wearing) but the decision was made to continue until the end of the set, rather than adjusting the aligners
  • This decision is probably the only reason the extra 14 weeks were needed as the only thing really being "fixed" in that second set were the two teeth I'd pointed out at week 15

Conclusion

I am very pleased with the overall result but a review and refinement half way though would improve the process. Also, reducing the cost of replacement retainers would be a good idea too, even if it means same price but more than 3 pairs.

CI & CD

This article is a summary of my understanding and use of Continuous Integration, Continuous Delivery and Continuous Deployment. There are several interpretations of these terms, some of which I'd argue are more correct than others. My interpretation is based on my experience and the processes I've followed and also articles by companies like AWS and by experts in the field like Dave Farley.

Continuous Integration

I always use a trunk-based approach, whether that be when building software, pipelines or Infrastructure as Code (IaC). I usually use short-lived feature branches rather than committing directly to the main branch, especially when working with others. I never use long-running branches, opting for feature toggles to manage the rollout of new features.

I then typically use pull requests to:

  • Verify the changes are the ones I intended
  • Run automated tests
  • Get feedback from others

Once the pull request is approved, I merge it into the main branch, usually using a squash commit. This triggers a build pipeline that will also run automated tests but it also builds packages, containers, etc... Once the build is successful, the deployment phase(s) of the pipeline begin.

Continuous Delivery

Every successful commit to main not only triggers the build process but also the deployment phase(s) of the pipeline, ultimately pushing code all the way to production.

Regardless of how many environments I have in place, the process tends to be the same for them all:

  • If environment is subject to change management, raise a change request
  • Deploy the change to the environment - if code:
    • Database changes first
    • Code changes second
  • Run automated tests (these may vary between environments)
  • If no automated tests exist, show a manual approval gate
  • Close the change as successful or failed as appropriate

If a deployment fails, sometimes excluding the development environment, then all changes are automatically reverted. This is to get the environment back to a known good state as quickly as possible.

Continuous Deployment

Continuous deployment is effectively the same as continuous deliver but with any manual gates removed. When building pipelines, I typically build them all to support continuous deployment but, when automated testing isn't available, revert to using a manual approval gate.

I'd say the biggest barrier to going to continuous deployment is the lack of automated testing or at least a lack of trust in your automated testing. If you can't trust your tests to catch issues, you can't trust your deployment to be successful. Once you have highly reliable and high confidence (and ideally high speed) automated testing in place, you can move to continuous deployment with confidence.

Delete a tag in ACR repository using CLI

If you have a tag in an ACR repository that you no longer need, you can delete it using the Azure CLI. It's a simple process and just requires remembering a few property names.

If you've not logged into Azure, do that first:

az login

Then, list the repositories in the registry to find the tag you want to delete:

az acr repository list --name acrname

Next list the tags for the repository you're interested in:

az acr repository show-tags --name acrname --repository your.repository

Once you've found the repository and tag you want to delete, you can delete it:

az acr repository delete --name acrname --image your.repository:1.2.3-alpha.456789

Obviously you'll need to replace acrname, your.repository and your.repository:1.2.3-alpha.456789 with your own values.

Output variables in PowerShell and GitHub Actions

When running a PowerShell script within a GitHub Actions workflow, you may wish to output variables from one step and access them in another.

Below is a simple example of outputting a variable in one step and accessing it in another:

name: Pass value from one step to another
on: 
  workflow_dispatch:
  push:
    branches:
      - main

jobs:
  PassTheParcel:
    runs-on: ubuntu-latest
    steps:
    - name: Determine some values
      id: calculate_values
      shell: pwsh
      run: |
        $ErrorActionPreference = "Stop" # not required but I always include it so errors don't get missed

        # Normally these would be calculated rather than just hard-coded strings
        $someValue = "Hello, World!"
        $anotherValue = "Goodbye, World!"

        # Outputting for diagnostic purposes - don't do this with sensitive data!
        Write-Host "Some value: $someValue"
        Write-Host "Another value: $anotherValue"

        "SOME_VALUE=$someValue" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
        "ANOTHER_VALUE=$anotherValue" | Out-File -FilePath $env:GITHUB_OUTPUT -Append

    - name: Use the values
      shell: pwsh
      env: 
        VALUE_TO_USE_1: ${{ steps.calculate_values.outputs.SOME_VALUE }}
        VALUE_TO_USE_2: ${{ steps.calculate_values.outputs.ANOTHER_VALUE }}
      run: |
        $ErrorActionPreference = "Stop" # not required but I always include it so errors don't get missed

        Write-Host "Values received were `"$($env:VALUE_TO_USE_1)`" and `"$($env:VALUE_TO_USE_2)`""

Whilst both examples use PowerShell, there is no requirement that both steps use the same shell.