Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env bash
- #
- # Filename: copy-to-target.bash
- # Version: ???
- # Release date: 2017-08-28
- # Intended compatibility: WSUS Offline Update Version 10.9.2 and newer
- # Tested, but use with eyes open - there are used some nasty tricks to
- # make XCOPY and Rsync exclude files compatible!
- #
- # Author: Václav Valíček <vaclav@valicek.name>
- #
- # License
- #
- # This file is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published
- # by the Free Software Foundation, either version 3 of the License,
- # or (at your option) any later version.
- #
- # This file is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- # General Public License for more details.
- #
- # You should have received a copy of the GNU General
- # Public License along with this program. If not, see
- # <http://www.gnu.org/licenses/>.
- #
- # USAGE:
- # ./copy-to-target.bash UPDATE LANGUAGE OUTPUT_PATH [OPTION,[OPTION..]]
- # Allowed UPDATE fields
- # - see $WinTargets and $OfcTargets arrays
- # Allowed LANGUAGE fields
- # - see $WinLangs/$OfcLangs arrays respectively
- # Allowed OUTPUT_PATH
- # - anywhere you have write access
- # Allowed Options
- # -excludesp - Exclude ServicePacks
- # -excludesw - Exclude MS Software
- # -includedotnet - Include .NET
- # -includemsse - Include MS Security Essentials
- # -includewddefs - Include Windows Defender Definitions
- # (W8.1 and W10)
- # -cleanup - Purge Output directory before doing anything
- # -hardlinks - Try to use Hardlinks to save some space
- # (must be same mountpoint/device)
- # Unofficial bash strict mode
- # http://redsymbol.net/articles/unofficial-bash-strict-mode/
- set -euo pipefail
- IFS=$'\n\t'
- # Configuration
- readonly script_dir=$(dirname $(realpath $0))
- readonly temp_dir="/tmp/wsusoffline_temp"
- readonly timestamp_dir="../timestamps"
- readonly log_dir="../log"
- readonly logfile="${log_dir}/copy-to-target.log"
- readonly cache_dir="../cache"
- readonly filter_dir="../exclude"
- # Windows Targets + ofc
- readonly WinTargets=(w60 w60-x64 w61 w61-x64 w62-x64 w63 w63-x64 w100 w100-x64)
- readonly WinLangs=(glb)
- # Defender vs msse
- # regular expression for installing Defender Defs, otherwise MSSE would be installed
- readonly WddefsTargets="w62|w63|w100"
- # Office Targets
- readonly OfcTargets=(ofc)
- readonly OfcLangs=(glb enu fra esn jpn kor rus ptg ptb deu nld ita chs cht plk hun csy sve trk ell ara heb dan nor fin)
- # Log function
- # ========================================================================
- function log {
- toPut="$(date "+%x %X") $@"
- echo $toPut
- echo "$toPut" >> $script_dir/$logfile
- }
- # Die Function
- # die RC Log message
- # ========================================================================
- function die {
- rc=$1
- shift
- log "$@"
- exit $rc
- }
- # FINISH Trap (in the case of issue)
- # ========================================================================
- function finish {
- log Cleaning up mess in $temp_dir
- [ -d $temp_dir ] && rm -Rf $temp_dir
- }
- # set the trap
- trap finish EXIT
- # Does Array contain element?
- # Usage: containsElement "requested string" "${array[@]}"
- # ========================================================================
- function contains() {
- local n=$#
- local value=${!n}
- for ((i=1;i < $#;i++)) {
- if [ "${!i}" == "${value}" ]; then
- return 0
- fi
- }
- return 1
- }
- # Run main Process
- # ========================================================================
- # Write new block to logfile
- [ -f $logfile ] && echo "--------------------------------------------------------------------------" >> $logfile
- echo "copy-to-target script started" >> $logfile
- echo "--------------------------------------------------------------------------" >> $logfile
- log "CMD: $0 $@"
- # Check number of arguments, at least two
- log "Checking arguments"
- [ $# -lt 3 ] && die 1 "You must specify at least three arguments!"
- update=$1
- language=$2
- target_dir=$3
- # Check, if its windows update
- if contains ${WinTargets[@]} $update
- then
- # It's windows, check windows language
- contains ${WinLangs[@]} $language || die 1 "Unknown Windows Language -> exiting"
- else
- # It could be office or mistake
- if contains ${OfcTargets[@]} $update
- then
- # It's office
- contains ${OfcLangs[@]} $language || die 1 "Unknown Office Language -> exiting"
- else
- die 1 "Unknown UPDATE parameter -> exiting"
- fi
- fi
- log "UPDATE: $update"
- log "LANG: $language"
- log "TARGET: $target_dir"
- # End of main arguments parsing, parse also options
- # defaults
- opt_exclude_sp=0
- opt_exclude_sw=0
- opt_include_dotnet=0
- opt_include_msse=0
- opt_include_wddefs=0
- opt_cleanup=0
- opt_hardlinks=0
- shift 3
- while [ $# -gt 0 ]
- do
- case $1 in
- "-excludesp") opt_exclude_sp=1
- ;;
- "-excludesw") opt_exclude_sw=1
- ;;
- "-includedotnet") opt_include_dotnet=1
- ;;
- "-includemsse") opt_include_msse=1
- ;;
- "-includewddefs")
- if echo $update | grep -E $WddefsTargets > /dev/null
- then
- opt_include_wddefs=1
- else
- log "Uncompatlible Windows version and $1 flag, setting -includemsse instead"
- opt_include_msse=1
- opt_include_wddefs=0
- fi
- ;;
- "-cleanup") opt_cleanup=1
- ;;
- "-hardlinks") opt_hardlinks=1
- ;;
- *) die 1 "Unknown option: $1 -> exiting!"
- ;;
- esac
- shift
- done
- [ $opt_exclude_sp -eq 1 ] && log "OPT: Exclude ServicePacks"
- [ $opt_exclude_sw -eq 1 ] && log "OPT: Exclude Updates of other SW"
- [ $opt_include_dotnet -eq 1 ] && log "OPT: Include .NET updates"
- [ $opt_include_msse -eq 1 ] && log "OPT: Include Microsoft Security Essentials"
- [ $opt_include_wddefs -eq 1 ] && log "OPT: Include Windows defender definitions"
- [ $opt_cleanup -eq 1 ] && log "OPT: Output path ($target_dir) will be purged"
- # Info
- log "Script dir: $script_dir"
- cd $script_dir
- # Temp directory
- if [ ! -d $temp_dir ]
- then
- log "Creating temp dir: $temp_dir"
- mkdir $temp_dir
- else
- log "Temp dir EXISTS!"
- fi
- # Create filter
- log "Creating filter for $update ($language)"
- filter=$temp_dir/Filter-$update-$language
- excl_prefix=$filter_dir/ExcludeListUSB
- # Main exclude for architecture
- [ -f $excl_prefix-$update.txt ] && cp $excl_prefix-$update.txt $filter || cp $excl_prefix-$update-x86.txt $filter
- # Customs
- [ -f $filter_dir/custom/ExcludeListUSB-$update.txt ] && cat $filter_dir/custom/ExcludeListUSB-$update.txt >> $filter
- # Customs x86
- [ -f $filter_dir/custom/ExcludeListUSB-$update-x86.txt ] && cat $filter_dir/custom/ExcludeListUSB-$update-x86.txt >> $filter
- # Filter other locales than allowed ones
- locales=(${WinLangs[@]} ${OfcLangs[@]})
- for loc in ${locales[@]}
- do
- # if locale is not same as chosen, add it to list
- [ ! "$language" == "$loc" ] && echo "$loc/" >> $filter
- done
- # Extend filter (with OPTS)
- [ $opt_exclude_sp -eq 1 ] && cat $filter_dir/ExcludeList-SPs.txt >> $filter
- [ $opt_exclude_sw -eq 1 ] && cat $filter_dir/ExcludeList-software.txt >> $filter
- [ $opt_include_dotnet -eq 0 ] && cat $filter_dir/ExcludeListISO-dotnet.txt >> $filter
- [ $opt_include_msse -eq 0 ] && cat $filter_dir/ExcludeList-msse.txt >> $filter
- [ $opt_include_wddefs -eq 0 ] && cat $filter_dir/ExcludeList-wddefs.txt >> $filter
- # replace \ with /
- cat $filter | sed 's/\\/\//g' | sed 's/\r$//' > $filter.tmp
- # truncate file
- cat /dev/null > $filter
- for line in $(cat $filter.tmp)
- do
- # is it path (ends with slash)
- if echo $line | grep -E '.*/$' > /dev/null
- then
- echo $line >> $filter
- else
- printf '*%s*\n' $line >> $filter
- fi
- done
- [ -f $target_dir ] && rm -f $target_dir
- if [ $opt_cleanup -eq 1 ]
- then
- log "Clean UP"
- rm -Rf $target_dir
- log "Done"
- fi
- mkdir -p $target_dir
- log "Synchronizing.."
- cd ../client
- if [ $opt_hardlinks -eq 1 ]
- then
- src=$(realpath .)
- tar=$(realpath $target_dir)
- rsync -a --log-file=$log_dir/rsync.txt --exclude-from=$filter --link-dest=$src $src/ $tar
- else
- rsync -a --log-file=$log_dir/rsync.txt --exclude-from=$filter . $target_dir
- fi
- log "Sync done"
- # Clean up Target
- log "Cleaning up Target dir"
- for f in $(find $target_dir -printf "%P\n")
- do
- # empty row - skip
- [ "x$f" == "x" ] && continue
- # is it file or direcory?
- if [ -f $target_dir/$f ]
- then
- # its a file
- if [ ! -f $f ]
- then
- log "Remove file: $f"
- rm -f $target_dir/$f
- fi
- else
- # its a directory
- if [ ! -d $f ]
- then
- log "Remove dir: $f"
- rm -rf $target_dir/$f
- fi
- fi
- done
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement