If you manage a mix of Windows Server and Ubuntu boxes, you know this problem: two versions of the same script, one in Bash, one in PowerShell. They drift apart every time you touch one and forget the other. Installing PowerShell 7 on Ubuntu fixes that. You get one script and one set of cmdlets that run the same way on both operating systems.
This guide installs PowerShell 7 via Microsoft’s official apt repository. You’ll verify the install worked, sort out which modules behave on Linux, and write a script that runs identically on Windows and Ubuntu. No if $OS -eq "Windows" hacks held together with duct tape.
What is PowerShell 7?
PowerShell 7 (still commonly called “PowerShell Core” from its early cross-platform days) is Microsoft’s open-source, cross-platform shell and scripting language. Windows PowerShell 5.1 is stuck on Windows, full stop. PowerShell 7 runs natively on Windows, macOS, and Linux distributions including Ubuntu. It uses the same pwsh executable and the same core cmdlet set everywhere.
That’s the real difference from 5.1, a legacy Windows-only edition stuck in maintenance mode. PowerShell 7 is the actively developed successor, built on .NET. It’s what Microsoft ships new features to now. It’s free and open-source under the MIT license, so there’s no licensing cost on Ubuntu, Windows, or macOS. Most modules on the PowerShell Gallery are free to install too, though some publisher-specific modules carry their own licensing or support terms, so check a module’s page before you build automation around it.
For sysadmins running mixed environments, this matters in a concrete way. Azure PowerShell modules like Az work fine on Linux — it’s REST-based with no Windows dependency. Not every Microsoft 365 admin module has the same Linux parity, so check a module’s compatibility notes before scripting against one you haven’t run on Ubuntu before. Still, for the modules that do work, you can manage cloud resources from an Ubuntu jump box instead of RDPing into a Windows management VM just to run a script. Homelab users get the same payoff at smaller scale: one scripting language across Windows and Linux VMs instead of two.
Before You Begin
Make sure you have:
- Ubuntu 24.04 LTS (Noble) on an x64 PC for this walkthrough
sudoor root access on the machine- Internet access to reach
packages.microsoft.com - A terminal session (local, SSH, or console)
- Basic familiarity with
aptpackage management
| Requirement | Details |
|---|---|
| OS version | Ubuntu 24.04 LTS on x64 hardware |
| Disk space | ~300 MB for PowerShell and dependencies |
| Privileges | sudo access required for repo setup and install |
| Network | Outbound HTTPS access to packages.microsoft.com |
The walkthrough targets PowerShell 7.6 on Ubuntu 24.04 LTS, using the x64 (amd64) repository. Check Microsoft’s support matrix before choosing a different Ubuntu or PowerShell release.
Step-by-Step Guide
Step 1: Update Ubuntu and install prerequisites
Refresh your package lists and pull in the tools needed to add a signed third-party repository: wget, curl, gpg, and apt-transport-https.
if sudo apt update; then
sudo apt upgrade -y
fi
sudo apt install -y wget apt-transport-https software-properties-common curl gpg
Expected output ends with something like:
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
If packages were missing, apt shows them downloading and unpacking instead. That’s normal on a fresh install. Don’t panic about it.
Step 2: Add Microsoft’s GPG signing key
Ubuntu needs to verify that the PowerShell package actually came from Microsoft and wasn’t tampered with in transit. Download Microsoft’s public signing key and store it in the modern keyring format. Skip the deprecated apt-key method; Ubuntu has phased it out.
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --dearmor -o /usr/share/keyrings/microsoft-archive-keyring.gpg
Note: Microsoft’s current Ubuntu install docs primarily recommend bootstrapping via the
packages-microsoft-prod.debpackage, which registers both the repository and the signing key automatically in one step. The manual curl/gpg –dearmor approach shown here is a valid, transparent alternative that produces the same signed-repository result, but it isn’t the method Microsoft’s official docs lead with.
There’s no output on success; the command just returns to a prompt. You can confirm the file exists:
ls -l /usr/share/keyrings/microsoft-archive-keyring.gpg
-rw-r–r– 1 root root 3122 Aug 26 09:14 /usr/share/keyrings/microsoft-archive-keyring.gpg
Step 3: Add the Microsoft APT repository
Register Microsoft’s package repository for your specific Ubuntu release. This example uses 24.04 (“noble”); swap the path for 22.04 if you’re on Jammy.
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/ubuntu/24.04/prod noble main" | sudo tee /etc/apt/sources.list.d/microsoft.list
deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/ubuntu/24.04/prod noble main
The signed-by= flag ties this repo entry to the specific key you just imported, instead of trusting every key in the system keyring. That’s current best practice. It’s also what saves you from the “apt-key deprecated” warnings you’ll still see in older tutorials.
Step 4: Install PowerShell
Refresh the package index so apt picks up the new repository, then install the powershell package.
sudo apt update
sudo apt install -y powershell
Apt reads Microsoft’s repository and downloads powershell. The following output is illustrative; package size and patch version vary:
Get:1 https://packages.microsoft.com/ubuntu/24.04/prod noble/main amd64 powershell amd64 7.6.6-1.deb_amd64 [140 MB]
…
Setting up powershell (7.6.6-1.deb_amd64) …
Step 5: Launch and verify
Start PowerShell with the pwsh command.
pwsh
Your prompt changes to indicate you’re now inside the PowerShell environment:
PowerShell 7.6.6
Copyright (c) Microsoft Corporation.https://aka.ms/powershell
Type ‘help’ to get help.PS /home/akishore>
Step 6: Confirm the version and OS details
Inside the pwsh session, check $PSVersionTable to confirm the exact version and platform.
$PSVersionTable
Name Value
—- —–
PSVersion 7.6.6
PSEdition Core
GitCommitId 7.6.6
OS Linux 6.8.0-40-generic #40-Ubuntu SMP
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
The OS and Platform fields are your quick check. They confirm you’re running the actual Linux build, not a Windows binary someone copied over by mistake. This is your verification step. If $PSVersionTable returns this table with PSEdition: Core, the install worked.
Installing on Windows and macOS
Since you’re probably managing both platforms, here’s the short version for the other two.
Windows
Open an elevated terminal (PowerShell or Command Prompt as Administrator) and use winget:
winget install --id Microsoft.PowerShell --source winget
This installs alongside the built-in Windows PowerShell 5.1. You’ll see a separate PowerShell 7 shortcut in the Start menu. Launch it and confirm with $PSVersionTable.PSVersion, same as on Ubuntu. If you’d rather not use winget, grab the .msi installer directly from the PowerShell GitHub releases page. Run through the setup wizard with default options.
macOS
Install via Homebrew (assuming Homebrew is already set up):
brew install --cask powershell
Then launch and verify:
pwsh
$PSVersionTable.PSVersion
Configuration: Modules and PSModulePath on Linux
This is where PowerShell on Ubuntu starts to diverge from the Windows experience. Understand this before you write scripts you’ll regret later.
Where modules live on Linux
PowerShell searches the $PSModulePath environment variable for installed modules. Same concept as Windows, different paths. Check yours:
$env:PSModulePath -split ':'
/home/akishore/.local/share/powershell/Modules
/usr/local/share/powershell/Modules
/opt/microsoft/powershell/7/Modules
~/.local/share/powershell/Modules: user-scoped modules, nosudoneeded/usr/local/share/powershell/Modules: machine-wide, shared across all users/opt/microsoft/powershell/7/Modules: built-in modules shipped with PowerShell itself; don’t touch this one
Installing modules
Use Install-Module with -Scope CurrentUser to avoid needing sudo for every module install:
Install-Module -Name PSScriptAnalyzer -Scope CurrentUser -Force
Untrusted repository
You are installing the modules from an untrusted repository…
Are you sure you want to install the modules from ‘PSGallery’?
[Y] Yes [A] Yes to All [N] No [L] No [S] Suspend [?] Help (default is “N”): A
An untrusted-repository confirmation can appear when the repository is not trusted and you omit -Force. The command above includes -Force, so it normally suppresses that confirmation. You can pre-trust it if you want a scripted, unattended install:
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
To see what’s already installed:
Get-Module -ListAvailable
Directory: /home/akishore/.local/share/powershell/Modules
ModuleType Version Name ExportedCommands
———- ——- —- —————-
Script 1.22.0 PSScriptAnalyzer {Get-Setting, Invoke-Formatter…}
Manifest 7.0.0 Microsoft.PowerShell.Management {Add-Content…}
Modules that actually work on Linux
| Module | Works on Ubuntu? | Notes |
|---|---|---|
PSScriptAnalyzer | Yes | Linting/static analysis, fully cross-platform |
Az (Azure PowerShell) | Yes | REST-based, no Windows dependency |
Pester | Yes | Testing framework, cross-platform by design |
Microsoft.PowerShell.SecretManagement | Yes | Cross-platform credential storage |
PowerShellGet | Yes | Built in, manages other modules |
ActiveDirectory | No | Depends on Windows-only LDAP/AD binaries |
PSReadLine | Partial | Ships and works, but some Windows key-binding defaults differ |
WebAdministration (IIS) | No | IIS doesn’t exist on Linux |
Before adding a module to a shared script, check its documentation page on the PowerShell Gallery for a “Linux compatible” note, or just test it. If it depends on the Windows registry, WMI, or COM, it’ll either fail to import or throw errors the moment you call a cmdlet.
What Doesn’t Work: Windows-Only Cmdlets on Ubuntu
This is the part that trips up people coming from a Windows-only background. PowerShell 7 ships the same engine everywhere. But plenty of cmdlets are thin wrappers around Windows-specific subsystems that simply don’t exist on Linux:
- Registry cmdlets (
Get-ItemProperty -Path HKLM:\...): there’s no Windows registry on Ubuntu, so registry-drive paths fail - Active Directory module (
Get-ADUser,New-ADGroup): depends on Windows AD DS binaries - Windows management commands:
Get-WmiObjectbelongs to Windows PowerShell 5.1 and is absent from PowerShell 7 on every platform. Do not assume Windows CIM classes or management modules are available on Linux. - COM automation (
New-Object -ComObject Excel.Application): COM is a Windows-only technology - IIS management (
WebAdministrationmodule): IIS is Windows-only - Classic GUI-dependent modules: anything that pops a Windows Forms dialog
If you run one of these on Ubuntu, you’ll typically get an error like:
New-Object: Cannot find type [System.__ComObject]: verify that the assembly containing this type is loaded.
or, for registry access:
Get-ItemProperty: Cannot find drive. A drive with the name ‘HKLM’ does not exist.
Don’t waste time hunting for a Linux equivalent cmdlet; there usually isn’t one. Branch your script logic instead, so Windows-only code only runs on Windows.
Practical Example: A Script That Runs on Both Windows and Ubuntu
Here’s a script that checks disk space and writes a log entry, using the same logic on both platforms. PowerShell exposes three built-in boolean variables, $IsWindows, $IsLinux, $IsMacOS, made for exactly this purpose.
# disk-check.ps1
# Runs identically on Windows PowerShell 7+ and PowerShell 7 on Ubuntu
$logDir = if ($IsWindows) {
"C:\Logs\DiskChecks"
} else {
Join-Path $HOME "logs/disk-checks"
}
# Join-Path builds the correct separator for whichever OS runs this script
if (-not (Test-Path $logDir)) {
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
}
$logFile = Join-Path $logDir "disk-check-$(Get-Date -Format 'yyyy-MM-dd').log"
if ($IsWindows) {
$volumes = Get-Volume | Where-Object { $_.DriveLetter } |
Select-Object DriveLetter, @{N='FreeGB';E={[math]::Round($_.SizeRemaining/1GB,2)}}
} else {
# Linux: parse df output instead of relying on Get-Volume, which is Windows-only
$dfOutput = df -B1 --output=target,avail | Select-Object -Skip 1
$volumes = $dfOutput | ForEach-Object {
$parts = ($_ -split '\s+').Where({ $_ -ne '' })
[PSCustomObject]@{
Mount = $parts[0]
FreeGB = [math]::Round([long]$parts[1] / 1GB, 2)
}
}
}
$volumes | ForEach-Object {
"$(Get-Date -Format o) $_" | Add-Content -Path $logFile
}
Write-Output "Checked $($volumes.Count) volume(s). Log written to $logFile"
Run it the same way on both systems:
pwsh ./disk-check.ps1
Checked 4 volume(s). Log written to /home/akishore/logs/disk-checks/disk-check-2026-08-26.log
Notice the pattern: $IsWindows/$IsLinux handle branching, Join-Path handles path separators, and the Windows-only cmdlet (Get-Volume) only runs inside the if ($IsWindows) block. The script never even attempts to call it on Ubuntu, so there’s nothing to crash.
Updating and Uninstalling PowerShell on Ubuntu
Updating
Because you installed through Microsoft’s apt repository, updates flow through normal apt commands. No separate updater, no manual download.
sudo apt update
sudo apt upgrade powershell -y
To check your current version without launching a full session:
pwsh --version
PowerShell 7.6.6
Uninstalling
Warning: This removes the
powershellpackage and its files. Any scripts stored elsewhere on disk are untouched. Locally installed modules under~/.local/share/powershell/Moduleswill remain. Remove that directory separately if you want a completely clean slate.
sudo apt remove powershell -y
To also remove Microsoft’s repository entry and signing key:
sudo rm /etc/apt/sources.list.d/microsoft.list
sudo rm /usr/share/keyrings/microsoft-archive-keyring.gpg
sudo apt update
Tips and Troubleshooting
sudo apt install powershell fails or can’t find the package
Why it happens: Either the Microsoft repository wasn’t added correctly, or you followed an older guide that used the deprecated apt-key add method instead of the current keyring + signed-by approach.
Fix: Re-run Steps 2 and 3 exactly. Re-import the key with gpg --dearmor into /usr/share/keyrings/. Make sure the signed-by= path in /etc/apt/sources.list.d/microsoft.list matches the keyring file. Then run sudo apt update again before retrying the install.
pwsh: command not found after installation
Why it happens: The install didn’t finish successfully. Or PowerShell was installed manually (for example, from a tarball) without a symlink into your PATH.
Fix: Check with which pwsh. If nothing returns, reinstall with sudo apt install -y powershell, or manually symlink it if you used the /opt tarball method:
sudo ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh
A script that works on Windows breaks on Ubuntu with file path errors
Why it happens: Hardcoded Windows-style paths like C:\logs\output.txt don’t translate. The backslash gets treated as a literal filename character on Linux, not a path separator.
Fix: Replace hardcoded paths with Join-Path or [IO.Path]::Combine(), as shown in the example script above. PowerShell then builds the correct separator for whichever OS runs the script.
A .ps1 script fails on Ubuntu with “No such file or directory” even though the file exists
Why it happens: The script has Windows-style CRLF line endings. This breaks the shebang line (#!/usr/bin/env pwsh) because the interpreter path ends up with a trailing carriage-return character the shell can’t resolve.
Fix: Convert to Unix LF line endings before running on Linux:
sed -i 's/\r//' script.ps1
Or configure your editor (VS Code, for example) to save PowerShell files with LF line endings by default.
Dependency errors when installing a downloaded .deb package directly
Why it happens: dpkg -i doesn’t resolve dependencies automatically the way apt does.
Fix: After sudo dpkg -i powershell_*.deb, run:
sudo apt-get install -f
This pulls in any missing dependencies and finishes the install cleanly.
Wrapping Up
You’ve got PowerShell 7 running natively on Ubuntu, verified with $PSVersionTable. Regular apt upgrade cycles keep it patched. The real payoff is the $IsWindows/$IsLinux branching habit and the module discipline that comes with it. Build that once, and most of your automation scripts stop caring which OS they land on.
PowerShell on Ubuntu earns its keep on mixed-environment admin work: Azure and M365 scripting, cross-platform CI pipelines, shared tooling between Windows Server and Linux fleets. For a pure Linux job, native Bash is still faster to write and lighter to run. Don’t reach for PowerShell to replace a five-line shell script just because you can.
| Step | Action | Applies To |
|---|---|---|
| 1-3 | Add Microsoft’s GPG key and apt repository | Ubuntu 22.04/24.04 |
| 4-6 | Install via apt, launch pwsh, verify with $PSVersionTable | Ubuntu |
| — | Install via winget | Windows |
| — | Install via Homebrew cask | macOS |
| Config | Set PSModulePath, install modules with -Scope CurrentUser | Ubuntu |
| Ongoing | sudo apt upgrade powershell | Ubuntu |