azure-multiprofile
v0.1.2
Published
Run several Azure CLI (and azd) accounts side by side, each in its own isolated profile.
Maintainers
Readme
azure-multiprofile
Run several Azure CLI (az) and Azure Developer CLI (azd) accounts on one computer at the same time: work and personal, several customers, several tenants. Each account lives in its own isolated profile. Signing in to one never signs you out of another.
$ azmp list
PROFILE SIGNED IN AS SUBSCRIPTION AZURE_CONFIG_DIR AZD_CONFIG_DIR
default [email protected] Pay-As-You-Go ~/.azure shared
fabrikam [email protected] Fabrikam-Dev ~/.azure-fabrikam shared
* work [email protected] Contoso-Prod ~/.azure-work ~/.azd-work
$ az-fabrikam group list -o table # one-off command as fabrikam
$ azmp use work # switch this terminal to work
$ cd ~/src/fabrikam-api # folder linked to fabrikam: switches automaticallyCommunity project. Not affiliated with or supported by Microsoft.
Why
az keeps everything (settings, the signed-in account list, and the MSAL token cache) in one folder, ~/.azure. Open two terminals, sign in to a second account in one of them, and both terminals now share that state. az account set only switches between subscriptions of accounts that are already signed in. It can't keep a work identity and a customer identity apart, and it can't keep two terminals on different accounts.
The CLI does support moving that folder with the AZURE_CONFIG_DIR environment variable. Rakhesh Sasidharan described the trick with a couple of shell functions. azure-multiprofile turns it into a tool:
- a registry of profiles and a wizard to create them
azmp use <profile>to switch the current shell, andaz-<profile> …for one-off commands- per-folder auto-switch with a
.azprofilefile, like.nvmrc AZD_CONFIG_DIRisolation forazd- prompt integration (starship, oh-my-posh, plain PS1)
doctor --fix(with--undo) for the things that go wrong- zsh, bash, fish and PowerShell, on macOS, Linux and Windows
Install
Requires Node.js 20.17+ and the Azure CLI.
npm install -g azure-multiprofile
azmp add # wizard: name, folders, azd, copy settings, shell setup, sign inazmp is a short alias for azure-multiprofile. Both are installed.
Quick start
azmp add work --azd --seed --login # create, copy settings from ~/.azure, sign in
azmp add fabrikam --tenant fabrikam.onmicrosoft.com # implies --login
azmp setup # add shell integration to your rc file (the wizard offers this too)
exec $SHELL # or open a new terminal
azmp use work && az account show # this terminal is now "work"
az-fabrikam account show # one command as fabrikam; the shell stays on "work"
azmp off # back to ~/.azureThe untouched ~/.azure is always available as the profile named default.
Profile name vs. folder
Each profile has two things, and only the name shows up in commands:
| | Example | Used for |
|---|---|---|
| Name | fabrikam | Everything you type: azmp use fabrikam, az-fabrikam …, azmp login fabrikam, .azprofile |
| Folder | ~/.azure-fabrikam | Where az stores that account's sign-in and settings. You never type it again |
Pick a short name for the account or customer (work, contoso, fabrikam). The tenant goes in --tenant when you sign in, not in the name or the folder. For the folder, just press Enter to accept the default ~/.azure-<name>. If you type a different folder in the wizard, a bare name such as my-folder is created in your home folder (the wizard shows the full path as you type). --dir on the command line follows normal CLI rules and is relative to the current directory.
$ azmp add fabrikam --tenant fabrikam.onmicrosoft.com
? Folder for this profile's az data (press Enter to use the default): (~/.azure-fabrikam) ← just press Enter
✓ Created profile fabrikam → ~/.azure-fabrikamHow it works
| What | Where |
|---|---|
| Profile's Azure CLI folder | ~/.azure-<name> (%USERPROFILE%\.azure-<name> on Windows) |
| Profile's azd folder (optional) | ~/.azd-<name> |
| Registry | ~/.config/azure-multiprofile/profiles.json (%APPDATA%\azure-multiprofile on Windows), plus a .bak of the last good copy |
| doctor --fix snapshots | ~/.config/azure-multiprofile/snapshots/ (last 10) |
| Shell integration | a marked block in ~/.zshrc, ~/.bashrc (~/.bash_profile on macOS), ~/.config/fish/config.fish or your PowerShell $PROFILE |
A profile is just a pair of environment variables:
AZURE_CONFIG_DIR=~/.azure-work # az: settings, accounts, token cache, extensions, logs
AZD_CONFIG_DIR=~/.azd-work # azd: its own login and settings (if enabled)
AZMP_PROFILE=work # for your promptAnything that reads Azure CLI credentials follows AZURE_CONFIG_DIR. That includes Terraform's azurerm provider, Bicep, kubelogin -l azurecli, and AzureCliCredential / DefaultAzureCredential in the Azure SDKs. So azmp exec work -- terraform plan works without any extra setup.
Shell integration
The rc-file block is one line that runs azure-multiprofile init <shell> when the shell starts. The generated script:
- defines
azmp.use,off,reload,linkandunlinkact on the current shell; other subcommands go to the CLI. - defines
az-<profile>(andazd-<profile>) for each profile. - adds a hook that auto-switches on
cd: zshchpwd, bashPROMPT_COMMAND, fish--on-variable PWD, PowerShellLocationChangedAction. The hook is plain shell and never starts Node. - exports
AZMP_PROFILEand definesazmp_prompt_infofor your prompt.
Profile folders are written into the generated script. The terminal where you run azmp add, rename or remove reloads itself. In other open terminals, run azmp reload or open new ones. azmp status tells you when a shell is stale.
Lines outside the # >>> azure-multiprofile >>> markers are never modified. azmp setup --uninstall removes the block.
Per-folder profiles
cd ~/src/fabrikam-api
azmp link fabrikam # writes .azprofile containing "fabrikam"When you cd into that folder or any subfolder, the shell switches to fabrikam. When you leave, it restores whatever was active before. An explicit azmp use overrides links until you run azmp off. Set AZMP_NO_AUTO=1 to turn auto-switching off. You can commit .azprofile so teammates with the same profile names get the same behavior, or add it to .gitignore.
Outside an interactive shell (CI, scripts, Makefiles), use azmp exec <name> -- …, or eval "$(azmp env <name>)".
Prompt
Cheapest (reads an env var, nothing runs):
# zsh / bash
PS1='$(azmp_prompt_info)'"$PS1"# starship.toml
[env_var.AZMP_PROFILE]
format = "[az:$env_value]($style) "
style = "blue"With the subscription name (starts Node once per prompt and reads azureProfile.json offline, with no network):
[custom.azmp]
command = "azure-multiprofile prompt --format '{profile}:{subscription}'"
when = "true"
format = "[az:$output]($style) "Placeholders: {profile}, {subscription}, {user}, {tenant}.
Commands
| Command | What it does |
|---|---|
| add [name] | Create a profile. Interactive by default. Flags: --dir PATH, --azd/--no-azd, --seed/--no-seed, --extensions, --shell zsh,bash, --no-shell, --login, --tenant T, --device-code, --yes |
| list [--json] | Profiles with the signed-in user and subscription (read offline) |
| status | Folder and sign-in state, rc blocks, and whether this shell's integration is current |
| use <name> / off | Switch the current shell (shell integration only) |
| exec <name> -- <cmd…> | Run any command with the profile's environment |
| login <name> [--azd] [az login args] | az login (and azd auth login) inside the profile |
| env <name> [-f sh\|fish\|pwsh\|cmd\|dotenv\|json] | Print the profile's variables |
| link <name> / unlink | Write or remove .azprofile in the current folder |
| current [-v] | Active profile, and with -v, why |
| prompt [-f FORMAT] | Prompt segment |
| rename <old> <new> | Rename a profile. Moves ~/.azure-old to ~/.azure-new and keeps sign-ins. --keep-dirs leaves the folders where they are |
| remove <name> [--delete-data] [-y] | Remove from the registry. Folders are kept unless you pass --delete-data and confirm |
| setup [--shell s,…] [--uninstall] | Add or remove the rc-file block |
| init <shell> | Print the integration script (what the rc block runs) |
| doctor [--fix] [--undo] [--json] | Diagnose, repair, revert |
Copying settings (--seed)
New profiles can start with your existing az preferences. Only config and clouds.config are copied from ~/.azure, and secret-bearing keys are removed first: [storage] key / sas_token / connection_string, [batch] access_key and [batchai] storage_key. These are never copied: msal_token_cache.*, azureProfile.json, service_principal_entries.*, accessTokens.json, msal_http_cache*, logs and caches.
Extensions are installed per folder ($AZURE_CONFIG_DIR/cliextensions). With --extensions, the wizard reinstalls the ones you have in ~/.azure. To share one extension folder across all profiles, set AZURE_EXTENSION_DIR yourself.
doctor
azmp doctor checks:
az/azdare on PATH, with their versions- the registry is valid (
--fixrestores.bak) - profile folders exist (
--fixcreates them) and aren't readable by other users (--fixrunschmod 700) - no two profiles share a folder
- no rc file exports
AZURE_CONFIG_DIRfor every shell (reported only; your lines are never edited) - rc blocks aren't outdated or duplicated (
--fixrewrites them) - on Windows, the WAM broker is turned off (see below;
--fixturns it off)
Every --fix run first snapshots each file it will touch. azmp doctor --undo reverts the latest run.
Windows notes
- Use PowerShell 7 (
pwsh).azmp setup --shell pwshadds the integration to its$PROFILE. Windows PowerShell 5.1 also works if you copy the same block into its own$PROFILE. cmd.exehas no shell integration.azmp use,azmp off,azmp reloadand theaz-<name>commands only exist in PowerShell, zsh, bash and fish. Incmd, every other command works, and you run things inside a profile withexec:
To switch a wholeazmp exec fabrikam -- az account showcmdwindow, set the variables fromazmp env:
(usefor /f "delims=" %i in ('azmp env fabrikam -f cmd') do %i%%iinside a.batfile).- Use a normal, non-Administrator terminal. An elevated
cmdstarts inC:\Windows\System32, and profiles belong to your user account. azmp refuses to create profile folders underC:\Windows. az was not found on PATHmeans the Azure CLI isn't installed, or the terminal was opened before it was installed. Install it from https://aka.ms/azcli (orwinget install Microsoft.AzureCLI), open a new terminal, then runazmp login <name>.- Since Azure CLI 2.61,
az loginon Windows uses the Web Account Manager (WAM) broker. WAM keeps accounts in Windows, not inAZURE_CONFIG_DIR, so the account picker shows the accounts of every profile and it's easy to pick the wrong one.azmp doctor --fixsetscore.enable_broker_on_windows=falsein each profile's ownconfig, which brings back the browser sign-in for that profile only.
Common patterns
# A different tenant in the same account
azmp add contoso-gov --tenant contoso.onmicrosoft.us --device-code
# A service principal profile for testing pipelines locally
azmp add ci --yes --no-shell
azmp exec ci -- az login --service-principal -u "$APP_ID" -p "$SECRET" --tenant "$TENANT"
# Terraform / Bicep / kubectl with a specific identity
azmp exec fabrikam -- terraform apply
azmp exec work -- az deployment group create -g rg -f main.bicep
azmp exec work -- kubectl get pods # with kubelogin -l azurecli
# direnv instead of the built-in auto-switch
echo 'eval "$(azure-multiprofile env fabrikam)"' > .envrcTroubleshooting
| Symptom | Fix |
|---|---|
| azmp use says it needs shell integration | azmp setup, then open a new terminal |
| unknown profile … run: azmp reload | The shell started before the profile was created. Run azmp reload |
| az-<name>: command not found | Same as above |
| Auto-switch doesn't happen in PowerShell 5.1 | Use PowerShell 7, or load the integration after any prompt theme (5.1 falls back to wrapping prompt) |
| Every terminal is stuck on one account | An rc file exports AZURE_CONFIG_DIR globally. azmp doctor shows the file and line |
| Wrong account offered at sign-in on Windows | azmp doctor --fix (WAM, see above) |
| 'az-fabrikam' is not recognized in cmd.exe | cmd has no shell integration. Use azmp exec fabrikam -- az …, or PowerShell (Windows notes) |
| A profile folder ended up somewhere unexpected | Fixed in 0.1.1: wizard answers are now relative to your home folder. Move it with azmp remove <name> then azmp add <name> (sign in again), or keep it. Where it lives doesn't change how you use the profile |
| az was not found on PATH during azmp add | Install the Azure CLI, open a new terminal, then azmp login <name> |
Isolation and limitations
- Isolation is per process environment. Anything started from a shell inherits the active profile. GUI apps (VS Code's Azure extensions, for example) don't see it unless VS Code is started from that shell (
code .). - Az PowerShell (
Connect-AzAccount) keeps its own context in~/.Azureand is not covered. UseSave-AzContext/-Scope Processfor that. azitself is unchanged and installed only once. Its version and the CLI binary are shared. Extensions are per profile, unless you share them throughAZURE_EXTENSION_DIR.
Security
- The tool never reads, copies or uploads tokens. The only file it reads from a profile folder is
azureProfile.json(account names, forlistandprompt). - It never writes to
~/.azure. - It makes no network calls of its own. Network traffic comes only from
az/azd/npmwhen you ask for them. - Profile folders are created with mode
0700on macOS and Linux.
See SECURITY.md to report a vulnerability.
Contributing
Issues and PRs are welcome. See CONTRIBUTING.md. npm test runs the whole suite in a throwaway HOME, using real zsh/bash/fish/pwsh when they are installed.
Credits
- The
AZURE_CONFIG_DIRtechnique: Rakhesh Sasidharan. - Project shape (registry, managed rc blocks,
doctor --fix/--undo): claude-multiprofile.
