Skip to content

Instantly share code, notes, and snippets.

@BananaAcid
Last active April 13, 2024 23:23
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BananaAcid/1dc9117571967b26ceabc972009137ae to your computer and use it in GitHub Desktop.
Save BananaAcid/1dc9117571967b26ceabc972009137ae to your computer and use it in GitHub Desktop.
Install PowerShellGSM from commandline without git, and setup basics by prompts (with default options)

PowerShellGSM installation script

Usage

Copy and paste the below one-liner into your powershell console (WIN+R, then "powershell.exe")

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://gist.githubusercontent.com/bananaacid/1dc9117571967b26ceabc972009137ae/raw/install_PowerShellGSM.ps1'))

What it does

It is supposed to lead through the basic download and prep steps (of PowerShellGSM by patrix87)

  1. This does run the install_PowerShellGSM.ps1 script below
  2. Downloads (and asks to update) the PowerShellGSM powershell script files *1
  3. Asks a few basic questions to configure the PowerShellGSM installation:
    • like where to save the server
    • what server template to use
    • what to change the passwords in the created config of the selected server template to
    • if you want to open the configuration file to be able to edit

*1 (preserves your server configs by design)

*You may skip any step in the process, to prepare a new server, a second, ... *

What it doesn't

This is not meant to configure the servers individually, nor to provide any UI to PowerShellGSM.

That means: you still have to run the C:\server\games\PowerShellGSM\launchers\yourgameserver.cmd after PowerShellGSM is installed to start installing the newly configured game server, and to launch it.

Any other configuration is as per documentation from the PowerShellGSM.

Note

Powershell 7 (pwsh.exe) has some graphical glitches after the download. To fix: download and extract, then CTRL+C, start again, and choose 'no' to not download and extract again. Powershell 5 (powershell.exe) works fine.

