AD Certificate Auto Renewal Workflow

danshaw
Contributor II

I've been tasked with setting up AD Certificates for Macs and after working a bit on it I now have it working where the computer gets a config profile installed that then requests from AD a certificate. Everything is working fine, but now I am at the point where I am not sure what needs to be done when the certificate expires 1-year from now. I need some type of workflow for renewing these as it will be impossible to keep track of all the expiration dates.

After doing some searching on JN, there are some posts a few years old where users recommend scripting this, but there was no one that could get it working.

There is also a feature request to have the JSS auto renew, but that is from 2013 and I don't think that will happen.

If anyone is out there who has put together a workflow for getting this to work I would love to hear about it.

40 REPLIES 40

NoahRJ
Contributor II

Hey @danshaw, I put together an EA for this back in April to track our cert expirations after we moved to a one year expiration. Since our machine certs are identified by the hostname of the machine and living in the System keychain (yours might be in Login), we were able to parse out the cert names based on the hostname of the machine (and if there were multiple certs, clean them up when we went through the renewal process ((see script below))), but since all certs with the SHA-1 hash and the cert info are returned top-down, oldest-newest, I can throw in that sed statement to grab the last occurrence of a result that starts SHA-1, which will get me the newest cert on the machine that matches my criteria (even if there were duplicates) and gives me an accurate representation of how long it had before expiration. Below is the EA (spit out the result as an integer and you can smart group it out as needed) that I'm using in my environment:

#!/bin/bash
#Created 4/14/16; NRJA

CompName=$(hostname)
ExpDate=$(/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | sed -n 'H; /^SHA-1/h; ${g;p;}' | /usr/bin/openssl x509 -noout -enddate 2>/dev/null | cut -f2 -d=)
EpochOne=$(date -j -f '%b %d %T %Y %Z' "$ExpDate" '+%s')
EpochTwo=$(date +%s)
MathOne=$(expr $EpochOne - $EpochTwo)
MathTwo=$(expr $MathOne / 86400)

echo "<result>${MathTwo}</result>"

From there, we have machine certs that are issued as part of our internal wireless/VPN setup policy, and we're able to issue a new one as part of that PKG installation. I also wrote a duplicate cert lookup script (below) that will clean up any remaining duplicate certs if they exist on the machine (again, identified by the hostname of the machine, because that's how our certs are issued) until only the newest one remains:

#!/bin/bash
#Created 4/15/16; NRJA

# Declare variables
CompName=$(hostname)
CertCount=$(/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | grep SHA-1 | wc | awk '{print $1}')

# Search for and clean up extra machine certificates until only the newest remains
if [ $CertCount == 1 ]; then
echo "Computer only has one cert"
exit 0          

elif [ $CertCount == 0 ]; then 
echo "Computer has no machine cert"
exit 0                  

else            
Certs=$(/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | grep SHA-1 | awk '{print $3}' | tail -r | tail +2 | tail -r)

while [ "$Certs" != "" ]                

do
Certs=$(/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | grep SHA-1 | awk '{print $3}' | tail -r | tail +2 | tail -r)
security delete-certificate -Z $Certs /Library/Keychains/System.keychain &2>/dev/null
done                                                                                            
fi

danshaw
Contributor II

@NoahRJ This is great! Thanks so much. We also name our computers by hostname so that works out perfectly. A couple followup questions:

  1. With this script you can track how many days are left on the certificate. When it is time to deploy again are you using a config profile that you then install as a package/policy or are you using the JSS config profile to deploy? If using a package, why that instead of using the built in JSS to deploy the config profile?

  2. In my tests, when I installed the config profile again it created a duplicate certificate, am I to assume that you then have that 2nd script run to remove the old certificates? How often do you run the script? Only after installation of the config profile or on a regular basis?

NoahRJ
Contributor II

@danshaw Happy to help!

  1. We use a package that includes profiles as part of the payload because we have a couple of different profiles that install based on location, so there's a postflight script that includes logic to determine which profile to install. Also, we've generally just had more success using the profiles command to install a profile rather than relying on the JSS to do it.

  2. Yep, that's correct! We only run that script after this cert renewal policy hits our scope (smart group with machines with less than 30 days remaining according to our EA) to clean up duplicates. And the script doesn't run on a regular basis. It doesn't matter for us if a computer has duplicate certs, because we're working off the newest cert on the machine for the EA, and it'll be cleaned up once a year as is.

perrycj
Contributor III

@NoahRJ This is great stuff. Thanks for posting. Couple of questions myself, if you don't mind..

Since you're installing using the profiles command, does that make the profiles local, instead of via MDM? It does right?

When renewing the certs for wireless, for example, are you able to accomplish this without an interruption of connection? We also used machine based certificate authentication to get on our internal networks but I'm wondering if I renew an expiring existing certificate while the user is actively using that internal network, would they then lose connection (even if just briefly)? If your users do lose connection, how are you getting them back on without interaction? Or does it require some user interaction?

alexjdale
Valued Contributor III

Profiles has a -W option that is supposed to attempt to renew a certificate in an installed profile. Has anyone tried that instead of reinstalling the profile entirely?

jhbush
Valued Contributor II

@NoahRJ I'm testing out your script and I'm seeing an issue where the script returns that it can't remove some certificates. It's also exiting properly but not removing certificates in some cases. We use an AD CA requested by a profile so this would be of great help to us. Any insight as to why this is hit or miss would be great.

perrycj
Contributor III

@alexjdale Yea I've tried using, -W with also a -p flag and then including the profiler identifier, but still no dice. By it's description, you would think -W is exactly what you need: “sets up command to renew certificates in an installed profile”.

gabriel_martine
New Contributor III

Hey @danshaw , hoping you can help me out. I'm trying to run your first script but keep getting "Failed conversion of '' using format%b %d %T %Y %Z'' ". Any thoughts?

NoahRJ
Contributor II

Sorry for the delay here, folks.

@perrycj That's correct that these are local profiles through our method of installation. We haven't had issues with our admin users removing them, and even if they do (bricking a wireless connection, for example), we have a Self Service policy that reinstalls company security certs, rebinds to AD, reissues AD cert, and reinstalls the wireless profile, so it's kind of a catchall for any self-inflicted issues they may incur.

And yeah, when renewing these certs, we've found the connection is actually almost always stable or reconnects. In our process, we're reissuing the new cert before removing the old one (which is partially why we avoided using the Profiles -W command), so even if there's a brief drop of connection, the wireless profile or VPN connection can seamlessly latch onto the newly installed machine cert for authentication.

NoahRJ
Contributor II

@jhbush1973, hard to troubleshoot without knowing more specifics of your environment. Sounds like it is working sometimes, but not always? On those machines that aren't removing old certs, I'd run my code down line by line on the machine and see what's being returned for each value. The script exits properly because I threw a "&2>/dev/null" on the third-to-last line, so any error output is being redirected to /dev/null. You can try stripping that value out and it'll return error notices on why it's not able to remove some of the old certs.

NoahRJ
Contributor II

@gabriel_martinez, that error looks like the ExpDate variable isn't being set and the date command in EpochOne doesn't have anything to manipulate since it's trying to convert a null value. Are your machine certs named by computer name, or do they have some other unique value attached to them? I'm grabbing the hostname value and setting that as the determination for the certificate to renew in System.keychain when I set the ExpDate var, so if that's not how they're defined in your environment, you'll need to set that value based on their names. If you're not sure, you can open up Keychain Access and look for the certificate under the System keychain, and then figure out what unique value is attached and update the code accordingly.

perrycj
Contributor III

@NoahRJ Thanks for the reply back and thanks for answering my questions.

