For most home users - ninite.com

If you’re not a developer and just want to quickly install common tools, ninite.com is a great option. It has a simple web interface where you can select the apps you want, and it generates a custom installer that will download and install them all for you. Keep the installer, run it regularly, and it will patch things over time.

For developers/techs/admins - winget

Here is my usual stuff. Winget can mostly replace chocolatey, however it is much more verbose. This script will get you up and running with a good set of dev tools for M365/D365/Azure dev and admin tasks.

# Core install sets (edit to taste). Each entry = Winget Id
$dev = @(
  'Git.Git'
  'GitHub.cli'
  'CoreyButler.NVMforWindows'
  'pnpm.pnpm'
  'Microsoft.DotNet.SDK.10'
  'Microsoft.VisualStudioCode'
  'Microsoft.PowerShell'
  'Python.Python.3.14'
  'astral-sh.uv'
  'GoLang.Go'
  'Rustlang.Rustup'
  'JanDeDobbeleer.OhMyPosh'
  'Microsoft.AzureCLI'
  'Microsoft.Azure.StorageExplorer'
  'Microsoft.SQLServerManagementStudio'
  'Microsoft.Azure.FunctionsCoreTools'
  'Docker.DockerDesktop'
  'Postman.Postman'
  'WinSCP.WinSCP'
  'ShiningLight.OpenSSL.Light'
  'WinMerge.WinMerge'
  'Microsoft.Sysinternals.Suite'
  'MikeFarah.yq'
  'jqlang.jq'
  'BurntSushi.ripgrep.MSVC'
  'Mozilla.Firefox'
)

$desktop = @(
  'Google.Chrome'
  'Microsoft.Teams'
  'Microsoft.Office'
  'Adobe.Acrobat.Reader.64-bit'
  'Microsoft.PowerToys'
  'AntibodySoftware.WizTree'
  'AntibodySoftware.WizFile'
  '7zip.7zip'
  'VideoLAN.VLC'
  'Spotify.Spotify'
)

# self-updating
$pin= @(
  'Microsoft.VisualStudioCode'
  'Microsoft.PowerShell'
  'Google.Chrome'
  'Microsoft.Teams'
  'Microsoft.Office'
)

$all = $dev + $desktop  
Write-Host "Installing $($all.Count) packages via winget..." -ForegroundColor Cyan

foreach ($id in $all) {
  Write-Host ("-> {0}" -f $id) -ForegroundColor DarkGray
  winget install --id $id -e -s winget --accept-package-agreements --accept-source-agreements
}
foreach ($id in $pin) {
  Write-Host ("-> Pinning {0}" -f $id) -ForegroundColor DarkGray
  winget pin add --id $id
}

Write-Host "Done." -ForegroundColor Green

After running these installs, in a new terminal:

dotnet tool install --global Microsoft.PowerApps.CLI.Tool
nvm install lts
nvm install 22                                    # SPFx 1.21 to 1.23 needs Node 22
nvm use lts
npm config set min-release-age 7                  # days; needs npm 11.10+ (Node 22 ships npm 10: npm i -g npm@11)
pnpm setup
pnpm config set --global minimumReleaseAge 10080  # minutes, so 7 here would mean 7 minutes
npm install -g @pnp/cli-microsoft365 @anthropic-ai/claude-code

The two release-age lines make npm and pnpm skip any version published in the last week, so a hijacked package has time to be caught before it reaches you.

On a regular basis, winget upgrade --all --accept-source-agreements --accept-package-agreements will update everything not pinned.

You will want to reboot, and don’t forget:

  • Set PowerShell to use oh-my-posh in your profile
  • Configure Windows Terminal to use PowerShell as the default shell
  • Log in to VS Code, browser profiles, and Office.
  • Set up a Dev Drive for your repos and the pnpm store
  • Set up your password vault, peripherals, and entertainment and chat apps.

Windows utilities and tools

Printer weirdness

If having difficulties installing a printer in a restricted environment, use admin acct to bring up the printer install wizard that actually works as admin:

rundll32 printui.dll,PrintUIEntry /il

Git Bash fork errors

If Git Bash (or a tool that drives it) fails with fork: ... died unexpectedly ... exit code 0xC0000142, Windows’ “Force randomization for images” (Mandatory ASLR) exploit protection is on and is breaking Git’s MSYS runtime. The Git installer (2.42+) can add exemptions for just Git’s executables, but winget installs skip that step: this gist has the winget switch and a script. Everything else keeps the protection.

Still stuck? Work with me or get in touch.