Skip to content

Instantly share code, notes, and snippets.

@perlmunger
Last active September 13, 2023 13:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save perlmunger/43bdd94a9be471313bd6662b1894b276 to your computer and use it in GitHub Desktop.
Save perlmunger/43bdd94a9be471313bd6662b1894b276 to your computer and use it in GitHub Desktop.
Display iOS Provisioning Profile (.mobileprovision) Details With Command Line Ruby Utility
#!/usr/bin/env ruby
# -----------------------------------------------------
# Usage: profname.rb /path/to/profiles/directory
# If no arguments are passed in, the default provisioning profiles directory
# on macOS is used: ~/Library/MobileDevice/Provisioning Profiles
#
# Script expects a directory, not a single file. Use grep on the command
# line to locate specific details.
# -----------------------------------------------------
require 'nokogiri'
# Function to grab values from the provisioing profile via Xpath
# Ref: Got this from https://gist.github.com/pdsarin/5377836 . Modified
# it to take a file handle instead of a file path so the file doesn't
# get opened/closed on every property access
def profile_value(profile_contents, name)
profile_contents = profile_contents.slice(profile_contents.index('<?'), profile_contents.length)
doc = Nokogiri.XML(profile_contents)
return doc.xpath('//key[text()="' + name + '"]')[0].next_element.text
end
if ARGV.count <= 0
# Go for the default if they don't specify a directory
directory = "#{Dir.home}/Library/MobileDevice/Provisioning Profiles/"
else
directory = ARGV[0]
end
# Only grab mobileprovision files
profile_glob = "#{directory}*.mobileprovision"
profiles = Array.new()
Dir.glob(profile_glob) {|filename|
contents = File.open(filename).read
profile_name = profile_value(contents, "Name")
uuid = profile_value(contents, "UUID")
expiration = profile_value(contents, "ExpirationDate")
identifier = profile_value(contents, "application-identifier")
file = File.basename(filename, ".mobileprovision")
profile = { profile_name: profile_name, uuid: uuid, expiration: expiration, identifier: identifier, file: file }
# Append everything to an array so we can dynamically calcualate
# column lengths for columner command line output
profiles << profile
}
# Calculate max lengths for command line column output
profile_name_length = profiles.map { |p| p[:profile_name].length }.max
uuid_length = profiles.map { |p| p[:uuid].length }.max
expiration_length = profiles.map { |p| p[:expiration].length }.max
identifier_length = profiles.map { |p| p[:identifier].length }.max
file_length = profiles.map { |p| p[:file].length }.max
# Print a header
printf "%-#{uuid_length}s %-#{identifier_length}s %-#{file_length}s %-#{profile_name_length}s %s\n", "-" * uuid_length, "-" * identifier_length, "-" * file_length, "-" * profile_name_length, "-" * expiration_length
printf "%-#{uuid_length}s %-#{identifier_length}s %-#{file_length}s %-#{profile_name_length}s %s\n", "UUID", "|App Identifier", "|Filename", "|Name", "|Expiration"
printf "%-#{uuid_length}s %-#{identifier_length}s %-#{file_length}s %-#{profile_name_length}s %s\n", "-" * uuid_length, "-" * identifier_length, "-" * file_length, "-" * profile_name_length, "-" * expiration_length
# Print profile details
profiles.each do |profile|
printf "%-#{uuid_length}s %-#{identifier_length}s %-#{file_length}s %-#{profile_name_length}s %s\n", profile[:uuid], profile[:identifier], profile[:file], profile[:profile_name], profile[:expiration]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment