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