Tuesday, April 14, 2020

BASH Concatenate Exampls

The simplest way to concatenate two or more string variables is to write them one after another:
VAR1="Hello,"
VAR2=" World"
VAR3="$VAR1$VAR2"
echo "$VAR3"
The last line will echo the concatenated string:
Hello, World
You can also concatenate one or more variable with literal strings:
VAR1="Hello, "
VAR2="${VAR1}World"
echo "$VAR2"

  Hello, World
Copy1
In the example above variable VAR1 is enclosed in curly braces to protect the variable name from surrounding characters. When the variable is followed by another valid variable-name character you must enclose it in curly braces ${VAR1}.
Always try to use double quotes around the variable name. If you want to suppress variable interpolation and special treatment of the backslash character instead of double use single quotes.
Bash does not segregate variables by “type”, variables are treated as integer or string depending on contexts. You can also concatenate variables that contain only digits.
VAR1="Hello, "
VAR2=99
VAR3=" Worlds"
VAR4="$VAR1$VAR2$VAR3"
echo "$VAR4"
Copy1
Hello, 99 Worlds
Copy1
Concatenating Strings with the += Operator
Another way of concatenating strings in bash is by appending variables or literal strings to a variable using the += operator:
VAR1="Hello,"
VAR1+="World"
echo "$VAR1"
Copy1
Hello,World
Copy1
Copy
The following example is using the += operator to concatenate strings in bash for loop:
VAR=""
for combination in 'abc' 'def' 'ghi' 'jkl'; do
  VAR+="${combination} "
done
echo "$VAR"
Copy1
abc def ghi jkl
Copy1
Copy


BASH exit codes

What are exit codes?

On Unix and Linux systems, programs can pass a value to their parent process while terminating. This value is referred to as an exit code or exit status, 0 for successful executions and 1 or higher for failed executions.
#!/bin/bash
touch /root/test
echo created file

The above sample script will execute both the 
touch command and the echo command. When we execute this script (as a non-root user) the touch command will fail, ideally since the touch command failed we would want the exit code of the script to indicate failure with an appropriate exit code. To check the exit code we can simply print the $? special variable in bash. This variable will print the exit code of the last run command.
$ ./tmp.sh 
touch: cannot touch '/root/test': Permission denied
created file
$ echo $?
0
After running the command ./tmp.sh the exit code was 0 which indicates success, even though the touch command failed. The sample script runs two commands touch and echo, since we did not specify an exit code the script exits with the exit code of the last run command. In this case, the last run command is the echo command, which did execute successfully.

#!/bin/bash
touch /root/test
If we remove the echo command from the script we should see the exit code of the touch command.

$ ./tmp.sh 
touch: cannot touch '/root/test': Permission denied
$ echo $?
1

As you can see, since the last command run was touch the exit code reflects the true status of the script; failed.

Using exit codes in bash scripts

While removing the echo command from our sample script worked to provide an exit code, what happens when we want to perform one action if the touch was successful and another if it was not. Actions such as printing to stdout on success and stderr on failure.
Earlier we used the $? special variable to print the exit code of the script. We can also use this variable within our script to test if the touch command was successful or not.

#!/bin/bash

touch /root/test 2> /dev/null

if [ $? -eq 0 ]
then
  echo "Successfully created file"
else
  echo "Could not create file" >&2
fi

In the above revision of our sample script; if the exit code for touch is 0 the script will echo a successful message. If the exit code is anything other than 0 this indicates failure and the script will echo a failure message to stderr.
$ ./tmp.sh
Could not create file
Providing your own exit code
While the above revision will provide an error message if the touch command fails, it still provides a 0 exit code indicating success.
$ ./tmp.sh
Could not create file
$ echo $?
0
Since the script failed, it would not be a good idea to pass a successful exit code to any other program executing this script. To add our own exit code to this script, we can simply use the exit command.
#!/bin/bash touch /root/test 2> /dev/null if [ $? -eq 0 ] then echo "Successfully created file" exit 0 else echo "Could not create file" >&2 exit 1 fi
With the exit command in this script, we will exit with a successful message and 0 exit code if the touch command is successful. If the touch command fails however, we will print a failure message to stderr and exit with a 1 value which indicates failure.
$ ./tmp.sh Could not create file $ echo $? 1
Command line exit codes
Now that our script is able to tell both users and programs whether it finished successfully or unsuccessfully we can use this script with other administration tools or simply use it with bash one liners.
$ ./tmp.sh && echo "bam" || (sudo ./tmp.sh && echo "bam" || echo "fail") Could not create file Successfully created file bam
The above grouping of commands use what is called list constructs in bash. List constructs allow you to chain commands together with simple && for and and || for or conditions. The above command will execute the ./tmp.sh script, and if the exit code is 0 the command echo "bam" will be executed. If the exit code of ./tmp.sh is 1 however, the commands within the parenthesis will be executed next. Within the parenthesis the commands are chained together using the && and || constructs again.
The list constructs use exit codes to understand whether a command has successfully executed or not. If scripts do not properly use exit codes, any user of those scripts who use more advanced commands such as list constructs will get unexpected results on failures.
The exit command in bash accepts integers from 0 - 255, in most cases 0 and 1 will suffice however there are other reserved exit codes that can be used for more specific errors. 

