Compare commits

...

27 Commits
v26.0 ... main

Author SHA1 Message Date
Graham Pugh
e6371c1852 Merge branch 'munki-main' 2025-08-21 12:48:20 +02:00
Graham Pugh
4410b44f7b Merge branch 'main' of https://github.com/munki/macadmin-scripts into munki-main 2025-08-21 12:47:49 +02:00
Greg Neagle
522fc7ff40 Workaround for issue with installer in macOS 15.6 2025-08-20 13:55:28 -07:00
Greg Neagle
2cc8b89920
Update README.md 2025-07-12 06:28:47 -07:00
Greg Neagle
a66413ec7e
Update README.md 2025-07-12 06:27:32 -07:00
Greg Neagle
85c643e684 macOS 26 updates 2025-06-24 09:52:55 -07:00
Graham Pugh
b2570b4b0d add beta catalog for macOS 26 2025-06-11 20:11:14 +02:00
Graham Pugh
eabf751816
Merge pull request #57 from PeterSuh-Q3/patch-1
Add Sequoia catalog.
2024-11-18 09:47:41 +01:00
Peter Suh
73d7b90c7d
Add Sequoia catalog. 2024-11-18 15:10:56 +09:00
Greg Neagle
77e507e435
Add Sequoia sucatalog URL 2024-09-18 08:45:38 -07:00
Greg Neagle
ba1eeab9d0 Add munki_bundle_pkg_finder script 2024-06-18 13:42:17 -07:00
Greg Neagle
1fc3224198 Add default catalog URL for Sonoma 2023-10-10 11:34:57 -07:00
Graham Pugh
0ea9dc5a6a
Merge pull request #55 from jthat/sonoma-catalog 2023-10-01 12:53:31 +02:00
Jason Thatcher
ca280304c0 Add Sonoma catalog 2023-10-01 20:30:28 +10:00
scheblein
944a01cb06
Update installinstallmacos.py (#115)
added catalog url for Ventura
2023-07-07 11:32:59 -07:00
Graham Pugh (iMac Pro)
ad107a5593 revert to distutils for py<=3.9 2023-01-24 21:33:44 +01:00
Graham Pugh (iMac Pro)
074c1a5d7b account for older python 2023-01-24 21:20:34 +01:00
Graham Pugh (iMac Pro)
4c4bdd8671 list shows latest version 2023-01-24 20:32:28 +01:00
Graham Pugh (iMac Pro)
f2e9a63872 use packaging.version.LegacyVersion 2023-01-24 20:24:15 +01:00
Graham Pugh
bd9205bde0
Merge pull request #51 from grahampugh/27.1
ventura catalog
2022-10-25 00:17:54 +01:00
Graham Pugh
55e6345d5c ventura catalog 2022-10-24 23:49:53 +01:00
Greg Neagle
a8a6f150c8 Python 3 fix for setting Seed Program xattr. 2022-04-05 10:42:52 -07:00
Greg Neagle
854798a010
Update README.md 2022-03-14 15:26:12 -07:00
Graham Pugh
ed6654e778 switch to pkg_resources 2022-03-09 19:25:36 +01:00
Graham Pugh
69ee37ae4e
Merge pull request #48 from grahampugh/dev-packaging
Allow for removal of distutils in a future python
2022-03-08 15:13:10 +01:00
Graham Pugh
8b2f2c58b9 Allow for removal of distutils in a future python 2022-03-08 15:11:59 +01:00
Graham Pugh
d77936d477
Merge pull request #46 from grahampugh/dev
Dev
2022-03-07 23:02:50 +01:00
3 changed files with 136 additions and 19 deletions

View File

@ -3,9 +3,9 @@
Some scripts that might be of use to macOS admins. Might be related to Munki;
might not.
These are currently only supported using Apple's Python on macOS. There is no support for running these on Windows or Linux.
These are only supported on macOS. There is no support for running these on Windows or Linux.
In macOS 12.3, Apple will be removing its Python 2.7 install. You'll need to provide your own Python to use these scripts. You may also need to install additional Python modules.
In macOS 12.3, Apple stopped providung Python as part of macOS. You'll need to provide your own Python to use these scripts. You may also need to install additional Python modules.
#### getmacosipsws.py
@ -39,7 +39,7 @@ Product installation failed.
Use a compatible Mac or select a different build compatible with your current hardware and try again. You may also have success running the script in a VM; the InstallationCheck script in versions of the macOS installer to date skips the checks (and returns success) when run on a VM.
##### Important note for Catalina+
Catalina privacy protections might interfere with the operation of this tool if you run it from ~/Desktop, ~/Documents, ~/Downloads or other directories protected in Catalina. Consider using /Users/Shared (or subdirectory) as the "working space" for this tool.
macOS privacy protections might interfere with the operation of this tool if you run it from ~/Desktop, ~/Documents, ~/Downloads or other directories protected in macOS Catalina or later. Consider using /Users/Shared (or subdirectory) as the "working space" for this tool.
##### Alternate implementations

View File

@ -42,7 +42,12 @@ except ImportError:
from urlparse import urlsplit
from xml.dom import minidom
from xml.parsers.expat import ExpatError
from distutils.version import LooseVersion
try:
from packaging.version import LegacyVersion
except ImportError:
# python <=3.9
from distutils.version import LooseVersion as LegacyVersion
try:
import xattr
@ -80,6 +85,38 @@ DEFAULT_SUCATALOGS = {
"index-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"22": (
"https://swscan.apple.com/content/catalogs/others/"
"index-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"23": (
"https://swscan.apple.com/content/catalogs/others/"
"index-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"24": (
"https://swscan.apple.com/content/catalogs/others/"
"index-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"25": (
"https://swscan.apple.com/content/catalogs/others/"
"index-16seed-16-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog"
),
"22": "https://swscan.apple.com/content/catalogs/others/"
"index-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
"23": "https://swscan.apple.com/content/catalogs/others/"
"index-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
"24": "https://swscan.apple.com/content/catalogs/others/"
"index-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
"25": "https://swscan.apple.com/content/catalogs/others/"
"index-26-15-14-13-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9"
"-mountainlion-lion-snowleopard-leopard.merged-1.sucatalog",
}
SEED_CATALOGS_PLIST = (
@ -260,11 +297,12 @@ def get_default_catalog(darwin_major=None):
def make_sparse_image(volume_name, output_path):
"""Make a sparse disk image we can install a product to"""
# note: for macOS 26 Tahoe we needed to increase the size
cmd = [
"/usr/bin/hdiutil",
"create",
"-size",
"16g",
"20g",
"-fs",
"HFS+",
"-volname",
@ -374,7 +412,12 @@ def install_product(dist_path, target_vol):
# set CM_BUILD env var to make Installer bypass eligibilty checks
# when installing packages (for machine-specific OS builds)
os.environ["CM_BUILD"] = "CM_BUILD"
cmd = ["/usr/sbin/installer", "-pkg", dist_path, "-target", target_vol]
# cmd = ['/usr/sbin/installer', '-pkg', dist_path, '-target', target_vol]
# a hack to work around a change in macOS 15.6+ since installing a .dist
# file no longer works
dist_dir = os.path.dirname(dist_path)
install_asst_pkg = os.path.join(dist_dir, "InstallAssistant.pkg")
cmd = ["/usr/sbin/installer", "-pkg", install_asst_pkg, "-target", target_vol]
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError as err:
@ -698,7 +741,7 @@ def os_installer_product_info(
def get_latest_version(current_item, latest_item):
"""Compares versions between two values and returns the latest (highest) value"""
try:
if LooseVersion(current_item) > LooseVersion(latest_item):
if LegacyVersion(current_item) > LegacyVersion(latest_item):
return current_item
else:
return latest_item
@ -1062,7 +1105,7 @@ def main():
# determine the latest valid build ID and select this
# when using auto, os and version options
if args.auto or args.version or args.os:
if args.auto or args.version or args.os or args.list:
if args.beta or "Beta" not in product_info[product_id]["title"]:
try:
latest_valid_build
@ -1132,10 +1175,10 @@ def main():
valid_build_found is False
and not args.build
and not args.current
and not args.validate
and args.validate
and not args.list
):
print("No valid build found for this hardware")
print("No valid build found for this computer")
exit(0)
# clear content directory in workdir if requested
@ -1147,6 +1190,18 @@ def main():
# Output a plist of available updates and quit if list option chosen
if args.list:
if args.os:
print("\nBuild checked against OS filter: %s" % (args.os))
pl["validity_filter"] = "OS: %s" % (args.os)
elif args.version:
print("\nBuild checked against version filter: %s" % (args.version))
pl["validity_filter"] = "Version: %s" % (args.version)
try:
print("\nLatest valid build: %s (# %s)" % (latest_valid_build, answer))
pl["latest_valid_build"] = latest_valid_build
except NameError:
pl["latest_valid_build"] = ""
print("\nNo valid build found")
write_plist(pl, output_plist)
print("\nValid seeding programs are: %s\n" % ", ".join(get_seeding_programs()))
exit(0)
@ -1158,23 +1213,21 @@ def main():
except NameError:
print(
"\n"
"Build %s is not available. "
"A valid installer for build %s is not available for this computer. "
"Run again without --build argument "
"to select a valid build to download "
"or run without --validate option to download anyway.\n" % args.build
)
exit(0)
else:
print(
"\n" "Build %s available. Downloading #%s...\n" % (args.build, answer)
)
print("\n" "Build %s valid. Downloading #%s...\n" % (args.build, answer))
elif args.current:
try:
answer
except NameError:
print(
"\n"
"Build %s is not available. "
"A valid installer for build %s is not available for this computer. "
"Run again without --current argument "
"to select a valid build to download.\n" % build_info[0]
)
@ -1222,7 +1275,7 @@ def main():
except NameError:
print(
"\n"
"Version %s is not available. "
"A valid installer for version %s is not available for this computer. "
"Run again without --version argument "
"to select a valid build to download.\n" % args.version
)
@ -1238,7 +1291,7 @@ def main():
except NameError:
print(
"\n"
"OS %s is not available. "
"A valid installer for OS %s is not available for this computer. "
"Run again without --os argument "
"to select a valid build to download.\n" % args.os
)
@ -1254,7 +1307,7 @@ def main():
except NameError:
print(
"\n"
"No valid version available. "
"No valid version available for this computer. "
"Run again without --auto argument "
"to select a valid build to download.\n"
)
@ -1344,7 +1397,9 @@ def main():
% seeding_program
)
xattr.setxattr(
installer_app, "SeedProgram", seeding_program.encode()
installer_app,
"SeedProgram",
seeding_program.encode("UTF-8").encode(),
)
print("Product downloaded and installed to %s" % sparse_diskimage_path)
if args.raw:

62
munki_bundle_pkg_finder.py Executable file
View File

@ -0,0 +1,62 @@
#!/usr/local/munki/munki-python
import os
import plistlib
import sys
sys.path.append("/usr/local/munki")
from munkilib import dmgutils
from munkilib import pkgutils
if len(sys.argv) != 2:
print('Need exactly one parameter: path to a munki repo!', file=sys.stderr)
sys.exit(-1)
repo_path = sys.argv[1]
all_catalog = os.path.join(repo_path, "catalogs/all")
with open(all_catalog, mode="rb") as FILE:
all_items = plistlib.load(FILE)
dmg_items = [{"name": item["name"],
"version": item["version"],
"location": item["installer_item_location"],
"package_path": item.get("package_path", "")}
for item in all_items
if item.get("installer_item_location", "").endswith(".dmg") and
item.get("installer_type") is None]
items_with_bundle_style_pkgs = []
for item in dmg_items:
full_path = os.path.join(repo_path, "pkgs", item["location"])
print("Checking %s..." % full_path)
mountpoints = dmgutils.mountdmg(full_path)
if mountpoints:
pkg_path = item["package_path"]
if pkg_path:
itempath = os.path.join(mountpoints[0], pkg_path)
if os.path.isdir(itempath):
print("***** %s--%s has a bundle-style pkg"
% (item["name"], item["version"]))
items_with_bundle_style_pkgs.append(item)
else:
for file_item in os.listdir(mountpoints[0]):
if pkgutils.hasValidInstallerItemExt(file_item):
itempath = os.path.join(mountpoints[0], file_item)
if os.path.isdir(itempath):
print("***** %s--%s has a bundle-style pkg"
% (item["name"], item["version"]))
items_with_bundle_style_pkgs.append(item)
break
dmgutils.unmountdmg(mountpoints[0])
else:
print("No filesystems mounted from %s" % full_path)
continue
print("Found %s items with bundle-style pkgs."
% len(items_with_bundle_style_pkgs))
for item in sorted(items_with_bundle_style_pkgs, key=lambda d: d["name"]):
print("%s--%s"% (item["name"], item["version"]))
print(" %s" % item["location"])