Progress bar of cached package using CocoaDialog

perrycj
Contributor III

I've been trying to figure it out but is there a way to show a progress bar with precentage (most likely using CocoaDialog) to show the download progress of a cached package?

We are kicking off a cached package policy via self service and our users have requested more feedback on the progress of the cached package download. I imagine this can be done through CocoaDialog but can't place it. Any help would be appreciated.

2 ACCEPTED SOLUTIONS

iJake
Valued Contributor

CocoaDialog can be finicky and you have to use the beta of version 3 for progress to work but here is code to show progress of caching a package. I have a function for when I call the installer too if you need that. You have to tell it the size of the package since it can't be determined dynamically with the way packages ae cached currently.

cdPath="/Path/To/cocoaDialog.app/Contents/MacOS/cocoaDialog"
cdIcon="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ApplicationsFolderIcon.icns"
cdTitle="Dialog Title"
pkgTotal=12064712 #Must know the size of the package
pkgPartial=0
downloadFolder="/Library/Application Support/JAMF/Downloads"
waitingRoomFolder="/Library/Application Support/JAMF/Waiting Room"
dmgName="Package.dmg"

## CocoaDialog Function
dialogDownload()
{
## Create the name pipe input for the progressbar & set brief pause
rm -f /tmp/hpipe
mkfifo /tmp/hpipe
sleep 0.2

## Display progress bar with initial text settings
"$cdPath" progressbar --stoppable --title "Upgrade Package Download Progress" --text "Downloading..." --float < /tmp/hpipe > /tmp/_out &

exec 3< <(yes)

## Send progress through the named pipe
exec 3<> /tmp/hpipe

if { >&3; } 2> /dev/null
    then
        writeLog "Pipe RW verified"
    else
        writeLog "Pipe RW failed"
fi

#Determine PID of jamf process so it can be killed.
trap : SIGTERM SIGINT

echo $$

(jamf policy -event PayloadName ) > /tmp/_out2 &

jamfPID=$!

## Give the policy time to start
sleep 5

#Initialize error counter
counter=0
#While loop to generate package download percent
while [[ $pkgPartial != $pkgTotal ]]
    do
        #Watches for the output of CocoaDialog to equal stopped if "Stop" button is clicked. Cancels install.
        dialogStopCheck=`cat /tmp/_out`
        if [[ "$dialogStopCheck" = "stopped" ]]
            then
                kill $jamfPID
                rm -f /tmp/_out
                rm -f /tmp/_out2
                writeLog "Upgrade cancelled by user."
                exit
        fi
        #Watches for possible jamf binary being upgraded which will fail download of package.
        binaryUpgradeCheck=`cat /private/tmp/_out2 | grep "Upgrading jamf binary..."`
        if [[ "$binaryUpgradeCheck" != "" ]]
            then
                kill $jamfPID
                rm -f /tmp/_out
                rm -f /tmp/_out2
                writeLog "jamf binary upgrade detected. Fixing..."
                jamf policy -event PayloadName >> "$logFile"
                sleep 20
                dialogDownload
        fi
        #Error counter check. Die at 10 errors.
        if [[ $counter -gt 9 ]]
            then
                echo "Package Download failed..." >&3
                sleep 5
                kill $jamfPID
                writeLog "Package download failed."
                exit
            else
                #If the package exists in the download folder determine percentage downloaded.
                if [[ -f  "$downloadFolder"/"$dmgName" ]]
                    then
                        pkgPartial=`du "$downloadFolder"/"$dmgName" | awk '{print $1}'`
                        modifiedTime=`stat -s "$downloadFolder"/"$dmgName" | awk '{print $10}' | sed 's/.*=//'`
                        currentTime=`date +%s`
                        timeDifference=`expr $currentTime - $modifiedTime`
                        #If the downloading file has not been updated in the 10 seconds relative to the current time download may have stalled. Increment error counter.
                        if [[ $timeDifference -gt 10 ]]
                            then
                                echo "$xferPercentage Download may have stalled... ${xferPercentage}%" >&3
                                sleep 5 
                                counter=$(expr $counter + 1)
                            else
                                #Calculate percentage
                                if [[ $pkgPartial =~ ^-?[0-9]+$ ]]
                                    then
                                        xferPercentage=`echo "scale=0; $pkgPartial*100/$pkgTotal" | bc`
                                        echo "$xferPercentage Downloading... ${xferPercentage}%" >&3
                                fi
                        fi
                    #Determine if the file has been moved to the JAMF Waiting room. Exit loop if so to begin install.
                    elif [[ -f "$waitingRoomFolder"/"$dmgName" ]]
                        then
                            writeLog "$dmgName downloaded to $waitingRoomFolder"
                            break
                    else
                        counter=$(expr $counter + 1)
                fi
        fi      
done

## Turn off progress bar by closing file descriptor 3 and removing the named pipe
echo "Closing progress bar."
exec 3>&-
rm -f /tmp/hpipe
}

