Device Migration API Postman Collection

Disclaimer: This information is provided as-is for the benefit of the Community. Please contact Sophos Professional Services if you require assistance with your specific environment.


Overview

This sample script gives you an easy start when using Sophos Endpoint API for device migration between Sophos Central accounts.

https://docs.sophos.com/central/Customer/help/en-us/ManageYourProducts/Overview/GlobalSettings/DeviceMigration/index.html

What to do

Save the following as "Sophos Central Device Migration.postman_collection.json"

{
	"info": {
		"_postman_id": "43aeba01-038e-45dc-b4a3-fc44e60b63db",
		"name": "Sophos Central Device Migration",
		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
	},
	"item": [
		{
			"name": "Step 1 - Authentication",
			"item": [
				{
					"name": "Source: Authenticate",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"var jsonData = JSON.parse(responseBody);",
									"pm.collectionVariables.set(\"SourceAccessToken\", jsonData.access_token);"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"auth": {
							"type": "noauth"
						},
						"method": "POST",
						"header": [],
						"body": {
							"mode": "urlencoded",
							"urlencoded": [
								{
									"key": "grant_type",
									"value": "client_credentials",
									"type": "text"
								},
								{
									"key": "scope",
									"value": "token",
									"type": "text"
								},
								{
									"key": "client_id",
									"value": "{{SourceClientID}}",
									"type": "text"
								},
								{
									"key": "client_secret",
									"value": "{{SourceClientSecret}}",
									"type": "text"
								}
							]
						},
						"url": {
							"raw": "https://id.sophos.com/api/v2/oauth2/token",
							"protocol": "https",
							"host": [
								"id",
								"sophos",
								"com"
							],
							"path": [
								"api",
								"v2",
								"oauth2",
								"token"
							]
						}
					},
					"response": []
				},
				{
					"name": "Source: Who am I?",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Status code is 200\", function () {",
									"    pm.response.to.have.status(200);",
									"    ",
									"    pm.test(\"Save ID and api host\", function () {",
									"        var jsonData = pm.response.json();",
									"",
									"        pm.collectionVariables.set(\"SourceTenantID\", jsonData.id);",
									"        pm.collectionVariables.set(\"SourceDataRegion\", jsonData.apiHosts.dataRegion.slice(12, 16));",
									"    });",
									"});",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"auth": {
							"type": "bearer",
							"bearer": [
								{
									"key": "token",
									"value": "{{SourceAccessToken}}",
									"type": "string"
								}
							]
						},
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://api.central.sophos.com/whoami/v1",
							"protocol": "https",
							"host": [
								"api",
								"central",
								"sophos",
								"com"
							],
							"path": [
								"whoami",
								"v1"
							]
						},
						"description": "Returns information about the caller."
					},
					"response": []
				},
				{
					"name": "Target: Authenticate",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"var jsonData = JSON.parse(responseBody);",
									"pm.collectionVariables.set(\"TargetAccessToken\", jsonData.access_token);"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"auth": {
							"type": "noauth"
						},
						"method": "POST",
						"header": [],
						"body": {
							"mode": "urlencoded",
							"urlencoded": [
								{
									"key": "grant_type",
									"value": "client_credentials",
									"type": "text"
								},
								{
									"key": "scope",
									"value": "token",
									"type": "text"
								},
								{
									"key": "client_id",
									"value": "{{TargetClientID}}",
									"type": "text"
								},
								{
									"key": "client_secret",
									"value": "{{TargetClientSecret}}",
									"type": "text"
								}
							]
						},
						"url": {
							"raw": "https://id.sophos.com/api/v2/oauth2/token",
							"protocol": "https",
							"host": [
								"id",
								"sophos",
								"com"
							],
							"path": [
								"api",
								"v2",
								"oauth2",
								"token"
							]
						}
					},
					"response": []
				},
				{
					"name": "Target: Who am I?",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Status code is 200\", function () {",
									"    pm.response.to.have.status(200);",
									"    ",
									"    pm.test(\"Save ID and api host\", function () {",
									"        var jsonData = pm.response.json();",
									"",
									"        pm.collectionVariables.set(\"TargetTenantID\", jsonData.id);",
									"        pm.collectionVariables.set(\"TargetDataRegion\", jsonData.apiHosts.dataRegion.slice(12, 16));",
									"           ",
									"    });",
									"});",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"auth": {
							"type": "bearer",
							"bearer": [
								{
									"key": "token",
									"value": "{{TargetAccessToken}}",
									"type": "string"
								}
							]
						},
						"method": "GET",
						"header": [],
						"url": {
							"raw": "https://api.central.sophos.com/whoami/v1",
							"protocol": "https",
							"host": [
								"api",
								"central",
								"sophos",
								"com"
							],
							"path": [
								"whoami",
								"v1"
							]
						},
						"description": "Returns information about the caller."
					},
					"response": []
				}
			],
			"auth": {
				"type": "noauth"
			},
			"event": [
				{
					"listen": "prerequest",
					"script": {
						"type": "text/javascript",
						"exec": [
							""
						]
					}
				},
				{
					"listen": "test",
					"script": {
						"type": "text/javascript",
						"exec": [
							""
						]
					}
				}
			]
		},
		{
			"name": "Step 2 - Source: Get List of Endpoints",
			"event": [
				{
					"listen": "test",
					"script": {
						"exec": [
							"let response = pm.response.json(),\r",
							"    ids = _.map(response.items, ({ id }) => ( id )); \r",
							"\r",
							"pm.collectionVariables.set('EndpointList', JSON.stringify(ids));\r",
							""
						],
						"type": "text/javascript"
					}
				}
			],
			"request": {
				"auth": {
					"type": "bearer",
					"bearer": [
						{
							"key": "token",
							"value": "{{SourceAccessToken}}",
							"type": "string"
						}
					]
				},
				"method": "GET",
				"header": [
					{
						"description": "(Required) Tenant ID.",
						"key": "X-Tenant-ID",
						"value": "{{SourceTenantID}}"
					}
				],
				"url": {
					"raw": "https://api-{{SourceDataRegion}}.central.sophos.com/endpoint/v1/endpoints?fields=id,hostname",
					"protocol": "https",
					"host": [
						"api-{{SourceDataRegion}}",
						"central",
						"sophos",
						"com"
					],
					"path": [
						"endpoint",
						"v1",
						"endpoints"
					],
					"query": [
						{
							"key": "fields",
							"value": "id,hostname"
						},
						{
							"key": "hostnameContains",
							"value": "WIN",
							"disabled": true
						}
					]
				},
				"description": "Get all the endpoints for the specified tenant."
			},
			"response": []
		},
		{
			"name": "Step 3 - Target: Start Receiver Task",
			"event": [
				{
					"listen": "test",
					"script": {
						"exec": [
							"var jsonData = pm.response.json();\r",
							"\r",
							"pm.collectionVariables.set(\"MigrationID\", jsonData.id);\r",
							"pm.collectionVariables.set(\"MigrationToken\", jsonData.token);"
						],
						"type": "text/javascript"
					}
				}
			],
			"request": {
				"auth": {
					"type": "bearer",
					"bearer": [
						{
							"key": "token",
							"value": "{{TargetAccessToken}}",
							"type": "string"
						}
					]
				},
				"method": "POST",
				"header": [
					{
						"description": "(Required) Tenant ID.",
						"key": "X-Tenant-ID",
						"value": "{{TargetTenantID}}"
					},
					{
						"key": "Content-Type",
						"value": "application/json"
					}
				],
				"body": {
					"mode": "raw",
					"raw": "{\n    \"fromTenant\": \"{{SourceTenantID}}\",\n    \"endpoints\": {{EndpointList}}\n}"
				},
				"url": {
					"raw": "https://api-{{TargetDataRegion}}.central.sophos.com/endpoint/v1/migrations",
					"protocol": "https",
					"host": [
						"api-{{TargetDataRegion}}",
						"central",
						"sophos",
						"com"
					],
					"path": [
						"endpoint",
						"v1",
						"migrations"
					]
				},
				"description": "Adds a new local site."
			},
			"response": []
		},
		{
			"name": "Step 4 - Source: Start Migration Job",
			"event": [
				{
					"listen": "test",
					"script": {
						"exec": [
							""
						],
						"type": "text/javascript"
					}
				}
			],
			"request": {
				"auth": {
					"type": "bearer",
					"bearer": [
						{
							"key": "token",
							"value": "{{SourceAccessToken}}",
							"type": "string"
						}
					]
				},
				"method": "PUT",
				"header": [
					{
						"description": "(Required) Tenant ID.",
						"key": "X-Tenant-ID",
						"value": "{{SourceTenantID}}"
					},
					{
						"key": "Content-Type",
						"value": "application/json"
					}
				],
				"body": {
					"mode": "raw",
					"raw": "{\n    \"token\": \"{{MigrationToken}}\",\n    \"endpoints\": {{EndpointList}}\n}\n"
				},
				"url": {
					"raw": "https://api-{{SourceDataRegion}}.central.sophos.com/endpoint/v1/migrations/{{MigrationID}}",
					"protocol": "https",
					"host": [
						"api-{{SourceDataRegion}}",
						"central",
						"sophos",
						"com"
					],
					"path": [
						"endpoint",
						"v1",
						"migrations",
						"{{MigrationID}}"
					]
				},
				"description": "Adds a new local site."
			},
			"response": []
		},
		{
			"name": "Step 5 - Target: Check Migration Status",
			"event": [
				{
					"listen": "test",
					"script": {
						"exec": [
							""
						],
						"type": "text/javascript"
					}
				}
			],
			"request": {
				"auth": {
					"type": "bearer",
					"bearer": [
						{
							"key": "token",
							"value": "{{TargetAccessToken}}",
							"type": "string"
						}
					]
				},
				"method": "GET",
				"header": [
					{
						"key": "X-Tenant-ID",
						"value": "{{TargetTenantID}}",
						"type": "default"
					}
				],
				"url": {
					"raw": "https://api-{{TargetDataRegion}}.central.sophos.com/endpoint/v1/migrations/{{MigrationID}}/endpoints",
					"protocol": "https",
					"host": [
						"api-{{TargetDataRegion}}",
						"central",
						"sophos",
						"com"
					],
					"path": [
						"endpoint",
						"v1",
						"migrations",
						"{{MigrationID}}",
						"endpoints"
					]
				},
				"description": "Returns information about the caller."
			},
			"response": []
		}
	],
	"event": [
		{
			"listen": "prerequest",
			"script": {
				"type": "text/javascript",
				"exec": [
					""
				]
			}
		},
		{
			"listen": "test",
			"script": {
				"type": "text/javascript",
				"exec": [
					""
				]
			}
		}
	],
	"variable": [
		{
			"key": "SourceClientID",
			"value": "",
			"type": "default"
		},
		{
			"key": "SourceClientSecret",
			"value": "",
			"type": "default"
		},
		{
			"key": "TargetClientID",
			"value": "",
			"type": "default"
		},
		{
			"key": "TargetClientSecret",
			"value": "",
			"type": "default"
		}
	]
}

