ruby-jss 0.10.2 → 0.11.0a5

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +49 -2
  3. data/README.md +14 -7
  4. data/lib/jss/api_connection.rb +48 -24
  5. data/lib/jss/api_object/advanced_search.rb +5 -1
  6. data/lib/jss/api_object/computer.rb +204 -402
  7. data/lib/jss/api_object/computer_invitation.rb +5 -3
  8. data/lib/jss/api_object/ebook.rb +5 -0
  9. data/lib/jss/api_object/extendable.rb +13 -0
  10. data/lib/jss/api_object/group/computer_group.rb +4 -0
  11. data/lib/jss/api_object/group/mobile_device_group.rb +4 -1
  12. data/lib/jss/api_object/group.rb +6 -1
  13. data/lib/jss/api_object/mac_application.rb +5 -0
  14. data/lib/jss/api_object/management_history/audit_event.rb +45 -0
  15. data/lib/jss/api_object/management_history/casper_imaging_log.rb +37 -0
  16. data/lib/jss/api_object/management_history/casper_remote_log.rb +37 -0
  17. data/lib/jss/api_object/management_history/computer_usage_log.rb +43 -0
  18. data/lib/jss/api_object/management_history/ebook.rb +70 -0
  19. data/lib/jss/api_object/management_history/mac_app_store_app.rb +69 -0
  20. data/lib/jss/api_object/management_history/mdm_command.rb +96 -0
  21. data/lib/jss/api_object/management_history/mobile_device_app.rb +99 -0
  22. data/lib/jss/api_object/management_history/policy_log.rb +60 -0
  23. data/lib/jss/api_object/management_history/screen_sharing_log.rb +41 -0
  24. data/lib/jss/api_object/management_history/user_location_change.rb +66 -0
  25. data/lib/jss/api_object/management_history.rb +865 -0
  26. data/lib/jss/api_object/mdm.rb +1298 -0
  27. data/lib/jss/api_object/mobile_device.rb +241 -644
  28. data/lib/jss/api_object/mobile_device_application.rb +6 -0
  29. data/lib/jss/api_object/mobile_device_configuration_profile.rb +36 -0
  30. data/lib/jss/api_object/osx_configuration_profile.rb +115 -151
  31. data/lib/jss/api_object/patch.rb +38 -0
  32. data/lib/jss/api_object/patch_policy.rb +38 -0
  33. data/lib/jss/api_object/peripheral.rb +5 -7
  34. data/lib/jss/api_object/policy.rb +5 -0
  35. data/lib/jss/api_object/restricted_software.rb +5 -0
  36. data/lib/jss/api_object/scopable/scope.rb +367 -411
  37. data/lib/jss/api_object/self_servable.rb +15 -4
  38. data/lib/jss/api_object/sitable.rb +197 -0
  39. data/lib/jss/api_object/site.rb +45 -76
  40. data/lib/jss/api_object/user.rb +7 -3
  41. data/lib/jss/api_object.rb +75 -4
  42. data/lib/jss/utility.rb +21 -0
  43. data/lib/jss/version.rb +1 -1
  44. data/lib/jss.rb +6 -0
  45. metadata +42 -6
@@ -0,0 +1,1298 @@
1
+ ### Copyright 2017 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
+ # Mixin Modules
30
+ #####################################
31
+
32
+ # This module provides the ability to work with MDM commands for objects that
33
+ # can receive them.
34
+ #
35
+ # Objects mixing in this module MUST:
36
+ #
37
+ # - Define the constant MDM_COMMAND_TARGET - One of:
38
+ # :computers, :computergroups, :mobiledevices, :mobiledevicegroups
39
+ #
40
+ #
41
+ #
42
+ #
43
+ module MDM
44
+
45
+ # Constants
46
+ #####################################
47
+
48
+ #### target types
49
+
50
+ # These targets are computers
51
+ COMPUTER_TARGETS = %i[computers computergroups].freeze
52
+
53
+ # The API resource for sending computer commands
54
+ COMPUTER_RSRC = 'computercommands'.freeze
55
+
56
+ # These targets are mobile devices
57
+ DEVICE_TARGETS = %i[mobiledevices mobiledevicegroups].freeze
58
+
59
+ # the API resource for sending device commands
60
+ DEVICE_RSRC = 'mobiledevicecommands'.freeze
61
+
62
+ # These targets are groups, and need their member ids expanded for sending commands
63
+ GROUP_TARGETS = %i[computergroups mobiledevicegroups].freeze
64
+
65
+ #### The commands
66
+
67
+ # Both computers & devices
68
+
69
+ BLANK_PUSH = 'BlankPush'.freeze
70
+ DEVICE_LOCK = 'DeviceLock'.freeze
71
+ ERASE_DEVICE = 'EraseDevice'.freeze
72
+ UNMANGE_DEVICE = 'UnmanageDevice'.freeze
73
+ # UPDATE_OS = 'UpdateOS'.freeze
74
+
75
+ # computers only
76
+
77
+ DELETE_USER = 'DeleteUser'.freeze
78
+ UNLOCK_USER_ACCOUNT = 'UnlockUserAccount'.freeze
79
+
80
+ # devices
81
+
82
+ SETTINGS = 'Settings'.freeze
83
+ CLEAR_PASSCODE = 'ClearPasscode'.freeze
84
+ UPDATE_INVENTORY = 'UpdateInventory'.freeze
85
+ CLEAR_RESTRICTIONS_PASSWORD = 'ClearRestrictionsPassword'.freeze
86
+ ENABLE_DATA_ROAMING = 'SettingsEnableDataRoaming'.freeze
87
+ DISABLE_DATA_ROAMING = 'SettingsDisableDataRoaming'.freeze
88
+ ENABLE_VOICE_ROAMING = 'SettingsEnableVoiceRoaming'.freeze
89
+ DISABLE_VOICE_ROAMING = 'SettingsDisableVoiceRoaming'.freeze
90
+
91
+ # shared ipads only
92
+
93
+ PASSCODE_LOCK_GRACE_PERIOD = 'PasscodeLockGracePeriod'.freeze
94
+
95
+ # supervised devices
96
+
97
+ WALLPAPER = 'Wallpaper'.freeze
98
+ DEVICE_NAME = 'DeviceName'.freeze
99
+ SHUTDOWN_DEVICE = 'ShutDownDevice'.freeze
100
+ RESTART_DEVICE = 'RestartDevice'.freeze
101
+ ENABLE_LOST_MODE = 'EnableLostMode'.freeze
102
+ DISABLE_LOST_MODE = 'DisableLostMode'.freeze
103
+ DEVICE_LOCATION = 'DeviceLocation'.freeze
104
+ PLAY_LOST_MODE_SOUND = 'PlayLostModeSound'.freeze
105
+ ENABLE_APP_ANALYTICS = 'SettingsEnableAppAnalytics'.freeze
106
+ DISABLE_APP_ANALYTICS = 'SettingsDisableAppAnalytics'.freeze
107
+ ENABLE_DIAGNOSTIC_SUBMISSION = 'SettingsEnableDiagnosticSubmission'.freeze
108
+ DISABLE_DIAGNOSTIC_SUBMISSION = 'SettingsDisableDiagnosticSubmission'.freeze
109
+
110
+ #### Groupings of commands
111
+
112
+ # The MDM commands applicable to computers
113
+ COMPUTER_COMMANDS = [
114
+ BLANK_PUSH,
115
+ DEVICE_LOCK,
116
+ ERASE_DEVICE,
117
+ UNMANGE_DEVICE,
118
+ DELETE_USER,
119
+ UNLOCK_USER_ACCOUNT
120
+ ].freeze
121
+
122
+ # The MDM commands applicable to all mobile devices
123
+ ALL_DEVICE_COMMANDS = [
124
+ BLANK_PUSH,
125
+ DEVICE_LOCK,
126
+ ERASE_DEVICE,
127
+ UNMANGE_DEVICE,
128
+ SETTINGS,
129
+ CLEAR_PASSCODE,
130
+ UPDATE_INVENTORY,
131
+ ENABLE_DATA_ROAMING,
132
+ DISABLE_DATA_ROAMING,
133
+ ENABLE_VOICE_ROAMING,
134
+ DISABLE_VOICE_ROAMING,
135
+ PASSCODE_LOCK_GRACE_PERIOD
136
+ ].freeze
137
+
138
+ # The MDM commands applicable to supervised mobile devices
139
+ SUPERVISED_DEVICE_COMMANDS = [
140
+ WALLPAPER,
141
+ DEVICE_NAME,
142
+ SHUTDOWN_DEVICE,
143
+ RESTART_DEVICE,
144
+ CLEAR_RESTRICTIONS_PASSWORD,
145
+ ENABLE_LOST_MODE,
146
+ DISABLE_LOST_MODE,
147
+ DEVICE_LOCATION,
148
+ PLAY_LOST_MODE_SOUND,
149
+ ENABLE_APP_ANALYTICS,
150
+ DISABLE_APP_ANALYTICS,
151
+ ENABLE_DIAGNOSTIC_SUBMISSION,
152
+ DISABLE_DIAGNOSTIC_SUBMISSION
153
+ ].freeze
154
+
155
+ # The MDM commands applicable to mobile devices
156
+ DEVICE_COMMANDS = ALL_DEVICE_COMMANDS + SUPERVISED_DEVICE_COMMANDS
157
+
158
+ # Symbols that can be used to represent the commands to the
159
+ # {.send_mdm_command} Class method.
160
+ # Alternates are provided to match both the actual API command,
161
+ # and the command label in the JSS web UI, as well as common
162
+ # variants.
163
+ # e.g. the DeviceLock command in the API, is recognized as:
164
+ # :device_lock and :lock_device, and just :lock
165
+ #
166
+ COMMANDS = {
167
+
168
+ # all objects
169
+ blank_push: BLANK_PUSH,
170
+ send_blank_push: BLANK_PUSH,
171
+ noop: BLANK_PUSH,
172
+
173
+ device_lock: DEVICE_LOCK,
174
+ lock_device: DEVICE_LOCK,
175
+ lock: DEVICE_LOCK,
176
+
177
+ erase_device: ERASE_DEVICE,
178
+ wipe_device: ERASE_DEVICE,
179
+ wipe_computer: ERASE_DEVICE,
180
+ wipe: ERASE_DEVICE,
181
+ erase: ERASE_DEVICE,
182
+
183
+ unmanage_device: UNMANGE_DEVICE,
184
+ remove_mdm_profile: UNMANGE_DEVICE,
185
+
186
+ # computers only
187
+ unlock_user_account: UNLOCK_USER_ACCOUNT,
188
+
189
+ delete_user: DELETE_USER,
190
+
191
+ # mobile devices only
192
+ settings: SETTINGS, # not yet implemented as its own method
193
+
194
+ update_inventory: UPDATE_INVENTORY,
195
+ recon: UPDATE_INVENTORY,
196
+
197
+ clear_passcode: CLEAR_PASSCODE,
198
+
199
+ clear_restrictions_password: CLEAR_RESTRICTIONS_PASSWORD,
200
+
201
+ enable_data_roaming: ENABLE_DATA_ROAMING,
202
+ disable_data_roaming: DISABLE_DATA_ROAMING,
203
+
204
+ enable_voice_roaming: ENABLE_VOICE_ROAMING,
205
+ disable_voice_roaming: DISABLE_VOICE_ROAMING,
206
+
207
+ # supervized mobile devices only
208
+ device_name: DEVICE_NAME, # implemented as part of MobileDevice.name=
209
+
210
+ wallpaper: WALLPAPER,
211
+ set_wallpaper: WALLPAPER,
212
+
213
+ passcode_lock_grace_period: PASSCODE_LOCK_GRACE_PERIOD,
214
+
215
+ shut_down_device: SHUTDOWN_DEVICE,
216
+ shutdown_device: SHUTDOWN_DEVICE,
217
+ shut_down: SHUTDOWN_DEVICE,
218
+ shutdown: SHUTDOWN_DEVICE,
219
+
220
+ restart_device: RESTART_DEVICE,
221
+ restart: RESTART_DEVICE,
222
+
223
+ enable_app_analytics: ENABLE_APP_ANALYTICS,
224
+ disable_app_analytics: DISABLE_APP_ANALYTICS,
225
+
226
+ enable_diagnostic_submission: ENABLE_DIAGNOSTIC_SUBMISSION,
227
+ disable_diagnostic_submission: DISABLE_DIAGNOSTIC_SUBMISSION,
228
+
229
+ enable_lost_mode: ENABLE_LOST_MODE,
230
+ disable_lost_mode: DISABLE_LOST_MODE,
231
+
232
+ device_location: DEVICE_LOCATION, # not yet implemented as its own method
233
+
234
+ play_lost_mode_sound: PLAY_LOST_MODE_SOUND
235
+ }.freeze
236
+
237
+ ### Command Data
238
+
239
+ COMMAND_DATA = {
240
+ DEVICE_LOCK => :passcode, # 6 char passcode
241
+ ERASE_DEVICE => String, # 6 char passcode
242
+ DELETE_USER => String, # username
243
+ UNLOCK_USER_ACCOUNT => String, # username
244
+
245
+ }.freeze
246
+
247
+ WALLPAPER_LOCATIONS = {
248
+ lock_screen: 1,
249
+ home_screen: 2,
250
+ lock_and_home_screen: 3
251
+ }.freeze
252
+
253
+ ### Status
254
+
255
+ # the status to flush for 'pending'
256
+ PENDING_STATUS = 'Pending'.freeze
257
+
258
+ # the status to flush for 'failed'
259
+ FAILED_STATUS = 'Failed'.freeze
260
+
261
+ # the status to flush for both pending and failed
262
+ PENDINGFAILED_STATUS = 'Pending+Failed'.freeze
263
+
264
+ FLUSHABLE_STATUSES = {
265
+ pending: PENDING_STATUS,
266
+ failed: FAILED_STATUS,
267
+ pending_failed: PENDINGFAILED_STATUS
268
+ }.freeze
269
+
270
+ BLANK_PUSH_RESULT = 'Command sent'.freeze
271
+
272
+ # xml elements
273
+
274
+ GENERAL_ELEMENT = 'general'.freeze
275
+ COMMAND_ELEMENT = 'command'.freeze
276
+ TARGET_ID_ELEMENT = 'id'.freeze
277
+
278
+ COMPUTER_COMMAND_ELEMENT = 'computer_command'.freeze
279
+ COMPUTER_ID_ELEMENT = 'computer_id'.freeze
280
+ COMPUTER_COMMAND_UDID_ELEMENT = 'command_uuid'.freeze
281
+
282
+ DEVICE_COMMAND_ELEMENT = 'mobile_device_command'.freeze
283
+ DEVICE_LIST_ELEMENT = 'mobile_devices'.freeze
284
+ DEVICE_ID_ELEMENT = 'id'.freeze
285
+ DEVICE_COMMAND_STATUS_ELEMENT = 'status'.freeze
286
+
287
+ # Mixin Class Methods
288
+ ###########################
289
+
290
+ # See
291
+ # https://codereview.stackexchange.com/questions/23637/mixin-both-instance-and-class-methods-in-ruby
292
+ # for discussion of this technique for mixing in both
293
+ # Class and Instance methods when including a module.
294
+ #
295
+ module ClassMethods
296
+
297
+ # Send an MDM command to one or more targets without instantiating them.
298
+ #
299
+ # This general class method, and all the specific ones that all it, have
300
+ # matching instance methods. Use the class method when you don't have, or
301
+ # don't want to retrieve, instances of all the targets.
302
+ #
303
+ # If you do have an instance or a target, call the matching instance method
304
+ # to send commands to that specific target.
305
+ #
306
+ # @example send a blank push to mobiledevice id 12 without instantiating:
307
+ #
308
+ # JSS::MobileDevice.send_blank_push 12
309
+ #
310
+ # @example send a blank push to mobiledevice id 12 with instantiating:
311
+ #
312
+ # device = JSS::MobileDevice.fetch id: 12
313
+ # device.send_blank_push
314
+ #
315
+ # @example send a blank push to computers in computer groups
316
+ # 'SpecialMacs' and 'FooBarGroup'
317
+ #
318
+ # JSS::ComputerGroup.send_blank_push ['SpecialMacs', 'FooBarGroup']
319
+ #
320
+ # @param targets[String,Integer,Array<String,Integer>]
321
+ # the name or id of the device(s), or devicegroup(s) to receive the
322
+ # command, or an array of such names or ids. NOTE: when calling this on a
323
+ # Group class, the targets are the groups themselves, not the individual
324
+ # members - the membership will be expanded.
325
+ #
326
+ # @param command[Symbol] the command to send, one of the keys
327
+ # of COMMANDS
328
+ #
329
+ # @param opts[Hash] Some commands require extra data, e.g. a device name.
330
+ # Put it here
331
+ #
332
+ # @param api[JSS::APIConnection] the API connection to use. Defaults to the
333
+ # currently active API, see {JSS::APIConnection}
334
+ #
335
+ # @return [Hash{Integer=>String}] Keys are the target device ids.
336
+ # Values depend on the kind of target:
337
+ # - Computers will have the udid of the command sent to that computer.
338
+ # The udid can be used to later retrieve info about the command.
339
+ # - Mobile Devices seem to only have one command udid returned - for the
340
+ # last device to have the command sent to it. (even in the Database,
341
+ # not just in the API). So instead, the Hash value is the status of
342
+ # the command for that device, most often 'Command sent'
343
+ # Blank pushes do not generate return values, so Hash values are
344
+ # always 'Command sent' (an error will be raised if there are problems
345
+ # sending)
346
+ #
347
+ def send_mdm_command(targets, command, opts: {}, api: JSS.api)
348
+ command = validate_command(command)
349
+
350
+ rsrc = "#{send_command_rsrc}/command/#{command}"
351
+
352
+ targets = raw_targets_to_ids targets, api: api
353
+
354
+ cmd_xml = mdm_command_xml(command, opts, targets)
355
+
356
+ if JSS.devmode?
357
+ puts "Sending XML:\n"
358
+ REXML::Document.new(cmd_xml).write STDOUT, 2
359
+ puts "\n\nTo rsrc: #{rsrc}"
360
+ end
361
+
362
+ result = api.post_rsrc rsrc, cmd_xml
363
+
364
+ if command == BLANK_PUSH
365
+ hash = {}
366
+ targets.each { |t| hash[t] = BLANK_PUSH_RESULT }
367
+ elsif COMPUTER_TARGETS.include? self::MDM_COMMAND_TARGET
368
+ hash = process_computer_xml_result(result)
369
+ elsif DEVICE_TARGETS.include? self::MDM_COMMAND_TARGET
370
+ hash = process_mobiledevice_xml_result(result)
371
+ end
372
+
373
+ hash
374
+ end
375
+
376
+ # Convert the result of senting a computer MDM command into
377
+ # the appropriate hash
378
+ #
379
+ # @param result [String] The raw XML from POSTing a computer command
380
+ #
381
+ # @return (see #send_mdm_command)
382
+ #
383
+ def process_computer_xml_result(result)
384
+ hash = {}
385
+ REXML::Document.new(result).elements[COMPUTER_COMMAND_ELEMENT].each_element do |cmd|
386
+ compid = cmd.elements[COMPUTER_ID_ELEMENT].text.to_i
387
+ udid = cmd.elements[COMPUTER_COMMAND_UDID_ELEMENT].text
388
+ hash[compid] = udid
389
+ end
390
+ hash
391
+ end
392
+
393
+ # Convert the result of senting a device MDM command into
394
+ # the appropriate hash
395
+ #
396
+ # @param result [String] The raw XML from POSTing a device command
397
+ #
398
+ # @return (see #send_mdm_command)
399
+ #
400
+ def process_mobiledevice_xml_result(result)
401
+ hash = {}
402
+ mds = REXML::Document.new(result).elements[DEVICE_COMMAND_ELEMENT].elements[DEVICE_LIST_ELEMENT]
403
+ mds.each_element do |md|
404
+ id = md.elements[DEVICE_ID_ELEMENT].text.to_i
405
+ status = md.elements[DEVICE_COMMAND_STATUS_ELEMENT].text
406
+ hash[id] = status
407
+ end
408
+ hash
409
+ end
410
+
411
+ # The API rsrc for sending MDM commands to this kind of target
412
+ #
413
+ # @return [String] The API rsrc.
414
+ #
415
+ def send_command_rsrc
416
+ case self::MDM_COMMAND_TARGET
417
+ when *COMPUTER_TARGETS
418
+ COMPUTER_RSRC
419
+ when *DEVICE_TARGETS
420
+ DEVICE_RSRC
421
+ else
422
+ raise JSS::InvalidDataError, "Unknown MDM command target: #{self::MDM_COMMAND_TARGET}"
423
+ end
424
+ end
425
+
426
+ # Convert the targets provided for sending a command into
427
+ # the final list of computers or mobile devices.
428
+ #
429
+ # @param targets[String,Integer,Array] See {#send_mdm_command}
430
+ #
431
+ # @param expand_groups[Boolean] Should groups be expanded into member ids?
432
+ #
433
+ # @param api[JSS::APIConnection] an API connection to use.
434
+ #
435
+ # @return [Array<Integer>] The ids of the target devices for a command
436
+ #
437
+ def raw_targets_to_ids(targets, api: JSS.api, expand_groups: true)
438
+ targets = targets.is_a?(Array) ? targets : [targets]
439
+
440
+ # make sure its an array of ids
441
+ targets.map! do |md|
442
+ id = valid_id md, api: api
443
+ raise JSS::NoSuchItemError, "No #{self} matches identifier: #{md}" unless id
444
+ id
445
+ end # map!
446
+
447
+ # expand group members if needed
448
+ if expand_groups && GROUP_TARGETS.include?(self::MDM_COMMAND_TARGET)
449
+ target_ids = []
450
+ targets.each { |group_id| target_ids += fetch(id: group_id).member_ids }
451
+ targets = target_ids
452
+ end
453
+ targets
454
+ end
455
+
456
+ # Generate the XML to send to the API, sending the MDM command to the targets
457
+ #
458
+ # @param command [Symbol] the command to be sent, a key from COMMANDS
459
+ #
460
+ # @param options [Hash] different commands require different options,
461
+ # see each command method
462
+ #
463
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
464
+ #
465
+ # @return [String] The XML content to send to the API
466
+ #
467
+ def mdm_command_xml(command, options, targets)
468
+ raise JSS::MissingDataError, 'Targets cannot be empty' if targets.empty?
469
+
470
+ case self::MDM_COMMAND_TARGET
471
+ when *COMPUTER_TARGETS
472
+ command_elem = COMPUTER_COMMAND_ELEMENT
473
+ target_list_elem = JSS::Computer::RSRC_LIST_KEY.to_s
474
+ target_elem = JSS::Computer::RSRC_OBJECT_KEY.to_s
475
+ when *DEVICE_TARGETS
476
+ command_elem = DEVICE_COMMAND_ELEMENT
477
+ target_list_elem = JSS::MobileDevice::RSRC_LIST_KEY.to_s
478
+ target_elem = JSS::MobileDevice::RSRC_OBJECT_KEY.to_s
479
+ else
480
+ raise JSS::NoSuchItemError, "Unknonwn MDM command target: #{self::MDM_COMMAND_TARGET}"
481
+ end # case
482
+
483
+ xml = REXML::Document.new JSS::APIConnection::XML_HEADER
484
+ cmd_xml = xml.add_element command_elem
485
+
486
+ general = cmd_xml.add_element GENERAL_ELEMENT
487
+ general.add_element(COMMAND_ELEMENT).text = command
488
+ options.each do |opt, val|
489
+ general.add_element(opt.to_s).text = val.to_s
490
+ end # do opt val
491
+
492
+ tgt_list = cmd_xml.add_element target_list_elem
493
+ targets.each do |tgt_id|
494
+ tgt = tgt_list.add_element(target_elem)
495
+ tgt.add_element(TARGET_ID_ELEMENT).text = tgt_id.to_s
496
+ end
497
+
498
+ xml.to_s
499
+ end # self.mdm_command_xml(command, options)
500
+
501
+ # Validate that this command is known and can be sent to this kind of
502
+ # object, raising an error if not.
503
+ #
504
+ # @param command[Symbol] One of the symbolic commands as keys in COMMANDS
505
+ #
506
+ # @return [String] the matching value for the command symbol given
507
+ #
508
+ def validate_command(command)
509
+ raise JSS::NoSuchItemError, "Unknown command '#{command}'" unless COMMANDS.keys.include? command
510
+
511
+ command = COMMANDS[command]
512
+
513
+ case self::MDM_COMMAND_TARGET
514
+ when *COMPUTER_TARGETS
515
+ return command if COMPUTER_COMMANDS.include? command
516
+ raise JSS::UnsupportedError, "'#{command}' cannot be sent to computers or computer groups"
517
+ when *DEVICE_TARGETS
518
+ return command if DEVICE_COMMANDS.include? command
519
+ raise JSS::UnsupportedError, "'#{command}' cannot be sent to mobile devices or mobile device groups"
520
+ end
521
+
522
+ raise JSS::NoSuchItemError, "'#{command}' is known, but not available for computers or mobile devices. This is a bug. Please report it."
523
+ end
524
+
525
+ ###### The individual commands
526
+
527
+ # NOTE: not implementing Settings and Location until I know more what they do
528
+
529
+ # Commands for both computers and devices
530
+ ################################
531
+
532
+ # Send a blank push to one or more targets
533
+ #
534
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
535
+ #
536
+ # @param api[JSS::APIConnection] the API thru which to send the command
537
+ #
538
+ # @return (see .send_mdm_command)]
539
+ #
540
+ def blank_push(targets, api: JSS.api)
541
+ send_mdm_command targets, :blank_push, api: api
542
+ end
543
+ alias send_blank_push blank_push
544
+ alias noop blank_push
545
+
546
+ # Send a Device Lock to one or more targets
547
+ #
548
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
549
+ #
550
+ # @param passcode[String] a six-char passcode, required for computers & computergroups
551
+ #
552
+ # @param message[String] An optional message to display on mobiledevices & mobiledevicegroups
553
+ #
554
+ # @param api[JSS::APIConnection] the API thru which to send the command
555
+ #
556
+ # @return (see .send_mdm_command)
557
+ #
558
+ def device_lock(targets, passcode: '', message: nil, api: JSS.api)
559
+ case self::MDM_COMMAND_TARGET
560
+ when *COMPUTER_TARGETS
561
+ raise JSS::InvalidDataError, 'Locking computers requires a 6-character String passcode' unless passcode.size == 6
562
+ opts = { passcode: passcode }
563
+ when *DEVICE_TARGETS
564
+ opts = {}
565
+ opts[:lock_message] = message if message
566
+ end # case
567
+ send_mdm_command targets, :device_lock, opts: opts, api: api
568
+ end
569
+ alias lock_device device_lock
570
+ alias lock device_lock
571
+
572
+ # Send an Erase Device command to one or more targets
573
+ #
574
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
575
+ #
576
+ # @param passcode[String] a six-char passcode, required for computers & computergroups
577
+ #
578
+ # @param preserve_data_plan[Boolean] Should the data plan of the mobile device be preserved?
579
+ #
580
+ # @param api[JSS::APIConnection] the API thru which to send the command
581
+ #
582
+ # @return (see .send_mdm_command)
583
+ #
584
+ def erase_device(targets, passcode: '', preserve_data_plan: false, api: JSS.api)
585
+ case self::MDM_COMMAND_TARGET
586
+ when *COMPUTER_TARGETS
587
+ raise JSS::InvalidDataError, 'Erasing computers requires a 6-character String passcode' unless passcode.size == 6
588
+ opts = { passcode: passcode }
589
+ when *DEVICE_TARGETS
590
+ opts = {}
591
+ opts[:preserve_data_plan] = 'true' if preserve_data_plan
592
+ end # case
593
+ send_mdm_command targets, :erase_device, opts: opts, api: api
594
+ end
595
+ alias wipe erase_device
596
+ alias wipe_device erase_device
597
+ alias erase erase_device
598
+ alias wipe_computer erase_device
599
+
600
+ # Send an Unmanage Device command to one or more targets
601
+ #
602
+ # NOTE: when used with computers, the mdm profile will probably
603
+ # be re-installed immediately unless the computer is also no longer
604
+ # managed by Jamf Pro itself. To fully unmanage a computer, use
605
+ # the {JSS::Computer#make_unmanaged} instance method.
606
+ #
607
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
608
+ #
609
+ # @param api[JSS::APIConnection] the API thru which to send the command
610
+ #
611
+ # @return (see .send_mdm_command)
612
+ #
613
+ def unmanage_device(targets, api: JSS.api)
614
+ send_mdm_command targets, :unmanage_device, api: api
615
+ end
616
+ alias remove_mdm_profile unmanage_device
617
+
618
+ # Commands for computers only
619
+ ################################
620
+
621
+ # Send an unlock_user_account command to one or more targets
622
+ #
623
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
624
+ #
625
+ # @param user[String] the username of the acct to unlock
626
+ #
627
+ # @param api[JSS::APIConnection] the API thru which to send the command
628
+ #
629
+ # @return (see .send_mdm_command)
630
+ #
631
+ def unlock_user_account(targets, user, api: JSS.api)
632
+ send_mdm_command targets, :unlock_user_account, opts: { user_name: user }, api: api
633
+ end
634
+
635
+ # Send a delete_user command to one or more targets
636
+ #
637
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
638
+ #
639
+ # @param user[String] the username of the acct to delete
640
+ #
641
+ # @param api[JSS::APIConnection] the API thru which to send the command
642
+ #
643
+ # @return (see .send_mdm_command)
644
+ #
645
+ def delete_user(targets, user, api: JSS.api)
646
+ send_mdm_command targets, :delete_user, opts: { user_name: user }, api: api
647
+ end
648
+
649
+ # Commands for mobile devices only
650
+ ################################
651
+
652
+ # Send an update_inventory command to one or more targets
653
+ #
654
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
655
+ #
656
+ # @param api[JSS::APIConnection] the API thru which to send the command
657
+ #
658
+ # @return (see .send_mdm_command)
659
+ #
660
+ def update_inventory(targets, api: JSS.api)
661
+ send_mdm_command targets, :update_inventory, api: api
662
+ end
663
+ alias recon update_inventory
664
+
665
+ # Send an clear_passcode command to one or more targets
666
+ #
667
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
668
+ #
669
+ # @param api[JSS::APIConnection] the API thru which to send the command
670
+ #
671
+ # @return (see .send_mdm_command)
672
+ #
673
+ def clear_passcode(targets, api: JSS.api)
674
+ send_mdm_command targets, :clear_passcode, api: api
675
+ end
676
+
677
+ # Send an clear_restrictions_password command to one or more targets
678
+ #
679
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
680
+ #
681
+ # @param api[JSS::APIConnection] the API thru which to send the command
682
+ #
683
+ # @return (see .send_mdm_command)
684
+ #
685
+ def clear_restrictions_password(targets, api: JSS.api)
686
+ send_mdm_command targets, :clear_restrictions_password, api: api
687
+ end
688
+
689
+ # Send an enable_data_roaming command to one or more targets
690
+ #
691
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
692
+ #
693
+ # @param api[JSS::APIConnection] the API thru which to send the command
694
+ #
695
+ # @return (see .send_mdm_command)
696
+ #
697
+ def enable_data_roaming(targets, api: JSS.api)
698
+ send_mdm_command targets, :enable_data_roaming, api: api
699
+ end
700
+
701
+ # Send andisable_data_roaming command to one or more targets
702
+ #
703
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
704
+ #
705
+ # @param api[JSS::APIConnection] the API thru which to send the command
706
+ #
707
+ # @return (see .send_mdm_command)
708
+ #
709
+ def disable_data_roaming(targets, api: JSS.api)
710
+ send_mdm_command targets, :disable_data_roaming, api: api
711
+ end
712
+
713
+ # Send an enable_voice_roaming command to one or more targets
714
+ #
715
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
716
+ #
717
+ # @param api[JSS::APIConnection] the API thru which to send the command
718
+ #
719
+ # @return (see .send_mdm_command)
720
+ #
721
+ def enable_voice_roaming(targets, api: JSS.api)
722
+ send_mdm_command targets, :enable_voice_roaming, api: api
723
+ end
724
+
725
+ # Send a disable_voice_roaming command to one or more targets
726
+ #
727
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
728
+ #
729
+ # @param api[JSS::APIConnection] the API thru which to send the command
730
+ #
731
+ # @return (see .send_mdm_command)
732
+ #
733
+ def disable_voice_roaming(targets, api: JSS.api)
734
+ send_mdm_command targets, :disable_voice_roaming, api: api
735
+ end
736
+
737
+ # Commands for supervized mobile devices only
738
+ ################################
739
+
740
+ # Send a device_name command to one or more targets
741
+ #
742
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
743
+ #
744
+ # @param name[String] The new name
745
+ #
746
+ # @param api[JSS::APIConnection] the API thru which to send the command
747
+ #
748
+ # @return (see .send_mdm_command)
749
+ #
750
+ def device_name(targets, name, api: JSS.api)
751
+ send_mdm_command targets, :device_name, opts: { device_name: name }, api: api
752
+ end
753
+ alias set_name device_name
754
+
755
+ # Send a wallpaper command to one or more targets
756
+ #
757
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
758
+ #
759
+ # @param wallpaper_setting[Symbol] :lock_screen, :home_screen, or :lock_and_home_screen
760
+ #
761
+ # @param wallpaper_content[String,Pathname] The local path to a .png or .jpg to use
762
+ # as the walpaper image, required if no wallpaper_id
763
+ #
764
+ # @param wallpaper_id[Symbol] The id of an Icon in Jamf Pro to use as the wallpaper image,
765
+ # required if no wallpaper_content
766
+ #
767
+ # @param api[JSS::APIConnection] the API thru which to send the command
768
+ #
769
+ # @return (see .send_mdm_command)
770
+ #
771
+ def wallpaper(targets, wallpaper_setting: nil, wallpaper_content: nil, wallpaper_id: nil, api: JSS.api)
772
+ raise ArgumentError, "wallpaper_setting must be one of: :#{WALLPAPER_LOCATIONS.keys.join ', :'}" unless WALLPAPER_LOCATIONS.keys.include? wallpaper_setting
773
+
774
+ opts = { wallpaper_setting: WALLPAPER_LOCATIONS[wallpaper_setting] }
775
+
776
+ if wallpaper_content
777
+ file = Pathname.new wallpaper_content
778
+ raise JSS::NoSuchItemError, "Not a file: #{file}" unless file.file?
779
+ opts[:wallpaper_content] = Base64.encode64 file.read
780
+ elsif wallpaper_id
781
+ opts[:wallpaper_id] = wallpaper_id
782
+ else
783
+ raise ArgumentError, 'Either wallpaper_id: or wallpaper_content must be provided'
784
+ end
785
+
786
+ send_mdm_command targets, :wallpaper, opts: opts, api: api
787
+ end
788
+ alias set_wallpaper wallpaper
789
+
790
+ # Send a passcode_lock_grace_period command to one or more targets
791
+ #
792
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
793
+ #
794
+ # @param secs[Integer] The numer of seconds for the grace period
795
+ #
796
+ # @param api[JSS::APIConnection] the API thru which to send the command
797
+ #
798
+ # @return (see .send_mdm_command)
799
+ #
800
+ def passcode_lock_grace_period(targets, secs, api: JSS.api)
801
+ send_mdm_command targets, :passcode_lock_grace_period, opts: { passcode_lock_grace_period: secs }, api: api
802
+ end
803
+
804
+ # Send a shut_down_device command to one or more targets
805
+ #
806
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
807
+ #
808
+ # @param api[JSS::APIConnection] the API thru which to send the command
809
+ #
810
+ # @return (see .send_mdm_command)
811
+ #
812
+ def shut_down_device(targets, api: JSS.api)
813
+ send_mdm_command targets, :shut_down_device, api: api
814
+ end
815
+ alias shutdown_device shut_down_device
816
+ alias shut_down shut_down_device
817
+ alias shutdown shut_down_device
818
+
819
+ # Send a restart_device command to one or more targets
820
+ #
821
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
822
+ #
823
+ # @param api[JSS::APIConnection] the API thru which to send the command
824
+ #
825
+ # @return (see .send_mdm_command)
826
+ #
827
+ def restart_device(targets, api: JSS.api)
828
+ send_mdm_command targets, :restart_device, api: api
829
+ end
830
+ alias restart restart_device
831
+
832
+ # Send an enable_app_analytics command to one or more targets
833
+ #
834
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
835
+ #
836
+ # @param api[JSS::APIConnection] the API thru which to send the command
837
+ #
838
+ # @return (see .send_mdm_command)
839
+ #
840
+ def enable_app_analytics(targets, api: JSS.api)
841
+ send_mdm_command targets, :enable_app_analytics, api: api
842
+ end
843
+
844
+ # Send a disable_app_analytics command to one or more targets
845
+ #
846
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
847
+ #
848
+ # @param api[JSS::APIConnection] the API thru which to send the command
849
+ #
850
+ # @return (see .send_mdm_command)
851
+ #
852
+ def disable_app_analytics(targets, api: JSS.api)
853
+ send_mdm_command targets, :disable_app_analytics, api: api
854
+ end
855
+
856
+ # Send an enable_diagnostic_submission command to one or more targets
857
+ #
858
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
859
+ #
860
+ # @param api[JSS::APIConnection] the API thru which to send the command
861
+ #
862
+ # @return (see .send_mdm_command)
863
+ #
864
+ def enable_diagnostic_submission(targets, api: JSS.api)
865
+ send_mdm_command targets, :enable_diagnostic_submission, api: api
866
+ end
867
+
868
+ # Send a disable_diagnostic_submission command to one or more targets
869
+ #
870
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
871
+ #
872
+ # @param api[JSS::APIConnection] the API thru which to send the command
873
+ #
874
+ # @return (see .send_mdm_command)
875
+ #
876
+ def disable_diagnostic_submission(targets, api: JSS.api)
877
+ send_mdm_command targets, :disable_diagnostic_submission, api: api
878
+ end
879
+
880
+ # Send a enable_lost_mode command to one or more targets
881
+ #
882
+ # Either or both of message and phone number must be provided
883
+ #
884
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
885
+ #
886
+ # @param message[String] The message to display on the lock screen
887
+ #
888
+ # @param phone[String] The phone number to display on the lock screen
889
+ #
890
+ # @param footnote[String] Optional footnote to display on the lock screen
891
+ #
892
+ # @param play_sound[Boolean] Play a sound when entering lost mode
893
+ #
894
+ # @param enforce_lost_mode[Boolean] Re-enabled lost mode when re-enrolled after wipe.
895
+ #
896
+ # @param api[JSS::APIConnection] the API thru which to send the command
897
+ #
898
+ # @return (see .send_mdm_command)
899
+ #
900
+ def enable_lost_mode(
901
+ targets,
902
+ message: nil,
903
+ phone: nil,
904
+ footnote: nil,
905
+ play_sound: false,
906
+ enforce_lost_mode: true,
907
+ api: JSS.api
908
+ )
909
+ raise ArgumentError, 'Either message: or phone_number: must be provided' unless message || phone
910
+ opts = { always_enforce_lost_mode: enforce_lost_mode }
911
+ opts[:lost_mode_message] = message if message
912
+ opts[:lost_mode_phone] = phone if phone
913
+ opts[:lost_mode_footnote] = footnote if footnote
914
+ opts[:lost_mode_with_sound] = 'true' if play_sound
915
+
916
+ send_mdm_command targets, :enable_lost_mode, opts: opts, api: api
917
+ end
918
+
919
+ # Send a play_lost_mode_sound command to one or more targets
920
+ #
921
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
922
+ #
923
+ # @param api[JSS::APIConnection] the API thru which to send the command
924
+ #
925
+ # @return (see .send_mdm_command)
926
+ #
927
+ def play_lost_mode_sound(targets, api: JSS.api)
928
+ send_mdm_command targets, :play_lost_mode_sound, api: api
929
+ end
930
+
931
+ # Send a disable_lost_mode command to one or more targets
932
+ #
933
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
934
+ #
935
+ # @param api[JSS::APIConnection] the API thru which to send the command
936
+ #
937
+ # @return (see .send_mdm_command)
938
+ #
939
+ def disable_lost_mode(targets, api: JSS.api)
940
+ send_mdm_command targets, :disable_lost_mode, api: api
941
+ end
942
+
943
+ # Flushing Commands
944
+ ###############################
945
+
946
+ # Flush pending or failed commands on devices or groups
947
+ #
948
+ # @param targets[String,Integer,Array<String,Integer>]
949
+ # the name or id of the device or group to flush commands, or
950
+ # an array of such names or ids, or a comma-separated string
951
+ # of them. NOTE: when calling this on a Group class, the targets
952
+ # are the groups themselves, not the individual members.
953
+ #
954
+ # @param status[String] a key from {JSS::Commandable::FLUSHABLE_STATUSES}
955
+ #
956
+ # @param api[JSS::APIConnection] an API connection to use.
957
+ # Defaults to the corrently active API. See {JSS::APIConnection}
958
+ #
959
+ # @return [void]
960
+ #
961
+ def flush_mdm_commands(targets, status: nil, api: JSS.api)
962
+ raise JSS::InvalidDataError, "Status must be one of :#{FLUSHABLE_STATUSES.keys.join ', :'}" unless FLUSHABLE_STATUSES.keys.include? status
963
+
964
+ status = FLUSHABLE_STATUSES[status]
965
+
966
+ target_ids = raw_targets_to_ids targets, api: api, expand_groups: false
967
+
968
+ command_flush_rsrc = "commandflush/#{self::MDM_COMMAND_TARGET}/id"
969
+
970
+ flush_rsrc = "#{command_flush_rsrc}/#{target_ids.join ','}/status/#{status}"
971
+
972
+ puts "Sending API DELETE: #{flush_rsrc}" if JSS.devmode?
973
+
974
+ api.delete_rsrc flush_rsrc
975
+ end
976
+
977
+ end # module ClassMethods
978
+
979
+ # Extend ourself when included
980
+ # @see {JSS::MDM::ClassMethods}
981
+ def self.included(klass)
982
+ klass.extend JSS::MDM::ClassMethods
983
+ end
984
+
985
+ # Mixin Instance Methods
986
+ ###########################
987
+ # See https://codereview.stackexchange.com/questions/23637/mixin-both-instance-and-class-methods-in-ruby
988
+ # for discussion of this technique for mixing in both
989
+ # Class and Instance methods when including a module.
990
+
991
+ # Commands for both computers and devices
992
+ ################################
993
+
994
+ # Send a blank push to this object
995
+ #
996
+ # @return [void]
997
+ #
998
+ def blank_push
999
+ self.class.send_blank_push @id, api: @api
1000
+ end
1001
+ alias send_blank_push blank_push
1002
+ alias noop blank_push
1003
+
1004
+ # Send a dev lock to this object
1005
+ #
1006
+ # @param passcode_or_message[String] a six-char passcode, required for computers & computergroups
1007
+ # Or an optional message to display on mobiledevices & mobiledevicegroups
1008
+ #
1009
+ # @return (see .send_mdm_command)
1010
+ #
1011
+ def device_lock(passcode_or_message = '')
1012
+ self.class.device_lock @id, passcode: passcode_or_message, message: passcode_or_message, api: @api
1013
+ end
1014
+ alias lock device_lock
1015
+ alias lock_device device_lock
1016
+
1017
+ # Send an erase device command to this object
1018
+ #
1019
+ # @param passcode[String] a six-char passcode, required for computers & computergroups
1020
+ #
1021
+ # @return (see .send_mdm_command)
1022
+ #
1023
+ def erase_device(passcode = '', preserve_data_plan: false)
1024
+ self.class.erase_device @id, passcode: passcode, preserve_data_plan: preserve_data_plan, api: @api
1025
+ end
1026
+ alias wipe_device erase_device
1027
+ alias wipe_computer erase_device
1028
+ alias wipe erase_device
1029
+ alias erase erase_device
1030
+
1031
+ # Send an unmanage device command to this object
1032
+ #
1033
+ # NOTE: when used with computers, the mdm profile will probably
1034
+ # be re-installed immediately unless the computer is also no longer
1035
+ # managed by Jamf Pro itself. To fully unmanage a computer, use
1036
+ # the {JSS::Computer#make_unmanaged} instance method.
1037
+ #
1038
+ # @return (see .send_mdm_command)
1039
+ #
1040
+ def unmanage_device
1041
+ self.class.unmanage_device @id, api: @api
1042
+ end
1043
+ alias remove_mdm_profile unmanage_device
1044
+
1045
+ # Commands for computers only
1046
+ ################################
1047
+
1048
+ # Send an unlock_user_account command to this computer or group
1049
+ #
1050
+ # @param user[String] the username of the acct to unlock
1051
+ #
1052
+ # @return (see .send_mdm_command)
1053
+ #
1054
+ def unlock_user_account(user)
1055
+ self.class.unlock_user_account @id, user, api: @api
1056
+ end
1057
+
1058
+ # Send a delete_user command to this computer or group
1059
+ #
1060
+ # @param user[String] the username of the acct to delete
1061
+ #
1062
+ # @return (see .send_mdm_command)
1063
+ #
1064
+ def delete_user(user)
1065
+ self.class.delete_user @id, user, api: @api
1066
+ end
1067
+
1068
+ # Commands for mobile devices only
1069
+ ################################
1070
+ # mobile devices only
1071
+ # settings: SETTINGS,
1072
+
1073
+ # Send an update_inventory command to this object
1074
+ #
1075
+ # @return (see .send_mdm_command)
1076
+ #
1077
+ def update_inventory
1078
+ self.class.update_inventory @id, api: @api
1079
+ end
1080
+ alias recon update_inventory
1081
+
1082
+ # Send an clear_passcode command to this object
1083
+ #
1084
+ # @return (see .send_mdm_command)
1085
+ #
1086
+ def clear_passcode
1087
+ self.class.clear_passcode @id, api: @api
1088
+ end
1089
+
1090
+ # Send an clear_restrictions_password command to this object
1091
+ #
1092
+ # @return (see .send_mdm_command)
1093
+ #
1094
+ def clear_restrictions_password
1095
+ self.class.clear_restrictions_password @id, api: @api
1096
+ end
1097
+
1098
+ # Send an enable_data_roaming command to this object
1099
+ #
1100
+ # @return (see .send_mdm_command)
1101
+ #
1102
+ def enable_data_roaming
1103
+ self.class.enable_data_roaming @id, api: @api
1104
+ end
1105
+
1106
+ # Send a disable_data_roaming command to this object
1107
+ #
1108
+ # @return (see .send_mdm_command)
1109
+ #
1110
+ def disable_data_roaming
1111
+ self.class.disable_data_roaming @id, api: @api
1112
+ end
1113
+
1114
+ # Send an enable_voice_roaming command to this object
1115
+ #
1116
+ # @return (see .send_mdm_command)
1117
+ #
1118
+ def enable_voice_roaming
1119
+ self.class.enable_voice_roaming @id, api: @api
1120
+ end
1121
+
1122
+ # Send a disable_voice_roaming command to this object
1123
+ #
1124
+ # @return (see .send_mdm_command)
1125
+ #
1126
+ def disable_voice_roaming
1127
+ self.class.disable_voice_roaming @id, api: @api
1128
+ end
1129
+
1130
+ # Commands for supervized mobile devices only
1131
+ #
1132
+ # NOTE: DeviceName is sent to supervised devices when
1133
+ # their name is changed with #name= and they are then
1134
+ # updated in the JSS with #update/#save
1135
+ ################################
1136
+
1137
+ # Send a device_name command to this object
1138
+ #
1139
+ # @param name[String] The new name
1140
+ #
1141
+ # @return (see .send_mdm_command)
1142
+ #
1143
+ def device_name(name)
1144
+ self.class.device_name @id, name, api: @api
1145
+ end
1146
+ alias set_name device_name
1147
+
1148
+ # Send a wallpaper command to this object
1149
+ #
1150
+ # @param wallpaper_setting[Symbol] :lock_screen, :home_screen, or :lock_and_home_screen
1151
+ #
1152
+ # @param wallpaper_content[String,Pathname] The local path to a .png or .jpg to use
1153
+ # as the walpaper image, required if no wallpaper_id
1154
+ #
1155
+ # @param wallpaper_id[Symbol] The id of an Icon in Jamf Pro to use as the wallpaper image,
1156
+ # required if no wallpaper_content
1157
+ #
1158
+ # @return (see .send_mdm_command)
1159
+ #
1160
+ def wallpaper(wallpaper_setting: nil, wallpaper_content: nil, wallpaper_id: nil)
1161
+ self.class.wallpaper(
1162
+ @id,
1163
+ wallpaper_setting: wallpaper_setting,
1164
+ wallpaper_content: wallpaper_content,
1165
+ wallpaper_id: wallpaper_id,
1166
+ api: @api
1167
+ )
1168
+ end
1169
+ alias set_wallpaper wallpaper
1170
+
1171
+ # Send a passcode_lock_grace_period command to this object
1172
+ #
1173
+ # @param secs[Integer] The numer of seconds for the grace period
1174
+ #
1175
+ # @return (see .send_mdm_command)
1176
+ #
1177
+ def passcode_lock_grace_period(secs)
1178
+ self.class.passcode_lock_grace_period @id, secs, api: @api
1179
+ end
1180
+
1181
+ # Send a shut_down_device command to this object
1182
+ #
1183
+ # @return (see .send_mdm_command)
1184
+ #
1185
+ def shut_down_device
1186
+ self.class.shut_down_device @id, api: @api
1187
+ end
1188
+ alias shutdown_device shut_down_device
1189
+ alias shut_down shut_down_device
1190
+ alias shutdown shut_down_device
1191
+
1192
+ # Send a restart_device command to this object
1193
+ #
1194
+ # @return (see .send_mdm_command)
1195
+ #
1196
+ def restart_device
1197
+ self.class.restart_device @id, api: @api
1198
+ end
1199
+ alias restart restart_device
1200
+
1201
+ # Send an enable_app_analytics command to this object
1202
+ #
1203
+ # @return (see .send_mdm_command)
1204
+ #
1205
+ def enable_app_analytics
1206
+ self.class.enable_app_analytics @id, api: @api
1207
+ end
1208
+
1209
+ # Send a disable_app_analytics command to this object
1210
+ #
1211
+ # @return (see .send_mdm_command)
1212
+ #
1213
+ def disable_app_analytics
1214
+ self.class.disable_app_analytics @id, api: @api
1215
+ end
1216
+
1217
+ # Send an enable_diagnostic_submission command to this object
1218
+ #
1219
+ # @return (see .send_mdm_command)
1220
+ #
1221
+ def enable_diagnostic_submission
1222
+ self.class.enable_diagnostic_submission @id, api: @api
1223
+ end
1224
+
1225
+ # Send a disable_diagnostic_submission command to this object
1226
+ #
1227
+ # @return (see .send_mdm_command)
1228
+ #
1229
+ def disable_diagnostic_submission
1230
+ self.class.disable_diagnostic_submission @id, api: @api
1231
+ end
1232
+
1233
+ # Send a enable_lost_mode command to one or more targets
1234
+ #
1235
+ # Either or both of message and phone number must be provided
1236
+ #
1237
+ # @param message[String] The message to display on the lock screen
1238
+ #
1239
+ # @param phone_number[String] The phone number to display on the lock screen
1240
+ #
1241
+ # @param footnote[String] Optional footnote to display on the lock screen
1242
+ #
1243
+ # @param play_sound[Boolean] Play a sound when entering lost mode
1244
+ #
1245
+ # @param enforce_lost_mode[Boolean] Re-enabled lost mode when re-enrolled after wipe.
1246
+ #
1247
+ # @return (see .send_mdm_command)
1248
+ #
1249
+ def enable_lost_mode(
1250
+ message: nil,
1251
+ phone_number: nil,
1252
+ footnote: nil,
1253
+ enforce_lost_mode: true,
1254
+ play_sound: false
1255
+ )
1256
+ self.class.enable_lost_mode(
1257
+ @id,
1258
+ message: message,
1259
+ phone_number: phone_number,
1260
+ footnote: footnote,
1261
+ play_sound: play_sound,
1262
+ enforce_lost_mode: enforce_lost_mode,
1263
+ api: @api
1264
+ )
1265
+ end
1266
+
1267
+ # Send a play_lost_mode_sound command to this object
1268
+ #
1269
+ # @return (see .send_mdm_command)
1270
+ #
1271
+ def play_lost_mode_sound
1272
+ self.class.play_lost_mode_sound @id, api: @api
1273
+ end
1274
+
1275
+ # Send a disable_lost_mode command to this object
1276
+ #
1277
+ # @return (see .send_mdm_command)
1278
+ #
1279
+ def disable_lost_mode
1280
+ self.class.disable_lost_mode @id, api: @api
1281
+ end
1282
+
1283
+ # Flushing Commands
1284
+ ###############################
1285
+
1286
+ # flush pending and/or failed MDM commands for this object
1287
+ #
1288
+ # @param status[String] a key from {JSS::Commandable::FLUSHABLE_STATUSES}
1289
+ #
1290
+ # @return [void]
1291
+ #
1292
+ def flush_mdm_commands(status)
1293
+ self.class.flush_mdm_commands @id, status: status, api: @api
1294
+ end
1295
+
1296
+ end # module MDM
1297
+
1298
+ end # module