View solution in original post

mm2270
Legendary Contributor III

Wow, @iJake's script is pretty advanced. Lots of neat stuff going on in there that I'll need to study on the side :)
Thanks for posting your version.

I don't know if this helps or if I'm just muddying the waters at this point, but just in case it helps, here is a version I came up with. Its much simpler - no advanced error state checking or log functions happening, although that could be incorporated. The only reason I'm posting it is because I'm using Casper script parameters for the relevant bits, like the package name, total file size and the policy custom trigger that does the caching.

#!/bin/bash

cdPath="/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog"
DownloadDir="/Library/Application Support/JAMF/Downloads"
WaitingRoomDir="/Library/Application Support/JAMF/Waiting Room"

if [ "$4" != "" ]; then
    PackageName="$4"
else
    echo "Paramater 4 was empty. This needs to contain the full file name of the package that will download. Exiting..."
    exit 1
fi

if [ "$5" != "" ]; then
    ## To get the correct size to use, run a `du /path/to/package.pkg` command
    ## and copy the first column's integers and use them as the string for parameter 5
    RawFileSize="$5"
else
    echo "Paramater 5 was empty. This needs to contain the raw file size of the package that will download in bytes. Exiting..."
    exit 2
fi

if [ "$6" != "" ]; then
    PolicyTrigger="$6"
else
    echo "Paramater 6 was empty. This needs to contain the caching policy trigger string. Exiting..."
    exit 3
fi



function showProgress ()
{

echo "Starting showProgress function..."

exec 20>&-
rm -f /tmp/prog
mkfifo /tmp/prog
sleep 0.2

"$cdPath" progressbar --title "" --text " Please wait. Beginning cache for "${PackageName}"..." --width 500 --icon info --posY top < /tmp/prog &

## Wait just a half sec
sleep 0.5

## Send progress through the named pipe
exec 20<> /tmp/prog


pct=0
while [[ "$pct" -lt 100 ]]; do
    sleep 0.2
    if [ ! -e "${DownloadDir}/${PackageName}" ]; then
        exec 20>&-
        rm -f /tmp/prog
    else
        dlSize=$(du "${DownloadDir}/${PackageName}" | awk '{print $1}' 2>/dev/null)
        if [ "$dlSize" != "" ]; then
            pct=$((dlSize*100/RawFileSize))
            echo "$pct ${pct}% Now caching "${PackageName}"..." >&20
        fi
    fi
done

}


function showError ()
{

"$cdPath" msgbox 
    --title "" 
    --text "There was a problem" 
    --informative-text "The caching policy could not be started. Please check with your administrator for more information." 
    --button1 "  OK  " 
    --icon caution 
    --width 400 
    --posY top 
    --quiet

exit 1

}


## Start off the caching policy, place into background
jamf policy -event "$PolicyTrigger" &>/dev/null &

## Wait until we see the package begin to show up in the Waiting Room before showing a progress bar.
## Wait up to 20 seconds before finally canceling

maxTries=20

x=1
until [[ $(ls "$DownloadDir" | grep "$PackageName") != "" ]]; do
    if [[ "$x" -lt "$maxTries" ]]; then
        sleep 1
        let x=$((x+1))
    else
        break
        showError
    fi  
done

echo "Package is there. We can start"

showProgress &

I'm sure there's like 10 scenarios that could happen during this that I'm not accounting for that @iJake is checking for with his script, so by no means is this better. Just an alternative.

Incidentally, going back to what @alexjdale wrote, for some reason I didn't need to spin off the policy stuff into a LaunchDaemon or other process. I did need to call the progress function in the background though or the script wouldn't exit, despite having exit calls within it. I'm pretty certain its related to calling a policy within a script called by a policy, but I didn't really dig into it much.

Also, you could run an "After" script that uses some of the same script parameters like file name and file size to check if the download was completed and pop up a message to that effect so the user knows everything was OK, or even call Management Action.app for a simple Notification Center message stating the same.

View solution in original post

35 REPLIES 35

alexjdale
Valued Contributor III

If you had a way of determining the progress in the script, you could update a CocoaDialog progress bar every second or so to reflect it. I suppose that could be done by monitoring the size of the file in the waiting room and comparing it to the total file size, which you'd probably need to manually determine and pass to the script somehow.

mm2270
Legendary Contributor III

Are you using a standard caching policy in your JSS policy, like using the "Cache" option for the package? Or, are you using something like an installer that downloads and then installs the "cached" package into a special directory for use later?

If you're using the built in policy option, I don't think there's a way to do it, since the standard policy stuff doesn't have any progress output I'm aware of you can send back to cocoaDialog to "move" the progress bar.

One possible way, which I use a bit in one of my scripts, but haven't used against JSS hosted pkgs, is to do a curl command on the package on your http Casper Share and get the size of the file, which shows up under a line called "Length" You can then use that info in a loop process that runs a du command on the file being downloaded and does math to convert to a percentage. In other words, use the total size and compare against the current size of the file being downloaded to figure out how much percentage-wise its complete. That can then be piped back to cocoaDialog to use for the percentage of the progressbar.
Does that make any sense?

Edit: @alexjdale basically said the same thing I just did.

perrycj
Contributor III

@mm2270 it does make sense and yes @alexjdale essentially said the same thing, ha. Thank you both for responding.

We are just using the cache option/policy from the JSS and then a separate policy to install it. Instead of using curl, you think I could hard code the size of the package since it's static?

Also, would the script with the cocoadialog commands, order wise, have to kick off after the cache policy started? So basically, in the policy, it would go "cache xyz.pkg" then run "progressbar.sh"? I'm just wondering if the script will kick off even if the package hasn't finished caching yet.

mm2270
Legendary Contributor III

Yes, you could hardcode a value of the actual full file size into the script to use (or pass it as a parameter) instead of getting it dynamically with curl.

As for the order, what would need to happen is the caching policy would need to be kicked off, maybe with something like a jamf policy -trigger <sometrigger> call, but placed into the background so the script can continue and then begin checking the local file size. This may all be kind of tricky, because it can take several moments for the download to even start, so essentially, you'd need to include some kind of wait process, where the script waits to see the initial file created in the /Library/Application Support/JAMF/Waiting Room/ directory before it begins the progress bar perhaps, or, pop up the progress bar, but with the understanding that "progress" on the download may not start for a short period.

If I have the time I can try putting together a sample script you can use. I think this is possible, but since I can't say I've done exactly this, I'd have to play with it to see how it would work in practice.

Hope that helps a little for the moment.

perrycj
Contributor III

@mm2270 Yea I think the tricky part is getting the cache to somehow delay so the script can run. We are using a custom trigger for the caching policy to start.

Although now that I write this, I realize I could place it in the script that calls the cache policy to start. I'm just not sure how to put the custom trigger policy on a delay so the script can continue to run to get the percentage once the file starts to cache using cocoadialog.

Thanks for any help you can provide and I may reach out to my rep to see if there is a way to delay a custom trigger policy and then make it resume again, all in the same script. If/when I come up with anything in terms of workflow, I'll post it back here.

alexjdale
Valued Contributor III

In scripts executed by Casper, I've found that you have to use a launchdaemon to truly spin off another execution thread.

You could look at my code here to get an idea of how to echo out and run a launchdaemon/script: https://jamfnation.jamfsoftware.com/discussion.html?id=14940

You should be able to create and load a launchdaemon that runs the policy trigger to cache the package. The main script could then monitor the download and provide progress bar updates. I also have a progress bar update loop in there that you might find useful with some modification.

iJake
Valued Contributor

CocoaDialog can be finicky and you have to use the beta of version 3 for progress to work but here is code to show progress of caching a package. I have a function for when I call the installer too if you need that. You have to tell it the size of the package since it can't be determined dynamically with the way packages ae cached currently.

