Compare commits

..

No commits in common. "main" and "v26.2" have entirely different histories.
main ... v26.2

3 changed files with 9 additions and 127 deletions

View File

@ -3,9 +3,9 @@
Some scripts that might be of use to macOS admins. Might be related to Munki; Some scripts that might be of use to macOS admins. Might be related to Munki;
might not. might not.
These are only supported on macOS. There is no support for running these on Windows or Linux. These are currently only supported using Apple's Python on macOS. There is no support for running these on Windows or Linux.
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. 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.
#### getmacosipsws.py #### 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. 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+ ##### Important note for Catalina+
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. 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.
##### Alternate implementations ##### Alternate implementations

View File

@ -43,11 +43,7 @@ except ImportError:
from xml.dom import minidom from xml.dom import minidom
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
try: from pkg_resources import parse_version as Version
from packaging.version import LegacyVersion
except ImportError:
# python <=3.9
from distutils.version import LooseVersion as LegacyVersion
try: try:
import xattr import xattr
@ -85,38 +81,6 @@ DEFAULT_SUCATALOGS = {
"index-12-10.16-10.15-10.14-10.13-10.12-10.11-10.10-10.9" "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" "-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 = ( SEED_CATALOGS_PLIST = (
@ -297,12 +261,11 @@ def get_default_catalog(darwin_major=None):
def make_sparse_image(volume_name, output_path): def make_sparse_image(volume_name, output_path):
"""Make a sparse disk image we can install a product to""" """Make a sparse disk image we can install a product to"""
# note: for macOS 26 Tahoe we needed to increase the size
cmd = [ cmd = [
"/usr/bin/hdiutil", "/usr/bin/hdiutil",
"create", "create",
"-size", "-size",
"20g", "16g",
"-fs", "-fs",
"HFS+", "HFS+",
"-volname", "-volname",
@ -412,12 +375,7 @@ def install_product(dist_path, target_vol):
# set CM_BUILD env var to make Installer bypass eligibilty checks # set CM_BUILD env var to make Installer bypass eligibilty checks
# when installing packages (for machine-specific OS builds) # when installing packages (for machine-specific OS builds)
os.environ["CM_BUILD"] = "CM_BUILD" 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: try:
subprocess.check_call(cmd) subprocess.check_call(cmd)
except subprocess.CalledProcessError as err: except subprocess.CalledProcessError as err:
@ -741,7 +699,7 @@ def os_installer_product_info(
def get_latest_version(current_item, latest_item): def get_latest_version(current_item, latest_item):
"""Compares versions between two values and returns the latest (highest) value""" """Compares versions between two values and returns the latest (highest) value"""
try: try:
if LegacyVersion(current_item) > LegacyVersion(latest_item): if Version(current_item) > Version(latest_item):
return current_item return current_item
else: else:
return latest_item return latest_item
@ -1105,7 +1063,7 @@ def main():
# determine the latest valid build ID and select this # determine the latest valid build ID and select this
# when using auto, os and version options # when using auto, os and version options
if args.auto or args.version or args.os or args.list: if args.auto or args.version or args.os:
if args.beta or "Beta" not in product_info[product_id]["title"]: if args.beta or "Beta" not in product_info[product_id]["title"]:
try: try:
latest_valid_build latest_valid_build
@ -1190,18 +1148,6 @@ def main():
# Output a plist of available updates and quit if list option chosen # Output a plist of available updates and quit if list option chosen
if args.list: 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) write_plist(pl, output_plist)
print("\nValid seeding programs are: %s\n" % ", ".join(get_seeding_programs())) print("\nValid seeding programs are: %s\n" % ", ".join(get_seeding_programs()))
exit(0) exit(0)
@ -1397,9 +1343,7 @@ def main():
% seeding_program % seeding_program
) )
xattr.setxattr( xattr.setxattr(
installer_app, installer_app, "SeedProgram", seeding_program.encode()
"SeedProgram",
seeding_program.encode("UTF-8").encode(),
) )
print("Product downloaded and installed to %s" % sparse_diskimage_path) print("Product downloaded and installed to %s" % sparse_diskimage_path)
if args.raw: if args.raw:

View File

@ -1,62 +0,0 @@
#!/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"])