Automate Updating a Minecraft Server

Update minecraft with Powershell

In this article, I will go over the process of creating a Powershell script on a Linux Ubuntu server to automate updating my Bedrock Minecraft server. The reason for this is that I am not playing Minecraft that much myself, but I am hosting a server for some friends who are playing it a lot.

The problem with this is that usually there will be released a new update to Minecraft, and my friends will update their client. But because I am not playing my self I usually don’t catch that there has been released a new update. This of course will result in my friends not being able to play on the server before I get around to update it.

So that’s why I’ve decided to automate the entire process of, checking for new updates, backing up the server, updating the server, and even send out an email to let users know that the server has been updated.

Prerequisites

There are some prerequisites you need to have down before you can utilize the script I have developed. If you don’t know how to set or configure these prerequisites, please check out my Article: Powershell Script For Installing Minecraft Bedrock Edition

  1. Have an Ubuntu server with Minecraft Bedrock installed
  2. Have Powershell installed on the server
  3. Have Minecraft Server running as a systemctl service (I will walk through the process on how in this article as

Now there are two more things you will need to have done.

First, you will need to rename your server folder name to “bedrock-server”. When you download the server it will be named something like: bedrock-server-1.16.221.01.

The second thing you will need to create a text document inside the server folder containing the current version. This is because the script will look at this text file to compare if a new version is available online.

The last important thing is the folder structure.

I have inside my users home folder:

  • bedrock-server (The actual Minecraft Server Folder)
  • bin (The different script for running the process)
  • Downloads (A folder I’ve created myself, to place the newly downloaded version of the server)

Managing the Minecraft Server Service in Powershell

One of the prerequisites I mentioned was that you should have Minecraft Server setup as a systemctl service. The reason for this is that instead of having to run the command:

LD_LIBRARY_PATH=. ./bedrock_server

You can use the command:

sudo systemctl start Minecraft

This also gives you the ability to not having to use screen or tmux for running the server terminal in the background.

By running the service as a service it will also be much easier for making it startup automatically when the server reboots.

Now if you already have your Minecraft server setup as a systemctl service you can go ahead and skip the following step.

Now if you don’t know how to set up the server as a service I will walk through the process now.

Setting the Minecraft Server as a Service

To set the Minecraft Server to run as a service you will need to create a .service file and place it inside the folder /etc/systemd/system/

So the file will look like this:

[Unit]
Description=Minecraft Service
After=network.target

[Service]
User=USERNAME

Type=Simple

WorkingDirectory=/home/USERNAME/bedrock-server/
ExecStart=/bin/sh -c "./bedrock_server"
TimeoutStopSec=20
Restart=on-failure

[Install]
WantedBy=multi-user.target

Be sure to replace USERNAME with your username.

Now you want to save the file in the folder /etc/systemd/system/ and name it minecraft.service.

if you now run the command:

sudo systemctl daemon-reload

You should be able to start, restart, stop and enable your Minecraft server with the commands:

sudo systemctl start minecraft
sudo systemctl restart minecraft
sudo systemctl stop minecraft
sudo systemctl enable minecraft

And if you want to check the status of the server you can run the command:

sudo systemctl status minecraft

Now one thing I need to do is to allow the user running the server to run the commands for systemctl with Minecraft, for starting and stopping the server, without entering a sudo password.

Setting the Minecraft User in the Sudoers File

The Minecraft user running the Minecraft Server will need to be allowed to enter the systemctl commands for starting and stopping the server without a password since when the script is running it will need to stop and start the server without having to provide a password.

Now to accomplish this I will add the following line into the file /etc/sudoers:

USERNAME ALL = NOPASSWD: /bin/systemctl start minecraft
USERNAME ALL = NOPASSWD: /bin/systemctl stop minecraft

To edit the sudoers file you will need to run the command:

sudo visudo /etc/sudoers

Then just add the two lines to the bottom of the file and save it.

You should now be able to run the commands:

sudo systemctl start minecraft
sudo systemctl stop minecraft

without having to enter a password.

Running bash commands in a Powershell Script

To start and stop the service i will need to run the bash commands “sudo systemctl start minecraft” inside the powershell script. So to do this we can use the command:

bash -c "string command"

This command will take a string as a command and pass it to the bash terminal.

So an example command could be:

bash -c "sudo systemctl start minecraft"

Creating the Update Minecraft Server Powershell Script

So the update script will need to accomplish the following steps:

  • Check the current installed Minecraft Server Version
  • Check the available online version

If a new version is available online:

  • Backup the server
  • Remove the current version of the server
  • Download the new server
  • Copying configurations from the old version to the new version
  • Creating a new version.txt file (to show what the “new” current version of the server will be)
  • Compress the backed-up server
  • Write an email notification to let users know the server has been updated.

I will start by creating the file update-mc-server.ps1 and I will start by setting the parameter:

param(
        [String]$WorkingDirectory = "/home/USERNAME",
        [Switch]$SendMail
)

Be sure to replace USERNAME with the User who is running the Minecraft server.

The Parameter $WorkingDirectory is to set the folder where the bedrock-minecraft server folder is located.

And the parameter $SendMail is a switch parameter to specify whether an email notification should be sent out when a new version has been installed.

Comparing the current version with the online version available

First, I will need to check the current version installed. To make this easy I will just get the content of the file version.txt I explained in the prerequisites.

$local_version = Get-Content -Path "$WorkingDirectory/bedrock-server/version.txt"

Second, I will find the current version available online.

To do this I will utilize the Powershell command Invoke-WebRequest to scrape the site: https://www.minecraft.net/en-us/download/server/bedrock for new versions.

To do this I will run the following:

# Saving the HTTP Request of the website into the variable $request
$request = Invoke-Webrequest -Uri "https://www.minecraft.net/en-us/download/server/bedrock"

# Finding the exact link of the download button to find the name of the version available
$download_link = $request.Links | ? class -match "btn" | ? href -match "bin-linux/bedrock" | select -ExpandProperty href

# Formatting the download link to find the specific version of the downloadable file
$online_version = $download_link.split("/")[4].split("-")[2].replace(".zip", "")

So when running the Invoke-WebRequest I will receive the Website in a Powershell object.

I will then search the website for all Links ($request.Links) and match them where the class is equal to “btn”. This makes sure that I will find all buttons on the website.

I will then grab the actual link of the button and match the button where the link contains “bin-linux-bedrock” since I am updating Minecraft on a linux server. 

The last thing I will do is to split the link at all “/“ and select the 4th section of this split. I will then split that part at all the symbols “-“ and select the 2nd part. Then I will remove the “.zip” part from the string and I will be left with the exact version number.

The to compare the version i will run the following powershell:

if ($local_version -eq $online_version) {
        Write-Verbose -Message "Local version and Online version are identical. Exiting script"
        exit
}
else {
       “Do something else”
}

Backing up the Minecraft Server with powershell

To backup the Minecraft server I will just copy the server to a backup folder. Later in the script, I will then compress the folder to save space. You could modify the script to save the backup zip file to a network share, but I won’t go through this in this article.

Before I backup the server I will stop it by running the bash command:

bash -c "sudo systemctl stop minecraft"

Then I will run the following lines to backup the server to a backup folder:

if(!(Test-Path -path "$WorkingDirectory/backup")){
        Write-Verbose -Message "Didn't find the Minecraft backup folder. Creating it now"
        New-Item -Path "$WorkingDirectory/backup" -ItemType Directory
}
Write-Verbose -Message "Copying the current server into the backup folder"
$backup_folder = "$WorkingDirectory/backup/bedrock-server-$($local_version)"
Copy-Item -Path "$WorkingDirectory/bedrock-server" -Destination $backup_folder -recurse

These lines will check if you have a folder named backup. If not then create it, and then copy the current server to the backup folder.

I will then need to remove the current version so I can download the new version:

Remove-Item -Path "$WorkingDirectory/bedrock-server" -Recurse -Force

Downloading a new Minecraft Server Version with Powershell

Now I want to download the new version. To do this with Powershell I will use the command Invoke-WebRequest, and I can use the variable I created earlier: $download_link.

I will download the file into the folder I have created named: “Downloads/“

Invoke-WebRequest -Uri $download_link -OutFile "$WorkingDirectory/Downloads/bedrock-server.zip"

Now the new server file is download I will need to extract it into the $WorkingDirectory folder. (home/USERNAME/bedrock-server)

$new_destination = "$WorkingDirectory/bedrock-server
Expand-Archive -Path "$WorkingDirectory/Downloads/bedrock-server.zip" -DestinationPath $new_destination

Saving the old configurations to the new server

Now because updating the server more or less is the same process as just installing a new server, I will need to copy some files from the old server into the new server. 

The files I will copy is:

  • worlds/
  • permissions.json
  • server.properties
  • whitelist.json
  • resource_packs/

The powershell for this:

Write-Verbose -Message "Copying world files into new server"
Copy-Item "$backup_folder/worlds" -Destination $new_destination -Recurse -Force
Write-Verbose -Message "Copying permissions file into new server"
Copy-Item "$backup_folder/permissions.json" -Destination $new_destination -Force
Write-Verbose -Message "Copying server properties file into new server"
Copy-Item "$backup_folder/server.properties" -Destination $new_destination -Force
Write-Verbose -Message "Copying whitelist file into new server"
Copy-Item "$backup_folder/whitelist.json" -Destination $new_destination -Force
Write-Verbose -Message "Copying Resource Packs"
Copy-Item "$backup_folder/resource_packs" -Destination $new_destination -Recurse -Force

And the last thing here is to create a new version.txt file inside the new server folder.

to do this run the following:

$version_file = "$new_destination/version.txt"
New-Item $version_file -ItemType File -Force
Add-Content -Path $version_file -Value "$($online_version)" -NoNewline

Setting the Minecraft to be Executable

So now the new server has been download I will need to make the server file bedrock_server to be executable. Otherwise, the systemctl service won’t be able to start the server.

To do this i will use the bash command “find” for locating the file and setting the correct permission on the file for my Linux User running the Minecraft Server.

The bash command inside the powershell script will look like:

bash -c "find /home/$Username/bedrock-server/ -name bedrock_server -type f -exec chmod 0755 {} \;"

Finishing up the script

The last couple of things I need to do is: Compressing the server backup. Removing the uncompressed backup, Remove the downloaded server zip, and starting the server again.

First, I will compress the backed-up server files

Compress-Archive -Path $backup_folder -DestinationPath "$($backup_folder).zip"

Then to remove the uncompressed backup folder

if(Test-Path "$($backup_folder).zip"){
    Remove-Item -Path $backup_folder -Recurse -Force
}

Now to remove the downloaded zip file

if(Test-Path "home/USERNAME/Downloads/bedrock-server.zip"){
    Remove-Item -Path "home/USERNAME/Downloads/bedrock-server.xip" -Force
}

And at last start the newly updated Minecraft Server

bash "/home/USERNAME/bin/start-minecraft.sh"

Setting up email notification

Now I chose to set up email notifications to let my users know that the server has been updated. To do this step you will need an email account and server information for this email account.

I will use the Powershell command:

Send-MailMessage

In the beginning, I set the switch parameter $SendMail. I will use this switch parameter to define whether the script should send a mail or not. I think this approach is a good idea for whenever I am using a mail or notification, which is sent to users. Because if I want to run the script but not let users know, I can just call the script without calling the switch parameter.

The Powershell:

if($SendMail.IsPresent) {
    $From = "email@domain.com" # the email address you are sending out from
    $Password = ConvertTo-SecureString “password” -AsPlainText -Force # Password for the email account
    $Creds = New-Object System.Management.Automation.PSCredential ($From, $Password)
    $To = "user1@domain.com", "user2@domain.com" # List of user you are sending to
    $Subject = "Minecraft Server Update!" # Email subject
    $Body = "Minecraft Server was updated to version: $($online_version)" # email body
    $SMTPServer = "send.smtp.com” # Smtp server for your email account
    
    # Sending the email
    Send-MailMessage -From $From -To $To -Credential $Creds -Subject $Subject -Body $Body -SmtpServer $SMTPServer -UseSsl -Port 587
}

Creating a Log File

Because this script is meant to just run, without me having to take action for the server to update, it will be nice to have a logging function, so that I can look back and check what happened on a certain date.

The way I prefer to handle logging in my script is to write out: output, verbose, warning, and error messages. Then I will set the output preferences to make the Powershell session output the information and use Start-Transcript to store everything that happens in the Powershell session in a file.

At the beginning of the script I have put in the following lines:

$Now = get-date
$LogFile = "home/USERNAME/logs/" + $Now.ToString("yyyy-MM-dd") + "-minecraf_update.log" # Defining Log name and path
Start-Transcript -Path $LogFile -Force # Starting the LOG
$DebugPreference = 'Continue'
$InformationPreference = 'SilentlyContinue'
$WarningPreference = 'Continue'
$VerbosePreference = 'Continue'

and at the very end of the script I will enter the following command:

Stop-Transcript

This functionality will save the output of the script to a file the folder home/USERNAME/logs.

Scheduling the Powershell Script on a Linux Server

To schedule the script on a Linux Server I will use Cron. Cron is the default task scheduler on Linux and is fairly easy to use.

So to enter the cron job run the following:

crontab -e

I want my job to run every night at 2 am. So to do this I have entered the following line at the bottom of the file.

# m h  dom mon dow   command
   0 2  *   *   *     pwsh /home/USERNAME/bin/update-mc-server.ps1

Now you can set the script to run at a much more aggressive interval, but I will leave this up to you.

Now once you’ve entered the cron job there is not anything to do other than lay back and be happy that your Minecraft server now always will be up to date.

The Finished Script

<#
	.SYNOPSIS
		Script for automating Minecraft Bedrock Server Updating
    .DESCRIPTION
        Script which will automatically retrieve the newest version of Bedrock Minecraft.
		Then download it and install the newest version. The script will also send out
		an email notification that the server has been updated.

	.NOTES
		You will need to input the following information for the variables
		in the EMAIL SECTION at the end of the script.

		$From,
		$Password,
		$To,
		$SMTPServer
#>

param(
	[String]$Username, # usernname of the linux user running the script
    [String]$WorkingDirectory = "/home/$Username",
    [Switch]$SendMail
)

# Setting Log Information 
$LogFile = "home/$Username/logs/" + $Now.ToString("yyyy-MM-dd") + "-minecraf_update.log" # Defining Log name and path
Start-Transcript -Path $LogFile -Force # Starting the LOG
$DebugPreference = 'Continue'
$InformationPreference = 'SilentlyContinue'
$WarningPreference = 'Continue'
$VerbosePreference = 'Continue'


# Checking for available Updates
Write-Verbose -Message "Checking for current version installed"
$local_version = Get-Content -Path "$WorkingDirectory/bedrock-server/version.txt"

Write-Verbose -Message "Checking for availabe version online"
$request = Invoke-Webrequest -Uri "https://www.minecraft.net/en-us/download/server/bedrock"

$download_link = $request.Links | ? class -match "btn" | ? href -match "bin-linux/bedrock" | select -ExpandProperty href

$online_version = $download_link.split("/")[4].split("-")[2].replace(".zip", "")
Write-Verbose -Message "Online version found: $($online_version)"

# If version is different the update the server
if ($local_version -eq $online_version) {
	Write-Verbose -Message "Local version and Online version are identical. Exiting script"
	exit
}
else {
    # Stopping the Minecraft server
	Write-Verbose -Message "There are difference in Online and Local versions"
	Write-Verbose -Message "Stopping the Minecraft service"
	bash -c "sudo systemctl stop minecraft"

	start-sleep -s 2

    # Backup the Minecraft server
	Write-Verbose -Message "Initiating server backup"
	if(!(Test-Path -path "$WorkingDirectory/backup")){
		Write-Verbose -Message "Didn't find the Minecraft backup folder. Creating it now"
		New-Item -Path "$WorkingDirectory/backup" -ItemType Directory
	}
	Write-Verbose -Message "Copying the current server into the backup folder"
	$backup_folder = "$WorkingDirectory/backup/bedrock-server-$($local_version)"
	Copy-Item -Path "$WorkingDirectory/bedrock-server" -Destination $backup_folder -recurse

    Start-Sleep -s 5

    # Removing old server files from $WorkingDirectory
    Write-Warning -Message "Removing the current version of the server!"
    Remove-Item -Path "$WorkingDirectory/bedrock-server" -Recurse -Force

    
    # Downloading and Extracting the new version of Minecraft
    Write-verbose -Message "Downloading the new version of the server"
	Invoke-WebRequest -Uri $download_link -OutFile "$WorkingDirectory/Downloads/bedrock-server.zip"
	Write-Verbose -Message "Expanding the folder to the home folder"
	$new_destination = "$WorkingDirectory/bedrock-server" # $WorkingDirectory/bedrock-server
	Expand-Archive -Path "$WorkingDirectory/Downloads/bedrock-server.zip" -DestinationPath $new_destination


    # Copying old Configurations files to the new server
	Write-Verbose -Message "Copying world files into new server"
	Copy-Item "$backup_folder/worlds" -Destination $new_destination -Recurse -Force
	Write-Verbose -Message "Copying permissions file into new server"
	Copy-Item "$backup_folder/permissions.json" -Destination $new_destination -Force
	Write-Verbose -Message "Copying server properties file into new server"
	Copy-Item "$backup_folder/server.properties" -Destination $new_destination -Force
	Write-Verbose -Message "Copying whitelist file into new server"
	Copy-Item "$backup_folder/whitelist.json" -Destination $new_destination -Force
	Write-Verbose -Message "Copying Resource Packs"
	Copy-Item "$backup_folder/resource_packs" -Destination $new_destination -Recurse -Force


    # Creating new Version text file
    Write-Verbose -Message "Creating a new version.txt file"
	$version_file = "$new_destination/version.txt"
	New-Item $version_file -ItemType File -Force
	Add-Content -Path $version_file -Value "$($online_version)" -NoNewline


    # Compressing the backup server folder
    Write-Verbose -Message "Compressing the backed up server version to conserve space"
	Compress-Archive -Path $backup_folder -DestinationPath "$($backup_folder).zip"


    # Removing the old uncompressed server files
    Write-Verbose -Message "Remove uncompressed version of backup server"
	if(Test-Path "$($backup_folder).zip"){
		Remove-Item -Path $backup_folder -Recurse -Force
	}


    # Setting the new Server Script to be executable and starting the server
    Write-Verbose "Setting new server script to be executable"
	Write-Verbose -Message "Starting the server again"
	bash -c "find /home/$Username/bedrock-server/ -name bedrock_server -type f -exec chmod 0755 {} \;"
	bash -c "sudo systemctl start minecraft"


    # Sending Emails
    if($SendMail.IsPresent){
		$From = # Email address to send mail out with
		$Password = ConvertTo-SecureString "<password>" -AsPlainText -Force # password for the email address to send mail with
		$Creds = New-Object System.Management.Automation.PSCredential ($From, $Password)
		$To = # Array of user emails
		$Subject = "Minecraft Server Update!"
		$Body = "Minecraft Server was updated to version: $($online_version)"
		$SMTPServer = "send.one.com"

		Send-MailMessage -From $From -To $To -Credential $Creds -Subject $Subject -Body $Body -SmtpServer $SMTPServer -UseSsl -Port 587
	}


    # Cleaning up downloaded files
    if(Test-Path "home/$Username/Downloads/bedrock-server.zip"){
		Remove-Item -Path "home/$Username/Downloads/bedrock-server.xip" -Force
	}
}

# Stopping the log file
Stop-Transcript

Related Post

Leave a Reply

Your email address will not be published. Required fields are marked *

This website uses cookies. By continuing to use this site, you accept our use of cookies.