#!/bin/bash # Install and configure a Ubuntu-PC for the charity organization angestöpselt e.V. | angestoepselt.de # created by matthias of angestöpselt e.V. # created at 2022-02-17 version=0.2 set -o errexit exec 100>/tmp/z31.lock || exit 1 flock 100 || exit 1 # Speed up script by not using unicode. LC_ALL=C LANG=C # some static variables DEBIAN_FRONTEND=noninteractive current_user=$(id 1000 | awk -F '[()]' '{print $2}') lockfile=/tmp/z31.lock sysinfofile=$HOME/.config/systeminfo.json random_tmpdir=$(mktemp) SCRIPT_DIR="$(dirname "$0")" TIME=$(date +%Y%m%d%H%M) LOGTIME=$(date "+%Y-%m-%d %H:%M:%S") LOGFILE="$SCRIPT_DIR/$TIME-z31.log" # Set variables for stdout print COLOR_N='\e[0m' COLOR_GREEN='\e[1;32m' COLOR_RED='\e[1;31m' COLOR_BLUE='\e[1;34m' COLOR_WHITE='\e[1;97m' OK="[${COLOR_GREEN}ok${COLOR_N}]" FAIL="[${COLOR_RED}fail${COLOR_N}]" INFO="[${COLOR_BLUE}info${COLOR_N}]" SKIP="[${COLOR_BLUE}skip${COLOR_N}]" PROGRESS="[${COLOR_BLUE}..${COLOR_N}]" # log actual command and it's stderr to logfile in one go runcmd_stdout() { echo "+ $1" >>"$LOGFILE" bash -c -o pipefail "$1" 2>>"$LOGFILE" | tee -a "$LOGFILE" } runcmd() { echo "+ $1" >>"$LOGFILE" bash -c -o pipefail "$1" >>"$LOGFILE" 2>&1 } printprog() { echo -ne "${PROGRESS} $*\r" } printok() { echo -e "\r${OK} $*" } printfail() { echo -e "\r${FAIL} $*" } printinfo() { echo -e "${INFO} $*" } printskip() { echo -e "\r${SKIP} $*" } ErrorHandling() { set -eu printfail "Something went wrong, exiting. Check $LOGFILE for more details." } system_update() { set -o pipefail trap ErrorHandling ERR INT printprog "update cache" runcmd "sudo /usr/bin/apt-get update -qq" printok "update cache" printprog "upgrade system" runcmd "sudo /usr/bin/apt-get dist-upgrade -y -qq" printok "upgrade system" } system_install_base() { set -o pipefail trap ErrorHandling ERR INT printprog "add anydesk repo to source.list.d" if [ -f "/etc/apt/sources.list.d/anydesk-stable.list" ]; then printskip "add anydesk repo to source.list.d" else runcmd "sudo /usr/bin/wget -qO - https://keys.anydesk.com/repos/DEB-GPG-KEY | sudo apt-key add - && \ echo "deb http://deb.anydesk.com/ all main" > /etc/apt/sources.list.d/anydesk-stable.list" printok "add anydesk repo to source.list.d" fi echo ttf-mscorefonts-installer msttcorefonts/accepted-mscorefonts-eula select true | sudo debconf-set-selections printprog "install apt packages (this can take some time)" runcmd "sudo /usr/bin/apt-get install --yes -qq -o Dpkg::Options::=--force-confdef --ignore-missing \ ubuntu-restricted-extras \ apt-transport-https \ vlc \ gdebi \ gparted \ tlp \ language-pack-de-base \ libreoffice \ libreoffice-l10n-de \ libreoffice-help-de \ libreoffice-help-en-gb \ libreoffice-l10n-en-gb \ firefox \ firefox-locale-de \ firefox-locale-en \ thunderbird \ thunderbird-locale-de \ thunderbird-locale-en \ thunderbird-locale-en-gb \ gimp \ anydesk \ libqt5qml5 \ language-selector-common \ openoffice.org-hyphenation \ language-pack-kde-ar \ language-pack-kde-uk \ language-pack-kde-ru \ language-pack-kde-fa" printok "install apt packages" } system_install_edubuntu() { set -o pipefail trap ErrorHandling ERR INT # Edubuntu packages (official support until 18.04) https://wiki.ubuntuusers.de/Edubuntu_Programme printprog "install Edubuntu packages (this can take some time)" runcmd "sudo /usr/bin/apt-get install --yes -qq -o Dpkg::Options::=--force-confdef --ignore-missing \ blinken \ calibre \ cantor \ chemtool \ dia \ einstein \ fritzing \ gamine \ gcompris \ goldendict \ inkscape \ kalgebra \ kalzium \ kanagram \ kbruch \ kgeography \ khangman \ kig \ klettres \ kmplot \ kstars \ ktouch \ ktuberling \ kturtle \ kwordquiz \ laby \ lightspeed \ lybniz \ marble \ melting \ parley \ pencil2d \ ri-li \ rocs \ step \ tuxmath \ tuxpaint \ tuxtype \ yorick" printok "install Edubuntu packages" } system_clean() { set -o pipefail trap ErrorHandling ERR INT printprog "clean up apt cache and packages" runcmd "sudo /usr/bin/apt-get autoremove --yes" printok "clean up apt cache and packages" } system_configure() { set -o pipefail trap ErrorHandling ERR INT printprog "set timezone" runcmd "timedatectl set-timezone Europe/Berlin" printok "set timezone" } system_files_download() { set -o pipefail trap ErrorHandling ERR INT printprog "" runcmd "" printok "" } system_modify_dm() { set -o pipefail trap ErrorHandling ERR INT # TODO: detect dm of device and choose modification # cat /etc/X11/default-display-manager > /usr/sbin/gdm3 (Gnome Desktop Manager) # goals to cover # - Wallpaper # - printprog "" runcmd "" printok "" } system_checkinfo() { set -o pipefail trap ErrorHandling ERR INT # this part checks if the device is already registered in snipe-IT # is already registered it returns 1 # this is a new device it returns 0 if [ ! -f $sysinfofile ]; then printprog "write systeminfo to $sysinfofile" runcmd "mkdir /home/$current_user/.config/angestoepselt && /bin/bash /usr/local/bin/angestoepselt-info > $sysinfofile" printok "write systeminfo to $sysinfofile" fi printprog "read systeminfo" runcmd "jq -e . $sysinfofile >/dev/null 2>&1" printok "read systeminfo" HW_ADDRESS=$(cat $sysinfofile | jq -r .HW_ADDRESS) ASSET_TAG=$(cat $sysinfofile | jq -r .Asset_Tag) ## start localcheck if [[ $ASSET_TAG =~ ^[0-9]+$ ]]; then printinfo "already in Snipe $ASSET_TAG" return 1 elif [ -f $SCRIPT_DIR/mac_white.list ] && grep -Fxq "$HW_ADDRESS" mac_white.list then unset HW_ADDRESS printinfo "Device is using a charity owned USB Ethernet-Adapter" return 1 ## end localcheck else ## start snipe-it check printprog "check presence of snipe-IT API" runcmd "curl -o /dev/null --silent https://$SNIPEIT_DOMAIN" printok "check presence of snipe-IT API" printinfo "fetch info from Snipe-IT" result=$(curl --silent --request GET \ --url "https://$SNIPEIT_DOMAIN/api/v1/hardware?limit=1&search=${HW_ADDRESS//[:]/%3A}" \ --header 'accept: application/json' \ --header 'authorization: Bearer '$SNIPEIT_APIKEY'') [[ $(echo $result | jq '(has("error"))') == true ]] && { printinfo "$(echo $result | jq .error)"; return 1; } system_check_result=$(echo $result | jq .total) # doesn't work asset_tag=$(echo $result | jq -r .rows[].asset_tag) if [ -n "$asset_tag" ]; then printinfo "Device already present in Snipe-IT: RE$asset_tag" printprog "add ASSET_TAG to $sysinfofile" runcmd "jq '. |= . + {"Asset_Tag": \"'${asset_tag}'\"}' $sysinfofile > $random_tmpdir/systeminfo.json.tmp && mv $random_tmpdir/systeminfo.json.tmp $sysinfofile" printok "add ASSET_TAG to $sysinfofile" else printok "Device not in Snipe-IT" system_checkinfo_value="newdevice" return 0 fi ## end snipe-it check fi } system_register() { set -o pipefail trap ErrorHandling ERR INT if [[ "$system_checkinfo_value" != "newdevice" ]]; then printskip "register Device at Snipe-IT" fi # is snipe-IT reachable? printprog "check presence of snipe-IT API" runcmd "curl -o /dev/null --silent https://$SNIPEIT_DOMAIN" printok "check presence of snipe-IT API" # convert json to variables, like key=value eval "$(jq -r '. | to_entries | .[] | .key + "=" + (.value | @sh)'< $sysinfofile)" printinfo "fetching variables for register $Platform at Snipe-IT" # get platform. at the moment this looks for a laptop in string. If ist not a laptop it is a desktop PC (model 2) [[ "$Platform" == *"laptop"* ]] && { model=1; display="$Displaysize @ $Resolution"; } || model=2 # clean up anydesk variable. > room for improvement, only integer should be in the var. This can be handled in the angestoepselt-info script [[ "$Anydesk_ID" == *"SERVICE_NOT_RUNNING"* ]] && unset Anydesk_ID # cannont locate issue with true and false, simple workaround to fix it [[ "$Optical_Drive" == "FALSE" ]] && Optical_Drive=nein || Optical_Drive=ja # change this variables used in this post to your needs, read the README of this repo and read ahead in the Snipe-IT API docs for more Informations # https://snipe-it.readme.io/reference/updating-custom-fields post_data() { cat < $random_tmpdir/systeminfo.json.tmp && mv $random_tmpdir/systeminfo.json.tmp $sysinfofile" printok "add PC to $sysinfofile" else printfail "$post_message" fi } script_check_root() { set -o pipefail trap ErrorHandling ERR INT printprog "check root privileges" runcmd "[ $(id -u) -eq 0 ]" printok "check root privileges" } script_check_snipesecrets() { set -o pipefail trap ErrorHandling ERR INT printprog "check .secrets.env" runcmd "[ -f $SCRIPT_DIR/.secrets.env ] && export $(cat $SCRIPT_DIR/.secrets.env)" printok "check .secrets.env" } script_prerequisites() { set -o pipefail trap ErrorHandling ERR INT printinfo "install requirements" printprog "install required packages" runcmd "sudo /usr/bin/apt-get -qq --yes install jq moreutils dialog html2ps python3 python3-pip curl wkhtmltopdf" printok "install required packages" printprog "install angestoepselt-info" runcmd "sudo /usr/bin/wget –quiet $REPO/raw/branch/master/angestoepselt-info -O /usr/local/bin/angestoepselt-info && sudo chmod +x /usr/local/bin/angestoepselt-info" printok "install angestoepselt-info" } usage() { printf "%s" "\ Usage: $0 --option Options: INFO: -h|--help print this info -v|--version show version of script -a|--all running all task below -u|--update perform an basic system update -i|--install install all packages for this system -r|--register Register PC in snipe-IT Asset Management -c|--configure running basic system config settings -d|--files_download download useful files to your HomeDirectory -m|--modify_dm paint your Desktop Manager with angestoepselt design --checkinfo Check if PC is already in snipe-IT present --clean clean up trash, like files and from system tasks like packagemanger " exit 1 } POSITIONAL_ARGS=() while [[ $# -gt 0 ]]; do case $1 in -h|--help) usage ;; -u|--update) script_check_root system_update shift shift ;; -i|--install) script_check_root system_install_base system_install_edubuntu shift shift ;; --clean) script_check_root system_clean shift shift ;; --charity) charity=${OPTARG:=angestoepselt} shift shift ;; -c|--configure) script_check_root system_configure shift shift ;; -d|--files_download) system_files_download shift shift ;; -m|--modify_dm) script_check_root system_modify_dm shift shift ;; --checkinfo) script_check_snipesecrets system_checkinfo shift shift ;; -r|--register) script_check_snipesecrets system_register shift shift ;; -a|--all) script_check_root system_update system_install system_clean system_configure system_files_download system_modify_dm script_check_snipesecrets system_checkinfo system_register exit 0 ;; -v|--version) printf '%s\n' "$0 v$version" exit 1 ;; -*|--*) echo "Unknown option $1" usage exit 1 ;; *) POSITIONAL_ARGS+=("$1") shift ;; esac done set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters if [[ -n $1 ]]; then echo "Last line of file specified as non-opt/last argument:" tail -1 "$1" fi