Chapter X

Extras

Additional helpful material for system administrators.

Subsections of Extras

Introduction

YouTube Video

Video Transcript

Greetings everyone! This module contains additional materials and helpful information for system administrators. You are not required to view all of these videos, but I encourage you to do so if there are any topics here you find interesting.

Also, feel free to suggest any topics you’d like to see covered in this section as you go through the course. Any suggestions may be considered toward the extra credit assignment in this course.

Enjoy!

SSH

YouTube Video

Resources

Video Transcript

In this video, I’ll discuss how to use the Secure Shell, or SSH, remote server and client. You’ll be using it throughout the semester to connect to various computers, and there are a few things you should know that will help make your experience a much more pleasant one.

If you’d like to know more about the technical details of how SSH works, refer to the links in the resources section below the video.

First, let’s look at the SSH client program, available as the ssh command on most Linux systems. It is typically installed by default, but if not you can install it using the apt command:

sudo apt install openssh-client

Once it is installed, you can connect to any server you wish by simply using the ssh command followed by the host you’d like to connect to. Optionally, you may need to provide a different username, in which case you would put the username before the host, connecting the two with an @ symbol, much like an email address. If you’d like to try it yourself, you can try to connect to the CS Linux servers using a command similar to the following:

ssh russfeld@cslinux.cs.ksu.edu

Obviously, you’ll need to replace russfeld with your own username.

If this is the first time you are connecting to a particular server, you’ll receive an error message similar to the following:

The authenticity of host ‘cislinux.cs.ksu.edu (129.130.10.43)’ can’t be established.
ECDSA key fingerprint is SHA256: <random_text>.
Are you sure you want to continue connecting (yes/no)?

As a security feature, the SSH client will remember the identity of each server you connect to using this fingerprint. Since this is the first time you have connected to this server, it doesn’t have a fingerprint stored, and it will ask you to confirm that the one presented is correct. If you wanted to, you could contact the owner of the server and ask them to verify that the fingerprint is correct before connecting, but in practice that is usually not necessary. However, once you’ve accepted the fingerprint, it will store it and check the stored fingerprint against the one presented on all future connections to that server.

If, at any point in the future, the fingerprints don’t match, you will be presented with a similar error message. In that case, however, you should be very cautious. It could be the case that the server was recently reset by its owner, in which case you can easily contact them to verify that fact. However, it could also be the case that someone is attempting to either listen to your connection or have you connect to a malicious server. In that case, you should terminate the connection immediately, or else they could possibly steal your credentials or worse.

In any case, since this is our first time connecting, just type yes to store the fingerprint and continue connecting. You’ll then be asked to provide your password. Note that when you enter your password here it will not show any indication that you are entering text, so you must type carefully. If the password is accepted, you’ll be given access to the system.

On that system, you can run any command that you normally would. You can even run graphical programs remotely via SSH, but that requires a bit more configuration and software which I won’t go into here. Once you are finished, you can type exit to close the remote session and return to your own computer.

Next, let’s discuss the SSH server. It is available as open-source software for Linux, and can easily be installed on any system running Ubuntu Linux using the apt command:

sudo apt install openssh-server

Once it has been installed, you can verify that it is working by using the ssh command to connect to your own system:

ssh localhost

If this is the first time you have done so, you should get the usual warning regarding host authenticity. You can simply type yes to continue connecting, then provide your password to log on to the system. Once you have verified that it is working, type exit to return to the local terminal. If your server is connected to a network, you can use ssh to connect to it just like you would any other server. Note that you may have to configure your firewall to allow incoming SSH connections, typically on port 22.

The SSH server has many options that you can configure. You can edit the configuration file using this command:

sudo nano /etc/ssh/sshd_config

There are many great resources online to help you understand this file. In general you can use the default settings without any problems, but there are a couple of lines you may want to change. Note that any line prefixed with a hash symbol # is a code comment, so you will need to remove that symbol for the change to be read. The commented lines reflect the default settings, which can be overridden by un-commenting the line and changing the value.

The first line you may want to change is:

#Port 22

This line defines the port that SSH listens on. By default, SSH uses port 22, a well-known port for that service. However, since everyone knows that SSH uses port 22, it is very common for servers connected to the internet to receive thousands of malicious login attempts via that port in an attempt to discover weak passwords and usernames. By changing the SSH port to a different port, you can eliminate much of that traffic. Of course, if you change this port here, you may also need to update your firewall rules to allow the new port through the firewall.

The other line worth looking at is:

#PasswordAuthentication yes

By changing this line to no you can require that all users on your system use SSH keys to log in, which are generally much more secure than passwords. We’ll discuss SSH keys shortly. Remember to make sure your own SSH key is properly configured before changing this setting, or you may lock yourself out from your own system.

If you make any changes to the configuration file, you can restart the server using the following command:

sudo systemctl restart ssh

You can also always check the status of the server using this command:

sudo systemctl status ssh

To make your life a bit easier, let’s discuss SSH keys. Instead of providing a password each time you want to log on to a system with SSH, you can have your computer automatically provide a key to prove your identity. Not only is this simpler for you, but in many cases it is much more secure overall.

To use SSH keys, you must first generate one. You’ll need to perform this step on the computer you plan to connect from, not on the server you’ll connect to. In Terminal, type the following command to start the process:

ssh-keygen -t rsa -b 4096

This will generate a public & private RSA keypair with a 4096 bit size, generally regarded as a very secure key by most standards.

The command will first ask you where to store the key. It defaults to ~/.ssh/id_rsa which is the standard location, so just press enter to accept the default.

Next, it will ask you to set a passphrase for your key. If you are setting up the key on a secure computer that only you would have access to, you can leave this blank to not set a passphrase on the key. In that way, you won’t have to enter any passwords to use SSH with this key. However, if anyone gains access to the key file itself, they can easily log in to any system as you with that key until you revoke access. If you want your keys to be more secure, you can set a passphrase to lock the key. The downside is that you’ll have to provide the passphrase for the key in order to use it, but it is still more secure than providing the password to the user account itself.

Once the key is created, it will give you some information about where it is stored. You can view those files by typing the following:

ls ~/.ssh/

There should be at least two files here. The first, id_rsa, is your private key. Do not share that file with anyone! You may choose to make a backup of that file for your own use, if desired. However, if the key was not protected with a passphrase when it was created, you should protect that file as closely as if it contained all of your passwords in plain text.

The second file, id_rsa.pub, is your public key. This is the file we’ll need to give to other servers so that we can log on using our private key. There are a couple of ways to do so. First, I’ll show you the automatic way, then I’ll discuss what it does so you could do it manually if needed.

To send your public key to a remote server, we’ll use the ssh-copy-id command. Its syntax is very similar to the normal SSH command. For example, to send my new public key to the CS Linux server, I would do the following:

ssh-copy-id russfeld@cslinux.cs.ksu.edu

It will prompt you for your password, and if it succeeds it will install the key on that server. You can then verify that it worked by using the normal SSH command to connect. It should succeed without asking you to provide any password, except possibly the passphrase for your SSH key.

Once on that server, we can see where the key gets installed. It is usually placed in a file at ~/.ssh/authorized_keys. On some systems, it may be ~/.ssh/authorized_keys2 due to a security vulnerability, or both files may be present. This is configurable in the SSH Server configuration file.

In that authorized_keys file, you’ll see a copy of your public key on a single line. To add additional keys to the system, you can either use the ssh-copy-id command from the system containing the new key, or copy and paste the public keys directly into this file, one per line. To remove a key, simply delete the corresponding line from this file. Note that at the end of the line you can see the username and computer name from the machine where the key was created, which can be very helpful in identifying keys.

Finally, there is one other trick you can use to make working with SSH servers much more useful, and that is through the use of an SSH config file. First, make sure you are back on your local computer and not on any remote servers. Check the command prompt carefully, or type exit a few times to make sure you have closed all SSH sessions. On your local computer, open a new SSH config file using the following command:

nano ~/.ssh/config

By convention, your SSH config file should reside in that location. In that file, you can configure a wide variety of host settings for the servers you connect to. For example, here is one entry from my own SSH config file:

Host cs
    HostName cslinux.cs.ksu.edu
    Port 22
    User russfeld
    IdentityFile ~/.ssh/id_rsa

The first line gives the short name for the host. Then, all lines below it give configuration information for that host. For example, here I’ve given the hostname (you can also use an IP address), the port, the username, and the private key file that should be used when connecting to this host. These are all options that you’d normally have to provide on the command line when using the ssh command. By placing them here, you can just reference the host by its short name, and all of this information will automatically be used when you connect to that system.

With this in place, all I have to do to connect to the CS Linux servers is type:

ssh cs

and all my other options are read from this configuration file. Pretty nifty, right?

There are many other options you can include in your SSH config file. I recommend checking out the links in the resources section for more information.

I hope this video will be very useful to you as you work with SSH throughout this semester and in the future. I know much of this information has been very helpful to me in my career thus far.

Bash Scripting

YouTube Video

Resources

Video Transcript

In this video, I’ll introduce the concepts for scripting using the Bash shell in Ubuntu Linux. In essence, scripting allows you to automate many common tasks that you would perform using the terminal in Linux. It is a very powerful skill for system administrators to learn.

First, I’m going to create a bin folder inside of our home folder (this will become useful later).

mkdir ~/bin

In that command, the tilde ~ character represents your home folder. It is one of the special folder paths that you can use on the terminal in Linux. Now, we can open that folder:

cd ~/bin

To begin, let’s open a text file using Nano in the terminal. I’m going to use the .sh file extension to make it clear that this is a script, but that is not necessary on Linux.

nano script.sh

At the top of the file, we must define the script interpreter we would like to use. For Bash, place this line at the very top of the file:

#!/bin/bash

Some experienced system administrators will refer to the start of that line as a “sha-bang,” which may make it easy to remember. It is actually a two-byte magic number that tells Linux what type of file it is reading, and then the rest of the line gives the path to the program that can interpret that file. This allows Linux to determine the type of the file even without checking the file extension, which is what Windows does.

Below that line, you can simply place terminal commands, one per line, that you wish to have the script perform. For example, here is a simple Hello World script:

#!/bin/bash

echo "Hello World"
exit 0

The echo command is pretty self-explanatory - it just prints text to the console. The final line gives the exit condition for the script. Returning zero 0 indicates that the script completed successfully. Any non-zero value is treated as an error, and can be used to diagnose failing scripts. See Chapter 6 of the Advanced Bash-Scripting Guide from TDLP for more information on exit conditions.

To run the script, save and exit the file using CTRL+X, then Y, then ENTER. Then, you can simply type:

./script.sh

and see if it works. Here, we are using the dot, or period ., as part of the path to the script. A single dot represents the current directory, so putting ./ in front of a file indicates that we want to run the script with that name from the current directory. At the end of the video, we’ll discuss how to modify your system so you don’t have to include the path to the script.

Unfortunately, it doesn’t run. This is because Linux has a separate file permission to allow files and scripts to be executed. By default, most files aren’t given that permission, so we have to manually add it before executing the script. To do so, type:

chmod u+x script.sh

This will give the owner of the file u the execute permission +x. Then, try to run it again:

./script.sh

It should display “Hello World” on the screen. Congratulations, you’ve written your first Bash script!

Now, let’s take a look at a more complex script. This is one I actually wrote years ago when I first interviewed for an instructor position here at K-State:

#!/bin/bash
#batman.sh

if (( $# < 1 || $# > 1 )); then
  echo "Usage: batman.sh <name>"
  exit 1
fi

if [ "$1" = "Batman" ]; then
  echo "Hello Mr. Wayne"
elif [ "$1" = "Robin" ]; then
  echo "Welcome back Mr. Grayson"
else
  echo "Intruder alert!"
fi
exit 0

There is quite a bit going on in this script, so let’s break it down piece by piece. First, this script includes parameters. The $1 variable references the first parameter, and obviously $2 would be the second, and so on. For parameter values above 9, include the number in curly braces, such as ${10} and ${11}.You can also access the number of parameters provided using $#, and the entire parameter string as $*.

Below that, the first if statement:

if (( $# < 1 || $# > 1 )); then
  echo "Usage: batman.sh <name>"
  exit 1
fi

uses double parentheses, representing arithmetic evaluation. In this case, it is checking to see if the number of parameters provided is either greater than or less than 1. If so, it will print an error message. It will also exit with a non-zero exit condition, indicating that the script encountered an error. Lastly, note that if statements are concluded with a backwards if, or “fi”, indicating the end of the internal code block. In many other programming languages, curly braces ({ and }) are used for this purpose.

The next if statement:

if [ "$1" = "Batman" ]; then
  echo "Hello Mr. Wayne"
elif [ "$1" = "Robin" ]; then
  echo "Welcome back Mr. Grayson"
else
  echo "Intruder alert!"
fi

uses square brackets for logical test comparisons. This is equivalent to using the Linux “test” command on that statement. Here, the script is checking to see if the string value of the first parameter exactly matches “Batman”. If so, it will print the appropriate welcome message.

So, this simple script introduces two different methods of comparison, as well as conditional statements and parameters.

Here’s another simple script to introduce a few other concepts:

#!/bin/bash
#listfiles.sh

files=`ls $* 2> /dev/null`
for afile in "$files"; do
    echo "$afile"
done
exit 0

The first line of the script:

files=`ls $* 2> /dev/null`

declares a new variable $files, and sets its value to the output of the command contained in backticks `. Inside of a script, any commands contained in backticks will be converted to the output of that script, which can then be stored in a variable for later use.

The next line:

for afile in "$files"; do

represents a “foreach” loop. It will execute the code inside of that statement once for each item in the $files variable. Note that when variables are declared and assigned, they don’t require the dollar sign $ in front of them, but when they are used it must be included. The loop is concluded with a “done” line at the bottom.

Finally, let’s review a couple more scripts:

#!/bin/bash
#simplemenu.sh

OPTIONS="Build Run Clean Quit"

select opt in $OPTIONS; do
  if [ "$opt" = "Build" ]; then
    echo "Building project..."
  elif [ "$opt" = "Run" ]; then
    echo "Running project..."
  elif [ "$opt" = "Clean" ]; then
    echo "Cleaning project..."
  elif [ "$opt" = "Quit" ]; then
    echo "Exiting..."
    break
  else
    echo "Invalid Input"
  fi
done
exit 0

This script creates a simple menu with four options, stored in the $OPTIONS variable at the top. It then uses a “select” statement, telling the terminal to ask the user to choose one of the options provided, and then inside the select statement is a set of “if” statements determining which option the user chose. This is very similar to a “case” statement in many other programming languages. When you run this script, note that it repeats the options until it hits an option containing a “break” statement, so it is not necessary to encapsulate it in a loop.

Lastly, Bash scripts also provide the ability to read input from the user directly, instead of using command-line parameters:

#!/bin/bash
#simpleinput.sh

echo "Input your name and press [ENTER]"
read name
echo "Welcome $name!"
exit 0

This script uses the “read” command to read input from the user and store it in the $name variable. Pretty simple, right?

If you plan on writing scripts for your own use, there is one thing you can do to greatly simplify the process of using them. Notice that, currently, you must provide the full path to the script using either ./ or some other path. This is because, by default, Linux will look for commands and scripts in all of the folders contained in your PATH environment variable, but not the current folder. So, we must simply add the folder containing all of our scripts to the PATH variable.

In recent versions of Ubuntu, all you have to do is create a bin folder in your home folder, as we did above. Then, restart the computer and it should automatically add that folder to your path. This is because of a setting hidden in your Bash profile configuration file, usually stored in ~/.profile. The same process works for the Windows Subsystem for Linux (WSL) version of Ubuntu as well.

You can check the current PATH variable using the following command:

echo $PATH

If you don’t see your ~/bin folder listed there after you’ve created it and rebooted your computer (it will usually have the full path, as in /home/cis527/bin or similar), you’ll need to add it manually. To do this, open your Bash settings file:

nano ~/.bashrc

And, at the very bottom of the file, add the following line:

export PATH=$PATH:$HOME/bin/

Then, save the file, close, and reopen your terminal window. You can check your PATH variable once again to confirm that it worked.

Now, you can directly access any script you’ve created and stored in the ~/bin folder without providing a path. So, for example, the very first script we created, stored in ~/bin/script.sh, can now be accessed from any folder just by typing

script.sh

on the terminal.

This is a very brief introduction to Bash scripting. I highly recommend reading the Advanced Bash-Scripting Guide from The Linux Documentation Project (TLDP) if you’d like to learn even more about scripting.

Cron (Linux Scheduled Tasks)

YouTube Video

Resources

Video Transcript

This video introduces the Cron tool on Linux, which can be used to run tasks automatically at specific times on your system. It is a very handy piece of software, but a little confusing at first.

To view the current list of scheduled tasks for your user, use the following command:

crontab -l

Generally, you probably won’t see anything there at first. You can also view the list for the root user using the sudo command

sudo crontab -l

Depending on the software installed on your system, you may already see a few entries there.

To edit the schedule, use the same command with a -e option:

crontab -e

It should open the file with your default text editor, usually Nano. At the top of the file, it gives some information about how the file is constructed. At the bottom, you can add lines for each command you’d like to run. There are 6 columns present in the file, in the following order:

  1. m - minute (0-59)
  2. h - hour (0-23)
  3. dom - day of month (1-31)
  4. mon - month (1-12)
  5. dow - day of week (0=Sunday, 1=Monday, … 7=Sunday)
  6. command - full path to the command to be run, followed by any parameters

The Linux Cron Guide from LinuxConfig.org has a great graphic describing these columns as well. All you have to do is add your entries and save the file, and the new settings will be applied automatically.

Honestly, the best way to learn cron is by example. For example, assume we have a script at /home/cis527/bin/script.sh that we’d like to run. If we add the following entry:

15 5 * * * /home/cis527/bin/script.sh

it will run the script at 5:15 AM every day. Note that the amount of whitespace between each column doesn’t matter; it will treat any continuous sequence of spaces and tabs as a single whitespace, much like HTML. So, feel free to align your columns however you choose, as long as they are in the correct order and separated by at least one whitespace character.

Let’s look at some other examples:

0 */6 * * * /home/cis527/bin/script.sh

This will run the script every six hours (note the */6, meaning that every time the hour is divisible by 6, it will run the script). So, it will run at 12 AM, 6 AM, 12 PM, and 6 PM each day.

10,30,50 * 15 * 5 /home/cis527/bin/script.sh

This will run every hour at 10, 30 and 50 minutes past the hour, but only on the 15th day of each month and every Friday. Note that the day of week option is generally separate from the day of month option. If both are included, it will run on each indicated day of the week, as well as the indicated day of the month.

0 5 * * 1-5 /home/cis527/bin/script.sh

This will run at 5:00 AM each weekday (Monday=1 through Friday=5)

@reboot /home/cis527/bin/script.sh

This will run once each time the system starts up.

There are many, many more ways to use cron, but hopefully this video gives you enough information to get started. Good luck!

PowerShell Scripting

YouTube Video

Resources

Video Transcript

This video introduces the Windows PowerShell Integrated Scripting Environment (ISE) and covers the basics for creating and running your own scripts in Windows PowerShell.

Before we begin, we must change one system setting to allow unsigned PowerShell scripts to run. To do this, you’ll need to open a PowerShell window using the Run as Administrator option, and then enter the following command:

Set-ExecutionPolicy Unrestricted

However, be aware that this makes your system a bit more vulnerable. If you or a malicious program tries to run a malicious PowerShell script that is unsigned, the system will not try to stop you. It would be a very rare occurrence, but it is something to be aware of.

Now, let’s open the PowerShell ISE to start writing scripts. To find it, simply search for PowerShell ISE on your Start Menu. It should be included by default on all versions of Windows 10.

When you first open the PowerShell ISE, you may have to click the Script button in the upper-right corner of the window to view both the scripting pane and the command window. To write your scripts, you can simply write the text in the upper window, then save the file and run the program using the Run script button on the top toolbar. You can also run the script in the command window below.

To begin, let’s take a look at a simple Hello World script:

Write-Host "Hello World"
return

This script should be pretty self-explanatory. The Write-Host command simply displays text on the terminal, and the return line ends the script. As with any programming language, it is good practice to include a return at the end of your script, but it is not necessarily required.

Let’s look at a more advanced script to see more features of the Windows PowerShell scripting language.

Param(
    [string]$user
)

if ( -not ($user)){
    Write-Host "Usage: batman.ps1 <name>"
    return
}

if ($user.CompareTo("Batman") -eq 0){
    Write-Host "Hello Mr. Wayne"
}else{
    if ($user.CompareTo("Robin") -eq 0){
        Write-Host "Welcome back Mr. Grayson"
    }else{
        Write-Host "Intruder alert!"
    }
}
return

At the top of this script, there is a special Param section. In PowerShell, any parameters expected from the user must be declared here, with the data type in square brackets ([ and ]), followed by the variable name prefixed with a dollar sign $. In this script, we have declared one command line parameter $user of type string.

Below that, we have the first if statement:

if ( -not ($user)){
    Write-Host "Usage: batman.ps1 <name>"
    return
}

This will check to see if the $user parameter was provided. If it was not, it will print an error message and return to end the script.

The next if statement:

if ($user.CompareTo("Batman") -eq 0){
    Write-Host "Hello Mr. Wayne"
}else{
    if ($user.CompareTo("Robin") -eq 0){
        Write-Host "Welcome back Mr. Grayson"
    }else{
        Write-Host "Intruder alert!"
    }
}

performs a string comparison between the $user parameter and the string “Batman”, if the comparison returns 0, they are equal. This is very similar to other string comparison functions in C# and Java. One interesting item to note here is the use of -eq to denote equality. For some reason, PowerShell uses short textual comparison operators instead of the common symbols for boolean comparisons. I really don’t know why that particular design decision was made, but I encourage you to look at the documentation to see what options are available for comparison.

Here is another simple script:

Param(
    [string]$path
)

$files = Get-ChildItem $path

foreach($file in $files){
    Write-Host $file.name
}

This is an example of a simple looping script. In this script, it will get a path from the user as an argument, then store a list of all the child items on that path in $files variable. Then, it will use a “foreach” loop to print out the name of each of those files. Thankfully, if you’ve done any programming in the .NET family of languages, most of this syntax will be very familiar to you.

You can also use PowerShell to create a simple menu for your script. This is a bit more involved than the example from the Linux Bash scripting video, but it is pretty straightforward:

$title = "Select Options"
$message = "Choose an option to perform"

$build = New-Object System.Management.Automation.Host.ChoiceDescription "&Build", "Build the project"
$run = New-Object System.Management.Automation.Host.ChoiceDescription "&Run", "Run the project"
$clean = New-Object System.Management.Automation.Host.ChoiceDescription "&Clean", "Clean the project"
$quit = New-Object System.Management.Automation.Host.ChoiceDescription "&Quit", "Quit"

$options = [System.Management.Automation.Host.ChoiceDescription[]]($build, $run, $clean, $quit)

$result = $host.ui.PromptForChoice($title, $message, $options, 0)
switch ($result)
{
    0 {
        Write-Host "You selected Build"
    }
    1 {
        Write-Host "You selected Run"
    }
    2 {
        Write-Host "You selected Clean"
    }
    3 {
        Write-Host "You selected Quit"
    }
}

At the top of the script, the first two variables define the text that will be shown as the title of the menu and the message displayed to the user before the menu options. The next four variables define the menu choices available. Looking at the first one, the &Build gives the title of the option, with the ampersand & before the ‘B’ indicating which letter should be the shortcut to choose that option. The next string gives a longer description of the option. Finally, we put it all together in the $options variable as an array of available options, then use the PromptForChoice function to display the menu to the user, storing the user’s choice in the $result variable. Finally, we use a simple “switch” statement to determine which option the user chose and then perform that task.

If you are having trouble understanding what each part does, I recommend just running the script once and then matching up the text displayed in the menu with the script’s code. It may seem a bit daunting at first, but it is actually pretty simple overall. As a quick aside, if you run this on a system with a GUI, you may get an actual pop-up menu instead of a textual menu, but rest assured that it will display the textual version on system’s without a GUI.

Finally, here is a quick script demonstrating how to get user input directly within the script:

$name = Read-Host "Input your name and press [ENTER]"
Write-Host "Welcome $name!"

It’s as simple as that! Of course, that is just a very small taste of what PowerShell is capable of. Hopefully this introduction gives you some idea of what is available, but I encourage you to consult the online documentation for PowerShell to learn even more about it.

Windows Subsystem for Linux

YouTube Video

Resources

Video Transcript

In this video, I will briefly introduce the Windows Subsystem for Linux, or WSL, which was one of the most highly anticipated features added to Windows 10 in the last couple of years. WSL allows you to install a full Linux distribution right inside your Windows 10 OS, giving you terminal access to some of your favorite Linux programs and tools. You can even run services such as sshd, MySQL, Apache, and more directly in WSL.

First, you must enable the feature on Windows. The simplest way to do this is to open a PowerShell window using the Run as Administrator option, then enter the following command:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

Once it is complete, you will need to reboot your computer to enable to feature.

Once you have rebooted, you can go to the Windows Store and install the distribution of your choice. There are many to choose from, and you can even have multiple distributions installed at the same time. For this example, I’ll choose Ubuntu.

Once it has finished installing, you must open it once to complete the initialization. During that process, you’ll be asked to create a username and password for your Linux system. It doesn’t have to be the same as your Windows user account, and it will not be synchronized with your Windows password either.

As soon as it is complete, you’ll be taken to your Linux distribution’s shell. Pretty neat, right?

So, what can you do from here? Pretty much anything! Here are a few things I suggest doing right off the bat.

First, you can update your system just like any other Linux system:

sudo apt update
sudo apt upgrade

You can also set up SSH keys so you can use SSH from WSL instead of dealing with PuTTY or other Windows-based terminal programs. Refer to the Extra - SSH page for more information on how to do that.

On WSL, you can find your normal Windows drives at /mnt by doing:

ls /mnt

To get easy access to your Windows files, you can add a symbolic link to your Windows user folder, or any folder you choose. For example, if your Windows username is cis527 you can use the following command to add a shortcut in your Windows home folder within your WSL home folder:

ln -s /mnt/c/Users/cis527/ ~/cis527

You can verify that it worked using this command:

ls -l

I’ve used this to create a few useful shortcuts to allow me to easily access my Windows files.

Finally, since I am a big fan of using Git on command line, I usually install Git on my WSL to allow me to easily manage my repositories just like I normally do on my Linux based development systems.

I hope you enjoy working with WSL as much as I have. If you have any suggestions of cool uses for WSL that I missed, feel free to send them to me. You just might get some extra credit points and see your idea featured here in a future semester!

Git

YouTube Video

Resources

Video Transcript

This video provides a brief introduction to the Git source control program used by many system administrators. While this video is not intended to provide a full introduction to Git as a programmer would use it, it should serve as a quick introduction to the ways that system administrators might come across Git in their workloads.

For this example, I’ll be working with the command-line git program. There are many graphical programs that can be used to interact with Git as well, such as GitHub Desktop and Git Krakken

If you haven’t already, you’ll need to install the Git command-line tool. You can do so using apt:

sudo apt update
sudo apt install git

Also, if you have not used Git on this system, you’ll want to configure your name and email address used when you create commits:

git config --global user.name "Your Name"
git config --global user.email username@emailprovider.tld

Now, let’s create a new Git repository on our computer. To do that, I’m going to create a new folder called git-test and add a couple of files to it:

mkdir ~/git-test
cd ~/git-test
echo "File 1" > file1.txt
echo "File 2" > file2.txt

Next, let’s initialize an empty Git repository in this folder. This is the first step to adding an existing folder to Git. You can also use this command in an empty folder before you begin adding content.

git init

Once you’ve done that command, let’s look at the directory and show all the hidden files:

ls -al

As you can see, there is now a folder .git in this directory. That folder contains the information for this Git repository, including all of the history and changes. DO NOT MODIFY OR DELETE THIS FOLDER! If you change this folder, it may break your Git repository.

To see the status of a Git repository, you can use the git status command:

git status

Here you’ll see that there are two files that are not included in the repository, which are the files we added earlier. To add a file to a Git repository, there are three steps. First, you must create or modify the file on the filesystem inside a git repository, which will cause Git to see the file as modified or “dirty.” Then, any changes you’d like to add to the Git repository will need to be “staged” using the git add command. Finally, those changes which are staged are “committed” using the git commit command.

So, to perform this process on the two files currently in our directory, we’ll do this command to stage them:

git add file1.txt file2.txt

Once they are staged, we can check the status to make sure they are ready to commit:

git status

If everything looks correct, we can commit those changes:

git commit -m "First Commit"

The -m flag on the git commit command allows us to specify a commit message on the command line. If you omit that option, you’ll be taken to your system’s default text editor, usually Nano or Vim, and be able to write a commit message there. Once you are done, just save and close the file as you normally would, and the git command will proceed to commit the changes.

Finally, once you have committed your changes, you can review the status of your repository again:

git status

You can also review the Git log to see a log of your commits:

git log

Now that we’ve created a Git repository and added our first commit, let’s talk about remotes. A remote in Git is a remote copy of a repository, which can be used as a backup for yourself, or as a way to share a repository with other developers. Most commonly, your remote will be an online service such as GitHub or GitLab, but there are many others as well. For this example, I’ll show you how to work with the GitLab instance hosted by K-State CS. The instructions are very similar for GitHub as well.

First, you’ll need to navigate to http://gitlab.cs.ksu.edu and sign-in with your K-State CS username and password. Once you’ve logged in, go to your account settings, and look for the SSH Keys option. In order to authenticate your system with GitLab, you’ll need to create an SSH key and copy-paste the public key here. See the SSH video in the Extras module for detailed instructions on creating those keys. I’ll perform the steps quickly for this example as well. Once you are done, you can click the logo in the upper-left to go back to the dashboard.

On the dashboard, you can click the New Project button to create a new project. To make it simple, I’m going to give it the same name as my folder, git-test. I can also give it a description, and I’ll need to set the visibility level for this project. I’m going to use the Private option for now, so I’ll be the only one able to see this project.

Once your project is created, it will give you some handy instructions for using it. We’re going to do the last option, which is to use an existing Git repository. So, at any time in the future, you can easily follow those instructions to get everything set up correctly.

Back on the terminal, we’ll need to add a remote to our Git repository. The command for this is:

git remote add origin <url>

Then, we’ll need to push our repository to the remote server. Since we don’t have any locally created branches or tags, we can just use this command:

git push -u origin master

If you have already created branches or tags in this repository, you can push them to the remote server using these commands:

git push -u origin --all
git push -u origin --tags

There you go! Your Git repository is set to be tracked by a remote server. If you open the GitLab page, you can now see your files here as well. You can now use that remote server to share this repository across multiple computers, or even with multiple developers. For example, let’s see how we could get a copy of this repository on another computer, make changes, and share those changes with both systems.

First, on the other computer, you’ll need to also create an SSH key and add it to your account on GitLab. I’ve already done so for this system.

Next, we’ll need to get a copy of the repository from the remote server using this command:

git clone <url>

That will create a copy of the repository in a subfolder of the current folder. Now, we can open that folder and edit a file:

cd git-test
echo "Some Changes" >> file1.txt

As you make edits, you can see all of the changes since your last commit using a couple of commands. First:

git status

will give you a list of the files changed, created, or deleted since the last commit. You can see the details of the changes using:

git diff HEAD

which will show you all of the changed files and those changes since the last commit.

Now, we can stage any changes using:

git add .

which will automatically add any changed, added, or removed files to the index. This command is very handy if you want to add all changed files to the repository at once, since you don’t have to explicitly list each one. Then, we can commit those changes using:

git commit -m "Modified file1.txt"

and finally, we can upload those changes to the remote server using:

git push

If we view the project on GitLab, we can see the changes there as well. Finally, on our original computer, we can use this command to download those changes:

git pull

If you have made changes on both systems, it is a good idea to always commit those changes to the local repository before trying to use git pull to download remote changes. As long as the changes don’t conflict with each other, you’ll be in good shape. If they conflict, you’ll have to fix them manually. I’ll discuss how to do that a bit later as we deal with branching and merging.

Another major feature of Git is the ability to create branches in the repository. For example, you might have a really great idea for a new feature as you are working on a project. However, you are worried that it might not work, and you don’t want to lose the progress you have so far. So, you can create a branch of the project and develop your feature there. If it works, you can merge those changes back into the master branch of your project. If it doesn’t, you can just switch back to the master branch without merging, and all of your original code is just as you left it.

To create and switch to a new branch, you can use these commands:

git branch <branch_name>
git checkout <branch_name>

It should tell you that you switched to your new branch. You can also run

git status

at any time to see what branch you are currently on. Now, let’s make some changes:

echo "File 12" > file1.txt
echo "More Changes" >> file2.txt

Here, you’ll note that I am overwriting the contents in file1.txt since I only used one > symbol, while I am adding a third line of content to file2.txt since I used >> to append to that file. You can always see the changes using:

git diff HEAD

Now, let’s commit those changes:

git add .
git commit -m "Branch Commit"
git push -u origin <branch_name>

Notice that the first time you push to a new branch, you’ll need to provide the -u <branch_name> option to tell Git which branch to use. Once you’ve done that the first time, you can just use git push in the future.

Now, let’s switch back to the master branch and make some changes there as well:

git checkout master
echo "File 13" > file1.txt
git add .
git commit -m "Master Commit"
git push

At this point, let’s try to merge the changes from my new branch back into the master branch. To merge branches, you’ll need to switch to the destination branch, which I’ve already done, then use this command:

git merge <branch_name>

If none of the changes cause a conflict, it should tell you that it was able to merge the branches successfully. However, in this case, we have created a conflict. This is because we have modified file1.txt in both branches, and Git cannot determine how to merge them together in the best way. While Git is very smart and able to merge modified files in many cases, it isn’t able to do it when the same lines are changed in both files and it can’t determine which option is correct. So, it will require you to intervene and make the changes.

So, let’s open the file:

nano file1.txt

Here, you should see content similar to this

<<<<<<< HEAD
File 13
=======
File 12
>>>>>>> new_branch

The first section, above the line of equals signs =, is the content that is in the destination branch, or the branch that you are merging into. The section below that shows the content in the incoming branch. To resolve the conflict, you’ll need to delete all of the lines except the ones you want to keep. So, I’ll keep the change in the incoming branch in this case:

File 12

and then I’ll save and close the file using CTRL+X, then Y, then ENTER. Once I’ve resolved all of the conflicts, I’ll need to commit them:

git add .
git commit -m "Resolve Merge Conflicts"
git push

Congratulations! You’ve now dealt with branching and merging in Git.

Finally, there are a couple of handy features of Git that I’d like to point out. First is the tagging system. At any time, you can create a tag based on a commit. This is typically used to mark a particular version or release of a program, or maybe even an assignment in a course. It makes it easy to find that particular commit later on, in case you need to jump back to it. To create and push a tag, you can do the following commands:

git tag -a <tag_name> -m <message>
git push

You can see the tags on GitLab too. It is a very handy feature when working with large projects.

Also, if you have some files that you don’t want Git to track, you can use a .gitignore file. It is simply a list of patterns that specify files, folders, paths, file extensions, and more that should be left out of Git’s index. I encourage you to read the documentation for this feature, which is linked in the resources section below the video. There are also some great sample .gitignore templates from GitHub linked there as well.

I hope this video has given you a brief introduction of Git and how you could use it as a system administrator. If you’d like to learn even more about Git, I encourage you to review the links in the resources section below this video for even more information and examples of how you can use Git.