#!/bin/bash # name : vbox_cli-manager # desciption : shell based cli management for virtualbox on various servers # autor : speefak (itoss@gmx.de) # licence : (CC) BY-NC-SA # version : 0.2.8 #------------------------------------------------------------------------------------------------------------------------------------------------------- ############################################################################################################ ####################################### define global variables ######################################## ############################################################################################################ #------------------------------------------------------------------------------------------------------------------------------------------------------- ConfigFile=/home/user/.vbox_mgr.cfg # configure => path to config file XfreeRDPPassword="password" # configure => password from virtual box user on VM host ConfigfileMD5SumOld=$(md5sum $ConfigFile 2> /dev/null) VirtualBoxInstalledVersion=$(dpkg -l | grep virtualbox | awk '{printf $3}' | cut -d "-" -f1) CheckMark="\033[0;32m\xE2\x9C\x94\033[0m" Version=$(cat $(readlink -f $(which $0)) | grep "# version" | head -n1 | awk -F ":" '{print $2}' | sed 's/ //g') ScriptName=$(basename $(readlink -f $(which $0))) #------------------------------------------------------------------------------------------------------------------------------------------------------- ############################################################################################################ ##################################### set vars from input options ####################################### ############################################################################################################ #------------------------------------------------------------------------------------------------------------------------------------------------------- OptionVarList=" VirtualMachineManagement;-vmm HelpDialog;-? HelpDialog;-help BootVM;-b PauseVM;-pv ResumeVM;-rv HibernateVM;-h ShutdownVM;-s ResetVM;-r PowerOffVM;-p KillVM;-k RDPConnectVM;-c RDPCloseVM;-C RDPQuitVM;-q UpdateVMSpecs;-us ShowVMSpecs;-ss ListVMStatus;-ls ShowConfig;-sc NewConfig;-nc Reconfigure;-rc CheckConfig;-cc Monochrome;-m ScriptInformation;-i VMConfigSet;-vmcfg " # set entered vars from optionvarlist OptionAllocator=" " # for option seperator "=" use cut -d "=" SAVEIFS=$IFS IFS=$(echo -en "\n\b") for InputOption in $(echo " $@" | sed 's/ -/\n-/g') ; do for VarNameVarValue in $OptionVarList ; do VarName=$(echo "$VarNameVarValue" | cut -d ";" -f1) VarValue=$(echo "$VarNameVarValue" | cut -d ";" -f2) # if [[ -n $(echo " $InputOption" | grep " $VarValue" 2>/dev/null) ]]; then if [[ $InputOption == "$VarValue" ]]; then eval $(echo "$VarName"='$InputOption') # if [[ -n Option1 ]]; then echo "Option1 set";fi #eval $(echo "$VarName"="true") elif [[ $(echo $InputOption | cut -d "$OptionAllocator" -f1) == "$VarValue" ]]; then eval $(echo "$VarName"='$(echo $InputOption | cut -d "$OptionAllocator" -f 2-10)') fi done done IFS=$SAVEIFS #------------------------------------------------------------------------------------------------------------------------------------------------------- ############################################################################################################ ########################################### define functions ########################################### ############################################################################################################ #------------------------------------------------------------------------------------------------------------------------------------------------------- usage () { cat << USAGE Virtualbox Shell Manager - version $VERSION Usage: $(basename $0) [-option] virtual machine management -b(X.X) (b)oot virtual machine (hostnumber.VMnumner) -pv(X.X) (p)ause (v)irtual machine (hostnumber.VMnumner) -rv(X.X) (r)esume (v)irtual machine (hostnumber.VMnumner) -h(X.X) (h)ibernate virtual machine (hostnumber.VMnumner) -s(X.X) (s)hutdown virtual machine via acpi (hostnumber.VMnumner) -r(X.X) (r)eset virtual machine (hostnumber.VMnumner) -p(X.X) (p)oweroff virtual machine (hostnumber.VMnumner) -k(X.X) (k)ill virtual machine (hostnumber.VMnumner) -c(X.X) (c)onnect virtual machine via rdp protokoll (hostnumber.VMnumner) -C(X.X) (C)lose RDP connection (hostnumber.VMnumner) -q(X.X) (q)uit (a)ll rdp sessions configuration and information -us (u)pdate virtual machines (s)pecifications -ss (s)how virtual machines (s)pecifications -ls (X) (l)ist virtual machines (s)tatus (X=) -sc (s)how (c)onfiguration -nc (n)ew (c)onfiguration -rc (r)e(c)onfigure -cc (c)heck (c)onnections (-ls h) virtual machine configuration -vmcfg (X.X) rdp configure virtual machine (hostnumber.VMnumner) rdp functions -i show script (i)nformation" -m (m)onocrome output" toggle RDP fullscreen: Strg+Alt+Enter USAGE printf "$(tput setaf 1) $@ $(tput sgr0)\n\n" exit } #------------------------------------------------------------------------------------------------------------------------------------------------------- load_color_codes () { # parse required colours for echo/printf usage: printf "%s\n" "Text in ${Red}red${Reset}, white and ${Blue}blue${Reset}." Black='\033[0;30m' && DGray='\033[1;30m' LRed='\033[0;31m' && Red='\033[1;31m' LGreen='\033[0;32m' && Green='\033[1;32m' LYellow='\033[0;33m' && Yellow='\033[1;33m' LBlue='\033[0;34m' && Blue='\033[1;34m' LPurple='\033[0;35m' && Purple='\033[1;35m' LCyan='\033[0;36m' && Cyan='\033[1;36m' LLGrey='\033[0;37m' && White='\033[1;37m' Reset='\033[0m' BG='\033[47m' FG='\033[0;30m' # parse required colours for sed usage: sed 's/status=sent/'${Green}'status=sent'${Reset}'/g' |\ if [[ $1 == sed ]]; then for i in $(cat $0 | sed -n '/^load_color_codes/,/FG/p' | tr "&" "\n" | grep "='"); do eval $(sed 's|\\|\\\\|g' <<< $i) # sed parser '\033[1;31m' => '\\033[1;31m' done fi } #------------------------------------------------------------------------------------------------------------------------------------------------------- script_information () { printf "\n" printf " Scriptname: $ScriptName\n" printf " Version: $Version \n" printf " Location: $(pwd)/$ScriptName\n" printf " Filesize: $(ls -lh $0 | cut -d " " -f5)\n" printf "\n" exit 0 } #------------------------------------------------------------------------------------------------------------------------------------------------------- check_input_options () { #############TODO###############! check_input_options () { # create available options list InputOptionList=$(cat $ScriptFile | sed -n '/usage()/,/exit/p' | grep " -[[:alpha:]]" | awk '{print $3}' | grep "^\-") # check for valid input options for Option in $@ ; do if [[ -z $(grep -w -- "$Option" <<< "$InputOptionList") ]]; then InvalidOptionList=$(echo $InvalidOptionList $Option) fi done # print invalid options and exit script_information if [[ -n $InvalidOptionList ]]; then usage "invalid option: $InvalidOptionList" fi } ############################ testing () { # create available options list AvailableOptionList=$(cat $ScriptName | sed -n '/USAGE/,/^exit/p' | grep "^ -[[:alpha:]]" | awk -F "(" '{print $1 $2}' | awk '{print $1}' | sed 's/X\./'[[:digit:]].*'/g' | cut -d "X" -f1 ) # print echo "$AvailableOptionList" for EntreredOption in $@ ; do for AvailableOption in $AvailableOptionList ; do echo "|$EntreredOption|$AvailableOption|" if [[ ! "$EntreredOption" == "$AvailableOption" ]]; then echo $EntreredOption fi done done exit } #testing for EntreredOption in $@ ; do for AvailableOption in $InputOptionList ; do echo "|$AvailableOption|$EntreredOption|" # If/ else doesnt work , even when the expression should match #if [[ -n $(grep -- "$AvailableOption" <<< "$EntreredOption") ]]; then if [[ "$EntreredOption" == "$AvailableOption" ]]; then # "-m" == "-m" => if does not break the loop ? WHY !!!???? break fi if [[ -n $(echo " $EntreredOption" | grep " $AvailableOption" ) ]]; then break fi InvalidOptionList=$(echo -e "$InvalidOptionList \n $EntreredOption") done done InvalidOptionList=$(echo "$InvalidOptionList" | sed 's/ //g' | sort -u | tr "\n" " ") # print invalid options and exit script_information if [[ -n $InvalidOptionList ]]; then usage "invalid option: $InvalidOptionList" fi } #------------------------------------------------------------------------------------------------------------------------------------------------------- configure_dialog () { # create config file ConfigParameterList=$(cat $0 | grep -A16 "configure_dialog () {" | grep "read -e -p \" Enter" | awk -F " " '{print $NF}') # display Var input prompt and default value, enter/edit value printf "\n" # default value # varname in configfile read -e -p " Enter available hosts (user1@host1 user1@host2): " -i "${VboxHostLoginList}" VboxHostLoginList read -e -p " Enter vbox manager user: " -i "${VboxManagerSSHKeyUser:-$(whoami)}" VboxManagerSSHKeyUser read -e -p " Enter configuration file: " -i "${ConfigFile:-$HOME/.vbox_mgr.cfg}" ConfigFile read -e -p " Enter VM specifications storage file: " -i "${VmSpecListFile:-$HOME/.vbox_mgr_vm_specs.list}" VmSpecListFile read -e -p " Enter connection timeout (seconds): " -i "${SSHCheckConnectionTimeout:-10}" SSHCheckConnectionTimeout if [[ -z $XfreeRDP ]] && [[ -z $(which xfreerdp) ]]; then XfreeRDP="not found, please install xfreerdp" fi read -e -p " Enter xfreerdp path: " -i "${XfreeRDP:-$(which xfreerdp)}" XfreeRDP read -e -p " Enter screen resolution: " -i "${ScreenRes:-1650x900x32}" ScreenRes # print new Vars printf "\n new configuration values: \n\n" for i in $ConfigParameterList; do echo " $i=\""$(eval echo $(echo "$"$i))\" done # check for existing config file if [[ -s $ConfigFile ]]; then printf "\n" read -e -p " overwrite existing configuration (y/n) " -i "y" OverwriteConfig if [[ $OverwriteConfig == [yY] ]]; then rm $ConfigFile else sed -i '/Reconfigure=true/d' $ConfigFile sed -i '/CreateNewConfig=true/d' $ConfigFile printf "\n existing configuration :\n\n" cat $ConfigFile exit fi fi # write Vars to config file for i in $ConfigParameterList; do echo "$i=\""$(eval echo $(echo "$"$i))\" >> $ConfigFile done printf " configuration saved in: $ConfigFile\n\n" sed -i "s|^ ConfigFile=.*| ConfigFile=$ConfigFile|" $(readlink -f $0) $HOME/.vbox_mgr.cfg #check for first run chmod 600 $ConfigFile # check for configuration changes if [[ ! $(md5sum $ConfigFile) == $ConfigfileMD5SumOld ]]; then printf "$(tput setaf 1) configuration changed - please update VM specs: $(tput sgr0)\n" printf "$(tput setaf 2) ( $0 -us ) $(tput sgr0)\n\n" else printf "$(tput setaf 3) no configuration changes $(tput sgr0)\n\n" fi } #------------------------------------------------------------------------------------------------------------------------------------------------------- set_vm_vars_from_configfileline () { # usage: set_vm_vars_from_configfileline # load processingline from config file ProcccessingLine=$(grep "^$1" <<< $VmSpecList) if [[ -n $ProcccessingLine ]]; then # set processing vars for Var in User=2 Host=3 VMID=4 RDPPort=5 CPU=6 RAM=7 OS=8 VMName=9 VMDisk=10 VMDiskSize=11 ;do VarName=$( cut -d "=" -f1 <<< $Var) ConfigfileField=$( cut -d "=" -f2 <<< $Var) eval $VarName=\"$(echo $ProcccessingLine | cut -d "|" -f$ConfigfileField)\" done VarLoadError=0 else printf "$(tput setaf 1)virtual machine $1 not found$(tput sgr0)\n" VarLoadError=1 fi } #------------------------------------------------------------------------------------------------------------------------------------------------------- check_config () { if [[ -s $ConfigFile ]] && [[ -z $(cat $ConfigFile | grep "Reconfigure=true\|CreateNewConfig=true") ]]; then # read config file source $ConfigFile elif [[ -s $ConfigFile ]] && [[ -n $(cat $ConfigFile | grep "Reconfigure=true") ]]; then # read config and reconfigure source $ConfigFile configure_dialog elif [[ ! -s $ConfigFile ]] || [[ -n $(cat $ConfigFile | grep "CreateNewConfig=true") ]]; then # create new config file rm $ConfigFile &> /dev/null configure_dialog exit fi } #------------------------------------------------------------------------------------------------------------------------------------------------------- check_execution_user () { # check execution user if [ ! "$(whoami)" = "$VboxManagerSSHKeyUser" ]; then printf "$(tput setaf 1) SSH key authentication user required $VboxManagerSSHKeyUser. You are $(whoami) \n$(tput sgr0)" exit 1 fi } #------------------------------------------------------------------------------------------------------------------------------------------------------- host_connection_check () { # VboxHostLogin var has to be set host_connection_check_thread () { Host=$(echo $VboxHostLogin | cut -d "@" -f2) Host=${Host/127.0.0.1/localhost} User=$(echo $VboxHostLogin | cut -d "@" -f1) # check for local execution on same user, no ssh connection required if [[ -n $( grep localhost <<< "$VboxHostLogin") ]]; then if [[ ! $User == $(whoami) ]]; then printf "$(tput setaf 1)unknown vbox user on local machine$(tput sgr0)" return fi HostVMListDetails=$(for i in $(VBoxManage list vms ) ; do vboxmanage showvminfo $i 2>> /dev/null ; done && echo VirtualHarddisks: && VBoxManage list hdds) if [[ $? == 0 ]]; then printf "$(tput setaf 2)online$(tput sgr0)" else printf "$(tput setaf 1)unknown error$(tput sgr0)" fi # check SSH connection to destination host else SSHCheckConnectionTimeout=2 CMDTimeout=$(($SSHCheckConnectionTimeout+1)) SSHOutoutLogfile="/tmp/.vbx-ssh.log" echo > $SSHOutoutLogfile timeout $CMDTimeout ssh -v -o ConnectTimeout=$SSHCheckConnectionTimeout $VboxHostLogin -E $SSHOutoutLogfile 2>&1 exit #TODO => use ssh return values for error output => https://support.microfocus.com/kb/doc.php?id=7021696 SSHOutputV="$(cat $SSHOutoutLogfile)" if [[ -n $(grep "No route to host" <<< $SSHOutputV) ]] ; then printf "$(tput setaf 1)offline, host unreachable$(tput sgr0)" elif [[ -n $(grep "Connection established" <<< $SSHOutputV) ]] ; then printf "$(tput setaf 2) online$(tput sgr0)" if [[ -n $(grep "Authenticated to $Host" <<< $SSHOutputV) ]] ; then printf ",$(tput setaf 2) authentication ok $CheckMark$(tput sgr0)" elif [[ -n $(grep "Next authentication method: password" <<< $SSHOutputV | tail -n 1) ]] ; then printf ",$(tput setaf 1) authentication failed (ssh key) $(tput sgr0)" elif [[ -n $(grep "Connection refused" <<< $SSHOutputV | tail -n 1) ]] ; then printf ",$(tput setaf 1) authentication error$(tput sgr0)" fi else printf "$(tput setaf 1)Unknown error$(tput sgr0)" fi fi } # check all hosts from config file if [[ $1 == ALL ]]; then for VboxHostLogin in $VboxHostLoginList ; do HostNumber=$(echo "$VboxHostLoginList" | tr " " "\n" | nl | grep -w "$VboxHostLogin" | awk '{print $1}') printf "Connection check for host #$HostNumber $VboxHostLogin: " | awk -F ":" '{printf " %-65s %s %s ",$1, $2, $3}' host_connection_check_thread printf "\n" done else host_connection_check_thread fi } #------------------------------------------------------------------------------------------------------------------------------------------------------- list_VM_status () { AvailableHosts=$(echo "$VboxHostLoginList" | tr " " "\n" | nl |sed 's/^[[:blank:]]*//') # create specific hostlist ( -ls &2 printf "$(tput setaf 1)|No virtual machines detected $(tput setaf 3)| update virtual machine specs: $0 -us|\n $(tput sgr0)" |\ awk -F "|" '{printf "\n%s %-47s %s ",$1, $2, $3}' >&2 continue else printf "|VMs on Host $HostNumber ($VboxHostLogin): |" | awk -F "|" '{printf "\n%s %-42s %s ",$1, $2, $3}' >&2 fi #TODO count calculate max caracter count for $VboxHostLogin VMName auto adjust slot width count VboxHostLogin SlotWidthCountVboxHostLogin=$(echo "$VmSpecList" | cut -d "|" -f3 | sed 1d | sort -u | awk '{ print length, $2 }' | sort -n | tail -1) SlotWidthCountVMName=$(echo "$VmSpecList" | grep -v "|||" | cut -d "|" -f9 | sed 1d | sort -u | awk '{ print length, $2 }' | sort -n | tail -1) ## Create HostVMList # create virtual machine list from local host if [[ $Host == "localhost" ]]; then if [[ ! $User == $(whoami) ]]; then printf "$(tput setaf 1) unknown user on local machine$(tput sgr0)\n" >&2 continue fi HostVMList=$(VBoxManage list vms && echo running vms: && VBoxManage list runningvms) HostVMListCMDExitCode=$? # create virtual machine list from remote host else HostVMList=$(timeout $SSHCheckConnectionTimeout ssh $VboxHostLogin "VBoxManage list vms && echo running vms: && VBoxManage list runningvms" 2>/dev/null ) HostVMListCMDExitCode=$? fi # if host is unreachable run host connection check if [[ ! $HostVMListCMDExitCode == 0 ]]; then HostConnectionCheckOutput=$(host_connection_check $VboxHostLogin) printf "$HostConnectionCheckOutput\n" >&2 # create virtual machine list from local VmSpecList HostVMList=$(echo "$VmSpecList" | grep "$Host" |sed '1d' | awk -F "|" '{printf "\"%s\" {%s}\n", $9 , $4}') else printf "$(tput setaf 2)host connected$(tput sgr0)\n" >&2 HostConnectionCheckOutput= fi ## Create HostVMList completed # proccess HostVMList for function output SAVEIFS=$IFS IFS=$(echo -en "\n\b") HostVMRunIDList=$(echo "$HostVMList" | grep -A50 "running vms:" | awk '{print $NF}' | sed '1,1d' ) HostVMRunIDList=${HostVMRunIDList:-none} for VM in $HostVMList; do # skip extra output for running vm entires in HostVMList, entries are used to mark running vms from HostVMList if [[ -n $(echo $VM| grep "running vms:") ]]; then break fi VMName=$(echo $VM | cut -d '"' -f2) VMID=$(echo $VM | cut -d '"' -f3 | sed 's/ {//g' | tr -d "}") # create VM status entry ( running vms ) for RunningVMID in $HostVMRunIDList ;do VMStatus="$(tput setaf 1) Offline $(tput sgr0)" if [[ $(echo $VM | grep "$RunningVMID") ]]; then VMStatus="$(tput setaf 2) Online $(tput sgr0)" break fi done if [[ -n $HostConnectionCheckOutput ]]; then VMStatus="$(tput setaf 1) Unkown $(tput sgr0)" fi VMNumber=$(echo "$VmSpecList" | grep $VMID | awk -F "|" '{print $1 }'| head -n1) echo "|$VMNumber|$VMName|$VboxHostLogin|$VMID|$VMStatus|" done IFS=$SAVEIFS #printf "Nr.|Virtual Machine Name|Host|ID|Status|\n" done | awk -F "|" '{printf " %-4s %-38s %-20s %s %s %s %s \n", $2, $3, $4, $5, $6, $8, $7}' printf "\n" } #------------------------------------------------------------------------------------------------------------------------------------------------------- update_vm_specifications () { echo "specs updated on $(date +%s)" > $VmSpecListFile chmod 600 $VmSpecListFile # load vm specs from all hosts for VboxHostLogin in $VboxHostLoginList ; do HostCounter=${HostCounter:-0} HostCounter=$(($HostCounter+1)) Host=$(echo $VboxHostLogin | cut -d "@" -f2) User=$(echo $VboxHostLogin | cut -d "@" -f1) printf "\n%-70s" " updating virtual machine specifications from $VboxHostLogin" >&2 CMDTimeout=$(($SSHCheckConnectionTimeout+1)) # get host vm information details - local execution - no ssh connection required if [[ -n $( grep localhost <<< "$VboxHostLogin") ]]; then # check for correct user on local machine if [[ ! $User == $(whoami) ]]; then host_connection_check $VboxHostLogin >&2 continue fi HostVMListDetails=$(for i in $(VBoxManage list vms ) ; do vboxmanage showvminfo $i 2>> /dev/null ; done && echo VirtualHarddisks: && VBoxManage list hdds) if [[ $? == 0 ]]; then printf "$(tput setaf 2)done$(tput sgr0)" >&2 else printf "$(tput setaf 1)unknown error$(tput sgr0)" >&2 fi # get host vm information details - ssh connection required else HostVMListDetails=$(timeout $CMDTimeout ssh $VboxHostLogin 2>/dev/null \ '''for i in $(VBoxManage list vms ) ; do vboxmanage showvminfo $i 2>> /dev/null ; done && echo VirtualHarddisks: && VBoxManage list hdds ''') # if host is offline run single connection check and quit loop if [[ ! $? == 0 ]]; then UpdateSpecsErrorMSG=UpdateSpecsError host_connection_check $VboxHostLogin >&2 else printf "$(tput setaf 2)done$(tput sgr0)" >&2 fi fi printf "\n$HostCounter.0||||||||Virtual Machines located on: $VboxHostLogin $UpdateSpecsErrorMSG\n" UpdateSpecsErrorMSG= # Filter VM parameter VMUUIDList=$(echo "$HostVMListDetails" | grep -A4 "^Name:" | grep UUID: | awk '{print $2}') SAVEIFS=$IFS IFS=$(echo -en "\n\b") VMNumber=0 for VMUUID in $VMUUIDList ; do VMNumber=$(($VMNumber+1)) VMName=$(echo "$HostVMListDetails" | grep -B4 $VMUUID | grep "Name:" | awk '{print $2}') GuestOS=$(echo "$HostVMListDetails" | grep -B1 $VMUUID | grep "Guest OS:" | awk '{print $3,$4}' | sed 's/ //') VMCPU="$(echo "$HostVMListDetails" | grep -A100 $VMUUID | grep "CPU exec cap:" | awk '{print $4}')%" VMRAM=$(echo "$HostVMListDetails" | grep -A100 $VMUUID | grep "Memory size" | awk '{print $3}') VMNet=$(echo "$HostVMListDetails" | grep "NIC 1: MAC:" | awk '{print $3}') # not needed VMGuiRes=$(echo "$HostVMListDetails" | grep -A100 $VMUUID | grep "Video mode:" | awk '{print $3}') # value only if vm runs, RDPPort=$(echo "$HostVMListDetails" | grep -A150 $VMUUID | grep "VRDE port:" | awk '{print $3}') # VBox 6.x if [[ -z $RDPPort ]]; then RDPPort=$(echo "$HostVMListDetails" | grep -A150 $VMUUID | grep "VRDE property .* : TCP/Ports = " | awk '{print $NF}' | tr -d '"') # VBox 5.X fi RDPPort=${RDPPort:- none} # write new line for each virtual disk VMDiskPathAll=$(echo "$HostVMListDetails" | grep -A100 $VMUUID | grep "vmdk\|vdi" | awk -F ": " '{print $2}' | sed 's/ (UUID.*$//' ) for VMDiskPath in $VMDiskPathAll ; do VMDiskSize="$(echo "$HostVMListDetails" | grep -A100 "VirtualHarddisks:" | grep -A2 $VMDiskPath | grep "Capacity" | awk '{print $2}')MB" printf "$HostCounter.$VMNumber|$User|$Host|$VMUUID|:$RDPPort|$VMCPU|$VMRAM|$GuestOS|$VMName|$VMDiskPath|$VMDiskSize|\n" done done IFS=$SAVEIFS done >> $VmSpecListFile printf "\n\n" } #------------------------------------------------------------------------------------------------------------------------------------------------------- show_vm_specifications () { # 1 2 3 4 5 6 7 8 9 10 11 (echo "Nr.| User|Host | UUID| RDP| CPU| RAM| OS|VM-Name|VM-Disk-Path| Disk" && echo "$VmSpecList" | grep -v "specs updated on") \ | awk -F "|" '{printf " %3-s %-38s %20s%s %-8s %-15s %5s %8s %10s %-37s %s %s \n",$1, $9, $3, $5, $2, $8, $6, $7, $11, $4, $10 ,$1}' printf "\n last update: $(date -d @$(echo $(echo "$VmSpecList" | grep 'specs updated on ') | awk -F 'specs updated on ' '{printf $NF}'))\n" } #------------------------------------------------------------------------------------------------------------------------------------------------------- parse_numeric_processing_input () { # usage: parse_numeric_processing_input <1.1|1-X.1-X> proccessing_vm_input () { VMs=$( cut -d "." -f2 <<< $HostVMProcessing) # processing vms if [[ -n $(grep "-" <<< $VMs) ]]; then for VMs in $(seq $(sed 's/-/ /' <<< $VMs)); do printf "$Host.$VMs\n" done else printf "$Host.$VMs\n" fi } # proccessing input options for HostVMProcessing in $( tr " " "\n" <<< $@) ; do Host=$( cut -d "." -f1 <<< $HostVMProcessing) # processing hosts if [[ -n $(grep "-" <<< $Host) ]]; then for Host in $(seq $(sed 's/-/ /' <<< $Host) | tr "\n" " "); do proccessing_vm_input done else proccessing_vm_input fi done } #------------------------------------------------------------------------------------------------------------------------------------------------------- proccessing_vm_control_options () { for VMControlOption in -b -rv -pv -r -h -s -p -c -C -q ; do # read option line OptionProccessingSyntax=$(echo $@ | sed 's/ -/ \n-/g'| grep '\'$VMControlOption'[0-9]' | cut -c 3-100 | tr -d [[:alpha:]]) # check for correct numeric input if [[ -n $(grep [[:alpha:]] <<< $OptionProccessingSyntax) ]]; then printf "Syntax error for option: $VMControlOption$OptionProccessingSyntax\n" >&2 continue elif [[ -n $(grep "\." <<< $OptionProccessingSyntax) ]] && [[ -n $(echo " $OptionProccessingSyntax" | grep '\'$VMControlOption) ]]; then printf "\n$(tput setaf 1)Error: Virtual machine $HostVMNumner not found$(tput sgr0)" >&2 continue elif [[ -n $(echo $OptionProccessingSyntax | grep "\.0" ) ]]; then printf "\n$(tput setaf 1)Error: $OptionProccessingSyntax is a Host$(tput sgr0)" >&2 continue elif [[ -n $(echo $OptionProccessingSyntax | grep "^0\." ) ]]; then printf "\n$(tput setaf 1)Error: $OptionProccessingSyntax is not a Host$(tput sgr0)" >&2 continue elif [[ -n $(echo $OptionProccessingSyntax | grep "0-" ) ]]; then printf "\n$(tput setaf 1)Error: $OptionProccessingSyntax is not a Host$(tput sgr0)" >&2 continue fi # parse multi inputs for single processing and load var for each selected VM Number for further proccessing | clear for 0.0 input #for HostVMNumner in $(parse_numeric_processing_input "$OptionProccessingSyntax" | sed '/.0/d' | sed '/0./d') ; do #X.10 does not work for HostVMNumner in $(parse_numeric_processing_input "$OptionProccessingSyntax" ) ; do set_vm_vars_from_configfileline $(parse_numeric_processing_input "$HostVMNumner") if [[ $VarLoadError == 1 ]]; then continue fi # connect VBOX host, execute command if [[ $VMControlOption == "-b" ]]; then printf " start virtual machine: $VMName\n" ssh $User@$Host -t -t vboxmanage startvm --type headless $VMID fi # connect VBOX host, execute command if [[ $VMControlOption == "-h" ]]; then printf " hibernate virtual machine: $VMName\n" ssh $User@$Host -t -t vboxmanage controlvm $VMID savestate fi # connect VBOX host, execute command if [[ $VMControlOption == "-pv" ]]; then printf " pause virtual machine: $VMName\n" ssh $User@$Host -t -t vboxmanage controlvm $VMID pause fi # connect VBOX host, execute command if [[ $VMControlOption == "-rv" ]]; then printf " resume virtual machine: $VMName\n" ssh $User@$Host -t -t vboxmanage controlvm $VMID resume fi # connect VBOX host, execute command if [[ $VMControlOption == "-s" ]]; then printf "shutdown (acpi) virtual machine: $VMName\n" ssh $User@$Host -t -t vboxmanage controlvm $VMID acpipowerbutton fi # connect VBOX host, execute command if [[ $VMControlOption == "-r" ]]; then printf " reset off virtual machine: $VMName\n" ssh $User@$Host -t -t vboxmanage controlvm $VMID reset fi # connect VBOX host, execute command if [[ $VMControlOption == "-p" ]]; then printf " power off virtual machine: $VMName\n" ssh $User@$Host -t -t vboxmanage controlvm $VMID poweroff fi # connect VBOX host, execute command if [[ $VMControlOption == "-k" ]]; then printf " kill virtual machine: $VMName\n" ssh $User@$Host -t -t VBoxManage startvm $VMID --type emergencystop fi # processing options if [[ $VMControlOption == "-c" ]]; then printf " connect virtual machine via rdp protokoll: $VMName\n" printf " execute => xfreerdp -u $User -p V\!rtlMchn -g $ScreenRes -T $VMName @ $Host$RDPPort ($User) $Host$RDPPort & \n" # xfreerdp -u $User -p V\!rtlMchn -g $ScreenRes -T "$VMName @ $Host$RDPPort ($User)" $Host$RDPPort # Temporary file to store the command's output local output_file=$(mktemp) # Run xfreerdp in the background and redirect output to the temporary file xfreerdp -u "$User" -p "$XfreeRDPPassword" -g "$ScreenRes" -T "$VMName @ $Host$RDPPort ($User)" "$Host$RDPPort" > "$output_file" 2>&1 & # Save the background process PID local pid=$! # Small delay to capture potential error messages sleep 1 # Check if the background process is still running # if grep -q "Do you trust the above certificate?" "$output_file"; then # check only for certificate error if ! kill -0 "$pid" 2>/dev/null; then echo "An error occurred. Starting xfreerdp in the foreground..." # Re-run the command in the foreground to allow interactive input xfreerdp -u "$User" -p "$XfreeRDPPassword" -g "$ScreenRes" -T "$VMName @ $Host$RDPPort ($User)" "$Host$RDPPort" else echo "Command started successfully in the background. Process ID: $pid" fi # Remove the temporary file rm -f "$output_file" fi # processing options if [[ $VMControlOption == "-C" ]]; then printf " close RDP connection : $VMName\n " #ssh $User@$Host -t -t vboxmanage controlvm $VMID poweroff # connect VBOX host, execute command_check fi # processing options if [[ $VMControlOption == "-q" ]]; then printf " (q)uit (a)ll rdp sessions: $VMName\n " #ssh $User@$Host -t -t vboxmanage controlvm $VMID poweroff # connect VBOX host, execute command_check fi done done #echo "---------------------------------------------" #echo "|$Host|$User|$VMID|$RDPPort|$CPU|$RAM|$OS|$VMName|$VMDisk|$VMDiskSize|" #echo "---------------------------------------------" printf "\n" } #------------------------------------------------------------------------------------------------------------------------------------------------------- ############################################################################################################ ############################################# start script ############################################# ############################################################################################################ #------------------------------------------------------------------------------------------------------------------------------------------------------- # check_input_options $@ #TODO if expressions does execute even if expressions match "-m" == -m" #------------------------------------------------------------------------------------------------------------------------------------------------------- check_config #------------------------------------------------------------------------------------------------------------------------------------------------------- check_execution_user #------------------------------------------------------------------------------------------------------------------------------------------------------- # check for monochrome output Reset='\033[0m' if [[ -z $Monochrome ]]; then load_color_codes fi #------------------------------------------------------------------------------------------------------------------------------------------------------- # check help dialog if [[ -z "$1" ]] || [[ -n "$HelpDialog" ]] ; then usage "help dialog" ; fi #------------------------------------------------------------------------------------------------------------------------------------------------------- # check for script information if [[ -n $ScriptInformation ]]; then script_information ; fi #------------------------------------------------------------------------------------------------------------------------------------------------------- ############################################################################################################ ############################################# check config ############################################# ############################################################################################################ # load virtual machine specs to var VmSpecList=$(cat "$VmSpecListFile") #------------------------------------------------------------------------------------------------------------------------------------------------------- # processing main configuration options if [[ -n $NewConfig ]]; then printf "$(tput setaf 3) Create new configuration$(tput sgr0)" rm $ConfigFile &> /dev/null sleep 0.2 $0 - exit fi if [[ -n $Reconfigure ]]; then printf "$(tput setaf 3) Start reconfiguration:$(tput sgr0)" echo "Reconfigure=true" >> $ConfigFile check_config fi if [[ -n $ShowConfig ]]; then printf "$(tput setaf 3) Configfile ($ConfigFile) content: \n$(tput sgr0)" cat $ConfigFile printf "\n"ConfigLine fi if [[ -n $CheckConfig ]] || [[ -n $(grep h <<< $ListVMStatus) ]]; then printf "$(tput setaf 3) Start host connection check: \n$(tput sgr0)" host_connection_check ALL fi if [[ -n $UpdateVMSpecs ]]; then printf "$(tput setaf 3) Start virtual machine spec update: $(tput sgr0)" update_vm_specifications fi if [[ -n $ShowVMSpecs ]]; then show_vm_specifications fi if [[ -n $ListVMStatus ]] && [[ ! $(grep h <<< $ListVMStatus) ]]; then list_VM_status fi #------------------------------------------------------------------------------------------------------------------------------------------------------- # processing VM specific configuration options if [[ -n $VMConfigSet ]]; then printf "$(tput setaf 3) Start virtual machine configuration mode\n$(tput sgr0)" # check for correct input VM Number VMConfigSetCommand=$(echo "$VMConfigSet" | tr " " "\n" | grep -v [[:digit:]] ) VMConfigSetProcessingHosts=$(echo "$VMConfigSet" | sed 's/'$VMConfigSetCommand'//' 2> /dev/null) # check for input command if [[ $? == 1 ]]; then usage " missing command: $(echo "$@") " elif [[ -z $VMConfigSetProcessingHosts ]]; then usage " missing virtual machine: -vmcfg $VMConfigSetCommand " fi ConfigLine # parse multi inputs for single processing and load var for each selected VM number for further proccessing | clear for 0.0 input #for HostVMNumner in $(parse_numeric_processing_input "$VMConfigSetProcessingHosts" | sed '/.0/d' | sed '/0./d') ; do for HostVMNumner in $(parse_numeric_processing_input "$VMConfigSetProcessingHosts" ) ; do set_vm_vars_from_configfileline $(parse_numeric_processing_input "$HostVMNumner") # skip proccessing loop when error occurs if [[ $VarLoadError = 1 ]]; then continue fi # get virtual machines status - one/first time run if [[ -z $GetVMStatus ]]; then printf "$(tput setaf 3) Check virtual machine status \n$(tput sgr0)" VMStatusList=$(list_VM_status 2>&1) GetVMStatus=done fi ProcccessingVMLine=$(echo "$VMStatusList" | grep $VMID) # check for running virtual machine if [[ -n $(echo "$ProcccessingVMLine" | grep Online) ]]; then printf "\n$(tput setaf 1) Virtual machine is running, shutdown for configuration \n$(tput sgr0)" printf "$ProcccessingVMLine\n" continue fi # configure vm remote desktop paramerter | infosource : https://www.virtualbox.org/manual/ch07.html if [[ $VMConfigSetCommand == rdp ]]; then # configure vrdp parameter RDPport=$(($(echo 10"$(echo $HostVMNumner | cut -d "." -f1)00")+$(echo $HostVMNumner | cut -d "." -f2))) RDPServerListenAddress=$(ssh $User@$Host hostname -I) # 0.0.0.0 to accept all connections, security risk Executelist_VM_status=true ConfigLine="--vrde on --vrdeauthtype external --vrdeaddress $RDPServerListenAddress --vrdeport $RDPport" printf "\n$(tput setaf 3) Set configuration:$(tput sgr0) vboxmanage modifyvm $VMID $ConfigLine\n" printf "$ProcccessingVMLine\n" # enable / set vrdp functions printf " execute => ssh $User@$Host -t -t vboxmanage modifyvm $VMID $ConfigLine 2> /dev/null \n" ssh $User@$Host -t -t vboxmanage modifyvm $VMID $ConfigLine 2> /dev/null fi done printf "\n update virtual machines specifications to apply changes ( $(basename $0) -us )" fi #------------------------------------------------------------------------------------------------------------------------------------------------------- proccessing_vm_control_options $@ # to do -b 2.3 4.4 doenst work => works -b2.3 4.4 #------------------------------------------------------------------------------- ------------------------------------------------------------------------ exit 0 #------------------------------------------------------------------------------------------------------------ ############################################################################################################ ########################################## changelog / notice ########################################### ############################################################################################################ #------------------------------------------------------------------------------------------------------------ # Configure Virtualbox Host for RDP connection, execute directly on host: ##################################################################################################### # => ConfigLine="--vrde on --vrdeauthtype external --vrdeaddress 192.168.1.80 --vrdeport 10000" # => vboxmanage list vms # => vboxmanage modifyvm 6047df41-7c93-43f2-9dac-0de61e35f16d $ConfigLine ##################################################################################################### # known issues : # # RDP connection failure solutions : # - Is RDP connection in VM configs enabled ? # - Is RDP connection for non local connecntion available ( Display => Remote desktop server port => LAN IP instead 127.0.0.1 ) # => VBoxManage modifyvm "[VM_NAME]" --vrdeaddress [0.0.0.0|LAN_IP|$(hostname -I)] # create vbox internal rdp user => https://www.marcomadeit.com/2017/02/26/set-user-authentication-in-virtualbox-remote-desktop-rdp/ # => https://docs.oracle.com/en/virtualization/virtualbox/6.1/admin/vrde.html # => https://github.com/phpvirtualbox/phpvirtualbox/issues/31