<#
BananaAcid 2022-2024
License MIT
v1.0.3
To run this file and get PowerShellGSM installed, paste the following into your powershell:
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://gist.githubusercontent.com/bananaacid/1dc9117571967b26ceabc972009137ae/raw/install_PowerShellGSM.ps1'))
Changes:
- 16.02.2024 fix for PalWorld config: parsed the replacement block (Sart-ServerProp) as well
#>
Function Main() {
## Source file: https://github.com/patrix87/PowerShellGSM/archive/refs/tags/2.9.zip --> folder inside: PowerShellGSM-2.9.zip:.\PowerShellGSM-2.9\*.*
## -> what a horrible naming party / dynamic every time.
# $tag = "latest"
# $file = "random_name.zip"
# $url = "https://github.com/patrix87/PowerShellGSM/releases/download/$tag/$file"
$url = "https://github.com/patrix87/PowerShellGSM/archive/refs/heads/main.zip"
$tmpFile = "$env:TEMP\PowerShellGSM.main.zip";
# ---> Extracted filepath will always be PowerShellGSM-main !
$lastState = Get-Content ~\.PowerShellGSM -erroraction 'silentlycontinue' | ConvertFrom-Json -erroraction 'silentlycontinue'
if ( -not $? ) {
$lastState = [pscustomobject]@{
exPath = ""
}
}
else {
echo "Installation found in: $($lastState.exPath)"
}
## DOWNLOAD
if (Test-Path $tmpFile) {
$r = Read-Host "Download fresh PowerShellGSM files (Y/n)"
if ($r -ne "" -and $r -ne "y" -and $r -ne "Y") {
$noDl = $True
}
}
if ($noDl -ne $True) {
echo "downloading $url"
Invoke-WebRequest $url -OutFile $tmpFile
## EXTRACT
if ($lastState.exPath -ne "") { $def = "to " + $lastState.exPath } else { $def = "here" }
$r = Read-Host "Extract installation file $def (Y/n)"
if ($r -eq "" -or $r -eq "y" -or $r -eq "Y") {
if ($lastState.exPath -ne "") { $r = $lastState.exPath } else { $r = pwd }
}
else {
$r = Read-Host "Installation path"
}
$exPath = $r
echo "Installation path used: $exPath"
Expand-Archive $tmpFile $env:TEMP -Force
ni $exPath -ItemType Directory -Force >$null
cp $env:TEMP\PowerShellGSM-main\* $exPath\ -Force -R
rm $env:TEMP\PowerShellGSM-main -R -Force
}
else {
if ($lastState.exPath -ne "") { $def = $lastState.exPath } else { $def = "here" }
$r = Read-Host "Enter path to previous installation (default: $def)"
if ($r -eq "") {
if ($lastState.exPath -ne "") { $r = $lastState.exPath } else { $r = pwd }
}
$exPath = $r
}
## ACTIVATE TEMPLATE
echo "Select a server template to add:"
$Options = ls $exPath\templates |? {$_.Name -notlike '#*'} |% BaseName
$Selection = Create-Menu -MenuOptions $Options -Columns "auto" -MaximumColumnWidth 20 -ShowCurrentSelection $True
$tmplFile = $Options[$Selection]
$cfgFile = "$tmplFile.psm1"
if (Test-Path $exPath\configs\$cfgFile) {
$r = Read-Host "Overwrite the config file for the selected server with new and blank one (backup will be created) (y/N)"
if ($r -eq "" -or $r -eq "n" -or $r -eq "N") {
$ignoreReplace = $True
}
else {
# just to make sure ...
$timestamp = Get-Date -format "yyyy-MM-dd_HH-mm-ss"
cp $exPath\configs\$cfgFile $exPath\configs\$cfgFile.backup.$timestamp -Force
cp $exPath\launchers\$tmplFile.cmd $exPath\launchers\$tmplFile.cmd.backup.$timestamp
}
}
if ($ignoreReplace -ne $True) {
cp $exPath\templates\$cfgFile $exPath\configs -Force
cp $exPath\launchers\run.cmd $exPath\launchers\$tmplFile.cmd -Force
}
echo "To run the selected server for $tmplFile, run $exPath\launchers\$tmplFile.cmd"
## change passwords
$r = Read-Host "Change all passwords in the new config (Y/n)"
if ($r -eq "" -or $r -eq "y" -or $r -eq "Y") {
# get content
$inputFile = gc $exPath\configs\$cfgFile -Raw
# find description, key, value (password)
$results = [Regex]::Matches($inputFile, "^[\s]+(?<desc>#.*)*\n^[\s]+(?<line>(?<key>[^#'\s]*Password[^=\s]*)[\s]*=[\s]*""(?<val>[^""]*)"")", "IgnoreCase,Multiline")
$newFile = $inputFile
For ($i = 0; $i -lt $results.count; $i++) {
# ask for new password and show comment + old value
Write-Host "$($results[$i].Groups['desc'].Value) -- currently: '$($results[$i].Groups['val'].Value)'" -ForegroundColor DarkGray
$val = Read-Host "New password for '$($results[$i].Groups['key'].Value)' (empty for random)"
if ($val -eq "") {
$val = ((-join (((48..57)+(65..90)+(97..122)) * 80 |Get-Random -Count 8 |%{[char]$_})) -replace '0|O|o|I|l|1|5|S|s','A').ToLower() # if not toLower, add: |Y|y|V|v|K|k|W|w|P|p|C|c|X|x
Write-Host "... random: $val"
}
# replace old value in line
$a = '"' + $results[$i].Groups["val"].Value + '"'
$b = '"' + $val + '"'
$x = $results[$i].Groups["line"].Value -replace $a,$b
# replace old row
$newFile = $newFile -replace $results[$i].Groups["line"].Value,$x
}
Write-Host ""
# write new content
$newFile | Out-File $exPath\configs\$cfgFile
}
## SHOW CONFIG
$r = Read-Host "Show config file to be edited manually (Y/n)"
if ($r -eq "" -or $r -eq "y" -or $r -eq "Y") {
notepad $exPath\configs\$cfgFile
explorer /select,"$exPath\configs\$cfgFile"
}
## REMEMBER
$lastState.exPath = Convert-Path $exPath
ConvertTo-Json $lastState | Out-File ~\.PowerShellGSM
}
## MODULES
# https://community.spiceworks.com/scripts/show/4785-create-menu-2-0-arrow-key-driven-powershell-menu-for-scripts
# Modified by BananaAcid
Function Create-Menu (){
#Start-Transcript "C:\_RRC\MenuLog.txt"
Param(
[Parameter(Mandatory=$True)][array]$MenuOptions,
[Parameter(Mandatory=$True)][String]$Columns = "Auto",
[Parameter(Mandatory=$False)][int]$MaximumColumnWidth=20,
[Parameter(Mandatory=$False)][bool]$ShowCurrentSelection=$False
)
$consoleTop = $False;
$MaxValue = $MenuOptions.count-1
$Selection = 0
$EnterPressed = $False
If ($Columns -eq "Auto"){
$WindowWidth = (Get-Host).UI.RawUI.MaxWindowSize.Width
$Columns = [Math]::Floor($WindowWidth/($MaximumColumnWidth+2))
}
If ([int]$Columns -gt $MenuOptions.count){
$Columns = $MenuOptions.count
}
$RowQty = ([Math]::Ceiling(($MaxValue+1)/$Columns))
Function ClearHost () {
if ($consoleTop -eq $False) {
$consoleTop = [Console]::CursorTop - $RowQty
}
[Console]::SetCursorPosition(0, $consoleTop)
}
$MenuListing = @()
For($i=0; $i -lt $Columns; $i++){
$ScratchArray = @()
For($j=($RowQty*$i); $j -lt ($RowQty*($i+1)); $j++){
$ScratchArray += $MenuOptions[$j]
}
$ColWidth = ($ScratchArray |Measure-Object -Maximum -Property length).Maximum
If ($ColWidth -gt $MaximumColumnWidth){
$ColWidth = $MaximumColumnWidth-1
}
For($j=0; $j -lt $ScratchArray.count; $j++){
If(($ScratchArray[$j]).length -gt $($MaximumColumnWidth -2)){
$ScratchArray[$j] = $($ScratchArray[$j]).Substring(0,$($MaximumColumnWidth-4))
$ScratchArray[$j] = "$($ScratchArray[$j])..."
} Else {
For ($k=$ScratchArray[$j].length; $k -lt $ColWidth; $k++){
$ScratchArray[$j] = "$($ScratchArray[$j]) "
}
}
$ScratchArray[$j] = " $($ScratchArray[$j]) "
}
$MenuListing += $ScratchArray
}
While($EnterPressed -eq $False){
If ($ShowCurrentSelection -eq $True){
$Host.UI.RawUI.WindowTitle = "CURRENT SELECTION: $($MenuOptions[$Selection])"
}
For ($i=0; $i -lt $RowQty; $i++){
For($j=0; $j -le (($Columns-1)*$RowQty);$j+=$RowQty){
If($j -eq (($Columns-1)*$RowQty)){
If(($i+$j) -eq $Selection){
Write-Host -BackgroundColor cyan -ForegroundColor Black "$($MenuListing[$i+$j])"
} Else {
Write-Host "$($MenuListing[$i+$j])"
}
} Else {
If(($i+$j) -eq $Selection){
Write-Host -BackgroundColor Cyan -ForegroundColor Black "$($MenuListing[$i+$j])" -NoNewline
} Else {
Write-Host "$($MenuListing[$i+$j])" -NoNewline
}
}
}
}
#Uncomment the below line if you need to do live debugging of the current index selection. It will put it in green below the selection listing.
#Write-Host -ForegroundColor Green "$Selection"
$KeyInput = $host.ui.rawui.readkey("NoEcho,IncludeKeyDown").virtualkeycode
Switch($KeyInput){
13{
$EnterPressed = $True
Return $Selection
ClearHost
break
}
37{ #Left
If ($Selection -ge $RowQty){
$Selection -= $RowQty
} Else {
$Selection += ($Columns-1)*$RowQty
}
ClearHost
break
}
38{ #Up
If ((($Selection+$RowQty)%$RowQty) -eq 0){
$Selection += $RowQty - 1
} Else {
$Selection -= 1
}
ClearHost
break
}
39{ #Right
If ([Math]::Ceiling($Selection/$RowQty) -eq $Columns -or ($Selection/$RowQty)+1 -eq $Columns){
$Selection -= ($Columns-1)*$RowQty
} Else {
$Selection += $RowQty
}
ClearHost
break
}
40{ #Down
If ((($Selection+1)%$RowQty) -eq 0 -or $Selection -eq $MaxValue){
$Selection = ([Math]::Floor(($Selection)/$RowQty))*$RowQty
} Else {
$Selection += 1
}
ClearHost
break
}
Default{
ClearHost
}
}
}
}
Main
@KngJn
Copy link

KngJn commented Aug 3, 2023

throws a bunch of errors on my side and leaves me with a blank .ps1

@BananaAcid
Copy link
Author

throws a bunch of errors on my side and leaves me with a blank .ps1

In case you get read/write/access/permission errors, create a folder like c:\server-games and run the installation command within that directory.

@spydey20
Copy link

spydey20 commented Apr 13, 2024

Any chance this could support server clustering in Ark Ascended?

Thank you for this by the way! Works great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment