diff --git a/scripts_staging/macos_Bitwarden_Install.sh b/scripts_staging/macos_Bitwarden_Install.sh new file mode 100644 index 00000000..4d7e631d --- /dev/null +++ b/scripts_staging/macos_Bitwarden_Install.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Description: Installs Bitwarden on macOS via the official Bitwarden DMG. +# The download URL redirects through Bitwarden's vault CDN and resolves +# to a DMG whose final URL contains a query string after the .dmg extension; +# the script follows HTTP redirects and checks for ".dmg" anywhere in the +# resolved URL (not just at the end) to handle this quirk. Once downloaded, +# it mounts the DMG, locates the .app bundle inside, and copies it to +# /Applications. Cleans up the temp download and unmounts the DMG when done. +# +# Configurable variables (edit at the top of the script or pass via RMM): +# DownloadUrl - URL to the Bitwarden DMG redirect (default: official macOS desktop build) +# ForceReinstall - Set to "True" to remove and reinstall if Bitwarden is already present +# +# Exit codes: +# 0 - Bitwarden installed successfully (or already present and ForceReinstall=False) +# 1 - Fatal error (URL resolution failure, download failure, mount failure, copy failure, etc.) +# +# Tested on: macOS (universal binary — works on Apple Silicon and Intel) +# Requires: curl, hdiutil (both available by default on macOS) + +DownloadUrl="https://vault.bitwarden.com/download/?app=desktop&platform=macos&variant=dmg" +ForceReinstall="False" # Set to "True" to reinstall even if already present +# ============================================================ + +# ── Logging ────────────────────────────────────────────────── +log() { echo "[INFO] $*"; } +warn() { echo "[WARN] $*"; } + +abort() { + echo "[ERROR] $*" + [[ -n "$DMGMountPoint" ]] && { hdiutil detach "$DMGMountPoint" -quiet 2>/dev/null; log "Detached DMG volume"; } + [[ -d "$TempFolder" ]] && { rm -rf "$TempFolder"; log "Cleaned up $TempFolder"; } + exit 1 +} + +# ── Resolve Final Download URL ──────────────────────────────── +log "Resolving download URL: $DownloadUrl" +ResolvedUrl=$(curl -sIL "$DownloadUrl" | grep -i "^location:" | tail -1 | awk '{print $2}' | tr -d '[:space:]') + +# Check if .dmg appears anywhere in the URL (may have query string after extension) +[[ "$ResolvedUrl" == *".dmg"* ]] || abort "Could not resolve a .dmg URL from headers. Got: $ResolvedUrl" +log "Resolved URL: $ResolvedUrl" + +# ── Download ────────────────────────────────────────────────── +TempFolder=$(mktemp -d) || abort "Failed to create temp folder" +log "Temp folder created: $TempFolder" + +log "Downloading Bitwarden DMG..." +curl -sL "$ResolvedUrl" -o "$TempFolder/Bitwarden.dmg" || abort "Download failed" +log "Download complete" + +# ── Mount DMG ───────────────────────────────────────────────── +log "Mounting DMG..." +hdiutilOutput=$(hdiutil attach "$TempFolder/Bitwarden.dmg" -nobrowse 2>&1) +[[ $? -ne 0 ]] && abort "hdiutil attach failed: $hdiutilOutput" + +DMGVolume=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $NF}' | tail -1 | sed 's/[[:space:]]*$//') +[[ -d "$DMGVolume" ]] || abort "Could not locate mounted DMG volume. hdiutil output: $hdiutilOutput" +log "Mounted volume: $DMGVolume" + +DMGMountPoint=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $1}' | tail -1 | sed 's/[[:space:]]*$//') +log "Mount point: $DMGMountPoint" + +# ── Find .app inside DMG ────────────────────────────────────── +DMGAppPath=$(find "$DMGVolume" -maxdepth 1 -name "*.app" | head -1) +[[ -n "$DMGAppPath" ]] || abort "No .app bundle found in $DMGVolume" +AppName=$(basename "$DMGAppPath") +log "Found app: $AppName" + +# ── Check for existing install ──────────────────────────────── +if [[ -d "/Applications/$AppName" ]]; then + if [[ "$ForceReinstall" == "True" ]]; then + warn "$AppName already installed — removing for reinstall" + rm -rf "/Applications/$AppName" || abort "Could not remove existing $AppName" + else + warn "$AppName is already installed. Set ForceReinstall=True to reinstall." + hdiutil detach "$DMGMountPoint" -quiet + rm -rf "$TempFolder" + exit 0 + fi +fi + +# ── Install ─────────────────────────────────────────────────── +log "Installing $AppName to /Applications..." +cp -pPR "$DMGAppPath" /Applications/ || abort "Failed to copy $AppName to /Applications" +log "Bitwarden installed successfully" + +# ── Cleanup ─────────────────────────────────────────────────── +hdiutil detach "$DMGMountPoint" -quiet +log "Detached DMG volume" +rm -rf "$TempFolder" +log "Cleaned up temp folder" + +log "Installation complete." +exit 0 \ No newline at end of file diff --git a/scripts_staging/macos_Google_Chrome_Install.sh b/scripts_staging/macos_Google_Chrome_Install.sh new file mode 100644 index 00000000..96836b97 --- /dev/null +++ b/scripts_staging/macos_Google_Chrome_Install.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# +# Description: Installs Google Chrome on macOS via the official Google DMG. +# Downloads the universal stable DMG, mounts it, locates the .app +# bundle inside, and copies it to /Applications. Cleans up the +# temp download and unmounts the DMG when done. +# +# Configurable variables (edit at the top of the script or pass via RMM): +# DownloadUrl - Direct URL to the Chrome DMG (default: Google stable universal) +# ForceReinstall - Set to "True" to remove and reinstall if Chrome is already present +# +# Exit codes: +# 0 - Chrome installed successfully (or already present and ForceReinstall=False) +# 1 - Fatal error (download failure, mount failure, copy failure, etc.) +# +# Tested on: macOS (Apple Silicon + Intel via universal binary) +# Requires: curl, hdiutil (both available by default on macOS) + +DownloadUrl="https://dl.google.com/chrome/mac/universal/stable/GGRO/googlechrome.dmg" +ForceReinstall="False" # Set to "True" to reinstall even if already present + +# ── Logging ────────────────────────────────────────────────── +log() { echo "[INFO] $*"; } +warn() { echo "[WARN] $*"; } + +abort() { + echo "[ERROR] $*" + [[ -n "$DMGMountPoint" ]] && { hdiutil detach "$DMGMountPoint" -quiet 2>/dev/null; log "Detached DMG volume"; } + [[ -d "$TempFolder" ]] && { rm -rf "$TempFolder"; log "Cleaned up $TempFolder"; } + exit 1 +} + +# ── Download ────────────────────────────────────────────────── +TempFolder=$(mktemp -d) || abort "Failed to create temp folder" +log "Temp folder created: $TempFolder" + +log "Downloading Google Chrome DMG..." +curl -sL "$DownloadUrl" -o "$TempFolder/GoogleChrome.dmg" || abort "Download failed" +log "Download complete" + +# ── Mount DMG ───────────────────────────────────────────────── +log "Mounting DMG..." +hdiutilOutput=$(hdiutil attach "$TempFolder/GoogleChrome.dmg" -nobrowse 2>&1) +[[ $? -ne 0 ]] && abort "hdiutil attach failed: $hdiutilOutput" + +DMGVolume=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $NF}' | tail -1 | sed 's/[[:space:]]*$//') +[[ -d "$DMGVolume" ]] || abort "Could not locate mounted DMG volume. hdiutil output: $hdiutilOutput" +log "Mounted volume: $DMGVolume" + +DMGMountPoint=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $1}' | tail -1 | sed 's/[[:space:]]*$//') +log "Mount point: $DMGMountPoint" + +# ── Find .app inside DMG ────────────────────────────────────── +DMGAppPath=$(find "$DMGVolume" -maxdepth 1 -name "*.app" | head -1) +[[ -n "$DMGAppPath" ]] || abort "No .app bundle found in $DMGVolume" +AppName=$(basename "$DMGAppPath") +log "Found app: $AppName" + +# ── Check for existing install ──────────────────────────────── +if [[ -d "/Applications/$AppName" ]]; then + if [[ "$ForceReinstall" == "True" ]]; then + warn "$AppName already installed — removing for reinstall" + rm -rf "/Applications/$AppName" || abort "Could not remove existing $AppName" + else + warn "$AppName is already installed. Set ForceReinstall=True to reinstall." + hdiutil detach "$DMGMountPoint" -quiet + rm -rf "$TempFolder" + exit 0 + fi +fi + +# ── Install ─────────────────────────────────────────────────── +log "Installing $AppName to /Applications..." +cp -pPR "$DMGAppPath" /Applications/ || abort "Failed to copy $AppName to /Applications" +log "Google Chrome installed successfully" + +# ── Cleanup ─────────────────────────────────────────────────── +hdiutil detach "$DMGMountPoint" -quiet +log "Detached DMG volume" +rm -rf "$TempFolder" +log "Cleaned up temp folder" + +log "Installation complete." +exit 0 \ No newline at end of file diff --git a/scripts_staging/macos_Google_Drive_Install.sh b/scripts_staging/macos_Google_Drive_Install.sh new file mode 100644 index 00000000..adeb8a17 --- /dev/null +++ b/scripts_staging/macos_Google_Drive_Install.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# +# Description: Installs Google Drive on macOS via the official Google DMG. +# Downloads the DMG, mounts it, locates the PKG installer inside, +# and runs it against the system target. Unlike a direct .app copy, +# this uses macOS's `installer` command to handle the PKG payload, +# which registers Google Drive's system components properly. +# Cleans up the temp download and unmounts the DMG when done. +# +# Configurable variables (edit at the top of the script or pass via RMM): +# DownloadUrl - Direct URL to the Google Drive DMG (default: Google stable) +# ForceReinstall - Set to "True" to proceed with install even if already present +# AppName - Expected app name used to detect an existing installation +# InstallPath - Parent directory checked for an existing install (default: /Applications) +# +# Exit codes: +# 0 - Google Drive installed successfully (or already present and ForceReinstall=False) +# 1 - Fatal error (download failure, mount failure, PKG install failure, etc.) +# +# Tested on: macOS (Apple Silicon + Intel) +# Requires: curl, hdiutil, installer (all available by default on macOS) + +DownloadUrl="https://dl.google.com/drive-file-stream/GoogleDrive.dmg" +ForceReinstall="False" # Set to "True" to reinstall even if already present +AppName="Google Drive.app" +InstallPath="/Applications" + +# ── Logging ────────────────────────────────────────────────── +log() { echo "[INFO] $*"; } +warn() { echo "[WARN] $*"; } + +abort() { + echo "[ERROR] $*" + [[ -n "$DMGMountPoint" ]] && { hdiutil detach "$DMGMountPoint" -quiet 2>/dev/null; log "Detached DMG volume"; } + [[ -d "$TempFolder" ]] && { rm -rf "$TempFolder"; log "Cleaned up $TempFolder"; } + exit 1 +} + +# ── Existing install check ──────────────────────────────────── +if [[ -d "$InstallPath/$AppName" ]]; then + if [[ "$ForceReinstall" != "True" ]]; then + log "Google Drive is already installed. Set ForceReinstall=True to reinstall." + exit 0 + else + warn "ForceReinstall=True — proceeding with reinstall" + fi +fi + +# ── Download ────────────────────────────────────────────────── +TempFolder=$(mktemp -d) || abort "Failed to create temp folder" +log "Temp folder created: $TempFolder" + +log "Downloading Google Drive DMG..." +curl -sL "$DownloadUrl" -o "$TempFolder/GoogleDrive.dmg" || abort "Download failed" +log "Download complete" + +# ── Mount DMG ───────────────────────────────────────────────── +log "Mounting DMG..." +hdiutilOutput=$(hdiutil attach "$TempFolder/GoogleDrive.dmg" -nobrowse 2>&1) +[[ $? -ne 0 ]] && abort "hdiutil attach failed: $hdiutilOutput" + +DMGVolume=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $NF}' | tail -1 | sed 's/[[:space:]]*$//') +[[ -d "$DMGVolume" ]] || abort "Could not locate mounted DMG volume. hdiutil output: $hdiutilOutput" +log "Mounted volume: $DMGVolume" + +DMGMountPoint=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $1}' | tail -1 | sed 's/[[:space:]]*$//') +log "Mount point: $DMGMountPoint" + +# ── Find PKG inside DMG ─────────────────────────────────────── +DMGPkgPath=$(find "$DMGVolume" -maxdepth 1 -name "*.pkg" | head -1) +[[ -n "$DMGPkgPath" ]] || abort "No PKG found inside $DMGVolume" +log "Found PKG: $DMGPkgPath" + +# ── Install PKG ─────────────────────────────────────────────── +log "Installing Google Drive..." +installer -pkg "$DMGPkgPath" -target / -verboseR +[[ $? -ne 0 ]] && abort "PKG installation failed" +log "Google Drive installed successfully" + +# ── Cleanup ─────────────────────────────────────────────────── +hdiutil detach "$DMGMountPoint" -quiet +log "Detached DMG volume" +rm -rf "$TempFolder" +log "Cleaned up temp folder" + +log "Installation complete." +exit 0 \ No newline at end of file diff --git a/scripts_staging/macos_Visual_Studio_Code_Install.sh b/scripts_staging/macos_Visual_Studio_Code_Install.sh new file mode 100644 index 00000000..390ca58f --- /dev/null +++ b/scripts_staging/macos_Visual_Studio_Code_Install.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# +# Description: Installs Visual Studio Code on macOS via the official Microsoft DMG. +# Automatically selects the correct DMG for the machine's CPU architecture: +# ARM64 (Apple Silicon), x86_64 (Intel), or universal as a fallback. +# The download URL is a redirect link; the script follows HTTP redirects +# to resolve the final DMG location before downloading. Once downloaded, +# it mounts the DMG, locates the .app bundle inside, and copies it to +# /Applications. Cleans up the temp download and unmounts the DMG when done. +# +# Configurable variables (edit at the top of the script or pass via RMM): +# ForceReinstall - Set to "True" to remove and reinstall if VS Code is already present +# +# Exit codes: +# 0 - VS Code installed successfully (or already present and ForceReinstall=False) +# 1 - Fatal error (URL resolution failure, download failure, mount failure, copy failure, etc.) +# +# Tested on: macOS Apple Silicon (ARM64) and Intel (x86_64) +# Requires: curl, hdiutil, uname (all available by default on macOS) + +ForceReinstall="False" # Set to "True" to reinstall even if already present + +# ── Logging ────────────────────────────────────────────────── +log() { echo "[INFO] $*"; } +warn() { echo "[WARN] $*"; } + +# ── Select architecture-appropriate download URL ────────────── +Arch=$(uname -m) +case "$Arch" in + arm64) + DownloadUrl="https://code.visualstudio.com/sha/download?build=stable&os=darwin-arm64-dmg" + log "Detected Apple Silicon (arm64)" + ;; + x86_64) + DownloadUrl="https://code.visualstudio.com/sha/download?build=stable&os=darwin-x64-dmg" + log "Detected Intel (x86_64)" + ;; + *) + DownloadUrl="https://code.visualstudio.com/sha/download?build=stable&os=darwin-universal-dmg" + warn "Unknown architecture '$Arch' — falling back to universal DMG" + ;; +esac + +abort() { + echo "[ERROR] $*" + [[ -n "$DMGMountPoint" ]] && { hdiutil detach "$DMGMountPoint" -quiet 2>/dev/null; log "Detached DMG volume"; } + [[ -d "$TempFolder" ]] && { rm -rf "$TempFolder"; log "Cleaned up $TempFolder"; } + exit 1 +} + +# ── Resolve Final Download URL ──────────────────────────────── +log "Resolving download URL: $DownloadUrl" +if [[ "$DownloadUrl" == *".dmg"* ]]; then + log "Direct download link detected" + ResolvedUrl="$DownloadUrl" +else + log "Following redirects to find final DMG URL..." + ResolvedUrl=$(curl -sIL "$DownloadUrl" | grep -i "^location:" | tail -1 | awk '{print $2}' | tr -d '[:space:]') + [[ "$ResolvedUrl" == *".dmg"* ]] || abort "Could not resolve a .dmg URL from headers. Got: $ResolvedUrl" + log "Resolved URL: $ResolvedUrl" +fi + +# ── Download ────────────────────────────────────────────────── +TempFolder=$(mktemp -d) || abort "Failed to create temp folder" +log "Temp folder created: $TempFolder" + +log "Downloading Visual Studio Code DMG..." +curl -sL "$ResolvedUrl" -o "$TempFolder/VSCode.dmg" || abort "Download failed" +log "Download complete" + +# ── Mount DMG ───────────────────────────────────────────────── +log "Mounting DMG..." +hdiutilOutput=$(hdiutil attach "$TempFolder/VSCode.dmg" -nobrowse 2>&1) +[[ $? -ne 0 ]] && abort "hdiutil attach failed: $hdiutilOutput" + +DMGVolume=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $NF}' | tail -1 | sed 's/[[:space:]]*$//') +[[ -d "$DMGVolume" ]] || abort "Could not locate mounted DMG volume. hdiutil output: $hdiutilOutput" +log "Mounted volume: $DMGVolume" + +DMGMountPoint=$(echo "$hdiutilOutput" | grep '/Volumes/' | awk -F'\t' '{print $1}' | tail -1 | sed 's/[[:space:]]*$//') +log "Mount point: $DMGMountPoint" + +# ── Find .app inside DMG ────────────────────────────────────── +DMGAppPath=$(find "$DMGVolume" -maxdepth 1 -name "*.app" | head -1) +[[ -n "$DMGAppPath" ]] || abort "No .app bundle found in $DMGVolume" +AppName=$(basename "$DMGAppPath") +log "Found app: $AppName" + +# ── Check for existing install ──────────────────────────────── +if [[ -d "/Applications/$AppName" ]]; then + if [[ "$ForceReinstall" == "True" ]]; then + warn "$AppName already installed — removing for reinstall" + rm -rf "/Applications/$AppName" || abort "Could not remove existing $AppName" + else + warn "$AppName is already installed. Set ForceReinstall=True to reinstall." + hdiutil detach "$DMGMountPoint" -quiet + rm -rf "$TempFolder" + exit 0 + fi +fi + +# ── Install ─────────────────────────────────────────────────── +log "Installing $AppName to /Applications..." +cp -pPR "$DMGAppPath" /Applications/ || abort "Failed to copy $AppName to /Applications" +log "Visual Studio Code installed successfully" + +# ── Cleanup ─────────────────────────────────────────────────── +hdiutil detach "$DMGMountPoint" -quiet +log "Detached DMG volume" +rm -rf "$TempFolder" +log "Cleaned up temp folder" + +log "Installation complete." +exit 0 \ No newline at end of file