RE:NODE

SteamCMD on Windows: install, scripts and updates

By RE:NODE Team
18 min read


SteamCMD on Windows is one zip file: download steamcmd.zip from Valve, unpack it into a short path such as C:\steamcmd, and run steamcmd.exe once with +quit so it can update itself. After that, every server install is the same line - +force_install_dir with an absolute path, +login anonymous, +app_update <id> validate, +quit - which you move into a script file and call from a batch file, and then hand to Task Scheduler for unattended updates. The Windows-specific parts are where things go wrong: paths with spaces, folders under Program Files or your profile, a scheduled task that runs as a different user from the one you tested with, and Defender scanning thousands of small files during every update. This post covers those parts. The arguments themselves, the error table and how app ids work are in SteamCMD explained, and branch switching is in SteamCMD app IDs and beta branches.

Downloading SteamCMD and the first run#

There is no installer and nothing to add to the Start menu. Valve publishes a zip containing a single small executable, and that executable downloads the rest of itself.

  1. Create a folder for it. C:\steamcmd is the convention, and the short path matters later.
  2. Download https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip and extract steamcmd.exe into that folder.
  3. Open Command Prompt or PowerShell, change to the folder, and run steamcmd.exe +quit.

The same three steps from an ordinary (not elevated) PowerShell window:

code
PS> New-Item -ItemType Directory -Path C:\steamcmdPS> Invoke-WebRequest -Uri https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip `      -OutFile C:\steamcmd\steamcmd.zipPS> Expand-Archive C:\steamcmd\steamcmd.zip -DestinationPath C:\steamcmdPS> C:\steamcmd\steamcmd.exe +quit

The first run is the self-update. SteamCMD reports that it is checking for updates, downloads its packages, extracts them, and relaunches itself before it gets to Loading Steam API...OK and a prompt. On a normal connection this takes a minute or two. The exact lines change between releases, but they look roughly like this:

code
[  0%] Checking for available updates...[----] Downloading update (...)[----] Extracting package...[----] Installing update...[----] Cleaning up...[----] Update complete, launching Steamcmd...Loading Steam API...OK

Let it finish. Interrupting the first run - closing the window, or a scheduled task that times out - leaves a half-unpacked client that fails in confusing ways on the next launch. If that happens, delete everything in the folder except steamcmd.exe and run +quit again. That is also the standard repair for a SteamCMD that has started crashing on startup after months of working: the bootstrapper rebuilds what it needs from scratch, and nothing you care about lives in those files unless you have been installing servers into the default location (see the next section).

SteamCMD checks for its own updates on every launch, not only the first. When Valve has shipped a new client, your next scripted update will spend its first minute updating SteamCMD before it touches the game. Plan timeouts around that.

Runtimes the server will want

SteamCMD itself needs nothing extra. The servers you download with it often do. Many Windows dedicated servers are built against the Microsoft Visual C++ Redistributable, and a missing one shows up as the server refusing to start with a message about a DLL such as VCRUNTIME140.dll or MSVCP140.dll. Some older or Unreal-based servers also want pieces of the DirectX runtime. These are per-game requirements, not SteamCMD's, so check the game's own server documentation. Installing the current x64 Visual C++ Redistributable from Microsoft before your first server is a reasonable default on a fresh Windows Server machine, which ships without most of what a desktop picked up from games over the years.

Where things go: the folder layout#

After the first run, C:\steamcmd holds a few dozen files and folders. The ones worth knowing:

PathWhat it holds
steamcmd.exeThe bootstrapper. The only file you need to keep
package\The client packages from the self-update
config\config.vdfSettings and the cached login for real accounts
logs\Text logs, including content_log.txt for downloads
steamapps\Default install location and SteamCMD's own state

Two of those deserve a comment. config\config.vdf is where SteamCMD keeps the cached credential after a real-account login has passed Steam Guard. For anonymous installs it does not matter; for Arma 3 or DayZ it is the file that makes unattended updates possible, and it should be treated like a password. logs\content_log.txt records every download, every state change and every failure with a timestamp. When an update fails overnight and the batch file's own log says nothing useful, this is the one to read.

If you never set +force_install_dir, servers land in C:\steamcmd\steamapps\common\<AppName>. That works for one server and becomes awkward for several, because the game files sit inside the tool's folder, a SteamCMD repair has to step around them, and backups of "the server" accidentally include the client. The layout that stays manageable keeps SteamCMD, servers and scripts apart:

code
C:\steamcmd\                 SteamCMD onlyC:\servers\valheim\          one folder per server installC:\servers\satisfactory\C:\servers\scripts\          .txt runscripts, .cmd files, logs

Keep the root short and free of spaces. Windows still has a 260-character path limit for many programs unless long paths are switched on in policy and the program opts in, and game servers are not reliably among the programs that opt in. A Workshop item several folders deep inside C:\Users\Administrator\Documents\Game Servers\... gets surprisingly close to that limit.

Avoid three places in particular:

  • `C:\Program Files` and `C:\Program Files (x86)`. Writing there needs elevation, so either every update runs as administrator or the update fails with a permissions error part-way through.
  • Your user profile, including Desktop, Documents and Downloads. A scheduled task running as another account cannot see it, and Defender's Controlled folder access, if it is on, blocks unrecognised programs from writing to those folders.
  • A OneDrive-synced folder. Sync clients lock and upload files while SteamCMD is replacing them, and a game server writing its world every few minutes turns into constant sync traffic.

Every server install also gets its own steamapps\appmanifest_<appid>.acf, holding the installed build id. That file is how you tell which version a server is on; SteamCMD explained goes through it.

force_install_dir on Windows#

+force_install_dir takes an absolute path, and on Windows the details are paths and quotes.

code
C:\steamcmd\steamcmd.exe +force_install_dir C:\servers\valheim +login anonymous ^    +app_update 896660 validate +quit

The ^ is the line continuation character in Command Prompt and batch files. In PowerShell the continuation character is the backtick instead, and in either shell it is safer to keep the whole command on one line until it works.

Order matters. Recent SteamCMD builds print a warning along the lines of "Please use force_install_dir before logon!" if +login comes first, and depending on the version the directory is then ignored and the files go to the default location. Put +force_install_dir first, then +login, then +app_update. The same order applies inside script files.

If the path contains a space, quote it: +force_install_dir "C:\Game Servers\valheim". Quoting works, but it is one more thing to get wrong in batch files, where a variable holding a quoted path picks up a second set of quotes when you use it. The simpler fix is a path without spaces.

Do not use relative paths. A relative directory is resolved against SteamCMD's own folder rather than the folder your batch file or shell is in, so +force_install_dir ..\valheim lands somewhere different depending on where SteamCMD lives. A mapped network drive is also a bad target: drive letters are per logon session, so a drive mapped in your desktop session does not exist for a scheduled task, and SteamCMD over SMB is slow and fragile even when it does.

One SteamCMD folder can manage any number of server installs, because each one is a separate force_install_dir. What it should not do is run twice at the same time. Two instances share package\, config\ and the self-update, and a second launch while the first is updating itself is a reliable way to corrupt the client. If several servers update on a schedule, update them one after another in a single script, or stagger their tasks by enough time for each to finish.

Script files and +runscript#

A long command line in a batch file becomes a maintenance problem the first time you need to change one argument in six places. SteamCMD reads commands from a text file instead, one per line, without the + prefix:

C:\servers\scripts\update-valheim.txt
// Valheim dedicated server, app 896660@ShutdownOnFailedCommand 1@NoPromptForPassword 1force_install_dir C:\servers\valheimlogin anonymousapp_update 896660quit
code
C:\steamcmd\steamcmd.exe +runscript C:\servers\scripts\update-valheim.txt

Lines starting with // are comments. The two @ lines are settings: @ShutdownOnFailedCommand 1 stops at the first failing command instead of carrying on to quit, and @NoPromptForPassword 1 stops an unattended run hanging forever on a password prompt nobody will answer. Both should be in every script that runs without you watching. Pass the script with an absolute path, for the same reason as force_install_dir.

Note what is not in that script: validate. A routine update fetches only changed chunks; validate reads and hashes the whole install, and replaces any shipped file you have edited. Keep a second script with validate for repairs, and run it by hand when you need it. The reasoning is in automating game server updates safely.

A script file is also where you would put more than one app. Several force_install_dir and app_update pairs can follow one login, which runs the updates in sequence under one SteamCMD launch and sidesteps the two-instances problem above:

C:\servers\scripts\update-all.txt
@ShutdownOnFailedCommand 1@NoPromptForPassword 1login anonymousforce_install_dir C:\servers\valheimapp_update 896660force_install_dir C:\servers\satisfactoryapp_update 1690800quit

That order puts login before the directory, which the warning above complains about. In practice later force_install_dir lines are honoured for the app_update that follows them, but behaviour has changed between SteamCMD versions, so check where the files land after the first run. If the warning matters to you, run one script per server instead.

A batch file that stops, updates and checks#

SteamCMD cannot replace files a running server holds open. Updating a running server either fails with a file-in-use error or, worse, half-succeeds and leaves an install that crashes on its next start. So the wrapper's job is: stop the server cleanly, update, check the result, start the server.

This example assumes the server runs as a Windows service named Valheim (NSSM is the usual way to do that - the Valheim on Windows guide sets one up with a proper Ctrl+C stop so the world saves). net stop waits for the service to stop before returning, which is what you want.

C:\servers\scripts\update-valheim.cmd
@echo offsetlocalcd /d "%~dp0"set LOG=%~dp0update-valheim.logecho ==== %DATE% %TIME% ==== >> "%LOG%"net stop Valheim >> "%LOG%" 2>&1C:\steamcmd\steamcmd.exe +runscript "%~dp0update-valheim.txt" > "%~dp0last-run.log" 2>&1type "%~dp0last-run.log" >> "%LOG%"findstr /C:"Success! App '896660'" "%~dp0last-run.log" >nulif errorlevel 1 (    echo UPDATE FAILED - server left stopped >> "%LOG%"    exit /b 1)net start Valheim >> "%LOG%" 2>&1exit /b 0

A few lines need explaining.

  • cd /d "%~dp0" changes to the folder the batch file is in. %~dp0 expands to that folder with a trailing backslash. Task Scheduler starts tasks in C:\Windows\System32 unless told otherwise, and any relative path in a script that "worked when I double-clicked it" breaks there.
  • The success check reads SteamCMD's output, not its exit code. The exit code has not been a reliable signal across versions, and a failed download can exit with a code that looks fine. The line SteamCMD prints after a good update or install is Success! App '<id>' fully installed., and when it is already up to date it prints Success! App '<id>' already up to date. Matching on the common prefix accepts both.
  • On failure the script leaves the server stopped. That is a choice. Starting a server on a half-updated install risks corrupting the world; leaving it down means players notice and somebody looks. For a server where downtime is worse than risk, change that branch to start the service anyway and alert you some other way.
  • %DATE% and %TIME% are formatted by the system locale, so do not try to build file names from them; the format changes between machines. If you want one log file per run, get the timestamp from PowerShell with Get-Date -Format yyyyMMdd-HHmm instead.

If the server is not a service but a console window started from a batch file, there is no clean way for a script to stop it. Closing the window or taskkill /F ends the process without letting it save. Run game servers as services if you intend to update them unattended; it is the only arrangement where "stop" means a clean stop.

Scheduled updates with Task Scheduler#

Task Scheduler is Windows' cron. It can be driven from the GUI (taskschd.msc) or from the command line with schtasks, which is easier to document and repeat.

code
schtasks /Create /TN "Servers\Update Valheim" ^    /TR "C:\servers\scripts\update-valheim.cmd" ^    /SC WEEKLY /D MON /ST 05:00 /RU SYSTEM /RL HIGHEST

That creates a task in a Servers folder that runs every Monday at 05:00 as the built-in SYSTEM account with highest privileges. Test it immediately, then read its last result:

code
schtasks /Run /TN "Servers\Update Valheim"schtasks /Query /TN "Servers\Update Valheim" /V /FO LIST

Last Result: 0 means the batch file exited with 0, which in the script above means the success line was found. 1 means the script's own failure branch ran. Anything else - a large hexadecimal number - usually means the task never got as far as running the script: a wrong path in /TR, or an account without permission to the folder.

The account the task runs as is the decision that matters.

Run asGood forWatch out for
SYSTEMAnonymous installs, servicesFull control of the machine
A dedicated local userReal-account loginsNeeds folder rights
Your own accountTestingPassword changes break it

SYSTEM is the simplest: it can stop and start services and write anywhere. It is also the most powerful account on the machine, so a script it runs should live in a folder that only administrators can write to. For servers that need a real Steam login (Arma 3, DayZ), a dedicated local user is cleaner. Log in once as that user, run SteamCMD by hand to pass Steam Guard, and the cached credential in config\config.vdf lets the scheduled task log in without a prompt afterwards. That user needs Modify rights on C:\steamcmd and C:\servers, the "Log on as a batch job" right (granted automatically when you save a task with its password), and the right to control the service if the script stops and starts it.

Options worth setting in the task's properties, whichever account you use:

  • Run whether user is logged on or not. Otherwise the task only runs while someone is signed in at the console.
  • Stop the task if it runs longer than something sensible, such as two hours. The default is three days, which hides a hung SteamCMD for a long time.
  • Do not start a new instance if the task is already running. This is the default and it prevents two SteamCMD runs overlapping.
  • Run task as soon as possible after a scheduled start is missed. Useful if the machine was rebooting for Windows updates at 05:00 - though a weekly server update colliding with Patch Tuesday is worth avoiding in the first place.

How often to run it depends on the server. A vanilla server can update weekly or on every restart; a modded server should not update itself at all on the day of a game patch, because the update breaks mods until their authors catch up. What to do when a mod update breaks covers the recovery, and scheduled tasks worth having covers what else belongs on the same schedule.

stop firstupdate.txtoutputstart only on successTask Schedulerweekly, 05:00update-valheim.cmdstop, update, checksteamcmd.exe+runscriptlast-run.logSuccess! AppValheim servicenet stop / net start
A scheduled update on Windows

Windows Defender exclusions#

Microsoft Defender's real-time protection scans files as they are written. An update writes thousands of them, and a validate reads every file in the install, which Defender may scan again. On a large install that is the difference between a validate finishing in a few minutes and one that takes much longer. Defender can also hold a freshly written file open for a moment while it scans, which occasionally collides with SteamCMD moving it into place.

Excluding the SteamCMD folder and the server folders from scanning removes both problems. From an elevated PowerShell window:

code
PS> Add-MpPreference -ExclusionPath "C:\steamcmd"PS> Add-MpPreference -ExclusionPath "C:\servers"PS> Get-MpPreference | Select-Object -ExpandProperty ExclusionPath

The last line lists the current exclusions so you can confirm they took. On a machine managed by Group Policy or Intune, local exclusions may be ignored or overwritten, and the policy has to carry them instead.

Be honest with yourself about the trade. An exclusion means Defender will not look at anything in those folders, including a malicious plugin someone sends you or a mod downloaded from a site you should not have trusted. Keep exclusions to the folders that need them, never exclude a downloads folder or a whole drive, and scan mods and plugins before they go into an excluded folder. Malicious plugins and mods explains why that is not paranoia.

Defender exclusions are separate from Windows Defender Firewall. SteamCMD itself needs only outbound internet access, which Windows allows by default. The game server needs inbound rules for its ports, and the first time it starts Windows will ask whether to allow it on private or public networks. Answer for the network the server is actually on, or create the rules yourself with New-NetFirewallRule - the Valheim Windows guide linked above walks through both.

Troubleshooting SteamCMD on Windows#

SteamCMD closes immediately when double-clicked, or the window flashes and vanishes. It probably updated itself and relaunched, or hit an error and exited. Run it from an open Command Prompt so the output stays on screen, and read logs\bootstrap_log.txt.

`Failed to install app 'X' (Disk write failure)`. The target folder is not writable by the account running SteamCMD, or the disk is full. Check the account first if it only fails from Task Scheduler. On a full disk, remember an update needs free space on top of the existing install - what to do when the disk is full covers how much.

`Failed to install app 'X' (Missing file permissions)` or access denied. A file in the install is in use (the server is still running), read-only, or owned by an account the current one cannot modify. Stop the server, then compare the folder's permissions against the account the task runs as.

The update says success but the server did not change. The task ran a different script, the install directory in the script differs from the one the service starts from, or force_install_dir came after login and the files went to C:\steamcmd\steamapps\common. Look for a second copy of the server there.

The task's Last Result is non-zero but the log is empty. The batch file never started, or started in System32 and wrote its log there. Check the path in the task's action and the cd /d "%~dp0" line.

SteamCMD hangs at login in a scheduled task. It is waiting for a password or a Steam Guard code that will never come. Run SteamCMD once by hand as the task's account to cache the credential, and keep @NoPromptForPassword 1 in the script so the next failure ends instead of hanging.

Everything stopped working after a Windows update. Usually not SteamCMD. Confirm the service still starts by hand and the task still exists; then delete everything in C:\steamcmd except steamcmd.exe and the config folder (if you use a real account), and run +quit to rebuild the client.

When you do not want to run Windows at all#

Most of this post exists because Windows was not designed around unattended command-line tools, and every step above - service wrappers, task accounts, Defender exclusions - is there to make it behave like one. Some servers only ship a Windows build, and for those it is worth it, or worth reading Linux vs Windows for game servers and the Wine and Proton route. For the rest, the question is whether you want to maintain the machine at all.

On RE:NODE the SteamCMD step runs when a game server is created, usually inside a minute of payment clearing, and the install output appears line for line in the console. Game variables and launch settings are fields on the Startup tab, so there is no script to maintain. The Schedules tab runs cron-style tasks with ordered steps - a backup, then a restart, with delays between them - which covers the job Task Scheduler does above; the guides show how it is set up. Games that need your own Steam login wait on the Setup tab until you add it.

FAQ#

Do I need to run SteamCMD as administrator?

No, as long as it and the server folders are somewhere the account can write to, such as C:\steamcmd and C:\servers. Needing administrator rights is usually a sign the files are under Program Files. The only part of this setup that needs elevation is adding Defender exclusions and creating tasks that run as SYSTEM.

Can I use the Steam client's Tools library instead of SteamCMD?

For some servers, yes: dedicated servers listed under Tools in the Steam library install like any game. That needs the full Steam client signed in on the machine and updates whenever Steam decides to, which suits a home PC that also plays games. A machine that only runs servers is better served by SteamCMD, which needs no desktop session.

Where are the SteamCMD logs on Windows?

In the logs folder inside the SteamCMD directory, for example C:\steamcmd\logs. content_log.txt records downloads and install failures and is the first file to read when an update fails. Your own batch file's log is separate and only holds what you redirected into it.

Can I download the Linux build of a server from Windows?

Yes. Add @sSteamCmdForcePlatformType linux at the top of the script before login. The files download but will not run on Windows; it is useful for preparing an install to copy to a Linux machine or a host's file manager.

How do I uninstall SteamCMD?

Delete its folder, and delete any scheduled tasks and Defender exclusions you created for it. SteamCMD does not write to the registry or install services of its own. Server installs in other folders are untouched and keep working; they only lose their updater.

Why does the update take longer every time a new SteamCMD is released?

Because SteamCMD updates itself before running your commands whenever Valve ships a new client. The first scheduled run after a client release spends extra time on that. It is normal, and the reason a task's time limit should be generous.