Automate All The Things: ETS2 Mods on a secondary drive

How to use Powershell to keep your ETS2 & ATS mods on a secondary drive.

3 min read
Automate All The Things: ETS2 Mods on a secondary drive
Photo by Gabriel Santos / Unsplash

On my gaming rig, I have a small SSD as the boot drive. As such, I have a separate larger SSD drive that I have installed all of my games on.

However, the games Euro Truck Simulator 2 & American Truck Simulator are set up to require external mods not installed through Steam Marketplace to be installed in the user profile Documents folder. Fortunately, the game does understand Symbolic Links, so we can place the files on the secondary drive with all other game files.

As the external mods often come in multiple files due to size limits, I often have to update multiple files at once, placing the new ones and removing the old ones. So I created a script that would automate the creation and removal of the symlinks so that the game has the latest mod files. The below is only for ETS2, as that is the game that I play the most often, and I currently don't have any external mods for ATS, but it is easy enough to duplicate for the ATS folder and changing the folder names.

$ModList = (Get-ChildItem -Path F:\ModsFiles\ETS2 -File).Name
$InstalledMods = (Get-ChildItem -Path "$env:USERPROFILE\Documents\Euro Truck Simulator 2\mod").Name
foreach($mod in $ModList){
    if($InstalledMods -contains $mod){
        #$mod
    }
    else{
        "$mod not found, creating symlink"
        New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\Documents\Euro Truck Simulator 2\mod" -Name $mod -Value "F:\ModsFiles\ETS2\$mod"
    }
}
foreach($mod in $InstalledMods){
    if($ModList -contains $mod){
        #$mod
    }
    else{
        "$mod not found in File Store, removing symlink"
        Remove-Item "$env:USERPROFILE\Documents\Euro Truck Simulator 2\mod\$mod"
    }
}

As I often participate in a Convoy with other members of a Virtual Trucking Company, the person who runs it hosts local mod files in Google Drive and shares the link out.

In the spirit of scripting everything, the below can be added to the top of the script to download the file. It will prompt for the Google File ID which is found within the sharing link (drive.google.com/file/d/{the required string found here}/view?usp=sharing). Thanks to this gist for pointing me down the right track, but Google have changed the way they link large files since then, so it is a bit more complicated now, trying to find the actual data.  The file is also 7-zip compressed, and there is a handy powershell module for extracting it.

#requires -modules 7zip4powershell -runasadministrator
param(
    [parameter(position=0,mandatory=$true)][string]$GoogleFileID
)
# set protocol to tls version 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Download the Warning into _tmp.txt
Invoke-WebRequest -Uri "https://drive.google.com/uc?export=download&id=$GoogleFileId" -OutFile "_tmp.txt" -SessionVariable googleDriveSession
$searchString = Select-String -Path "_tmp.txt" -Pattern "action="
#Look for the URL
$searchString  -match "https:\/\/drive.google.com/[a-z0-9?&;=-]*"
#Grab the file name, which is in a <a> tag, so easy to pull
$FileName = $(Invoke-WebRequest -Uri "https://drive.google.com/uc?export=download&id=$GoogleFileId").links.innertext
$FileDestination = "F:\Temp\$FileName"
# Delete _tmp.txt
Remove-Item "_tmp.txt"
# Only download if file has an updated file name or doesnt exist on disk
if(!$(Get-Item -Path $FileDestination)){
    # It apparently prompts twice...
    if($($searchString -match "confirm=(?<content>.*)&amp;id=") -eq $true){
        $confirmCode = $matches['content']
        Invoke-WebRequest -Uri "https://drive.google.com/uc?export=download&confirm=$confirmCode&id=$GoogleFileId" -OutFile "_tmp.txt" -WebSession $googleDriveSession
        $searchString = Select-String -Path "_tmp.txt" -Pattern "action="
        #Look for the URL
        $searchString  -match "https:\/\/[a-z0-9?&;=-]*.googleusercontent.com/[a-z0-9\/\*?&;=_-]*"
        # Delete _tmp.txt
        Remove-Item "_tmp.txt"
        #Now the actual file...
        Invoke-WebRequest -Uri $Matches[0] -OutFile $FileDestination -WebSession $googleDriveSession
    }
    Elseif($($searchString -match "confirm=(?<content>.*)&amp;uuid=") -eq $true){
        $confirmCode = $matches['content']
        Invoke-WebRequest -Uri "https://drive.google.com/uc?export=download&confirm=$confirmCode&id=$GoogleFileId" -OutFile "_tmp.txt" -WebSession $googleDriveSession
        $searchString = Select-String -Path "_tmp.txt" -Pattern "action="
        #Look for the URL
        $searchString  -match "https:\/\/[a-z0-9?&;=-]*.googleusercontent.com/[a-z0-9\/\*?&;=_-]*"
        # Delete _tmp.txt
        Remove-Item "_tmp.txt"
        #Now the actual file...
        Invoke-WebRequest -Uri $Matches[0] -OutFile $FileDestination -WebSession $googleDriveSession
    }
    Else{"Error getting download link`r`nOutput is:`r`n$searchString"}
}
if($(Get-Item -Path $FileDestination -ErrorAction SilentlyContinue)){
    #Extract the 7z - it will overwrite files that exist
    Expand-7Zip -ArchiveFileName $FileDestination -TargetPath "F:\ModsFiles\ETS2\MMT"
}

Edit: I have since found that for the symlink part, you can just use a launch flag of -homedir "F:\Games\ATS" after copying the files within Documents here. But for my setup, where the F: drive is an external SSD, I'll keep doing it this way, if I unplug the disk I only lose local mods.

Edit 2: Apparently Google have changed their link structure... plus they used an underscore this time which was not in the original regex. Code updated to take care of that.

Me on Mastodon - This link is here for verification purposes.