The perfect Minecraft server launch script



The author is very fond of the game, and he himself is the administrator of a small server "purely for friends." As usual among amateurs, everything is modulated on the server, and this entails the instability of work and as a result of the fall. Since the author knows Powershell better than the location of stores on his street, he decided to make "The Best Minecraft 2020 Launch Script ." The same script served as the basis for the template in the Ruvds marketplace . But all the sources are already in the article. Now, in order, how it all happened.

We need teams


Alternative logging


Having once put a couple more mods, I found that the server seems to crash without declaring war. The server did not write errors in latest.log or debug, and the console, which was supposed to write and stop this error, was closed.

Does not want to write - no need. We have Powershell with the Tee-Object cmdlet , which takes an object and displays it in a file and in the console at the same time.

.\handler.ps1 | Tee-Object .\StandardOutput.txt -Append

In this way, Powershell will pick up StandardOutput and write it to a file. Do not try to use Start-Process , because it will return System.ComponentModel.Component, not StandardOutput, and -RedirectStandardOutput will make it impossible to enter the console, which we want to avoid.

Launch Arguments


Putting the same pair of mods, the author noticed that the server also lacks RAM. And this needs to change the startup arguments. Instead of changing them every time in start.bat, which everyone uses, just use this script.

Since Tee-Object reads StandardOutput only when the executable is called “Right So”, you will have to make another script. This script will run minecraft itself. Let's start with the arguments.

In order to indulge in ultimate laziness in the future, the script must collect start arguments on the fly. To do this, start by looking for the latest version of forge .

$forge = ((Get-ChildItem | Where-Object Name -Like "forge*").Name | Sort-Object -Descending) | Select-Object -last 1

With the help of sort-object, we will always take the object with the largest digit, no matter how much you put them there. The ultimate laziness.

Now you need to assign memory to the server. To do this, take the amount of system memory and write its amount in string.

$ram = ((Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb)
$xmx = "-Xms" + $ram + "G"

Correct auto restart


The author saw .bat files from other people, but they did not take into account the reason the server was stopped. Is it inconvenient that if you just need to change the mod file or delete something?
Now let's do the right restart. The author previously came across strange scripts that restarted the server despite the fact that the server shut down. We will use exitcode. Java uses 0 as a successful completion, hence we will dance.

First, create a function that will restart the server if it fails to complete.

function Get-MinecraftExitCode {
   
    do {
        
        if ($global:Process.ExitCode -ne 0) {
            Write-Log
            Restart-Minecraft
        }
        else {
            Write-Log
        }
 
    } until ($global:Process.ExitCode -eq 0)
    
}

The script will remain in the loop until the server from its own console shuts down normally using the / stop command.

If we all decided to automate, it would be nice to collect the launch date, completion, as well as the reason for the completion.

To do this, we write the Start-Process result to a variable. In the script, it looks like this:

$global:Process = Start-Process -FilePath  "C:\Program Files (x86)\common files\Oracle\Java\javapath_target_*\java.exe" -ArgumentList "$xmx -server -jar $forge nogui" -Wait -NoNewWindow -PassThru

And then we write the results to a file. Here is what returns to us in the variable:

$global:Process.StartTime
$global:Process.ExitCode	
$global:Process.ExitTime

All this using Add-Content can be added to the file. Having combed a little, we get such a script, and call it handler.ps1.

Add-Content -Value "Start time:" -Path $Logfile 
$global:Process.StartTime
 
Add-Content -Value "Exit code:" -Path $Logfile 
$global:Process.ExitCode | Add-Content $Logfile
    
Add-Content -Value "Exit time:" -Path $Logfile 
$global:Process.ExitTime | Add-Content $Logfile

Now let's execute the script with the launch of the handler.

Proper startup


The author wants one module to launch minecraft of various versions from any paths, and also be able to put logs in a specific folder.

The problem is that the process must be started by the user who is on the system. This can be done through the desktop or WinRm. If you start the server on behalf of the system or even the administrator, but do not log in, then Server.jar will not even be able to read eula.txt and start up.

We can enable auto-login to the system by adding three entries to the registry.

New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name DefaultUserName -Value $Username -ErrorAction SilentlyContinue
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name DefaultPassword -Value $Password  -ErrorAction SilentlyContinue
New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name AutoAdminLogon -Value 1 -ErrorAction SilentlyContinue

It's not safe. The login and password are indicated here in plaintext, so you need to start an individual user who has access at the user level, or in an even narrower group, to start the server. Using a standard administrator for this is strongly discouraged.

With auto input sorted out. Now you need to register a new task under the server. We will run the command from Powershell, so it will look like this:

$Trigger = New-ScheduledTaskTrigger -AtLogOn
$User = "ServerAdmin"
$PS = New-ScheduledTaskAction -Execute 'PowerShell.exe" -Argument "Start-Minecraft -Type Forge -LogFile "C:\minecraft\stdout.txt" -MinecraftPath "C:\minecraft\"'
Register-ScheduledTask -TaskName "StartSSMS" -Trigger $Trigger -User $User -Action $PS -RunLevel Highest

Putting the module together


Now let's make everything into modules that can be used later. All code of ready-made scripts is here, import and use.

You can use everything described above separately if you do not want to bother with modules.

Start-minecraft


First, we’ll make a module that will only do that, run a script that will listen and record standardoutput.

In the parameter block, he asks from which folder to launch minecraft and where to put the log.

Set-Location (Split-Path $MyInvocation.MyCommand.Path)
function Start-Minecraft {
    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]
        $LogFile,
 
        [Parameter(Mandatory)]  
        [ValidateSet('Vanilla', 'Forge')]
        [ValidateNotNullOrEmpty()]
        [string]
        $Type,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $MinecraftPath
 
    )
    powershell.exe -file .\handler.ps1 -type $type -MinecraftPath $MinecraftPath | Tee-Object $LogFile -Append
}
Export-ModuleMember -Function Start-Minecraft

