Increase Your Output: Essential Tools Every Developer Needs!

Maros Kukan
13 min readJun 13, 2023

--

Foreword

Give me six hours to chop down a tree and I will spend the first four sharpening the axe.
– Abraham Lincoln

In today’s rapidly evolving software development landscape, DevOps has emerged as a crucial methodology for streamlining collaboration, enhancing productivity, and accelerating software delivery. As Windows remains a popular choice for developers, especially in large enterprise environments, it becomes essential to harness the power of DevOps tools and technologies seamlessly on this platform.

In this article, we delve into the realm of Windows-based DevOps tooling, exploring the setup and utilization of essential tools that enable a robust and efficient development environment. We will embark on a journey to unleash the potential of Hyper-V, WSL2, Vagrant, VScode, and Git — powerhouse tools that equip developers with the necessary arsenal to conquer modern software development challenges.

Ground Zero

We start by opening a Windows PowerShell prompt as administrator. Depending on the current Windows build, features such as Windows Package Manager CLI or Windows Terminal are available by default from certain Windows OS build number. You can check and validate your build number using the Get-ComputerInfo command.

📝Note: In this article there is a difference between Windows PowerShell and PowerShell. The first one refers the legacy built-in and the second refers to newer PowerShell Core.

(Get-ComputerInfo).OsBuildNumber

📝Note: My starting point for this article is a fresh installation of Windows 11 build 22621 what was fully patched and deployed from the ISO image available at Microsoft.

Features

Hyper-V

Hyper-V is a virtualization technology that enables us to create and manage virtual machines. It supports virtual switches, snapshots, and integration services. It is an essential tool for engineers to explore various OS-specific features in a confined environment.

We can interact with Hyper-V using GUI tools such as Hyper-V Manager ( virtmgmt.msc) or PowerShell cmdlets, for example Start-VM. To address common workflows, we can write scripts such as vm_create.ps1 or vm_delete.ps1. We can also employ tools such as Vagrant, which can abstract many lower-level actions and provide additional benefits.

Before we enable the Hyper-V feature, I recommend to update the user’s group membership. It is necessary for interacting with Hyper-V as normal user without having an elevated command prompt.

Add-LocalGroupMember -Group 'Hyper-V Administrators' -Member $env:USERNAME

Next, we enable the feature itself. Later, the WSL feature will also ask for a machine restart. We skip it at this point.

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All -NoRestart

Let us move to the next feature in the list.

Windows Subsystem for Linux 2

Windows Subsystem for Linux 2 (WSL 2) is an enhanced version of the Windows Subsystem for Linux (WSL) introduced in Windows 10 and further improved in Windows 11. WSL 2 provides a more complete Linux kernel experience by running Linux kernel in a lightweight virtual machine on the Windows host.

Enabling WSL2 used to be a multi-step procedure, but nowadays is easy as running a single command which will automatically install and enable the Virtual Machine Platform and install the feature itself.

To use the most recent version of WSL, we use the --web-download option. To speed up the installation, we skip the distribution installation with --no-distribution.

wsl --install --web-download --no-distribution

📝Note: WSL is a prerequisite for running containers using Podman on Windows.

Once completed, we will perform a reboot.

Restart-Computer -Force

After reboot, we open an elevated Windows PowerShell prompt and validate that Hyper-V and WSL are enabled.

# Verify Hyper-V State
(Get-WindowsOptionalFeature -FeatureName Microsoft-Hyper-V-All -Online).State
Enabled

# Verify WSL State
wsl --version
WSL version: 1.1.3.0
Kernel version: 5.15.90.1
WSLg version: 1.0.49
MSRDC version: 1.2.3770
Direct3D version: 1.608.2-61064218
DXCore version: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows version: 10.0.22621.1702

With these features enabled we will move to installing essential tools that will help speed our development workflow.

Once these features are activated, we can swiftly progress to the installation of tools that will streamline our development workflow.

Packages

