How to Install Python on Windows Server 2022
Python is increasingly common on Windows Server — for automation scripts, data pipelines, web APIs (Flask, FastAPI, Django), machine learning workloads, and DevOps tooling. Windows Server 2022 does not include Python, so it must be installed manually. This guide covers downloading and installing Python from python.org, the Python Launcher for Windows, creating and activating virtual environments, managing multiple Python versions with pyenv-win, running Python scripts as Windows services with NSSM, and configuring pip for corporate proxy environments.
Downloading Python for Windows Server 2022
Download the Windows installer from https://www.python.org/downloads/windows/. For server deployments, always use the Windows installer (64-bit) for the latest stable release. As of mid-2026, Python 3.12 and 3.13 are the current stable versions. Avoid the Store version — it uses a stub launcher and does not work well in server contexts.
# Download Python 3.12 installer via PowerShell
$pythonVersion = "3.12.4"
Invoke-WebRequest `
-Uri "https://www.python.org/ftp/python/$pythonVersion/python-$pythonVersion-amd64.exe" `
-OutFile "C:Installerspython-$pythonVersion-amd64.exe"
Installing Python — Installer Options
Run the installer interactively or silently. For server deployments, silent installation with explicit options is preferred for repeatability. Key installer flags:
InstallAllUsers=1— Install for all users (system-wide) toC:Program FilesPython312PrependPath=1— Add Python and Scripts to the system PATHInclude_pip=1— Install pip (default)Include_launcher=1— Install the Python Launcher (py.exe)AssociateFiles=1— Associate .py files with the Python Launcher
# Silent install for all users, add to PATH, include pip and launcher
Start-Process -FilePath "C:Installerspython-3.12.4-amd64.exe" `
-ArgumentList "/quiet InstallAllUsers=1 PrependPath=1 Include_pip=1 Include_launcher=1 AssociateFiles=1" `
-Wait -Verb RunAs
# Verify
python --version
pip --version
py --version
For interactive installation, run the installer and check both:
- “Add Python to PATH” at the bottom of the first screen
- “Install for all users” (optional but recommended on servers)
The Python Launcher (py.exe)
The Python Launcher (py.exe) is installed to C:Windows and is available to all users without modifying PATH. It reads shebang lines and version specifiers to dispatch to the correct Python version. This is especially useful when multiple Python versions are installed:
# List installed Python versions
py --list
py -0p # Same, but shows full paths
# Run a specific version explicitly
py -3.12 --version
py -3.11 script.py
py -3 script.py # Latest Python 3.x
# Use in a shebang line (top of script)
#!/usr/bin/env python3
# or
#!/usr/bin/python3.12
The launcher also respects a python.ini file in the script directory or a py.ini in %APPDATA% to set the default version:
# C:UsersAdminAppDataRoamingpy.ini (user default)
[defaults]
python=3.12
Verifying and Configuring PATH
After installation, open a new PowerShell session and verify Python is on the PATH:
python --version
# Python 3.12.4
where python
# C:Program FilesPython312python.exe
# Check pip
pip --version
# pip 24.0 from C:Program FilesPython312Libsite-packagespip (python 3.12)
# If python is not found, add it manually
$pythonPath = "C:Program FilesPython312"
$scriptsPath = "C:Program FilesPython312Scripts"
$current = [System.Environment]::GetEnvironmentVariable("PATH", "Machine")
[System.Environment]::SetEnvironmentVariable("PATH", "$pythonPath;$scriptsPath;$current", "Machine")
Creating Virtual Environments
Virtual environments isolate Python packages on a per-project basis, preventing dependency conflicts between projects. On Windows Server, always use virtual environments for any production Python workload.
# Create a virtual environment in the project directory
cd C:ProjectsMyPythonApp
python -m venv venv
# The venv structure created:
# venv
# Scripts <- python.exe, pip.exe, activate.ps1, activate.bat
# Libsite-packages
# pyvenv.cfg
# Inspect the venv config
Get-Content C:ProjectsMyPythonAppvenvpyvenv.cfg
Activating a Virtual Environment
Activating a venv modifies the current shell session’s PATH to prefer the venv’s Python and pip. The activation script depends on the shell being used.
# PowerShell activation
.venvScriptsActivate.ps1
# CMD activation
.venvScriptsactivate.bat
# Verify activation — prompt should show (venv)
python -c "import sys; print(sys.executable)"
# C:ProjectsMyPythonAppvenvScriptspython.exe
# Deactivate
deactivate
PowerShell Execution Policy for venv Activation
By default, Windows Server 2022 PowerShell enforces the RemoteSigned execution policy, which blocks unsigned local scripts. The Activate.ps1 venv script is unsigned and may be blocked. Fix this with:
# Check current policy
Get-ExecutionPolicy -List
# Allow local unsigned scripts (RemoteSigned is the recommended policy)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# or for all users on the server (requires admin):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
# Alternative: bypass for a single session only
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
# Check that venv activation now works
.venvScriptsActivate.ps1
In CI/CD pipelines, the execution policy for a single pipeline stage can be bypassed without changing the machine-level policy:
powershell.exe -ExecutionPolicy Bypass -File ".deploy.ps1"
Installing Packages with pip
# Activate the venv first, then install packages
.venvScriptsActivate.ps1
pip install requests flask sqlalchemy
# Install from a requirements file
pip install -r requirements.txt
# Freeze current environment to requirements.txt
pip freeze > requirements.txt
# Upgrade pip itself
python -m pip install --upgrade pip
# Show installed packages
pip list
# Show details for a specific package
pip show requests
Managing Multiple Python Versions with pyenv-win
pyenv-win is a Windows port of the Unix pyenv tool. It manages multiple Python versions and lets you set per-directory or global Python versions without touching system PATH manually.
# Install pyenv-win via PowerShell (from GitHub)
Invoke-WebRequest `
-Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" `
-OutFile "$HOMEinstall-pyenv-win.ps1"
& "$HOMEinstall-pyenv-win.ps1"
# OR install via pip (if Python is already installed)
pip install pyenv-win --target "$HOME.pyenv"
# Add pyenv to PATH (the installer usually does this automatically)
[System.Environment]::SetEnvironmentVariable("PYENV", "$HOME.pyenvpyenv-win", "User")
[System.Environment]::SetEnvironmentVariable("PYENV_HOME", "$HOME.pyenvpyenv-win", "User")
$currentPath = [System.Environment]::GetEnvironmentVariable("PATH", "User")
[System.Environment]::SetEnvironmentVariable("PATH", "$HOME.pyenvpyenv-winbin;$HOME.pyenvpyenv-winshims;$currentPath", "User")
# List available Python versions to install
pyenv install --list
pyenv install --list | findstr "3.11"
# Install specific versions
pyenv install 3.11.9
pyenv install 3.12.4
pyenv install 3.10.14
# List installed versions
pyenv versions
# Set global default version
pyenv global 3.12.4
# Set local (directory-specific) version — writes .python-version file
cd C:ProjectsLegacyApp
pyenv local 3.10.14
# Verify
python --version
pyenv version
pip Proxy Settings for Corporate Environments
Many corporate Windows Server environments route outbound web traffic through an HTTP proxy. pip must be configured to use the proxy to reach PyPI. There are multiple ways to configure this:
# Option 1: Command-line flag (per-command)
pip install requests --proxy http://proxy.corp.local:8080
# Option 2: Environment variable (per-session)
$env:HTTP_PROXY = "http://proxy.corp.local:8080"
$env:HTTPS_PROXY = "http://proxy.corp.local:8080"
pip install requests
# Option 3: pip.ini configuration file (persistent)
# Location: C:ProgramDatapippip.ini (system-wide)
# or %APPDATA%pippip.ini (per-user)
New-Item -Path "C:ProgramDatapip" -ItemType Directory -Force
Set-Content -Path "C:ProgramDatapippip.ini" -Value @"
[global]
proxy = http://proxy.corp.local:8080
trusted-host = pypi.org
files.pythonhosted.org
pypi.python.org
index-url = https://pypi.org/simple/
timeout = 60
"@
# For authenticated proxy
# proxy = http://DOMAINuser:[email protected]:8080
# Option 4: Use an internal PyPI mirror (Artifactory, Nexus, DevPI)
pip install requests --index-url https://pypi.corp.local/simple/ --trusted-host pypi.corp.local
Python PATH Configuration
For system-level PATH configuration (affecting all users and services), use the machine-level environment variable. For per-user config, use the user-level PATH. Services running as SYSTEM or a service account use the machine-level PATH:
# Check the current machine PATH (relevant for services)
[System.Environment]::GetEnvironmentVariable("PATH", "Machine") -split ";" | Sort-Object
# Verify Python is accessible to SYSTEM account
psexec -s cmd.exe /c "python --version"
# If psexec is not available, use a scheduled task:
$action = New-ScheduledTaskAction -Execute "python.exe" -Argument "--version"
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddSeconds(10)
Register-ScheduledTask -TaskName "TestPythonPath" -Action $action -Trigger $trigger -RunLevel Highest
Start-Sleep 15
Get-ScheduledTaskInfo -TaskName "TestPythonPath"
Unregister-ScheduledTask -TaskName "TestPythonPath" -Confirm:$false
Running Python Scripts as Windows Services with NSSM
NSSM (Non-Sucking Service Manager) wraps any executable — including Python scripts — as a proper Windows service with automatic restart, stdout/stderr logging, and service dependency support. This is the most practical way to run Python web servers (Flask/FastAPI/Gunicorn-for-Windows/Waitress) or background workers as persistent services.
# Download NSSM (https://nssm.cc/download)
Invoke-WebRequest -Uri "https://nssm.cc/release/nssm-2.24.zip" `
-OutFile "C:Installersnssm-2.24.zip"
Expand-Archive -Path "C:Installersnssm-2.24.zip" -DestinationPath "C:Toolsnssm"
# Add nssm to PATH
$path = [System.Environment]::GetEnvironmentVariable("PATH", "Machine")
[System.Environment]::SetEnvironmentVariable("PATH", "$path;C:Toolsnssmnssm-2.24win64", "Machine")
$env:PATH = "$env:PATH;C:Toolsnssmnssm-2.24win64"
# Install a Python app as a Windows service
# Example: a Waitress WSGI server for a Flask app
# First, install waitress in the venv
C:ProjectsMyFlaskAppvenvScriptspip install waitress
# Create a startup script: C:ProjectsMyFlaskApprun_service.py
Set-Content -Path "C:ProjectsMyFlaskApprun_service.py" -Value @"
from waitress import serve
from app import create_app
app = create_app()
serve(app, host='0.0.0.0', port=5000, threads=4)
"@
# Install as service using NSSM
nssm install MyFlaskApp "C:ProjectsMyFlaskAppvenvScriptspython.exe"
nssm set MyFlaskApp AppParameters "C:ProjectsMyFlaskApprun_service.py"
nssm set MyFlaskApp AppDirectory "C:ProjectsMyFlaskApp"
nssm set MyFlaskApp DisplayName "My Flask Application"
nssm set MyFlaskApp Description "Flask web application running with Waitress"
nssm set MyFlaskApp Start SERVICE_AUTO_START
nssm set MyFlaskApp AppStdout "C:Logsmyflaskappstdout.log"
nssm set MyFlaskApp AppStderr "C:Logsmyflaskappstderr.log"
nssm set MyFlaskApp AppRotateFiles 1
nssm set MyFlaskApp AppRotateSeconds 86400
nssm set MyFlaskApp AppEnvironmentExtra "FLASK_ENV=production" "DB_HOST=sql01" "SECRET_KEY=myprodkey"
# Create log directory
New-Item -Path "C:Logsmyflaskapp" -ItemType Directory -Force
# Start the service
nssm start MyFlaskApp
Get-Service MyFlaskApp
To configure the service to run as a specific service account (recommended over SYSTEM for security):
nssm set MyFlaskApp ObjectName "DOMAINsvc-flaskapp" "ServiceAccount@Pass"
# Or use a Local account
nssm set MyFlaskApp ObjectName ".LocalSvcUser" "LocalPassword123"
# Grant the service account read/execute on the app directory
icacls "C:ProjectsMyFlaskApp" /grant "DOMAINsvc-flaskapp:(OI)(CI)RX" /T
# Grant write access to the log directory
icacls "C:Logsmyflaskapp" /grant "DOMAINsvc-flaskapp:(OI)(CI)M" /T
Upgrading Python
When upgrading to a new Python minor version (e.g., 3.12 to 3.13), install the new version alongside the existing one, then migrate your virtual environments by recreating them:
# Install new version without removing old one
Start-Process -FilePath "python-3.13.0-amd64.exe" `
-ArgumentList "/quiet InstallAllUsers=1 PrependPath=0 Include_pip=1" `
-Wait
# Recreate venv with new Python version
cd C:ProjectsMyPythonApp
Rename-Item venv venv_3.12_backup
py -3.13 -m venv venv
.venvScriptsActivate.ps1
# Reinstall packages from frozen requirements
pip install -r requirements.txt
# Verify all tests pass before removing old venv backup
python -m pytest tests/