N-4 support for Windows Server Upgrades – Wow?

Windows Server 2025 is well and truly here, and Microsoft is pushing hard to convince you that this is the smoothest upgrade cycle in years. They’re not wrong but is it the whole story. If you’re running 2012 R2, 2016, 2019, or 2022, the new N‑4 in‑place upgrade support means you can jump straight to 2025 in one hop. That’s a big deal. But whether you really can do this is a different question.

If you’re still on 2012 R2, this is your last lifeline.

Media‑Based Upgrade: The Official Story vs Reality

Microsoft claims the ISO‑based upgrade takes “under an hour per server.” Sure, in a lab. With clean images. And no vendor agents. And no ancient NIC drivers. And no weird backup software from 2014. I was able to easily do it under these ideal conditions.

In the real world, which is often quite messy (today’s understatement), expect:

  • Several hours for typical servers – some of these old physical servers take 15 minutes to boot.
  • Longer for anything with third‑party agents, monitoring hooks, or legacy storage drivers
  • Rollback time if something breaks (and something always breaks). Do you have a rollback plan for your in-place upgrade? Does your backup actually work?

Still, the process is quite straightforward: mount ISO —> run setup —> choose “Keep files, settings, and apps” —> Ok, some form of conversation with a deity may help here.

Virtual Machines: The Easy Path (Mostly)

If you’re on Hyper‑V, Microsoft is right: upgrades are usually painless. Hyper‑V integration components update automatically during setup.

If you’re on VMware, Nutanix, Proxmox, or anything else, Microsoft’s advice is blunt but correct:

Update your guest drivers first. Outdated virtualization drivers are the #1 cause of upgrade failures.

Ignore this and you’ll be staring at a recovery console and re-considering your life choices.

Physical Servers: Where Things Get Messy

Microsoft politely hints that your 2012 R2 hardware is “about 15 years old.” Translation: Your server is a fossil. Don’t expect miracles.

You must validate:

  • NIC drivers
  • HBAs
  • RAID/storage controllers
  • PCIe cards
  • Out‑of‑band management firmware

If any of these lack 2025‑compatible drivers, you’re choosing between:

  • Buying new hardware
  • Virtualizing the workload
  • Moving it to the cloud
  • Or hoping

Planning: The Part Everyone Skips Until It’s Too Late

Microsoft’s checklist is great, but incomplete. But really put some thought into these as well …

  • Uninstall old antivirus/EDR agents as they break upgrades constantly
  • Disable third‑party disk encryption
  • Remove legacy monitoring agents (SolarWinds, SCOM, etc.)
  • Disconnect from SANs you don’t need during upgrade
  • Expect to reboot multiple times even after the upgrade completes

The main missing step: Fix whatever broke. Something always breaks.

You cannot in‑place upgrade domain controllers. Don’t even bother trying, let me help you here – no, stop, don’t, you can thank me later

The process for Active Directory upgrades remains the same as it has been for 20 years: Deploy new DC, Replicate, Demote / Promote, Raise Functional Levels.

Licensing: The Part Everyone Forgets – I say everyone, but it was me – I forgot.

If you have Software Assurance, you’re fine. If you rely on KMS, make sure it’s updated — 2025 requires new keys.

If the Upgrade Fails

Microsoft recommends:

  • Checking logs in C:\Windows\Panther
  • Running SetupDiag
  • Restoring from backup

Final Thoughts

If you didn’t test the upgrade on a clone first, you’re already headed for disaster – think of your future self.

You can find more details at Upgrading to Windows Server 2025 from Windows Server 2012 R2, 2016, 2019, or 2022 using Media (ISO) | Microsoft Community Hub

Looking at the Microsoft Agent Framework 1.0

Microsoft Agent Framework 1.0 is the Microsoft’s first production‑level, open‑source platform for building long‑running, autonomous, multi‑agent systems in .NET and Python. It formalises what developers have been improvising for the past year: structured reasoning loops, tool calling, multi‑agent orchestration, and governance. Basically, Microsoft thinks we need to move from ‘research toys’ to ‘cloud‑native automation components’ with deterministic workflows and enterprise boundaries.

What is it?

The framework is not a simple code library! it’s a runtime, SDK and, orchestration fabric:

Why care?

Agents are no longer simplistic ‘chatbots’. Agentic AI is shifting toward long‑running, autonomous systems that collaborate, reason, and operate reliably in production, aligning with the broader industry trend where LLMs are becoming cloud automation components, not fancy UI features.

How? or what’s inside an agentic application

Agents

In the start, Agents were basically just wrappers around various prompts. Now they are stateful runtime components that use LLMs to interpret inputs, call tools and MCP servers, maintain session state, and generate responses. This creates a clean abstraction that aligns well with cloud-native micro-automation.

Workflows

