Windows Command Aliases: DOSKEY Macros in CMD and Aliases in PowerShell

If you come from Linux, you expect aliases to just work — type alias ll='ls -la', press Enter, done. Windows has the same concept, but it lives in two separate places depending on which shell you are in: CMD has DOSKEY macros, PowerShell has its own alias system built into the language. Neither persists across sessions without extra configuration, and neither is well-documented in a single place.

This guide covers both systems in full: syntax, argument passing, multi-command macros, and — most importantly — how to make everything stick across reboots and new sessions. That last part is what most documentation skips, and it is usually the reason admins give up and keep retyping the same commands.

CMD macros and PowerShell aliases are completely independent. A DOSKEY macro defined in CMD is invisible to PowerShell, and vice versa. If you work in both shells, you configure both separately.

Applies to: Windows 10 / 11 / Server 2019 / Server 2022


CMD vs PowerShell: concept map

Before diving in, here is how the two alias systems map to each other. The concepts are similar, but the mechanics and limitations differ significantly.

ConceptCMDPowerShell
Alias mechanismDOSKEY macroBuilt-in alias system + functions
Define an aliasdoskey name=command $*Set-Alias -Name n -Value Cmdlet
Alias with arguments baked indoskey name=command -flag $*Not possible with aliases — use a function
Multi-command alias$T separatorNot possible with aliases — use a function
List all aliasesdoskey /macrosGet-Alias
Remove an aliasdoskey name= (assign empty)Remove-Alias -Name name
Persist across sessionsRegistry AutoRun key + macro file$PROFILE script
Works inside batch/scriptsNoYes (if defined in scope)
Share across machinesdoskey /macros > file.txtExport-Alias / Import-Alias

Quick answer

CMD — define a macro that works for the current session only:

doskey ll=dir /b /a $*

Type ll and press Enter — CMD expands it to dir /b /a and lists everything in the current directory, including hidden files. Type ll C:\bat and the path is passed through $*.

PowerShell — define an alias for the current session:

Set-Alias -Name grep -Value Select-String

Now grep works as a shorthand for Select-String. Type Get-Content C:\logs\app.log | grep "error" and it filters lines containing “error”.

Both disappear when the session closes. Persistence requires extra steps — covered in full below.


CMD: DOSKEY macros

What DOSKEY does

DOSKEY is a built-in CMD utility that does two things: it enables command history (arrow key recall) and it lets you define macros — short names that expand to longer command strings. Macros live only in the CMD session where they were defined. Close the window and they are gone.

DOSKEY macros are for interactive use only. They do not work inside batch files — even if a macro is loaded in the current session, a running .bat file cannot call it. If you need reusable logic in a batch file, use a subroutine with CALL :label or a separate .bat file instead.

Syntax

Basic form:

doskey macroname=command $*

Argument placeholders — special tokens DOSKEY substitutes when the macro is called:

PlaceholderMeaningExample
$*All arguments, as a single stringdoskey go=cd /d $*go D:\Projects
$1$9Individual positional argumentsdoskey p=ping -n 4 $1p SRV-PROD-01
$TCommand separator — runs commands in sequencedoskey two=echo first $T echo second
$BPipe character | — required inside macro definitionsdoskey pf=tasklist $B findstr $1
$GOutput redirect >doskey save=dir $G C:\bat\list.txt
$LInput redirect <Rarely used interactively
Note: You cannot use |, >, or < literally inside a DOSKEY macro definition — CMD interprets them as shell operators before the macro is stored. Use $B, $G, and $L instead. These substitutions only apply inside the definition; when the macro runs, the real characters are used automatically.

CMD macro examples

Navigation shortcuts

The problem: You navigate to the same directories dozens of times a day — logs, scripts, deployment folders. Typing full paths is slow and error-prone.

The solution: Define short names that expand to cd /d with the full path. The /d flag is important — without it, cd cannot switch drives.

rem Jump to the scripts folder — /d allows switching drives, not just folders
doskey scripts=cd /d C:\bat

rem Jump to the logs folder
doskey logs=cd /d C:\logs

rem Generic go — pass any path after the alias name, $* captures everything you type
rem Example: go D:\Archive\2025
doskey go=cd /d $*

Type scripts and press Enter — CMD changes the current directory to C:\bat immediately, even if you were on a different drive. Type go D:\Archive\2025 and CMD navigates directly to that path.

Command shortcuts

