Help with a DO loop scripyt

cgiordano
Contributor

When it comes to scripting I'd say I'm mediocre compared to most folks so I need some help really nailing down a DO loop which I don't really use very often.

Purpose of the script: We use ARD to remote into machines so we populate ARD Field #1 on our machines to with the asset tag number that applies to the machine; found on a sticker on the bottom of the laptop. We're looking at moving over to DEP and I'll need a way for the user to enter the asset tag number for us since we, as techs, are no longer doing since we're not building the machine any longer.

I'd like for the script to basically not exit until the user has entered an integer into Cocoa Dialog field that is appearing on screen. It's mostly working but it's definitely not pretty and the pop-ups are not appearing in the order I'd like every single time.

#!/bin/bash

## Global Variables
CD="/Applications/Utilities/CocoaDialog.app/Contents/MacOS/CocoaDialog"
jamfHelper='/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper'
icon='/Users/Shared/icon.png'

## Global functions
enterTag()
{
tag=`"${CD}" standard-inputbox --title "Asset Tag Number Required" --informative-text "Please enter the asset tag number of your computer" --text "Your asset tag can be found on the bottom of your laptop." --float --no-cancel | tail -1`

if [[ $tag =~ ^-?[0-9]+$ ]]; then
        intCheck="0"
else
        "${jamfHelper}" -windowType utility -icon "$icon" -title "Incorrect Asset Tag Entered" -description "Letters are not allowed in your asset tag.  Please re-enter your asset tag using only numbers" -button1 "OK" -defaultButton 1
        intCheck="2"
fi
}

## Run the function
enterTag
echo "pre-loop"

while [[ $intCheck == "2" ]]; do
        enterTag
        echo "first do loop"
done

tagConfirm=`"${CD}" msgbox --title "Asset Tag Confirmation" --informative-text <<EOF "You said you're asset tag is: $tag. 
Is that correct?" EOF --button1 "Yes" --button2 "No" --string-ouput`

while [ $tagConfirm == "2" ]; do
        echo "second do loop"
        enterTag
        tagConfirm=`"${CD}" msgbox --title "Asset Tag Confirmation" --informative-text <<EOF "You said you're asset tag is: $tag. 
Is that correct?" EOF --button1 "Yes" --button2 "No" --string-ouput`

        while [ "$intCheck" = "2" ]; do
                echo "third do loop"
                enterTag
                tagConfirm=`"${CD}" msgbox --title "Asset Tag Confirmation" --informative-text <<EOF "You said you're asset tag is: $tag. 
Is that correct?" EOF --button1 "Yes" --button2 "No" --string-ouput`
        done
done

#/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -computerinfo -set1 -1 $tag

Any help would be greatly appreciated!
Thanks!
Chris

1 ACCEPTED SOLUTION

mm2270
Legendary Contributor III

Hey @cgiordano I can offer some advice on this. I would consider rewriting this into a couple of functions within the script and then calling them when needed. You may not be aware of it, but a function can be called or re-run by a result returned within the function itself, which can create the kind of loop you're looking for, I believe.

I took a little time to rewrite your script using just cocoaDialog only, although you could certainly try to incorporate jamfHelper into this if you really want to. I'm also using the last beta 3 version of cocoaDialog, which has some extra features I'm using below, such as value-required and empty-text The value-required flag is used with things like inputbox and other window types to ensure a value is entered or a box selected, etc before confirming with a button. Meaning it's impossible to click OK or Enter and have an empty value in the field. The dialog won't allow it. The empty-text flag is used to customize the sheet that appears when no value is detected.

In the below, you'll see I broke this up into 2 functions. The first one calls the asset tag enter dialog, then checks to see if the value returned is an integer. Here. I'm doing some simple math by dividing the value entered by itself, which will always yield "1" if it's an integer. If that fails, it calls the function again, but in order to make the text appear differently, it sets a loop flag, which gets checked each time the function is run and sets either the error text for the dialog, or the original text. If the value entered is good, it clears the loop flag in preparation for if it gets called again.
From there, it pops up the confirmation dialog, checks for which button was clicked and if the user clicks No, it calls the original function to enter the asset tag again. If they click Yes, it moves onto setting the tag in the ARD field. In this way, you can keep going round and round almost indefinitely. For example, enter "123" then click No on the confirmation, then enter "456" then click No again and enter "789" and so on and so until the integer value is confirmed by clicking "Yes"