Workflows are deterministic graphs that enforce execution order, coordinate multiple agents, and support both checkpointing and human-in-the-loop interactions. They’re important because LLM’s are non-deterministic, they don’t respond the same way to the same inputs. In a business process determinism can be a key concern.

This separation of concerns is the most important architectural decision which relates ‘Reasoning / Interpretation’ to the Agent, and the overall execution policy and control to the Workflow giving us the best of both worlds.

Middleware

The middleware pipeline allows overall addition of logging, telemetry, filters and compliance logic to our application. Without this, governance typically fails.

Agent to Agent (A2A) communication

Agents can now communicate across runtimes (e.g. From Python to .NET) using a structured protocol.This opens up the multi-language development world for agents.

MCP Integration

Agents can dynamically discover and invoke tools without custom integration code. This defacto industry standard is a must-have for tool usage.

If you’re already in Azure, this will likely become your default agentic automation layer over the next year, or until the next announcements change the playing-field again.

If you’re multi‑cloud, it’s still worth having a look, because this is the direction the entire industry is moving. Frameworks help keep the gun-bearing monkey’s known as LLM’s under control.

AlmaLinux 10 – Install docker-ce

You can read lots of blogs about this. This is the simple minimal version 🙂

Assuming you’re doing everything as root, but if you aren’t then prefix these commands with sudo as appropriate for your environment.

dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker

That’s it. Done. Now if you want to allow non-root users to use docker.

 usermod -aG docker user   # user is the non-root user you want to be able to use docker

Permanently mount a CIFS share on Linux

Install the required packages

You will need to install the cifs-utils package to mount a network drive on an Ubuntu Linux system.

sudo apt-get install -y cifs-utils

For a Red Hat based system you will also need the cifs-utils package, installed by dnf

sudo dnf install -y cifs-utils

Create a mount point

Create a mount point for the CIFS share. eg.

sudo mkdir /srv/cifs/<share>      # where '<share>' is the name of the share you want mounted

Create a credentials file

sudo vim /etc/credentials.<share>   # where '<share>' is the name of the share you want mounted

Add the following contents to the credentials file, updating with your userid/password details to access your share.

username=<shareuser>
password=<sharepassword>

Make sure the credentials file is only visible to root

sudo chown root:root /etc/credentials.<share>      # where '<share>' is the name of the share you want mounted
sudo chmod 600 /etc/credentials.<share>

Add the mount to /etc/fstab

To mount the network drive permanently, you need to add an entry to the /etc/fstab file to ensure the share is mounted automatically when the system boots.

Open the /etc/fstab file in a text editor and add the following line:

//<ip address of your cifs server>/<share> /srv/cifs/<share> cifs credentials=/etc/credentials.<share> 0 0

Testing the mount

sudo mount -a
df -h


This should show the CIFS share mounted at the specified mount point.

AlmaLinux 9 & Centos 9 Stream builds can now be created for oVirt Nodes

When PR https://github.com/oVirt/ovirt-node-ng-image/pull/146 lands you will be able to build oVirt nodes using AlmaLinux 9 (new) and Centos 9 Stream (fixed).

There are still a few issues with AlmaLinux 9, not because of AlmaLinux, but because the oVirt engine force enables a bunch of Centos 9 Stream repositories breaking the system. You can get around this by basically disabling those repositories in /etc/yum.repos.d/ as they appear – bugs will be filed with the engine.

VS Code on Almalinux 9

Step 1. Add the signing key


sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc

Step 2. Add the repository


echo -e  "[vscode]\nname=packages.microsoft.com\nbaseurl=https://packages.microsoft.com/yumrepos/vscode/\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc\nmetadata_expire=1h" | sudo tee -a /etc/yum.repos.d/vscode.repo

Step 3. Refresh the yum meta data


sudo dnf update -y

Step 4. Install vscode


sudo dnf install code -y

Microsoft Edge on Almalinux 9

Step 1. Import the key


sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc

Step 2. Add the repos


sudo dnf config-manager --add-repo https://packages.microsoft.com/yumrepos/edge

Step 3. Refresh the yum meta data


sudo dnf update --refresh

Step 4. Install Edge


sudo dnf install microsoft-edge-stable

Microsoft Edge should now be available for you to use either via the CLI or the Gnome Deskop

Compacting WSL hard disk

Like many people I am an extensive user of WSL and Linux under Windows in general. It’s the only real option I have at work and it’s quite a reasonable proposition.

That being said though, the WSL vhdx files can grow as you’re doing Linux work and while you can (and should) clean up side the Linux environment it’s not reflected back to windows as free space.