I don't see it mentioned, so I wanted to ask.. how are you actually getting new machine certs on your clients then? I see where you check for expiration and get rid of old ones once new certs are on.. but how are you getting new machine certs to generate? In my experiences, renewing the certs requires user interaction. Do you have a way or are you using a way where it's automated in generating a new cert on a client? Hopefully that makes sense.

gabriel_martine
New Contributor III

@NoahRJ Thanks. We are using our own variable in there to get the cert name. I realized the issue was that we store the cert in the Login keychain. I got it working now. Thanks!

NoahRJ
Contributor II

@perrycj Oops, definitely didn't mention that. We have a few different payloads in our wireless config profile that we're installing that handle this. We have our Network payload, a couple Certificate payloads, and an AD Certificate payload. Since our wireless uses an AD cert to connect, we just generate that machine cert with a request to our certificate server via our specified certificate authority.

perrycj
Contributor III

@NoahRJ So is that request scripted? We do the same things, in terms of how you have your payloads. One for network, one for certs and one for AD.

But I'm assuming you send a request. Currently, at least in my experiences, it doesn't just happen on it's own even with those payloads in place.

NoahRJ
Contributor II

@perrycj No, we don't script anything to generate that cert. It all happens under the AD Certificate payload. Upon installation of the profile for us, the payload will go out to the specified cert server validated with a CA that's already installed on the machine (or is included as part of the profile), and generate a cert based on the custom computer certificate template we've put together on the AD side. This (pretty out of date) article on JN talks a little more about it: https://www.jamf.com/jamf-nation/articles/209/requesting-a-certificate-from-a-microsoft-certificate-...

perrycj
Contributor III

@noahRJ Oh I totally get that. We do the same thing. I'm asking once that process happens a first time, how are you getting the new cert on the Mac 6-12 months down the line? Or should I say, how are you getting it to generate a new cert once the original one starts to expire? Hope that's clear.

AVmcclint
Honored Contributor

@NoahRJ I tried running your first script for the EA and it kept failing. I found that I had to change the tail number to 38 lines instead of 37. Now it reports properly!

NoahRJ
Contributor II

@perrycj, yeah, so that's where the duplicate cert cleanup stuff comes in. As part of the automated renewal process, we'll install that same wireless profile again over the top, which will only serve to pull down a new machine cert from AD, and then the second script I posted initially will clean up the older cert(s).

@AVmcclint, that's a good call out. The length of our SHA-1 hash + certificate info is 37 lines, so that's why my tail command is tail -n 37. What would better is a sed statement of the last match that starts with SHA-1, since that will always be the newest cert on the machine. Something like this should work:

/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | sed -n 'H; /^SHA-1/h; ${g;p;}' | /usr/bin/openssl x509 -noout -enddate 2>/dev/null | cut -f2 -d=

Want to give that a shot in your environment and see if it works for you? I'll update my original post accordingly with that new (and ugly) sed statement.

perrycj
Contributor III

@NoahRJ Ah, yes. I get what you mean now. For some reason I was assuming you were pulling it some automated way. I wasn't even thinking about just installing the profile again. Yes that would definitely work. If your profiles are MDM though, makes it a little trickier.

I have time scheduled with Apple in about 2 weeks and we're going to try to come up with a way to script automatic renew instead of A) the user getting prompted to do it or B) installing the profile again. Hopefully we can come up with an automated way to take care of this.

If we do come up with anything, I will update this thread with what we find out.

perrycj
Contributor III

@NoahRJ Ah, yes. I get what you mean now. For some reason I was assuming you were pulling it some automated way. I wasn't even thinking about just installing the profile again. Yes that would definitely work. If your profiles are MDM though, makes it a little trickier.

I have time scheduled with Apple in about 2 weeks and we're going to try to come up with a way to script automatic renew instead of A) the user getting prompted to do it or B) installing the profile again. Hopefully we can come up with an automated way to take care of this.

If we do come up with anything, I will update this thread what we find out.

mattiasvdm
New Contributor

