Key takeaways
- Automated installation: The script automates the installation of ConnectWise Control on macOS, enhancing efficiency in IT environments.
- Customization features: It supports customizing installations with organization name, device location, type, and department.
- Error handling: The script includes robust error handling and retry logic for reliable downloading.
- Flexibility in parameters: Offers flexibility by accepting various formats for command-line arguments.
- URL building: Dynamically builds the download URL tailored to specific organizational needs.
- Pre-installation check: Includes a check to avoid reinstalling ConnectWise Control if it’s already present.
- Security considerations: Emphasizes the need for secure sourcing and package integrity verification.
- Adaptability: While designed for macOS, the script’s concept is adaptable for other systems or software.
- Integration with IT management tools: Highlights the script’s potential synergies with broader IT management platforms like NinjaOne.
Automation and efficiency are crucial in the ever-evolving landscape of IT management. Streamlining the installation of essential tools, like remote support software, not only saves valuable time but also ensures consistency across multiple devices. This approach is particularly significant for Managed Service Providers (MSPs) and IT professionals who manage a fleet of machines.
Background
ConnectWise Control, formerly known as ScreenConnect, is a popular remote support, access, and meeting solution widely used in the IT industry. Its adaptability and robust feature set make it an indispensable tool for MSPs and IT departments. The script in question automates the installation of ConnectWise Control on macOS systems. This automation is particularly vital for IT professionals and MSPs to deploy this software efficiently across multiple macOS devices, maintaining standardization and reducing manual workload.
The script:
#!/usr/bin/env bash # # Description: Download and Install ConnectWise ScreenConnect. Supports automatic customization of the company name, device type, location, and other ScreenConnect fields. # By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use. # Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. # Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. # Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. # Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. # Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. # Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. # EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA). # # Preset Parameter: --screenconnectdomain "replace.me" # Replace the text encased in quotes to have the script build the download URL and then install ScreenConnect. # # Preset Parameter: --useOrgName # Modifies your URL to use the organization name in the "Company Name" field in ScreenConnect. # # Preset Parameter: --useLocation # Modifies your URL to use the Location Name in the "Site" field in ScreenConnect. # # Preset Parameter: --useDeviceType # Modifies your URL to fill in the "Device Type" field in ScreenConnect. (Either Workstation or Laptop). # # Preset Parameter: --Department "REPLACEME" # Modifies your URL to fill in the Department name with the text encased in quotes. # # Preset Parameter: --skipSleep # By default, this script sleeps at a random interval (between 3 and 30 seconds) before downloading the installation file. # This option skips the random sleep interval. # # Preset Parameter: --help # Displays some help text. # These are all our preset parameter defaults. You can set these = to something if you would prefer the script automatically assumed a parameter is used. _arg_instanceId= _arg_screenconnectdomain= # For parameters that don't have arguments "on" or "off" is used. _arg_useOrgName="off" _arg_useLocation="off" _arg_useDeviceType="off" _arg_department= _arg_filename="ClientSetup.pkg" _arg_destfolder=/tmp _arg_skipsleep="off" # Help text function for when invalid input is encountered print_help() { printf '\n\n%s\n\n' 'Usage: [--screenconnectdomain <arg>] [--useOrgName] [--useLocation] [--useDeviceType] [--department <arg>] [--skipSleep] [-h|--help]' printf '\n%s\n' 'Preset Parameter: --screenconnectdomain "replace.me"' printf '\t%s\n' "Replace the text encased in quotes with the domain used for ConnectWise ScreenConnect. ex. 'example.screenconnect.com'" printf '\n%s\n' 'Preset Parameter: --useOrgName' printf '\t%s\n' "Builds the url so the 'Company Name' field in ScreenConnect is filled in with the Organization Name." printf '\n%s\n' 'Preset Parameter: --useLocation' printf '\t%s\n' "Builds the url so the 'Site Name' field in ScreenConnect is filled in with the Location the device is in in Ninja." printf '\n%s\n' 'Preset Parameter: --useDeviceType' printf '\t%s\n' "Builds the url so the 'Device Type' field in ScreenConnect is filled in with the detected device type (Laptop or Workstation)." printf '\n%s\n' 'Preset Parameter: --department "YourDesiredDepartmentName"' printf '\t%s\n' "Builds the url so the 'Department' field in ScreenConnect is filled in with the text encased in quotes." printf '\n%s\n' 'Preset Parameter: --skipSleep' printf '\t%s\n' "By default this script will sleep at a random interval between 3 and 60 seconds prior to download. Use this option to skip this behavior." printf '\n%s\n' 'Preset Parameter: --help' printf '\t%s\n' "Displays this help menu." } # Determines whether or not help text is necessary and routes the output to stderr die() { local _ret="${2:-1}" echo "$1" >&2 test "${_PRINT_HELP:-no}" = yes && print_help >&2 exit "${_ret}" } # Grabbing the parameters and parsing through them. parse_commandline() { while test $# -gt 0; do _key="$1" case "$_key" in --screenconnectdomain | --domain) test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 _arg_screenconnectdomain=$2 shift ;; --screenconnectdomain=*) _arg_screenconnectdomain="${_key##--screenconnectdomain=}" ;; --useOrgName | --useorgname | --orgname) _arg_useOrgName="on" ;; --useLocation | --useOrgLocation | --uselocation | --location) _arg_useLocation="on" ;; --useDeviceType | --usedevicetype | --devicetype) _arg_useDeviceType="on" ;; --department | --Department) test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1 _arg_department="$2" shift ;; --department=*) _arg_department="${_key##--department=}" ;; --skipsleep | --skipSleep) _arg_skipsleep="on" ;; --help | -h) _PRINT_HELP=yes die 0 ;; *) _PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1 ;; esac shift done } parse_commandline "$@" # If dynamic script variables are used override the comand line arguments if [[ -n $screenconnectDomainName ]]; then _arg_screenconnectdomain="$screenconnectDomainName" fi if [[ -n $useNinjaOrganizationName && $useNinjaOrganizationName == "true" ]]; then _arg_useOrgName="on" fi if [[ -n $useNinjaLocationName && $useNinjaLocationName == "true" ]]; then _arg_useLocation="on" fi if [[ -n $addDeviceType && $addDeviceType == "true" ]]; then _arg_useDeviceType="on" fi if [[ -n $department ]]; then _arg_department="$department" fi if [[ -n $skipSleep && $skipSleep == "true" ]]; then _arg_skipsleep="on" fi # This function will download our file when we're ready for that. downloadFile() { i=1 while [[ $i -lt 4 ]]; do if [[ ! $_arg_skipsleep == "on" ]]; then sleep_time=$((3 + RANDOM % 60)) echo "Sleeping for $sleep_time seconds..." sleep $sleep_time fi echo "Download Attempt $i" curl -L "$url" -o "$_arg_destfolder/$_arg_filename" -s -f file=$_arg_destfolder/$_arg_filename if [[ -f $file ]]; then echo 'Download was successful!' i=4 else echo 'Attempt Failed!' ((i += 1)) fi done } # If we're not given a download method error out if [[ -z $_arg_screenconnectdomain ]]; then _PRINT_HELP=yes die "FATAL ERROR: The domain you use for ScreenConnect is required to install ScreenConnect." 1 fi pattern='^http(.?)://(.*)' if [[ $_arg_screenconnectdomain =~ $pattern ]]; then _arg_screenconnectdomain=${_arg_screenconnectdomain//http*:\/\//} echo "You accidentally included http with the domain. Using '$_arg_screenconnectdomain' instead." fi # If the destination folder doesn't exist create it. if [[ ! -d $_arg_destfolder ]]; then mkdir "$_arg_destfolder" fi # If a file already exists with that name remove it. if [[ -f "$_arg_destfolder/$_arg_filename" ]]; then rm "$_arg_destfolder/$_arg_filename" fi # Start the build process echo "Building URL..." # For anything we put in the url we'll need to escape it as curl won't do this conversion for us. companyName=$(echo "$NINJA_COMPANY_NAME" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"') baseURL="https://$_arg_screenconnectdomain/Bin/$companyName.ClientSetup.pkg?e=Access&y=Guest" # If the technician specified --useOrgName (or any other switch/flag) we set it to "on" when we parse the parameters if [[ $_arg_useOrgName == "on" ]]; then orgName=$(echo "$NINJA_ORGANIZATION_NAME" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"') baseURL="$baseURL&c=$orgName" else # If they decided to not use that field we just leave it blank so ScreenConnect will skip over it. baseURL="$baseURL&c=" fi if [[ $_arg_useLocation == "on" ]]; then location=$(echo "$NINJA_LOCATION_NAME" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"') baseURL="$baseURL&c=$location" else baseURL="$baseURL&c=" fi if [[ -n $_arg_department ]]; then _arg_department=$(echo "$_arg_department" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"') baseURL="$baseURL&c=$_arg_department" else baseURL="$baseURL&c=" fi # Getting whether or not the device is a laptop is a bit tricky. Fortunately only MacBooks are laptops (everything else is too old to worry about e.g. PowerBooks). if [[ $_arg_useDeviceType == "on" ]]; then modelName=$(system_profiler SPHardwareDataType -detaillevel mini | grep "Model Name" | sed 's/Model Name://' | xargs) modelIdentifier=$(system_profiler SPHardwareDataType -detaillevel mini | grep "Model Identifier" | sed 's/Model Identifier://' | xargs) if [[ $modelName == *"MacBook"* || $modelIdentifier == *"MacBook"* ]]; then deviceType="Laptop" else deviceType="Workstation" fi baseURL="$baseURL&c=$deviceType&c=&c=&c=&c=" else baseURL="$baseURL&c=&c=&c=&c=&c=" fi url="$baseURL" echo "URL Built: $url" # At this point we should have everything setup for us to be able to download the file. downloadFile # Lets check if the download was a success file="$_arg_destfolder/$_arg_filename" if [[ ! -f $file ]]; then _PRINT_HELP=no die "FATAL ERROR: The Installation File has failed to download please try again." 1 fi # Analyze .pkg file and grab application name pkgutil --expand $file "$_arg_destfolder/ScreenConnect" pkgname=$(grep -Eo "connectwisecontrol-.*" "$_arg_destfolder/ScreenConnect/PackageInfo" | sed 's/".*//') # Grabs a list of all installed packages and then filters it by connectwisecontrol-yourinstanceid if [[ -z $pkgname ]]; then echo "WARNING: Failed to get package name from .Pkg file. Checking if ANY ScreenConnect instance is installed." installedPkg=$(pkgutil --pkgs | grep "connectwisecontrol-") else installedPkg=$(pkgutil --pkgs | grep "$pkgname") fi if [[ -n $installedPkg ]]; then echo "Connectwise ScreenConnect is already installed!" exit 0 else echo "ConnectWise ScreenConnect is not installed. Installing..." fi # Start installing echo "Installing application..." if installer -pkg "$file" -target /; then echo "Exit Code: $?" echo "Connectwise ScreenConnect Installed Successfully!" rm "$file" exit 0 else echo "Exit Code: $?" rm "$file" _PRINT_HELP=no die "FATAL ERROR: The Installation has failed!" 1 fi
Access over 300+ scripts in the NinjaOne Dojo
Detailed breakdown
The script starts by defining a series of preset parameters. These parameters include the ConnectWise domain, options to include organization name, device location, and type, along with a department identifier. A notable feature is the ‘–skipSleep’ parameter, designed to bypass a random sleep interval before initiating the download, a clever addition to speed up the installation process when necessary.
Upon execution, the script first parses the command-line arguments provided, setting the appropriate variables based on user input. Noteworthy is its flexibility to accommodate different parameter formats (like –useOrgName and –useorgname), making it user-friendly.
The script then proceeds to build the download URL for the ConnectWise Control installer. This step involves dynamically adding parameters like organization name, location, and device type to the URL. It’s a critical part of the script, as it tailors the installation package to the specific needs of the organization or device.
The download process, handled by the downloadFile function, includes error handling and retry logic, ensuring reliable download even in less-than-ideal network conditions. The script attempts to download the file up to three times if necessary, a robust approach to handling potential download issues.
After downloading, the script checks if ConnectWise Control is already installed, avoiding unnecessary reinstallation. If not already installed, it proceeds to install the software.
Potential use cases
Consider an MSP managing IT infrastructure for several small businesses. Each business might have different configurations, like distinct departments or device types. Using this script, the MSP can quickly deploy ConnectWise Control across all client devices, customized to each business’s specific setup, thereby enhancing efficiency and reducing manual errors.
Comparisons
Traditionally, such installations would require manual downloading and configuration on each device or the use of bulk deployment tools that might not offer the same level of customization. This script provides a more streamlined, customizable approach, particularly beneficial for environments with varied and specific configuration needs.
FAQs
Q: Can this script be used for operating systems other than macOS?
A: No, this script is specifically designed for macOS.
Q: Is it possible to modify the script for different remote support software?
A: Yes, with appropriate modifications to the URL building and installation logic, it could be adapted for other software.
Implications
While this script vastly improves efficiency, it’s essential to consider security implications. Automated scripts can be a vector for security vulnerabilities if not handled correctly. Ensuring the script sources from a secure URL and verifying the integrity of the downloaded package are crucial steps.
Recommendations
Best practices would include regular reviews and updates of the script to accommodate any changes in the ConnectWise Control installation process or macOS updates. Also, ensuring the script is run in a secure environment to prevent any security breaches is essential.
Final thoughts
In the context of NinjaOne, a unified IT management platform, this script exemplifies the kind of efficiency and automation that can be integrated into broader IT management strategies. Such automation scripts, when combined with a comprehensive tool like NinjaOne, can significantly enhance the efficiency and effectiveness of IT management, particularly in diverse and dynamic environments.