Some BASH commands that might be helpful

These are some BASH commands that I use from time to time that help me

Using EVAL to send commands to CLI

In this example, i was trying to send some bash commands to asterisk, but the asterisk syntax wouldn't accept a variable, so i had to run it as a EVAL command
command="asterisk -rx 'sip show peer "$extensionnumber"' | grep Useragent >> /etc/temp.dat"
eval "$command"


So the command is a variable, and everything in quotes gets saved to that variable
Then "EVAL" runs that variable, and all the commands inside it.

Also I wasn't able to reliably work out how to save the output of EVAL to a variable, so i was forced to save it to a temporary file, 'temp.dat'


Checking for variable for Interger value in BASH

If you are looking for a way to check if a variable is integer value heres some code
if expr "$number" : '-\?[0-9]\+$' >/dev/null
      then
         echo "$number is an integer"
      else
         echo "$number is not an integer"
         continue
if

Check if integer variable is between a range of low/high values

if [ "$number" -le "$HighValue" ] && [ "$number" -ge "$LowValue" ]
        then
                echo "$number IN RANGE";
        else
                echo "$number OUT OF RANGE"
                continue
fi

Grep something based on object stored in a variable
So we have a variable with some item(s) that we want to match for
Find everything that matches these values
#if multiple use "'Find1Name\|Find2Name'" and use the \| as a separatorFind="'Find1Name'"
SOMECOMMAND | grep "$Find" 
Find everything that DOES NOT matches these values

#if multiple use "'Find1Name\|Find2Name'" and use the \| as a separator
Find="'Find1Name'"
SOMECOMMAND | grep -v "$Find" 

data="/pathto/filename"
while IFS= read -r lineread
do
  echo "$lineread"
done < "$data"

Use GREP to return a TRUE or FALSE 
if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

Bash Script Sleep or Delay a Specified Amount of Time

s
 for seconds (the default)
m for minutes.
h for hours.
d for days.
sleep 5
sleep 2m
sleep 3h
read -p "Waiting five secs for no reason before continuing...." -t 5
fi





Asterisk - block SIP registrations from unapproved devices

Ok, so maybe you want to limit the types of devices that connect.
This isn't perfect, only works for SIP on asterisk (not PJSIP yet)

its not so much the program that i"m posting here, as much as it is the bash script code that I wanted to remind myself how to do.

basically this bash script, if you kick it off will scan SIP extensions in asterisk, pull out their types an then ban the IP of any that aren't valid based on your criteria

So script kicks off, removes any previous known IPS that it would have blocked,
waits a few minutes based on your script input then, re-runs itself.  The pause lets users who might have been banned the chance to reconnect with approved devices.

#!/bin/bash
 
#temp directory and filename.
TempFileNameAndPath="/etc/asterisk/disallowedextensions.txt"
 
#this is the ALLOWED devices in your system
#if you just one, use "'DeviceName'"
#if multiple use "'Device1Name\|Device2Name'" and use the \| as a seperator
 
alloweddevices="'Bria'"
 
#number of minutes to pause after previous firewall bans are removed to allow new extensions to try and reconnect
pauseminute=0
 
#This lets you set an extension range that would be affected.
#for testing, set both values to match your test extension
 
lowestextension=3151
highestextension=3151
 
#this code removes any previous blocks the script put in.
sipphonesANDip="$TempFileNameAndPath"
while IFS= read -r line
        do
        extensionIP="$(cut -d' ' -f2 <<<"$line")"
        FirewallCommand="fwconsole firewall del blacklist "$extensionIP""
        eval "$FirewallCommand"
done < "$sipphonesANDip"
 
#delete the temp file, as we've cleared all users from firewall.
rm $TempFileNameAndPath
 
#pause script for X minutes.  This will allow anyone who have been blocked by this script to get time to reconnect
sleep ${pauseminute}m
 
#this pulls all registered extensions in asterisk.  Final output is the extension number and IP address.
sipphonesANDip="$(asterisk -rx 'sip show peers' | grep / | awk '{print $1,$2}' | awk 'BEGIN { FS = "/" } ; {print $2}')"
 
#now we parse the list of extensions and IPs to make sure they are valid.  This should sort out SIP TRUNKS too
while read -r sipphonesANDip
do
 
#were going to make sure the extension is valid (sometimes they can be names like a trunk so we want to sift those out)
extensionnumber=$(echo $sipphonesANDip | awk '{print $1}')
 
        #checking to see if the extension is an INTIGER.
        if expr "$extensionnumber" : '-\?[0-9]\+$' >/dev/null
                then
                        echo "$extensionnumber valid extension value"
                else
                        echo "$extensionnumber invalid extension. Skipping."
                        continue
        fi
 
        #check to see if the number is within a valid range to work with that was set in the variables at the top
        if [ "$extensionnumber" -le "$highestextension" ] && [ "$extensionnumber" -ge "$lowestextension" ]
                then
                        echo "$extensionnumber IN RANGE";
                else
                        echo "$extensionnumber OUT OF RANGE"
                        continue
        fi
 
        #this will remove extensions that have no IP assigned.
        extensionIP=$(echo $sipphonesANDip | awk '{print $2}')
 
        if [ "$extensionIP" = "(Unspecified)" ]
                then
                        echo "$extensionIP is null"
                continue
        fi
 
#I have not worked out how to send a variable to the "asterisk -rx" command from bash.  So did it using EVAL command.
#output looks like below and is stored in a temp file (assigned in the variable at the beginning).  EVAL can't save to a STRING, so file it is.  Now we query each registered extension in asterisk to get its USERAGENT value
#3151 10.1.210.33   Useragent    : MicroSIP/3.19.28
command="asterisk -rx 'sip show peer "$extensionnumber"' | grep Useragent | grep -v "$alloweddevices" | sed 's/^/"$sipphonesANDip" /' >> "$TempFileNameAndPath""
 
eval "$command"
done <<<"$sipphonesANDip"
 
#now we take the temp file generated above, parse out the IP address and set it to be blocked in firewall
sipphonesANDip="$TempFileNameAndPath"
while IFS= read -r line
        do
        extensionIP="$(cut -d' ' -f2 <<<"$line")"
        echo "$extensionIP"
        FirewallCommand="fwconsole firewall add blacklist "$extensionIP""
 
#Comment out this next line if you want to test, but not apply any rules to the firewall        
        eval "$FirewallCommand"
 
done < "$sipphonesANDip"



Wednesday, April 1, 2020

Stream a ZOOM meeting on Facebook

First, make sure Facebook is enabled in your account settings in the GUI

Start your meeting

Then select MORE -> Live on Facebook
Upon selecting the option, facebook will pop up (assuming you are already logged into the account that you want to stream to)

It will want to know where do you want to place your live feed.


Facebook and Zoom will establish connection
You'll be presented with the live producer application.


You'll see your stream in the corner, and when you are ready, you can press "Go Live" and you are streaming!

Tips on securing a Zoom meeting

Going to have a zoom meeting?  Especially a large one? 50, 100, 500 people attending?
This document focuses around large meetings where you might have 25+ people joining in a type of forum that might be more one way.  Such as a large classroom or presentation.

Here's some tips to make the meeting go smoother with less unwanted interruptions. 

1> Practice.  First and foremost you have to get to know the Zoom client and the nuances.  Jumping into host a zoom meeting and not knowing how to handle situations isn't a fault of the product.

2>Minimize attendee feature access- For a large meeting, 25+ you need to ensure you minimize features.

3>Secure your meeting to ensure, if you are the main presenter, that you have minimized potential distractions from attendees, to you or your other invited guests.

4>Spread out meeting administration with co-hosts..  Delegate responsibilities of aspects of a large meeting to other co-hosts.  If you are hosting the meeting, assign a cohost to monitors the attendees, even the mute/unmute of users.  Have them scan the attendees to ensure they aren't doing something in Chat or on the video


PRACTICE:
You simply have to know the controls in ZOOM.  They aren't complicated, and knowing this will ensure you can have a successful meeting.  You need to learn the nuisances of Zoom and where certain controls are and how to quickly get to them.  Create meetings, join them with other computers or devices.  Learn what the experience is like for attendees based on different control settings you apply.  Whats the impact of 'unmute all' and 'let attendees unmute themselves'?  I've been in meetings where this absolutely ruined the experience because hosts didn't know the difference.
How do you prevent an attendee from hijacking your screen share?  And how do you lock it so that only certain users can perform screen shares?  All things you have to learn else you are only setting yourself up for potential trouble..

Minimize Distractions

You absolutely must remove as many unwanted interruptions that attendees can do to your meeting, malicious or not.  People aren't always meeting savey or computer or phone savey.  The simple ability to ensure one has muted themselves can be challenging.  You, as the meeting host, must take control of this from the start.

Here's some settings i suggest

Log into your personal account for your meetings, assuming you are the host.
Here's some settings I would configure.

  Goto zoom.us and Sign IN




Now select SETTINGS

A number of features will be available to you.



Participants Video - Set OFF

Large meeting a whole bunch of videos is usually distracting.  People will turn them on, and there are modes further down to control that.  I leave them off by default in large meetings because that many videos, if they are not participating, is not usually useful.  Its usually far more distracting.

Join before host - Set OFF
If you are having a large meeting and you want to control the attendees, this is a good thing to set to OFF.  Attendees will get a message saying they have connected successfully, but that the host hasn't started the meeting yet.

Mute participants upon entry - (ON)
If you have a large number of people all joining, it will be a noisy affair of background noise, people talking, usually not knowing their mic is live.  You must control the sound!
This is only fully effective if you lock the ability for users to unmute themselves once the meeting has started:

Once you have started the meeting, you want to then you will want to make sure the entry for "Allow Participants to Unmute Themselves" is NOT check marked.  You want to limit the ability for attendees to change the state of their microphone.  Co-hosts can unmute themselves and other attendees.

Feedback to Zoom  (OFF)


Co-host - (ON)

Cohosts by default have similar privileges to hosts, they can mute/unmute themselves and others and can share their screens.

Allow host to put attendee on hold - (ON)

Discovered a trouble maker, this is great way to stop them.

Always show meeting control toolbar 
- (ON)

keep the controls from disappearing for attendees.


Screen sharing - (ON)

Who can share?  Select Host Only
       

        By setting this as "Host Only" ensures that you (or a co-host) are the only ones you can share.


Show a "Join from your browser" link - (ON)



SECURING

Allow Hosts to put attendee on hold - very handy.  Someone being a problem, convenient way to handle it.

Require a password = This is up to you, it really can help bigger meetings, especially if the meetings have the potential of being crashed by unwanted people who have gotten the meeting number, or are just guessing.  This isn't fool proof, but it can slow unwanted guests down if that is a concern.  

Screen sharing - ONLY HOSTS can share - easily have someone share a screen without intervention and take over a meeting, knowingly or unknowingly.

Allow removed participants to rejoin - up to you.  depends on if you have someone joining causing problems.

Waiting room - this allows you to screen the users joining your meeting.  This can be difficult to manage in a large meeting if you are presenting.  Deligates to your meeting to handle it is where this is very useful.

When you start the meeting, click on participants - ensure MUTE on entry is selected.
Unselect Allow participants to umnute themselves
Unselect allow participants to rename themselves
And know how to lock a meeting.

Spread the work load
Assign a co-host in large meetings to handle the operation of users, muting/unmuting etc.
You may have another co-host handling the chat responses
Co-host dedicated to managing possible screen sharing, maybe you are sharing a power point, you can have multiple co-hosts doing events in your room on your behalf.

Consider a YouTube channel to broadcast your meeting to.  If your presentation requires minimal feedback from  attendees (voice/video responses) then the one-way YouTube is a great way to allow people to join your meeting without having to install the zoom application and configure it.

Meeting Etiquette
Let the people joining know the state of their system.  You can remind them they are muted or video is off.

Requests can be made through the client to be unmuted

Join early - As the host, be prepared when you are having a large meeting.  have something on the screen that at least acknolwedges that they are in the right meeting.  Could be just a shared PAINT picture that says "Meeting starts at X:XX time"

Participant join/departure Sounds.  Nothing wrecks a large meeting worse than a "beep join/leave" tone and the useless name announcement recording interrupting all the time.  Small meeting of 5-10 people, not a big deal.  200 people?  Its distracting and overrides your voice if you are presenting.