@perrycj I know this is sort of an old thread. I've dived into the -W option. I've done some tests and it looks like the -W option only works when the certificate is expiring in the next 14 days. If this is not the case, it will give a "returned 0 ((null))" exit code.

I've used @NoahRJ 's script to read out how many days until the certificate expires. Next, I tweaked it to use the -W option if the number of days is < 14.

I noticed that the default renewal notification interval is 14 days. So I hoped this was linked to the -W option, but when I changed this value to 31 days I still wasn't able to use the -W option earlier than 14 days.

Next up my list is to test how the renewal impacts the network connection if the workstation is using the certificate for its connection.

perrycj
Contributor III

@mattiasvdm Thanks for the post. Were you able to get it to renew using -W yet? Or is that your next step?

NoahRJ
Contributor II

As an FYI for everyone in the thread, looks like there's new automatic cert renewal options via config profile beginning in 10.12.4. It has a fair number of caveats, like it can't renew certs that contain MDM payloads or ones that were issued OTA (in addition to a couple of others), but for the purposes of our environment, it looks promising.

perrycj
Contributor III

@NoahRJ Thanks for the link to that Apple KBase. I heard of the changes with 10.12.4 but haven't had a chance to read up on it yet. This seems like it may work in our environment.

mattiasvdm
New Contributor

@perrycj Yes, the -W option works fine. But only if the certificate is expiring in the next 14 days. You can test it with a workstation or VM by changing the date to a couple of days before expiring.

I've just tested the renewal of the certificate while the Mac is connected to VPN or WiFi (using the certificate). There was no hick-up at all. It worked fine. I even removed the entire profile while connected to WiFi and nothing happened. It just stayed connected.

perrycj
Contributor III

@mattiasvdm Nice, I'll definitely try that out then. Thanks for the feedback.

perrycj
Contributor III

@mattiasvdm I was able to use the profiles -W -p "identifier" (no quotes) command with success. Thanks for verifying that. Here is another Apple kbase talking about how to use the -W command and syntax:

https://support.apple.com/en-us/HT204446

mattiasvdm
New Contributor

@NoahRJ Thanks for sharing. I've tested the functionality today and the automatic update renewal proces works fine. I just logged into a machine and changed the date to two days before expiring. Then I went out for lunch and when I came back it was renewed. It does keep the old certificate so I'm using your script to remove those.

@perrycj The link you posted doesn't work, it has an 'L' at the end. But I've read it, thanks for that.

So for 10.12.4 machines and newer, I'll use the automatic process. For older OS versions I'll use the script.

AVmcclint
Honored Contributor

How do you script the removal of the old certificate if it has the exact same name? I've been handling the whole renewal process manually on every computer as they start to get their 14 day warnings. If I can make the process 100% hands-off, that would make my day. I do have a 10.12.4 Mac that has a cert that's about to expire soon. I'm looking forward to seeing the renewal in action.

AVmcclint
Honored Contributor

Oops, I just realized the 2nd script in the comments is intended to search and destroy duplicate computer certs. Reading through it, I still don't understand how it knows to only delete the old certs. Where does the magic come into play to leave the brand new cert alone?

perrycj
Contributor III

@mattiasvdm I fixed it, thanks.

NoahRJ
Contributor II

Hey @AVmcclint, the secret sauce is the three commands here: tail -r | tail +2 | tail -r. If you have multiple certs, they'll show up like this when you query through the security command:

Oldest
Older
Old
New
Newer
Newest

When you run the tail -r | tail +2 | tail -r commands after getting that info out from the security command, the output is:

Oldest
Older
Old
New
Newer

So it'll iterate through and remove everything in that list from Newer on up, since the tail -r command reverses the order of those results, strips out the top line with tail +2, and then corrects the order again with tail -r. If there's just one line remaining, the tail +2 will return results of null, since it's always set to exempt the first line of the results. So, when it hits 'while [ "$Certs" != "" ]', if the $Certs variable isn't blank from more than one line being returned, it'll keep cleaning until it is blank, AKA one line is returned and then excluded from the tail +2 command.

