diff --git a/articles/mdm-commands.md b/articles/mdm-commands.md index b1e5918c5e..17ab1b4207 100644 --- a/articles/mdm-commands.md +++ b/articles/mdm-commands.md @@ -1,29 +1,33 @@ # MDM commands -In Fleet you can run MDM commands to take action on your macOS, iOS, iPadOS, and Windows hosts, like restarting the host, remotely. +MDM commands can be sent to macOS, iOS / iPadOS and Windows hosts managed in Fleet using the following general steps: -## Custom commands +1. Create a payload that functions as the MDM command. +2. Choose a target host, or, a set of target hosts on which to run the MDM command. +3. Execute the MDM command by using the `fleetctl` command line interface (CLI) or by sending the payload in a Fleet API call. +4. If needed, verify the MDM command result with an additional `fleetctl` command or API call. -You can run custom commands and view a specific command's results using the `fleetctl` command-line interface. +### Step 1: Create an MDM command payload -To run a custom command, we will do the following steps: +An MDM command payload can be created in mulitple ways. -1. Create a `.xml` with the request payload -2. Choose a target host -3. Run the command using `fleetctl` -4. View our command's results using `fleetctl` +For Apple devices, the payload is a `.plist` that can be copied like this example from [Apple's developer documentation](https://developer.apple.com/documentation/devicemanagement/remove-profile-command), created with the [iMazing Profile Editor](https://imazing.com/profile-editor) or exported from a 3rd party MDM solution. -### Step 1: Create an XML file +For Windows, the payload is standard `xml` and command options can be referenced in the [Microsoft CSP Policy docuementation](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-configuration-service-provider). You can run any command supported by [Apple's MDM protocol](https://developer.apple.com/documentation/devicemanagement/commands_and_queries) or [Microsoft's MDM protocol](https://learn.microsoft.com/en-us/windows/client-management/mdm/). -> The lock and wipe commands are only available in Fleet Premium +The end result simply needs to be a standard, plain text file with the correct key / values for obtaining the intended result on the host device. -For example, to restart a macOS host, we'll use the "Restart a Device" command documented by Apple [here](https://developer.apple.com/documentation/devicemanagement/restart_a_device#3384428). +> Lock and wipe commands are only available in Fleet Premium. -First, we'll need to create a `restart-device.xml` file locally with this payload: +### Examples -```xml +To restart a macOS host, we can use the "Restart a Device" MDM command documented by Apple [here](https://developer.apple.com/documentation/devicemanagement/restart_a_device#3384428). + +Below is the text to be used as the MDM command payload. Save it as a file and name it something like `apple-restart-device.xml`. + +``` @@ -37,11 +41,11 @@ First, we'll need to create a `restart-device.xml` file locally with this payloa ``` -To restart a Windows host, we'll use the "Reboot" command documented by Microsoft [here](https://learn.microsoft.com/en-us/windows/client-management/mdm/reboot-csp). +To restart a Windows host, we can use the "Reboot" command documented by Microsoft [here](https://learn.microsoft.com/en-us/windows/client-management/mdm/reboot-csp). -The `restart-device.xml` file will have this payload instead: +Below is the text to be used as the MDM command payload. Save it as a file and name it something like `windows-restart-device.xml`. -```xml +``` @@ -56,34 +60,151 @@ The `restart-device.xml` file will have this payload instead: ``` +To prepare an MDM command payload for use with the Fleet API, generate a UUID to be used as the `CommandUUID`, e.g., + +In Terminal, execute the following command: + +``` +% uuidgen +16F4301E-7A88-42AD-8523-A2F73F9D38FA +``` + +> It's not necessary to add the `CommandUUID` to the MDM command payload, but, already having it available makes it's easier and quicker to verify the MDM command result if a check is needed. + +A `.plist` with the `CommandUUID` key / value added will look something like this: + +``` + + + + + Command + + Identifier + com.some.profile + RequestType + RemoveProfile + + CommandUUID + 16F4301E-7A88-42AD-8523-A2F73F9D38FA + + +``` + ### Step 2: Choose a target host -To run a command, we need to specify a target host by hostname. +Run the `fleetctl get hosts --mdm` command to get a list of hosts that are enrolled in Fleet and have MDM enabled. This may not be practical in Fleet environments with a large number hosts without using command line tools to parse the output, e.g., -1. Run the `fleetctl get hosts --mdm` command to get a list of hosts that are enrolled to Fleet and have MDM turned on. -2. Find your target host's hostname. You'll need this hostname to run the command. +Use something like `grep` with `fleetctl`: -### Step 3: Run the command +``` +% fleetctl get hosts --mdm | grep -i 'someSearchStringHere' +Client Version: 4.67.3 +Server Version: 4.67.3 +| 1B848BE8-some-uuid | someComputer | darwin | 5.17.0 | online | +| 08C7634C-some-uuid | someOtherComputer | windows | 5.17.0 | online | +``` -1. Run the `fleetctl mdm run-command --payload=restart-device.xml --hosts=hostname ` command. +Or, something like `jq` for API output: -> Replace the --payload and --hosts flags with your XML file and hostname respectively. +``` +% curl -LSs \ +--request GET \ +--header 'Accept: application/json' \ +--header "Authorization: Bearer $fleet_key" \ +"$fleet_url/api/v1/fleet/hosts" | jq '.hosts[] | select(.computer_name | contains("someSearchStringHere"))' +``` -2. Look at the on-screen information. In the output you'll see the command to see results. +> You will need a [Fleet API token](https://fleetdm.com/docs/rest-api/rest-api#retrieve-your-api-token) in your `fleetctl` configuration or for any interaction with the Fleet API to work. -### Step 4: View the command's results +### Step 3: Execute the MDM command -1. Run the `fleetctl get mdm-command-results --id=` -2. Look at the on-screen information. +To deliver the MDM command payload with `fleetctl`, use something like the following that: -## List recent commands +- references the MDM command payload file created above, and +- references the intended host targets, e.g., -You can view a list of the 1,000 latest commands: +`fleetctl mdm run-command --payload='apple-restart-device.xml' --hosts='someHostname'` -1. Run `fleetctl get mdm-commands` -2. View the list of latest commands, most recent first, along with the timestamp, targeted hostname, command type, execution status and command ID. +For targeting multiple hosts, the `--hosts` option can be populated with comma-separated values. -The command ID can be used to view command results as documented in [step 4 of the previous section](#step-4-view-the-commands-results). +To prepare the MDM command payload for execution in a Fleet API call, it must be base64-encoded. This is true for Apple and Windows MDM command payloads. E.g., to encode the `.plist` in Terminal: + +``` +% echo ' + + + + Command + + Identifier + com.some.profile + RequestType + RemoveProfile + + CommandUUID + 16F4301E-7A88-42AD-8523-A2F73F9D38FA + +' | base64 +PD94bWwgdmVyc2lvbj0iMS4wIiBlSomeMorebase64blahblahblah... +``` + +Then, to deliver the MDM command payload via the Fleet API, use a command that conforms to the `curl` example below. (This can be achieved with any programmatic solution, e.g., python `requests` or `urllib.request`). + +``` +% fleet_key='yourfleetAPItoken' +% fleet_url='https://your.url.com' +% /usr/bin/curl -LSs \ +--request POST \ +--header 'Content-Type: application/json' \ +--header "Authorization: Bearer $fleet_key" \ +--data '{"command":"PD94bWwgdmVyc2lvbj0iMS4wIiBlSomeMorebase64blahblahblah...","host_uuids":["some-host-uuid"]}' \ +"$fleet_url/api/v1/fleet/commands/run" +``` + +For targeting multiple hosts, the `"host_uuids"` key / value is a json array that can be populated with multiple host uuid values, e.g., + +`"host_uuids":["some-host-uuid-1","some-host-uuid-2","some-host-uuid-3"]` + +### Step 4: Verify the MDM command result + +To verify the MDM command result with `fleetctl`, use something like the command below: + +`fleetctl get mdm-command-results --id=` + +If you generated the `CommandUUID`, add that value in the `--id` field. If you did not generate a command ID, one will be added to the MDM command by Fleet and it should appear in a succesful response after execution or in the MDM command results stored in Fleet. + +To verify the MDM command result with the Fleet API, use a command that conforms to the `curl` example below: + +``` +% /usr/bin/curl -LSs \ +--request GET \ +--header 'Accept: application/json' \ +--header "Authorization: Bearer $fleet_key" \ +"$fleet_url/api/v1/fleet/commands/results?command_uuid=16F4301E-7A88-42AD-8523-A2F73F9D38FA" +``` + +> The `?command_uuid=` parameter appended to the URL is populated with the same `CommandUUID` string that was used to populate the `CommandUUID` key / value in the base64-encoded `.plist` in Step 1. + +## Troubleshooting + +You can view a list of the 1,000 most recent MDM commands executed in Fleet by running: + +`fleetctl get mdm-commands` + +The output will be sorted by "most recent first" and will include timestamp, targeted hostname, command type, execution status and command ID. + +The command ID can be used to view MDM command results as documented in Step 4. + +You can also get this list of MDM commands from the Fleet API with: + +``` +% /usr/bin/curl -LSs \ +--request GET \ +--header 'Accept: application/json' \ +--header "Authorization: Bearer $fleet_key" \ +"$fleet_url/api/v1/fleet/commands/results" +```