ruby-jss 1.2.3 → 1.2.4a1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby-jss might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/jamf.rb +169 -0
- data/lib/jamf/api/abstract_classes/collection_resource.rb +422 -0
- data/lib/jamf/api/abstract_classes/generic_reference.rb +145 -0
- data/lib/jamf/api/abstract_classes/json_object.rb +1074 -0
- data/lib/jamf/api/abstract_classes/prestage.rb +219 -0
- data/lib/jamf/api/abstract_classes/prestage_skip_setup_items.rb +126 -0
- data/lib/jamf/api/abstract_classes/resource.rb +250 -0
- data/lib/jamf/api/abstract_classes/singleton_resource.rb +87 -0
- data/lib/jamf/api/attribute_classes/ip_address.rb +66 -0
- data/lib/jamf/api/attribute_classes/timestamp.rb +144 -0
- data/lib/jamf/api/connection.rb +734 -0
- data/lib/jamf/api/connection/api_error.rb +111 -0
- data/lib/jamf/api/connection/api_error_styleguide.rb +96 -0
- data/lib/jamf/api/connection/token.rb +220 -0
- data/lib/jamf/api/json_objects/account_prefs.rb +79 -0
- data/lib/jamf/api/json_objects/android_details.rb +139 -0
- data/lib/jamf/api/json_objects/appletv_details.rb +110 -0
- data/lib/jamf/api/json_objects/attachment.rb +68 -0
- data/lib/jamf/api/json_objects/cellular_network.rb +151 -0
- data/lib/jamf/api/json_objects/change_log_entry.rb +77 -0
- data/lib/jamf/api/json_objects/computer_prestage_skip_setup_items.rb +67 -0
- data/lib/jamf/api/json_objects/country.rb +51 -0
- data/lib/jamf/api/json_objects/extension_attribute_value.rb +128 -0
- data/lib/jamf/api/json_objects/installed_application.rb +59 -0
- data/lib/jamf/api/json_objects/installed_certificate.rb +53 -0
- data/lib/jamf/api/json_objects/installed_configuration_profile.rb +67 -0
- data/lib/jamf/api/json_objects/installed_ebook.rb +58 -0
- data/lib/jamf/api/json_objects/installed_provisioning_profile.rb +59 -0
- data/lib/jamf/api/json_objects/inventory_preload_extension_attribute.rb +52 -0
- data/lib/jamf/api/json_objects/ios_details.rb +244 -0
- data/lib/jamf/api/json_objects/location.rb +95 -0
- data/lib/jamf/api/json_objects/md_prestage_name.rb +57 -0
- data/lib/jamf/api/json_objects/md_prestage_names.rb +82 -0
- data/lib/jamf/api/json_objects/md_prestage_skip_setup_items.rb +165 -0
- data/lib/jamf/api/json_objects/mobile_device_details.rb +219 -0
- data/lib/jamf/api/json_objects/mobile_device_security.rb +101 -0
- data/lib/jamf/api/json_objects/prestage_assignment.rb +61 -0
- data/lib/jamf/api/json_objects/prestage_location.rb +104 -0
- data/lib/jamf/api/json_objects/prestage_purchasing_data.rb +132 -0
- data/lib/jamf/api/json_objects/prestage_scope.rb +54 -0
- data/lib/jamf/api/json_objects/prestage_sync_status.rb +63 -0
- data/lib/jamf/api/json_objects/purchasing_data.rb +125 -0
- data/lib/jamf/api/mixins/abstract.rb +58 -0
- data/lib/jamf/api/mixins/bulk_deletable.rb +39 -0
- data/lib/jamf/api/mixins/change_log.rb +136 -0
- data/lib/jamf/api/mixins/extendable.rb +75 -0
- data/lib/jamf/api/mixins/immutable.rb +39 -0
- data/lib/jamf/api/mixins/locatable.rb +124 -0
- data/lib/jamf/api/mixins/lockable.rb +48 -0
- data/lib/jamf/api/mixins/referable.rb +92 -0
- data/lib/jamf/api/mixins/searchable.rb +202 -0
- data/lib/jamf/api/mixins/uncreatable.rb +40 -0
- data/lib/jamf/api/mixins/undeletable.rb +40 -0
- data/lib/jamf/api/resources/collection_resources/account.rb +163 -0
- data/lib/jamf/api/resources/collection_resources/building.rb +114 -0
- data/lib/jamf/api/resources/collection_resources/category.rb +82 -0
- data/lib/jamf/api/resources/collection_resources/computer.rb +49 -0
- data/lib/jamf/api/resources/collection_resources/computer_prestage.rb +80 -0
- data/lib/jamf/api/resources/collection_resources/department.rb +79 -0
- data/lib/jamf/api/resources/collection_resources/extension_attribute.rb +45 -0
- data/lib/jamf/api/resources/collection_resources/inventory_preload_record.rb +274 -0
- data/lib/jamf/api/resources/collection_resources/md_prestage.rb +139 -0
- data/lib/jamf/api/resources/collection_resources/mobile_device.rb +315 -0
- data/lib/jamf/api/resources/collection_resources/script.rb +190 -0
- data/lib/jamf/api/resources/collection_resources/site.rb +77 -0
- data/lib/jamf/api/resources/singleton_resources/app_store_country_codes.rb +131 -0
- data/lib/jamf/api/resources/singleton_resources/authorization.rb +88 -0
- data/lib/jamf/api/resources/singleton_resources/client_checkin_settings.rb +139 -0
- data/lib/jamf/api/resources/singleton_resources/reenrollment_settings.rb +95 -0
- data/lib/jamf/client.rb +301 -0
- data/lib/jamf/client/jamf_binary.rb +132 -0
- data/lib/jamf/client/jamf_helper.rb +298 -0
- data/lib/jamf/client/management_action.rb +114 -0
- data/lib/jamf/compatibility.rb +88 -0
- data/lib/jamf/composer.rb +190 -0
- data/lib/jamf/configuration.rb +281 -0
- data/lib/jamf/exceptions.rb +107 -0
- data/lib/jamf/ruby_extensions.rb +36 -0
- data/lib/jamf/ruby_extensions/array.rb +35 -0
- data/lib/jamf/ruby_extensions/array/predicates.rb +46 -0
- data/lib/jamf/ruby_extensions/array/utils.rb +47 -0
- data/lib/jamf/ruby_extensions/filetest.rb +32 -0
- data/lib/jamf/ruby_extensions/filetest/predicates.rb +46 -0
- data/lib/jamf/ruby_extensions/hash.rb +33 -0
- data/lib/jamf/ruby_extensions/hash/backports.rb +92 -0
- data/lib/jamf/ruby_extensions/ipaddr.rb +37 -0
- data/lib/jamf/ruby_extensions/ipaddr/utils.rb +95 -0
- data/lib/jamf/ruby_extensions/object.rb +30 -0
- data/lib/jamf/ruby_extensions/object/predicates.rb +51 -0
- data/lib/jamf/ruby_extensions/pathname.rb +39 -0
- data/lib/jamf/ruby_extensions/pathname/predicates.rb +50 -0
- data/lib/jamf/ruby_extensions/pathname/utils.rb +75 -0
- data/lib/jamf/ruby_extensions/string.rb +35 -0
- data/lib/jamf/ruby_extensions/string/backports.rb +66 -0
- data/lib/jamf/ruby_extensions/string/conversions.rb +65 -0
- data/lib/jamf/ruby_extensions/string/predicates.rb +47 -0
- data/lib/jamf/utility.rb +423 -0
- data/lib/jamf/validate.rb +224 -0
- data/lib/jamf/version.rb +32 -0
- data/lib/jpapi.rb +26 -0
- data/lib/jss/version.rb +1 -1
- metadata +104 -4
@@ -0,0 +1,132 @@
|
|
1
|
+
### Copyright 2019 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
###
|
27
|
+
module JSS
|
28
|
+
|
29
|
+
#
|
30
|
+
class Client
|
31
|
+
|
32
|
+
# Constants
|
33
|
+
#####################################
|
34
|
+
|
35
|
+
# The Pathname to the jamf binary executable
|
36
|
+
# Before SIP (macOS 10.10 and below)
|
37
|
+
ORIG_JAMF_BINARY = Pathname.new '/usr/sbin/jamf'
|
38
|
+
|
39
|
+
# The Pathname to the jamf binary executable
|
40
|
+
# After SIP (OS X 10.11 and above)
|
41
|
+
SIP_JAMF_BINARY = USR_LOCAL_BIN_FOLDER + 'jamf'
|
42
|
+
|
43
|
+
# The path to the jamf binary
|
44
|
+
JAMF_BINARY = SIP_JAMF_BINARY.executable? ? SIP_JAMF_BINARY : ORIG_JAMF_BINARY
|
45
|
+
|
46
|
+
# These jamf commands don't need root privs (most do)
|
47
|
+
ROOTLESS_JAMF_COMMANDS = %i[
|
48
|
+
about
|
49
|
+
checkJSSConnection
|
50
|
+
getARDFields
|
51
|
+
getComputerName
|
52
|
+
help
|
53
|
+
listUsers
|
54
|
+
version
|
55
|
+
].freeze
|
56
|
+
|
57
|
+
# the option that makes the jamf binary verbose
|
58
|
+
JAMF_VERBOSE_OPT = ' -verbose'.freeze
|
59
|
+
|
60
|
+
# class Methods
|
61
|
+
#####################################
|
62
|
+
|
63
|
+
# Run an arbitrary jamf binary command.
|
64
|
+
#
|
65
|
+
# @note Most jamf commands require superuser/root privileges.
|
66
|
+
#
|
67
|
+
# @param command[String,Symbol] the jamf binary command to run
|
68
|
+
# The command is the single jamf command that comes after the/usr/bin/jamf.
|
69
|
+
#
|
70
|
+
# @param args[String,Array] the arguments passed to the jamf command.
|
71
|
+
# This is to be passed to Kernel.` (backtick), after being combined with the
|
72
|
+
# jamf binary and the jamf command
|
73
|
+
#
|
74
|
+
# @param verbose[Boolean] Should the stdout & stderr of the jamf binary be sent to
|
75
|
+
# the current stdout in realtime, as well as returned as a string?
|
76
|
+
#
|
77
|
+
# @return [String] the stdout & stderr of the jamf binary.
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# These two are equivalent:
|
81
|
+
#
|
82
|
+
# JSS::Client.run_jamf "recon", "-assetTag 12345 -department 'IT Support'"
|
83
|
+
#
|
84
|
+
# JSS::Client.run_jamf :recon, ['-assetTag', '12345', '-department', 'IT Support'"]
|
85
|
+
#
|
86
|
+
#
|
87
|
+
# The details of the Process::Status for the jamf binary process can be
|
88
|
+
# captured from $CHILD_STATUS immediately after calling. (See Process::Status)
|
89
|
+
#
|
90
|
+
def self.run_jamf(command, args = nil, verbose = false)
|
91
|
+
raise JSS::UnmanagedError, 'The jamf binary is not installed on this computer.' unless installed?
|
92
|
+
unless ROOTLESS_JAMF_COMMANDS.include?(command.to_sym) || JSS.superuser?
|
93
|
+
raise JSS::UnsupportedError, 'You must have root privileges to run that jamf binary command'
|
94
|
+
end
|
95
|
+
cmd = build_jamf_command command, args
|
96
|
+
cmd += " #{JAMF_VERBOSE_OPT}" if verbose && !cmd.include?(JAMF_VERBOSE_OPT)
|
97
|
+
execute_jamf cmd, verbose
|
98
|
+
end # run_jamf
|
99
|
+
|
100
|
+
private_class_method
|
101
|
+
|
102
|
+
def self.build_jamf_command(command, args)
|
103
|
+
case args
|
104
|
+
when nil
|
105
|
+
"#{JAMF_BINARY} #{command}"
|
106
|
+
when String
|
107
|
+
"#{JAMF_BINARY} #{command} #{args}"
|
108
|
+
when Array
|
109
|
+
([JAMF_BINARY.to_s, command] + args).join(' ')
|
110
|
+
else
|
111
|
+
raise JSS::InvalidDataError, 'args must be a String or Array of Strings'
|
112
|
+
end # case
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.execute_jamf(cmd, verbose)
|
116
|
+
puts "Running: #{cmd}" if verbose
|
117
|
+
output = ''
|
118
|
+
IO.popen("#{cmd} 2>&1") do |proc|
|
119
|
+
loop do
|
120
|
+
line = proc.gets
|
121
|
+
break unless line
|
122
|
+
output << line
|
123
|
+
puts line if verbose
|
124
|
+
end
|
125
|
+
end
|
126
|
+
output.force_encoding('UTF-8')
|
127
|
+
output
|
128
|
+
end
|
129
|
+
|
130
|
+
end # class Client
|
131
|
+
|
132
|
+
end # module
|
@@ -0,0 +1,298 @@
|
|
1
|
+
### Copyright 2019 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
###
|
27
|
+
module JSS
|
28
|
+
|
29
|
+
#
|
30
|
+
class Client
|
31
|
+
|
32
|
+
# Constants
|
33
|
+
#####################################
|
34
|
+
|
35
|
+
# The Pathname to the jamfHelper executable
|
36
|
+
JAMF_HELPER = SUPPORT_BIN_FOLDER + 'jamfHelper.app/Contents/MacOS/jamfHelper'
|
37
|
+
|
38
|
+
# The window_type options for jamfHelper
|
39
|
+
JAMF_HELPER_WINDOW_TYPES = {
|
40
|
+
hud: 'hud',
|
41
|
+
utility: 'utility',
|
42
|
+
util: 'utility',
|
43
|
+
full_screen: 'fs',
|
44
|
+
fs: 'fs'
|
45
|
+
}.freeze
|
46
|
+
|
47
|
+
# The possible window positions for jamfHelper
|
48
|
+
JAMF_HELPER_WINDOW_POSITIONS = [nil, :ul, :ll, :ur, :lr].freeze
|
49
|
+
|
50
|
+
# The available buttons in jamfHelper
|
51
|
+
JAMF_HELPER_BUTTONS = [1, 2].freeze
|
52
|
+
|
53
|
+
# The possible alignment positions in jamfHelper
|
54
|
+
JAMF_HELPER_ALIGNMENTS = %i[right left center justified natural].freeze
|
55
|
+
|
56
|
+
# class Methods
|
57
|
+
#####################################
|
58
|
+
|
59
|
+
|
60
|
+
# A wrapper for the jamfHelper command, which can display a window on the client machine.
|
61
|
+
#
|
62
|
+
# The first parameter must be a symbol defining what kind of window to display. The options are
|
63
|
+
# - :hud - creates an Apple "Heads Up Display" style window
|
64
|
+
# - :utility or :util - creates an Apple "Utility" style window
|
65
|
+
# - :fs or :full_screen or :fullscreen - creates a full screen window that restricts all user input
|
66
|
+
# WARNING: Remote access must be used to unlock machines in this mode
|
67
|
+
#
|
68
|
+
# The remaining options Hash can contain any of the options listed. See below for descriptions.
|
69
|
+
#
|
70
|
+
# The value returned is the Integer exitstatus/stdout (both are the same) of the jamfHelper command.
|
71
|
+
# The meanings of those integers are:
|
72
|
+
#
|
73
|
+
# - 0 - Button 1 was clicked
|
74
|
+
# - 1 - The Jamf Helper was unable to launch
|
75
|
+
# - 2 - Button 2 was clicked
|
76
|
+
# - 3 - Process was started as a launchd task
|
77
|
+
# - XX1 - Button 1 was clicked with a value of XX seconds selected in the drop-down
|
78
|
+
# - XX2 - Button 2 was clicked with a value of XX seconds selected in the drop-down
|
79
|
+
# - 239 - The exit button was clicked
|
80
|
+
# - 240 - The "ProductVersion" in sw_vers did not return 10.5.X, 10.6.X or 10.7.X
|
81
|
+
# - 243 - The window timed-out with no buttons on the screen
|
82
|
+
# - 250 - Bad "-windowType"
|
83
|
+
# - 254 - Cancel button was select with delay option present
|
84
|
+
# - 255 - No "-windowType"
|
85
|
+
#
|
86
|
+
# If the :abandon_process option is given, the integer returned is the Process ID
|
87
|
+
# of the abondoned process running jamfHelper.
|
88
|
+
#
|
89
|
+
# See also /Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -help
|
90
|
+
#
|
91
|
+
# @note the -startlaunchd and -kill options are not available in this implementation, since
|
92
|
+
# they don't work at the moment (casper 9.4).
|
93
|
+
# -startlaunchd seems to be required to NOT use launchd, and when it's ommited, an error is generated
|
94
|
+
# about the launchd plist permissions being incorrect.
|
95
|
+
#
|
96
|
+
# @param window_type[Symbol] The type of window to display
|
97
|
+
#
|
98
|
+
# @param opts[Hash] the options for the window
|
99
|
+
#
|
100
|
+
# @option opts :window_position [Symbol,nil] one of [ nil, :ul, :ll. :ur, :lr ]
|
101
|
+
# Positions window in the upper right, upper left, lower right or lower left of the user's screen
|
102
|
+
# If no input is given, the window defaults to the center of the screen
|
103
|
+
#
|
104
|
+
# @option opts :title [String]
|
105
|
+
# Sets the window's title to the specified string
|
106
|
+
#
|
107
|
+
# @option opts :heading [String]
|
108
|
+
# Sets the heading of the window to the specified string
|
109
|
+
#
|
110
|
+
# @option opts :align_heading [Symbol] one of [:right, :left, :center, :justified, :natural]
|
111
|
+
# Aligns the heading to the specified alignment
|
112
|
+
#
|
113
|
+
# @option opts :description [String]
|
114
|
+
# Sets the main contents of the window to the specified string
|
115
|
+
#
|
116
|
+
# @option opts :align_description [Symbol] one of [:right, :left, :center, :justified, :natural]
|
117
|
+
# Aligns the description to the specified alignment
|
118
|
+
#
|
119
|
+
# @option opts :icon [String,Pathname]
|
120
|
+
# Sets the windows image field to the image located at the specified path
|
121
|
+
#
|
122
|
+
# @option opts :icon_size [Integer]
|
123
|
+
# Changes the image frame to the specified pixel size
|
124
|
+
#
|
125
|
+
# @option opts :full_screen_icon [any value]
|
126
|
+
# Scales the "icon" to the full size of the window.
|
127
|
+
# Note: Only available in full screen mode
|
128
|
+
#
|
129
|
+
# @option opts :button1 [String]
|
130
|
+
# Creates a button with the specified label
|
131
|
+
#
|
132
|
+
# @option opts :button2 [String]
|
133
|
+
# Creates a second button with the specified label
|
134
|
+
#
|
135
|
+
# @option opts :default_button [Integer] either 1 or 2
|
136
|
+
# Sets the default button of the window to the specified button. The Default Button will respond to "return"
|
137
|
+
#
|
138
|
+
# @option opts :cancel_button [Integer] either 1 or 2
|
139
|
+
# Sets the cancel button of the window to the specified button. The Cancel Button will respond to "escape"
|
140
|
+
#
|
141
|
+
# @option opts :timeout [Integer]
|
142
|
+
# Causes the window to timeout after the specified amount of seconds
|
143
|
+
# Note: The timeout will cause the default button, button 1 or button 2 to be selected (in that order)
|
144
|
+
#
|
145
|
+
# @option opts :show_delay_options [String,Array<Integer>] A String of comma-separated Integers, or an Array of Integers.
|
146
|
+
# Enables the "Delay Options Mode". The window will display a dropdown with the values passed through the string
|
147
|
+
#
|
148
|
+
# @option opts :countdown [any value]
|
149
|
+
# Displays a string notifying the user when the window will time out
|
150
|
+
#
|
151
|
+
# @option opts :align_countdown [Symbol] one of [:right, :left, :center, :justified, :natural]
|
152
|
+
# Aligns the countdown to the specified alignment
|
153
|
+
#
|
154
|
+
# @option opts :lock_hud [Boolean]
|
155
|
+
# Removes the ability to exit the HUD by selecting the close button
|
156
|
+
#
|
157
|
+
# @option opts :abandon_process [Boolean] Abandon the jamfHelper process so that your code can exit.
|
158
|
+
# This is mostly used so that a policy can finish while a dialog is waiting
|
159
|
+
# (possibly forever) for user response. When true, the returned value is the
|
160
|
+
# process id of the abandoned jamfHelper process.
|
161
|
+
#
|
162
|
+
# @option opts :output_file [String, Pathname] Save the output of jamfHelper
|
163
|
+
# (the exit code) into this file. This is useful when using abandon_process.
|
164
|
+
# The output file can be examined later to see what happened. If this option
|
165
|
+
# is not provided, no output is saved.
|
166
|
+
#
|
167
|
+
# @option opts :arg_string [String] The jamfHelper commandline args as a single
|
168
|
+
# String, the way you'd specify them in a shell. This is appended to any
|
169
|
+
# Ruby options provided when calling the method. So calling:
|
170
|
+
# JSS::Client.jamf_helper :hud, title: 'This is a title', arg_string: '-heading "this is a heading"'
|
171
|
+
# will run
|
172
|
+
# jamfHelper -windowType hud -title 'this is a title' -heading "this is a heading"
|
173
|
+
# When using this, be careful not to specify the windowType, since it's generated
|
174
|
+
# by the first, required, parameter of this method.
|
175
|
+
#
|
176
|
+
# @return [Integer] the exit status of the jamfHelper command. See above.
|
177
|
+
#
|
178
|
+
def self.jamf_helper(window_type = :hud, opts = {})
|
179
|
+
raise JSS::UnmanagedError, 'The jamfHelper app is not installed properly on this computer.' unless JAMF_HELPER.executable?
|
180
|
+
|
181
|
+
unless JAMF_HELPER_WINDOW_TYPES.include? window_type
|
182
|
+
raise JSS::InvalidDataError, "The first parameter must be a window type, one of :#{JAMF_HELPER_WINDOW_TYPES.keys.join(', :')}."
|
183
|
+
end
|
184
|
+
|
185
|
+
# start building the arg array
|
186
|
+
|
187
|
+
args = ['-startlaunchd', '-windowType', JAMF_HELPER_WINDOW_TYPES[window_type]]
|
188
|
+
|
189
|
+
opts.keys.each do |opt|
|
190
|
+
case opt
|
191
|
+
when :window_position
|
192
|
+
raise JSS::InvalidDataError, ":window_position must be one of :#{JAMF_HELPER_WINDOW_POSITIONS.join(', :')}." unless \
|
193
|
+
JAMF_HELPER_WINDOW_POSITIONS.include? opts[opt].to_sym
|
194
|
+
args << '-windowPosition'
|
195
|
+
args << opts[opt].to_s
|
196
|
+
|
197
|
+
when :title
|
198
|
+
args << '-title'
|
199
|
+
args << opts[opt].to_s
|
200
|
+
|
201
|
+
when :heading
|
202
|
+
args << '-heading'
|
203
|
+
args << opts[opt].to_s
|
204
|
+
|
205
|
+
when :align_heading
|
206
|
+
raise JSS::InvalidDataError, ":align_heading must be one of :#{JAMF_HELPER_ALIGNMENTS.join(', :')}." unless \
|
207
|
+
JAMF_HELPER_ALIGNMENTS.include? opts[opt].to_sym
|
208
|
+
args << '-alignHeading'
|
209
|
+
args << opts[opt].to_s
|
210
|
+
|
211
|
+
when :description
|
212
|
+
args << '-description'
|
213
|
+
args << opts[opt].to_s
|
214
|
+
|
215
|
+
when :align_description
|
216
|
+
raise JSS::InvalidDataError, ":align_description must be one of :#{JAMF_HELPER_ALIGNMENTS.join(', :')}." unless \
|
217
|
+
JAMF_HELPER_ALIGNMENTS.include? opts[opt].to_sym
|
218
|
+
args << '-alignDescription'
|
219
|
+
args << opts[opt].to_s
|
220
|
+
|
221
|
+
when :icon
|
222
|
+
args << '-icon'
|
223
|
+
args << opts[opt].to_s
|
224
|
+
|
225
|
+
when :icon_size
|
226
|
+
args << '-iconSize'
|
227
|
+
args << opts[opt].to_s
|
228
|
+
|
229
|
+
when :full_screen_icon
|
230
|
+
args << '-fullScreenIcon'
|
231
|
+
|
232
|
+
when :button1
|
233
|
+
args << '-button1'
|
234
|
+
args << opts[opt].to_s
|
235
|
+
|
236
|
+
when :button2
|
237
|
+
args << '-button2'
|
238
|
+
args << opts[opt].to_s
|
239
|
+
|
240
|
+
when :default_button
|
241
|
+
raise JSS::InvalidDataError, ":default_button must be one of #{JAMF_HELPER_BUTTONS.join(', ')}." unless \
|
242
|
+
JAMF_HELPER_BUTTONS.include? opts[opt]
|
243
|
+
args << '-defaultButton'
|
244
|
+
args << opts[opt].to_s
|
245
|
+
|
246
|
+
when :cancel_button
|
247
|
+
raise JSS::InvalidDataError, ":cancel_button must be one of #{JAMF_HELPER_BUTTONS.join(', ')}." unless \
|
248
|
+
JAMF_HELPER_BUTTONS.include? opts[opt]
|
249
|
+
args << '-cancelButton'
|
250
|
+
args << opts[opt].to_s
|
251
|
+
|
252
|
+
when :timeout
|
253
|
+
args << '-timeout'
|
254
|
+
args << opts[opt].to_s
|
255
|
+
|
256
|
+
when :show_delay_options
|
257
|
+
args << '-showDelayOptions'
|
258
|
+
args << JSS.to_s_and_a(opts[opt])[:arrayform].join(', ')
|
259
|
+
|
260
|
+
when :countdown
|
261
|
+
args << '-countdown' if opts[opt]
|
262
|
+
|
263
|
+
when :align_countdown
|
264
|
+
raise JSS::InvalidDataError, ":align_countdown must be one of :#{JAMF_HELPER_ALIGNMENTS.join(', :')}." unless \
|
265
|
+
JAMF_HELPER_ALIGNMENTS.include? opts[opt].to_sym
|
266
|
+
args << '-alignCountdown'
|
267
|
+
args << opts[opt].to_s
|
268
|
+
|
269
|
+
when :lock_hud
|
270
|
+
args << '-lockHUD' if opts[opt]
|
271
|
+
|
272
|
+
end # case opt
|
273
|
+
end # each do opt
|
274
|
+
|
275
|
+
cmd = Shellwords.escape JAMF_HELPER.to_s
|
276
|
+
args.each { |arg| cmd << " #{Shellwords.escape arg}" }
|
277
|
+
cmd << " #{opts[:arg_string]}" if opts[:arg_string]
|
278
|
+
cmd << " > #{Shellwords.escape opts[:output_file]}" if opts[:output_file]
|
279
|
+
|
280
|
+
if opts[:abandon_process]
|
281
|
+
pid = Process.fork
|
282
|
+
if pid.nil?
|
283
|
+
# In child
|
284
|
+
exec cmd
|
285
|
+
else
|
286
|
+
# In parent
|
287
|
+
Process.detach(pid)
|
288
|
+
pid
|
289
|
+
end
|
290
|
+
else
|
291
|
+
system cmd
|
292
|
+
$CHILD_STATUS.exitstatus
|
293
|
+
end
|
294
|
+
end # def self.jamf_helper
|
295
|
+
|
296
|
+
end # class Client
|
297
|
+
|
298
|
+
end # module
|
@@ -0,0 +1,114 @@
|
|
1
|
+
### Copyright 2019 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
###
|
27
|
+
module JSS
|
28
|
+
|
29
|
+
# jamf client computer
|
30
|
+
class Client
|
31
|
+
|
32
|
+
# Constants
|
33
|
+
#####################################
|
34
|
+
|
35
|
+
# The Pathname to the Management Action executable
|
36
|
+
MGMT_ACTION = SUPPORT_BIN_FOLDER + 'Management Action.app/Contents/MacOS/Management Action'
|
37
|
+
|
38
|
+
# NC_ALERT_STYLE_FLAGS = 4432
|
39
|
+
# NCPREFS_DOMAIN = 'com.apple.ncprefs'.freeze
|
40
|
+
# MGMT_ACTION_BUNDLE_ID = 'com.jamfsoftware.Management-Action'.freeze
|
41
|
+
# HUP_NOTIF_CTR_CMD = '/usr/bin/killall sighup usernoted NotificationCenter'.freeze
|
42
|
+
|
43
|
+
# class Methods
|
44
|
+
#####################################
|
45
|
+
|
46
|
+
def self.management_action(msg, title: nil, subtitle: nil, delay: 0)
|
47
|
+
raise JSS::InvalidDataError, 'delay: must be a non-negative integer.' unless delay.is_a?(Integer) && delay > -1
|
48
|
+
|
49
|
+
cmd = Shellwords.escape MGMT_ACTION.to_s
|
50
|
+
cmd << " -message #{Shellwords.escape msg.to_s}"
|
51
|
+
cmd << " -title #{Shellwords.escape title.to_s}" if title
|
52
|
+
cmd << " -subtitle #{Shellwords.escape subtitle.to_s}" if subtitle
|
53
|
+
cmd << " -deliverydelay #{Shellwords.escape delay}" if delay > 0
|
54
|
+
`#{cmd} 2>&1`
|
55
|
+
end
|
56
|
+
|
57
|
+
# an alias of management_action
|
58
|
+
def self.nc_notify(msg, title: nil, subtitle: nil, delay: 0)
|
59
|
+
management_action(msg, title: title, subtitle: subtitle, delay: delay)
|
60
|
+
end
|
61
|
+
|
62
|
+
private_class_method
|
63
|
+
|
64
|
+
# Skipping all the force-alerts stuff until we figure out cleaner
|
65
|
+
# ways to do it in 10.13+
|
66
|
+
# The plan is to be able to make the NotificationCenter notification be an
|
67
|
+
# 'alert' (which stays visible til the user clicks) or a
|
68
|
+
# 'banner' (which vanishes in a few seconds), regardless of the user's
|
69
|
+
# setting in the NC prefs.
|
70
|
+
|
71
|
+
def self.force_alerts
|
72
|
+
orig_flags = {}
|
73
|
+
console_users.each do |user|
|
74
|
+
orig_flags[user] = set_mgmt_action_ncprefs_flags user, NC_ALERT_STYLE_FLAGS, hup: false
|
75
|
+
end
|
76
|
+
system HUP_NOTIF_CTR_CMD unless orig_flags.empty?
|
77
|
+
sleep 1
|
78
|
+
orig_flags
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.restore_alerts(orig_flags)
|
82
|
+
orig_flags.each do |user, flags|
|
83
|
+
set_mgmt_action_ncprefs_flags user, flags, hup: false
|
84
|
+
end
|
85
|
+
system HUP_NOTIF_CTR_CMD unless orig_flags.empty?
|
86
|
+
end
|
87
|
+
|
88
|
+
# set the NotificationCenter option flags for a user
|
89
|
+
# flags = an integer.
|
90
|
+
#
|
91
|
+
# Doesn't seem to work in 10.13, so ignore this for now.
|
92
|
+
#
|
93
|
+
# @return [Integer] the original flags, or given flags if no originals.
|
94
|
+
#
|
95
|
+
def self.set_mgmt_action_ncprefs_flags(user, flags, hup: true)
|
96
|
+
plist = Pathname.new "/Users/#{user}/Library/Preferences/#{NCPREFS_DOMAIN}.plist"
|
97
|
+
prefs = JSS.parse_plist plist
|
98
|
+
mgmt_action_setting = prefs['apps'].select { |a| a['bundle-id'] == MGMT_ACTION_BUNDLE_ID }.first
|
99
|
+
if mgmt_action_setting
|
100
|
+
orig_flags = mgmt_action_setting['flags']
|
101
|
+
mgmt_action_setting['flags'] = flags
|
102
|
+
else
|
103
|
+
orig_flags = flags
|
104
|
+
prefs['apps'] << { 'bundle-id' => MGMT_ACTION_BUNDLE_ID, 'flags' => flags }
|
105
|
+
end
|
106
|
+
# system "/usr/bin/defaults write #{NCPREFS_DOMAIN} '#{prefs.to_plist}'"
|
107
|
+
plist.open('w') { |f| f.write prefs.to_plist }
|
108
|
+
system HUP_NOTIF_CTR_CMD if hup
|
109
|
+
orig_flags
|
110
|
+
end
|
111
|
+
|
112
|
+
end # class Client
|
113
|
+
|
114
|
+
end # module
|