I added comments to most items so it's easy (hopefully) to see what's actually going on.
Give this script a try to see how it works for you. I would suggest getting the CD 3 beta version though since I can't predict how it will work under the 2.x release.

#!/bin/bash

## Path to cocoaDialog binary
CD="/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog"

function checkTag ()
{

## Display dialog asking for confirmation that the tag entered was correct
confirmTag=$("$CD" msgbox 
    --title "Asset Tag Confirmation" 
    --text "Confirm Asset Tag" 
    --informative-text "You said you're asset tag is: $tag

Is that correct?" 
    --button1 "  Yes  " 
    --button2 "  No  " 
    --icon info)

## Check the button clicked
if [ "$confirmTag" == "1" ]; then
    echo "Tag was confirmed by user"

    ## User confirmed. Write the value entered into the ARD info field for the system
    #/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -computerinfo -set1 -1 $tag
elif [ "$confirmTag" == "2" ]; then
    ## User clicked No. Re-run the function to ask for the asset tag
    echo "Re-running enter asset tag"
    enterTag
fi

}


function enterTag ()
{

## Default title string for dialog
Title="Asset Tag"

## If the loop flag is set, set the dialog strings to the error values
if [ "$loop" ]; then
    Text="Incorrect Asset Tag Entered.

Letters are not allowed in your asset tag. Please re-enter your asset tag using only numbers"
else
    ## If the loop flag is NOT set, set the dialog strings to their normal values
    Text="Asset Tag Number Required.

Please enter the asset tag number of your computer"
fi

## Display dialog asking for asset tag value
tag=$("${CD}" inputbox 
    --title "$Title" 
    --text "" 
    --informative-text "$Text" 
    --button1 " Enter " 
    --value-required 
    --empty-text "You must enter a value to continue" 
    --icon computer 
    --quiet)

## Run a math function to determine if the value entered was an integer
## Divides the value by itself, which will always be "1" if an integer, or error if not

check=$(expr $tag / $tag 2>/dev/null)

## Check on the value returned from above
if [[ "$check" == "1" ]]; then
    echo "Integer entered. Continuing."
    ## Blank out the loop flag
    loop=""
    ## Run the checkTag function
    checkTag
else
    echo "Non-integer entered. Re-run function"
    ## Set the loop flag
    loop="Yes"
    ## Run the enterTag function again
    enterTag
fi

}

## Starts here. Run the function asking for the asset tag
enterTag

View solution in original post

4 REPLIES 4

mm2270
Legendary Contributor III

Hey @cgiordano I can offer some advice on this. I would consider rewriting this into a couple of functions within the script and then calling them when needed. You may not be aware of it, but a function can be called or re-run by a result returned within the function itself, which can create the kind of loop you're looking for, I believe.

I took a little time to rewrite your script using just cocoaDialog only, although you could certainly try to incorporate jamfHelper into this if you really want to. I'm also using the last beta 3 version of cocoaDialog, which has some extra features I'm using below, such as value-required and empty-text The value-required flag is used with things like inputbox and other window types to ensure a value is entered or a box selected, etc before confirming with a button. Meaning it's impossible to click OK or Enter and have an empty value in the field. The dialog won't allow it. The empty-text flag is used to customize the sheet that appears when no value is detected.

In the below, you'll see I broke this up into 2 functions. The first one calls the asset tag enter dialog, then checks to see if the value returned is an integer. Here. I'm doing some simple math by dividing the value entered by itself, which will always yield "1" if it's an integer. If that fails, it calls the function again, but in order to make the text appear differently, it sets a loop flag, which gets checked each time the function is run and sets either the error text for the dialog, or the original text. If the value entered is good, it clears the loop flag in preparation for if it gets called again.
From there, it pops up the confirmation dialog, checks for which button was clicked and if the user clicks No, it calls the original function to enter the asset tag again. If they click Yes, it moves onto setting the tag in the ARD field. In this way, you can keep going round and round almost indefinitely. For example, enter "123" then click No on the confirmation, then enter "456" then click No again and enter "789" and so on and so until the integer value is confirmed by clicking "Yes"

