ruby-jss 4.2.4 → 5.0.0b1

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