ruby-jss 0.10.1 → 0.10.2a4

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.

@@ -0,0 +1,1268 @@
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 [Type] describe_command_here
459
+ # @param options [Type] describe_options_here
460
+ # @param targets [Type] describe_targets_here
461
+ # @return [String] The XML content to send to the API
462
+ #
463
+ def mdm_command_xml(command, options, targets)
464
+ raise JSS::MissingDataError, 'Targets cannot be empty' if targets.empty?
465
+
466
+ case self::MDM_COMMAND_TARGET
467
+ when *COMPUTER_TARGETS
468
+ command_elem = COMPUTER_COMMAND_ELEMENT
469
+ target_list_elem = JSS::Computer::RSRC_LIST_KEY.to_s
470
+ target_elem = JSS::Computer::RSRC_OBJECT_KEY.to_s
471
+ when *DEVICE_TARGETS
472
+ command_elem = DEVICE_COMMAND_ELEMENT
473
+ target_list_elem = JSS::MobileDevice::RSRC_LIST_KEY.to_s
474
+ target_elem = JSS::MobileDevice::RSRC_OBJECT_KEY.to_s
475
+ else
476
+ raise JSS::NoSuchItemError, "Unknonwn MDM command target: #{self::MDM_COMMAND_TARGET}"
477
+ end # case
478
+
479
+ xml = REXML::Document.new JSS::APIConnection::XML_HEADER
480
+ cmd_xml = xml.add_element command_elem
481
+
482
+ general = cmd_xml.add_element GENERAL_ELEMENT
483
+ general.add_element(COMMAND_ELEMENT).text = command
484
+ options.each do |opt, val|
485
+ general.add_element(opt.to_s).text = val.to_s
486
+ end # do opt val
487
+
488
+ tgt_list = cmd_xml.add_element target_list_elem
489
+ targets.each do |tgt_id|
490
+ tgt = tgt_list.add_element(target_elem)
491
+ tgt.add_element(TARGET_ID_ELEMENT).text = tgt_id.to_s
492
+ end
493
+
494
+ xml.to_s
495
+ end # self.mdm_command_xml(command, options)
496
+
497
+ # Validate that this command is known and can be sent to this kind of
498
+ # object, raising an error if not.
499
+ #
500
+ # @param command[Symbol] One of the symbolic commands as keys in COMMANDS
501
+ #
502
+ # @return [String] the matching value for the command symbol given
503
+ #
504
+ def validate_command(command)
505
+ raise JSS::NoSuchItemError, "Unknown command '#{command}'" unless COMMANDS.keys.include? command
506
+
507
+ command = COMMANDS[command]
508
+
509
+ case self::MDM_COMMAND_TARGET
510
+ when *COMPUTER_TARGETS
511
+ return command if COMPUTER_COMMANDS.include? command
512
+ raise JSS::UnsupportedError, "'#{command}' cannot be sent to computers or computer groups"
513
+ when *DEVICE_TARGETS
514
+ return command if DEVICE_COMMANDS.include? command
515
+ raise JSS::UnsupportedError, "'#{command}' cannot be sent to mobile devices or mobile device groups"
516
+ end
517
+
518
+ raise JSS::NoSuchItemError, "'#{command}' is known, but not available for computers or mobile devices. This is a bug. Please report it."
519
+ end
520
+
521
+ ###### The individual commands
522
+
523
+ # NOTE: not implementing Settings and Location until I know more what they do
524
+
525
+ # Commands for both computers and devices
526
+ ################################
527
+
528
+ # Send a blank push to one or more targets
529
+ #
530
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
531
+ #
532
+ # @param api[JSS::APIConnection] the API thru which to send the command
533
+ #
534
+ # @return (see .send_mdm_command)]
535
+ #
536
+ def blank_push(targets, api: JSS.api)
537
+ send_mdm_command targets, :blank_push, api: api
538
+ end
539
+ alias send_blank_push blank_push
540
+ alias noop blank_push
541
+
542
+ # Send a Device Lock to one or more targets
543
+ #
544
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
545
+ #
546
+ # @param passcode[String] a six-char passcode, required for computers & computergroups
547
+ #
548
+ # @param message[String] An optional message to display on mobiledevices & mobiledevicegroups
549
+ #
550
+ # @param api[JSS::APIConnection] the API thru which to send the command
551
+ #
552
+ # @return (see .send_mdm_command)
553
+ #
554
+ def device_lock(targets, passcode: '', message: nil, api: JSS.api)
555
+ case self::MDM_COMMAND_TARGET
556
+ when *COMPUTER_TARGETS
557
+ raise JSS::InvalidDataError, 'Locking computers requires a 6-character String passcode' unless passcode.size == 6
558
+ opts = { passcode: passcode }
559
+ when *DEVICE_TARGETS
560
+ opts = {}
561
+ opts[:lock_message] = message if message
562
+ end # case
563
+ send_mdm_command targets, :device_lock, opts: opts, api: api
564
+ end
565
+ alias lock_device device_lock
566
+ alias lock device_lock
567
+
568
+ # Send an Erase Device command to one or more targets
569
+ #
570
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
571
+ #
572
+ # @param passcode[String] a six-char passcode, required for computers & computergroups
573
+ #
574
+ # @param preserve_data_plan[Boolean] Should the data plan of the mobile device be preserved?
575
+ #
576
+ # @param api[JSS::APIConnection] the API thru which to send the command
577
+ #
578
+ # @return (see .send_mdm_command)
579
+ #
580
+ def erase_device(targets, passcode: '', preserve_data_plan: false, api: JSS.api)
581
+ case self::MDM_COMMAND_TARGET
582
+ when *COMPUTER_TARGETS
583
+ raise JSS::InvalidDataError, 'Erasing computers requires a 6-character String passcode' unless passcode.size == 6
584
+ opts = { passcode: passcode }
585
+ when *DEVICE_TARGETS
586
+ opts = {}
587
+ opts[:preserve_data_plan] = 'true' if preserve_data_plan
588
+ end # case
589
+ send_mdm_command targets, :erase_device, opts: opts, api: api
590
+ end
591
+ alias wipe erase_device
592
+ alias wipe_device erase_device
593
+ alias erase erase_device
594
+ alias wipe_computer erase_device
595
+
596
+ # Send an Unmanage Device command to one or more targets
597
+ #
598
+ # NOTE: when used with computers, the mdm profile will probably
599
+ # be re-installed immediately unless the computer is also no longer
600
+ # managed by Jamf Pro itself. To fully unmanage a computer, use
601
+ # the {JSS::Computer#make_unmanaged} instance method.
602
+ #
603
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
604
+ #
605
+ # @param api[JSS::APIConnection] the API thru which to send the command
606
+ #
607
+ # @return (see .send_mdm_command)
608
+ #
609
+ def unmanage_device(targets, api: JSS.api)
610
+ send_mdm_command targets, :unmanage_device, api: api
611
+ end
612
+ alias remove_mdm_profile unmanage_device
613
+
614
+ # Commands for computers only
615
+ ################################
616
+
617
+ # Send an unlock_user_account command to one or more targets
618
+ #
619
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
620
+ #
621
+ # @param user[String] the username of the acct to unlock
622
+ #
623
+ # @param api[JSS::APIConnection] the API thru which to send the command
624
+ #
625
+ # @return (see .send_mdm_command)
626
+ #
627
+ def unlock_user_account(targets, user, api: JSS.api)
628
+ send_mdm_command targets, :unlock_user_account, opts: { user_name: user }, api: api
629
+ end
630
+
631
+ # Send a delete_user command to one or more targets
632
+ #
633
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
634
+ #
635
+ # @param user[String] the username of the acct to delete
636
+ #
637
+ # @param api[JSS::APIConnection] the API thru which to send the command
638
+ #
639
+ # @return (see .send_mdm_command)
640
+ #
641
+ def delete_user(targets, user, api: JSS.api)
642
+ send_mdm_command targets, :delete_user, opts: { user_name: user }, api: api
643
+ end
644
+
645
+ # Commands for mobile devices only
646
+ ################################
647
+
648
+ # Send an update_inventory command to one or more targets
649
+ #
650
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
651
+ #
652
+ # @param api[JSS::APIConnection] the API thru which to send the command
653
+ #
654
+ # @return (see .send_mdm_command)
655
+ #
656
+ def update_inventory(targets, api: JSS.api)
657
+ send_mdm_command targets, :update_inventory, api: api
658
+ end
659
+ alias recon update_inventory
660
+
661
+ # Send an clear_passcode command to one or more targets
662
+ #
663
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
664
+ #
665
+ # @param api[JSS::APIConnection] the API thru which to send the command
666
+ #
667
+ # @return (see .send_mdm_command)
668
+ #
669
+ def clear_passcode(targets, api: JSS.api)
670
+ send_mdm_command targets, :clear_passcode, api: api
671
+ end
672
+
673
+ # Send an clear_restrictions_password command to one or more targets
674
+ #
675
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
676
+ #
677
+ # @param api[JSS::APIConnection] the API thru which to send the command
678
+ #
679
+ # @return (see .send_mdm_command)
680
+ #
681
+ def clear_restrictions_password(targets, api: JSS.api)
682
+ send_mdm_command targets, :clear_restrictions_password, api: api
683
+ end
684
+
685
+ # Send an enable_data_roaming command to one or more targets
686
+ #
687
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
688
+ #
689
+ # @param api[JSS::APIConnection] the API thru which to send the command
690
+ #
691
+ # @return (see .send_mdm_command)
692
+ #
693
+ def enable_data_roaming(targets, api: JSS.api)
694
+ send_mdm_command targets, :enable_data_roaming, api: api
695
+ end
696
+
697
+ # Send andisable_data_roaming command to one or more targets
698
+ #
699
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
700
+ #
701
+ # @param api[JSS::APIConnection] the API thru which to send the command
702
+ #
703
+ # @return (see .send_mdm_command)
704
+ #
705
+ def disable_data_roaming(targets, api: JSS.api)
706
+ send_mdm_command targets, :disable_data_roaming, api: api
707
+ end
708
+
709
+ # Send an enable_voice_roaming command to one or more targets
710
+ #
711
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
712
+ #
713
+ # @param api[JSS::APIConnection] the API thru which to send the command
714
+ #
715
+ # @return (see .send_mdm_command)
716
+ #
717
+ def enable_voice_roaming(targets, api: JSS.api)
718
+ send_mdm_command targets, :enable_voice_roaming, api: api
719
+ end
720
+
721
+ # Send a disable_voice_roaming command to one or more targets
722
+ #
723
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
724
+ #
725
+ # @param api[JSS::APIConnection] the API thru which to send the command
726
+ #
727
+ # @return (see .send_mdm_command)
728
+ #
729
+ def disable_voice_roaming(targets, api: JSS.api)
730
+ send_mdm_command targets, :disable_voice_roaming, api: api
731
+ end
732
+
733
+ # Commands for supervized mobile devices only
734
+ ################################
735
+
736
+ # Send a wallpaper command to one or more targets
737
+ #
738
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
739
+ #
740
+ # @param wallpaper_setting[Symbol] :lock_screen, :home_screen, or :lock_and_home_screen
741
+ #
742
+ # @param wallpaper_content[String,Pathname] The local path to a .png or .jpg to use
743
+ # as the walpaper image, required if no wallpaper_id
744
+ #
745
+ # @param wallpaper_id[Symbol] The id of an Icon in Jamf Pro to use as the wallpaper image,
746
+ # required if no wallpaper_content
747
+ #
748
+ # @param api[JSS::APIConnection] the API thru which to send the command
749
+ #
750
+ # @return (see .send_mdm_command)
751
+ #
752
+ def wallpaper(targets, wallpaper_setting: nil, wallpaper_content: nil, wallpaper_id: nil, api: JSS.api)
753
+ raise ArgumentError, "wallpaper_setting must be one of: :#{WALLPAPER_LOCATIONS.keys.join ', :'}" unless WALLPAPER_LOCATIONS.keys.include? wallpaper_setting
754
+
755
+ opts = { wallpaper_setting: WALLPAPER_LOCATIONS[wallpaper_setting] }
756
+
757
+ if wallpaper_content
758
+ file = Pathname.new wallpaper_content
759
+ raise JSS::NoSuchItemError, "Not a file: #{file}" unless file.file?
760
+ opts[:wallpaper_content] = Base64.encode64 file.read
761
+ elsif wallpaper_id
762
+ opts[:wallpaper_id] = wallpaper_id
763
+ else
764
+ raise ArgumentError, 'Either wallpaper_id: or wallpaper_content must be provided'
765
+ end
766
+
767
+ send_mdm_command targets, :wallpaper, opts: opts, api: api
768
+ end
769
+ alias set_wallpaper wallpaper
770
+
771
+ # Send a passcode_lock_grace_period command to one or more targets
772
+ #
773
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
774
+ #
775
+ # @param secs[Integer] The numer of seconds for the grace period
776
+ #
777
+ # @param api[JSS::APIConnection] the API thru which to send the command
778
+ #
779
+ # @return (see .send_mdm_command)
780
+ #
781
+ def passcode_lock_grace_period(targets, secs, api: JSS.api)
782
+ send_mdm_command targets, :passcode_lock_grace_period, opts: { passcode_lock_grace_period: secs }, api: api
783
+ end
784
+
785
+ # Send a shut_down_device command to one or more targets
786
+ #
787
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
788
+ #
789
+ # @param api[JSS::APIConnection] the API thru which to send the command
790
+ #
791
+ # @return (see .send_mdm_command)
792
+ #
793
+ def shut_down_device(targets, api: JSS.api)
794
+ send_mdm_command targets, :shut_down_device, api: api
795
+ end
796
+ alias shutdown_device shut_down_device
797
+ alias shut_down shut_down_device
798
+ alias shutdown shut_down_device
799
+
800
+ # Send a restart_device command to one or more targets
801
+ #
802
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
803
+ #
804
+ # @param api[JSS::APIConnection] the API thru which to send the command
805
+ #
806
+ # @return (see .send_mdm_command)
807
+ #
808
+ def restart_device(targets, api: JSS.api)
809
+ send_mdm_command targets, :restart_device, api: api
810
+ end
811
+ alias restart restart_device
812
+
813
+ # Send an enable_app_analytics command to one or more targets
814
+ #
815
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
816
+ #
817
+ # @param api[JSS::APIConnection] the API thru which to send the command
818
+ #
819
+ # @return (see .send_mdm_command)
820
+ #
821
+ def enable_app_analytics(targets, api: JSS.api)
822
+ send_mdm_command targets, :enable_app_analytics, api: api
823
+ end
824
+
825
+ # Send a disable_app_analytics command to one or more targets
826
+ #
827
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
828
+ #
829
+ # @param api[JSS::APIConnection] the API thru which to send the command
830
+ #
831
+ # @return (see .send_mdm_command)
832
+ #
833
+ def disable_app_analytics(targets, api: JSS.api)
834
+ send_mdm_command targets, :disable_app_analytics, api: api
835
+ end
836
+
837
+ # Send an enable_diagnostic_submission command to one or more targets
838
+ #
839
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
840
+ #
841
+ # @param api[JSS::APIConnection] the API thru which to send the command
842
+ #
843
+ # @return (see .send_mdm_command)
844
+ #
845
+ def enable_diagnostic_submission(targets, api: JSS.api)
846
+ send_mdm_command targets, :enable_diagnostic_submission, api: api
847
+ end
848
+
849
+ # Send a disable_diagnostic_submission command to one or more targets
850
+ #
851
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
852
+ #
853
+ # @param api[JSS::APIConnection] the API thru which to send the command
854
+ #
855
+ # @return (see .send_mdm_command)
856
+ #
857
+ def disable_diagnostic_submission(targets, api: JSS.api)
858
+ send_mdm_command targets, :disable_diagnostic_submission, api: api
859
+ end
860
+
861
+ # Send a enable_lost_mode command to one or more targets
862
+ #
863
+ # Either or both of message and phone number must be provided
864
+ #
865
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
866
+ #
867
+ # @param message[String] The message to display on the lock screen
868
+ #
869
+ # @param phone[String] The phone number to display on the lock screen
870
+ #
871
+ # @param footnote[String] Optional footnote to display on the lock screen
872
+ #
873
+ # @param play_sound[Boolean] Play a sound when entering lost mode
874
+ #
875
+ # @param enforce_lost_mode[Boolean] Re-enabled lost mode when re-enrolled after wipe.
876
+ #
877
+ # @param api[JSS::APIConnection] the API thru which to send the command
878
+ #
879
+ # @return (see .send_mdm_command)
880
+ #
881
+ def enable_lost_mode(
882
+ targets,
883
+ message: nil,
884
+ phone: nil,
885
+ footnote: nil,
886
+ play_sound: false,
887
+ enforce_lost_mode: true,
888
+ api: JSS.api
889
+ )
890
+ raise ArgumentError, 'Either message: or phone_number: must be provided' unless message || phone
891
+ opts = { always_enforce_lost_mode: enforce_lost_mode }
892
+ opts[:lost_mode_message] = message if message
893
+ opts[:lost_mode_phone] = phone if phone
894
+ opts[:lost_mode_footnote] = footnote if footnote
895
+ opts[:lost_mode_with_sound] = 'true' if play_sound
896
+
897
+ send_mdm_command targets, :enable_lost_mode, opts: opts, api: api
898
+ end
899
+
900
+ # Send a play_lost_mode_sound command to one or more targets
901
+ #
902
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
903
+ #
904
+ # @param api[JSS::APIConnection] the API thru which to send the command
905
+ #
906
+ # @return (see .send_mdm_command)
907
+ #
908
+ def play_lost_mode_sound(targets, api: JSS.api)
909
+ send_mdm_command targets, :play_lost_mode_sound, api: api
910
+ end
911
+
912
+ # Send a disable_lost_mode command to one or more targets
913
+ #
914
+ # @param targets[String,Integer,Array<String,Integer>] @see .send_mdm_command
915
+ #
916
+ # @param api[JSS::APIConnection] the API thru which to send the command
917
+ #
918
+ # @return (see .send_mdm_command)
919
+ #
920
+ def disable_lost_mode(targets, api: JSS.api)
921
+ send_mdm_command targets, :disable_lost_mode, api: api
922
+ end
923
+
924
+ # Flushing Commands
925
+ ###############################
926
+
927
+ # Flush pending or failed commands on devices or groups
928
+ #
929
+ # @param targets[String,Integer,Array<String,Integer>]
930
+ # the name or id of the device or group to flush commands, or
931
+ # an array of such names or ids, or a comma-separated string
932
+ # of them. NOTE: when calling this on a Group class, the targets
933
+ # are the groups themselves, not the individual members.
934
+ #
935
+ # @param status[String] a key from {JSS::Commandable::FLUSHABLE_STATUSES}
936
+ #
937
+ # @param api[JSS::APIConnection] an API connection to use.
938
+ # Defaults to the corrently active API. See {JSS::APIConnection}
939
+ #
940
+ # @return [void]
941
+ #
942
+ def flush_mdm_commands(targets, status: nil, api: JSS.api)
943
+ raise JSS::InvalidDataError, "Status must be one of :#{FLUSHABLE_STATUSES.keys.join ', :'}" unless FLUSHABLE_STATUSES.keys.include? status
944
+
945
+ status = FLUSHABLE_STATUSES[status]
946
+
947
+ target_ids = raw_targets_to_ids targets, api: api, expand_groups: false
948
+
949
+ command_flush_rsrc = "commandflush/#{self::MDM_COMMAND_TARGET}/id"
950
+
951
+ flush_rsrc = "#{command_flush_rsrc}/#{target_ids.join ','}/status/#{status}"
952
+
953
+ puts "Sending API DELETE: #{flush_rsrc}" if JSS.devmode?
954
+
955
+ api.delete_rsrc flush_rsrc
956
+ end
957
+
958
+ end # module ClassMethods
959
+
960
+ # Extend ourself when included
961
+ # @see {JSS::MDM::ClassMethods}
962
+ def self.included(klass)
963
+ klass.extend JSS::MDM::ClassMethods
964
+ end
965
+
966
+ # Mixin Instance Methods
967
+ ###########################
968
+ # See https://codereview.stackexchange.com/questions/23637/mixin-both-instance-and-class-methods-in-ruby
969
+ # for discussion of this technique for mixing in both
970
+ # Class and Instance methods when including a module.
971
+
972
+ # Commands for both computers and devices
973
+ ################################
974
+
975
+ # Send a blank push to this object
976
+ #
977
+ # @return [void]
978
+ #
979
+ def blank_push
980
+ self.class.send_blank_push @id, api: @api
981
+ end
982
+ alias send_blank_push blank_push
983
+ alias noop blank_push
984
+
985
+ # Send a dev lock to this object
986
+ #
987
+ # @param passcode_or_message[String] a six-char passcode, required for computers & computergroups
988
+ # Or an optional message to display on mobiledevices & mobiledevicegroups
989
+ #
990
+ # @return (see .send_mdm_command)
991
+ #
992
+ def device_lock(passcode_or_message = '')
993
+ self.class.device_lock @id, passcode: passcode_or_message, message: passcode_or_message, api: @api
994
+ end
995
+ alias lock device_lock
996
+ alias lock_device device_lock
997
+
998
+ # Send an erase device command to this object
999
+ #
1000
+ # @param passcode[String] a six-char passcode, required for computers & computergroups
1001
+ #
1002
+ # @return (see .send_mdm_command)
1003
+ #
1004
+ def erase_device(passcode = '', preserve_data_plan: false)
1005
+ self.class.erase_device @id, passcode: passcode, preserve_data_plan: preserve_data_plan, api: @api
1006
+ end
1007
+ alias wipe_device erase_device
1008
+ alias wipe_computer erase_device
1009
+ alias wipe erase_device
1010
+ alias erase erase_device
1011
+
1012
+ # Send an unmanage device command to this object
1013
+ #
1014
+ # NOTE: when used with computers, the mdm profile will probably
1015
+ # be re-installed immediately unless the computer is also no longer
1016
+ # managed by Jamf Pro itself. To fully unmanage a computer, use
1017
+ # the {JSS::Computer#make_unmanaged} instance method.
1018
+ #
1019
+ # @return (see .send_mdm_command)
1020
+ #
1021
+ def unmanage_device
1022
+ self.class.unmanage_device @id, api: @api
1023
+ end
1024
+ alias remove_mdm_profile unmanage_device
1025
+
1026
+ # Commands for computers only
1027
+ ################################
1028
+
1029
+ # Send an unlock_user_account command to this computer or group
1030
+ #
1031
+ # @param user[String] the username of the acct to unlock
1032
+ #
1033
+ # @return (see .send_mdm_command)
1034
+ #
1035
+ def unlock_user_account(user)
1036
+ self.class.unlock_user_account @id, user, api: @api
1037
+ end
1038
+
1039
+ # Send a delete_user command to this computer or group
1040
+ #
1041
+ # @param user[String] the username of the acct to delete
1042
+ #
1043
+ # @return (see .send_mdm_command)
1044
+ #
1045
+ def delete_user(user)
1046
+ self.class.delete_user @id, user, api: @api
1047
+ end
1048
+
1049
+ # Commands for mobile devices only
1050
+ ################################
1051
+ # mobile devices only
1052
+ # settings: SETTINGS,
1053
+
1054
+ # Send an update_inventory command to this object
1055
+ #
1056
+ # @return (see .send_mdm_command)
1057
+ #
1058
+ def update_inventory
1059
+ self.class.update_inventory @id, api: @api
1060
+ end
1061
+ alias recon update_inventory
1062
+
1063
+ # Send an clear_passcode command to this object
1064
+ #
1065
+ # @return (see .send_mdm_command)
1066
+ #
1067
+ def clear_passcode
1068
+ self.class.clear_passcode @id, api: @api
1069
+ end
1070
+
1071
+ # Send an clear_restrictions_password command to this object
1072
+ #
1073
+ # @return (see .send_mdm_command)
1074
+ #
1075
+ def clear_restrictions_password
1076
+ self.class.clear_restrictions_password @id, api: @api
1077
+ end
1078
+
1079
+ # Send an enable_data_roaming command to this object
1080
+ #
1081
+ # @return (see .send_mdm_command)
1082
+ #
1083
+ def enable_data_roaming
1084
+ self.class.enable_data_roaming @id, api: @api
1085
+ end
1086
+
1087
+ # Send a disable_data_roaming command to this object
1088
+ #
1089
+ # @return (see .send_mdm_command)
1090
+ #
1091
+ def disable_data_roaming
1092
+ self.class.disable_data_roaming @id, api: @api
1093
+ end
1094
+
1095
+ # Send an enable_voice_roaming command to this object
1096
+ #
1097
+ # @return (see .send_mdm_command)
1098
+ #
1099
+ def enable_voice_roaming
1100
+ self.class.enable_voice_roaming @id, api: @api
1101
+ end
1102
+
1103
+ # Send a disable_voice_roaming command to this object
1104
+ #
1105
+ # @return (see .send_mdm_command)
1106
+ #
1107
+ def disable_voice_roaming
1108
+ self.class.disable_voice_roaming @id, api: @api
1109
+ end
1110
+
1111
+ # Commands for supervized mobile devices only
1112
+ #
1113
+ # NOTE: DeviceName is sent to supervised devices when
1114
+ # their name is changed with #name= and they are then
1115
+ # updated in the JSS with #update/#save
1116
+ ################################
1117
+
1118
+ # Send a wallpaper command to this object
1119
+ #
1120
+ # @param wallpaper_setting[Symbol] :lock_screen, :home_screen, or :lock_and_home_screen
1121
+ #
1122
+ # @param wallpaper_content[String,Pathname] The local path to a .png or .jpg to use
1123
+ # as the walpaper image, required if no wallpaper_id
1124
+ #
1125
+ # @param wallpaper_id[Symbol] The id of an Icon in Jamf Pro to use as the wallpaper image,
1126
+ # required if no wallpaper_content
1127
+ #
1128
+ # @return (see .send_mdm_command)
1129
+ #
1130
+ def wallpaper(wallpaper_setting: nil, wallpaper_content: nil, wallpaper_id: nil)
1131
+ self.class.wallpaper(
1132
+ @id,
1133
+ wallpaper_setting: wallpaper_setting,
1134
+ wallpaper_content: wallpaper_content,
1135
+ wallpaper_id: wallpaper_id,
1136
+ api: @api
1137
+ )
1138
+ end
1139
+ alias set_wallpaper wallpaper
1140
+
1141
+ # Send a passcode_lock_grace_period command to this object
1142
+ #
1143
+ # @param secs[Integer] The numer of seconds for the grace period
1144
+ #
1145
+ # @return (see .send_mdm_command)
1146
+ #
1147
+ def passcode_lock_grace_period(secs)
1148
+ self.class.passcode_lock_grace_period @id, secs, api: @api
1149
+ end
1150
+
1151
+ # Send a shut_down_device command to this object
1152
+ #
1153
+ # @return (see .send_mdm_command)
1154
+ #
1155
+ def shut_down_device
1156
+ self.class.shut_down_device @id, api: @api
1157
+ end
1158
+ alias shutdown_device shut_down_device
1159
+ alias shut_down shut_down_device
1160
+ alias shutdown shut_down_device
1161
+
1162
+ # Send a restart_device command to this object
1163
+ #
1164
+ # @return (see .send_mdm_command)
1165
+ #
1166
+ def restart_device
1167
+ self.class.restart_device @id, api: @api
1168
+ end
1169
+ alias restart restart_device
1170
+
1171
+ # Send an enable_app_analytics command to this object
1172
+ #
1173
+ # @return (see .send_mdm_command)
1174
+ #
1175
+ def enable_app_analytics
1176
+ self.class.enable_app_analytics @id, api: @api
1177
+ end
1178
+
1179
+ # Send a disable_app_analytics command to this object
1180
+ #
1181
+ # @return (see .send_mdm_command)
1182
+ #
1183
+ def disable_app_analytics
1184
+ self.class.disable_app_analytics @id, api: @api
1185
+ end
1186
+
1187
+ # Send an enable_diagnostic_submission command to this object
1188
+ #
1189
+ # @return (see .send_mdm_command)
1190
+ #
1191
+ def enable_diagnostic_submission
1192
+ self.class.enable_diagnostic_submission @id, api: @api
1193
+ end
1194
+
1195
+ # Send a disable_diagnostic_submission command to this object
1196
+ #
1197
+ # @return (see .send_mdm_command)
1198
+ #
1199
+ def disable_diagnostic_submission
1200
+ self.class.disable_diagnostic_submission @id, api: @api
1201
+ end
1202
+
1203
+ # Send a enable_lost_mode command to one or more targets
1204
+ #
1205
+ # Either or both of message and phone number must be provided
1206
+ #
1207
+ # @param message[String] The message to display on the lock screen
1208
+ #
1209
+ # @param phone_number[String] The phone number to display on the lock screen
1210
+ #
1211
+ # @param footnote[String] Optional footnote to display on the lock screen
1212
+ #
1213
+ # @param play_sound[Boolean] Play a sound when entering lost mode
1214
+ #
1215
+ # @param enforce_lost_mode[Boolean] Re-enabled lost mode when re-enrolled after wipe.
1216
+ #
1217
+ # @return (see .send_mdm_command)
1218
+ #
1219
+ def enable_lost_mode(
1220
+ message: nil,
1221
+ phone_number: nil,
1222
+ footnote: nil,
1223
+ enforce_lost_mode: true,
1224
+ play_sound: false
1225
+ )
1226
+ self.class.enable_lost_mode(
1227
+ @id,
1228
+ message: message,
1229
+ phone_number: phone_number,
1230
+ footnote: footnote,
1231
+ play_sound: play_sound,
1232
+ enforce_lost_mode: enforce_lost_mode,
1233
+ api: @api
1234
+ )
1235
+ end
1236
+
1237
+ # Send a play_lost_mode_sound command to this object
1238
+ #
1239
+ # @return (see .send_mdm_command)
1240
+ #
1241
+ def play_lost_mode_sound
1242
+ self.class.play_lost_mode_sound @id, api: @api
1243
+ end
1244
+
1245
+ # Send a disable_lost_mode command to this object
1246
+ #
1247
+ # @return (see .send_mdm_command)
1248
+ #
1249
+ def disable_lost_mode
1250
+ self.class.disable_lost_mode @id, api: @api
1251
+ end
1252
+
1253
+ # Flushing Commands
1254
+ ###############################
1255
+
1256
+ # flush pending and/or failed MDM commands for this object
1257
+ #
1258
+ # @param status[String] a key from {JSS::Commandable::FLUSHABLE_STATUSES}
1259
+ #
1260
+ # @return [void]
1261
+ #
1262
+ def flush_mdm_commands(status)
1263
+ self.class.flush_mdm_commands @id, status: status, api: @api
1264
+ end
1265
+
1266
+ end # module MDM
1267
+
1268
+ end # module