cdPath="/Path/To/cocoaDialog.app/Contents/MacOS/cocoaDialog"
cdIcon="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ApplicationsFolderIcon.icns"
cdTitle="Dialog Title"
pkgTotal=12064712 #Must know the size of the package
pkgPartial=0
downloadFolder="/Library/Application Support/JAMF/Downloads"
waitingRoomFolder="/Library/Application Support/JAMF/Waiting Room"
dmgName="Package.dmg"

## CocoaDialog Function
dialogDownload()
{
## Create the name pipe input for the progressbar & set brief pause
rm -f /tmp/hpipe
mkfifo /tmp/hpipe
sleep 0.2

## Display progress bar with initial text settings
"$cdPath" progressbar --stoppable --title "Upgrade Package Download Progress" --text "Downloading..." --float < /tmp/hpipe > /tmp/_out &

exec 3< <(yes)

## Send progress through the named pipe
exec 3<> /tmp/hpipe

if { >&3; } 2> /dev/null
    then
        writeLog "Pipe RW verified"
    else
        writeLog "Pipe RW failed"
fi

#Determine PID of jamf process so it can be killed.
trap : SIGTERM SIGINT

echo $$

(jamf policy -event PayloadName ) > /tmp/_out2 &

jamfPID=$!

## Give the policy time to start
sleep 5

#Initialize error counter
counter=0
#While loop to generate package download percent
while [[ $pkgPartial != $pkgTotal ]]
    do
        #Watches for the output of CocoaDialog to equal stopped if "Stop" button is clicked. Cancels install.
        dialogStopCheck=`cat /tmp/_out`
        if [[ "$dialogStopCheck" = "stopped" ]]
            then
                kill $jamfPID
                rm -f /tmp/_out
                rm -f /tmp/_out2
                writeLog "Upgrade cancelled by user."
                exit
        fi
        #Watches for possible jamf binary being upgraded which will fail download of package.
        binaryUpgradeCheck=`cat /private/tmp/_out2 | grep "Upgrading jamf binary..."`
        if [[ "$binaryUpgradeCheck" != "" ]]
            then
                kill $jamfPID
                rm -f /tmp/_out
                rm -f /tmp/_out2
                writeLog "jamf binary upgrade detected. Fixing..."
                jamf policy -event PayloadName >> "$logFile"
                sleep 20
                dialogDownload
        fi
        #Error counter check. Die at 10 errors.
        if [[ $counter -gt 9 ]]
            then
                echo "Package Download failed..." >&3
                sleep 5
                kill $jamfPID
                writeLog "Package download failed."
                exit
            else
                #If the package exists in the download folder determine percentage downloaded.
                if [[ -f  "$downloadFolder"/"$dmgName" ]]
                    then
                        pkgPartial=`du "$downloadFolder"/"$dmgName" | awk '{print $1}'`
                        modifiedTime=`stat -s "$downloadFolder"/"$dmgName" | awk '{print $10}' | sed 's/.*=//'`
                        currentTime=`date +%s`
                        timeDifference=`expr $currentTime - $modifiedTime`
                        #If the downloading file has not been updated in the 10 seconds relative to the current time download may have stalled. Increment error counter.
                        if [[ $timeDifference -gt 10 ]]
                            then
                                echo "$xferPercentage Download may have stalled... ${xferPercentage}%" >&3
                                sleep 5 
                                counter=$(expr $counter + 1)
                            else
                                #Calculate percentage
                                if [[ $pkgPartial =~ ^-?[0-9]+$ ]]
                                    then
                                        xferPercentage=`echo "scale=0; $pkgPartial*100/$pkgTotal" | bc`
                                        echo "$xferPercentage Downloading... ${xferPercentage}%" >&3
                                fi
                        fi
                    #Determine if the file has been moved to the JAMF Waiting room. Exit loop if so to begin install.
                    elif [[ -f "$waitingRoomFolder"/"$dmgName" ]]
                        then
                            writeLog "$dmgName downloaded to $waitingRoomFolder"
                            break
                    else
                        counter=$(expr $counter + 1)
                fi
        fi      
done

## Turn off progress bar by closing file descriptor 3 and removing the named pipe
echo "Closing progress bar."
exec 3>&-
rm -f /tmp/hpipe
}

