├── ADPassMonHelper └── ADPassMonHelper.sh ├── BackupRestoreUsers ├── BackupRestoreUsers.sh ├── BackupUsers.command └── RestoreUsers.command ├── CasperImagingDeploy ├── postinstall.sh └── preinstall.sh ├── FVHelper ├── FVHelper.png ├── fvhelper.sh └── readme.md ├── QuickAddHelper ├── Enroll.command └── quickadd.command ├── README.md ├── cfgScripts ├── cfgsysAddPrinterAdmin.sh ├── cfgsysComputerName.sh ├── cfgsysDefaultDesktopImg.sh ├── cfgsysDisableDSStores.sh ├── cfgsysDisableSetupAssist.sh ├── cfgsysDisableTimeMachineoffers.sh ├── cfgsysDockFixupRemove.sh ├── cfgsysEnableARD.sh ├── cfgsysEnableSSH.sh ├── cfgsysEnableVNC.sh ├── cfgsysFinderDefaults.sh ├── cfgsysHideMacintoshHD.sh ├── cfgsysLocaleRegion.sh ├── cfgsysMouseCfg2Button.sh ├── cfgsysSWUpdateOff.sh ├── cfgsysSetTimeManual.sh ├── cfgsysUnBindAD.sh ├── cfguserFinderNSNavDefaults.sh ├── cfguserMountHome.sh ├── cfguserMountShares.sh └── cfguserShareAlias.sh ├── dockBuilder ├── dockBuilder.sh ├── docs │ ├── ss1.png │ ├── ss2.png │ └── ss3.png └── readme.md ├── extattributes ├── ea_sepdef_date.sh ├── ea_sepdef_days.sh └── ea_timemachine_days.sh ├── infoAboutMyMac.sh ├── jamfCredEncypter.command ├── profileInstaller └── postinstall.sh ├── progressScreenHelper.py ├── superrecon.sh ├── synccdps ├── com.github.loceee.synccdps.plist └── synccdps.sh ├── zzz_flushPolicyHistory.sh └── zzz_partionhd.sh /ADPassMonHelper/ADPassMonHelper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # ADPassMonHelper.sh 4 | # 5 | # run on casper login trigger, check if user is AD 6 | # writes adpassmon prefs and launches ADPassMon if so. 7 | # 8 | # macmule's fork - https://macmule.com/2014/04/01/announcing-adpassmon-v2-fork/ 9 | # 10 | 11 | adpassmon="/Applications/Utilities/ADPassMon.app" 12 | userloggedin="${3}" 13 | 14 | expireage=${4} 15 | passwordpolicytext="${5}" 16 | 17 | uniqueid=$(echo $(dscl . read /Users/${userloggedin} UniqueID 2> /dev/null | awk '{print $2}')) 18 | 19 | if [ -z "${uniqueid}" ] || (( ${uniqueid} > 1000 )) # if user doesn't exist in localds, or uid is > 1000 - network user 20 | then 21 | echo "${userloggedin} is an AD account" 22 | if [ -f "${adpassmon}/Contents/MacOS/ADPassMon" ] 23 | then 24 | echo "writing ADPassMon preferences ..." 25 | sudo -u ${userloggedin} defaults write org.pmbuko.ADPassMon expireAge -int ${expireage} 26 | sudo -u ${userloggedin} defaults write org.pmbuko.ADPassMon pwPolicy -string "${passwordpolicytext}" 27 | sudo -u ${userloggedin} defaults write org.pmbuko.ADPassMon selectedBehaviour -int 2 28 | sudo -u ${userloggedin} defaults write org.pmbuko.ADPassMon prefsLocked -bool true 29 | echo "launching ADPassMon ..." 30 | sudo -u "${userloggedin}" "${adpassmon}/Contents/MacOS/ADPassMon" & 31 | else 32 | echo "ADPassMon is NOT installed, doing nothing" 33 | fi 34 | else 35 | echo "${userloggedin} is a local user, doing nothing" 36 | fi 37 | exit 0 38 | -------------------------------------------------------------------------------- /BackupRestoreUsers/BackupRestoreUsers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | version="0.99" 3 | # 4 | # BackupRestoreUsers 5 | # 6 | # INTERACTIVE MODE 7 | # ---------------- 8 | # usage: 9 | # 10 | # configure your backuprepo as below (default: backuproot="$(dirname "$0")/_UserBackups") 11 | # 12 | # or 13 | # 14 | # copy the script folder to a share, then launch script via the xxx.command wrappers. 15 | # 16 | # CASPER IMAGING MODE 17 | #-------------------- 18 | # usage: 19 | # as casper imaging is a little difficult with it's scripting workflows it goes like this. 20 | # 21 | # configure your backuprepo as below (either backuproot=/Volume/LocalHD, afpurl, smburl) 22 | # or 23 | # use the network segment section so you can find the nearest backupserver automatically. 24 | # 25 | # set 'caspermode=true' 26 | # uncomment 'mode="backup"' 27 | # save as 'BackupRestoreUsers-backup.sh' 28 | # do the same for 'mode="restore"' 29 | # save as 'BackupRestoreUsers-restore.sh' 30 | # 31 | # you should now have 2 scripts, a backup and restore mode script. 32 | # 33 | # upload both Casper Admin repo. 34 | # 35 | # allocate it to a configuration 36 | # 37 | # get info set the -backup.sh to run BEFORE, and -restore.sh to run AFTER 38 | # 39 | # 40 | # CDP mode 41 | # --------- 42 | # If you had an additonal UserBackup share on your CDPs, you can set the script 43 | # to cdpmode=true, it will look for a mounted "CasperShare" (set in $caspersharename) 44 | # and then attempt to mount and backup/restore to/from that server/share using the 45 | # supplied credentials. In a multisite install this could be helpful and reduce config 46 | # and admin overhead --- findServer - function assumes afp CDP. adjust as you see fit 47 | # 48 | # 49 | # more info lachlan.stewart@interpublic.com 50 | ############################################################## 51 | 52 | 53 | ############################### 54 | # 55 | # configure from here 56 | # 57 | ############################### 58 | 59 | caspermode=false # enable casper imaging mode (auto - nooptions to restore a different backup, logs log and doesn't recognise command switches) 60 | #mode="backup" # set mode for use with casper - set priority to run before 61 | #mode="restore" # set mode for use with casper - set priority to run after 62 | 63 | userfolder="/Users" 64 | altuserpart="/Volumes/Data" # watch for this user partition/path and use if seen (good if using fstab method to mount a userpartion eg. "/Volumes/UserHD/Users") 65 | excludedusers="^\.|Shared|Deleted Users|admin|Library" # first line excludes all files starting with "." add anymore here... 66 | restoreto="$userfolder" 67 | 68 | showlog=true # open the log during 69 | 70 | rsyncexcludes=( ".Spotlight-V100" ".fseventsd" ".TemporaryItems" "**/Library/Application Support/Google/Chrome/Safe Browsing Download/**" ) # exclude any know troublesome files from copy 71 | 72 | debug=false # dump to debuglog - very verbose - just for me. 73 | 74 | ############################### 75 | # 76 | # backup repo config 77 | # 78 | ############################### 79 | 80 | # 81 | # cdp mode 82 | # 83 | 84 | cdpmode=false 85 | caspersharename="CasperShare" # share name to grep mount for, find your cdp mount 86 | userbackupcredentials="userbackup:userbackup" # username:password to mount userbackup share from mounted cdp 87 | userbackupshare="UserBackup" 88 | 89 | # 90 | # manual backuproot 91 | # 92 | 93 | backuproot="$(dirname "$0")/_UserBackups" # backup to ./_UserBackups/ in this script folder 94 | 95 | # single network destinations 96 | # ---------------------------- 97 | # afp://[username:password]@rhost[:port]/volume 98 | #afpurl="afp://username:password@servername/backup" 99 | # //[domain;][user[:password]@]server[/share] path 100 | #smburl="//username:password@servername/backup" 101 | 102 | # network segment specific destinations 103 | # -------------------------------------- 104 | # edit the xxx.xxx.xxx and associated xxxurl= 105 | # 106 | # or (comment out networksegment to disable) 107 | 108 | #networksegment=$(ipconfig getifaddr en0 | cut -d. -f1-3) # ip and cut last quad for network segment 109 | 110 | if [ "$networksegment" != "" ] 111 | then 112 | case $networksegment in 113 | 10.132.11 ) 114 | # site1 115 | afpurl="afp://userbackup:userbackup@server1.domain.com/UserBackup" 116 | ;; 117 | 10.128.15 ) 118 | # site2 119 | afpurl="afp://userbackup:userbackup@server2.domain.com/UserBackup" 120 | ;; 121 | 10.132.9 ) 122 | # site3 123 | afpurl="afp://userbackup:userbackup@server3.domain.com/UserBackup" 124 | ;; 125 | 10.132.108 | 10.128.20 | 10.132.3 | 10.132.12 ) 126 | # site4 - handle multi matches like this 127 | afpurl="afp://userbackup:userbackup@server4.domain.com/UserBackup" 128 | ;; 129 | *) 130 | # default fallback 131 | echo "Unhandled network segment -- $networksegment - using default" 132 | afpurl="afp://userbackup:userbackup@mainserver/UserBackup" 133 | ;; 134 | esac 135 | fi 136 | 137 | scriptname="BackupRestoreUsers" 138 | 139 | ##################################### 140 | # 141 | # End of configurable settings 142 | # 143 | ##################################### 144 | 145 | # 146 | # some common fuctions 147 | # 148 | 149 | secho() 150 | { 151 | # superecho - writes to log and will display a dialog to gui with timeout (a kludge for UI feedback in CI) 152 | message="$1" 153 | dialogtimeout="$2" 154 | echo "$message" 155 | echo "$message" >> "$logto/$log" 156 | [ "$dialogtimeout" != "" ] && osascript -e "tell app \"System Events\"" -e "activate" -e "display dialog \"$message\" buttons {\"...\"} giving up after $dialogtimeout" -e "end tell" > /dev/null 157 | } 158 | 159 | errorHander() 160 | { 161 | # Error function 162 | message="$1" 163 | secho "ERROR: $message" 164 | osascript -e "tell app \"System Events\"" -e "activate" -e "display dialog \"$message\" buttons {\"OK\"} default button {\"OK\"} with title \"Error\"" -e "end tell" > /dev/null 165 | cp "$logto/$log" "$backuppath/$log.ERROR.log" 166 | rm "$logto/$log" 167 | killall "Casper Imaging" 168 | exit 1 169 | } 170 | 171 | askQuestion() 172 | { 173 | message=$1 174 | button1=$2 #default 175 | button2=$3 176 | timeout=$4 #will return default after 177 | # we'll follow apple convention... default button should be right bottommost (button1) 178 | if [ "$timeout" != "" ] 179 | then 180 | buttonreturn=$(osascript -e "tell app \"System Events\"" -e "activate" -e "display dialog \"$message\n\n\n(Default: $button1 in $timeout secs)\" buttons {\"$button2\",\"$button1\"} default button {\"$button1\"} giving up after $timeout" -e "end tell") 181 | else 182 | # no timeout.. important questions 183 | buttonreturn=$(osascript -e "tell app \"System Events\"" -e "activate" -e "display dialog \"$message\" buttons {\"$button2\",\"$button1\"} default button {\"$button1\"}" -e "end tell") 184 | fi 185 | [ "$(echo $buttonreturn | grep "gave up:true")" != "" ] && result=1 # timeout, return default 1 186 | [ "$(echo $buttonreturn | grep -w "$button1")" != "" ] && result=1 187 | [ "$(echo $buttonreturn | grep -w "$button2")" != "" ] && result=2 188 | echo $result 189 | } 190 | 191 | # 192 | # core brains 193 | # 194 | 195 | findServer() 196 | { 197 | server=$(mount | grep $caspersharename | cut -d'@' -f2- | cut -d':' -f-1) 198 | # if there was no mount with caspershare, don't set afp url 199 | [ "$server" != "" ] && afpurl="afp://$userbackupcredentials@$server/$userbackupshare" 200 | } 201 | 202 | 203 | mountShare() 204 | { 205 | # this code is for automounting network shares, if running the script via ARD / Casper Imaging / DeployStudio 206 | # lets try to mount network volume, no error checking here... expecting properly formed urls to be passed to mount_afp/smb 207 | secho "Mounting the network share..." 1 208 | share=$(echo "$networkbackuppath" | cut -d'/' -f 4-) 209 | mountpath="/Volumes/$share" 210 | mkdir "$mountpath" 211 | # check if afp or smb 212 | if [ "$afpurl" != "" ] 213 | then 214 | mount_afp "$afpurl" "$mountpath" 215 | mounterror="$?" 216 | fi 217 | if [ "$smburl" != "" ] 218 | then 219 | mount_smb "$smburl" "$mountpath" 220 | mounterror="$?" 221 | fi 222 | if [ "$mounterror" != "0" ] 223 | then 224 | errorHander "There was a problem mounting the network share $share - mount_afp/smb returned $mounterror" 225 | exit 1 226 | fi 227 | backuproot="$mountpath/_UserBackups" 228 | [ ! -d "$backuproot" ] && mkdir "$backuproot" 229 | # end network mount 230 | } 231 | 232 | unmountShare() 233 | { 234 | #if we are using a network share, unmount it 235 | cd / 236 | secho "Unmounting $mountpath" 1 237 | sleep 1 238 | umount "$mountpath" 239 | 240 | if [ "$?" != "0" ] 241 | then 242 | echo "Forcing unmount" 243 | diskutil unmount force "$mountpath" 244 | if [ "$?" != "0" ] 245 | then 246 | errorHander "There was a problem unmounting $backuproot" 247 | fi 248 | fi 249 | } 250 | 251 | excludeUsers() 252 | { 253 | while true 254 | do 255 | # generate a dialog message for exlusions 256 | message=$( 257 | echo -ne "Would you like to exclude any users?\n" 258 | echo -ne "\n" 259 | echo -ne " Users to backup\n" 260 | echo -ne "-------------------------\n" 261 | echo -ne "\n" 262 | for user in $(ls $userfolder | grep -vE "$excludedusers") 263 | do 264 | echo -ne "$user " 265 | if [ -f "$userfolder/.$user-excluded" ] 266 | then 267 | echo -ne " - EXCLUDED\n" 268 | else 269 | echo -ne "\n" 270 | fi 271 | done 272 | ) 273 | answer=$(askQuestion "$message" "Start Backup" "Exclude Users" 15) 274 | if [ "$answer" == "2" ] 275 | then 276 | for user in $(ls $userfolder | grep -vE "$excludedusers") 277 | do 278 | answer=$(askQuestion "User:\n\n$user\n" "Include" "Exclude") 279 | if [ "$answer" == "1" ] 280 | then 281 | # remove exclusion if it exists 282 | [ -f "$userfolder/.$user-excluded" ] && rm "$userfolder/.$user-excluded" 283 | else 284 | # flag them as excluded 285 | touch "$userfolder/.$user-excluded" 286 | fi 287 | done 288 | else 289 | # don't exclude anymore 290 | break 291 | fi 292 | done 293 | } 294 | 295 | chooseUserfolder() 296 | { 297 | # in case you User partition isn't found, GUI to select a difference backup source 298 | answer=$(askQuestion "Do you want to backup from:\n\n\n$userfolder" "Yes" "Choose different..." 20) 299 | if [ "$answer" == "2" ] 300 | then 301 | newuserfolder=$(/usr/bin/osascript << EOT 302 | tell application "Finder" 303 | activate 304 | set theFolder to (choose folder with prompt "Choose another /Users folder to backup:") 305 | return (POSIX path of theFolder) 306 | end tell 307 | EOT) 308 | fi 309 | # if a new location is chosen, use it 310 | [ ! -z "$newuserfolder" ] && userfolder="$newuserfolder" 311 | } 312 | 313 | chooseBackup() 314 | { 315 | while true 316 | do 317 | # generate a dialog message for backuplist 318 | message=$( 319 | echo -ne " Available Backups\n" 320 | echo -ne "-------------------------\n" 321 | echo -ne "\n" 322 | [ -f "$backuproot/.DS_Store" ] && rm "$backuproot/.DS_Store" # just in case someone has been poking around in Users) 323 | for backupid in $(ls "$backuproot") 324 | do 325 | echo -ne "$backupid\n" 326 | done 327 | ) 328 | answer=$(askQuestion "$message" "Select a Backup..." "Quit") 329 | if [ "$answer" == "1" ] 330 | then 331 | for backupid in $(ls "$backuproot") 332 | do 333 | answer=$(askQuestion "BackupID: $backupid" "Next" "Select") 334 | if [ "$answer" == "2" ] 335 | then 336 | # set new backup 337 | uniqueid="$backupid" 338 | backuppath="$backuproot/$uniqueid" 339 | backupsettings="$backuppath/BackupSettings" 340 | return 0 341 | fi 342 | done 343 | else 344 | # jump out 345 | return 2 346 | fi 347 | done 348 | } 349 | 350 | backupUsers() 351 | { 352 | [ -d "$altuserpart" ] && userfolder="$altuserpart" # if we find alternate user partion, point at it 353 | 354 | if $caspermode 355 | then 356 | # if we wish to run an automated image, skipping backup... touch /Users/.nobackup before executing script 357 | # but double check before skpping the backup. 358 | if [ -f "$userfolder/.nobackup" ] 359 | then 360 | answer=$(askQuestion "### This Mac has been flagged NOT to Backup ###\n\n($userfolder/.nobackup exists)" "Don't Backup - WIPE IT ALL" "Remove flag and continue..." 30) 361 | if [ "$answer" == "1" ] 362 | then 363 | # flag to save us checking for backups to restore post imaging 364 | touch "/tmp/.nobackup-$uniqueid" 365 | return 0 366 | else 367 | # remove the flag and run as normal 368 | rm "$userfolder/.nobackup" 369 | fi 370 | fi 371 | 372 | answer=$(askQuestion "Do you want to backup user data on this Mac?" "Backup" "Don't Backup" 20) 373 | if [ "$answer" == "2" ] 374 | then 375 | answer=$(askQuestion "Are you really sure?\n\nAll user data will be LOST!" "Backup" "Wipe it ALL!") 376 | if [ "$answer" == "2" ] 377 | then 378 | # flag to save us checking for backups after restore 379 | touch "/tmp/.nobackup-$uniqueid" 380 | return 0 381 | fi 382 | fi 383 | fi 384 | 385 | # Check to see if there is an existing backup for this Mac 386 | if [ -d "$backuppath" ] 387 | then 388 | # check to see if it's complete 389 | if [ "$(defaults read $backupsettings BackupComplete)" != "1" ] 390 | then 391 | # if there is an incomplete backup, prompt... default to overwrite.. or give option to abort and sort it out. 392 | answer=$(askQuestion "There is an INCOMPLETE backup, would you like to overwrite it?" "Backup and Overwrite" "Abort" 20) 393 | [ "$answer" == "2" ] && errorHander "There is already a backup @ $backuppath ... Aborting..." 394 | else 395 | # if there is an COMPLETE backup, prompt... default to abort.. or give option to overwrite... 396 | if [ "$(defaults read $backupsettings HasBeenRestored)" == "1" ] 397 | then 398 | answer=$(askQuestion "There is an existing COMPLETE backup which HAS been restored, would you like to overwrite it?" "Backup and Overwrite" "Abort" 20) 399 | [ "$answer" == "2" ] && errorHander "There is already a backup @ $backuppath ... Aborting..." 400 | else 401 | answer=$(askQuestion "WARNING! There is an existing COMPLETE backup which HAS NOT been restored, would you like to overwrite it?" "Abort" "Backup and Overwrite" 60) 402 | [ "$answer" == "1" ] && errorHander "There is already a backup @ $backuppath ... Aborting..." 403 | fi 404 | fi 405 | # remove the old / existing backup 406 | rm -R "$backuppath" 407 | fi 408 | 409 | chooseUserfolder 410 | 411 | excludeUsers 412 | 413 | answer=$(askQuestion "Would you like to flush user Trashes?" "Flush" "Don't Flush" 5) 414 | if [ "$answer" == "1" ] 415 | then 416 | flushtrash=true 417 | else 418 | flushtrash=false 419 | fi 420 | 421 | #answer=$(askQuestion "Would you like to flush user Caches?" "Flush" "Don't Flush" 5) 422 | #if [ "$answer" == "1" ] 423 | #then 424 | # flushcache=true 425 | #else 426 | # flushcache=false 427 | #fi 428 | 429 | # make paths and copy the logs to the server so we don't run out of space 430 | mkdir "$backuppath" 431 | mkdir "$backuppath/logs" 432 | cp "$logto/$log" "$backuppath/logs/$log" 433 | rm "$logto/$log" 434 | logto="$backuppath/logs" 435 | 436 | secho 437 | secho "Backing up $uniqueid" 438 | secho 439 | secho "Scanning and sizing home folders ..." 2 440 | secho "--------------------------------------" 441 | secho 442 | 443 | # open the log in console for more feedback 444 | [ $showlog ] && open "$logto/$log" 445 | 446 | usercount=0 447 | totalsize=0 448 | 449 | # get all the user folders in /User, process them and get size in bytes 450 | for user in $(ls $userfolder | grep -vE "$excludedusers") 451 | do 452 | if [ ! -f "$userfolder/.$user-excluded" ] # check if they are excluded 453 | then 454 | 455 | if $flushtrash 456 | then 457 | secho "Flushing Trash for $user..." 458 | rm -R "$userfolder/$user/.Trash" 459 | fi 460 | 461 | #if $flushcache 462 | #then 463 | # secho "Flushing Trash for $user..." 464 | # rm -R "$userfolder/$user/Library/Caches/" 465 | #fi 466 | 467 | secho "Sizing home for $user..." 468 | size=$(( $(du -sk "$userfolder/$user" | awk '{print $1}') * 1024 )) 469 | secho "$user - $(($size / 1024 / 1024 )) MB" 2 470 | userarray[$usercount]="$user" 471 | sizearray[$usercount]="$size" 472 | totalsize=$(( $totalsize + $size )) 473 | (( usercount ++ )) 474 | else 475 | secho "$user - EXCLUDED" 476 | fi 477 | done 478 | 479 | # get free space on back up disk 480 | backupfree=$(( $(df -k "$backuproot" | tail -n1 | awk '{ print $4 }') * 1024 )) 481 | 482 | secho "----------------------------------------------------------------------------------" 483 | secho "Total for $usercount user(s) is $(( $totalsize / 1024 / 1024 )) MBs - Free space on backup volume is $(( backupfree / 1024 / 1024 )) MBs" 2 484 | secho "----------------------------------------------------------------------------------" 485 | if [ $totalsize -gt $backupfree ] 486 | then 487 | answer=$(askQuestion "There may not be enough free space on Backup volume" "Continue" "Stop" 30) 488 | if [ "$answer" == "2" ] 489 | then 490 | # error out ... 491 | errorHander "There is not enough space on the backup volume." 492 | else 493 | secho "WARNING: Ignoring free space error... I sure hope you know what you are doing!" 494 | fi 495 | fi 496 | 497 | before=$(date +%s) 498 | backuptogo=$totalsize 499 | for (( i = 0 ; i < $usercount ; i++ )) 500 | do 501 | user="${userarray[$i]}" 502 | usersize="${sizearray[$i]}" 503 | usersettings="$backuppath/Users/$user/UserSettings" 504 | # write some details about the user 505 | defaults write $usersettings UserSize -string $usersize 506 | # this reads the local ds via localonly (reads ds on target disk - not the system we are booted from) 507 | networkusertest=$(dscl -f "$dslocal" localonly -read "/Local/Default/Users/$user" AuthenticationAuthority | grep LocalCachedUser) 508 | if [ "$networkusertest" != "" ] 509 | then 510 | defaults write $usersettings NetworkUser -bool true 511 | usertype="Network User" 512 | else 513 | defaults write $usersettings NetworkUser -bool false 514 | usertype="Local User" 515 | fi 516 | secho 517 | secho "Backing up ($(( $i + 1 ))/$usercount): $user - $(( $usersize / 1024 / 1024 ))/$(( $backuptogo / 1024 / 1024 )) MBs - $usertype" 2 518 | secho "-------------------------------------------------------------------" 519 | mkdir -p "$backuppath/Users/$user" 520 | imagesize=$(( $usersize + (( $usersize / 4 )) )) # add 25% of padding to vol size 521 | # create a sparse image on the backup store 522 | secho "Creating image for $user of size $(( $imagesize / 1024 / 1024 )) MBs..." 1 523 | hdiutil create -size ${imagesize} -type SPARSE -fs HFS+J -volname _backup_$user "$backuppath/Users/$user/$user.sparseimage" 2>> "$logto/$log" 524 | error="$?" 525 | if [ "$error" != "0" ] 526 | then 527 | errorHander "Error creating backup image for $user - hdiutil returned error: $error" 528 | fi 529 | # attach our new image 530 | hdiutil attach -owners on "$backuppath/Users/$user/$user.sparseimage" 2>> "$logto/$log" 531 | if [ "$error" != "0" ] 532 | then 533 | errorHander "Error attaching backup image for $user - hdiutil returned error: $error" 534 | fi 535 | # write our rsync exclude file 536 | for rsyncexclude in ${rsyncexcludes[@]} 537 | do 538 | echo "$rsyncexclude" >> /tmp/rsync-excludes.txt 539 | done 540 | # rsync all data 541 | rsync $rsyncopts -aE --log-file="$logto/$log" --exclude-from="/tmp/rsync-excludes.txt" "$userfolder/$user/" "/Volumes/_backup_$user/$user/" 542 | error="$?" 543 | rm /tmp/rsync-excludes.txt 544 | 545 | # rsync error handler - we can ignore a couple of common errors 546 | if [ "$error" != "0" ] 547 | then 548 | case $error in 549 | 23) 550 | secho "rsync error 23 - some files were inaccessible (probably in use)" 551 | ;; 552 | 24) 553 | secho "rsync error 24 - some files disappeared during rsync" 554 | ;; 555 | 12) 556 | errorHander "Problem backing $user, out of disk space" 557 | ;; 558 | *) 559 | errorHander "Problem backing up $user, rsync returned error: $error" 560 | ;; 561 | esac 562 | fi 563 | secho "Ejecting /Volumes/_backup_$user ..." 564 | diskutil eject "/Volumes/_backup_$user" 565 | [ "$?" != "0" ] && errorHander "There was a problem ejecting /Volumes/_backup_$user" 566 | # decrement our backupdata to go... 567 | backuptogo=$(( $backuptogo - $usersize )) 568 | done 569 | after=$(date +%s) 570 | totalsecs=$(( $after - $before )) 571 | # echo "Completed in $(($diff / 60)):$(($diff % 60)) min:secs" 572 | totaltime="$(date -r $totalsecs +%M:%S) secs" 573 | 574 | [ $showlog ] && killall Console 575 | 576 | defaults write $backupsettings BackupDate -string "$(date)" 577 | defaults write $backupsettings TotalTime -string "$totaltime" 578 | defaults write $backupsettings TotalSize -string "$totalsize" 579 | defaults write $backupsettings HasBeenRestored -bool false 580 | defaults write $backupsettings BackupComplete -bool true 581 | 582 | secho 583 | secho "==========================================" 584 | secho " Completed $(( $totalsize / 1024 / 1024 )) MBs in $totaltime" 3 585 | secho "==========================================" 586 | secho "finished: $(date)" 587 | secho 588 | secho "NOTE: this script only backs up User folders in $userfolder" 589 | secho " any files outside of this have NOT been backup up." 590 | secho 591 | } 592 | 593 | 594 | restoreUsers() 595 | { 596 | # check for no backup flag 597 | if [ -f "/tmp/.nobackup-$uniqueid" ] 598 | then 599 | secho "No backup performed for $uniqueid..." 2 600 | rm "/tmp/.nobackup-$uniqueid" 601 | return 0 602 | fi 603 | 604 | while true 605 | do 606 | if [ -d "$backuppath" ] # if there is a backup for this mac restore 607 | then 608 | #if its already been restored, error out 609 | if [ "$(defaults read $backupsettings HasBeenRestored)" == "1" ] 610 | then 611 | answer=$(askQuestion "Backup $uniqueid has already been restored" "Continue with Restore" "Choose another backup..." ) 612 | if [ "$answer" == "2" ] 613 | then 614 | # to choose another... reset backup path and reloop 615 | backuppath="" 616 | continue 617 | fi 618 | fi 619 | backupdate=$(defaults read $backupsettings BackupDate) 620 | totaltime=$(defaults read $backupsettings TotalTime) 621 | totalsize=$(defaults read $backupsettings TotalSize) 622 | if ! $caspermode 623 | then 624 | # if we are in interactive mode.. present options 625 | # read in backup details and make a dialog message 626 | message=$( 627 | echo -ne "Backup Details\n--------------------\n$uniqueid\nTotalsize: $(( $totalsize / 1024 / 1024 )) MBs\nCompleted in: $totaltime" 628 | echo -ne "\n\n" 629 | echo -ne "Users\n" 630 | echo -ne "------\n" 631 | # 632 | # read in all the backups on the store 633 | # 634 | [ -f "$backuppath/Users/.DS_Store" ] && rm "$backuppath/Users/.DS_Store" # just in case someone has been poking around in Users 635 | for backupuserfolder in $(ls "$backuppath/Users/") 636 | do 637 | user=$(basename $backupuserfolder) 638 | usersize=$(defaults read "$backuppath/Users/$backupuserfolder/UserSettings" UserSize) 639 | echo -ne "$user - $(( $usersize / 1024 / 1024 )) MBs\n" 640 | done 641 | echo -ne "\n\n" 642 | ) 643 | answer=$(askQuestion "$message" "Restore" "Choose another backup..." ) 644 | if [ "$answer" == "2" ] 645 | then 646 | # to choose another... reset backup path and reloop 647 | backuppath="" 648 | continue 649 | fi 650 | fi 651 | 652 | # ask to remove backup, do it before we start the restore so it can be unattended 653 | answer=$(askQuestion "Would you like to delete the backup once it has been restore successfully?" "Delete Backup" "Keep" 20) 654 | if [ "$answer" == "1" ] 655 | then 656 | removebackup=true 657 | else 658 | removebackup=false 659 | fi 660 | 661 | # do the restore 662 | cp "$logto/$log" "$backuppath/logs/$log" 663 | rm "$logto/$log" 664 | logto="$backuppath/logs" 665 | 666 | # open the log in console for more feedback 667 | [ $showlog ] && open "$logto/$log" 668 | 669 | secho "$uniqueid - Restore size: $(( $totalsize / 1024 / 1024 )) MBs" 2 670 | secho 671 | before=$(date +%s) 672 | backuptogo=$totalsize 673 | [ -f "$backuppath/Users/.DS_Store" ] && rm "$backuppath/Users/.DS_Store" # just in case someone has been poking around in Users 674 | for userroot in "$backuppath/Users/"* 675 | do 676 | user=$(basename $userroot) 677 | usersettings="$backuppath/Users/$user/UserSettings" 678 | usersize=$(defaults read $usersettings UserSize) 679 | if [ "$(defaults read $usersettings NetworkUser)" == "1" ] 680 | then 681 | usertype="Network" 682 | else 683 | usertype="Local" 684 | fi 685 | secho 686 | secho "Restoring: $user $(( $usersize / 1024 / 1024 ))/$(( $backuptogo / 1024 / 1024 )) MBs - $usertype account" 2 687 | secho "-------------------------------------------------------------------" 688 | 689 | hdiutil attach -owners on "$userroot/$user.sparseimage" 2>> "$logto/$log" 690 | error="$?" 691 | if [ "$error" != "0" ] 692 | then 693 | errorHander "Error attaching backup image for $user - hdiutil returned error: $error" 694 | fi 695 | rsync $rsyncopts -aE --log-file="$logto/$log" "/Volumes/_backup_$user/$user/" "$restoreto/$user/" 696 | error="$?" 697 | # rsync error handler 698 | if [ "$error" != "0" ] 699 | then 700 | case $error in 701 | 23) 702 | secho "rsync error 23 - some files were inaccessible (probably in use)" 703 | ;; 704 | 24) 705 | secho "rsync error 24 - some files disappeared during rsync" 706 | ;; 707 | 12) 708 | errorHander "Problem backing $user, out of disk space" 709 | ;; 710 | *) 711 | errorHander "Problem backing up $user, rsync returned error: $error" 712 | ;; 713 | esac 714 | fi 715 | secho "Ejecting /Volumes/_backup_$user ..." 716 | diskutil eject "/Volumes/_backup_$user" 717 | [ "$?" != "0" ] && errorHander "There was a problem ejecting /Volumes/_backup_$user" 718 | # decrement data 719 | backuptogo=$(( $backuptogo - $usersize )) 720 | done 721 | after=$(date +%s) 722 | totalsecs=$(( $after - $before )) 723 | totaltime="$(date -r $totalsecs +%M:%S) secs" 724 | defaults write $backupsettings HasBeenRestored -bool true 725 | secho 726 | secho "==========================================" 727 | secho " Completed $(( $totalsize / 1024 / 1024 )) MBs in $totaltime" 3 728 | secho "==========================================" 729 | secho "finished: $(date)" 730 | cp "$logto"/*.log "$target/Library/Logs/" # copy logs to target when done 731 | 732 | [ $showlog ] && killall Console 733 | 734 | # remove them when done 735 | if $removebackup 736 | then 737 | # delete the backup 738 | secho "Deleting $backuppath" 2 739 | while [ -d "$backuppath" ] 740 | do 741 | # network shares have some locks / trashes that hold up proceedings, just keep hitting it until it dies 742 | rm -R "$backuppath" 743 | sleep 1 744 | done 745 | else 746 | defaults write $backupsettings HasBeenRestored -bool true 747 | fi 748 | break 749 | else 750 | # no backups found for restore 751 | if $caspermode 752 | then 753 | secho "There are no backups for $uniqueid" 4 754 | break 755 | else 756 | if [ ! "$(ls $backuproot)" ] # check if the backup folder is empty 757 | then 758 | secho "There are no backups on $backuproot" 759 | break 760 | fi 761 | # interactive mode choose another backup and loop back 762 | chooseBackup 763 | # we want to quit? 764 | [ "$?" == "2" ] && break 765 | fi 766 | fi 767 | done 768 | } 769 | 770 | 771 | ################################ 772 | # Begin! 773 | ################################ 774 | 775 | 776 | datestamp=$(date "+%F_%H-%M-%S") 777 | 778 | logto="/tmp" 779 | log="$scriptname-$datestamp.log" 780 | 781 | if $debug 782 | then 783 | # dump debug logs to / 784 | set -xv; exec 1>/BackupRestoreUsers-DEBUG-$datestamp.log 2>&1 785 | fi 786 | 787 | dscl="/usr/bin/dscl" ### test - we should run dscl from current booted os. assumed that netboot system will be > system if upgrading. 788 | dslocal="/var/db/dslocal/nodes/Default" # path to local directory data 789 | 790 | target="$1" # casper passes .. $1 - target, $2 - computername, $3 username --- we only need target path. 791 | [ "$target" == "/" ] && target="" # if we are targetting / - set target to "" so we don't end up with //Users 792 | userfolder="$target$userfolder" # eg. /Volumes/MacHD/Users 793 | restoreto="$target$restoreto" # 794 | dslocal="$target$dslocal" # etc.. 795 | 796 | # if there we are in cdpmode, find the cdp server, and set url 797 | [ $cdpmode ] && findServer 798 | 799 | # just drop afp or smb url into this variable 800 | networkbackuppath="$afpurl$smburl" 801 | 802 | # uniqueid - serial or MAC address of en0 803 | uniqueid=$(ioreg -c "IOPlatformExpertDevice" | awk -F '"' '/IOPlatformSerialNumber/ {print $4}') 804 | [ "$uniqueid" == "" ] && uniqueid=$(ifconfig en0 | awk ' /ether/ {print $2}') # if no serial, fallback to MAC address 805 | 806 | # set the IFS to cr 807 | OLDIFS=$IFS 808 | IFS=$'\n' 809 | 810 | # 811 | # Lets Go! 812 | # 813 | secho 814 | secho "$scriptname $mode $version - $uniqueid" 1 815 | secho "=================================================" 816 | secho "started: $(date)" 817 | secho 818 | 819 | # if we have a network path, mount it 820 | [ "$networkbackuppath" != "" ] && mountShare 821 | 822 | [ ! -d "$backuproot" ] && errorHander "I can't find $backuproot" 823 | 824 | backuppath="$backuproot/$uniqueid" 825 | backupsettings="$backuppath/BackupSettings" 826 | 827 | # 828 | # Core handler .. parse mode line etc 829 | # 830 | 831 | if $caspermode 832 | then 833 | # mode is hard coded 834 | case $mode in 835 | backup ) 836 | backupUsers 837 | ;; 838 | restore ) 839 | restoreUsers 840 | ;; 841 | esac 842 | else 843 | # interactive mode called by wrappers 844 | case $2 in 845 | --backup ) 846 | backupUsers 847 | ;; 848 | --restore ) 849 | restoreUsers 850 | ;; 851 | * ) 852 | usage 853 | ;; 854 | esac 855 | fi 856 | 857 | # unmount network share 858 | [ "$networkbackuppath" != "" ] && unmountShare 859 | 860 | IFS=$OLDIFS 861 | exit -------------------------------------------------------------------------------- /BackupRestoreUsers/BackupUsers.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #################################################################### 3 | # 4 | # a basic wrapper script for backup and restore users 5 | # 6 | # .command so that it can be launched by double clicking 7 | # and it will sudo the script it's calling to ensure that the we 8 | # execute as root! 9 | # 10 | #################################################################### 11 | script="BackupRestoreUsers.sh" 12 | 13 | ### go ### 14 | basedir=`dirname "$0"` 15 | 16 | clear 17 | echo "" 18 | echo "** Running $script **" 19 | echo "" 20 | echo "This script must be excuted with root privleges" 21 | echo "" 22 | echo "" 23 | echo " Please ensure you have:" 24 | echo "" 25 | echo " 1. READ THE DOCs" 26 | echo " 2. Configured $script for your environment" 27 | echo "" 28 | echo "" 29 | echo "To continue please enter your admin password and press " 30 | echo "" 31 | sudo "$basedir/$script" / --backup 32 | exit 33 | -------------------------------------------------------------------------------- /BackupRestoreUsers/RestoreUsers.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #################################################################### 3 | # 4 | # a basic wrapper script for backup and restore users 5 | # 6 | # .command so that it can be launched by double clicking 7 | # and it will sudo the script it's calling to ensure that the we 8 | # execute as root! 9 | # 10 | #################################################################### 11 | script="BackupRestoreUsers.sh" 12 | 13 | ### go ### 14 | basedir=`dirname "$0"` 15 | 16 | clear 17 | echo "" 18 | echo "** Running $script **" 19 | echo "" 20 | echo "This script must be excuted with root privleges" 21 | echo "" 22 | echo "" 23 | echo " Please ensure you have:" 24 | echo "" 25 | echo " 1. READ THE DOCs" 26 | echo " 2. Configured $script for your environment" 27 | echo "" 28 | echo "" 29 | echo "To continue please enter your admin password and press " 30 | echo "" 31 | sudo "$basedir/$script" / --restore 32 | exit 33 | -------------------------------------------------------------------------------- /CasperImagingDeploy/postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # start casperimaging 4 | 5 | casperimaging="/tmp/Casper Imaging.app" 6 | 7 | cleanUpWhenDone() 8 | { 9 | # wait for casperimaging to start, then kill installer.app 10 | while [ "$(pgrep "Casper Imaging")" == "" ] 11 | do 12 | sleep 1 13 | done 14 | sleep 3 15 | killall Installer 16 | 17 | # wait for casperimaging to close then delete tmp app 18 | while [ "$(pgrep "Casper Imaging")" != "" ] 19 | do 20 | sleep 1 21 | done 22 | rm -r "${casperimaging}" 23 | } 24 | 25 | sudo open "${casperimaging}" & 26 | 27 | #cleanUpWhenDone & # spawn this 28 | 29 | exit 0 30 | -------------------------------------------------------------------------------- /CasperImagingDeploy/preinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # start casperimaging 4 | 5 | jssurl="https://jss.youthplus.edu.au:8443" 6 | #invalidcert=false 7 | invalidcert=true 8 | 9 | userloggedin="$(who | grep console | awk '{print $1}')" 10 | 11 | sudo -u ${userloggedin} defaults write com.jamfsoftware.jss allowInvalidCertificate -bool $invalidcert 12 | sudo -u ${userloggedin} defaults write com.jamfsoftware.jss url -string "$jssurl" 13 | 14 | exit 0 15 | -------------------------------------------------------------------------------- /FVHelper/FVHelper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loceee/OSXCasperScripts/ff94404bcbd52139f530be3bd5e0873e38229139/FVHelper/FVHelper.png -------------------------------------------------------------------------------- /FVHelper/fvhelper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # 4 | # Filevault Helper 5 | # 6 | # 7 | # FVHelper leverages Casper's built FV handling (so we can use the GUI and key escrow) 8 | # - adds some GUI 9 | # - allows you to skip a management account(s) 10 | # - call it at login trigger so we don't forget to enable FV 11 | # - execute it via self service and it will logout for you 12 | # - give users a few defers now 13 | # - added --selfservice mode, skips user check and spawns (when spawning all runs you don't get meaninful logs back to jss) 14 | # - change to jamfHelper for dialogs, too many broken scripting plugins on our fleet, causing issues displaying dialogs 15 | 16 | skipusers=( "admin" ) # prevent these users from being prompted (your local management accounts etc.) 17 | #fvpolicy="-id 1234" # use either the policy id or a custom trigger of your FV policy. 18 | fvpolicy="-trigger filevault" 19 | 20 | # users can defer x fv enable prompts 21 | defermode=true 22 | deferthreshold=5 23 | 24 | spawned="${1}" # used internally 25 | username="${3}" 26 | selfservice="${4}" # will spawn and skip username trip if not empty 27 | [ "${username}" == "" ] && username="$(who | grep console | awk '{print $1}')" # if running from self service 28 | 29 | 30 | # localise your prompts 31 | 32 | msgprompthead="This Mac requires FileVault Encryption" 33 | msgpromptenable="Enabling FileVault requires a restart. 34 | 35 | Would you like to enable for ${username} ?" 36 | msgpromptenableforce="Enabling FileVault requires a restart. 37 | 38 | You MUST enable FileVault for ${username} NOW!" 39 | msgenabled="FileVault has been enabled. 40 | 41 | Your Mac will now logout, prompt you for your password and then restart to initiate the background encryption process." 42 | 43 | dialogicon="/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/FileVaultIcon.icns" 44 | jamfhelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper" 45 | 46 | prefs="/Library/Preferences/com.github.loceee.fvhelper" 47 | 48 | 49 | checkProcess() 50 | { 51 | if [ "$(ps aux | grep "${1}" | grep -v grep)" != "" ] 52 | then 53 | return 0 54 | else 55 | return 1 56 | fi 57 | } 58 | 59 | checkConsoleStatus() 60 | { 61 | userloggedin="$(who | grep console | awk '{print $1}')" 62 | consoleuser="$(ls -l /dev/console | awk '{print $3}')" 63 | screensaver="$(ps aux | grep ScreenSaverEngine | grep -v grep)" 64 | 65 | if [ "${screensaver}" != "" ] 66 | then 67 | # screensaver is running 68 | echo "screensaver" 69 | return 70 | fi 71 | 72 | if [ "${userloggedin}" == "" ] 73 | then 74 | # no users logged in (at loginwindow) 75 | echo "nologin" 76 | return 77 | fi 78 | 79 | if [ "${userloggedin}" != "${consoleuser}" ] 80 | then 81 | # a user is loggedin, but we are at loginwindow or we have multiple users logged in with switching (too hard for now) 82 | echo "loginwindow" 83 | return 84 | fi 85 | 86 | # if we passed all checks, user is logged in and we are safe to prompt or display bubbles 87 | echo "userloggedin" 88 | } 89 | 90 | 91 | logoutUser() 92 | { 93 | waitforlogout=30 94 | # sending appleevent seems most robust and fastest way, can still be blocked by stuck app (I'm looking at you MS Office and Lync) 95 | echo "sending logout ..." 96 | osascript -e "ignoring application responses" -e "tell application \"loginwindow\" to $(printf \\xc2\\xab)event aevtrlgo$(printf \\xc2\\xbb)" -e "end ignoring" 97 | 98 | while [ "$(checkConsoleStatus)" != "nologin" ] 99 | do 100 | for (( c=1; c<=${waitforlogout}; c++ )) 101 | do 102 | sleep 1 103 | # check if we've logged out yet, break if so, otherwise check every second 104 | [ "$(checkConsoleStatus)" == "nologin" ] && break 105 | done 106 | if [ "$(checkConsoleStatus)" != "nologin" ] 107 | then 108 | osascript -e "ignoring application responses" -e "tell application \"loginwindow\" to $(printf \\xc2\\xab)event aevtrlgo$(printf \\xc2\\xbb)" -e "end ignoring" 109 | fi 110 | done 111 | # we should have really logged out by now! 112 | } 113 | 114 | spawnScript() 115 | { 116 | # we use this so we can execute from self service.app and call a logout with out breaking policy execution. 117 | # the script copies, then spawns itself 118 | if [ "$spawned" != "--spawned" ] 119 | then 120 | tmpscript="$(mktemp /tmp/fvhelper.XXXXXXXXXXXXXXX)" 121 | cp "${0}" "${tmpscript}" 122 | # spawn the script in the background 123 | echo "spawned script $tmpscript" 124 | chmod 700 "${tmpscript}" 125 | "${tmpscript}" --spawned '' ${username} & 126 | exit 0 127 | fi 128 | } 129 | 130 | cleanUp() 131 | { 132 | [ "$spawned" == "--spawned" ] && rm "${0}" #if we are spawned, eat ourself. 133 | } 134 | 135 | # 136 | # Start the bidness 137 | # 138 | 139 | exitcode=0 140 | 141 | # if self service, spawn and skip username check (perhaps we want to enable for this user) 142 | if [ -n "${selfservice}" ] 143 | then 144 | spawnScript 145 | else 146 | for skipuser in ${skipusers[@]} 147 | do 148 | if [ "${username}" == "${skipuser}" ] 149 | then 150 | echo "${username} shouldn't be filevaulted by fvhelper, bye." 151 | cleanUp 152 | exit 0 153 | fi 154 | done 155 | fi 156 | 157 | # if starting on login trigger, wait for the finder to start 158 | 159 | until checkProcess "Finder.app" 160 | do 161 | sleep 3 162 | done 163 | 164 | 165 | if [ "$(fdesetup status | grep "FileVault is Off.")" == "FileVault is Off." ] # FV is off, lets prompt 166 | then 167 | if [ "$(checkConsoleStatus)" == "userloggedin" ] # double check we have logged in user 168 | then 169 | if $defermode 170 | then 171 | # read defercounter if exists, write if not 172 | defercount=$(defaults read "${prefs}" DeferCount 2> /dev/null) 173 | if [ "$?" != "0" ] 174 | then 175 | defaults write "${prefs}" DeferCount -int 0 176 | defercount=0 177 | fi 178 | 179 | deferremain=$(( deferthreshold - defercount )) 180 | if [ ${deferremain} -eq 0 ] || [ ${deferremain} -lt 0 ] 181 | then 182 | filevaultprompt=$("${jamfhelper}" -windowType utility -heading "${msgprompthead}" -alignHeading center -description "${msgpromptenableforce}" -icon "${dialogicon}" -button1 "Enable..." -defaultButton 1) 183 | else 184 | filevaultprompt=$("${jamfhelper}" -windowType utility -heading "${msgprompthead}" -alignHeading center -description "${msgpromptenable} 185 | (You may defer ${deferremain} more times)" -icon "${dialogicon}" -button1 "Enable..." -button2 "Later" -defaultButton 1 -cancelButton 2) 186 | fi 187 | else 188 | # no defer mode, just prompt 189 | filevaultprompt=$("${jamfhelper}" -windowType utility -heading "${msgprompthead}" -alignHeading center -description "${msgpromptenable}" -icon "${dialogicon}" -button1 "Enable..." -button2 "Later" -defaultButton 1 -cancelButton 2) 190 | fi 191 | if [ "$filevaultprompt" == "0" ] 192 | then 193 | echo "jamf please call the fv policy" 194 | jamf policy ${fvpolicy} 195 | "${jamfhelper}" -windowType utility -description "${msgenabled}" -icon "${dialogicon}" -button1 "Ok" -defaultButton 1 196 | rm "${prefs}.plist" 197 | logoutUser 198 | elif [ "$filevaultprompt" == "2" ] 199 | then 200 | if $defermode 201 | then 202 | (( defercount ++ )) 203 | defaults write "${prefs}" DeferCount -int ${defercount} 204 | echo "user skipped FV - defercounter: ${defercount}" 205 | fi 206 | else 207 | echo "user skipped FV" 208 | fi 209 | else 210 | echo "there is no console user active, consolestatus: $(checkConsoleStatus)..." 211 | fi 212 | else 213 | # if we've run this policy FV ISN'T off, the JSS isn't up to date so this mac hasn't falled out of the smart group, recon. this will run post-reboot. 214 | echo "FileVault is ON or encrypting, will recon to update JSS." 215 | jamf recon 216 | fi 217 | 218 | cleanUp 219 | exit $exitcode 220 | -------------------------------------------------------------------------------- /FVHelper/readme.md: -------------------------------------------------------------------------------- 1 | FV Helper 2 | ========= 3 | 4 | ####A helper for Casper 9.x FileVault configuration 5 | 6 | Casper handles FileVault very well, with an admin GUI and key escrow. FVHelper aims to assist you with automating the initiation of the encryption process and minimise the possibility of the incorrect account becoming the primary FV user. 7 | 8 | By leveraging the FileVault config built into Casper, we can utilise jamf's key escrow without re-inventing the wheel. We also can tell FVhelper to skip certain accounts (perhaps your local management or admin accounts) to prevent your L2 or desktop support accidentally activating FV for these accounts instead of the enduser. 9 | 10 | Launching FVHelper on the login trigger means that the first user to logon to a FV "eligible" unencrypted Mac will be prompted to enable Filevault. From the enduser or desktop support perspective, FV is enabled in the background, they are prompted that in order to complete the process they must be logged out and enter their password again. 11 | 12 | ##### New: Defer Mode! 13 | 14 | **TODO:** handle additional FV unlock accounts post FV enable. 15 | 16 | Vague instructions 17 | ------------------ 18 | 19 | 1. Setup your FV config (set it to run at **Current or Next User**) equiv of. *fdesetup -defer* 20 | 3. Setup a smart group to catch eligible computers 21 | * FileVault 2 Eligibility **is Eligible** 22 | * **AND** **(** FileVault 2 Partition Encryp State **is not Encrypted** 23 | * **AND** File Vault 2 Partition 2 Encrypt State **is not Encrypting )** 24 | * **AND** ... your other criteria (eg. computer model like **book**). 25 | 5. Create a policy to run the FV config, scope to your smart group - **No trigger, ongoing** (or a custom trigger you might want to initiate manually, fvhelper.sh can handle both) 26 | * Note down the policy ID of your FV policy (copy from the URL bar of your browser) unless using a custom trigger. 27 | 5. Edit the **fvhelper.sh** and add accounts to skip, and set the fvpolicy varliable to either the ="-id xxx" or "-trigger xxx" that calls your FV policy. 28 | 7. Create a policy to run script **fvhelper.sh** - **login trigger, self service (optional)** 29 | 8. Scope the *FVHelper* policy to your FV smart group 30 | * This policy calls the your FV Policy, so ensure this is scoped to the Macs you wish to FV. 31 | 32 | 33 | Thanks for Quam Sodji for a much better walkthrough here... [http://jumpt.wordpress.com/2014/10/13/leveraging-filevault-on-casper/](http://jumpt.wordpress.com/2014/10/13/leveraging-filevault-on-casper/) 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /QuickAddHelper/Enroll.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mydir=$(dirname $0) 3 | tmpdir="/tmp/QuickAdd" 4 | startquickadd="quickadd.command" 5 | 6 | mkdir "${tmpdir}" 7 | echo "${mydir}" > "${tmpdir}/vol.tmp" 8 | ditto -v "${mydir}/" "${tmpdir}" 9 | open "${tmpdir}/${startquickadd}" 10 | 11 | exit 12 | -------------------------------------------------------------------------------- /QuickAddHelper/quickadd.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | tmpdir="/tmp/QuickAdd" 3 | vol=$(cat ${tmpdir}/vol.tmp) 4 | echo "ejecting ${vol}" 5 | diskutil eject "${vol}" 6 | echo -en "\007" # beep 7 | echo 8 | echo "Enter local admin password to enroll this Mac" 9 | echo 10 | sudo installer -verbose -pkg "${tmpdir}/QuickAdd.pkg" -target / 11 | rm -R ${tmpdir} 12 | 13 | if jamf checkJSSConnection 14 | then 15 | say "Done" 16 | killall Terminal 17 | else 18 | say "Error" 19 | fi 20 | exit 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OSXCasperScripts 2 | ================ 3 | 4 | These scripts are free to use! 5 | 6 | Also check out my other project - http://patchoo.github.io 7 | 8 | 9 | Lach 10 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysAddPrinterAdmin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # pass it a domain group, or default to everyone (all user accounts on computers) 3 | # everyone is good for staff / student macs 4 | # 5 | group="${4}" 6 | 7 | [ -z "${group}" ] && countycode="everyone" 8 | 9 | dseditgroup -o edit -n /Local/Default -a ${group} -t group lpadmin 10 | 11 | exit 0 12 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysComputerName.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # sets the computer/host names to prefix-$serial, triming to last places of serial 3 | 4 | prefix="${4}" 5 | length=15 6 | 7 | serial=$(ioreg -c "IOPlatformExpertDevice" | awk -F '"' '/IOPlatformSerialNumber/ {print $4}') 8 | 9 | lenprefix=${#prefix} 10 | trimserial=$(( length - lenprefix + 1)) 11 | serialtrim=$(echo ${serial} | tail -c ${trimserial}) 12 | 13 | computername=$(echo "${prefix}${serialtrim}") 14 | 15 | echo "setting computername to ${computername} ..." 16 | scutil --set ComputerName "${computername}" 17 | scutil --set HostName "${computername}" 18 | scutil --set LocalHostName "${computername}" 19 | 20 | exit 21 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysDefaultDesktopImg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set default desktop (mav / yoyo) 3 | desktopimg="${4}" 4 | 5 | echo "setting default desktop to ${desktopimg}" 6 | rm /System/Library/CoreServices/DefaultDesktop.jpg 7 | ln -s "${desktopimg}" /System/Library/CoreServices/DefaultDesktop.jpg 8 | 9 | exit 0 10 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysDisableDSStores.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # NO .ds-store files on Network Shares 4 | 5 | defaults write /Library/Preferences/com.apple.desktopservices DSDontWriteNetworkStores -bool true 6 | 7 | exit 8 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysDisableSetupAssist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # cfgCasper 4 | # 5 | # i disable the setup assistant and registration wizards 6 | # 7 | 8 | target=$1 9 | computername=$2 10 | username=$3 11 | 12 | echo "Disabling setup and reg assistant..." 13 | touch $target/Library/Receipts/.SetupRegComplete 14 | touch $target/private/var/db/.AppleSetupDone 15 | 16 | exit 0 17 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysDisableTimeMachineoffers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # disable time machine offers 4 | 5 | echo "Disabling Time Machine new disk offers..." 6 | defaults write /Library/Preferences/com.apple.TimeMachine DoNotOfferNewDisksForBackup -bool YES 7 | 8 | exit 0 9 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysDockFixupRemove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # kill entries in dockfixup, prevents osx yoyo from "fixing" our dock (eg. adding maps / ibooks) 3 | 4 | /usr/libexec/PlistBuddy -c "delete:add-app" /System/Library/CoreServices/Dock.app/Contents/Resources/com.apple.dockfixup.plist 5 | /usr/libexec/PlistBuddy -c "delete:add-doc" /System/Library/CoreServices/Dock.app/Contents/Resources/com.apple.dockfixup.plist 6 | 7 | exit 8 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysEnableARD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # set ARD and lock to user 4 | 5 | adminuser="${4}" 6 | 7 | [ -z "${adminuser}" ] && adminuser="admin" 8 | 9 | echo "Kickstarting ARD and locking to ${adminuser}..." 10 | /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -allowAccessFor -specifiedUsers 11 | /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -users ${adminuser} -access -on -privs -all -agent -restart 12 | exit 0 -------------------------------------------------------------------------------- /cfgScripts/cfgsysEnableSSH.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # enable ssh admin lock to adminuer 4 | 5 | adminuser="${4}" 6 | 7 | [ -z "${adminuser}" ] && adminuser="admin" 8 | 9 | 10 | # turn on ssh 11 | systemsetup -setremotelogin on 12 | 13 | # create the sacl group 14 | dseditgroup -o create -q com.apple.access_ssh 15 | 16 | # add adminuser to the sacl group 17 | dseditgroup -o edit -a ${adminuser} -t user com.apple.access_ssh 18 | 19 | exit 0 -------------------------------------------------------------------------------- /cfgScripts/cfgsysEnableVNC.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # turn on vnc for Mac 4 | 5 | vncpassword="${4}" 6 | 7 | if [ -n "${vncpassword}" ] 8 | then 9 | echo "Kickstarting ARD enabling VNC..." 10 | /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -clientopts -setvnclegacy -vnclegacy yes -setvncpw -vncpw ${vncpassword} -restart -agent 11 | fi 12 | exit 0 -------------------------------------------------------------------------------- /cfgScripts/cfgsysFinderDefaults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # set finder defaults me likey 4 | 5 | template="/System/Library/User Template/English.lproj" 6 | 7 | echo "set Finder default .." 8 | defaults write "${template}/Library/Preferences/com.apple.finder" NewWindowTarget -string PfCm 9 | 10 | exit 0 11 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysHideMacintoshHD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # hide Macintosh HD from finder 4 | 5 | chflags hidden "/Volumes/Macintosh HD" 6 | 7 | exit 8 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysLocaleRegion.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # locale / region osx 3 | applelocale="${4}" 4 | countycode="${5}" 5 | 6 | [ -z "${applelocale}" ] && applelocale="en_AU" 7 | [ -z "${countycode}" ] && countycode="AU" 8 | 9 | defaults write /Library/Preferences/.GlobalPreferences AppleLocale ${applelocale} 10 | defaults write /Library/Preferences/.GlobalPreferences Country ${countycode} 11 | 12 | exit 0 13 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysMouseCfg2Button.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | template="/System/Library/User Template/English.lproj" 4 | 5 | # Set Apple Mouse button 1 to Primary click and button 2 to Secondary click. 6 | defaults write "${template}/Library/Preferences/com.apple.driver.AppleHIDMouse" Button1 -integer 1 7 | defaults write "${template}/Library/Preferences/com.apple.driver.AppleHIDMouse" Button2 -integer 2 8 | 9 | # Set Apple Magic Mouse button 1 to Primary click and button 2 to Secondary click. 10 | defaults write "${template}/Library/Preferences/com.apple.driver.AppleBluetoothMultitouch.mouse" MouseButtonMode -string TwoButton 11 | 12 | exit 13 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysSWUpdateOff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | echo "turning off auto software updates" 4 | softwareupdate --schedule off 5 | 6 | exit 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysSetTimeManual.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # set timezone manually 3 | tzone="${4}" 4 | tserv="${5}" 5 | 6 | [ -z "${tzone}" ] && tzone="Australia/Brisbane" 7 | [ -z "${tserv}" ] && tserv="time.asia.apple.com" 8 | 9 | defaults write /Library/Preferences/com.apple.timezone.auto Active -bool False 10 | 11 | systemsetup -setusingnetworktime on 12 | systemsetup -settimezone ${tzone} -setnetworktimeserver ${tserv} 13 | 14 | ntpdate -bvs ${tserv} 15 | 16 | exit 0 17 | -------------------------------------------------------------------------------- /cfgScripts/cfgsysUnBindAD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # unBinderAD.sh 4 | # unbind a mac from AD. 5 | 6 | aduser="${4}" 7 | adpass="${5}" 8 | 9 | tries=3 10 | 11 | if [ -z "$(dsconfigad -show)" ] 12 | then 13 | echo "this mac doesn't seem to be bound to ad" 14 | exit 0 15 | fi 16 | 17 | 18 | 19 | for (( i = 0; i < ${tries}; i++ )) 20 | do 21 | echo "unbinding from AD - try ${i}/${tries}" 22 | dsconfigad -remove -force -u "${aduser}" -p "${adpass}" 23 | sleep 10 24 | if [ -z "$(dsconfigad -show)" ] 25 | then 26 | echo "unbind successful!" 27 | exit 0 28 | fi 29 | done 30 | 31 | echo "unbind failed :(" 32 | exit 1 33 | -------------------------------------------------------------------------------- /cfgScripts/cfguserFinderNSNavDefaults.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # settng new Finder to open PFCm (computer, will show mounted shares) 4 | # setting NSNav to open 'target' so save dialogs land at target (~/Documents/Servers) 5 | 6 | user="${3}" 7 | target="${4}" 8 | 9 | echo "set Finder NewWindowTarget to PfDo .." 10 | sudo -u ${user} defaults write com.apple.finder NewWindowTarget -string PfDo 11 | 12 | # ms office doesnt' seem to respect this 13 | echo "set NSNavpanel to ${target} and expanded .." 14 | sudo -u ${user} defaults write NSGlobalDomain NSNavLastRootDirectory -string "${target}" 15 | sudo -u ${user} defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /cfgScripts/cfguserMountHome.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # home network share mapping script 4 | # run at login, scoped to LDAP groups in casper 5 | 6 | # we may be running this via self service $3 may not be populated 7 | userloggedin="$(who | grep console | awk '{print $1}')" 8 | 9 | adcheck=$(dscl . read /Users/${userloggedin} AuthenticationAuthority | grep LocalCachedUser) 10 | [ -z "${adcheck}" ] && exit 0 11 | 12 | homepath=$(dscl . read /Users/${userloggedin} SMBHome | awk '{print $2}' | tr '\\' '/') 13 | [ -z "${homepath}" ] && exit 0 14 | 15 | homepath="smb:${homepath}" # append smb:// 16 | 17 | mountShare() 18 | { 19 | share="${1}" 20 | urlshare="${share// /%20}" # swap out ' ' for %20 21 | echo "mounting ${share} ..." 22 | # we are assuming all is kerberized, but Finder can take care of credentials that aren't 23 | #osascript -e "tell app \"Finder\"" -e "activate" -e "open location \"${urlshare}\"" -e "end tell" 24 | osascript -e "try" -e "mount volume \"${urlshare}\"" -e "on error" -e "end try" 25 | } 26 | 27 | # wait for the Finder (we are running a login trigger) 28 | 29 | until pgrep Finder > /dev/null 30 | do 31 | sleep 2 32 | done 33 | 34 | mountShare "${homepath}" 35 | 36 | exit 0 37 | -------------------------------------------------------------------------------- /cfgScripts/cfguserMountShares.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # additional network share mapping script 4 | # run at login, scoped to LDAP groups in casper 5 | 6 | IFS=$'\n' 7 | 8 | # we may be running this via self service $3 may not be populated 9 | userloggedin="$(who | grep console | awk '{print $1}')" 10 | 11 | adcheck=$(dscl . read /Users/${userloggedin} AuthenticationAuthority | grep LocalCachedUser) 12 | [ -z "${adcheck}" ] && exit 0 13 | 14 | sharearray=( "${4}" "${5}" "${6}" "${7}" "${8}" "${9}" "${10}" ) 15 | 16 | mountShare() 17 | { 18 | share="${1}" 19 | urlshare="${share// /%20}" # swap out ' ' for %20 20 | echo "mounting ${share} ..." 21 | # we are assuming all is kerberized, but Finder can take care of credentials that aren't 22 | #osascript -e "tell app \"Finder\"" -e "activate" -e "open location \"${urlshare}\"" -e "end tell" 23 | osascript -e "try" -e "mount volume \"${urlshare}\"" -e "on error" -e "end try" 24 | } 25 | 26 | # wait for the Finder (we are running a login trigger) 27 | 28 | until pgrep Finder > /dev/null 29 | do 30 | sleep 2 31 | done 32 | 33 | 34 | for share in ${sharearray[@]} 35 | do 36 | [ ! -z "${share}" ] && mountShare "${share}" 37 | done 38 | 39 | exit 0 40 | -------------------------------------------------------------------------------- /cfgScripts/cfguserShareAlias.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # cfguserShareAlias.sh 3 | # this script will create aliases for all mounted shares (grep username) in target 4 | # default ~/Documents/Servers 5 | # 6 | 7 | loggedinuser="${3}" 8 | target="${4}" 9 | 10 | # if you'd like to add your target to dock, point me a dockutil 11 | dockutil="/Library/Management/bin/dockutil" 12 | 13 | IFS=$'\n' 14 | 15 | [ -z "${target}" ] && target="~/Documents/Servers" 16 | 17 | abshome=$(dscl . read /Users/${loggedinuser} NFSHomeDirectory | awk '{print $2}') 18 | 19 | target=$(echo ${target} | sed "s|~|${abshome}|g") # switch to abs path, applescript and ~ = blerg 20 | 21 | [ ! -d "${target}" ] && sudo -u ${loggedinuser} mkdir -p "${target}" 22 | 23 | mountedsharearray=( $(mount | grep ${loggedinuser}@ | cut -d' ' -f3- | rev | cut -d'(' -f2- | rev | sed 's/ *$//') ) 24 | 25 | # no shares mounted, exit without deleting aliases 26 | [ ${#mountedsharearray[@]} == 0 ] && exit 27 | 28 | # remove existing symlinks - don't delete an icon file if it's there 29 | find "${target}/" -type f -not \( -name "Icon*" -xattrname com.apple.ResourceFork \) -delete 30 | 31 | sleep 2 32 | 33 | # ensure the finder has started 34 | until pgrep Finder > /dev/null 35 | do 36 | sleep 2 37 | done 38 | 39 | 40 | for volname in ${mountedsharearray[@]} 41 | do 42 | echo "creating alias for ${volname} .." 43 | sudo -u ${loggedinuser} osascript -e "tell application \"Finder\" to make alias file to POSIX file \"${volname}\" at POSIX file \"${target}\"" > /dev/null 44 | done 45 | 46 | # if we have dockutil, add it to the dock 47 | if [ -f "${dockutil}" ] 48 | then 49 | targettile="$(basename ${target})" 50 | if [ "$(${dockutil} --find "${targettile}" "${abshome}" | grep "was found")" == "" ] 51 | then 52 | echo "Adding ${targettile} to Dock ..." 53 | ${dockutil} --add "${target}" --display folder --view grid "${abshome}" 54 | fi 55 | fi 56 | exit 57 | -------------------------------------------------------------------------------- /dockBuilder/dockBuilder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # dockBuilder.sh - build a new Dock with dockutil 3 | # https://github.com/loceee/OSXCasperScripts 4 | # 5 | # dockutil is awesome - https://github.com/kcrawford/dockutil 6 | # - https://patternbuffer.wordpress.com 7 | 8 | # dockBuilder is a helper to progmatically build docks 9 | # use as part of your build process, or nuke all users docks if you are a meanie. 10 | # 11 | # 12 | # not enough param slots? chain scripts together --set xx xx xx xx --end 13 | 14 | IFS=$'\n' 15 | 16 | dockutil="/Library/Management/bin/dockutil" 17 | template="/System/Library/User Template/English.lproj" 18 | 19 | paramarray=( 20 | "${4}" 21 | "${5}" 22 | "${6}" 23 | "${7}" 24 | "${8}" 25 | "${9}" 26 | "${10}" 27 | "${11}" 28 | ) 29 | 30 | # dockutil freaks out without an existing pref file, copy in the default 31 | [ ! -f "${template}/Library/Preferences/com.apple.dock.plist" ] && \ 32 | cp "/System/Library/CoreServices/Dock.app/Contents/Resources/en.lproj/default.plist" \ 33 | "${template}/Library/Preferences/com.apple.dock.plist" 34 | 35 | for param in ${paramarray[@]} 36 | do 37 | if [ -n "${param}" ] 38 | then 39 | case "${param}" in 40 | 41 | "--reset" ) 42 | echo "dockBuilder! resetting user template" 43 | "${dockutil}" --remove all --no-restart "${template}" 44 | ;; 45 | 46 | "--reset-allhomes" ) 47 | touch "/tmp/.dockbuilder-allhomes" 48 | echo "dockBuilder! resetting user template" 49 | "${dockutil}" --remove all --no-restart "${template}" 50 | echo "resetting all users docks" 51 | "${dockutil}" --remove all --no-restart --allhomes 52 | ;; 53 | 54 | "--end" ) 55 | # if we are nuking all docks, restart if users logged in. 56 | if [ -f "/tmp/.dockbuilder-allhomes" ] 57 | then 58 | [ -n "$(pgrep Dock)" ] && killall Dock 59 | rm "/tmp/.dockbuilder-allhomes" 60 | fi 61 | ;; 62 | 63 | * ) 64 | # everything else must be items to go in the dock 65 | echo "adding ${param} ..." 66 | "${dockutil}" --add "${param}" --no-restart "${template}" 67 | [ -f "/tmp/.dockbuilder-allhomes" ] && "${dockutil}" --add "${param}" --no-restart --allhomes 68 | ;; 69 | 70 | esac 71 | fi 72 | done 73 | 74 | exit 75 | -------------------------------------------------------------------------------- /dockBuilder/docs/ss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loceee/OSXCasperScripts/ff94404bcbd52139f530be3bd5e0873e38229139/dockBuilder/docs/ss1.png -------------------------------------------------------------------------------- /dockBuilder/docs/ss2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loceee/OSXCasperScripts/ff94404bcbd52139f530be3bd5e0873e38229139/dockBuilder/docs/ss2.png -------------------------------------------------------------------------------- /dockBuilder/docs/ss3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loceee/OSXCasperScripts/ff94404bcbd52139f530be3bd5e0873e38229139/dockBuilder/docs/ss3.png -------------------------------------------------------------------------------- /dockBuilder/readme.md: -------------------------------------------------------------------------------- 1 | dockBuilder 2 | =========== 3 | 4 | ### Progmatically build a Dock with dockutil & Casper ### 5 | 6 | **TODO:** handle ~ for the user template if possible ? 7 | 8 | 9 | [dockutil](https://github.com/kcrawford/dockutil) rocks, but it handles one item at a time. I see people on jamfnation rolling their docks in firstboot scripts, but I wanted something that I could leverage in JSS policies, and then scope accordingly. 10 | 11 | Using dockBuilder in a policy based build / provisioning "imaging" workflow means you can leverage all JSS data to roll a default dock. 12 | 13 | 14 | eg. dockBuilder.sh --reset-allhomes "/Applications/Safari.app" "/Applications/Launchpad.app" "/Applications/Self Service.app". 15 | 16 | Would set all existing users and the user template to a very basic Dock. 17 | 18 | 19 | Instructions 20 | ------------ 21 | 22 | 1. Install [dockutil](https://github.com/kcrawford/dockutil) on your client macs 23 | 2. Edit the dockutil variable to reflect it's location on client mac. 24 | 3. Create a policy as part of your build process. 25 | 4. Add the script 26 | 5. Fill in the parameters *(see examples below)* 27 | 6. 28 | 29 | It accepts the following switches 30 | 31 | ``` 32 | --reset 33 | resets the user template to blank (dockutil --remove all --no-restart *usertemplate*) 34 | 35 | --reset-allhomes 36 | resets the user template to blank (dockutil --remove all --allhomes --no-restart) 37 | 38 | --end 39 | when reached, and allhomes is specified it restarts the dock 40 | ``` 41 | 42 | Without any switches items are appended in order, so you can actually chain together polices to build Docks based on JSS information (eg. group membership, location info, network segments). 43 | 44 | #### Example #### 45 | 46 | 47 | ![ss1](docs/ss1.png) 48 | 49 | The first policy is triggered on custom trigger dock (as part of our build process), and scope to all managed clients. 50 | 51 | ![ss2](docs/ss2.png) 52 | 53 | It resets the template and all homes (so we can call the dock trigger for troubleshooting if needed), and then creates a very basic Dock. 54 | 55 | ![ss2](docs/ss3.png) 56 | 57 | The second policy is scoped by the Department info the JSS (we use this to define our computer / software builds with [Patchoo! Deploy](https://github.com/patchoo/patchoo/blob/master/docs/patchoo_deploy_overview.md)). It adds required Adobe apps to and **--end** when done. 58 | 59 | 60 | This gives more flexible framework to create and modify Docks in your build process! 61 | -------------------------------------------------------------------------------- /extattributes/ea_sepdef_date.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # get date of SEP defs 4 | # http://github.com/loceee 5 | # 6 | 7 | sepsupportpath="/Library/Application Support/Symantec/Antivirus" 8 | 9 | for defdir in "${sepsupportpath}"/* 10 | do 11 | # if we've found the folder with the whatnew.txt - start scraping date 12 | if [ -d "${defdir}" ] && [ -f "${defdir}/whatsnew.txt" ] 13 | then 14 | defdate=$(date -j -f "%b %d, %Y" "$(grep -e "Symantec Security" "${defdir}/whatsnew.txt" | awk '{print $5, $6, $7}')" "+%Y-%m-%d") 15 | fi 16 | done 17 | 18 | # if defdate isn't blank we've got a date 19 | if [ ${defdate} ] 20 | then 21 | result=${defdate} 22 | else 23 | result="Unknown" 24 | fi 25 | 26 | echo "${result}" 27 | exit 28 | -------------------------------------------------------------------------------- /extattributes/ea_sepdef_days.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # get date of SEP defs 4 | # http://github.com/loceee 5 | # 6 | 7 | sepsupportpath="/Library/Application Support/Symantec/Antivirus" 8 | 9 | for defdir in "${sepsupportpath}"/* 10 | do 11 | # if we've found the folder with the whatnew.txt - start scraping date 12 | if [ -d "${defdir}" ] && [ -f "${defdir}/whatsnew.txt" ] 13 | then 14 | defdatesecs=$(date -j -f "%b %d, %Y" "$(grep -e "Symantec Security" "${defdir}/whatsnew.txt" | awk '{print $5, $6, $7}')" "+%s") 15 | fi 16 | done 17 | 18 | # if defdate isn't blank we've got a date 19 | if [ ${defdatesecs} ] 20 | then 21 | currentdatesecs=$(date "+%s") 22 | # subtract from current date and convert back to days 23 | result=$(((currentdatesecs - defdatesecs)/60/60/24)) 24 | else 25 | # return a bogus days if missing 26 | result=999999 27 | fi 28 | 29 | echo "${result}" 30 | exit 31 | -------------------------------------------------------------------------------- /extattributes/ea_timemachine_days.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # days since last Time Machine backup, 0 if not enabled 4 | # scope < smart group to catch devices that are not backing up promptly 5 | # 6 | # - known issue with multiple destinations - 7 | # - thanks here - https://jamfnation.jamfsoftware.com/discussion.html?id=8814 8 | 9 | OS=$(sw_vers | awk '/ProductVersion/{print substr($2,1,5)}' | tr -d ".") 10 | 11 | # check the OS 12 | if [ "$OS" -ge "109" ] 13 | then 14 | lastBackupTime=$(defaults read /Library/Preferences/com.apple.TimeMachine Destinations 2> /dev/null | sed -n '/SnapshotDates/,$p' | grep -e '[0-9]' | awk -F '"' '{print $2}' | sort | tail -n1 | cut -d" " -f1,2) 15 | #lastBackupTime=$(defaults read /Library/Preferences/com.apple.TimeMachine Destinations 2> /dev/null | sed -n '/SnapshotDates/,$p' | grep -A 1 -v "DestinationUUIDs" | grep -v "DestinationID" | grep -v "RootVolumeUUID" | grep -e '[0-9]' | awk -F '"' '{print $2}' | sort | tail -n1 | cut -d" " -f1,2) 16 | else 17 | [ -f /private/var/db/.TimeMachine.Results.plist ] && lastBackupTime=$(defaults read /private/var/db/.TimeMachine.Results "BACKUP_COMPLETED_DATE" 2> /dev/null ) 18 | fi 19 | 20 | if [ "${lastBackupTime}" != "" ] 21 | then 22 | lastBackupSec=$(date -jf "%Y-%m-%d %H:%M:%S" "${lastBackupTime}" +"%s") 23 | curDate=$(date "+%s") # in seconds 24 | lastBackupAge=$(((curDate - lastBackupSec)/60/60/24)) # seconds to days 25 | else 26 | lastBackupAge="0" 27 | fi 28 | 29 | # return days since last backup to JSS 30 | echo "${lastBackupAge}" 31 | 32 | -------------------------------------------------------------------------------- /infoAboutMyMac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # what's my ip and stuff 4 | # 5 | # run me from a self service policy (handy if windows guys need to VNC on for remote support) 6 | 7 | displayDialog() 8 | { 9 | osascript -e "tell app \"System Events\"" -e "activate" -e "display dialog \"$message\" with title \"Information about your Mac\" buttons {\"OK\"}" -e "end tell" 10 | } 11 | 12 | makeMessage() 13 | { 14 | message="$message\n$1" 15 | } 16 | 17 | myip=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1' | head -n1) 18 | compname=$(scutil --get ComputerName) 19 | username=$(who | grep console | awk '{print $1}') 20 | 21 | makeMessage "User: $username" 22 | makeMessage "IP address: $myip" 23 | makeMessage "Computer Name: $compname" 24 | 25 | displayDialog "$message" & 26 | 27 | exit 28 | -------------------------------------------------------------------------------- /jamfCredEncypter.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Use 'openssl' to create an encrypted string for script parameters 3 | # obscure creds from jamf console when passing account credentials from the JSS to a client 4 | # 5 | # based on jamfIT's script - https://github.com/jamfit/Encrypted-Script-Parameters 6 | # but easier and more reusable 7 | # lach 8 | clear 9 | 10 | read -p "username: " username 11 | read -s -p "password: " password 12 | echo 13 | read -p "salt (or blank to gen): " SALT 14 | read -p "key (or blank to gen): " KEY 15 | 16 | # Usage ~$ GenerateEncryptedString "String" 17 | [ -z ${SALT} ] && SALT=$(openssl rand -hex 8) 18 | [ -z ${KEY} ] && KEY=$(openssl rand -hex 12) 19 | username_enc=$(echo "${username}" | openssl enc -aes256 -a -A -S "${SALT}" -k "${KEY}") 20 | password_enc=$(echo "${password}" | openssl enc -aes256 -a -A -S "${SALT}" -k "${KEY}") 21 | 22 | clear 23 | echo ' 24 | --- pass these encrypted creds to your script from the jamf policy --- 25 | 26 | username_enc: '${username_enc}' 27 | password_enc: '${password_enc}' 28 | 29 | -----------------8<----- add this to your jamf script -----8<------------------- 30 | 31 | ################################################################################ 32 | # 33 | # decrypt credentials - jamfCredEncrypter.sh 34 | # 35 | ################################################################################ 36 | 37 | username_enc="${4}" 38 | password_enc="${5}" 39 | salt="'${SALT}'" 40 | key="'${KEY}'" 41 | 42 | username=$(echo "${username_enc}" | openssl enc -aes256 -d -a -A -S "${salt}" -k "${key}") 43 | password=$(echo "${password_enc}" | openssl enc -aes256 -d -a -A -S "${salt}" -k "${key}") 44 | 45 | ################################################################################ 46 | 47 | -----------------8<----- add this to your jamf script -----8<------------------- 48 | 49 | ' 50 | exit 51 | -------------------------------------------------------------------------------- /profileInstaller/postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # postinstall-profileInstaller.sh 4 | # 5 | # because, derp - https://jamfnation.jamfsoftware.com/discussion.html?id=13997 6 | IFS=$'\n' 7 | 8 | for mobileconfig in /tmp/profiles/* 9 | do 10 | profiles -I -F ${mobileconfig} 11 | done 12 | 13 | rm -R /tmp/profiles/ 14 | 15 | exit 0 16 | -------------------------------------------------------------------------------- /progressScreenHelper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # progresScreenHelper.py 3 | # the most bodacious progress screen's best friend - https://github.com/jason-tratta/ProgressScreen 4 | # 5 | # progress screen interacts via applescript, which isn't the most fun thing from a jamf policy 6 | # progresScreenHelper is here to halp. 7 | # 8 | # put it in jamf 9 | # call it from a policy at the start of your build policies 10 | # Policy: Start Build 11 | # progressScreenHelper.py 12 | # --start 13 | # /Library/Management/Images/ProgresScreen/build/index.html 14 | # --fullscreen 15 | # --hidequit 16 | # --buildtime 600 17 | # 18 | # Policy: Install Apps 19 | # Package: App.pkg Install 20 | # 21 | # Policy: Build - Half way there 22 | # progressScreenHelper.py 23 | # --progress 50 24 | # 25 | # Policy: Install Moar Apps 26 | # Package: App_2.pkg Install 27 | # 28 | # Policy: Build - Almost done 29 | # progressScreenHelper.py 30 | # --progress 95 31 | # 32 | # Policy: Build - Done 33 | # progressScreenHelper.py 34 | # --progress 100 35 | # --end 36 | 37 | 38 | import sys 39 | import os 40 | import argparse 41 | import shlex 42 | import subprocess 43 | import argparse 44 | import time 45 | 46 | progress_screen_app = "/Library/Management/bin/ProgressScreen.app" 47 | prefs = "/tmp/.progressscreen_helper" 48 | jamf_log="/var/log/jamf.log" 49 | 50 | def getArguments(): 51 | ''' 52 | get the arguments from command line 53 | ''' 54 | parser = argparse.ArgumentParser() 55 | parser.add_argument("jamf-arguments", nargs="*", help='toss in all the jamf arguments in here') 56 | parser.add_argument('--start', nargs='?', const='_empty_', metavar='html_path', help='start ProgressScreen with [html_path]') 57 | parser.add_argument('--fullscreen', action='store_true', help='set fullscreen mode') 58 | parser.add_argument('--hidequit', action='store_true', help='hide the quit button') 59 | parser.add_argument('--buildtime', nargs=1, metavar='build_time_secs', type=int, help='set [build_time_secs] for progress bar') 60 | parser.add_argument('--progress', nargs=1, metavar='progress_percentage', type=int, help='set [progress_percentage] (based on build_time_sec) for progress bar') 61 | parser.add_argument('--waypoints', nargs=4, metavar='app.pkg', help='set waypoints to [app1.pkg] [app2.pkg] [app3.pkg] [app4.pkg]') 62 | parser.add_argument('--message', nargs='?', const='_empty_', metavar='log_message', help='write an entry to jamf.log that ProgressScreen will display') 63 | parser.add_argument('--end', action='store_true', help='quit the app and remove temp file') 64 | parser.add_argument('--sleep', nargs=1, metavar='sleep_secs', type=int, help='sleep for [sleep_secs]') 65 | 66 | if len(sys.argv[1:])==0: 67 | parser.print_help() 68 | parser.exit() 69 | args = parser.parse_known_args()[0] 70 | return args 71 | 72 | def sendAppleScript(command): 73 | ''' 74 | send Apple script to command to ProgressScreen 75 | ''' 76 | osa_full_command = shlex.split("""osascript -e 'tell application "ProgressScreen"' -e '%s' -e 'end tell'""" % command) 77 | subprocess.check_output(osa_full_command) 78 | 79 | def tellProgressScreen(command, setting): 80 | ''' 81 | tell progress screen to do any of it's tricks - ref.. https://github.com/jason-tratta/ProgressScreen 82 | ''' 83 | # if we've been passed a boolean, make it a string to be passto osa_script 84 | if isinstance(setting, bool): 85 | setting = "True" 86 | applescript = "set %s of every configuration to %s" % (command, setting) 87 | sendAppleScript(applescript) 88 | 89 | def logMessage(message): 90 | with open(jamf_log, 'a') as f: 91 | f.write('ProgressScreen[]: %s' % message) 92 | 93 | def errorHander(error, type): 94 | ''' 95 | type - anything or ='stop' to break execution 96 | ''' 97 | print "%s: %s" % (type, error) 98 | if type == "STOP": 99 | sys.exit(1) 100 | 101 | def main(): 102 | args = getArguments() 103 | 104 | if args.sleep: 105 | sleep_secs = args.sleep[0] 106 | time.sleep(sleep_secs) 107 | 108 | if args.message: 109 | message = args.message 110 | if message == "_empty_": 111 | errorHander("i expected a message", "STOP") 112 | logMessage(message) 113 | 114 | if args.start: 115 | html_path = args.start 116 | if html_path == "_empty_": 117 | errorHander("i expected and html file", "STOP") 118 | if not os.path.exists(html_path): 119 | errorHander("couldn't find: %s" % html_path, "STOP") 120 | # i couldn't figure out quoting passing this to sendAppleScript -derp 121 | osa_full_command = shlex.split("""osascript -e 'tell application "ProgressScreen"' -e 'set htmlURL of every configuration to "%s"' -e 'end tell'""" % html_path) 122 | subprocess.check_output(osa_full_command) 123 | 124 | if args.fullscreen: 125 | tellProgressScreen("fullscreen", True) 126 | 127 | if args.hidequit: 128 | tellProgressScreen("hideQuitButton", True) 129 | 130 | if args.buildtime: 131 | build_time = args.buildtime[0] 132 | with open(prefs, 'w') as f: 133 | f.write(str(build_time)) 134 | tellProgressScreen("buildTime", build_time) 135 | 136 | if args.progress: 137 | progress_percentage = args.progress[0] 138 | # read the build time from previous policy 139 | if os.path.isfile(prefs): 140 | with open (prefs, 'r') as f: 141 | build_time = int(f.read().replace('\n', '')) 142 | # or set it as a default 143 | else: 144 | build_time = 10000 145 | current_time = (progress_percentage * build_time) / 100 146 | tellProgressScreen("currentTime", current_time) 147 | 148 | if args.waypoints: 149 | tellProgressScreen("useWayPointMethod", True) 150 | tellProgressScreen("wayPointOne", args.waypoints[1]) 151 | tellProgressScreen("wayPointTwo", args.waypoints[2]) 152 | tellProgressScreen("wayPointThree", args.waypoints[3]) 153 | tellProgressScreen("wayPointFour", args.waypoints[4]) 154 | 155 | if args.end: 156 | if os.path.isfile(prefs): 157 | os.remove(prefs) 158 | subprocess.check_output(['killall','ProgressScreen']) 159 | 160 | if __name__ == "__main__": 161 | main() 162 | -------------------------------------------------------------------------------- /superrecon.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # superrecon2.sh 4 | # 5 | # scrape directory for user & location info 6 | 7 | userloggedin="$(who | grep console | awk '{print $1}')" 8 | adcheck=$(dscl . read /Users/${userloggedin} AuthenticationAuthority | grep LocalCachedUser) 9 | 10 | if [ -z "${adcheck}" ] 11 | then 12 | echo "superRecon - ${userloggedin} is a Local Account" 13 | echo "------------------------------------------------------------------------" 14 | jamf recon -endUsername "${userloggedin}" -position "Local Account" -realname "" -email "" -position "" -phone "" # blank out empty fields in jss. 15 | else 16 | echo "supeRecon - ${userloggedin} is an AD Account" 17 | echo "------------------------------------------------------------------------" 18 | userrealname=$(dscl . -read /Users/${userloggedin} original_realname 2> /dev/null | tail -1 | cut -d ' ' -f 2-) 19 | useremail=$(dscl . -read /Users/${userloggedin} EMailAddress 2> /dev/null | cut -d ' ' -f 2-) 20 | userposition=$(dscl . -read /Users/${userloggedin} JobTitle 2> /dev/null | tail -1 | cut -d ' ' -f 2-) # these keys may not be filed 21 | userphone=$(dscl . -read /Users/${userloggedin} PhoneNumber 2> /dev/null | tail -1 | cut -c 2-) 22 | jamf recon -endUsername "${userloggedin}" -realname "${userrealname}" -email "${useremail}" -position "${userposition}" -phone "${userphone}" 23 | fi 24 | 25 | exit 0 26 | -------------------------------------------------------------------------------- /synccdps/com.github.loceee.synccdps.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.github.loceee.synccdps 7 | ProgramArguments 8 | 9 | /Library/Scripts/syncCDPs.sh 10 | 11 | StartCalendarInterval 12 | 13 | Hour 14 | 21 15 | Minute 16 | 0 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /synccdps/synccdps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # rsyncs CDPs points... run on your master CDP nightly or whenevers... 5 | # 6 | # queries your jss api and pulls down all your CDP info. 7 | # rsyncs local via a file share (slower) but more compatible 8 | # 9 | # why hasn't someone mades this sooner... sheesh? 10 | # 11 | # 12 | # github.com/loceee 13 | 14 | # read only api user please! 15 | apiuser="apiuser" 16 | apipass="apipass" 17 | 18 | # we can't read this from the api 19 | casperadminpassword="cadminpass" 20 | 21 | # you know 22 | jssurl="https://jss.company.com:8443" 23 | 24 | # if you are using a self signed cert for you jss, tell curl to allow it. 25 | selfsignedjsscert=true 26 | 27 | # your local casper share path 28 | masterlocalpath="/Volumes/Data/CasperShare" 29 | 30 | # local netboot image path (inc .nbi folder) - sync your production netboot nbi to NetSUS 31 | # blank to disable 32 | #localnetbootpath="/Library/NetBoot/NetBootSP0/NetBoot.nbi" 33 | 34 | # you need this ... http://caspian.dotconf.net/menu/Software/SendEmail/ 35 | # and I expect to find it at $sendemail 36 | sendemail="$(dirname $0)/sendEmail" # comment or blank to disable email sending 37 | smtpserver="smtp.company.com" 38 | smtpuser="" 39 | smtppass="" 40 | fromemail="$(basename ${0})@$(hostname)" 41 | erroremails=( "email@address.com" ) 42 | 43 | log="/var/log/synccdps.log" 44 | 45 | # 46 | # don't touch below. 47 | # 48 | echo "$(basename ${0}) logging to: ${log}" 49 | #set -xv 50 | exec 1> ${log} 2>&1 51 | 52 | if ${selfsignedjsscert} 53 | then 54 | curlopts="-k" 55 | else 56 | curlopts="" 57 | fi 58 | 59 | 60 | # make tmp folder 61 | tmpdir="/tmp/rsyncdp-$$" 62 | cdplist="${tmpdir}/cdplist.xml" 63 | cdpdata="${tmpdir}/cdpdata" 64 | mkdir "${tmpdir}" 65 | mkdir "${cdpdata}" 66 | 67 | errorHander() 68 | { 69 | # Error function 70 | message="${1}" 71 | echo "ERROR: ${message}" 72 | unmountShare 73 | if [ -f ${sendemail} ] 74 | then 75 | ( 76 | echo "$(basename ${0})" 77 | echo "from: $(hostname)" 78 | echo "$(date)" 79 | echo 80 | echo "ERROR: ${message}" 81 | echo "log attached: ${log}" 82 | echo "----------------------------------------------------------" 83 | echo "" 84 | ) > "${tmpdir}/erroremail.tmp" 85 | cat "${log}" >> "${tmpdir}/erroremail.tmp" 86 | for emailaddress in ${erroremails[@]} 87 | do 88 | ${sendemail} -o tls=no -f ${fromemail} -t ${emailaddress} -u "ERROR: $(basename ${0}) from $(hostname)" -o message-file="${tmpdir}/erroremail.tmp" -s ${smtpserver} -xu ${smtpuser} -xp ${smtppass} 89 | done 90 | fi 91 | rm -R "${tmpdir}" 92 | exit 1 93 | } 94 | 95 | unmountShare() 96 | { 97 | if [ -d "${mountpath}" ] 98 | then 99 | echo "unmounting ${mountpath}..." 100 | sleep 1 101 | umount "${mountpath}" 102 | 103 | if [ "$?" != "0" ] 104 | then 105 | echo "forcing unmount..." 106 | diskutil unmount force "${mountpath}" 107 | if [ "$?" != "0" ] 108 | then 109 | echo "There was a problem unmounting $mountpath" 110 | exit 1 111 | fi 112 | fi 113 | rm -R "${mountpath}" 114 | fi 115 | } 116 | 117 | makeMountPath() 118 | { 119 | if [ -d "${mountpath}" ] 120 | then 121 | echo "${mountpath} exists.. just throwing it an umount" 122 | umount "${mountpath}" 123 | else 124 | mkdir "${mountpath}" 125 | fi 126 | } 127 | 128 | echo "rsync to cdps started: $(date)" 129 | echo "=======================================================================" 130 | echo "getting cdp details from ${jssurl} ..." 131 | curl ${curlopts} -H "Accept: application/xml" -s -u "${apiuser}":"${apipass}" ${jssurl}/JSSResource/distributionpoints > "${cdplist}" 132 | # get number of cdps 133 | cdpsize=$(xpath "${cdplist}" //distribution_points/size 2> /dev/null | sed -e 's///g;s/<\/size>//g') 134 | 135 | 136 | for (( i=1; i<=${cdpsize}; i++ )) 137 | do 138 | cdpname[${i}]=$(xpath "${cdplist}" //distribution_points/distribution_point[${i}]/name 2> /dev/null | sed -e 's///g;s/<\/name>//g') 139 | echo "getting details for ${cdpname[${i}]} ..." 140 | curl ${curlopts} -H "Accept: application/xml" -s -u "${apiuser}":"${apipass}" ${jssurl}/JSSResource/distributionpoints/name/$(echo ${cdpname[${i}]} | sed -e 's/ /\+/g') > "${cdpdata}/${cdpname[${i}]}.xml" 141 | cdpip[${i}]=$(xpath "${cdpdata}/${cdpname[${i}]}.xml" //distribution_point/ip_address 2> /dev/null | sed -e 's///g;s/<\/ip_address>//g') 142 | cdplocalpath[${i}]=$(xpath "${cdpdata}/${cdpname[${i}]}.xml" //distribution_point/local_path 2> /dev/null | sed -e 's///g;s/<\/local_path>//g') 143 | cdpismaster[${i}]=$(xpath "${cdpdata}/${cdpname[${i}]}.xml" //distribution_point/is_master 2> /dev/null | sed -e 's///g;s/<\/is_master>//g') 144 | cdpprotocol[${i}]=$(xpath "${cdpdata}/${cdpname[${i}]}.xml" //distribution_point/connection_type 2> /dev/null | sed -e 's///g;s/<\/connection_type>//g') 145 | cdpshare[${i}]=$(xpath "${cdpdata}/${cdpname[${i}]}.xml" //distribution_point/share_name 2> /dev/null | sed -e 's///g;s/<\/share_name>//g') 146 | cdpusername[${i}]=$(xpath "${cdpdata}/${cdpname[${i}]}.xml" //distribution_point/read_write_username 2> /dev/null | sed -e 's///g;s/<\/read_write_username>//g') 147 | cdpsshname[${i}]=$(xpath "${cdpdata}/${cdpname[${i}]}.xml" //distribution_point/ssh_username 2> /dev/null | sed -e 's///g;s/<\/ssh_username>//g') 148 | done 149 | 150 | for (( i=1; i<=${cdpsize}; i++ )) 151 | do 152 | 153 | [ "${cdpismaster[${i}]}" == "true" ] && continue # if it's the master, skip it, we don't sync to ourself, silly beans 154 | 155 | mountpath="/tmp/${cdpshare[${i}]}" 156 | makeMountPath 157 | 158 | echo 159 | echo "-----------------------------------------------------------------------" 160 | echo "starting sync to ${cdpname[${i}]}.." 161 | echo "mounting ${cdpip[${i}]}/${cdpshare[${i}]} via ${cdpprotocol[${i}]} ..." 162 | case ${cdpprotocol[${i}]} in 163 | AFP) 164 | mount_afp afp://${cdpusername[${i}]}:${casperadminpassword}@${cdpip[${i}]}/${cdpshare[${i}]} "$mountpath" 165 | mounterror="$?" 166 | ;; 167 | 168 | SMB) 169 | mount_smbfs //${cdpusername[${i}]}:${casperadminpassword}@${cdpip[${i}]}/${cdpshare[${i}]} "$mountpath" 170 | mounterror="$?" 171 | ;; 172 | 173 | *) 174 | errorHander "unhandled protomacol ${cdpprotocol[i$]}... zoink!" 175 | ;; 176 | esac 177 | [ "${mounterror}" != "0" ] && errorHander "there was a problem mounting the network share $share from ${cdpname[${i}]} - mount_${cdpprotocol[${i}]} returned ${mounterror}"] 178 | 179 | echo "rsyncing to ${cdpname[${i}]}: $(date) ..." 180 | #rsync -av --delete --exclude=".*" --no-perms --omit-dir-times "$masterlocalpath/" "$mountpath/" 181 | rsync -rltDv --delete --exclude=".*" "${masterlocalpath}/" "${mountpath}/" 182 | error="$?" 183 | # rsync error handler - we can ignore a couple of common errors 184 | 185 | if [ "${error}" != "0" ] 186 | then 187 | case $error in 188 | 23) 189 | echo "rsync error 23 - non-critical" 190 | ;; 191 | 192 | 24) 193 | echo "rsync error 24 - non-critical" 194 | ;; 195 | 196 | 12) 197 | errorHander "out of disk space.. blerg" 198 | ;; 199 | 200 | *) 201 | errorHander "rsync returned error: ${error}" 202 | ;; 203 | esac 204 | fi 205 | # done, unmount this server 206 | unmountShare 207 | 208 | # if we are syncing netboot images to cdps as well, do it. 209 | if [ -n "${localnetbootpath}" ] 210 | then 211 | echo "mounting NetBoot share on NetSUS and syncing.." 212 | mountpath="/tmp/NetBoot" 213 | makeMountPath 214 | mount_smbfs //smbuser:${casperadminpassword}@${cdpip[${i}]}/NetBoot "$mountpath" 215 | mounterror="$?" 216 | [ "${mounterror}" != "0" ] && errorHander "${cdpname[${i}]} Problem Syncing Netboot image - mount_smbfs returned ${mounterror}"] 217 | rsync -rltDv --delete --exclude=".*" "${localnetbootpath}/" "${mountpath}/NetBoot.nbi/" 218 | unmountShare 219 | fi 220 | 221 | done 222 | 223 | echo 224 | echo "finished !" 225 | echo "=======================================================================" 226 | echo "rsync to cdps finished: $(date)" 227 | 228 | rm -R "${tmpdir}" 229 | exit 230 | -------------------------------------------------------------------------------- /zzz_flushPolicyHistory.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | jamf flushPolicyHistory 4 | 5 | exit 0 6 | -------------------------------------------------------------------------------- /zzz_partionhd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # repartion main hard disk 4 | # 5 | # casper imaging doesn't allow you to partion back to 1 single parition? 6 | # 7 | # undo a previous fstab / system / data partition setup. 8 | # 9 | # WARNING. THIS DESTROYS ALL DATA ON YOUR INTERNAL DISK 10 | # RUN IN A DESTRUCTIVE CASPER IMAGING WORKFLOW ONLY 11 | # 12 | # YOU HAVE BEEN WARNED! 13 | # 14 | # (it won't handle fusion disks) 15 | # http://github.com/loceee 16 | 17 | numberofinternals=0 18 | 19 | checkDiskInfo() 20 | { 21 | devicepath="${1}" 22 | info="${2}" 23 | result=$(diskutil info ${devicepath} | grep "${info}:" | awk '{ print $2 }') 24 | echo "${result}" 25 | } 26 | 27 | for device in $(diskutil list | grep /dev/) 28 | do 29 | internal=$(checkDiskInfo ${device} "Internal") 30 | ejectable=$(checkDiskInfo ${device} "Ejectable") 31 | # if it's internal and not ejectable, we'll assume it's the internal drive 32 | if [ "${internal}" == "Yes" ] && [ "${ejectable}" == "No" ] 33 | then 34 | (( numberofinternals ++ )) 35 | internaldevice="${device}" 36 | fi 37 | done 38 | 39 | if [ "${numberofinternals}" == "1" ] 40 | then 41 | # there is only 1 internal disk that complies... let's blow it away! 42 | diskutil umountDisk force ${internaldevice} 43 | diskutil partitionDisk ${internaldevice} 1 GPTFormat JHFS+ "Macintosh HD" 100% 44 | else 45 | # there is 0 or 2+ disks.. too tricky for this script (for now) 46 | echo "there are ${numberofinternals} valid internal devices... I don't know what to do." 47 | fi 48 | 49 | exit 50 | 51 | --------------------------------------------------------------------------------