[PowerShell] STEAM WORKSHOP MOD DOWNLOADER TOOL


PowerGod

Forum Addict!
Joined
Jun 20, 2011
Messages
4,419
There is an issue when games are from stores different from Steam, them don't have access to Steam WorkShop, and so to almost all the MODs.

Most of the time anyway it is possible to download the MODs from Steam WorkShop, and manually put them in the game folder.
This operation is not an issue if you need one or two of them, but it becomes pretty difficult if you want to try them all !!

There is an official Valve command-line tool named SteamCMD, that can download massively all the MODs you want, but it has two problems:
  • it needs the ID of every single MOD to download
  • it downloads them in a standard Steam Archive format (every MOD folder is an ID), and the only way to know what MOD is inside every folder is to have a look at the content of the "text_*.csv" files to get the name

I solved many months ago the first issue, using a Bash script, to create a SteamCMD script containing all the MODs present on the Steam WorkShop site about a game.
The script can be found here: https://dev.pyra-handheld.com/PowerGod/various-game-tools/-/blob/master/get_steamworkshop_links.sh

There was also an old Thread about it, at the beginning it was also able to download directly the MODs thanks to an external site, but when it was closed I repurposed the script to generate SteamCMD scripts too.

It will generate a file "mod-steamcmd.txt" with something like this inside (but could contain hundreds of entries):
Code:
login anonymous
workshop_download_item 1202130 2930229745
workshop_download_item 1202130 2930230098
quit


About the second issue, the Steam Archive format, I made a PowerShell script to:
  1. launch SteamCMD with the script you choose (like the one in the previous example), to download/update all the MODs of a game
  2. massively create junction links of all the MODs, into the game folder, naming every link with the MOD title (instead of the SteamID)
This solves three issues:
  1. you don't have to physically copy folders from the SteamCMD repository to the game directory
  2. SteamCMD will be always able to massively update all the MODs
  3. while inside a game, browsing for the MOD to use, you will see folders with understandable names
More info are inside the script.

Code:
# ---------------------------------------------
$ScrName = "STEAM WORKSHOP MOD DOWNLOADER TOOL"
# ---------------------------------------------
$ScrVer  = "v1.0a - PowerGod (2023)"
# ---------------------------------------------
#
# This is a PowerShell script.
#
# This will launch a script from SteamCMD to download MODs,
# then creates junction links to the MOD folders into the game directory.
#
# What are "junction links" also called "symlink" ?
# These are links that from the game point of view are actual directories,
# but instead all the files are still in the SteamCMD local repository.
# The advantage is that all the MODs can still be maintained via SteamCMD,
# because it is also able to just update them, without the issue of copying
# around files from SteamCMD repository and the game folder.
#
# The link naming rules are these:
# 1) All the links will be named using the MOD title found in the "text_*.csv" files,
#    but only a restricted set of common characters will be kept, all the others
#    will be substituted with an undescore
# 2) If a MOD has no title, the link will be called with the original MOD ID
# 3) If there are MODs with the same name, a number will be added to the link.
# 4) If a MOD contains more then one title, for different languages, different
#    links will be created, all pointing to the same folder
#
# === WARNING ===
# Before launching (or re-launching) this script, it is recommended to delete
# previous links from the destination game folder, else will be created a lot
# of duplicates.
#
#
# At the beginning I tried to obtain this with a CMD Batch script, but
# dealing with special characters or unknown character codes to make a workable
# link turned out almost impossible... PowerShell instead did the job.
#
#
# TODO:
#
# -- Give option to add MOD ID to the link name, or force always it
# -- Better output
# -- Check if a junction with the same name already points to the same location ?!
# -- Give a preferred language choice list for the title ?!
#    Using the only one present if there's no other choice ?!
#    The preferred language could also have no title at all, but other laguages yes...
# -- Add error checks
#

# -----------------
# Setting VARIABLES
# -----------------
#
# Game Title
$SteamGameName      = "STARSHIP TROOPERS: TERRAN COMMAND"

# SteamID of the Game
$SteamGameID        = "1202130"

# SteamCMD executable path (full path to launch "steamcmd.exe")
$StmCMDExePath      = "$($env:userprofile)\Desktop\SteamCMD\steamcmd\steamcmd.exe"

# SteamCMD script to download the MODs
$ScriptFileGameName = "$($env:userprofile)\Desktop\SteamCMD\StarshipTroopersMODS_Script.txt"

# SteamCMD archive base path
# - The same folder of "force_install_dir" if this option is used in the script
# - The directory where "steamcmd.exe" is, if no destination folder was specified
$StmCMDBasePath     = "$($env:userprofile)\Desktop\SteamCMD\steamcmd"

# Game folder where to put the MODs
$GameMODPath        = "$($env:userprofile)\Documents\My Games\Starship Troopers\Scenarios"
# -----------------



# ------------------------------------
# DO NOT CHANGE VALUES AFTER THIS LINE
# ------------------------------------

# SteamCMD repository path
$StmCMDWrkShPath    = "$StmCMDBasePath\steamapps\workshop\content"
# Strings to get the titles
$ScenarioSTR        = "^scenario_name,"
$TxtCsvName         = "text_*.csv"

# Strings used during rename of links with the same name (type of quotes are IMPORTANT !!)
# Example: "link_name (1)"

# Begin
$StrDupBef          = " ("
# Format of the Counter
# Example: '0000' to have always 4 digits - "link_name (0001)"
$StrDupNum          = '0'
# After
$StrDupAft          = ")"
# ------------------------------------

Clear-Host

Write-Host "`n`r`n`r$(''.PadLeft($($ScrName).Length,'-'))";
Write-Host "$ScrName`n`r$ScrVer";
Write-Host "$(''.PadLeft($($ScrName).Length,'-'))";

Write-Host "`n`r`n`rStarting connection to Steam Workshop for:`n`r`n`r$SteamGameName`n`r`n`r";

# Running SteamCMD with the download script
& $StmCMDExePath +runscript $ScriptFileGameName

Write-Host "`n`r`n`rPress a Key to create links, or press CTRL+C to stop the process.`n`r`n`r";
pause

Write-Host "`n`r`n`rCreating junctions to the main game MOD folder...`n`r`n`r";

foreach ($dir in (Get-ChildItem -Path "$StmCMDWrkShPath\$SteamGameID" -Attributes Directory)) {
    foreach ($textcsv in (Get-ChildItem -Path "$($dir.FullName.ToString())\$TxtCsvName")) {
        # Cleaning link from special characters
        $LnkName = ((Select-String -Pattern "$ScenarioSTR" -Path "$textcsv" | select -ExpandProperty Line) -replace $ScenarioSTR,'' -replace '[^A-Za-z0-9()\[\] ]','_');
        $LnkName = $LnkName.Trim();
        # Using MOD ID if there is no name
        $LnkName = $(if (!$LnkName.Equals('')) {$LnkName} else {$($textcsv.Directory.Name)});
        # If a link already exists, a counter will be added to the name;
        $CntDir = 0;
        $LnkNew = $LnkName;
        # Write-Host $LnkNew
        # Test-Path -LiteralPath "$GameMODPath\$LnkNew"
        if (Test-Path -LiteralPath "$GameMODPath\$LnkNew") {
            do {
                $CntDir = $CntDir + 1;
                $LnkNew = "$($LnkName)$($StrDupBef)$(($CntDir).ToString($StrDupNum))$($StrDupAft)";
            } while (Test-Path -LiteralPath "$GameMODPath\$LnkNew");
        };
        # Write-Host "mklink /j ""$GameMODPath\$LnkNew"" ""$($textcsv.Directory)""";
        cmd /c mklink /j "$GameMODPath\$LnkNew" "$($textcsv.Directory)"
    };
};

Write-Host "`n`r`n`r...THE END...`n`r`n`r";
pause

This is a comparison between the SteamCMD folder structure (left) and the respective junction links (right) created in the game folder (this was a run with hundreds of MODs !!! :cool:)
1691705211145.png
 
Last edited:
Back
Top