Help with extension attribute scripting

May
Contributor III

Hi all

I'm trying to create an extension attribute that checks all available network interfaces to see if a proxy is enabled or not, and then use the AE with a policy to disable or enable the proxy dependent on the Mac's building location.

At the moment the script i have returns the status of each individual interface and when used as an extension attribute it will only show the status of the last port checked, can anyone advise how i'd get the script to look at all the results then echo "yes" if they are all on and "no" if any of them are off ?

<result>on</result>
<result>on</result>
<result>on</result>
<result>off</result>
<result>on</result>
<result>on</result>
<result>on</result> = off

and

<result>on</result>
<result>on</result>
<result>on</result>
<result>on</result>
<result>on</result>
<result>on</result>
<result>on</result> = on

this is what i have so far

#!/bin/sh
#Declaring Variables


Ethernet=`/usr/sbin/networksetup -getautoproxyurl "Ethernet" | grep -x "Enabled: Yes"`
WiFi=`/usr/sbin/networksetup -getautoproxyurl "Wi-Fi" | grep -x "Enabled: Yes"`
USBEthernet=`/usr/sbin/networksetup -getautoproxyurl "USB Ethernet" | grep -x "Enabled: Yes"`
Broadcom_NetXtreme_Gigabit_Ethernet_Controller=`/usr/sbin/networksetup -getautoproxyurl "Broadcom NetXtreme Gigabit Ethernet Controller" | grep -x "Enabled: Yes"`
Display_Ethernet=`/usr/sbin/networksetup -getautoproxyurl "Display Ethernet" | grep -x "Enabled: Yes"`
Thunderbolt_Bridge=`/usr/sbin/networksetup -getautoproxyurl "Thunderbolt Bridge" | grep -x "Enabled: Yes"`
Thunderbolt_Ethernet=`/usr/sbin/networksetup -getautoproxyurl "Thunderbolt Ethernet" | grep -x "Enabled: Yes"`




#Checking Ethernet status
if [ "$Ethernet" = "Enabled: Yes" ]; then
    echo "<result>on</result>"

else
    echo "<result>off</result>" 

fi

#Checking WiFi status
if [ "$WiFi" = "Enabled: Yes" ]; then
    echo "<result>on</result>"

else
    echo "<result>off</result>" 

fi

#Checking USBEthernet status
if [ "$USBEthernet" = "Enabled: Yes" ]; then
    echo "<result>on</result>"

else
    echo "<result>off</result>" 

fi

#Checking Broadcom_NetXtreme_Gigabit_Ethernet_Controller status
if [ "$Broadcom_NetXtreme_Gigabit_Ethernet_Controller" = "Enabled: Yes" ]; then
    echo "<result>on</result>"

else
    echo "<result>off</result>" 

fi

#Checking Display_Ethernet status
if [ "$Display_Ethernet" = "Enabled: Yes" ]; then
    echo "<result>on</result>"

else
    echo "<result>off</result>" 

fi

#Checking Thunderbolt_Bridge status
if [ "$Thunderbolt_Bridge" = "Enabled: Yes" ]; then
    echo "<result>on</result>"

else
    echo "<result>off</result>" 

fi

#Checking Thunderbolt_Ethernet status
if [ "$Thunderbolt_Ethernet" = "Enabled: Yes" ]; then
    echo "<result>on</result>"

else
    echo "<result>off</result>" 

fi

Thanks,
Andy

1 ACCEPTED SOLUTION

mm2270
Legendary Contributor III

@May - I see the issue. Didn't really think about the ports that can't have a proxy associated with them.
I'm not sure yet if there's a scripted way to only look at hardware ports that can have a proxy and skip others, but for the time being, how would something like this work?

#!/bin/bash

validConnections=("Ethernet" "Wi-Fi" "USB Ethernet" 
"Broadcom NetXtreme Gigabit Ethernet Controller" 
"Display Ethernet"
"Thunderbolt Bridge"
"Thunderbolt Ethernet")

while read connection; do
    if [[ $(echo "${validConnections[@]}" | grep "$connection") ]]; then
        setting=$(networksetup -getautoproxyurl "$connection" | awk '/Enabled/{print $NF}')
        if [[ "$setting" == "No" ]]; then
            Disabled+=("$connection")
        elif [[ "$setting" == "Yes" ]]; then
            Enabled+=("$connection")
        fi
    fi
done < <(networksetup -listallhardwareports | awk -F': ' '/Hardware Port:/{print $NF}')

if [[ -z "${Disabled[@]}" ]]; then
    echo "<result>Yes</result>"
else
    echo "<result>No</result>"
fi

Basically, as it goes over each hardware port, it checks to see if its one that you specified it to check on in the array up top. If its there, it looks at the settings and drops it into the appropriate array (Enabled or Disabled), otherwise it skips it.
The only thing about this is, since its possible to rename the display name for a hardware port in System Preferences > Network, its possible for this to miss some anyway if a user happened to rename one of the ones you wanted it to check on. There's probably a better way to do this, but I don't have the answer at the moment.
Anyway, try that and see if it works for the moment.

View solution in original post

10 REPLIES 10

mm2270
Legendary Contributor III

You might want to try something like this-

#!/bin/bash

while read connection; do
    setting=$(networksetup -getautoproxyurl "$connection" | awk '/Enabled/{print $NF}')
    if [[ "$setting" == "No" ]]; then
        Disabled+=("$connection")
    elif [[ "$setting" == "Yes" ]]; then
        Enabled+=("$connection")
    fi
done < <(networksetup -listallhardwareports | awk -F': ' '/Hardware Port:/{print $NF}')

if [[ -z "${Disabled[@]}" ]]; then
    echo "<result>Yes</result>"
else
    echo "<result>No</result>"
fi

Edit: To make the EA a little more useful perhaps, you could also use it with this modification:

#!/bin/bash

while read connection; do
    setting=$(networksetup -getautoproxyurl "$connection" | awk '/Enabled/{print $NF}')
    if [[ "$setting" == "No" ]]; then
        Disabled+=("$connection")
    elif [[ "$setting" == "Yes" ]]; then
        Enabled+=("$connection")
    fi
done < <(networksetup -listallhardwareports | awk -F': ' '/Hardware Port:/{print $NF}')

if [[ -z "${Disabled[@]}" ]]; then
    echo "<result>Yes</result>"
else
    printf '%s
' "<result>No:
${Disabled[@]}</result>"
fi

This will print "Yes" only if all connections are enabled. If any are not enabled for autoproxy, it places them into an array that can also get printed along with a "No" So in your policy later, scope to any Macs that are not specifically returning a "Yes" But the EA will also specifically show you which connection(s) are not enabled with that option.

Josh_Smith
Contributor III

Are you trying to change proxy settings as laptops move between buildings? If so I just wanted to mention that any EA will only update when you run inventory, so this may not be the best way to do that.

If you are validating/enforcing desktop settings then it could do the trick.

mm2270
Legendary Contributor III

@May, @Josh.Smith makes a good point. Since EA values only get updated normally during an inventory update, if you wanted to take immediate action on a building change to adjust the proxy settings, you would need to look at it another way.

There may be a much more logical and easy way to address that scenario, perhaps with configuration profiles, but barring anything else, one thing you could do is create an Ongoing policy activated by the Network State Change trigger that runs a script which gathers the same EA values, plugs them into an xml file and uploads said xml file to the computer record in the JSS using the API. This would negate the need for a full inventory collection every time there is a network state change, which can be a little time and resource consuming. It would however require using an API account with write privileges to computer objects, so there are some security implications to that to consider.
But it would work.

mostlikelee
Contributor

you could run it on network state change but I've found it to be overly chatty especially when using networksetup commands (which tend to trigger it). install crankd and use a launchdaemon to run your script locally based on the trigger file it creates.

mostlikelee
Contributor

I built this to search through /Library/Preferences/SystemConfiguration/NetworkInterfaces.plist and create available network interfaces. This recreates deleted interfaces as well as creates them when plugging into a new connection (i.e. connecting to a Thunderbolt Display for the first time). I found the system doesn't always do this too well.

createnetworkinterfaces()
{
##This function checks for any newly connected network interfaces and adds it/them to your current network location

#logtitle
echo "--CREATE NETWORK INTERFACES---" >> $logfile

##VARIABLES##
plist="/Library/Preferences/SystemConfiguration/NetworkInterfaces.plist"
i=0
intarr=()
maxinterfaces=10

#create array of connected interfaces formatted ie. Wi-Fi:en0 Ethernet:en1 etc...
while [ $i -le $maxinterfaces ];
do
    lastint=`/usr/libexec/PlistBuddy -c "print :Interfaces:${i}:BSD Name" $plist 2>&1 | cut -d " " -f5-7`

    if [ "$lastint" != "Does Not Exist" ]; then
        #echo "$lastint exists" >> $logfile
        intname=`/usr/libexec/PlistBuddy -c "print :Interfaces:${i}:SCNetworkInterfaceInfo:UserDefinedName" $plist`
        intpos=`/usr/libexec/PlistBuddy -c "print :Interfaces:${i}:BSD Name" $plist 2>&1 | cut -d " " -f5-7`
        intarr[$i]=${intname}:${intpos}
        i=$(($i + 1))
    else
        i=$(($i + 1))   
    fi
done

# check current network location for existing interfaces in array, create them if they're not enabled.
i=0
for i in "${intarr[@]}" 
do
    intname=`echo "$i" | cut -d ":" -f1`
    intpos=`echo "$i" | cut -d ":" -f2`
    netenabled=`networksetup -getnetworkserviceenabled "$intname"`
        if [ "$netenabled" != "Enabled" ]; then
            echo ${i} | cut -d ":" -f1 >> $logfile
            networksetup -createnetworkservice "$intname" "$intpos" 
        fi
done

}

May
Contributor III

@mm2270 Thanks Mike!

That's pretty much it

I just tested it and as it's checking all the network interfaces including the ones where it's not possible for there to be a proxy set (Bluetooth Pan) it will always return "No"

Would it work if it was changed to look at only the specific interfaces that can use a proxy ?
ie would it be able to look at each specific interface one by one as in my wonky script then use the rest of yours ?

or could i use the networksetup -listallhardwareports and exclude the output from any interfaces that aren't capable of using a proxy ?

Really appreciate your help!

mm2270
Legendary Contributor III

@May - I see the issue. Didn't really think about the ports that can't have a proxy associated with them.
I'm not sure yet if there's a scripted way to only look at hardware ports that can have a proxy and skip others, but for the time being, how would something like this work?

#!/bin/bash

validConnections=("Ethernet" "Wi-Fi" "USB Ethernet" 
"Broadcom NetXtreme Gigabit Ethernet Controller" 
"Display Ethernet"
"Thunderbolt Bridge"
"Thunderbolt Ethernet")

while read connection; do
    if [[ $(echo "${validConnections[@]}" | grep "$connection") ]]; then
        setting=$(networksetup -getautoproxyurl "$connection" | awk '/Enabled/{print $NF}')
        if [[ "$setting" == "No" ]]; then
            Disabled+=("$connection")
        elif [[ "$setting" == "Yes" ]]; then
            Enabled+=("$connection")
        fi
    fi
done < <(networksetup -listallhardwareports | awk -F': ' '/Hardware Port:/{print $NF}')

if [[ -z "${Disabled[@]}" ]]; then
    echo "<result>Yes</result>"
else
    echo "<result>No</result>"
fi

Basically, as it goes over each hardware port, it checks to see if its one that you specified it to check on in the array up top. If its there, it looks at the settings and drops it into the appropriate array (Enabled or Disabled), otherwise it skips it.
The only thing about this is, since its possible to rename the display name for a hardware port in System Preferences > Network, its possible for this to miss some anyway if a user happened to rename one of the ones you wanted it to check on. There's probably a better way to do this, but I don't have the answer at the moment.
Anyway, try that and see if it works for the moment.

May
Contributor III

@mm2270 Mike, that is so awesome thank you for sharing !

Just tested it on a few Macs with and without the full compliment of network interfaces and works like a charm!
I'm not so worried about it being reliant on the naming of the interfaces as the majority of our users don't have access to the network prefs.

Now i need to start looking at the other suggestions re the best way to update the smart groups based on Building, coffee first!

again, thank you so much Mike, really appreciated!

bentoms
Release Candidate Programs Tester

@May you might want to look at two policies, set to the trigger of "network state" & with one limited to buildings that use the proxy, the other with buildings to not.

Then run a script that sets or removes the proxy.

I've an example here for both scenarios. Hope they help.

May
Contributor III

@bentoms Thanks Ben

I've been testing with a similar set up, the policy to enable the proxy has a network state change trigger and is scoped to the proxied buildings and Macs without the proxy on. When the policy runs it enables the proxy on all intefaces and deposits a dummy receipt.

then the policy to disable the proxy is scoped to all macs with the receipt, with the proxy on and not in the proxied buildings, it also deletes the receipt.

I'll have a look at the scripts on your site, they will be very useful!

@Josh.Smith @timkalee also thanks Josh and Tim

We have the check in set to 15 minutes at the moment, i've tested a few machines and the smart groups update properly, i may include a self service button for users to manually disable/enable the proxy scoped on their location as a back up.

The Network state change trigger seems to be the best for the policy, i'll monitor how busy it gets, i got myself an iBeacon to play around with and that works really well at triggering the policy though i haven't fully tested it in the appropriate environment and also have no idea how reliable they are.

Thank you again for all your advice and time!