Hello @iJake ; I know it's a very old thread, but would you have a functioning script with progress Bar for when actually calling the installer? Perhaps with Number of Files processed?

Thanks!

perrycj
Contributor III

@iJake Thanks so much for your response.

It seems to just pass the script for me and not run any of the cocoadialog stuff. Besides the paths at the top of the script, where else needs to be customized?

Currently, I've just filled in my jamfPID, like so:

(jamf policy -event PayloadName ) > /tmp/_out2 &

jamfPID=863

Am I missing something else? Would a custom trigger go in place of "PayloadName"? Let me know your thoughts. Thanks again.

iJake
Valued Contributor

Yeah, sorry, I stripped out my policy names. One of the payloads is the cache policy and another is me installing our agent health daemon. You can just strip that whole part since you don't have it. It's where it's checking if an agent upgrade is happening. You'll also need to fill in the DMG file name and its size. You could always get the name dynamically but I didn't have a need at the time.

perrycj
Contributor III

@iJake Thanks and yea I filled in everything at the top, size, name, etc. I was just having trouble seeing where it was kicking off the caching policy.

From what I can see, if it starts to cache, everything else gets ignored until it's done. How are you getting it to start caching and then also kicking off the cocoadialog stuff? Separate launchdaemon?

iJake
Valued Contributor

This line

(jamf policy -event PayloadName ) > /tmp/_out2 &

It calls the policy, redirects it to that file and then runs its as a background process so the scrip can continue on.

This line

"$cdPath" progressbar --stoppable --title "Upgrade Package Download Progress" --text "Downloading..." --float < /tmp/hpipe > /tmp/_out &

Calls CoocoaDialog with it reading in from the named pipe.

Then anywhere you see >&3 we are sending data to that named pipe.

Let me know if that makes sense. If not, i'd be happy to jump on a WebEx and see if we can get it working for you.

perrycj
Contributor III

@iJake totally makes sense ha. However, I put my custom trigger for the cache policy in place of PayloadName:

(jamf policy -event mytrigger ) > /tmp/_out2 &

and the script basically runs for 2 seconds and finishes. It seems it doesn't call the policy and therefore no progress bars and finishes with nothing happening. If I do "jamf policy -event mytrigger" in terminal on the same mac, the policy works as expected and starts to cache my package. Any ideas?

iJake
Valued Contributor

First, let's get you the logging function I use so we can see what's going

softwareTitle=cachedDialogTest
logFolder="/Library/Logs/FOLDERNAME"
logFile="$logFolder"/"$softwareTitle.log"
timeStamp=$(date "+%Y %b %d %T")
consoleUser=$(stat -f %Su "/dev/console")
logSize=$(stat -f%z $LogFile)

## LOGGING
writeLog(){ echo "[$timeStamp] [$softwareTitle] [$consoleUser]: $1" >> $logFile; }
[[ -d $logFolder ]] || mkdir -p -m 775 "$logFolder"
[[ $logSize -ge $maxSize ]] && rm -rf "$logFile"

Second, are you making sure to tell it the name of the package you are caching?

dmgName="Package.dmg"

perrycj
Contributor III

@iJake Thanks for your continued responses.

So it makes the log folder but no log inside. The JSS policy log says the policy is successful and just says script exit code 0. So, no logging going on or being made, besides the log folder being created. Again, the script finishes running in about 5 seconds. Running the script from terminal yields the same result.

And yes, package name is correct.

iJake
Valued Contributor

Run the script locally in bash debug mode.

sudo bash -x scriptName.sh

perrycj
Contributor III

@iJake Here is the output:

+ softwareTitle=cachedDialogTest
+ logFolder=/Library/Logs/jamfcache
+ logFile=/Library/Logs/jamfcache/cachedDialogTest.log
++ date '+%Y %b %d %T'
+ timeStamp='2016 Jan 22 17:00:51'
++ stat -f %Su /dev/console
+ consoleUser=cp
++ stat -f%z
+ logSize=0
+ [[ -d /Library/Logs/jamfcache ]]
+ [[ 0 -ge '' ]]
+ rm -rf /Library/Logs/jamfcache/cachedDialogTest.log
+ cdPath=/Applications/Utilities/cocoaDialog.app/Contents/MacOS/cocoaDialog
+ cdIcon=/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ApplicationsFolderIcon.icns
+ cdTitle='OS X Installer Cache Progress'
+ pkgTotal=6194494570
+ pkgPartial=0
+ downloadFolder='/Library/Application Support/JAMF/Downloads'
+ waitingRoomFolder='/Library/Application Support/JAMF/Waiting Room'
+ dmgName=InstallOSX_10.11.3_15D21.pkg.zip

And that's where it ends and goes back to the prompt.

iJake
Valued Contributor

OH. You're never calling the function :)

Put dialogDownload at the part where you want the download and dialog to happen.

perrycj
Contributor III

@iJake Ok I think I'm just tired ha but how would that work exactly? Can you give me an example?

iJake
Valued Contributor

Sure. So, what i've sent are some variable definition and functions. To make the function work you need to call it. It takes no arguments so all you do is type out dialogDownload much like you would call a variable just without the $ in front of it. You can see that the logging I use is really just a function and its being called by having its name typed out.

Variable Definitions... #definitions go at the top
variable="stuff"
Function Definitions... #then we create the functions
dialogDownlod()
{
lots of code stuffs here
}
dialogDownload #now we call the function

At any point before or after the function you can have other code

perrycj
Contributor III

@iJake Yup that did it. I feel rather foolish. I was just missing the function at the end the whole time.

The only thing that remains is that the progress stays at 0% and never updates. If I stop the cache through the prompt, and then check the file, it's actually 1 or 2 GB already, but before that it just stays stuck at 212k or whatever the first value is. For the value "partialPkg=0" that stays at 0 correct?

iJake
Valued Contributor

Yeah, it should stay at that 0. Its just the initial definition and we dynamically update it lower. If you run the working script now in debug you should see it doing all the math if its working. Might have to cancel it so you can stop and read the output.

This line does the work to update that number

pkgPartial=`du "$downloadFolder"/"$dmgName" | awk '{print $1}'`

perrycj
Contributor III

@iJake Ok cool.

Well when I go into debug mode in terminal, it just goes crazy and writes forever it seems, all while the progress doesn't move and the display shows 0%. Again, if i cancel it, and click on the file in /Library/Application Support/JAMF/Downloads, it definitely is downloading and usually a GB or two by the time I hit cancel.

Any ideas on what to check?

iJake
Valued Contributor

@perrycj Copy and paste some of the debug output where it is doing that line i showed above.

perrycj
Contributor III

@iJake sure thing.

++ stat -s '/Library/Application Support/JAMF/Downloads/InstallOSX_10.11.3_15D21.pkg.zip'
++ awk '{print $10}'
++ sed 's/.*=//'
+ modifiedTime=1453503069
++ date +%s
+ currentTime=1453503070
++ expr 1453503070 - 1453503069
+ timeDifference=1
+ [[ 1 -gt 10 ]]
+ [[ 747424 =~ ^-?[0-9]+$ ]]
++ echo 'scale=0; 747424*100/6194494570'
++ bc
+ xferPercentage=0
+ echo '0 Downloading... 0%'
+ [[ 747424 != 6194494570 ]]
++ cat /tmp/_out
+ dialogStopCheck=
+ [[ '' = s	opped ]]
++ cat /private/tmp/_out2
++ grep 'Upgrading jamf binary...'
+ binaryUpgradeCheck=
+ [[ '' != '' ]]
+ [[ 0 -gt 9 ]]
+ [[ -f /Library/Application Support/JAMF/Downloads/InstallOSX_10.11.3_15D21.pkg.zip ]]
++ du '/Library/Application Support/JAMF/Downloads/InstallOSX_10.11.3_15D21.pkg.zip'
++ awk '{print $1}'
+ pkgPartial=747584
++ stat -s '/Library/Application Support/JAMF/Downloads/InstallOSX_10.11.3_15D21.pkg.zip'
++ awk '{print $10}'
++ sed 's/.*=//'
+ modifiedTime=1453503070
++ date +%s
+ currentTime=1453503070
++ expr 1453503070 - 1453503070
+ timeDifference=0
+ [[ 0 -gt 10 ]]
+ [[ 747584 =~ ^-?[0-9]+$ ]]
++ echo 'scale=0; 747584*100/6194494570'
++ bc
+ xferPercentage=0
+ echo '0 Downloading... 0%'
+ [[ 747584 != 6194494570 ]]
++ cat /tmp/_out
+ dialogStopCheck=
+ [[ '' = s	opped ]]
++ cat /private/tmp/_out2
++ grep 'Upgrading jamf binary...'
+ binaryUpgradeCheck=
+ [[ '' != '' ]]
+ [[ 0 -gt 9 ]]
+ [[ -f /Library/Application Support/JAMF/Downloads/InstallOSX_10.11.3_15D21.pkg.zip ]]
++ du '/Library/Application Support/JAMF/Downloads/InstallOSX_10.11.3_15D21.pkg.zip'
++ awk '{print $1}'
+ pkgPartial=747808