I added comments to most items so it's easy (hopefully) to see what's actually going on.
Give this script a try to see how it works for you. I would suggest getting the CD 3 beta version though since I can't predict how it will work under the 2.x release.

#!/bin/bash

## Path to cocoaDialog binary
CD="/Library/Application Support/JAMF/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog"

function checkTag ()
{

## Display dialog asking for confirmation that the tag entered was correct
confirmTag=$("$CD" msgbox 
    --title "Asset Tag Confirmation" 
    --text "Confirm Asset Tag" 
    --informative-text "You said you're asset tag is: $tag

Is that correct?" 
    --button1 "  Yes  " 
    --button2 "  No  " 
    --icon info)

## Check the button clicked
if [ "$confirmTag" == "1" ]; then
    echo "Tag was confirmed by user"

    ## User confirmed. Write the value entered into the ARD info field for the system
    #/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -computerinfo -set1 -1 $tag
elif [ "$confirmTag" == "2" ]; then
    ## User clicked No. Re-run the function to ask for the asset tag
    echo "Re-running enter asset tag"
    enterTag
fi

}


function enterTag ()
{

## Default title string for dialog
Title="Asset Tag"

## If the loop flag is set, set the dialog strings to the error values
if [ "$loop" ]; then
    Text="Incorrect Asset Tag Entered.

Letters are not allowed in your asset tag. Please re-enter your asset tag using only numbers"
else
    ## If the loop flag is NOT set, set the dialog strings to their normal values
    Text="Asset Tag Number Required.

Please enter the asset tag number of your computer"
fi

## Display dialog asking for asset tag value
tag=$("${CD}" inputbox 
    --title "$Title" 
    --text "" 
    --informative-text "$Text" 
    --button1 " Enter " 
    --value-required 
    --empty-text "You must enter a value to continue" 
    --icon computer 
    --quiet)

## Run a math function to determine if the value entered was an integer
## Divides the value by itself, which will always be "1" if an integer, or error if not

check=$(expr $tag / $tag 2>/dev/null)

## Check on the value returned from above
if [[ "$check" == "1" ]]; then
    echo "Integer entered. Continuing."
    ## Blank out the loop flag
    loop=""
    ## Run the checkTag function
    checkTag
else
    echo "Non-integer entered. Re-run function"
    ## Set the loop flag
    loop="Yes"
    ## Run the enterTag function again
    enterTag
fi

}

## Starts here. Run the function asking for the asset tag
enterTag

geoffrepoli
Contributor
 assetNumber=$(osascript -e 'display dialog "Enter Asset Number:" default answer "" giving up after 86400 with text buttons {"OK"} default button 1' -e 'return text returned of result')
 until [[ $assetNumber =~ ^-?[0-9]+([.][0-9]+)?$ ]]
 do assetNumber=$(osascript -e 'display dialog "Invalid Asset Number. Try again:" default answer "" giving up after 86400 with text buttons {"OK"} default button 1' -e 'return text returned of result')
 done

Or a basic loop that verifies

#!/usr/bin/env bash

getAssetNumber() {
 assetNumber=$(osascript -e 'display dialog "Enter Asset Number:" default answer "" giving up after 86400 with text buttons {"OK"} default button 1' -e 'return text returned of result')
 until [[ $assetNumber =~ ^-?[0-9]+([.][0-9]+)?$ ]]
 do assetNumber=$(osascript -e 'display dialog "Invalid Asset Number. Try again:" default answer "" giving up after 86400 with text buttons {"OK"} default button 1' -e 'return text returned of result')
 done
 verify=$(osascript -e 'display dialog "Confirm Asset Number:" default answer "" giving up after 86400 with text buttons {"Confirm"} default button 1' -e 'return text returned of result')
}

getAssetNumber
until [[ $verify = $assetNumber ]]
do getAssetNumber
done

CapU
Contributor III

@mm2270 Is a rock star

cgiordano
Contributor

Wow. These are both really great solutions. I was clearly trying to over complicate the process. I'm UNTIL and WHILE loops and cycling functions are definitely power tools that I just need more time and experience with. I really appreciate you both taking the time to help me out.

I will say that I went with @grepoli's solution for the time being because I had some of what he suggested already in place but once the beta features are rolled into the CD release I'll probably rollover to @mm2270.

Thanks again to you both!