ruby-jss 0.6.3

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.

Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGES.md +112 -0
  4. data/LICENSE.txt +174 -0
  5. data/README.md +426 -0
  6. data/THANKS.md +6 -0
  7. data/bin/cgrouper +485 -0
  8. data/bin/subnet-update +400 -0
  9. data/lib/jss-api.rb +2 -0
  10. data/lib/jss.rb +190 -0
  11. data/lib/jss/api_connection.rb +410 -0
  12. data/lib/jss/api_object.rb +616 -0
  13. data/lib/jss/api_object/advanced_search.rb +389 -0
  14. data/lib/jss/api_object/advanced_search/advanced_computer_search.rb +95 -0
  15. data/lib/jss/api_object/advanced_search/advanced_mobile_device_search.rb +96 -0
  16. data/lib/jss/api_object/advanced_search/advanced_user_search.rb +95 -0
  17. data/lib/jss/api_object/building.rb +92 -0
  18. data/lib/jss/api_object/category.rb +147 -0
  19. data/lib/jss/api_object/computer.rb +852 -0
  20. data/lib/jss/api_object/creatable.rb +98 -0
  21. data/lib/jss/api_object/criteriable.rb +189 -0
  22. data/lib/jss/api_object/criteriable/criteria.rb +231 -0
  23. data/lib/jss/api_object/criteriable/criterion.rb +228 -0
  24. data/lib/jss/api_object/department.rb +93 -0
  25. data/lib/jss/api_object/distribution_point.rb +560 -0
  26. data/lib/jss/api_object/extendable.rb +221 -0
  27. data/lib/jss/api_object/extension_attribute.rb +466 -0
  28. data/lib/jss/api_object/extension_attribute/computer_extension_attribute.rb +362 -0
  29. data/lib/jss/api_object/extension_attribute/mobile_device_extension_attribute.rb +189 -0
  30. data/lib/jss/api_object/extension_attribute/user_extension_attribute.rb +117 -0
  31. data/lib/jss/api_object/group.rb +380 -0
  32. data/lib/jss/api_object/group/computer_group.rb +124 -0
  33. data/lib/jss/api_object/group/mobile_device_group.rb +139 -0
  34. data/lib/jss/api_object/group/user_group.rb +139 -0
  35. data/lib/jss/api_object/ldap_server.rb +535 -0
  36. data/lib/jss/api_object/locatable.rb +286 -0
  37. data/lib/jss/api_object/matchable.rb +97 -0
  38. data/lib/jss/api_object/mobile_device.rb +556 -0
  39. data/lib/jss/api_object/netboot_server.rb +148 -0
  40. data/lib/jss/api_object/network_segment.rb +414 -0
  41. data/lib/jss/api_object/osx_configuration_profile.rb +262 -0
  42. data/lib/jss/api_object/package.rb +839 -0
  43. data/lib/jss/api_object/peripheral.rb +335 -0
  44. data/lib/jss/api_object/peripheral_type.rb +295 -0
  45. data/lib/jss/api_object/policy.rb +898 -0
  46. data/lib/jss/api_object/purchasable.rb +316 -0
  47. data/lib/jss/api_object/removable_macaddr.rb +98 -0
  48. data/lib/jss/api_object/scopable.rb +136 -0
  49. data/lib/jss/api_object/scopable/scope.rb +621 -0
  50. data/lib/jss/api_object/script.rb +631 -0
  51. data/lib/jss/api_object/self_servable.rb +356 -0
  52. data/lib/jss/api_object/site.rb +93 -0
  53. data/lib/jss/api_object/software_update_server.rb +109 -0
  54. data/lib/jss/api_object/updatable.rb +117 -0
  55. data/lib/jss/api_object/uploadable.rb +138 -0
  56. data/lib/jss/api_object/user.rb +272 -0
  57. data/lib/jss/client.rb +504 -0
  58. data/lib/jss/compatibility.rb +66 -0
  59. data/lib/jss/composer.rb +185 -0
  60. data/lib/jss/configuration.rb +306 -0
  61. data/lib/jss/db_connection.rb +298 -0
  62. data/lib/jss/exceptions.rb +95 -0
  63. data/lib/jss/ruby_extensions.rb +35 -0
  64. data/lib/jss/ruby_extensions/filetest.rb +43 -0
  65. data/lib/jss/ruby_extensions/hash.rb +79 -0
  66. data/lib/jss/ruby_extensions/ipaddr.rb +91 -0
  67. data/lib/jss/ruby_extensions/pathname.rb +77 -0
  68. data/lib/jss/ruby_extensions/string.rb +59 -0
  69. data/lib/jss/ruby_extensions/time.rb +63 -0
  70. data/lib/jss/server.rb +108 -0
  71. data/lib/jss/utility.rb +478 -0
  72. data/lib/jss/version.rb +31 -0
  73. metadata +187 -0
