• Upgrading to Windows 11 22H2 on the Release Preview channel

    Windows 11 logo

    I’m on leave this week and was listening to episode 835 of the RunAs Radio podcast “Updating Windows with Aria Carley” while out on my morning walk. I’ve been thinking about upgrading my main laptop to Windows 11 for a while now (Windows Update has indicated that it is compatible), but had been putting it off as my impression was that the initial release was possibly rushed out the door just a little bit early. Now that 22H2 is in the Release Preview channel, and scheduled for final release later this year, I figured it might not be too risky to give it a go given it’s had a bit more spit and polish applied.

    Screenshot from Windows Update - "Great news—your PC meets the minimum system requirements for Windows 11"

    Steps to upgrade from Windows 10 to Windows 11 Release Preview

    1. If you’re at all cautious, make sure you have a good backup first. I verified that Synology Active Backup for Business had a current backup of this machine, and for good measure, I clicked on the Version button and locked the latest backup to preserve it in case I wanted to roll back to a known good state in the future.

      Screenshot of Synology Active Backup for Business 'Backup Version Information' dialog

    2. From the Windows menu, launch Settings, then Windows Update and Windows Insider Programme (Yes, I’ve got the Australia/British English language settings). From here you can choose to join the Windows Insider Program. Click on Get started.

      Screenshot from Windows Update, Windows Insider Programme "Windows Insider Programme. Join the Windows Insider Programme to get preview builds of Windows 10 and provide feedback to help make Windows better.

    3. Click on Link an account

      Screenshot of dialog "Choose an account to get started"

    4. Select the account you want to use

      Screenshot of dialog for choosing an account

    5. Now you get to choose which Insider channel you want to join. I chose Release Preview but you could choose Dev Channel or Beta Channel if you prefer.

      Screenshot of the dialog "Choose your Insider settings", with "Release preview" highlighted

    6. One final chance to confirm (and review the privacy statement and programme agreement)

      Screenshot of the final confirmation dialog

    7. Now restart your computer!

      Screenshot of prompt to restart your computer

    8. After rebooting, you’re still running Windows 10, but if we go to Windows Update again and click Check for updates, you’ll now see a new section indicating that Windows 11, version 22H2 is available.

      Screenshot of Windows Update, showing 'Windows 11, version 22H2 is ready'

      Because I’d clicked Check for updates, it automatically started to download the Cumulative Update Preview (as you can see in the image above). But clicking on the Download and install button halted that and instead Windows 11 started downloading.

      Screenshot of Windows Update downloading Windows 11 22H2

    9. Finally, the download completes and Windows Update is ready to restart to begin installing Windows 11.

      Screenshot of Windows Update with the 'Restart now' button

    10. After a few minutes (I grabbed some lunch at this point so I’m not sure exactly how many), you can now sign in to Windows 11. Just to confirm this, I launched winver.exe to check (if the centred Start menu wasn’t already a clue!) that we are indeed running Windows 11.

      Screenshot of 'About Windows' app, showing "Windows 11 Microsoft Windows Version 22H2 (OS Build 22621.169)"

    11. For good measure, launch the Microsoft Store app, then Library and Get update to bring all your store apps up to date.

      Screenshot of Microsoft Store app, showing updates being downloaded

    12. If you use WSL, then run wsl --update to upgrade to the latest version. Before I did this, the output of wsl --status was:

      Default Distribution: Ubuntu-20.04
      Default Version: 2
      
      Windows Subsystem for Linux was last updated on 28/03/2022
      WSL automatic updates are on.
      
      Kernel version: 5.10.102.1
      

      But after wsl --update it now displays:

      Default Distribution: Ubuntu-20.04
      Default Version: 2
      WSL version: 0.61.8.0
      Kernel version: 5.10.102.1
      WSLg version: 1.0.39
      MSRDC version: 1.2.3213
      Direct3D version: 1.601.0
      DXCore version: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
      Windows version: 10.0.22621.169
      

    And with that, I’m up and running Windows 11 22621.169 (which was the latest version of Windows 11 available to the Release Preview channel at the time of writing)

  • 7 years being a Microsoft MVP

    MVP Logo

    A few days later than usual, but this morning I got an email to confirm I’m again a recipient of the Microsoft Most Valuable Professional (MVP) award!

    Dear David Gardiner,

    We’re once again pleased to present you with the 2022-2023 Microsoft Most Valuable Professional (MVP) award in recognition of your exceptional technical community leadership. We appreciate your outstanding contributions in the following technical communities during the past year:

    • Developer Technologies

    This is my 7th award since 2015.

    What’s the big deal?

    Well if nothing else, it is nice to be recognised, acknowledged, and thanked for the things you do in the developer community. That’s not to say that recognition, acknowledgement, and appreciation haven’t been forthcoming in other ways. And it’s not to say that the reason I do the things I do is that I want those from the community or Microsoft.

    Having said that, if the only feedback I got was negative (not that I actually get much of that) then it probably would cause me to reconsider if it was worth doing the things I do. So thanks Microsoft for your support!

    What’s in it for me?

    There are some tangible benefits that Microsoft give me which include:

    • Early access to Microsoft products
    • Direct communication channels with product teams
    • An invitation to the Global MVP Summit (usually held in Redmond USA, but online the last few years)
    • An executive recognition letter
    • A Visual Studio technical subscription
    • An Office 365 subscription
    • A certificate and glass trophy

    And not forgetting the occasional bit of swag! (the hoodie arrived in the mail earlier this week which was a nice surprise)

    Hoodie with Microsoft MVP branding, and a blue card with the text 'Thank you for everything you do to support technical communities around the world. Here is a token of our appreciation'

    Several 3rd party software vendors also offer discounts or free licenses of their products to MVPs. JetBrains is one I do take advantage of.

    Now it is true that some of these things I could purchase myself, or might be provided by my employer, but having them available and for use on my own personal and community projects is a bonus.

    The other big benefit for me is the networking connections I make both within Microsoft and the broader MVP community. Leveraging those connections has been a real advantage in organising speakers for the Adelaide .NET User Group.

    What’s in it for Microsoft?

    You might think with all those nice things, I’d feel obligated to constantly sing Microsoft’s praises? Not necessarily. I will indeed re-share public updates that I think are of interest, but while I’m sure they appreciate that, what I think Microsoft benefit from the most is me (and other MVPs) giving them candid, open and honest feedback. Because most MVPs sign a non-disclosure agreement, they can give that feedback confidentially. Let me tell you, MVPs can be pretty passionate and honest at times!

    What now?

    If you’re curious, check out my MVP Profile at https://mvp.microsoft.com/en-us/PublicProfile/5001655.

    Regardless of whether I get another MVP award or not, I’ll just keep on doing what I’m doing.

  • Passing variables between Azure Pipelines stages, jobs and deployment jobs

    Azure Pipelines logo

    Azure Pipelines, the continuous integration and continuous deployment feature of Azure DevOps, has the concept of variables. For scripts and tasks, they behave just like environment variables. There’s a bunch that are predefined that you might have used before, like System.AccessToken, System.DefaultWorkingDirectory and Build.ArtifactStagingDirectory.

    In YAML pipelines, you can define your own variables in:

    • a variable block in YAML

        variables:
          one: initialValue 
      

      This variable block can also reference previously defined variable groups. Variable groups are managed in the Library tab under the Pipelines menu of your Azure DevOps project.

        variables:
        - group: "Contoso Variable Group"
        - name: anothervariable
          value: 'Hi there'
      
    • The UI for the YAML pipeline.

      YAML UI Variables

    • A script using task.setvariable

        - bash: |
            echo "##vso[task.setvariable variable=myVar;]foo"
        - bash: |
            echo "You can use macro syntax for variables: $(myVar)"
      

    It’s this last case (using task.setvariable) that can be interesting, as by default that variable is only available to subsequent tasks in the same job. To access the variable from other jobs or stages, you need to add isoutput=true and give the step a name. eg.

      - bash: |
         echo "##vso[task.setvariable variable=myOutputJobVar;isoutput=true]this is the same job too"
        name: setOutput
    

    And here’s where it gets interesting. Depending on whether the task that is setting the variable (often referred to as an ‘output variable’) is in a regular job or a deployment job, and whether you’re wanting to reference the variable from another job in the same stage or a job in a subsequent stage, the syntax varies.

    If you’re not familiar with them, a deployment job is the YAML equivalent of the GUI-based ‘Classic’ Release pipelines. They are similar to regular pipeline jobs, but there are some differences too.

    Most of the existing examples for referencing output variables are listed in the documentation Set variables in scripts, but as deployment jobs have a different syntax, there’s another section under Deployment jobs. Unfortunately, between these two pages, not all the possibilities seem to be covered.

    So I came up with a pipeline workflow that correctly demonstrates these options:

    • Deployment Job to another Job in the same stage
    • Deployment Job to another Job in a different stage
    • Deployment Job to another Deployment Job in a different stage
    • Job to another Job in a different stage

    Here’s the entire YAML pipeline definition (source on GitHub)

    trigger:
     - master
    
    pool:
      vmImage: 'ubuntu-latest'
    
    stages:
    - stage: Stage1
      displayName: Stage 1
      jobs:
      - deployment: Stage1DeploymentJob1
        displayName: Stage 1 Deployment Job 1
        environment: Environment1
        strategy:
          runOnce:
            deploy:
              steps:
              - bash: echo "##vso[task.setvariable variable=my_Stage1DeploymentJob1_OutputVar;isOutput=true]Variable from $(Agent.JobName)"
                name: stepVar_Stage1DeploymentJob1
                displayName: Set my_Stage1DeploymentJob1_OutputVar
    
    - stage: Stage2
      displayName: Stage 2
      dependsOn: Stage1
      jobs:
      - deployment: Stage2DeploymentJob1
        displayName: Stage 2 Deployment Job 1
        environment: Environment2
        strategy:
          runOnce:
            deploy:
              steps:
              - bash: echo "##vso[task.setvariable variable=my_Stage2DeploymentJob1_OutputVar;isOutput=true]Variable from $(Agent.JobName)"
                name: stepVar_Stage2DeploymentJob1
                displayName: Set my_Stage2DeploymentJob1_OutputVar
    
      - job: Stage2Job2
        displayName: Stage 2 Job 2
        dependsOn: Stage2DeploymentJob1
        variables:
          varFrom_Stage2DeploymentJob1: $[ dependencies.Stage2DeploymentJob1.outputs['Stage2DeploymentJob1.stepVar_Stage2DeploymentJob1.my_Stage2DeploymentJob1_OutputVar'] ]
        steps:
          - checkout: none
          - bash: echo $(varFrom_Stage2DeploymentJob1)
            displayName: Display varFrom_Stage2DeploymentJob1
    
    - stage: Stage3
      displayName: Stage 3
      dependsOn: Stage1
      variables:
        varFrom_Stage1DeploymentJob1: $[ stageDependencies.Stage1.Stage1DeploymentJob1.outputs['Stage1DeploymentJob1.stepVar_Stage1DeploymentJob1.my_Stage1DeploymentJob1_OutputVar'] ]
      jobs:
      - deployment: Stage3DeploymentJob1
        displayName: Stage 3 Deployment Job 1
        environment: Environment3
        strategy:
          runOnce:
            deploy:
              steps:
              - bash: echo $(varFrom_Stage1DeploymentJob1)
                displayName: Display varFrom_Stage1DeploymentJob1
              - bash: printenv
                displayName: printenv
    
      - job: Stage3Job2
        displayName: Stage 3 Job 2
        steps:
          - checkout: none
          - bash: echo "##vso[task.setvariable variable=my_Stage3Job2_OutputVar;isOutput=true]Variable from $(Agent.JobName)"
            name: stepVar_Stage3Job2
            displayName: Set my_Stage3Job2_OutputVar
    
    - stage: Stage4
      displayName: Stage 4
      dependsOn:
        # Need to mention stage here to be able to reference variables from it, even though the dependency is implied by Stage2 and Stage3
        - Stage1
        - Stage3
        - Stage2
      jobs:
      - job: Stage4Job1
        displayName: Stage 4 Job 1
        variables:
          varFrom_Stage1DeploymentJob1: $[ stageDependencies.Stage1.Stage1DeploymentJob1.outputs['Stage1DeploymentJob1.stepVar_Stage1DeploymentJob1.my_Stage1DeploymentJob1_OutputVar'] ]
          varFrom_Stage2DeploymentJob1: $[ stageDependencies.Stage2.Stage2DeploymentJob1.outputs['Stage2DeploymentJob1.stepVar_Stage2DeploymentJob1.my_Stage2DeploymentJob1_OutputVar'] ]
          varFrom_Stage3Job2: $[ stageDependencies.Stage3.Stage3Job2.outputs['stepVar_Stage3Job2.my_Stage3Job2_OutputVar'] ]
        
        steps:
        - checkout: none
        - bash: |
            echo "varFrom_Stage1DeploymentJob1: $(varFrom_Stage1DeploymentJob1)"
            echo "varFrom_Stage2DeploymentJob1: $(varFrom_Stage2DeploymentJob1)"
            echo "varFrom_Stage3Job2: $(varFrom_Stage3Job2)"
          displayName: Display variables
        - bash: printenv
          displayName: printenv
    

    The stage dependencies result in the following flow:

    Azure Pipeline stage workflow

    Here’s the output from the Stage4Job1’s Display variables step:

    Starting: Display variables
    ==============================================================================
    Task         : Bash
    Description  : Run a Bash script on macOS, Linux, or Windows
    Version      : 3.201.1
    Author       : Microsoft Corporation
    Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/bash
    ==============================================================================
    Generating script.
    ========================== Starting Command Output ===========================
    /usr/bin/bash /home/vsts/work/_temp/8ce87e72-545d-4804-8461-3910a1412c90.sh
    varFrom_Stage1DeploymentJob1: Variable from Stage 1 Deployment Job 1
    varFrom_Stage2DeploymentJob1: Variable from Stage 2 Deployment Job 1
    varFrom_Stage3Job2: Variable from Stage 3 Job 2
    Finishing: Display variables
    

    Some things to note:

    • The format for referencing a deployment job from a different stage is $[ stageDependencies.<StageName>.<DeploymentJobName>.outputs['<DeploymentJobName>.<StepName>.<VariableName>'] ] - I’ve seen some online posts suggesting the environment name be used instead of the second DeploymentJobName, but I think that is incorrect - this format works for me.
    • As the comment in the YAML mentions, if you want to reference a variable from a job or stage, then you have to add that to your dependsOn list. The fact that Stage 1 is ‘upstream’ from Stage 4 (because Stage 4 explicitly depends on Stage 2 and Stage 3) isn’t enough.

    Summary

    In this post, we saw how to reference variables from previous Jobs or Deployment Jobs in either the same or different stages of an Azure Pipeline.