The problem: Commands like ipconfig /all and systeminfo are typed constantly during troubleshooting, always with the same flags.

The solution: Wrap them in macros with your preferred flags baked in. Note that $B is how you write a pipe character inside a macro definition — CMD would misinterpret a literal | at definition time.

rem List all running processes — same as tasklist with no arguments
doskey ps=tasklist

rem Full IP configuration — /all shows DNS servers, DHCP state, and MAC addresses
doskey ipa=ipconfig /all

rem Filter systeminfo output by keyword — $* passes whatever you type after the alias
rem $B is the pipe character inside a macro definition
rem Example: sysinfo "OS Name"
rem Example: sysinfo "Total Physical Memory"
doskey sysinfo=systeminfo $B findstr /i "$*"

Type sysinfo "OS Name" — CMD runs systeminfo | findstr /i "OS Name" and returns only the matching lines instead of the full systeminfo wall of text:

OS Name:                   Microsoft Windows Server 2022 Datacenter
OS Version:                10.0.20348 N/A Build 20348

Multi-command macros with $T

The problem: Some tasks always involve the same sequence — flush DNS then check what is cached; verify a service then check its dependent services. Doing it in two separate commands every time is tedious.

The solution: Use $T to chain multiple commands into a single macro call. It is the only way to run more than one command from a DOSKEY macro — the normal && and & operators cannot be used inside macro definitions.

rem Flush the DNS resolver cache, then immediately display what remains cached
rem $T is the command separator — both commands run in sequence when you type dnsreset
doskey dnsreset=ipconfig /flushdns $T ipconfig /displaydns

rem Show the current directory path, then list its contents
rem Useful to confirm where you are and what is there at the same time
doskey here=cd $T dir /b

Type dnsreset — CMD runs both commands back to back without you pressing Enter twice:

Windows IP Configuration

Successfully flushed the DNS Resolver Cache.

Windows IP Configuration

    Record Name . . . . . : SRV-PROD-01.corp.local
    Record Type . . . . . : 1
    Time To Live  . . . . : 86379
    Data Length . . . . . : 4
    Section . . . . . . . : Answer
    A (Host) Record . . . : 10.0.1.50

Positional arguments with $1–$9

The problem: You want a macro that takes a specific argument and inserts it at a precise position in the command — not just appended at the end.

The solution: Use numbered placeholders. $1 maps to the first word typed after the macro name, $2 to the second, and so on up to $9. Use $* when you want everything the user typed, regardless of how many words.

rem Check whether a named service is running — $1 is replaced by the service name you type
rem Example: svccheck Spooler
doskey svccheck=sc query $1 $B findstr /i "STATE"

rem Ping a host exactly 4 times — -n 4 is always baked in, $1 is the target hostname or IP
rem Example: p SRV-PROD-01
doskey p=ping -n 4 $1

rem Find a running process by name fragment — $1 is the search term
rem Example: pf chrome
doskey pf=tasklist $B findstr /i "$1"

Type svccheck Spooler — CMD runs sc query Spooler | findstr /i "STATE" and returns just the state line, trimming the rest of the sc output:

        STATE              : 4  RUNNING

Removing a DOSKEY macro

To remove a macro from the current session, assign it an empty value — nothing after the equals sign:

rem Remove the ps macro — assigning empty clears it from the session
doskey ps=

rem Confirm it is gone — ps should no longer appear in the output
doskey /macros

Making CMD macros persistent

DOSKEY macros die with the session. To load them automatically every time a CMD window opens, you use two things together: a macro definition file and a registry AutoRun key that tells CMD to run a command on startup.

Step 1 — Check for an existing AutoRun value

Before writing anything, check whether the AutoRun value already exists — some software sets it during installation and overwriting it blindly would break their initialization:

reg query "HKCU\Software\Microsoft\Command Processor" /v AutoRun

If a value exists, you will see something like this — note it so you can append to it rather than overwrite:

HKEY_CURRENT_USER\Software\Microsoft\Command Processor
    AutoRun    REG_SZ    @chcp 65001>nul

If you get ERROR: The system was unable to find the specified registry key or value, the key does not exist and you can set it freely.

Step 2 — Create the macro definition file

Create a plain text file at C:\bat\cmd-macros.txt. One macro per line, no doskey keyword — just the definitions. This is the same format that doskey /macros outputs, so you can also generate this file by running your preferred macros in a session and then exporting:

ll=dir /b /a $*
scripts=cd /d C:\bat
logs=cd /d C:\logs
go=cd /d $*
ipa=ipconfig /all
ps=tasklist
p=ping -n 4 $1
pf=tasklist $B findstr /i "$1"
svccheck=sc query $1 $B findstr /i "STATE"
sysinfo=systeminfo $B findstr /i "$*"
dnsreset=ipconfig /flushdns $T ipconfig /displaydns
here=cd $T dir /b
Note: In the macro file, use $B for pipes and $T for command separators — exactly as in the interactive doskey command. Do not use literal | or & in the file.

Step 3 — Set the AutoRun registry key

CMD reads this registry value on startup and runs whatever command is stored there. Set it to load your macro file. Run this once from an elevated CMD:

rem /f overwrites the value without prompting for confirmation
rem HKCU applies to your user account only — use HKLM to apply for all users (requires elevation)
reg add "HKCU\Software\Microsoft\Command Processor" /v AutoRun /t REG_SZ /d "doskey /macrofile=C:\bat\cmd-macros.txt" /f

If an AutoRun value already existed, chain both commands in the value string using &. For example, if the existing value was @chcp 65001>nul:

rem Preserve the existing command and append the macro loader after it
reg add "HKCU\Software\Microsoft\Command Processor" /v AutoRun /t REG_SZ /d "@chcp 65001>nul & doskey /macrofile=C:\bat\cmd-macros.txt" /f

Open a new CMD window and verify the macros loaded:

doskey /macros
dnsreset=ipconfig /flushdns $T ipconfig /displaydns
go=cd /d $*
here=cd $T dir /b
ipa=ipconfig /all
ll=dir /b /a $*
logs=cd /d C:\logs
p=ping -n 4 $1
pf=tasklist $B findstr /i "$1"
ps=tasklist
scripts=cd /d C:\bat
svccheck=sc query $1 $B findstr /i "STATE"
sysinfo=systeminfo $B findstr /i "$*"
Result: Every new CMD window — including elevated ones — will load these macros automatically without any manual setup.

Exporting and importing macros manually

You can snapshot all current session macros to a file and reload them later — useful for sharing a macro set or transferring it to another machine without touching the registry:

rem Export all currently active macros to a file
doskey /macros > C:\bat\cmd-macros.txt

rem Load macros from a file into the current session immediately
doskey /macrofile=C:\bat\cmd-macros.txt

PowerShell aliases

How PowerShell aliases work

PowerShell has a native alias system built into the language. An alias is a short name that maps to a cmdlet, a function, or an external executable. Unlike DOSKEY macros, a PowerShell alias is a pure name substitution — it cannot carry arguments. For shortcuts that need flags baked in, you use functions instead (covered below).

PowerShell ships with a large set of built-in aliases, many of them deliberately familiar to Linux users. Run this to see them all:

# List all built-in and custom aliases, sorted alphabetically
Get-Alias | Select-Object Name, Definition | Sort-Object Name

A selection of the most useful built-in aliases:

AliasExpands toLinux equivalent
catGet-Contentcat
cdSet-Locationcd
clsClear-Hostclear
cpCopy-Itemcp
dir / lsGet-ChildItemls
echoWrite-Outputecho
mvMove-Itemmv
ps / gpsGet-Processps
pwdGet-Locationpwd
rmRemove-Itemrm
sleepStart-Sleepsleep
typeGet-Contentcat

Get-Alias: look up existing aliases

Use Get-Alias to check what a short name maps to, or to find all aliases for a given cmdlet. Always worth checking before defining a new alias — to avoid silently overwriting one that already exists.

# Check what 'ls' maps to — shows the cmdlet behind the alias name
Get-Alias ls
CommandType     Name                Version    Source
-----------     ----                -------    ------
Alias           ls -> Get-ChildItem
# Find ALL aliases that point to the same cmdlet
# Useful to discover that dir, gci, and ls all do the same thing
Get-Alias -Definition Get-ChildItem
CommandType     Name                Version    Source
-----------     ----                -------    ------
Alias           dir -> Get-ChildItem
Alias           gci -> Get-ChildItem
Alias           ls  -> Get-ChildItem
# List all aliases whose name starts with 'g' — useful for discovering short Get-* names
Get-Alias g*
CommandType     Name                Version    Source
-----------     ----                -------    ------
Alias           gci  -> Get-ChildItem
Alias           gcm  -> Get-Command
Alias           gl   -> Get-Location
Alias           gmo  -> Get-Module
Alias           gp   -> Get-ItemProperty
Alias           gps  -> Get-Process
Alias           group -> Group-Object
Alias           gsv  -> Get-Service
Alias           gv   -> Get-Variable
Alias           gwmi -> Get-WmiObject