It looks like it's getting the partial part but just not updating the %

iJake
Valued Contributor

I see it doing the math for the percentage, too. Hmm. Try changing

xferPercentage=`echo "scale=0; $pkgPartial*100/$pkgTotal" | bc`
xferPercentage=$(echo "scale=0; $pkgPartial*100/$pkgTotal" | bc)

perrycj
Contributor III

@iJake nope, % still stays at 0 and progress bar doesn't move.

iJake
Valued Contributor

Okay, not sure what the deal is. Let's pick this up on Monday where we can jump on a WebEx and look at it live.

perrycj
Contributor III

@iJake Ok sounds good, thanks for all your help so far.

mm2270
Legendary Contributor III

Wow, @iJake's script is pretty advanced. Lots of neat stuff going on in there that I'll need to study on the side :)
Thanks for posting your version.

I don't know if this helps or if I'm just muddying the waters at this point, but just in case it helps, here is a version I came up with. Its much simpler - no advanced error state checking or log functions happening, although that could be incorporated. The only reason I'm posting it is because I'm using Casper script parameters for the relevant bits, like the package name, total file size and the policy custom trigger that does the caching.

#!/bin/bash

cdPath="/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog"
DownloadDir="/Library/Application Support/JAMF/Downloads"
WaitingRoomDir="/Library/Application Support/JAMF/Waiting Room"

if [ "$4" != "" ]; then
    PackageName="$4"
else
    echo "Paramater 4 was empty. This needs to contain the full file name of the package that will download. Exiting..."
    exit 1
fi

if [ "$5" != "" ]; then
    ## To get the correct size to use, run a `du /path/to/package.pkg` command
    ## and copy the first column's integers and use them as the string for parameter 5
    RawFileSize="$5"
else
    echo "Paramater 5 was empty. This needs to contain the raw file size of the package that will download in bytes. Exiting..."
    exit 2
fi

if [ "$6" != "" ]; then
    PolicyTrigger="$6"
else
    echo "Paramater 6 was empty. This needs to contain the caching policy trigger string. Exiting..."
    exit 3
fi



function showProgress ()
{

echo "Starting showProgress function..."

exec 20>&-
rm -f /tmp/prog
mkfifo /tmp/prog
sleep 0.2

"$cdPath" progressbar --title "" --text " Please wait. Beginning cache for "${PackageName}"..." --width 500 --icon info --posY top < /tmp/prog &

## Wait just a half sec
sleep 0.5

## Send progress through the named pipe
exec 20<> /tmp/prog


pct=0
while [[ "$pct" -lt 100 ]]; do
    sleep 0.2
    if [ ! -e "${DownloadDir}/${PackageName}" ]; then
        exec 20>&-
        rm -f /tmp/prog
    else
        dlSize=$(du "${DownloadDir}/${PackageName}" | awk '{print $1}' 2>/dev/null)
        if [ "$dlSize" != "" ]; then
            pct=$((dlSize*100/RawFileSize))
            echo "$pct ${pct}% Now caching "${PackageName}"..." >&20
        fi
    fi
done

}


function showError ()
{

"$cdPath" msgbox 
    --title "" 
    --text "There was a problem" 
    --informative-text "The caching policy could not be started. Please check with your administrator for more information." 
    --button1 "  OK  " 
    --icon caution 
    --width 400 
    --posY top 
    --quiet

exit 1

}


## Start off the caching policy, place into background
jamf policy -event "$PolicyTrigger" &>/dev/null &

## Wait until we see the package begin to show up in the Waiting Room before showing a progress bar.
## Wait up to 20 seconds before finally canceling

maxTries=20

x=1
until [[ $(ls "$DownloadDir" | grep "$PackageName") != "" ]]; do
    if [[ "$x" -lt "$maxTries" ]]; then
        sleep 1
        let x=$((x+1))
    else
        break
        showError
    fi  
done

echo "Package is there. We can start"

showProgress &

I'm sure there's like 10 scenarios that could happen during this that I'm not accounting for that @iJake is checking for with his script, so by no means is this better. Just an alternative.

Incidentally, going back to what @alexjdale wrote, for some reason I didn't need to spin off the policy stuff into a LaunchDaemon or other process. I did need to call the progress function in the background though or the script wouldn't exit, despite having exit calls within it. I'm pretty certain its related to calling a policy within a script called by a policy, but I didn't really dig into it much.

Also, you could run an "After" script that uses some of the same script parameters like file name and file size to check if the download was completed and pop up a message to that effect so the user knows everything was OK, or even call Management Action.app for a simple Notification Center message stating the same.

perrycj
Contributor III

@mm2270 Thanks for info. And sorry if you've gotten 38472947298342 notifications from this thread ha.

So I tried out your script and it works, however same thing happens. It sits at 0% and at least for me, our cached package doesn't move into Waiting Room until it's done. It downloads in entirety in the JAMF/Downloads folder and then moves to the Waiting Room. I suspect that's why I only see 0% with your script since it comments to not show a progress bar until it's in the waiting room.

mm2270
Legendary Contributor III

@perrycj Hmm, well, it sounds like there is something being configured wrong. I have a hard time believing that both of our scripts work for us, but just won't for you. I don't doubt what you're saying, but we're overlooking something here.

So let's back up a moment. I can't really help with Jacob's script, so I'll focus on mine for a moment. You set up a policy using this? If so, did you set up the correct parameters. Here's an example of how I have my test policy set up.

Parameter 4: Microsoft_Office_2016_Volume_Installer.pkg
Parameter 5: 2314016
Parameter 6: CacheMyFiles

So, respectively, I've assigned the package name, the package size as seen from du, and the custom trigger that runs the policy which caches the package. So I have 2 policies. One that runs the above script using those parameters, and then a second policy using only the custom trigger also scoped to my Mac. That second policy is only doing the caching of the package. The script then calls that policy by its trigger, which begins the download and the script continues on, looks for the download and begins showing progress by calculating the file size on disk.

As for it moving from Downloads into Waiting Room, that is expected and is what happens. Downloads is a sort of temporary location. Typically items that are downloaded and installed immediately like in regular policies may use that directory, but are cleaned up afterwards. Waiting Room is used for cached items, but it won't move the download there until its complete. My script is only looking for the file in Downloads. Once its then gone, moved to Waiting Room, it shuts the progress bar down.

Anyway, can you verify all your settings are correct, that you have 2 policies set up like above and they are correctly scoped to the test Mac?

EDIT: I just re-read what you said above, and that was a typo on my part in the comments of my script. Originally I was having it watch in Waiting Room, but then realized I was looking in the wrong spot. I just forgot to edit the comment in the script. My bad. I'll change that. Its in fact looking for the file in "Downloads" If you look at the until line, its using "$DownloadDir" to look for the file to begin the progress bar.

perrycj
Contributor III

@mm2270 So I'm an idiot. I had the wrong file size. I had everything else correct in terms of parameters, policies set up correctly, etc. Just had the wrong file size. I changed the file size to the correct value and I am seeing the percentage increase as it downloads. Both of your workflows are working now.

It is very much appreciated for all your help, both @iJake and @mm2270

iJake
Valued Contributor

Glad to help. I need to look over the script @mm2270 wrote to see what he did better. The parameters is a good idea. I never took mine past the one scenarios but that's certainly the more extensible way to go.

ClassicII
Contributor III

@mm2270

Thank you for putting this together as I have been looking for something like this for a long time!

Everything was working except for the actual dialog box would never show up. The policy would work and the file would get cached using the 2 polices. I can not figure out why it is not working.

I then tested it on 10.12.6 and it worked great!!! So something is not mixing right with 10.13.x or 10.13.4.

Any ideas or have you updated the script for 10.13 ?

EDIT: it worked on a different 10.13 machine! please go back to your regular scheduled program. ;)
P.S. Thanks again for putting this together!