And you will need to run minecraft like this:

Start-Minecraft -Type Forge -LogFile "C:\minecraft\stdout.txt" -MinecraftPath "C:\minecraft\"

Now let's move on to the ready-to-use Handler.ps1

So that our script can accept parameters when called, we also need to specify a parameter block. Please note that it starts Oracle Java, if you use a different distribution, you will need to change the path to the executable file.

param (
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$type,
 
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$MinecraftPath,
 
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string]$StandardOutput
)
 
Set-Location $MinecraftPath
 
function Restart-Minecraft {
 
    Write-host "=============== Starting godlike game server ============"
 
    $forge = ((Get-ChildItem | Where-Object Name -Like "forge*").Name | Sort-Object -Descending) | Select-Object -first 1
 
    $ram = ((Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb)
    $xmx = "-Xms" + $ram + "G"
    $global:Process = Start-Process -FilePath  "C:\Program Files (x86)\common files\Oracle\Java\javapath_target_*\java.exe" -ArgumentList "$xmx -server -jar $forge nogui" -Wait -NoNewWindow -PassThru
    
}
 
function Write-Log {
    Write-host "Start time:" $global:Process.StartTime
 
    Write-host "Exit code:" $global:Process.ExitCode
    
    Write-host "Exit time:" $global:Process.ExitTime
 
    Write-host "=============== Stopped godlike game server ============="
}
 
function Get-MinecraftExitCode {
   
    do {
        
        if ($global:Process.ExitCode -ne 0) {
            Restart-Minecraft
            Write-Log
        }
        else {
            Write-Log
        }
 
    } until ($global:Process.ExitCode -eq 0)
    
}
 
Get-MinecraftExitCode

Register-minecraft


The script practically repeats Start-Minecraft, except that it only registers a new task. Accepts the same arguments. The username, if not specified, takes the current one.

function Register-Minecraft {
    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]
        $LogFile,
 
        [Parameter(Mandatory)]  
        [ValidateSet('Vanilla', 'Forge')]
        [ValidateNotNullOrEmpty()]
        [string]$Type,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$MinecraftPath,
 
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$User,
 
        [Parameter(Mandatory)]
        [string]$TaskName = $env:USERNAME
    )
 
    $Trigger = New-ScheduledTaskTrigger -AtLogOn
    $arguments = "Start-Minecraft -Type $Type -LogFile $LogFile -MinecraftPath $MinecraftPath"
    $PS = New-ScheduledTaskAction -Execute "PowerShell" -Argument "-noexit -command $arguments"
    Register-ScheduledTask -TaskName $TaskName -Trigger $Trigger -User $User -Action $PS -RunLevel Highest
    
}
 
Export-ModuleMember -Function Register-Minecraft

Register-autologon


In the parameter block, the script accepts the Username and Password parameter. If Username was not specified, the name of the current user is used.

function Set-Autologon {
 
    param (
        [Parameter(
        HelpMessage="Username for autologon")]
        $Username = $env:USERNAME,
 
        [Parameter(Mandatory=$true,
        HelpMessage="User password")]
        [ValidateNotNullOrEmpty()]
        $Password
    )
 
    $i = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
 
    if ($null -eq $i) {
        New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name DefaultUserName -Value $Username
        New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name DefaultPassword -Value $Password 
        New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name AutoAdminLogon -Value 1
        Write-Verbose "Set-Autologon will enable user auto logon."
 
    }
    else {
        Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name DefaultUserName -Value $Username
        Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name DefaultPassword -Value $Password
        Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name AutoAdminLogon -Value 1
    }
 
    
    Write-Verbose "Autologon was set successfully."
 
}

Running this script looks like this:

Set-Autologon -Password "PlaintextPassword"

How to use


Now we will consider how the author himself uses all this. How to deploy Minecraft public server on Windows. Let's start from the very beginning.

1. Create a user

$pass = Get-Credential
New-LocalUser -Name "MinecraftServer" -Password $pass.Password -AccountNeverExpires -PasswordNeverExpires -UserMayNotChangePassword

2. Register the task of running the script.

You can register using the module, as follows:

Register-Minecraft -Type Forge -LogFile "C:\minecraft\stdout.txt" -MinecraftPath "C:\minecraft\" -User "MInecraftServer" -TaskName "MinecraftStarter"

Or use the standard tools:

$Trigger = New-ScheduledTaskTrigger -AtLogOn
$User = "ServerAdmin"
$PS = New-ScheduledTaskAction -Execute 'PowerShell.exe" -Argument "Start-Minecraft -Type Forge -LogFile "C:\minecraft\stdout.txt" -MinecraftPath "C:\minecraft\"'
Register-ScheduledTask -TaskName "StartSSMS" -Trigger $Trigger -User $User -Action $PS -RunLevel Highest

3. Turn on auto-login to the system and reboot the machine

Set-Autologon -Username "MinecraftServer" -Password "Qw3"

Completion


The author made the script, including for himself, therefore, he will be happy to hear your suggestions for improving the script. The author hopes that all this code was at least minimally useful for you, and the article is interesting.


All Articles