Set-Alias and New-Alias

Set-Alias creates an alias or silently overwrites one that already exists. New-Alias creates one but throws an error if the name is already taken — the safer choice in scripts where an accidental overwrite of a built-in alias would be a bug.

# Map 'grep' to Select-String
# After this: grep "error" .\app.log  works like grep on Linux
Set-Alias -Name grep -Value Select-String

# Map 'which' to Get-Command
# After this: which notepad  shows the full path of the executable that would run
Set-Alias -Name which -Value Get-Command

# Use New-Alias when you want it to fail loudly if the name is already taken
# Safer in scripts — prevents silent overwrites of built-in aliases
New-Alias -Name svc -Value Get-Service

Try the new aliases right away — no need to restart PowerShell:

# Find lines containing 'error' in a log file
grep "error" C:\logs\app.log

# Show the full path of notepad.exe
which notepad
C:\Windows\System32\notepad.exe
Warning: PowerShell aliases map to a cmdlet name only — they cannot include arguments. Set-Alias ll "Get-ChildItem -Force" throws an error because the value must be a single command name, not a string with flags. Use a function for anything that needs arguments baked in.

Removing an alias

To remove an alias from the current session, use Remove-Alias. The most practical use case is removing a built-in alias that conflicts with an external tool you want to call by the same name.

# Remove the built-in 'curl' alias, which maps to Invoke-WebRequest
# After this, typing 'curl' calls the real curl.exe binary instead of the PowerShell wrapper
# The two have different syntax — this avoids silent breakage in scripts copied from Linux
Remove-Alias -Name curl

# Remove a custom alias defined earlier in the session
Remove-Alias -Name grep
Note: Remove-Alias is available in PowerShell 6 and later. In Windows PowerShell 5.1, use Remove-Item Alias:\curl instead — the Alias: drive is a built-in provider that lets you manage aliases like files in a directory.

PowerShell: aliases with arguments — use functions

When you need a shortcut that includes specific flags or argument logic, define a function. Functions are first-class citizens in PowerShell — they accept parameters, receive pipeline input, and can contain any logic. A short function is the standard way to build “aliases with arguments” in PowerShell.

Inside a simple function, $args holds all arguments passed to it as an array. $args[0] is the first argument, $args[1] the second, and so on. For more structured input, use a param() block.

# ll: list directory contents including hidden files (-Force)
# Equivalent to: ls -la on Linux
# $args passes any path or flags you type after 'll' straight through to Get-ChildItem
# Usage: ll   or   ll C:\bat   or   ll -Recurse C:\bat
function ll { Get-ChildItem -Force $args }

# ipa: full network adapter configuration for all interfaces
# Equivalent to: ipconfig /all in CMD
# Usage: ipa
function ipa { Get-NetIPConfiguration -Detailed }

# svccheck: show the name, status, and startup type of a service
# $args[0] captures the first argument — the service name
# Usage: svccheck Spooler
function svccheck {
    Get-Service -Name $args[0] | Select-Object Name, Status, StartType
}

# top: show the 10 processes currently consuming the most CPU
# Sorts by CPU descending and takes the first 10 results
# Usage: top
function top {
    Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, CPU, Id
}

# pf: find a running process by partial name match
# -like with wildcards on both sides matches any process whose name contains the search term
# Usage: pf chrome
function pf {
    Get-Process | Where-Object { $_.Name -like "*$($args[0])*" }
}

Type svccheck Spooler — PowerShell returns a clean, formatted table with just the fields you care about:

Name    Status  StartType
----    ------  ---------
Spooler Running Automatic

Type top to see which processes are currently consuming the most CPU:

Name                CPU       Id
----                ---       --
MsMpEng         1842.27     3320
svchost          923.14      984
powershell       412.66     7240
explorer         188.09     4512
Teams             91.33     6804
chrome            78.11     9120
SearchHost        52.44     7788
OneDrive          31.09     5640
WmiPrvSE          18.22     3988
lsass             12.77      692

Making PowerShell aliases persistent: $PROFILE

PowerShell loads a profile script on startup — the equivalent of .bashrc on Linux. Anything you put in the profile runs automatically every time PowerShell starts. This is where you define aliases and functions that should always be available.

Find your profile path

The $PROFILE automatic variable holds the path to the current user’s profile script. Run this to see where it lives on your machine:

$PROFILE
C:\Users\John\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

Create the profile if it does not exist

The profile file is not created by default. Check first, then create it — the -Force flag creates any missing parent directories automatically:

# Test-Path returns True if the file exists, False if it does not
# New-Item -Force creates the file and any missing parent directories in one step
if (-not (Test-Path $PROFILE)) {
    New-Item -Path $PROFILE -ItemType File -Force
}

Add aliases and functions to the profile

Open the profile in your editor of choice. Notepad works; VS Code gives you syntax highlighting and error highlighting for free:

notepad $PROFILE
# or, if you use VS Code:
code $PROFILE

A complete, ready-to-paste profile with all the aliases and functions from this guide:

# ── Aliases ─────────────────────────────────────────────────────────────────
# grep: shorthand for Select-String — filters output by pattern, like grep on Linux
Set-Alias -Name grep  -Value Select-String

# which: shorthand for Get-Command — shows the full path of an executable
Set-Alias -Name which -Value Get-Command

# ── Functions ────────────────────────────────────────────────────────────────

# ll: list directory contents including hidden files
# Usage: ll   or   ll C:\bat
function ll { Get-ChildItem -Force $args }

# ipa: full IP and adapter configuration for all interfaces
# Usage: ipa
function ipa { Get-NetIPConfiguration -Detailed }

# top: top 10 processes by current CPU usage
# Usage: top
function top {
    Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, CPU, Id
}

# svccheck: show status and start type of a named service
# Usage: svccheck Spooler
function svccheck {
    Get-Service -Name $args[0] | Select-Object Name, Status, StartType
}

# pf: find a running process by partial name
# Usage: pf chrome
function pf {
    Get-Process | Where-Object { $_.Name -like "*$($args[0])*" }
}

<#
    Remove the built-in curl alias so the real curl.exe binary runs when you type 'curl'.
    PowerShell maps 'curl' to Invoke-WebRequest by default, which has completely
    different syntax from curl.exe — this prevents silent breakage in commands
    copied from Linux or documentation written for curl.exe.
    The -ErrorAction SilentlyContinue guard prevents an error on machines where
    the alias does not exist (e.g. after a PowerShell update removes it).
#>
if (Get-Alias curl -ErrorAction SilentlyContinue) {
    Remove-Alias -Name curl
}

After saving, reload the profile in the current session without restarting PowerShell. The dot (.) is the dot-sourcing operator — it runs the script in the current scope so all definitions become immediately available:

. $PROFILE
Warning: If PowerShell throws a script execution error when loading the profile, the execution policy is blocking it. Run this once from an elevated session to allow local scripts to run: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned. This permits locally created scripts to run without a signature, while still requiring any script downloaded from the internet to be signed.

Profile scope reference

PowerShell supports multiple profile files with different scopes. For personal use on a single machine, $PROFILE is the right choice. Use AllUsers scopes only if you are managing a shared machine and want every user to inherit the same aliases:

VariableScopeTypical path
$PROFILEYour account, this PowerShell host onlyDocuments\PowerShell\Microsoft.PowerShell_profile.ps1
$PROFILE.CurrentUserAllHostsYour account, all PowerShell hosts (ISE, VSCode terminal, etc.)Documents\PowerShell\profile.ps1
$PROFILE.AllUsersCurrentHostAll users on the machine, requires admin to editC:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1
Note: Windows PowerShell 5.1 and PowerShell 7 have separate profile files in separate folders — WindowsPowerShell vs PowerShell. Changes to one do not affect the other. If you use both, either maintain both profiles separately or define shared content in $PROFILE.CurrentUserAllHosts and verify it actually loads in both hosts.

Exporting and importing PowerShell aliases

PowerShell has dedicated cmdlets for sharing alias sets across machines or sessions — cleaner than copying profile files when you only want to transfer aliases, not the entire profile configuration.

# Export all current session aliases to a CSV file
# The file includes: name, definition, description, and options for each alias
Export-Alias -Path C:\bat\ps-aliases.csv

# Export only specific aliases by name — useful for sharing a curated subset
Export-Alias -Path C:\bat\ps-aliases.csv -Name grep, which, svc

The exported file is a plain CSV — readable and editable in any text editor or spreadsheet:

# Alias File
# Exported by : John
# Date/Time : 05/10/2026 09:14:33
# Computer : SRV-PROD-01
"grep","Select-String","",""
"which","Get-Command","",""
"svc","Get-Service","",""
# Import aliases from the file into the current session
Import-Alias -Path C:\bat\ps-aliases.csv

# Import and overwrite any existing aliases with the same name
Import-Alias -Path C:\bat\ps-aliases.csv -Force
Note: Export-Alias only exports aliases, not functions. If your shortcuts are defined as functions (like ll, top, or svccheck), copy the function definitions to the target machine’s profile manually — they will not appear in the exported CSV.

Hidden gems

DOSKEY macros shadow real commands silently. If you define doskey ping=ping -n 4 $1, typing ping in your session runs your macro. But a batch script calling ping bypasses the macro entirely and runs the real binary — scripts do not see session macros at all. This asymmetry causes confusion when a command behaves differently in your interactive session versus in a script.

The Alias: drive in PowerShell. PowerShell exposes all aliases through a virtual filesystem drive called Alias:. You can navigate it like a directory and manage aliases using the same cmdlets you use for files — which means tab completion, wildcards, and Get-ChildItem all work:

# List all aliases through the Alias: drive — same result as Get-Alias
Get-ChildItem Alias:

# Remove an alias using Remove-Item — works in PowerShell 5.1 where Remove-Alias does not exist
Remove-Item Alias:\curl

Check what actually runs before you call it. When you have both an alias and a function with the same name, or when a built-in alias conflicts with a custom definition, PowerShell resolves them in a fixed priority order: aliases win over functions, functions win over cmdlets, cmdlets win over external executables. Use Get-Command to see exactly which one would run:

# Show which 'grep' would run — alias, function, cmdlet, or external binary?
Get-Command grep
CommandType     Name                Version    Source
-----------     ----                -------    ------
Alias           grep -> Select-String

Where this matters

Daily troubleshooting sessions. Typing ipa instead of ipconfig /all, svccheck Spooler instead of the full sc query pipeline, or top instead of the full Get-Process sort chain saves real time across a full day of work.

Standardized admin environments. Distributing a shared macro file or a shared PowerShell profile across a team ensures everyone has the same shorthand available — useful when support teams follow runbooks that reference short command names.

Onboarding Linux-background engineers to Windows. Aliases like grep, which, ll, and ps reduce friction for engineers used to Bash, letting them be productive before they have internalized PowerShell cmdlet names.

Avoiding typos in long service names. Services like wuauserv, MpsSvc, and CryptSvc typed repeatedly during incident response are a common source of small errors. A svccheck macro removes the repetition.

Jump-starting new CMD sessions from scripts. A batch script that bootstraps a working environment — loading macros, setting variables, mapping drives — can be called from a desktop shortcut and give you a fully configured CMD window in one click.


Tips and limitations

  • DOSKEY macros are session-local and interactive-only. They do not work inside batch files. The AutoRun registry method is the only way to make them load automatically in new CMD sessions.
  • PowerShell aliases cannot carry arguments. If you try to bake in flags, you need a function. The alias is a name substitution only — Set-Alias ll "Get-ChildItem -Force" throws an error.
  • The execution policy blocks $PROFILE on new machines. The default policy (Restricted) prevents any script from running, including the profile. Set it to RemoteSigned for the current user before expecting the profile to load.
  • Windows PowerShell 5.1 and PowerShell 7 have separate profiles. Changes to one do not affect the other. If you use both, maintain both profile files.
  • DOSKEY command history is also per-session. Arrow-key recall of previous commands does not persist between CMD windows. There is no built-in equivalent of ~/.bash_history for CMD.
  • The AutoRun registry key affects all CMD windows, including elevated ones. If your macro file contains commands that assume a specific working directory or environment, test in both a normal and elevated CMD window after setting it up.
  • Export-Alias does not export functions. If your shortcuts are functions rather than aliases, copy the function definitions to the target machine’s profile manually — they will not appear in the exported CSV.

Official documentation


Related tools

  • Windows 11 Registry Tweak Generator — generate the exact reg add command for the CMD AutoRun key without typing it by hand
  • ROBOCOPY Command Builder — build robocopy commands interactively; a natural candidate for a DOSKEY macro or PowerShell function once you have settled on your preferred flags
  • nltest Command Builder — compose nltest commands visually; wrap the result in a DOSKEY macro for repeated use during domain troubleshooting sessions

Related guides