In this section, we will cover essential tools. These include Integrated Developer Tools, Version Control Systems, Package Managers to Build and Deployment Tools.

We start by opening a privileged Windows PowerShell prompt and using winget to install packages from a list.

📝Note: Winget is relatively new to the package management game on Windows. If you prefer something more established, I advise you to use Chocolatey.

💡Tip: For the Nerd Fonts below, I was having issues rendering glyphs using version 3.x.x. Therefore I selected 2.3.3 which worked well,

# Install Nerd Font
winget install --id "DEVCOM.JetBrainsMonoNerdFont" --version 2.3.3 --silent --accept-source-agreements

# Define Packages
$packages = @(
"Microsoft.PowerShell",
"Hashicorp.Vagrant",
"RedHat.Podman",
"Kubernetes.minikube",
"Git.Git",
"Microsoft.WindowsTerminal",
"Starship.Starship",
"Postman.Postman",
"Microsoft.VisualStudioCode",
"Python.Python.3.11"
)

# Install Packages
foreach ($package in $packages) {
winget install --id $package -e --silent
}

After the installation of the last package has been completed successfully, we need to relaunch the Windows PowerShell so that the $PATH variable is updated and new applications are reachable from the shell.

Once we have installed all applications from the previous step, we will update execution policy for Windows PowerShell (required for starship prompt).

Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force

Finally, we will enable trust for PowerShell Gallery repository and install additional modules.

# Enable Trust for PSGallery Repository for PowerShell
pwsh -c "Set-PSRepository -Name PSGallery -InstallationPolicy Trusted"

# Install required modules for PowerShell
pwsh -c "Install-Module -Name Terminal-Icons"
pwsh -c "Install-Module -Name z"

The Terminal-Icons module enhances your terminal experience by seamlessly incorporating visually descriptive icons that correspond to specific file extensions. The z module lets you quickly navigate the file system in PowerShell based on your cd command history. It’s a port of the z bash shell script.

Dotfiles

The term “dotfiles” comes from Unix-like systems, where files and directories starting with a dot (.) are hidden. These hidden files store personalized configurations, and the term “dotfiles” refers to these hidden configuration files.

This concept can be adopted for Windows as more applications store their configuration in a text-based format such as JSON. These files can be checked out in the version control system and easily synced between machines.

The following part is a simplified version of the full description found in this repository.

# Optional but recommended to set default branch name
git config --global init.defaultBranch main

# Create a new dotfiles directory in your home folder and initialize a bare repository.
New-Item -Path $HOME\dotfiles -ItemType Directory -Force; git init --bare $HOME\dotfiles

# Optionally hide this folder from explorer directory listening
Set-ItemProperty -Path $HOME\dotfiles -Name Attributes -Value ([System.IO.FileAttributes]::Hidden)

# Create a runtime alias for ease of use
function config()
{
git.exe --git-dir=$HOME\dotfiles --work-tree=$HOME $args
}

# Optionally hide untracked files
config config --local status.showUntrackedFiles no

# Configure the upstream repository
config remote add origin https://github.com/maroskukan/dotfiles-win

# Pull from origin
config pull origin main

Once the pull operation completes, we open Windows Terminal and confirm the changes are in effect.

Windows Terminal with Starship prompt

In the following section, we explore some of these applications in greater detail.

Windows Terminal

Windows Terminal is a modern and feature-rich terminal application. It supports profiles, tab splitting, command palettes, and custom color schemes. The configuration file is defined in JSON format.

PowerShell

PowerShell also known as PowerShell Core is a cross-platform, open-source scripting language and command-line shell developed by Microsoft. It is a modern and powerful version of PowerShell that runs on Windows, Linux, and macOS, providing a consistent scripting and automation experience across different platforms.

PowerShell offers an extensive set of commands and features for managing and automating system tasks, interacting with APIs, and working with various data formats such as JSON. With its cross-platform capabilities, PowerShell Core enables users to write and run scripts seamlessly on different operating systems, making it a versatile tool for system administrators, developers, and IT professionals. It is also extensible trough packages. My favorite include PSReadLine, Terminal-Icons and z.

Starship

Starship prompt is a versatile and cross-shell prompt that offers a range of benefits to enhance the command-line experience. Its main advantages include cross-shell compatibility, allowing us to enjoy a consistent prompt experience across different shell environments (e.g. PowerShell, Bash and Zsh). The prompt is highly customizable, enabling you to personalize it according to your preferences and display relevant information such as Git status, runtime version, and current directory.

With its lightweight and fast performance, the prompt doesn’t compromise shell responsiveness. The rich visual elements, including Unicode symbols and colorization, make the prompt visually appealing and easy to distinguish. It is a perfect match for Nerd Fonts. Starship’s extensibility allows users to create custom modules and themes, expanding its functionality.

Git

Git is a widely used distributed version control system written by Linux Torvalds. It provides a framework for tracking changes in software development projects. It offers a range of features that enable efficient collaboration, version management, and code organization.

Git allows developers to create local repositories on their machines, make changes to files, and track those changes over time. It provides branching and merging capabilities, allowing multiple developers to work on different features simultaneously and later integrate their changes seamlessly.

Git’s distributed nature enables developers to work offline and synchronize their changes with remote repositories when connected. It also offers robust conflict resolution mechanisms to handle merge conflicts. With its popularity and extensive ecosystem, Git has become a standard tool in the software development industry, facilitating efficient and scalable version control workflows.

VS Code

Visual Studio Code is a lightweight and versatile source code editor developed by Microsoft. It combines powerful features, such as intelligent code completion, debugging, and Git integration, with a simple and intuitive user interface. Extensions are available in the marketplace. My favorites include Copilot, GitHub Copilot Labs, PowerShell, Python, GitLens, Ansible, YAML, Markdown All in One, Remote WSL, SSH, and Dev Containers.

VS Code provides a highly customizable and productive environment for coding across various programming languages and platforms. Its focus on performance, versatility, and ease of use has made it a popular choice among developers for both small projects and large-scale applications.

💡Tip: Although Visual Studio Code is open source, this distribution includes Microsoft-specific customizations. If you are looking for free open-source distribution, explore VSCodium.

Postman

Postman is a comprehensive API development and testing tool that simplifies the process of building, documenting, and testing APIs. It provides a user-friendly interface that allows developers to send HTTP requests, view responses, and analyze API behavior. With Postman, users can easily create requests using different HTTP methods, set headers, add parameters, and handle authentication. It supports various types of requests, including GET, POST, PUT, DELETE, and more.

Postman also enables the creation of collections, allowing users to organize and group related requests together. This is my primary tool when learning and interacting with new API endpoints. The code generation feature is great starting point moving to language specific implementation.

Podman

Podman is an open-source container runtime tool that allows users to manage containers and container images on Linux-based systems. It provides a command-line interface (CLI) for running and managing containers without requiring a separate daemon process. With Podman, users can create, run, stop, and remove containers, as well as manage container networks and volumes.

One of the key advantages of Podman is its ability to run containers as non-root users, enhancing security and reducing potential vulnerabilities. Podman is also compatible with Docker, enabling users to run existing Docker images and work seamlessly with Docker-compose files. Additionally, Podman supports the use of rootless containers, allowing non-root users to create and manage containers without administrative privileges.

Overall, Podman offers a lightweight and user-friendly alternative to traditional container runtimes, providing powerful container management capabilities for Linux-based systems.

💡Tip: When it comes to running containers on Windows, I used to be a long-time Docker Desktop user. When they changed the licensing policy, I decided to run the docker daemon inside a WSL2 instance with systemd enabled. I recently started to explore Podman as an alternative.

In the Packages section, we installed Podman using winget. To complete the setup there are few additional steps required.

We need to initialize the Podman machine (server-side), which is a custom WSL2 instance (container) based on Fedora project.

podman machine init
podman machine set --rootful
podman machine start

💡Tip: Rootful mode is required in case containers need to access TCP/UDP ports below 1024. More details can be found in the documentation.

You can inspect the configuration by using the following arguments.

podman machine inspect
[
{
"ConfigPath": {
"Path": "C:\\Users\\mk\\.config\\containers\\podman\\machine\\wsl\\podman-machine-default.json"
},
"ConnectionInfo": {
"PodmanSocket": null,
"PodmanPipe": {
"Path": "\\\\.\\pipe\\podman-machine-default"
}
},
"Created": "2023-06-12T06:15:25.8578639-07:00",
"Image": {
"IgnitionFilePath": {
"Path": ""
},
"ImageStream": "35",
"ImagePath": {
"Path": "C:\\Users\\mk\\.local\\share\\containers\\podman\\machine\\wsl\\podman-machine-default_fedora-podman-amd64-v37.0.37.tar"
}
},
"LastUp": "2023-06-12T07:20:05.1437211-07:00",
"Name": "podman-machine-default",
"Resources": {
"CPUs": 4,
"DiskSize": 2786066432,
"Memory": 1043918848
},
"SSHConfig": {
"IdentityPath": "C:\\Users\\mk\\.ssh\\podman-machine-default",
"Port": 65529,
"RemoteUsername": "user"
},
"State": "running"
}
]

As you can see the Podman client communicates with the server using a named pipe.

Get-ChildItem '\\.\pipe\podman-machine-default'

Directory: \\.\pipe


Mode LastWriteTime Length Name
---- ------------- ------ ----
----- 12/31/1600 4:00 PM 2  podman-machine-default

From WSL point of view, a new instance was registered.

wsl --list
Windows Subsystem for Linux Distributions:
podman-machine-default (Default)

We perform final verification by creating a container from ubi9-micro image and printing the OS information.

 podman run --rm ubi9-micro cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="9.2 (Plow)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="9.2"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Red Hat Enterprise Linux 9.2 (Plow)"
ANSI_COLOR="0;31"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9"
BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9"
REDHAT_BUGZILLA_PRODUCT_VERSION=9.2
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.2"

Ansible

Ansible, created by Michael DeHaan and now owned by Red Hat, is an open-source automation tool that simplifies task automation, configuration management, and application deployment. It uses declarative language to define system states and configurations, enabling infrastructure management as code. With Ansible, developers can automate tasks, orchestrate applications, and leverage its agentless architecture and extensive module library. Ansible streamlines development workflows ensures consistency, and fosters collaboration among teams.

Ansible is not directly support on Windows. However, we can run it inside a container provisioned by Podman. The following diagram depicts the interaction between various components.

Ansible Execution Environment

To demonstrate this workflow in practice, we create a sample inventory and playbook file in the current working directory.

type .\inventory.ini
localhost ansible_connection=local

type .\playbook.yml
---
- name: Sample Playbook
hosts: localhost
gather_facts: false

tasks:
- name: Ping
ansible.builtin.ping:

- name: Gather system facts
ansible.builtin.setup:

- name: Print system facts
ansible.builtin.debug:
var: ansible_facts.env

To execute this playbook, we will leverage the creator-ee container image.

podman run --rm --workdir /ansible `
-v ${PWD}:/ansible ghcr.io/ansible/creator-ee:latest `
ansible-playbook -i inventory.ini playbook.yml

The playbook results are displayed below.

PLAY [Sample Playbook] *********************************************************

TASK [Ping] ********************************************************************
ok: [localhost]

TASK [Gather system facts] *****************************************************
ok: [localhost]

TASK [Print system facts] ******************************************************
ok: [localhost] => {
"ansible_facts.env": {
"CONTAINER_NAME": "creator-ee:v0.18.0",
"DISTTAG": "f38container",
"FGC": "f38",
"HOME": "/home/runner",
"HOSTNAME": "a88fc35da4b3",
"LC_CTYPE": "C.UTF-8",
"PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"PWD": "/ansible",
"SHLVL": "1",
"TERM": "xterm",
"_": "/usr/bin/python3",
"container": "oci"
}
}

PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Vagrant

Vagrant is an open-source tool written in Ruby that originated from the work of Mitchell Hashimoto in early 2010. It was designed to simplify the process of setting up and managing development environments.

From a developer’s perspective, Vagrant serves as a powerful tool for creating consistent and reproducible development environments across different platforms. It achieves this by utilizing a declarative configuration file called Vagrantfile, which allows developers to define the desired operating system template, software packages, networking, and other settings for their development environment. Vagrant has a plugin-based architecture and supports virtualization providers like VirtualBox, VMware, and Hyper-V, giving developers flexibility in choosing the backend that best suits their needs.

With Vagrant, developers can spin up and tear down virtual machines, automate software provisioning using tools like Shell scripts or configuration management systems, and seamlessly share their development environments with teammates.

The following diagram depicts how Vagrant interacts with Hyper-V on a Windows host to achieve desired state defined in blueprint file.

Vagrant interaction with Hyper-V backend

To demonstrate this workflow in practice, we create a working directory and download a sample Vagrant file from GitHub repository.

New-Item -Path $HOME\code\maroskukan\demo
cd $HOME\code\maroskukan\demo

$url = "https://raw.githubusercontent.com/maroskukan/rhcsa/main/Vagrantfiles/env1/Vagrantfile"
Invoke-WebRequest -Uri $url -OutFile Vagrantfile

We can optionally inspect various sections in this blueprint.

# -*- mode: ruby -*-end
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
# Hyper-V Provider Specific Configuration
config.vm.provider "hyperv" do |h|
h.enable_virtualization_extensions = true
h.linked_clone = true
h.memory = 2048
h.maxmemory = 2048
end

# [ ...Omitted for brevity ]

config.vm.define "client" do |client|
# VM Shared Configuration
client.vm.box = "generic/rhel9"
client.vm.hostname = "client"

# Hyper-V VM Specific Configuration
client.vm.provider 'hyperv' do |h, override|
override.vm.synced_folder ".", "/vagrant", type: "rsync", disabled: true
override.vm.network "public_network", bridge: "Default Switch"
end

# [ ...Omitted for brevity ]

💡Tip: This blueprint defines a single Virtual Machine which can be created using multiple backend providers. In the above code snipped I only highlighted portions related to the Hyper-V backend.

Next, using vagrant up we initialize the creation of the virtual machine from the template. When it comes to templates, you can build your own or use one of many available on Vagrant Cloud.

vagrant up

We can see the process for creating this machine below.

Bringing machine up with Hyper-V provider

Once completed, our machine is ready and we can log in using vagrant ssh.

vagrant ssh

Last login: Fri Jun 9 06:37:23 2023 from 172.22.144.1
[vagrant@client ~]$ cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="9.1 (Plow)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="9.1"
PLATFORM_ID="platform:el9"
PRETTY_NAME="Red Hat Enterprise Linux 9.1 (Plow)"
ANSI_COLOR="0;31"
LOGO="fedora-logo-icon"
CPE_NAME="cpe:/o:redhat:enterprise_linux:9::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/red_hat_enterprise_linux/9/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 9"
REDHAT_BUGZILLA_PRODUCT_VERSION=9.1
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="9.1"

When you are done interacting with the Virtual Machine, it is good practice to reclaim resources such as CPU and Memory by shutting it down.

vagrant halt

The stopped VM however still consumes storage resources, therefore to fully remove it use vagrant destroy --force command.

vagrant destory --force

Closing thoughts

As we conclude this article, I hope you’ve enjoyed exploring the setup of essential DevOps tools on Windows. By implementing these tools, you’ll be well-equipped to streamline your development processes, enhance collaboration, and improve overall productivity. We’d love to hear your thoughts and experiences in the comments below. If you have any questions or additional insights to share, feel free to join the conversation. Thank you for reading, and happy DevOps-ing!

--

--