Skip to content

Commit

Permalink
Merge pull request #7 from USS-IT/USS-IT-version-upload
Browse files Browse the repository at this point in the history
USS-IT version upload
  • Loading branch information
justatechie authored Oct 30, 2023
2 parents ac50113 + e452fe6 commit d903225
Show file tree
Hide file tree
Showing 8 changed files with 996 additions and 73 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
settings.conf
/.idea
settings.conf.test
Logs/
.virtualenv/
12 changes: 12 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
7-1-23 MJC
- Updated jamf2snipe from official github. This fixed a KeyError it was having but broke updates from Snipe-It to Jamf (Error code 415, jamf2snipe issue #99).

7-5-23 MJC
- Created forward-errorlogs.ps1 to parse and send logfiles to designated recipients on detected errors, adding a call in run-jamf2snipe.
- Merged fixes from jamf2snipe issue #99 to fix response error code 415 when updating asset tags in JAMF.

7-10-23 MJC
- Added exclusion for response code 502 in forward-errorlogs.ps1.

7-27-23 MJC
- Add '[email protected]' to recipients in forward-errorlogs.ps1.
69 changes: 33 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,36 @@
# jamf2snipe
## Import/Sync Computers from JAMF to Snipe-IT
```
usage: jamf2snipe [-h] [-v] [--auto_incrementing] [--dryrun] [-d] [--do_not_update_jamf] [--do_not_verify_ssl] [-r] [-f] [--version] [-u | -ui | -uf] [-uns] [-m | -c]
options:
-h, --help show this help message and exit
-v, --verbose Sets the logging level to INFO and gives you a better
idea of what the script is doing.
--auto_incrementing You can use this if you have auto-incrementing
enabled in your snipe instance to utilize that
instead of adding the Jamf ID for the asset tag.
--dryrun This checks your config and tries to contact both
the JAMFPro and Snipe-it instances, but exits before
updating or syncing any assets.
-d, --debug Sets logging to include additional DEBUG messages.
--do_not_update_jamf Does not update Jamf with the asset tags stored in
Snipe.
--do_not_verify_ssl Skips SSL verification for all requests. Helpful when
you use self-signed certificate.
-r, --ratelimited Puts a half second delay between API calls to adhere
to the standard 120/minute rate limit
-f, --force Updates the Snipe asset with information from Jamf
every time, despite what the timestamps indicate.
--version Prints the version and exits.
-u, --users Checks out the item to the current user in Jamf if
it's not already deployed
-ui, --users_inverse Checks out the item to the current user in Jamf if
it's already deployed
-uf, --users_force Checks out the item to the user specified in Jamf no
matter what
-uns, --users_no_search
Doesn't search for any users if the specified fields
in Jamf and Snipe don't match. (case insensitive)
-m, --mobiles Runs against the Jamf mobiles endpoint only.
-c, --computers Runs against the Jamf computers endpoint only.
usage: jamf2snipe [-h] [-v] [--dryrun] [-d] [--do_not_verify_ssl] [-r]
[--no_search] [-u | -ui | -uf] [-m | -c]
optional arguments:
-h, --help show this help message and exit
-v, --verbose Sets the logging level to INFO and gives you a better
idea of what the script is doing.
--dryrun This checks your config and tries to contact both the
JAMFPro and Snipe-it instances, but exits before
updating or syncing any assets.
-d, --debug Sets logging to include additional DEBUG messages.
--do_not_update_jamf Does not update Jamf with the asset tags stored in
Snipe.
--do_not_verify_ssl Skips SSL verification for all requests. Helpful when
you use self-signed certificate.
-r, --ratelimited Puts a half second delay between Snipe IT API calls to
adhere to the standard 120/minute rate limit
-f, --force Updates the Snipe asset with information from Jamf
every time, despite what the timestamps indicate.
-u, --users Checks out the item to the current user in Jamf if
it's not already deployed
-ui, --users_inverse Checks out the item to the current user in Jamf if
it's already deployed
-uf, --users_force Checks out the item to the user specified in Jamf no
matter what
-uns, --users_no_search
Doesn't search for any users if the specified fields
in Jamf and Snipe don't match. (case insensitive)
-m, --mobiles Runs against the Jamf mobiles endpoint only.
-c, --computers Runs against the Jamf computers endpoint only.
```

## Overview:
Expand All @@ -47,7 +44,7 @@ Lastly, if the asset_tag field is blank in JAMF when it is being created in Snip

## Requirements:

- Python3 (3.7 or higher) is installed on your system with the requests, json, time, and configparser python libs installed.
- Python3 is installed on your system with the requests, json, time, and configparser python libs installed.
- Network access to both your JAMF and Snipe-IT environments.
- A JAMF username and password that has read & write permissions for computer assets, mobile device assets, and users.
- Computers: Read, Update
Expand All @@ -59,10 +56,10 @@ Lastly, if the asset_tag field is blank in JAMF when it is being created in Snip

### Mac

1. Install Python 3.7 or later
1. Install Python 3.6 or later
- Grab the latest PKG installer from the Python website and run it.

2. Add Python 3.7 or later to your PATH
2. Add Python 3.6 or later to your PATH
- Run the `Update Shell Profile.command` script in the `/Applications/Python 3.X` folder to add `python3.X` your PATH

3. Create a virtualenv for jamf2snipe
Expand Down
71 changes: 71 additions & 0 deletions forward-errorlogs.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Original Author: MJC
# Last Updated: MJC 7-5-23
# Forwards error logs to given address. This can be a user, list of users, or a distribution group.

# Email configuration for reports
$EMAIL_SMTP = 'smtp.johnshopkins.edu'
# If filled out, send error reports
$EMAIL_ERROR_REPORT_FROM = 'USS IT Services <[email protected]>'
# Can be string or array of strings.
$EMAIL_ERROR_REPORT_TO = @('[email protected]','[email protected]','[email protected]','[email protected]')
# Local filepath to last log file.
$LOGFILEPATH = "Logs\jamf2snipe_$(get-date -f yyyy-MM-dd).log"

# Also notify on warnings about error responses ($regexWarningError)
$NotifyOnErrorResponse = $true

# Regex to seach for in log file. Should start at beginning of line.
$regexError = "(Traceback |ERROR: |Error: )"
$regexErrorExclude = $null
$regexWarningError = "WARNING:[^\r\n]+error .+(?!\[502\])"
$regexWarningErrorExclude = "[502]" # Exclude 502 generic errors

# Split on these log boundaries and use the last one found.
$splitLogBoundaries = '** LOG START: '

# Combines regex into named captures.
[regex]$regexCombined = "(?<error>((^|[\r\n])$regexError[^\r\n]+))|(?<warningerror>((^|[\r\n])$regexWarningError[^\r\n]+))"

# Look in PsScriptRoot first. If not found, look in current directory.
if (Test-Path ".\$LOGFILEPATH" -PathType Leaf) {
$LOGFILEPATH = "$PsScriptRoot\$LOGFILEPATH"
} else {
$LOGFILEPATH = ".\$LOGFILEPATH"
}

if (Test-Path $LOGFILEPATH -PathType Leaf) {
$rawText = Get-Content $LOGFILEPATH -Raw
If ($rawText) {
# Get the last entry starting with $splitLogBoundaries.
$rawText = $rawText -split $splitLogBoundaries, 0, "simplematch" | Select -Last 1
$matches = $regexCombined.matches($rawText)
$errorCount = ($matches.Groups | where {$_.Success -eq $true -And $_.Name -eq 'error' -And ([string]::IsNullOrEmpty($regexErrorExclude) -Or $_.Value -notmatch $regexErrorExclude)}).Count
$warningErrorCount = ($matches.Groups | where {$_.Success -eq $true -And $_.Name -eq 'warningerror' -And ([string]::IsNullOrEmpty($regexWarningErrorExclude) -Or $_.Value -notmatch $regexWarningErrorExclude)}).Count

Write-Host("DEBUG: ErrorCount=$errorCount, WarningErrorCount=$warningErrorCount")

If ($errorCount -gt 0 -Or ($warningErrorCount -gt 0 -And $NotifyOnErrorResponse)) {
$params = @{
"From" = $EMAIL_ERROR_REPORT_FROM
"To" = $EMAIL_ERROR_REPORT_TO
"SmtpServer" = $EMAIL_SMTP
"Subject" = 'Errors from jamf2snipe'
"Body" = "There were [{0}] errors and [{1}] warnings with errors from [jamf2snipe] running on [${ENV:COMPUTERNAME}]. See attached logfile for more details." -f $errorCount, $warningErrorCount
"Priority" = "High"
"DeliveryNotificationOption" = "OnSuccess", "OnFailure"
"Attachments" = $LOGFILEPATH
}

# Email out notifications of any errors.
try {
Send-MailMessage @params
} catch {
$params['Attachments'] = $null
$params['Body'] = "There were [{0}] errors and [{1}] warnings with errors from [jamf2snipe] running on [${ENV:COMPUTERNAME}]. See server log file for more detail." -f $errorCount, $warningErrorCount
Send-MailMessage @params
}

Add-Content -Path $LOGFILEPATH -Value ("[forward-errorlogs.ps1][{0}] Emailed error report to [{1}]" -f ((Get-Date).toString("yyyy/MM/dd HH:mm:ss")), ($EMAIL_ERROR_REPORT_TO -join ", ")) -PassThru
}
}
}
7 changes: 4 additions & 3 deletions jamf2snipe
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
# _snipeit_custom_name_1234567890 = subset jamf_key
#
# A list of valid subsets are:
version = "1.0.5"
version = "1.0.4"

validsubset = [
"general",
Expand Down Expand Up @@ -224,8 +224,9 @@ def request_jamf_token():
# The headers are also global, because they get used elsewhere.
logging.info("Setting new jamf headers with bearer token")
jamfheaders = {'Authorization': 'Bearer {}'.format(jsonresponse['token']),'Accept': 'application/json','Content-Type':'application/json'}
jamfxmlheaders = {'Authorization': 'Bearer {}'.format(jsonresponse['token']),'Accept': 'application/xml','Content-Type':'application/xml'}
logging.debug('Request headers for JamfPro will be: {}\nRequest headers for Snipe will be: {}'.format(jamfheaders, snipeheaders))
jamfxmlheaders = {'Authorization': 'Bearer {}'.format(jsonresponse['token']),'Accept': 'application/xml','Content-Type':'application/xml'}
logging.debug('Request headers for updating asset tags in JamfPro will be: '.format(jamfxmlheaders))
else:
logging.error("Could not obtain a token for use with Jamf's classic API. Please check your username and password.")
raise SystemExit("Unable to obtain Jamf Token")
Expand Down Expand Up @@ -903,7 +904,7 @@ for jamf_type in jamf_types:
jamf_value = jamf_value[item]
payload = {snipekey: jamf_value}
latestvalue = jamf_value
except (KeyError, TypeError):
except KeyError:
logging.debug("Skipping the payload, because the JAMF key we're mapping to doesn't exist")
continue

Expand Down
Loading

0 comments on commit d903225

Please sign in to comment.