forked from grahampugh/jamf-upload
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjamf_softwarerestriction_upload.py
executable file
·274 lines (238 loc) · 8.06 KB
/
jamf_softwarerestriction_upload.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#!/usr/bin/env python3
"""
** Jamf Software Restriction Upload Script
by G Pugh
Credentials can be supplied from the command line as arguments, or inputted, or
from an existing PLIST containing values for JSS_URL, API_USERNAME and API_PASSWORD,
for example an AutoPkg preferences file which has been configured for use with
JSSImporter: ~/Library/Preferences/com.github.autopkg
Note that criteria containing dependent computer groups can only be set if those groups
already exist. This script will not create them. Ensure you script in a logical order
to build up the dependencies in turn.
For usage, run jamf_softwarerestriction_upload.py --help
"""
import argparse
import os
import re
from time import sleep
from jamf_upload_lib import actions, api_connect, api_get, curl
def get_restriction_name(template_contents, verbosity):
"""Determine software restriction name from template - used when no name is supplied in CLI"""
regex_search = "<name>.*</name>"
result = re.search(regex_search, template_contents)[0]
print(result)
if result:
restriction_name = re.sub("<name>", "", result, 1)
restriction_name = re.sub("</name>", "", restriction_name, 1)
else:
restriction_name = ""
return restriction_name
def replace_restriction_name(restriction_name, template_contents, verbosity):
"""Write restriction name to template - used when name is supplied in CLI"""
if verbosity:
print(
"Replacing computer restriction name '{}' in XML".format(restriction_name)
)
regex_search = "<name>.*</name>"
regex_replace = "<name>{}</name>".format(restriction_name)
template_contents = re.sub(regex_search, regex_replace, template_contents, 1)
return template_contents
def upload_restriction(
jamf_url,
enc_creds,
restriction_name,
template_contents,
cli_custom_keys,
verbosity,
obj_id=None,
):
"""Upload software restriction"""
# if we find an object ID we put, if not, we post
if obj_id:
url = "{}/JSSResource/restrictedsoftware/id/{}".format(jamf_url, obj_id)
else:
url = "{}/JSSResource/restrictedsoftware/id/0".format(jamf_url)
if verbosity > 2:
print("Software Restriction data:")
print(template_contents)
print("Uploading Software Restriction...")
# write the template to temp file
template_xml = curl.write_temp_file(template_contents)
count = 0
while True:
count += 1
if verbosity > 1:
print("Software Restriction upload attempt {}".format(count))
method = "PUT" if obj_id else "POST"
r = curl.request(method, url, enc_creds, verbosity, template_xml)
# check HTTP response
if curl.status_check(r, "Software Restriction", restriction_name) == "break":
break
if count > 5:
print(
"WARNING: Software Restriction upload did not succeed after 5 attempts"
)
print("\nHTTP POST Response Code: {}".format(r.status_code))
break
sleep(30)
if verbosity > 1:
api_get.get_headers(r)
# clean up temp files
if os.path.exists(template_xml):
os.remove(template_xml)
def get_args():
"""Parse any command line arguments"""
parser = argparse.ArgumentParser()
parser.add_argument(
"-n",
"--name",
action="append",
dest="names",
default=[],
help=("Software Restriction to create or update"),
)
parser.add_argument(
"--replace",
help="overwrite an existing Software Restriction",
action="store_true",
)
parser.add_argument(
"--process-name",
default="",
help="process name",
)
parser.add_argument(
"--display-message",
default="",
help="message to display",
)
parser.add_argument(
"--match-exact-process-name",
help="match exact process name (boolean)",
action="store_true",
)
parser.add_argument(
"--send-notification",
help="send notification (boolean)",
action="store_true",
)
parser.add_argument(
"--kill-process",
help="kill process (boolean)",
action="store_true",
)
parser.add_argument(
"--delete-executable",
help="delete executable (boolean)",
action="store_true",
)
parser.add_argument(
"--template",
default="",
help="Path to Software Restriction XML template",
)
parser.add_argument(
"--url",
default="",
help="the Jamf Pro Server URL",
)
parser.add_argument(
"--user",
default="",
help="a user with the rights to create and update a computer group",
)
parser.add_argument(
"--password",
default="",
help="password of the user with the rights to create and update a computer group",
)
parser.add_argument(
"--prefs",
default="",
help=(
"full path to an AutoPkg prefs file containing "
"JSS URL, API_USERNAME and API_PASSWORD, "
"for example an AutoPkg preferences file which has been configured "
"for use with JSSImporter (~/Library/Preferences/com.github.autopkg.plist) "
"or a separate plist anywhere (e.g. ~/.com.company.jcds_upload.plist)"
),
)
parser.add_argument(
"-v",
"--verbose",
action="count",
default=0,
help="print verbose output headers",
)
args = parser.parse_args()
return args
def main():
"""Do the main thing here"""
print("\n** Jamf computer group upload script")
print("** Creates a computer group in Jamf Pro.")
# parse the command line arguments
args = get_args()
verbosity = args.verbose
# grab values from a prefs file if supplied
jamf_url, _, _, _, enc_creds = api_connect.get_creds_from_args(args)
# import computer group from file and replace any keys in the XML
with open(args.template, "r") as file:
template_contents = file.read()
# substitute user-assignable keys
template_contents = actions.substitute_assignable_keys(
template_contents, cli_custom_keys, verbosity, xml_escape=True
)
# set a list of names either from the CLI args or from the template if no arg provided
if args.names:
names = args.names
else:
names = [get_restriction_name(template_contents, verbosity)]
# now process the list of names
for restriction_name in names:
# where a group name was supplied via CLI arg, replace this in the template
if args.names:
template_contents = replace_restriction_name(
restriction_name, template_contents, verbosity
)
# check for existing group
print("\nChecking '{}' on {}".format(restriction_name, jamf_url))
obj_id = api_get.get_api_obj_id_from_name(
jamf_url, "computer_group", restriction_name, enc_creds, verbosity
)
if obj_id:
print(
"Software Restriction '{}' already exists: ID {}".format(
restriction_name, obj_id
)
)
if args.replace:
upload_computergroup(
jamf_url,
enc_creds,
restriction_name,
template_contents,
cli_custom_keys,
verbosity,
obj_id,
)
else:
print(
"Not replacing existing Software Restriction. Use --replace to enforce."
)
else:
print(
"Software Restriction '{}' not found - will create".format(
restriction_name
)
)
upload_computergroup(
jamf_url,
enc_creds,
restriction_name,
template_contents,
cli_custom_keys,
verbosity,
)
print()
if __name__ == "__main__":
main()