So how do you compact your WSL file?

  1. Shutdown your WSL system.

    wsl.exe --list --verbose # note the verbose is required to get the state
    Output from wsl.exe to show running WSL environment

    wsl.exe --terminate Ubuntu-24.04
    This shows the output of the wsl command with the instance being terminated
  2. Shrink the disk using diskpart

    diskpart

    The diskpart dialogue is displayed

    You need to select the vhdx file for your WSL instance. The VHDX file is typically found in your AppData folder. In my case it was this.

    Windows explorer show the location of my VHDX file

    I copy the VHDX file location as a path.

    The easiest way to get the full filename + path is to use explorer to copy as path

    DISKPART> select vdisk file="C:\Users\geoff\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu24.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx"

    Output from selecting the vdisk in diskpart
  3. Compact the vdisk

    DISKPART> compact vdisk

    output of diskpart compact
  4. The results.

    BEFORE

    Explorer vhdx filesize before compact

    AFTER

    Explorer vhdx file size after compact

    As you can see, i’ve freed up nearly 6Gb.

Getting WSL2 just right

Recent changes to WSL2 by Microsoft have made using Linux on Windows even more comfortable. I’ll describe some of the options and their use below.

Firstly, do you have WSL2 installed? If not, then this will help https://learn.microsoft.com/en-us/windows/wsl/install-manual#step-1—enable-the-windows-subsystem-for-linux

In order to best use WSL, you of course need to have a distribution installed. Ubuntu is one of the easiest and most common to install.

wsl --list --online           #check what distros are available
wsl --install -d Ubuntu-24.04 #latest at the time of writing

Now that you have a distro installed, we have something to configure. There are 2 configuration files that customise the distribution experience under WSL2. wsl.conf and .wslconfig

wsl.conf contains per-distribution settings, whereas .wslconfig configures global settings for the WSL2 environment.

wsl.conf is stored in the /etc directory within the distribution.

.wslconfig is stored in your %UserProfile% folder.

.wslconfig

The .wslconfig file is in .ini format with the GA features found under section [wsl2]. There is also an [experimental] section for unreleased options.

Note: All options may not be available to you as they are Windows OS and WSL version dependent. You can reasonably assume if you are running Windows 11, 22H2 or higher that most of the options described below are available to you. This is not the complete list, just the one’s I have found to be quite useful

GA features that I find useful

Accessible via the [wsl2] section of the .wslconfig file

KeyValueNotes
memorymemory size (Mb, Gb)Default is 50% of the windows memory. I find it useful to constrain the memory (in conjunction with the experimental memory release features below)
processorsnumberDefault is the same as present in windows
localhostForwardingtrue/falseDefault is true, this allows your WSL2 application to be accessible via localhost:port
nestedVirtualizationtrue/falseAllow nesting inside WSL2, Windows 11+
networkingModestring, NAT, mirroredThe default is NAT, mirrored turns on mirrored networking mode. Mirrored mode is a great addition for many of my use cases.
firewalltrue / falseHyper-V firewall can filter WSL network traffic
dnsTunnelingfalsesee the experimental section
Some of the GA features

Experimental (though very useful) features

Accessible via [experimental] section of the .wslconfig file.

KeyValueNotes
autoMemoryReclaimdisabledDefault is disabled, but options list gradual and dropcache can dramatically return memory outside wsl2. I default to gradual.
sparseVHDfalseWhen set to true new VHD’s are created as sparse saving considerable disk with all the overprovisioning issues. By default, i’m using sparse, but then again i’ve been using sparse filesystems for many years
useWindowsDnsCachefalseIf you have dnsTunneling turned on then this option allows you to use or ignore what windows dns may’ve cached
hostAddressLoopbackfalseif networkingMode is set to mirrored then the loopback 127.0.0.1 address can be used to access the host and the container depending on where the listening resource may be running – windows or wsl2. This is a great option if you want better sharing between windows and wsl2 distro. For example, i’ve had a mongo client on windows and mongo in wsl2 ubuntu.
Some of the Experimental features

wsl.conf

As I mentioned above the /etc/wsl.conf within the distribution controls some interesting behaviours, especially on distro launch.

[boot]

systemd=true

Solves the problem where you’re reliant on systemd resources within your WSL2 distro. I normally have it turned on.

[automount]

KeyValueNotes
enabledtrue / falseAllows windows fixed drives to be automatically mounted under /mnt (or where the root key points). I have this enabled by default
root/mntWhere the mounts occur for auto mounted systems
mountFsTabtrue/falseAllow the /etc/fstab to be processed at WSL distro boot time. Great to get those SMB/NFS mounts going. I have this set to true as I use a lot of NFS in my test environment.

Some things to note.

Windows disks are mounted using Drvfs and are by default case sensitive. You can override this behaviour for all or single drives. More information is available at Per-directory case sensitivity and WSL – Windows Command Line (microsoft.com)

[network]

KeyValueNotes
generateHoststrue/falsewsl will generate an appropriate /etc/hosts file based on the windows environment. I generally set this to true (the default).
generateResolvConftrue/falsewsl will generate an appropriate list of dns resolvers. I generally set this to true (the default).
hostnamestringThis sets the hostname to be used within the distro. The default is the windows hostname, but this is useful if you run multiple WSL instances.

Navigation