Writing and Video Portfolio
I've spent almost my entire career in large enterprise data centers and SaaS technology. During that time, I've built a broad, adaptable skillset in documentation and training, process and procedure standardization, solution engineering, troubleshooting and root cause analysis, large-scale implementation and remediation, and cross-team/cross-organization coordination. I know that sounds like buzzwords, but it's no exaggeration.
My documentation and video toolkit has spanned several different software titles over the years:
- Git Repos: GitHub | Bitbucket
- Git Clients: Tower | SourceTree | VS Code
- Productivity: Google Workspace | Office 365
- Developer Tools: VS Code | BBEdit | Postman | Chrome Developer Tools
- Documentation & Training: Camtasia | SnagIt | Markdown | Hugo | Confluence | Readme.com
- Task Management: Jira | Jira Service Manager | Trello | Microsoft Planner
- Diagramming: Miro | LucidChart | Draw.io | Visio
- Work OS: Apple iPadOS and macOS (preferred) | Windows 10/11 and ChromeOS (experienced)
This site uses the following technologies: Cloudflare (Websites, Analytics, Pages), Github, Hugo, Markdown, and the Hugo Clarity theme.
Note that some of the content below was written by me but owned by another organization and may be removed at any point in time. Additionally, much of the content I created at VMware has been removed due to the Broadcom/KKR transition.
Documentation
Category | Document | Description |
---|---|---|
Hands-On Lab | Getting Started with Digital Workspace | I designed and authored this lab's Apple iOS (Module 2) and macOS (Module 3) sections. These modules are aimed at customers and prospects new to Workspace ONE and unified endpoint management concepts. In addition to the initial source, I maintained these modules every 6 months as we updated the backing SaaS environment to adopt new features. Most of this content was authored based on my expertise, though I reviewed it with product managers for final sign-off. |
Troubleshooting | Troubleshooting macOS Management | This comprehensive troubleshooting document served as a tutorial for macOS Administrators needing to troubleshoot Workspace ONE functionality. I was responsible for the first three iterations of this guide and used it primarily as a tool for knowledge sharing with coworkers and customers. I wrote this content in ScreenSteps based on my testing and research. I collaborated with the Support SMEs and macOS Product Managers for peer review. |
Tutorial | Managing iOS Updates | I authored this tutorial to clarify the configuration process and expected behaviors for a feature (iOS Update Management) across multiple versions of iOS. The idea for this document was sourced from a Product Manager, but the content was based on my testing and authored in ScreenSteps. |
Glossary | Mapping concepts from Munki to Workspace ONE UEM | At the time I authored this page, I was receiving numerous questions about a recently-released integration between Workspace ONE UEM and Munki. This glossary page linked the Workspace ONE equivalents to the Munki terminology many of the macOS community knew. I wrote this on my blog (using Markdown, Hugo, and VS Code) to benefit the macOS admin community. |
Best Practices | Best Practices for Apple Admins in Workspace ONE UEM | I wrote this best practices document after reading a blog article about the loss of a system administrator. The point of this guide was to show prospective Apple Administrators how to set their environments up for survivability of the unexpected (layoffs, catastrophic accidents, etc). The toolset for this is also Markdown, Hugo, and VS Code. |
For additional reference, I've included links to some additional documents that I've authored and/or contributed below:
- Onboarding Options for macOS Tutorial
- Distributing Scripts to macOS Devices
- Deploying a Third-Party macOS App
Code Sample
I strive to find repeatable processes and automate them. At one employer, I created multiple product satisfaction surveys in Gainsight PX. I wrote a script to combine the responses from all the surveys into a single CSV file (that also integrated additional information about the respondents and the accounts to which they belong). In the snippet below, I use Python to aggregate the responses from a single survey in Gainsight PX. I subsequently posted this Github Gist to the Gainsight PX Community to assist others in learning how to leverage the scrollID to return multiple pages of data from the API. The full version of this script included additional helper functions for the additional APIs (account/user info) and recursive loops (aggregating responses from multiple surveys).
1# Example Gainsight Paging API Call
2
3##############################################################################
4# Reference API documentation:
5# https://gainsightpx.docs.apiary.io/#reference/surveyresponse
6#
7# Use the returned scrollId to make a request for the next page of results (i.e. /users?pageSize=100&scrollId=XXXXXXX)
8# Scroll until the returned result list is less than the requested size. Do not depend on the scrollId becoming null,
9# in some cases it does not be null even though the last page of results is returned.
10##############################################################################
11
12
13import json, requests, sys
14from datetime import datetime, timedelta, date
15
16##############################################################################
17## CONSTANTS
18##############################################################################
19
20# BaseURL for API calls
21BASE_URL = "BASE-URL-HERE"
22# API Key Name
23API_KEY_NAME = "X-APTRINSIC-API-KEY"
24# API Key Value
25API_KEY_VALUE = "GUID-HERE"
26# API Page Size
27API_PAGE_SIZE = 100
28# Survey Engagement ID
29ENGAGEMENT_ID = "ENGAGEMENT-ID-HERE"
30
31
32##############################################################################
33## HELPER FUNCTION
34##############################################################################
35
36# create a function to get the list of survey responses for a specific survey
37def get_surveyresponsesapi(engagementId, scrollId, datefiltertimestamp):
38
39 if scrollId == "":
40 # Set the request url for the first page of results
41 if datefiltertimestamp == "":
42
43 url = BASE_URL + "/v1/survey/responses?filter=engagementId=="+ engagementId + "&pageSize=" + str(API_PAGE_SIZE) + "&sort=-date"
44
45 else:
46
47 url = BASE_URL + "/v1/survey/responses?filter=engagementId=="+ engagementId + ";date>" + str(datefiltertimestamp) + "&pageSize=" + str(API_PAGE_SIZE) + "&sort=-date"
48
49 else:
50 # Set the request url for the subsequent pages of results
51 url = BASE_URL + "/v1/survey/responses?filter=engagementId=="+ engagementId + "&pageSize=" + str(API_PAGE_SIZE) + "&sort=-date" + "&scrollId=" + scrollId
52
53 payload={}
54 headers = {
55 'Accept': 'application/json',
56 API_KEY_NAME: API_KEY_VALUE
57 }
58
59 # Make the API call
60 return requests.request("GET", url, headers=headers, data=payload)
See more of this code at my Gist