When Apple release software updates for their device devices, which will include both macOS and iOS This is obviously well covered by websites that are third-party to Apple.
Apple being in Cupertino, California Will release their updates at a certain time and depending on the time zone you are in will depend on when you get the update - being in the UK that is usually 6 PM.
This will end you giving a notification as an example like this:
Apple Update Site
This will end you giving a notification as an example like this:
Apple Update Site
Apple also have a support site that lists their latest versions of both iOS and macOS, but sometimes these releases incorporations can be missed, When Apple releasing update every device whether it’s managed or not will start downloading that software update.
Software updates - Internet saturation
That update can in turn, depending on the density of your office or work environment, can cause quite a few network problems, depending on your bandwidth allocation - for example, one phone trying to download a 3 GB file is not a problem for many Wi-Fi networks, However, 1500 phones all individually downloading the same iOS upgrade can be a problem.
This is where a Mac content caching server can save the bandwidth to the Internet - but how does this work?
MacOS : The the rescue 🛟
Well, it’s quite simple you place the Mac device on the same network as your clients then when those clients request a upgrade, they will talk to the Mac device if it’s properly registered and activated, then the Mac will go to the Internet on behalf of your device and download the updates with your device until it’s successfully been cached.
This means the first download of that update will go at your native Internet speed however once successfully downloaded all future downloads will not use the Internet, but the Mac to deliver that iOS update.
Managing bandwidth with new software updates 🤨
The theory behind this is very simple, However, you need to remember that you need either an iOS or macOS device for this to work.
When the new software update is released, which I’ve mentioned is usually 6 PM in the UK, but this is not a hard and fast rule, the website that lists all the latest versions of iOS macOS will be updated.
Prepare the Mac with the software update
When the new iOS or macOS version is released you need to ensure that out of business hours the Mac with its very capable content caching successfully downloads that update, this means the update will be local to the Mac device.
If this operation is completed before business hours, when people arrive at your dens office, they will talk to the Mac instead of the Internet, saving your Internet bandwidth from becoming saturated.
macOS/iOS notification email
I would rather not rely on speculations about when these upgrades are coming out, but refer to the official Apple website, which will be updated once that new OTA update is live.
Yes, you could easily go to the official Apple website and check it yourself, but that relies on a very human element, and sometimes humans forget.
This is where I have a script that regularly monitors this website as much as required to check for updates to iOS or macOS and if an updated detected it will send you an email, I have separated the iOS emails from the macOS emails as they can independently of each other.
The script will also record the last version in a JSON file so if nothings been updated, you won’t get any emails, however, if a new version is detected, it will send you an email then update that JSON file to reflect those new values.
You can update all the options in bold, I have the option for a image with the e-mails for a Mac or iPhone that is a "png" file which you can choose to use or not.
Script : iOSChecker.ps1
# Apple OS Version Checker
# This script checks for new versions of iOS and macOS and sends email notifications
# Get the script's directory
$scriptPath = $PSScriptRoot
if (!$scriptPath) {
$scriptPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition
}
# Email configuration
$emailConfig = @{
From = "Apple.Updates@croucher.cloud"
To = "lee@croucher.cloud"
SMTPServer = "smtp.bear.local"
Port = 587
UseSSL = $True
UseCredentials = $false
Username = "username"
Password = "password"
}
# File to store previous versions
$versionFile = "previous_versions.json"
# Function to get iOS version
function Get-iOSVersion {
try {
$response = Invoke-WebRequest -Uri "https://support.apple.com/en-us/HT201222" -UseBasicParsing
$content = $response.Content
if ($content -match "iOS\s+(\d+\.\d+\.?\d*)\s+(?!beta|RC)") {
$version = $matches[1]
if ($version -notmatch "beta|rc|dev" -and $version.Length -lt 10) {
return $version
}
}
Write-Warning "Could not find production iOS version"
return $null
}
catch {
Write-Error "Error getting iOS version: $_"
return $null
}
}
# Function to get macOS version
function Get-MacOSVersion {
try {
$response = Invoke-WebRequest -Uri "https://support.apple.com/en-us/HT201260" -UseBasicParsing
$content = $response.Content
if ($content -match "macOS\s+[\w\s]+?(\d+\.\d+\.?\d*)") {
$version = $matches[1]
if ($version -notmatch "beta|rc|dev" -and $version.Length -lt 10) {
return $version
}
}
Write-Warning "Could not find production macOS version"
return $null
}
catch {
Write-Error "Error getting macOS version: $_"
return $null
}
}
# Function to convert image to Base64
function Get-Base64Image {
param (
[string]$ImagePath
)
try {
$fullPath = Join-Path -Path $scriptPath -ChildPath $ImagePath
if (Test-Path $fullPath) {
$imageBytes = [System.IO.File]::ReadAllBytes($fullPath)
$base64String = [System.Convert]::ToBase64String($imageBytes)
$imageExtension = [System.IO.Path]::GetExtension($ImagePath).TrimStart('.')
return "data:image/$imageExtension;base64,$base64String"
} else {
Write-Warning "Image file not found: $fullPath"
return $null
}
}
catch {
Write-Error "Error processing image: $_"
return $null
}
}
# Function to send email notification
function Send-VersionNotification {
param (
[string]$OS,
[string]$Version
)
Write-Host "Debug: OS=$OS, Version=$Version" -ForegroundColor Cyan
# Early validation
if ([string]::IsNullOrWhiteSpace($OS) -or [string]::IsNullOrWhiteSpace($Version)) {
Write-Error "OS or Version is empty. OS='$OS', Version='$Version'"
return
}
# Get icon based on OS type
$iconPath = if ($OS -eq "iOS") { "iPhone-Icon.png" } else { "Macbook-icon.png" }
$iconBase64 = Get-Base64Image -ImagePath $iconPath
$iconHtml = if ($iconBase64) {
"<img src='$iconBase64' alt='$OS Icon' style='width: 64px; height: 64px; margin-bottom: 15px;'>"
} else {
""
}
try {
$mailParams = @{
From = $emailConfig.From
To = $emailConfig.To
Subject = "$OS Version $Version Now Available"
SmtpServer = $emailConfig.SMTPServer
Port = $emailConfig.Port
BodyAsHtml = $true
}
# HTML Email Template
$mailParams.Body = @"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Apple OS Update Notification</title>
</head>
<body style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; margin: 0; padding: 0; background-color: #f5f5f7;">
<table width="100%" cellpadding="0" cellspacing="0" style="max-width: 600px; margin: 0 auto; padding: 20px;">
<tr>
<td style="background-color: white; border-radius: 16px; padding: 30px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
<!-- Header -->
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding-bottom: 25px;">
$iconHtml
<h1 style="color: #1d1d1f; font-size: 24px; margin: 0; font-weight: 600;">New Update Available</h1>
<p style="color: #86868b; margin-top: 8px; font-size: 14px;">$(Get-Date -Format "MMMM dd, yyyy")</p>
</td>
</tr>
</table>
<!-- Update Card -->
<table width="100%" cellpadding="0" cellspacing="0" style="background-color: #f5f5f7; border-radius: 12px; margin-bottom: 20px;">
<tr>
<td style="padding: 25px;">
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td style="padding-bottom: 20px;">
<h2 style="margin: 0; color: #1d1d1f; font-size: 28px; font-weight: 600;">$OS</h2>
</td>
</tr>
<tr>
<td>
<p style="color: #1d1d1f; font-size: 42px; margin: 0; font-weight: 700;">Version $Version</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- Warning Card -->
<table width="100%" cellpadding="0" cellspacing="0" style="background-color: #fff1f0; border: 1px solid #ffa39e; border-radius: 12px; margin-bottom: 20px;">
<tr>
<td style="padding: 20px;">
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td style="padding-bottom: 10px;">
<span style="background-color: #ff4d4f; color: white; padding: 4px 12px; border-radius: 4px; font-size: 14px; font-weight: 500;">WARNING</span>
</td>
</tr>
<tr>
<td>
<p style="color: #434343; margin: 0; font-size: 14px; line-height: 1.5;">If you have a Mac caching server remember you have to download this update on the same network as this device before it can cache it so it can serve it to other clients on your network to save your bandwidth.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- Footer -->
<table width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center" style="padding-top: 20px; border-top: 1px solid #e5e5e7;">
<p style="color: #86868b; font-size: 12px; margin: 0;">This is an automated notification from your Apple Version Checker</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
"@
# Add SSL if configured
if ($emailConfig.UseSSL) {
$mailParams.Add("UseSsl", $true)
}
# Add credentials if configured
if ($emailConfig.UseCredentials) {
$securePassword = ConvertTo-SecureString $emailConfig.Password -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential($emailConfig.Username, $securePassword)
$mailParams.Add("Credential", $credentials)
}
Write-Host "Sending email notification for $OS version $Version..." -NoNewline
Send-MailMessage @mailParams
Write-Host "Done!" -ForegroundColor Green
}
catch {
Write-Error "Error sending email notification: $_"
}
}
# Function to load previous versions
function Get-PreviousVersions {
if (Test-Path $versionFile) {
try {
return Get-Content $versionFile | ConvertFrom-Json
}
catch {
Write-Warning "Error reading previous versions file. Creating new one."
return @{
iOS = ""
macOS = ""
}
}
}
else {
return @{
iOS = ""
macOS = ""
}
}
}
# Function to save versions
function Save-Versions {
param (
[string]$iOSVersion,
[string]$macOSVersion
)
$versions = @{
iOS = $iOSVersion
macOS = $macOSVersion
}
$versions | ConvertTo-Json | Set-Content $versionFile
}
# Main script
try {
Write-Host "`n=== Apple Version Checker ===`n" -ForegroundColor Cyan
# Get previous versions
$previousVersions = Get-PreviousVersions
# Get current versions
Write-Host "Checking for iOS version..." -NoNewline
$currentiOS = Get-iOSVersion
if ($currentiOS) {
Write-Host " Found: $currentiOS" -ForegroundColor Green
} else {
Write-Host " Not found" -ForegroundColor Red
}
Write-Host "Checking for macOS version..." -NoNewline
$currentMacOS = Get-MacOSVersion
if ($currentMacOS) {
Write-Host " Found: $currentMacOS" -ForegroundColor Green
} else {
Write-Host " Not found" -ForegroundColor Red
}
# Debug output
Write-Host "`nPrevious versions:" -ForegroundColor Cyan
Write-Host "iOS: $($previousVersions.iOS)"
Write-Host "macOS: $($previousVersions.macOS)"
# Check for new iOS version
if ($currentiOS -and ($currentiOS -ne $previousVersions.iOS)) {
Write-Host "`nNew iOS version detected: $currentiOS" -ForegroundColor Yellow
Send-VersionNotification -OS "iOS" -Version $currentiOS
}
# Check for new macOS version
if ($currentMacOS -and ($currentMacOS -ne $previousVersions.macOS)) {
Write-Host "`nNew macOS version detected: $currentMacOS" -ForegroundColor Yellow
Send-VersionNotification -OS "macOS" -Version $currentMacOS
}
# Save current versions
if ($currentiOS -or $currentMacOS) {
Save-Versions -iOSVersion $currentiOS -macOSVersion $currentMacOS
}
Write-Host "`nScript completed successfully" -ForegroundColor Green
}
catch {
Write-Error "Error in main script execution: $_"
}
The folder should look like this after the script is run:
The previous_versions.json will track the current releases for iOS and MacOS as below, this will be dynamically updated on the next run of the script:
When run if not changes are detected as below then you will see the version and the script will terminate without an email, an email is only sent when changes are detected.
The previous_versions.json will track the current releases for iOS and MacOS as below, this will be dynamically updated on the next run of the script:
{
"macOS": "10.15",
"iOS": "18.2.1"
}