Open the file in Postman and replace any necessary fields.



Updated link
[edited by: Qoosh at 4:25 PM (GMT -7) on 11 Oct 2024]
Parents Reply
  • Hi, thanks for ideas.

    1 - This was all done in the space of 10 minutes within postman, so the tokens should be good

    2 - I was using enterprise dashboard credentials before. However following the postman flow and using separate tenant credentials for the source and destination tenants did not help

    3 - Device migration is enabled indefinately for all tenants

    Any other ideas?

Children
  • Unfortunately no. I just used the Postman collection in my own test environment and successfully migrated a device from one tenant to the other.

    I only get a forbidden, at Step 4 when Device Migration is not enabled in the Source account. But in that case it will also show you the reason why its not allowed, see example below:

    {
        "error": "forbidden",
        "correlationId": "a4535e0f-2d35-46c7-b5b7-0debaab25160",
        "requestId": "6ee51443-1de3-4933-92df-2ebfdfd21001",
        "message": "Endpoint Migration is not enabled"
    }


    If it is only a small number of devices that you have to migrate then a manual migration might be an option, you could download the SophosSetup installer from the target account and run that one on the devices with the paremeter --registeronly. Just make sure that you deactivate Tamper Protection before doing so.

    If it is concerning a larger number of devices then I would recommend opening a support case.

  • Ah! I am getting the following:

    "error": "forbidden",
    "correlationId": "894035df-198e-40b4-ac54-14f01d0dbee3",
    "requestId": "d01d51f3-6c94-4ce0-8dd2-7e0fd79a8945",
    "message": "Access Denied"

    The issue we have with reinstalling with registeronly is that I don't believe that option is available on the Mac. Also you have the second step of going back to the original tenant and deleting the original instance, after it is recreated in the new tenant.

  • I have to guess here, "Access Denied" could mean that you are not using the correct credentials/permissions (for a migration you need Service Principal Super Admin) or maybe it is a licensing based issue. 

    I strongly recommend opening a support case, I have no means to analyze the error you are seeing.

  • Thank you!! Creating keys with Service Principal Super Admin was the solution. Before they were just for the management role.