Update mdm-commands.md (#29252)

Top down rewrite of the MDM command article with the intended purpose of
giving a clear example on using the API to deliver an MDM command in
addition to using fleetctl.
This commit is contained in:
Brock Walters 2025-05-20 13:54:24 -04:00 committed by GitHub
parent 7c69c69728
commit 5e8c5a52f3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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`.
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
@ -37,11 +41,11 @@ First, we'll need to create a `restart-device.xml` file locally with this payloa
</plist>
```
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
```
<Exec>
<Item>
<Target>
@ -56,34 +60,151 @@ The `restart-device.xml` file will have this payload instead:
</Exec>
```
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:
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Command</key>
<dict>
<key>Identifier</key>
<string>com.some.profile</string>
<key>RequestType</key>
<string>RemoveProfile</string>
</dict>
<key>CommandUUID</key>
<string>16F4301E-7A88-42AD-8523-A2F73F9D38FA</string>
</dict>
</plist>
```
### 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=<insert-command-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 '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Command</key>
<dict>
<key>Identifier</key>
<string>com.some.profile</string>
<key>RequestType</key>
<string>RemoveProfile</string>
</dict>
<key>CommandUUID</key>
<string>16F4301E-7A88-42AD-8523-A2F73F9D38FA</string>
</dict>
</plist>' | 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=<insert-command-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"
```
<meta name="category" value="guides">
<meta name="authorGitHubUsername" value="noahtalerman">