@@ -0,0 +1,504 @@
1
+ ### Copyright 2016 Pixar
2
+ ###
3
+ ### Licensed under the Apache License, Version 2.0 (the "Apache License")
4
+ ### with the following modification; you may not use this file except in
5
+ ### compliance with the Apache License and the following modification to it:
6
+ ### Section 6. Trademarks. is deleted and replaced with:
7
+ ###
8
+ ### 6. Trademarks. This License does not grant permission to use the trade
9
+ ### names, trademarks, service marks, or product names of the Licensor
10
+ ### and its affiliates, except as required to comply with Section 4(c) of
11
+ ### the License and to reproduce the content of the NOTICE file.
12
+ ###
13
+ ### You may obtain a copy of the Apache License at
14
+ ###
15
+ ### http://www.apache.org/licenses/LICENSE-2.0
16
+ ###
17
+ ### Unless required by applicable law or agreed to in writing, software
18
+ ### distributed under the Apache License with the above modification is
19
+ ### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20
+ ### KIND, either express or implied. See the Apache License for the specific
21
+ ### language governing permissions and limitations under the Apache License.
22
+ ###
23
+ ###
24
+
25
+ ###
26
+ module JSS
27
+
28
+ #####################################
29
+ ### Module Variables
30
+ #####################################
31
+
32
+ #####################################
33
+ ### Module Methods
34
+ #####################################
35
+
36
+ #####################################
37
+ ### Classes
38
+ #####################################
39
+
40
+ ###
41
+ ### This class represents a Casper/JSS Client computer, on which
42
+ ### this code is running.
43
+ ###
44
+ ### Since the class represents the current machine, there's no need
45
+ ### to make an instance of it, all methods are class methods.
46
+ ###
47
+ ### At the moment, only Macintosh computers are supported.
48
+ ###
49
+ ###
50
+ class Client
51
+
52
+ #####################################
53
+ ### Class Constants
54
+ #####################################
55
+
56
+ ### The Pathname to the jamf binary executable
57
+ ### As of El Capitan (OS X 10.11) the location has moved.
58
+ ORIG_JAMF_BINARY = Pathname.new "/usr/sbin/jamf"
59
+ ELCAP_JAMF_BINARY = Pathname.new "/usr/local/jamf/bin/jamf"
60
+ JAMF_BINARY = ELCAP_JAMF_BINARY.executable? ? ELCAP_JAMF_BINARY : ORIG_JAMF_BINARY
61
+
62
+ ### The Pathname to the jamfHelper executable
63
+ JAMF_HELPER = Pathname.new "/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"
64
+
65
+ ### The window_type options for jamfHelper
66
+ JAMF_HELPER_WINDOW_TYPES = {
67
+ :hud => 'hud',
68
+ :utility => 'utility',
69
+ :util => 'utility',
70
+ :full_screen => 'fs',
71
+ :fs => 'fs'
72
+ }
73
+
74
+ ### The possible window positions for jamfHelper
75
+ JAMF_HELPER_WINDOW_POSITIONS = [nil, :ul, :ll, :ur, :lr]
76
+
77
+ ### The available buttons in jamfHelper
78
+ JAMF_HELPER_BUTTONS = [1,2]
79
+
80
+ ### The possible alignment positions in jamfHelper
81
+ JAMF_HELPER_ALIGNMENTS = [:right, :left, :center, :justified, :natural]
82
+
83
+ ### The Pathname to the preferences plist used by the jamf binary
84
+ JAMF_PLIST = Pathname.new "/Library/Preferences/com.jamfsoftware.jamf.plist"
85
+
86
+ ### The Pathname to the JAMF support folder
87
+ JAMF_SUPPORT_FOLDER = Pathname.new "/Library/Application Support/JAMF"
88
+
89
+ ### The JAMF receipts folder, where package installs are tracked.
90
+ RECEIPTS_FOLDER = JAMF_SUPPORT_FOLDER + "Receipts"
91
+
92
+ ### The JAMF downloads folder
93
+ DOWNLOADS_FOLDER = JAMF_SUPPORT_FOLDER + "Downloads"
94
+
95
+ ### These jamf commands don't need root privs (most do)
96
+ ROOTLESS_JAMF_COMMANDS = [
97
+ :about,
98
+ :checkJSSConnection,
99
+ :getARDFields,
100
+ :getComputerName,
101
+ :help,
102
+ :listUsers,
103
+ :version ]
104
+
105
+ #####################################
106
+ ### Class Variables
107
+ #####################################
108
+
109
+ #####################################
110
+ ### Class Methods
111
+ #####################################
112
+
113
+ ###
114
+ ### Get the current IP address as a String.
115
+ ###
116
+ ### This handy code doesn't acutally make a UDP connection,
117
+ ### it just starts to set up the connection, then uses that to get
118
+ ### the local IP.
119
+ ###
120
+ ### Lifted gratefully from
121
+ ### http://coderrr.wordpress.com/2008/05/28/get-your-local-ip-address/
122
+ ###
123
+ ### @return [String] the current IP address.
124
+ ###
125
+ def self.my_ip_address
126
+ ### turn off reverse DNS resolution temporarily
127
+ ### @note the 'socket' library has already been required by 'rest-client'
128
+ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
129
+
130
+ UDPSocket.open do |s|
131
+ s.connect '192.168.0.0', 1
132
+ s.addr.last
133
+ end
134
+ ensure
135
+ Socket.do_not_reverse_lookup = orig
136
+ end
137
+
138
+
139
+
140
+ ###
141
+ ### @return [Boolean] is the jamf binary installed?
142
+ ###
143
+ def self.installed?
144
+ JAMF_BINARY.executable?
145
+ end
146
+
147
+ ###
148
+ ### @return [String,nil] the version of the jamf binary installed on this client, nil if not installed
149
+ ###
150
+ def self.jamf_version
151
+ self.installed? ? self.run_jamf(:version).chomp.split('=')[1] : nil
152
+ end
153
+
154
+ ###
155
+ ### @return [String] the url to the JSS for this client
156
+ ###
157
+ def self.jss_url
158
+ @url = self.jamf_plist['jss_url']
159
+ return nil if @url.nil?
160
+ @url =~ %r{(https?)://(.+):(\d+)/}
161
+ @protocol = $1
162
+ @server = $2
163
+ @port = $3
164
+ return @url
165
+ end
166
+
167
+ ###
168
+ ### @return [String] the JSS server for this client
169
+ ###
170
+ def self.jss_server
171
+ self.jss_url
172
+ return @server
173
+ end
174
+
175
+ ###
176
+ ### @return [String] the protocol to the JSS for this client, "http" or "https"
177
+ ###
178
+ def self.jss_protocol
179
+ self.jss_url
180
+ return @protocol
181
+ end
182
+
183
+ ###
184
+ ### @return [Integer] the port to the JSS for this client
185
+ ###
186
+ def self.jss_port
187
+ self.jss_url
188
+ @port ? @port.to_i : 80
189
+ end
190
+
191
+ ###
192
+ ### @return [Hash] the parsed contents of the JAMF_PLIST if it exists, an empty hash if not
193
+ ###
194
+ def self.jamf_plist
195
+ return {} unless JAMF_PLIST.file?
196
+ Plist.parse_xml `/usr/libexec/PlistBuddy -x -c print #{Shellwords.escape JSS::Client::JAMF_PLIST.to_s}`
197
+ end
198
+
199
+
200
+ ###
201
+ ### @return [Array<Pathname>] an array of Pathnames for all regular files in the jamf receipts folder
202
+ ###
203
+ def self.receipts
204
+ raise JSS::NoSuchItemError, "The JAMF Receipts folder doesn't exist on this computer." unless RECEIPTS_FOLDER.exist?
205
+ RECEIPTS_FOLDER.children.select{|c| c.file?}
206
+ end
207
+
208
+ ###
209
+ ### @return [Boolean] is the JSS available now?
210
+ ###
211
+ def self.jss_available?
212
+ output = run_jamf :checkJSSConnection, "-retry 1"
213
+ $?.exitstatus == 0
214
+ end
215
+
216
+
217
+ ###
218
+ ### @return [JSS::Computer] The JSS record for this computer
219
+ ###
220
+ def self.jss_record
221
+ begin
222
+ JSS::Computer.new :udid => self.udid
223
+ rescue JSS::NoSuchItemError
224
+ JSS::Computer.new :serial_number => self.serial_number
225
+ end
226
+ end
227
+
228
+ ###
229
+ ### @return [String] the UUID/UDID for this computer
230
+ ###
231
+ def self.udid
232
+ self.hardware_data["platform_UUID"]
233
+ end
234
+
235
+ ###
236
+ ### @return [String] the serial number for this computer
237
+ ###
238
+ def self.serial_number
239
+ self.hardware_data["serial_number"]
240
+ end
241
+
242
+ ###
243
+ ### @return [Hash] the HardwareDataType data from the system_profiler command
244
+ ###
245
+ def self.hardware_data
246
+ raw = `/usr/sbin/system_profiler SPHardwareDataType -xml 2>/dev/null`
247
+ Plist.parse_xml(raw)[0]["_items"][0]
248
+ end
249
+
250
+
251
+ ### Run an arbitrary jamf binary command.
252
+ ###
253
+ ### @note Most jamf commands require superuser/root privileges.
254
+ ###
255
+ ### @param command[String,Symbol] the jamf binary command to run
256
+ ### The command is the single jamf command that comes after the/usr/bin/jamf.
257
+ ###
258
+ ### @param args[String,Array] the arguments passed to the jamf command.
259
+ ### This is to be passed to Kernel.` (backtick), after being combined with the
260
+ ### jamf binary and the jamf command
261
+ ###
262
+ ### @param verbose[Boolean] Should the stdout & stderr of the jamf binary be sent to
263
+ ### the current stdout in realtime, as well as returned as a string?
264
+ ###
265
+ ### @return [String] the stdout & stderr of the jamf binary.
266
+ ###
267
+ ### @example
268
+ ### These two are equivalent:
269
+ ###
270
+ ### JSS::Client.run_jamf "recon", "-assetTag 12345 -department 'IT Support'"
271
+ ###
272
+ ### JSS::Client.run_jamf :recon, ['-assetTag', '12345', '-department', 'IT Support'"]
273
+ ###
274
+ ###
275
+ ### The details of the Process::Status for the jamf binary process can be captured from $?
276
+ ### immediately after calling. (See Process::Status)
277
+ ###
278
+ def self.run_jamf(command, args = nil, verbose = false)
279
+ raise JSS::UnmanagedError, "The jamf binary is not installed on this computer." unless self.installed?
280
+ raise JSS::UnsupportedError, "You must have root privileges to run that jamf binary command" unless ROOTLESS_JAMF_COMMANDS.include? command.to_sym or JSS.superuser?
281
+
282
+ cmd = case args
283
+ when nil
284
+ "#{JAMF_BINARY} #{command}"
285
+ when String
286
+ "#{JAMF_BINARY} #{command} #{args}"
287
+ when Array
288
+ "#{([JAMF_BINARY.to_s, command] + args).join(' ')}"
289
+ else
290
+ raise JSS::InvalidDataError, "args must be a String or Array of Strings"
291
+ end # case
292
+
293
+ cmd += " -verbose" if verbose and (not cmd.include? " -verbose")
294
+ puts "Running: #{cmd}" if verbose
295
+
296
+ output = []
297
+ IO.popen("#{cmd} 2>&1") do |proc|
298
+ while line = proc.gets
299
+ output << line
300
+ puts line if verbose
301
+ end
302
+ end
303
+ install_out = output.join('')
304
+ install_out.force_encoding("UTF-8") if install_out.respond_to? :force_encoding
305
+ return install_out
306
+ end # run_jamf
307
+
308
+
309
+ ### A wrapper for the jamfHelper command, which can display a window on the client machine.
310
+ ###
311
+ ### The first parameter must be a symbol defining what kind of window to display. The options are
312
+ ### - :hud - creates an Apple "Heads Up Display" style window
313
+ ### - :utility or :util - creates an Apple "Utility" style window
314
+ ### - :fs or :full_screen or :fullscreen - creates a full screen window that restricts all user input
315
+ ### WARNING: Remote access must be used to unlock machines in this mode
316
+ ###
317
+ ### The remaining options Hash can contain any of the options listed. See below for descriptions.
318
+ ###
319
+ ### The value returned is the Integer exitstatus/stdout (both are the same) of the jamfHelper command.
320
+ ### The meanings of those integers are:
321
+ ###
322
+ ### - 0 - Button 1 was clicked
323
+ ### - 1 - The Jamf Helper was unable to launch
324
+ ### - 2 - Button 2 was clicked
325
+ ### - 3 - Process was started as a launchd task
326
+ ### - XX1 - Button 1 was clicked with a value of XX seconds selected in the drop-down
327
+ ### - XX2 - Button 2 was clicked with a value of XX seconds selected in the drop-down
328
+ ### - 239 - The exit button was clicked
329
+ ### - 240 - The "ProductVersion" in sw_vers did not return 10.5.X, 10.6.X or 10.7.X
330
+ ### - 243 - The window timed-out with no buttons on the screen
331
+ ### - 250 - Bad "-windowType"
332
+ ### - 254 - Cancel button was select with delay option present
333
+ ### - 255 - No "-windowType"
334
+ ###
335
+ ### See also /Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -help
336
+ ###
337
+ ### @note the -startlaunchd and -kill options are not available in this implementation, since
338
+ ### they don't work at the moment (casper 9.4).
339
+ ### -startlaunchd seems to be required to NOT use launchd, and when it's ommited, an error is generated
340
+ ### about the launchd plist permissions being incorrect.
341
+ ###
342
+ ### @param window_type[Symbol] The type of window to display
343
+ ###
344
+ ### @param opts[Hash] the options for the window
345
+ ###
346
+ ### @option opts :window_position [Symbol,nil] one of [ nil, :ul, :ll. :ur, :lr ]
347
+ ### Positions window in the upper right, upper left, lower right or lower left of the user's screen
348
+ ### If no input is given, the window defaults to the center of the screen
349
+ ###
350
+ ### @option opts :title [String]
351
+ ### Sets the window's title to the specified string
352
+ ###
353
+ ### @option opts :heading [String]
354
+ ### Sets the heading of the window to the specified string
355
+ ###
356
+ ### @option opts :align_heading [Symbol] one of [:right, :left, :center, :justified, :natural]
357
+ ### Aligns the heading to the specified alignment
358
+ ###
359
+ ### @option opts :description [String]
360
+ ### Sets the main contents of the window to the specified string
361
+ ###
362
+ ### @option opts :align_description [Symbol] one of [:right, :left, :center, :justified, :natural]
363
+ ### Aligns the description to the specified alignment
364
+ ###
365
+ ### @option opts :icon [String,Pathname]
366
+ ### Sets the windows image field to the image located at the specified path
367
+ ###
368
+ ### @option opts :icon_size [Integer]
369
+ ### Changes the image frame to the specified pixel size
370
+ ###
371
+ ### @option opts :full_screen_icon [any value]
372
+ ### Scales the "icon" to the full size of the window.
373
+ ### Note: Only available in full screen mode
374
+ ###
375
+ ### @option opts :button1 [String]
376
+ ### Creates a button with the specified label
377
+ ###
378
+ ### @option opts :button2 [String]
379
+ ### Creates a second button with the specified label
380
+ ###
381
+ ### @option opts :default_button [Integer] either 1 or 2
382
+ ### Sets the default button of the window to the specified button. The Default Button will respond to "return"
383
+ ###
384
+ ### @option opts :cancel_button [Integer] either 1 or 2
385
+ ### Sets the cancel button of the window to the specified button. The Cancel Button will respond to "escape"
386
+ ###
387
+ ### @option opts :timeout [Integer]
388
+ ### Causes the window to timeout after the specified amount of seconds
389
+ ### Note: The timeout will cause the default button, button 1 or button 2 to be selected (in that order)
390
+ ###
391
+ ### @option opts :show_delay_options [String,Array<Integer>] A String of comma-separated Integers, or an Array of Integers.
392
+ ### Enables the "Delay Options Mode". The window will display a dropdown with the values passed through the string
393
+ ###
394
+ ### @option opts :countdown [any value]
395
+ ### Displays a string notifying the user when the window will time out
396
+ ###
397
+ ### @option opts :align_countdown [Symbol] one of [:right, :left, :center, :justified, :natural]
398
+ ### Aligns the countdown to the specified alignment
399
+ ###
400
+ ### @option opts :lock_hud [any value]
401
+ ### Removes the ability to exit the HUD by selecting the close button
402
+ ###
403
+ ### @return [Integer] the exit status of the jamfHelper command. See above.
404
+ ###
405
+ def self.jamf_helper(window_type = :hud, opts = {})
406
+
407
+ raise JSS::UnmanagedError, "The jamfHelper app is not installed properly on this computer." unless JAMF_HELPER.executable?
408
+
409
+ unless JAMF_HELPER_WINDOW_TYPES.include? window_type
410
+ raise JSS::InvalidDataError, "The first parameter must be a window type, one of :#{JAMF_HELPER_WINDOW_TYPES.keys.join(', :')}."
411
+ end
412
+
413
+ # start building the arg array
414
+
415
+ args = ["-startlaunchd", "-windowType", JAMF_HELPER_WINDOW_TYPES[window_type]]
416
+
417
+ opts.keys.each do |opt|
418
+ case opt
419
+ when :window_position
420
+ raise JSS::InvalidDataError, ":window_position must be one of :#{JAMF_HELPER_WINDOW_POSITIONS.join(', :')}." unless JAMF_HELPER_WINDOW_POSITIONS.include? opts[opt].to_sym
421
+ args << "-windowPosition"
422
+ args << opts[opt].to_s
423
+
424
+ when :title
425
+ args << "-title"
426
+ args << opts[opt].to_s
427
+
428
+ when :heading
429
+ args << "-heading"
430
+ args << opts[opt].to_s
431
+
432
+ when :align_heading
433
+ raise JSS::InvalidDataError, ":align_heading must be one of :#{JAMF_HELPER_ALIGNMENTS.join(', :')}." unless JAMF_HELPER_ALIGNMENTS.include? opts[opt].to_sym
434
+ args << "-alignHeading"
435
+ args << opts[opt].to_s
436
+
437
+ when :description
438
+ args << "-description"
439
+ args << opts[opt].to_s
440
+
441
+ when :align_description
442
+ raise JSS::InvalidDataError, ":align_description must be one of :#{JAMF_HELPER_ALIGNMENTS.join(', :')}." unless JAMF_HELPER_ALIGNMENTS.include? opts[opt].to_sym
443
+ args << "-alignDescription"
444
+ args << opts[opt].to_s
445
+
446
+ when :icon
447
+ args << "-icon"
448
+ args << opts[opt].to_s
449
+
450
+ when :icon_size
451
+ args << "-iconSize"
452
+ args << opts[opt].to_s
453
+
454
+ when :full_screen_icon
455
+ args << "-fullScreenIcon"
456
+
457
+ when :button1
458
+ args << "-button1"
459
+ args << opts[opt].to_s
460
+
461
+ when :button2
462
+ args << "-button2"
463
+ args << opts[opt].to_s
464
+
465
+ when :default_button
466
+ raise JSS::InvalidDataError, ":default_button must be one of #{JAMF_HELPER_BUTTONS.join(', ')}." unless JAMF_HELPER_BUTTONS.include? opts[opt]
467
+ args << "-defaultButton"
468
+ args << opts[opt].to_s
469
+
470
+ when :cancel_button
471
+ raise JSS::InvalidDataError, ":cancel_button must be one of #{JAMF_HELPER_BUTTONS.join(', ')}." unless JAMF_HELPER_BUTTONS.include? opts[opt]
472
+ args << "-cancelButton"
473
+ args << opts[opt].to_s
474
+
475
+ when :timeout
476
+ args << "-timeout"
477
+ args << opts[opt].to_s
478
+
479
+ when :show_delay_options
480
+ args << "-showDelayOptions"
481
+ args << JSS.to_s_and_a(opts[opt])[:arrayform].join(', ')
482
+
483
+ when :countdown
484
+ args << "-countdown"
485
+
486
+ when :align_countdown
487
+ raise JSS::InvalidDataError, ":align_countdown must be one of :#{JAMF_HELPER_ALIGNMENTS.join(', :')}." unless JAMF_HELPER_ALIGNMENTS.include? opts[opt].to_sym
488
+ args << "-alignCountdown"
489
+ args << opts[opt].to_s
490
+
491
+ when :lock_hud
492
+ args << " -lockHUD "
493
+ end # case opt
494
+ end # each do opt
495
+
496
+ system JAMF_HELPER.to_s, *args
497
+ return $?.exitstatus
498
+
499
+ end # def self.jamf_helper
500
+
501
+
502
+ end # class Client
503
+
504
+ end # module