Hope that helps!

AVmcclint
Honored Contributor

@NoahRJ That is very creative. My scripting abilities are on the weak side to begin with but when diving into the security command, i'm totally lost. The way you explained the flow, I think I can understand on a conceptual level. :)

jason_d
New Contributor III

@NoahRJ great stuff thanks for sharing! How are you setting the identity preference to use the new certificate?

EDIT: I figured it out

#!/bin/sh
/usr/bin/security set-identity-preference -c $certname -s com.apple.network.eap.system.identity.wlan.ssid.YOUR_SSID /Library/Keychains/System.keychain

mattiasvdm
New Contributor

@jason.desveaux Were you able to set the identity preference? I know I've been testing with this before and got it working, but somehow it doesn't work with 10.12.4. If I run the set-identity-preference command, it doesn't do anything. There's no identity being created, also no error whatsoever.

EDIT: I think I got it. It's a user setting. I thought it would add the identity to the System keychain so all users can connect to the specific WLAN.

LAST EDIT: :) I found a way to add the WLAN identity preference with the profile to the system keychain. You just have to add your WiFi network to the profile as usual. Choose TLS as the protocol and set the username to %AD_ComputerID% (never knew that profile manager accepted variables).

jason_d
New Contributor III

@mattiasvdm the command I posted should add the identity preference to the system keychain. Since my post, I've come across a few machines where it hasn't worked and I'm not really sure why.

As you mentioned, you can include the identity preference in the profile itself. The problem I have is when you renew the certificate and remove the old one, that preference doesn't get updated to use the new cert automatically.

PhillyPhoto
Valued Contributor

I made a package in Composer to take most of what's listed above and consolidate it. I have my mobileconfig file in /pvt/tmp, and then a postinstall script to check for network connectivity, then install it. I have tested while connected to VPN, and it does get the new cert before dropping the connection, so this should cover our in-office and remote users. I also noticed I don't need to set which certificate to use in the keychain, so I dropped that part.

We have had issues with the automatic deployment of our network profile, where it would randomly drop from machines, so we've been including a step for techs to login and install it from Self Service manually when building the machines. With this package, I should be able to add it to the application install step that's automated, and reduce a step in the build process!

#!/bin/sh
## postinstall

pathToScript=$0
pathToPackage=$1
targetLocation=$2
targetVolume=$3

# Echo function
echoFunc () {
    # Date and Time function for the log file
    fDateTime () { echo $(date +"%a %b %d %T"); }

    # Title for beginning of line in log file
    Title="NetworkProfile:"

    # Header string function
    fHeader () { echo $(fDateTime) $(hostname) $Title; }

    # Check for the log file
    if [ -e "/Library/Logs/MachineCert.log" ]; then
        echo $(fHeader) "$1" >> "/Library/Logs/MachineCert.log"
    else
        cat > "/Library/Logs/MachineCert.log"
        if [ -e "/Library/Logs/MachineCert.log" ]; then
            echo $(fHeader) "$1" >> "MachineCert.log"
        else
            echo "Failed to create log file, writing to JAMF log"
            echo $(fHeader) "$1" >> "/var/log/jamf.log"
        fi
    fi

    # Echo out
    echo $(fDateTime) ": $1"
}

echoFunc "======================== Starting Script ========================"

IFS='
'

# Attempt to ping ad.domain.com to make sure we're on the internal network
pingHost=ad.domain.com
if ( ping -c1 $pingHost &>/dev/null )
then
    echoFunc "Successfully pinged ad.domain.com, proceeding with profile installation!"

    # Install the network profile
    echoFunc "Installing new profile"
    profiles -I -F "/pvt/tmp/AD_Network_802.1x_Wired_&_Wireless_Configuration_Signed.mobileconfig"
    sleep 5

    # Declare variables
    CompName=$(hostname)
    CertCount=$(/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | grep SHA-1 | wc | awk '{print $1}')

    # Search for and clean up extra machine certificates until only the newest remains
    if [ $CertCount == 1 ]; then
        echoFunc "Computer only has one cert"
    elif [ $CertCount == 0 ]; then
        echoFunc "Computer has no machine cert"
    else
        Certs=$(/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | grep SHA-1 | awk '{print $3}' | tail -r | tail +2 | tail -r)
        while [ "$Certs" != "" ]
        do
            Certs=$(/usr/bin/security find-certificate -a -c $CompName -p -Z "/Library/Keychains/System.keychain" | grep SHA-1 | awk '{print $3}' | tail -r | tail +2 | tail -r)
            echoFunc "Deleting $Certs"
            security delete-certificate -Z $Certs /Library/Keychains/System.keychain &2>/dev/null
        done
    fi

    # Update the DNS Search domains for the network connections
    networksetup -listallnetworkservices | tail -n +2 |
    while read CURRENT_SERVICE; do
        echoFunc "Setting DNS Search Domains"
        /usr/sbin/networksetup -setsearchdomains "${CURRENT_SERVICE}" ad.domain.com domain.com
    done
else
    echoFunc "Failure to ping ad.domain.com, profile installation NOT attempted!"
fi

unset IFS

# Clean up the network profile
rm -rf "/pvt/tmp/AD_Network_802.1x_Wired_&_Wireless_Configuration_Signed.mobileconfig"

echoFunc "======================== Script Complete ========================"
echoFunc "Exit code: $?"
exit $?

PhillyPhoto
Valued Contributor

I cleaned up the multi-cert section so it actually deleted the extra certificates. I also added a jamfHelper notification to let the end-user know when their new cert expires.

#!/bin/sh

# Echo function
echoFunc ()
{
    # Date and Time function for the log file
    fDateTime () { echo $(date +"%a %b %d %T"); }

    # Title for beginning of line in log file
    Title="MachineCert:"

    # Header string function
    fHeader () { echo $(fDateTime) $(hostname) $Title; }

    # Check for the log file, and write to it
    if [ -e "/Library/Logs/MachineCert.log" ]; then
        echo $(fHeader) "$1" >> "/Library/Logs/MachineCert.log"
    else
        cat > "/Library/Logs/MachineCert.log" &
        cat "/Library/Logs/MachineCert.log"
        if [ -e "/Library/Logs/MachineCert.log" ]; then
            echo $(fHeader) "$1" >> "/Library/Logs/MachineCert.log"
        else
            echo "Failed to create log file, writing to JAMF log"
            echo $(fHeader) "$1" >> "/var/log/jamf.log"
        fi
    fi

    # Echo out
    echo $(fHeader) "$1"
}

echoFunc "======================== Starting Script ========================"

IFS='
'

# Attempt to ping an internal server to make sure we're on the internal network
pingHost=ad.domain.com
if ( ping -c1 $pingHost &>/dev/null )
then
    echoFunc "Successfully pinged $pingHost, proceeding with profile installation!"

    # Install the network profile
    echoFunc "Installing new profile"
    profiles -I -F "/pvt/tmp/Wired_&_Wireless_Configuration_Signed.mobileconfig"
    echoFunc "Profile installation result: $?"

    # Count the number of machine certificates currently on the device
    CertCount=$(security find-certificate -apZ -c $(hostname) "/Library/Keychains/System.keychain" | grep SHA-1 | wc | awk '{print $1}')

    # Search for and clean up extra machine certificates until only the newest remains
    if [ $CertCount == 0 ]; then
            # No machine certificate was found
        echoFunc "Computer has no machine certificate!"
    elif [ $CertCount == 1 ]; then
            # One machine certificate was found

            # Find the certificate expiration date
            CertExp=$(security find-certificate -apZ -c $(hostname) "/Library/Keychains/System.keychain" | sed -n 'H; /^SHA-1/h; ${g;p;}' | openssl x509 -noout -enddate 2>/dev/null | cut -f2 -d=)
            dateformat=$(date -j -f "%b %d %T %Y %Z" "$CertExp" "+%b %d %Y")
            echoFunc "Computer certificate expiration: $dateformat, notifying user"
            /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -button1 "OK" -defaultButton 1 -icon /Applications/Utilities/Keychain Access.app/Contents/Resources/AppIcon.icns -timeout 30 -title "New Machine Certificate" -description "Your new machine certificate expires on: $dateformat. Please make note of this. This window will close in 30 seconds."
    else
            # Multiple machine certificates were found
            echoFunc "Number of machine certificates found: $CertCount"

            # Delete the old certificates
            Tail=$CertCount
            while [ $Tail -ge 2 ]
        do
            CertsCount=$(security find-certificate -apZ -c $(hostname) "/Library/Keychains/System.keychain" | grep SHA-1 | awk '{print $3}' | tail -r | tail "+$Tail" | tail -r)
            echoFunc "Deleting certificate with SHA-1: $CertsCount"
            security delete-certificate -Z $CertsCount /Library/Keychains/System.keychain &2>/dev/null
            Tail=$(expr $Tail - 1)
        done

        # Find the new certificate expiration date
            CertExp=$(security find-certificate -apZ -c $(hostname) "/Library/Keychains/System.keychain" | sed -n 'H; /^SHA-1/h; ${g;p;}' | openssl x509 -noout -enddate 2>/dev/null | cut -f2 -d=)
            dateformat=$(date -j -f "%b %d %T %Y %Z" "$CertExp" "+%b %d %Y")
            echoFunc "Computer certificate expiration: $dateformat, notifying user"
            /Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -button1 "OK" -defaultButton 1 -icon /Applications/Utilities/Keychain Access.app/Contents/Resources/AppIcon.icns -timeout 30 -title "New Machine Certificate" -description "Your new machine certificate expires on: $dateformat. Please make note of this. This window will close in 30 seconds."
    fi

    # Update the configurations for the network connections
    networksetup -listallnetworkservices | tail -n +2 |
    while read CURRENT_SERVICE
    do
        echoFunc "Configuring Current Service: ${CURRENT_SERVICE}"
        networksetup -setsearchdomains "${CURRENT_SERVICE}" ad.domain.com
            networksetup -setautoproxyurl "${CURRENT_SERVICE}" http://proxy.domain.com:8080/pac
            networksetup -setproxybypassdomains "${CURRENT_SERVICE}" 127.0.0.1 *.domain.com
        SERVICE_CONFIG_TYPE=`networksetup -getinfo ${CURRENT_SERVICE} | grep "DHCP Configuration"`
        if [[ "${SERVICE_CONFIG_TYPE}" == "DHCP Configuration" ]]; then
            MAC_ADDRESS=`networksetup -getinfo ${CURRENT_SERVICE} | grep "Ethernet Address" | awk '{ print $3 }'`
            if [[ -z ${MAC_ADDRESS} ]]; then
                MAC_ADDRESS=`networksetup -getinfo ${CURRENT_SERVICE} | grep "Wi-Fi ID" | awk '{ print $3 }'`
            fi
            if [[ ${MAC_ADDRESS} != "(null)" && ${MAC_ADDRESS} != "" ]]; then
                echoFunc "Setting DHCP Client ID to: ${MAC_ADDRESS}"
                networksetup -setdhcp "${CURRENT_SERVICE}" "${MAC_ADDRESS}"
            fi
            fi
    done
else
    echoFunc "Failure to ping $pingHost, profile installation NOT attempted!"
fi

unset IFS

# Clean up the network profile
rm -rf "/pvt/tmp/Wired_&_Wireless_Configuration_Signed.mobileconfig"

echoFunc "Exit code: $?"
echoFunc "======================== Script Complete ========================"
exit $?