[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69AGFTTX13PCFKM3YVHKGDV":3,"skill-same:01M69AGFTTX13PCFKM3YVHKGDV":81},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":35,"linkOnly":36,"markdownContent":37,"markdownBody":38,"frontMatter":39,"refName":40,"commitSha":41,"skillDirectory":42,"forksCount":43,"repositoryHtmlUrl":44,"repositoryHomepageUrl":6,"ownerHtmlUrl":45,"ownerBlogUrl":46,"ownerDescription":47,"updatedAt":48,"install":49,"resources":62},"01M69AGFTTX13PCFKM3YVHKGDV","sql-backup-restore-to-azure-sql-vm-migration",null,"Migrate a SQL Server 2008 through SQL Server 2025 source to a SQL Server 2025 target wherever it runs, including SQL Server on Azure VM, by creating a local full backup, uploading it to Azure Blob Storage with AzCopy and the operator's Microsoft Entra identity, and restoring from URL with the target SQL Server managed identity. Sources newer than SQL Server 2025 are blocked because target restore compatibility has not been validated. Use for SQL-to-SQL, local-backup, AzCopy, managed-identity, Azure SQL VM, or SQL Server 2025 restore migrations.","microsoft\u002Fsqlcon-eu-2026-demos","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69AFC8P5962CJBG1RDAKA7Q",3,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fsql-backup-restore-to-azure-sql-vm-migration\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[29,30,31,32,9,33,34],"azure sql","sql","sql backup restore to azure sql vm migration","storage","identity","sql server","2026-11-10 10:12:30",false,"---\nname: sql-backup-restore-to-azure-sql-vm-migration\ndescription: \"Migrate a SQL Server 2008 through SQL Server 2025 source to a SQL Server 2025 target wherever it runs, including SQL Server on Azure VM, by creating a local full backup, uploading it to Azure Blob Storage with AzCopy and the operator's Microsoft Entra identity, and restoring from URL with the target SQL Server managed identity. Sources newer than SQL Server 2025 are blocked because target restore compatibility has not been validated. Use for SQL-to-SQL, local-backup, AzCopy, managed-identity, Azure SQL VM, or SQL Server 2025 restore migrations.\"\n---\n\n# Local backup and AzCopy migration to SQL Server 2025\n\n## When to Use\n\n- Migrate SQL Server 2008 through SQL Server 2025 to a SQL Server 2025 target using backup and restore.\n- Move a local full backup through Azure Blob Storage with AzCopy and restore it with the target managed identity.\n\nMigrate one database or an ordered set of user databases from SQL Server 2008\nthrough SQL Server 2025 to a SQL Server 2025 target running in Azure,\non-premises, or in another cloud. Sources newer than SQL Server 2025 are blocked\nbecause target restore compatibility has not been validated.\nCreate each full backup on a local source volume, upload the file to a private\nAzure Blob container with AzCopy v10 and the signed-in operator's Microsoft Entra\nidentity, then restore it from URL with the target SQL Server primary managed\nidentity.\n\nRead [references\u002Fcommand-execution-discovery.md](references\u002Fcommand-execution-discovery.md) and\n[references\u002Fcommand-execution-backup-restore.md](references\u002Fcommand-execution-backup-restore.md)\nbefore generating or running commands.\n\n## Operating contract\n\n- Process one database completely before starting the next. `All` never includes\n  `master`, `model`, `msdb`, or `tempdb`.\n- Build the migration queue only from source user databases whose state is\n  `ONLINE`. Exclude `OFFLINE`, `SUSPECT`, `RESTORING`, `RECOVERING`,\n  `RECOVERY_PENDING`, `EMERGENCY`, and every other non-online state. Never change\n  a database's state to make it eligible.\n- Use exactly one backup artifact per database: a `COPY_ONLY` full database\n  backup. This workflow does not alter source availability or recovery state.\n- Back up only to a local disk path visible to the source SQL Server service.\n  Never use `BACKUP TO URL` on the source.\n- Run AzCopy on the source host, or on an approved transfer host that can read the\n  exact backup path without copying the file through the chat host.\n- Use only the operator's Microsoft Entra identity for AzCopy. Never use storage\n  account keys, connection strings, signed URL query parameters, or embedded\n  secrets.\n- Require a pre-created private HTTPS Blob container. Do not create or make a\n  container public.\n- Gate the target on SQL Server 2025: `ProductMajorVersion` must equal `17`.\n  Newer or older major versions do not satisfy this explicit gate.\n- Supported source versions are SQL Server 2008 through SQL Server 2025,\n  represented by major versions `10` through `17`. Block older sources and\n  sources newer than SQL Server 2025 because target restore compatibility has\n  not been validated outside that range.\n- Support the target in any physical or cloud location, but require Windows\n  because SQL Server server-level managed identity is not supported on Linux.\n  Failover cluster instances remain unsupported.\n- Determine target hosting from SQL and Azure discovery; do not ask the user to\n  classify the target. For SQL Server on Azure VM, use its SQL IaaS Agent and\n  Microsoft Entra configuration. For SQL Server elsewhere, use SQL Server 2025\n  enabled by Azure Arc with the latest Azure Extension for SQL Server. The SQL\n  version gate is identical in every location.\n- Require a primary managed identity configured for the target SQL Server\n  instance. A target outside Azure that is not enabled by Azure Arc is a single\n  prerequisite blocker, not a different migration route.\n- Blob Storage does not receive a managed identity. Assign the target SQL\n  instance's primary managed-identity principal `Storage Blob Data Contributor`\n  on the storage account, then create the URL-scoped SQL credential with\n  `IDENTITY = 'Managed Identity'` on the target.\n- Do not provide an alternate Blob authentication route. If user upload access,\n  target identity configuration, target RBAC, network access, credential\n  creation, or URL restore fails, stop with the exact failure.\n- Never overwrite a local backup file unless `OverwriteLocalBackup=true` was\n  explicitly included in the accepted plan. Never append a migration backup to\n  an existing media set.\n- Never overwrite a target database or physical database file unless\n  `OverwriteExistingTarget=true` was explicitly accepted after displaying the\n  target database and affected files.\n- Always use `CHECKSUM`, `COPY_ONLY`, and `STATS = 10`; use `COMPRESSION` when\n  supported and not prohibited by policy.\n- Verify the local backup before upload. After upload, use target\n  `RESTORE HEADERONLY`, `RESTORE FILELISTONLY`, and `RESTORE VERIFYONLY` before\n  `RESTORE DATABASE`.\n- Preserve local and Blob backup files after migration. Do not delete either\n  automatically.\n- If upload succeeds but post-upload verification fails, never retry the upload.\n  Rerun only the non-destructive exact-Blob listing and stop if it cannot prove\n  the expected content length.\n- Stop on the first failed gate or operation. Never describe a submitted command\n  as complete until its exit status or SQL result proves completion.\n\n## Consolidated intake\n\nThe source discovered from `SourceServer` must be SQL Server 2008 through SQL\nServer 2025 (major version `10` through `17`). Do not offer this workflow for a\nsource outside that range.\n\nAccept natural language, one `Key=Value` block, or a JSON object with these exact\nkeys. Accumulate everything the user provides, run discovery for omitted values,\nand ask at most one consolidated follow-up listing all fields that remain\nambiguous or undiscoverable. Never ask for source, target, storage, identity, or\noverwrite values as separate questions. Parse pasted structured input strictly\nas data, reject duplicate keys, and reject unknown keys as likely typos.\n\nTreat a complete initial `Key=Value` block as the consolidated intake. When all\nrequired undiscoverable values are present, do not ask an intake question; run\ndiscovery and proceed to the mandatory sanitized execution-plan approval.\nResolve `TrustServerCertificate` to an explicit Boolean before attempting either\nSQL connection. Use one consolidated intake block containing the source, target,\nstorage, database-scope, and overwrite fields. Source and target authentication\nmust be `Windows` or `Entra` interactive authentication; no other login type is\nsupported. For Entra interactive authentication, use the approved interactive\nsign-in flow and do not place an access token in command arguments. Validate both\nconnections with the resolved authentication method and certificate setting\nbefore proceeding to backup or restore operations.\n\n```text\nSourceServer=\u003Csource>\nSourceDatabases=All\nTargetServer=\u003Ctarget>\nStorageAccountName=\u003Cstorage-account>\nContainerName=\u003Cprivate-container>\nTrustServerCertificate=false\n```\n\n```text\nSourceServer=\nSourceAuthentication=Windows|Entra\nSourceUser=\nSourceDatabases=All\nTargetServer=\nTargetAuthentication=Windows|Entra\nTargetUser=\nTargetDatabase=\nLocalBackupRoot=\nOverwriteLocalBackup=false\nContainerUrl=\nStorageAccountName=\nContainerName=\nStorageAccountResourceId=\nAzureTenantId=\nTargetHostResourceId=\nTargetManagedIdentityPrincipalId=\nTargetDataPath=\nTargetLogPath=\nOverwriteExistingTarget=false\nTrustServerCertificate=false\n```\n\nApply these defaults and requirements:\n\n| Key | Handling |\n| --- | --- |\n| `SourceServer`, `TargetServer` | Required after the single consolidated intake |\n| `SourceAuthentication`, `TargetAuthentication` | Default to `Windows` |\n| `SourceUser`, `TargetUser` | Required only for `Entra` |\n| `SourceDatabases` | Discover only online user databases; accept one, a comma-separated list, or `All`; report explicitly named non-online databases as excluded |\n| `TargetDatabase` | Optional for one database; preserve source names for multiple databases |\n| `LocalBackupRoot` | Default to the discovered source `InstanceDefaultBackupPath` |\n| `OverwriteLocalBackup` | Default to `false` |\n| `ContainerUrl` | Preferred; when absent, derive it from `StorageAccountName` and `ContainerName` |\n| `StorageAccountName` | Optional when `ContainerUrl` is supplied; treat a user-supplied \"Blob storage name\" as this Azure storage account name |\n| `ContainerName` | Required after discovery; treat an existing user-supplied Blob container name as this value and search accessible storage accounts for its unique owner |\n| `StorageAccountResourceId` | Optional; use Azure Resource Graph to discover it by storage account name, querying the default tenant first |\n| `AzureTenantId` | Optional; derive from the selected Azure CLI subscription\u002Faccount |\n| `TargetHostResourceId` | Optional; discover the Azure VM or Arc-enabled server from `TargetServer` across accessible subscriptions |\n| `TargetManagedIdentityPrincipalId` | Optional assertion; discover the target primary identity object ID and require an exact match when supplied |\n| `TargetDataPath`, `TargetLogPath` | Optional; use validated target defaults |\n| `OverwriteExistingTarget` | Default to `false` |\n| `TrustServerCertificate` | Default to `false` |\n\nDiscover SQL versions, editions, defaults, and database metadata instead of\nasking for them. Never connect to either the source or target with SQL login\u002FSQL\nauthentication. Do not request, accept, retrieve, or use SQL passwords or SQL\ncredentials. Use only Windows Integrated authentication or Microsoft Entra\nauthentication supported by the workflow. Never read SQL credentials from Key\nVault or Credential Manager, or display a password prompt.\n\nNormalize a supplied `ContainerUrl` by extracting its storage account and\ncontainer names. Group enabled subscriptions by tenant. For each tenant query,\nselect one subscription with `az account set`, confirm the active tenant with\n`az account show`, and run `az graph query` without `--tenant` or\n`--subscriptions`. Parse results from `response.data` and filter them against the\nknown enabled subscription IDs for that tenant. Query the current\u002Fdefault tenant\nfirst and query other signed-in tenants only if the account is not uniquely found\nthere or the user supplied a different tenant. Reuse the same tenant-scoped ARG\nhelper for storage-account and target-host discovery. Use\n`az storage account show` only for the one matched resource\nto read its `primaryEndpoints.blob` URI, then combine that URI with the validated\ncontainer name. When only a container name is supplied,\nsearch accessible storage accounts with the user's Entra data-plane access and\nselect its owner only if the match is unique. The destination backup Blob object\nname is generated later; do not confuse it with the container name. Never\nconstruct an endpoint suffix by assumption; this preserves sovereign-cloud\nendpoints.\n\nAfter discovery, display one sanitized execution plan containing endpoint names,\ndatabase scope, local and Blob paths, overwrite choices, discovered target hosting\nand identity, target host and storage resource IDs, and authentication methods.\nAsk once for migration execution acceptance. If discovery leaves multiple\nstorage accounts, containers, subscriptions, or target hosts, present all\nremaining choices together in that same prompt.\nChanging an overwrite value from `false` to `true` requires a new explicit\nacceptance.\n\nValidate execution-plan responses as typed data before acting. Never coerce a\nfree-form string in `OverwriteLocalBackup`, `OverwriteExistingTarget`, or an\napproval field to Boolean. If an overwrite response contains a path, treat it as\na proposed `LocalBackupRoot` change, rerun path and collision discovery, and\ndisplay a revised plan for acceptance. Likewise, a requested database exclusion\nchanges the migration scope and requires revised plan acceptance.\n\n## Tool prerequisites\n\nRequire all of the following on the host where each command runs:\n\n- Go `sqlcmd`, selected from every PATH candidate by a successful `--version`\n  check and the required flags across modern (`--help`) and SQLCMD-compatible\n  (`-?`) help for Windows Integrated and Microsoft Entra authentication.\n- AzCopy v10 on the transfer host, validated with `azcopy --version`.\n- Azure CLI on the transfer\u002Fadministration host, validated with `az version`.\n- Azure CLI `resource-graph` extension, validated with\n  `az extension show --name resource-graph`. Install it with\n  `az extension add --name resource-graph` before Azure discovery.\n\nTransport SQL query results as strict pipe-delimited rows produced by `sqlcmd`\nwith headers disabled. Do not use `FOR JSON`, `FOR XML`, or formatted console\ntables as a SQL-to-PowerShell serialization format. Prefix each row with a stable\nrecord type, encode nullable text fields as specified in\n`references\u002Fcommand-execution-discovery.md`, require the exact field count for that record\ntype, and convert numeric and Boolean fields explicitly. This restriction applies\nto SQL result sets only; Azure CLI JSON output remains the required format for\nAzure control-plane responses.\n\nDetect the tools before collecting execution acceptance. If AzCopy v10 or Azure\nCLI is missing, return `Needs input`, give the official Microsoft Learn install\nlink, and ask the user to install it. If the `resource-graph` extension is\nmissing, return `Needs input` with the exact extension install command and the\nMicrosoft Learn Azure Resource Graph CLI link. Do not install tools, extensions,\nportable binaries, or package managers silently. Cache each validated canonical\nexecutable path for the run.\n\nUse one interactive Azure CLI user sign-in only when no usable session exists.\nDerive the tenant from the selected subscription unless the user supplied an\nassertion. Configure AzCopy to reuse that user session with\n`AZCOPY_AUTO_LOGIN_TYPE=AZCLI` and `AZCOPY_TENANT_ID`. Do not run a separate\nservice-principal or managed-identity AzCopy login.\n\nThe signed-in user needs `Storage Blob Data Contributor` on the destination\ncontainer or storage account to upload. The user also needs permission to read\nand, when absent, create the target identity's storage role assignment. If the\nrole assignment cannot be created, report the required principal, role, scope,\nand exact Azure error; do not elevate or substitute credentials.\n\n## Workflow\n\n```text\nPhase 0  Parse one intake; gate tools and sign-in; resolve storage and target host\nPhase 1  Connect; require source ProductMajorVersion = 10..17 and target = 17\nPhase 2  Prove target primary managed identity and storage role assignment\nPhase 3  Build one database manifest and resolve local overwrite behavior\nPhase 4  Create and verify one COPY_ONLY full backup on local disk\nPhase 5  Upload the backup with AzCopy under the operator's Entra identity\nPhase 6  Create and verify the target managed-identity URL credential\nPhase 7  Inspect, verify, map, and restore the backup from URL\nPhase 8  Report completion and continue with the next database\n```\n\n## Phase requirements\n\n### Phase 0 - Tools and authentication\n\nValidate and cache tool paths once. Connect independently to source and target\nusing Windows Integrated or direct Microsoft Entra SQL authentication. Require\nencrypted SQL transport and certificate validation unless the accepted plan sets\n`TrustServerCertificate=true`.\n\nResolve `TrustServerCertificate` before constructing or attempting either SQL\nconnection. Do not use a failed connection as a prompt to decide certificate\ntrust.\n\nAuthenticate the user to Azure CLI once and make AzCopy reuse that session.\nUse Azure Resource Graph name filters for storage account and target-resource\ndiscovery instead of enumerating each subscription. Search the current\u002Fdefault\ntenant first and widen to other signed-in tenants only when needed. Cache\ndiscovery for the complete multi-database run. Before any cross-subscription or\ncross-tenant discovery, capture the original Azure CLI subscription and tenant.\nRestore that subscription in a `finally` block after every temporary context\nswitch and use `az account show` to prove both the original subscription and\ntenant were restored. Later operations must either pass their resolved\nsubscription explicitly or use the same temporary-switch-and-restore pattern;\nnever inherit whichever context a discovery probe happened to select.\n\n### Phase 1 - SQL discovery and target gate\n\nDiscover both instances and online source user databases. `All` expands only to\nthe online result set. Omit every non-online database from the migration queue;\nif the user explicitly named one, report its current state as `Excluded` without\nblocking the remaining online databases. Block unless the target is\nSQL Server 2025 major version `17`, is not Azure SQL Managed Instance, and is not\na failover cluster instance. On the target, read `host_platform` from\n`sys.dm_os_host_info` and require its value to equal `Windows`; do not use\n`SERVERPROPERTY('HostPlatform')` as the authoritative gate because it can return\n`NULL`. Location does not otherwise affect eligibility. A source backup from a\nnewer SQL major version also blocks restore.\n\nDiscover the source default backup path with\n`SERVERPROPERTY('InstanceDefaultBackupPath')`. When it returns `NULL`, including\non SQL Server 2016, read `BackupDirectory` with\n`master.dbo.xp_instance_regread`. Validate that the resolved directory exists,\nis visible to the SQL Server service, and has sufficient free space.\n\nCheck source backup permission, local path visibility and free space, target\nrestore permission, target paths and free space, encryption dependencies, and\ntarget database\u002Ffile collisions.\n\nResolve every known local-file, target-database, and target-physical-file\ncollision before starting the first database. For an `All` plan, do not migrate\nearlier databases while a later database has an unresolved collision. Obtain\nexplicit overwrite acceptance, accept an explicitly revised scope that excludes\nthe colliding database, or return `Blocked`.\n\n### Phase 2 - Identity and storage\n\nInfer target hosting from the uniquely discovered Azure resource. For an Azure\nVM, prove SQL IaaS Agent registration and a configured SQL primary managed\nidentity. Otherwise require a SQL Server 2025 enabled by Azure Arc resource, the\nlatest Azure Extension for SQL Server, and its primary managed identity. A\nphysical server or VM in any other environment is supported through Arc; do not\nreject it merely because it is not an Azure VM.\n\nWhen `TargetManagedIdentityPrincipalId` was supplied, require an exact object-ID\nmatch. If Arc enrollment or the SQL primary identity is missing, return one\n`Needs input` result containing every missing prerequisite and the Microsoft\nLearn portal steps. Do not automate the documented registry route.\n\nVerify or create `Storage Blob Data Contributor` for that principal at\n`StorageAccountResourceId`. Wait for role propagation by retrying the\nnon-destructive target metadata read only after credential creation; do not use\narbitrary sleep loops.\n\n### Phase 3 - Manifest and overwrite decision\n\nUse one deterministic file per database:\n\n```text\n\u003CLocalBackupRoot>\\\u003Cvalidated-database-artifact-name>_migration.bak\n\u003CResolvedContainerUrl>\u002F\u003Cencoded-artifact-name>\u002F\u003Cencoded-migration-utc>\u002F\u003Cencoded-backup-file-name>\n```\n\nNever interpolate a SQL database name directly into a filesystem path or Blob\nURL. Derive a separate deterministic ASCII artifact name, validate it against a\nstrict allowlist, retain its mapping to the source and target database names in\nthe manifest, and verify the resolved local file remains directly beneath\n`LocalBackupRoot`. Percent-encode each Blob object path segment independently;\ndo not encode the complete URL as one string and do not allow a database name to\nintroduce `\u002F`, `\\`, `#`, `%`, a query, or a fragment.\n\nIf the local file exists and `OverwriteLocalBackup=false`, stop before backup and\nask for a different root or explicit overwrite acceptance. If overwrite is\naccepted, use `INIT, SKIP`; otherwise use `INIT` only for a path proven absent.\nNever append with `NOINIT`.\n\n### Phase 4 - Local backup\n\nRun `BACKUP DATABASE ... TO DISK`, followed by local `RESTORE VERIFYONLY` and\n`RESTORE HEADERONLY`. Record the database name, backup type, backup start\u002Ffinish,\nbackup set GUID, database version, first\u002Flast LSN, size, local path, and file hash.\nMaterialize escaped SQL identifiers and literals in PowerShell before creating an\nexpandable here-string. Do not put nested `.Replace()` expressions inside the\nhere-string, and pass the backup path through a T-SQL variable.\n\n### Phase 5 - AzCopy upload\n\nUse `azcopy copy` for the single file with an HTTPS destination that contains no\nquery string. Set `--from-to=LocalBlob`, `--overwrite=false`, and\n`--check-length=true`. Require exit code zero, exactly one\n`Final Job Status: Completed` line, exactly one completed file transfer, and zero\nfor every reported skipped-transfer count. Reject prefix statuses such as\n`CompletedWithSkipped`. Then use\nEntra-authenticated `azcopy list` to prove the exact Blob exists and its content\nlength equals the local file length. Use `--machine-readable` for exact-URL\nlistings; do not use a valueless `--properties` option. Treat a successful exact\nlisting containing the expected `Content Length` as proof even when AzCopy omits\nthe filename. A pre-existing Blob path blocks the run. If post-upload listing\ncannot prove the expected length, never rerun `azcopy copy`; rerun only the\nnon-destructive listing.\n\n### Phase 6 - Target credential\n\nRun the executable credential reconciler in the command reference. Only its\n`Absent` branch may create the URL-scoped server credential, using exactly:\n\n```sql\nCREATE CREDENTIAL [https:\u002F\u002F\u003Caccount>.blob.core.windows.net\u002F\u003Ccontainer>]\n    WITH IDENTITY = 'Managed Identity';\n```\n\nEnable trace flag 4675 for the credential-creation session so a missing primary\nidentity is surfaced. If an exact URL credential already exists, reuse it only\nwhen `credential_identity = 'Managed Identity'`. Classify credential state as\n`Absent`, `Matching`, or `Conflicting`; create only for `Absent`, reuse only for\n`Matching`, and for `Conflicting` report the exact existing name and identity and\nstop without altering or dropping it. Any repair is a separate mutation requiring\nexplicit definition and approval. Never include a\n`SECRET` clause.\n\n### Phase 7 - Restore\n\nRun `RESTORE HEADERONLY`, `RESTORE FILELISTONLY`, and `RESTORE VERIFYONLY` from\nthe Blob URL. Map every logical file to a validated target path. Restore with\n`RECOVERY`, `CHECKSUM`, `STATS = 10`, and `MOVE` for every file.\n\nIf `OverwriteExistingTarget=false`, any target database or physical-file\ncollision blocks restore. If overwrite was explicitly accepted, show the final\ndatabase and file mapping immediately before using `REPLACE`; do not drop the\ntarget database automatically.\n\n### Phase 8 - Complete\n\nRequire the target database to be `ONLINE`. Report the source backup metadata,\nlocal file path and hash, AzCopy job ID, Blob URL and size, target identity\nprincipal ID, credential identity, restore timestamps, target paths, and final\ndatabase state. Do not delete the local backup, Blob, or managed-identity\ncredential. Do not switch application connections automatically.\n\nPreserve `TargetAuthentication` in the immutable post-migration validation\nhandoff. Include `TargetUser` only when that mode is `Entra`, identify the target\ntype as `SQL VM`, and pass the verified reusable target connection handle when\navailable. If that handle later becomes unavailable, validation must retain a\n`Windows` handoff with `-E` instead of changing the target identity to Entra.\n\n## Result format\n\nReport `Needs input`, `Ready`, `Blocked`, `Running`, `Completed`, or `Failed`.\nReserve `Blocked` for a technical gate that was executed and failed. Include one\nrow per database with local backup, AzCopy upload, target credential, restore,\nand final-state status, plus the exact next technical action for failures.\n\n## References\n\n- [Command execution reference — discovery and setup](references\u002Fcommand-execution-discovery.md)\n- [Command execution reference — backup and restore](references\u002Fcommand-execution-backup-restore.md)\n- [Managed identity support for backup and restore](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Ftroubleshoot\u002Fsql\u002Freleases\u002Fsqlserver-2022\u002Fmicrosoft-entra-managed-identity-support-for-backup-restore-database-ekm-akv)\n- [SQL Server 2025 Arc backup to URL with managed identity](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Fsql-server\u002Fazure-arc\u002Fbackup-to-url)\n- [Set up managed identity for SQL Server 2025 enabled by Azure Arc](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Fsql-server\u002Fazure-arc\u002Fmicrosoft-entra-authentication-with-managed-identity)\n- [Authorize AzCopy with a user identity](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fstorage\u002Fcommon\u002Fstorage-use-azcopy-authorize-user-identity)\n- [Upload files with AzCopy](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fstorage\u002Fcommon\u002Fstorage-use-azcopy-blobs-upload)\n- [Run an Azure Resource Graph query with Azure CLI](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fgovernance\u002Fresource-graph\u002Ffirst-query-azurecli)\n- [BACKUP](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Ft-sql\u002Fstatements\u002Fbackup-transact-sql?view=sql-server-ver17)\n- [RESTORE](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Ft-sql\u002Fstatements\u002Frestore-statements-transact-sql?view=sql-server-ver17)","# Local backup and AzCopy migration to SQL Server 2025\n\n## When to Use\n\n- Migrate SQL Server 2008 through SQL Server 2025 to a SQL Server 2025 target using backup and restore.\n- Move a local full backup through Azure Blob Storage with AzCopy and restore it with the target managed identity.\n\nMigrate one database or an ordered set of user databases from SQL Server 2008\nthrough SQL Server 2025 to a SQL Server 2025 target running in Azure,\non-premises, or in another cloud. Sources newer than SQL Server 2025 are blocked\nbecause target restore compatibility has not been validated.\nCreate each full backup on a local source volume, upload the file to a private\nAzure Blob container with AzCopy v10 and the signed-in operator's Microsoft Entra\nidentity, then restore it from URL with the target SQL Server primary managed\nidentity.\n\nRead [references\u002Fcommand-execution-discovery.md](references\u002Fcommand-execution-discovery.md) and\n[references\u002Fcommand-execution-backup-restore.md](references\u002Fcommand-execution-backup-restore.md)\nbefore generating or running commands.\n\n## Operating contract\n\n- Process one database completely before starting the next. `All` never includes\n  `master`, `model`, `msdb`, or `tempdb`.\n- Build the migration queue only from source user databases whose state is\n  `ONLINE`. Exclude `OFFLINE`, `SUSPECT`, `RESTORING`, `RECOVERING`,\n  `RECOVERY_PENDING`, `EMERGENCY`, and every other non-online state. Never change\n  a database's state to make it eligible.\n- Use exactly one backup artifact per database: a `COPY_ONLY` full database\n  backup. This workflow does not alter source availability or recovery state.\n- Back up only to a local disk path visible to the source SQL Server service.\n  Never use `BACKUP TO URL` on the source.\n- Run AzCopy on the source host, or on an approved transfer host that can read the\n  exact backup path without copying the file through the chat host.\n- Use only the operator's Microsoft Entra identity for AzCopy. Never use storage\n  account keys, connection strings, signed URL query parameters, or embedded\n  secrets.\n- Require a pre-created private HTTPS Blob container. Do not create or make a\n  container public.\n- Gate the target on SQL Server 2025: `ProductMajorVersion` must equal `17`.\n  Newer or older major versions do not satisfy this explicit gate.\n- Supported source versions are SQL Server 2008 through SQL Server 2025,\n  represented by major versions `10` through `17`. Block older sources and\n  sources newer than SQL Server 2025 because target restore compatibility has\n  not been validated outside that range.\n- Support the target in any physical or cloud location, but require Windows\n  because SQL Server server-level managed identity is not supported on Linux.\n  Failover cluster instances remain unsupported.\n- Determine target hosting from SQL and Azure discovery; do not ask the user to\n  classify the target. For SQL Server on Azure VM, use its SQL IaaS Agent and\n  Microsoft Entra configuration. For SQL Server elsewhere, use SQL Server 2025\n  enabled by Azure Arc with the latest Azure Extension for SQL Server. The SQL\n  version gate is identical in every location.\n- Require a primary managed identity configured for the target SQL Server\n  instance. A target outside Azure that is not enabled by Azure Arc is a single\n  prerequisite blocker, not a different migration route.\n- Blob Storage does not receive a managed identity. Assign the target SQL\n  instance's primary managed-identity principal `Storage Blob Data Contributor`\n  on the storage account, then create the URL-scoped SQL credential with\n  `IDENTITY = 'Managed Identity'` on the target.\n- Do not provide an alternate Blob authentication route. If user upload access,\n  target identity configuration, target RBAC, network access, credential\n  creation, or URL restore fails, stop with the exact failure.\n- Never overwrite a local backup file unless `OverwriteLocalBackup=true` was\n  explicitly included in the accepted plan. Never append a migration backup to\n  an existing media set.\n- Never overwrite a target database or physical database file unless\n  `OverwriteExistingTarget=true` was explicitly accepted after displaying the\n  target database and affected files.\n- Always use `CHECKSUM`, `COPY_ONLY`, and `STATS = 10`; use `COMPRESSION` when\n  supported and not prohibited by policy.\n- Verify the local backup before upload. After upload, use target\n  `RESTORE HEADERONLY`, `RESTORE FILELISTONLY`, and `RESTORE VERIFYONLY` before\n  `RESTORE DATABASE`.\n- Preserve local and Blob backup files after migration. Do not delete either\n  automatically.\n- If upload succeeds but post-upload verification fails, never retry the upload.\n  Rerun only the non-destructive exact-Blob listing and stop if it cannot prove\n  the expected content length.\n- Stop on the first failed gate or operation. Never describe a submitted command\n  as complete until its exit status or SQL result proves completion.\n\n## Consolidated intake\n\nThe source discovered from `SourceServer` must be SQL Server 2008 through SQL\nServer 2025 (major version `10` through `17`). Do not offer this workflow for a\nsource outside that range.\n\nAccept natural language, one `Key=Value` block, or a JSON object with these exact\nkeys. Accumulate everything the user provides, run discovery for omitted values,\nand ask at most one consolidated follow-up listing all fields that remain\nambiguous or undiscoverable. Never ask for source, target, storage, identity, or\noverwrite values as separate questions. Parse pasted structured input strictly\nas data, reject duplicate keys, and reject unknown keys as likely typos.\n\nTreat a complete initial `Key=Value` block as the consolidated intake. When all\nrequired undiscoverable values are present, do not ask an intake question; run\ndiscovery and proceed to the mandatory sanitized execution-plan approval.\nResolve `TrustServerCertificate` to an explicit Boolean before attempting either\nSQL connection. Use one consolidated intake block containing the source, target,\nstorage, database-scope, and overwrite fields. Source and target authentication\nmust be `Windows` or `Entra` interactive authentication; no other login type is\nsupported. For Entra interactive authentication, use the approved interactive\nsign-in flow and do not place an access token in command arguments. Validate both\nconnections with the resolved authentication method and certificate setting\nbefore proceeding to backup or restore operations.\n\n```text\nSourceServer=\u003Csource>\nSourceDatabases=All\nTargetServer=\u003Ctarget>\nStorageAccountName=\u003Cstorage-account>\nContainerName=\u003Cprivate-container>\nTrustServerCertificate=false\n```\n\n```text\nSourceServer=\nSourceAuthentication=Windows|Entra\nSourceUser=\nSourceDatabases=All\nTargetServer=\nTargetAuthentication=Windows|Entra\nTargetUser=\nTargetDatabase=\nLocalBackupRoot=\nOverwriteLocalBackup=false\nContainerUrl=\nStorageAccountName=\nContainerName=\nStorageAccountResourceId=\nAzureTenantId=\nTargetHostResourceId=\nTargetManagedIdentityPrincipalId=\nTargetDataPath=\nTargetLogPath=\nOverwriteExistingTarget=false\nTrustServerCertificate=false\n```\n\nApply these defaults and requirements:\n\n| Key | Handling |\n| --- | --- |\n| `SourceServer`, `TargetServer` | Required after the single consolidated intake |\n| `SourceAuthentication`, `TargetAuthentication` | Default to `Windows` |\n| `SourceUser`, `TargetUser` | Required only for `Entra` |\n| `SourceDatabases` | Discover only online user databases; accept one, a comma-separated list, or `All`; report explicitly named non-online databases as excluded |\n| `TargetDatabase` | Optional for one database; preserve source names for multiple databases |\n| `LocalBackupRoot` | Default to the discovered source `InstanceDefaultBackupPath` |\n| `OverwriteLocalBackup` | Default to `false` |\n| `ContainerUrl` | Preferred; when absent, derive it from `StorageAccountName` and `ContainerName` |\n| `StorageAccountName` | Optional when `ContainerUrl` is supplied; treat a user-supplied \"Blob storage name\" as this Azure storage account name |\n| `ContainerName` | Required after discovery; treat an existing user-supplied Blob container name as this value and search accessible storage accounts for its unique owner |\n| `StorageAccountResourceId` | Optional; use Azure Resource Graph to discover it by storage account name, querying the default tenant first |\n| `AzureTenantId` | Optional; derive from the selected Azure CLI subscription\u002Faccount |\n| `TargetHostResourceId` | Optional; discover the Azure VM or Arc-enabled server from `TargetServer` across accessible subscriptions |\n| `TargetManagedIdentityPrincipalId` | Optional assertion; discover the target primary identity object ID and require an exact match when supplied |\n| `TargetDataPath`, `TargetLogPath` | Optional; use validated target defaults |\n| `OverwriteExistingTarget` | Default to `false` |\n| `TrustServerCertificate` | Default to `false` |\n\nDiscover SQL versions, editions, defaults, and database metadata instead of\nasking for them. Never connect to either the source or target with SQL login\u002FSQL\nauthentication. Do not request, accept, retrieve, or use SQL passwords or SQL\ncredentials. Use only Windows Integrated authentication or Microsoft Entra\nauthentication supported by the workflow. Never read SQL credentials from Key\nVault or Credential Manager, or display a password prompt.\n\nNormalize a supplied `ContainerUrl` by extracting its storage account and\ncontainer names. Group enabled subscriptions by tenant. For each tenant query,\nselect one subscription with `az account set`, confirm the active tenant with\n`az account show`, and run `az graph query` without `--tenant` or\n`--subscriptions`. Parse results from `response.data` and filter them against the\nknown enabled subscription IDs for that tenant. Query the current\u002Fdefault tenant\nfirst and query other signed-in tenants only if the account is not uniquely found\nthere or the user supplied a different tenant. Reuse the same tenant-scoped ARG\nhelper for storage-account and target-host discovery. Use\n`az storage account show` only for the one matched resource\nto read its `primaryEndpoints.blob` URI, then combine that URI with the validated\ncontainer name. When only a container name is supplied,\nsearch accessible storage accounts with the user's Entra data-plane access and\nselect its owner only if the match is unique. The destination backup Blob object\nname is generated later; do not confuse it with the container name. Never\nconstruct an endpoint suffix by assumption; this preserves sovereign-cloud\nendpoints.\n\nAfter discovery, display one sanitized execution plan containing endpoint names,\ndatabase scope, local and Blob paths, overwrite choices, discovered target hosting\nand identity, target host and storage resource IDs, and authentication methods.\nAsk once for migration execution acceptance. If discovery leaves multiple\nstorage accounts, containers, subscriptions, or target hosts, present all\nremaining choices together in that same prompt.\nChanging an overwrite value from `false` to `true` requires a new explicit\nacceptance.\n\nValidate execution-plan responses as typed data before acting. Never coerce a\nfree-form string in `OverwriteLocalBackup`, `OverwriteExistingTarget`, or an\napproval field to Boolean. If an overwrite response contains a path, treat it as\na proposed `LocalBackupRoot` change, rerun path and collision discovery, and\ndisplay a revised plan for acceptance. Likewise, a requested database exclusion\nchanges the migration scope and requires revised plan acceptance.\n\n## Tool prerequisites\n\nRequire all of the following on the host where each command runs:\n\n- Go `sqlcmd`, selected from every PATH candidate by a successful `--version`\n  check and the required flags across modern (`--help`) and SQLCMD-compatible\n  (`-?`) help for Windows Integrated and Microsoft Entra authentication.\n- AzCopy v10 on the transfer host, validated with `azcopy --version`.\n- Azure CLI on the transfer\u002Fadministration host, validated with `az version`.\n- Azure CLI `resource-graph` extension, validated with\n  `az extension show --name resource-graph`. Install it with\n  `az extension add --name resource-graph` before Azure discovery.\n\nTransport SQL query results as strict pipe-delimited rows produced by `sqlcmd`\nwith headers disabled. Do not use `FOR JSON`, `FOR XML`, or formatted console\ntables as a SQL-to-PowerShell serialization format. Prefix each row with a stable\nrecord type, encode nullable text fields as specified in\n`references\u002Fcommand-execution-discovery.md`, require the exact field count for that record\ntype, and convert numeric and Boolean fields explicitly. This restriction applies\nto SQL result sets only; Azure CLI JSON output remains the required format for\nAzure control-plane responses.\n\nDetect the tools before collecting execution acceptance. If AzCopy v10 or Azure\nCLI is missing, return `Needs input`, give the official Microsoft Learn install\nlink, and ask the user to install it. If the `resource-graph` extension is\nmissing, return `Needs input` with the exact extension install command and the\nMicrosoft Learn Azure Resource Graph CLI link. Do not install tools, extensions,\nportable binaries, or package managers silently. Cache each validated canonical\nexecutable path for the run.\n\nUse one interactive Azure CLI user sign-in only when no usable session exists.\nDerive the tenant from the selected subscription unless the user supplied an\nassertion. Configure AzCopy to reuse that user session with\n`AZCOPY_AUTO_LOGIN_TYPE=AZCLI` and `AZCOPY_TENANT_ID`. Do not run a separate\nservice-principal or managed-identity AzCopy login.\n\nThe signed-in user needs `Storage Blob Data Contributor` on the destination\ncontainer or storage account to upload. The user also needs permission to read\nand, when absent, create the target identity's storage role assignment. If the\nrole assignment cannot be created, report the required principal, role, scope,\nand exact Azure error; do not elevate or substitute credentials.\n\n## Workflow\n\n```text\nPhase 0  Parse one intake; gate tools and sign-in; resolve storage and target host\nPhase 1  Connect; require source ProductMajorVersion = 10..17 and target = 17\nPhase 2  Prove target primary managed identity and storage role assignment\nPhase 3  Build one database manifest and resolve local overwrite behavior\nPhase 4  Create and verify one COPY_ONLY full backup on local disk\nPhase 5  Upload the backup with AzCopy under the operator's Entra identity\nPhase 6  Create and verify the target managed-identity URL credential\nPhase 7  Inspect, verify, map, and restore the backup from URL\nPhase 8  Report completion and continue with the next database\n```\n\n## Phase requirements\n\n### Phase 0 - Tools and authentication\n\nValidate and cache tool paths once. Connect independently to source and target\nusing Windows Integrated or direct Microsoft Entra SQL authentication. Require\nencrypted SQL transport and certificate validation unless the accepted plan sets\n`TrustServerCertificate=true`.\n\nResolve `TrustServerCertificate` before constructing or attempting either SQL\nconnection. Do not use a failed connection as a prompt to decide certificate\ntrust.\n\nAuthenticate the user to Azure CLI once and make AzCopy reuse that session.\nUse Azure Resource Graph name filters for storage account and target-resource\ndiscovery instead of enumerating each subscription. Search the current\u002Fdefault\ntenant first and widen to other signed-in tenants only when needed. Cache\ndiscovery for the complete multi-database run. Before any cross-subscription or\ncross-tenant discovery, capture the original Azure CLI subscription and tenant.\nRestore that subscription in a `finally` block after every temporary context\nswitch and use `az account show` to prove both the original subscription and\ntenant were restored. Later operations must either pass their resolved\nsubscription explicitly or use the same temporary-switch-and-restore pattern;\nnever inherit whichever context a discovery probe happened to select.\n\n### Phase 1 - SQL discovery and target gate\n\nDiscover both instances and online source user databases. `All` expands only to\nthe online result set. Omit every non-online database from the migration queue;\nif the user explicitly named one, report its current state as `Excluded` without\nblocking the remaining online databases. Block unless the target is\nSQL Server 2025 major version `17`, is not Azure SQL Managed Instance, and is not\na failover cluster instance. On the target, read `host_platform` from\n`sys.dm_os_host_info` and require its value to equal `Windows`; do not use\n`SERVERPROPERTY('HostPlatform')` as the authoritative gate because it can return\n`NULL`. Location does not otherwise affect eligibility. A source backup from a\nnewer SQL major version also blocks restore.\n\nDiscover the source default backup path with\n`SERVERPROPERTY('InstanceDefaultBackupPath')`. When it returns `NULL`, including\non SQL Server 2016, read `BackupDirectory` with\n`master.dbo.xp_instance_regread`. Validate that the resolved directory exists,\nis visible to the SQL Server service, and has sufficient free space.\n\nCheck source backup permission, local path visibility and free space, target\nrestore permission, target paths and free space, encryption dependencies, and\ntarget database\u002Ffile collisions.\n\nResolve every known local-file, target-database, and target-physical-file\ncollision before starting the first database. For an `All` plan, do not migrate\nearlier databases while a later database has an unresolved collision. Obtain\nexplicit overwrite acceptance, accept an explicitly revised scope that excludes\nthe colliding database, or return `Blocked`.\n\n### Phase 2 - Identity and storage\n\nInfer target hosting from the uniquely discovered Azure resource. For an Azure\nVM, prove SQL IaaS Agent registration and a configured SQL primary managed\nidentity. Otherwise require a SQL Server 2025 enabled by Azure Arc resource, the\nlatest Azure Extension for SQL Server, and its primary managed identity. A\nphysical server or VM in any other environment is supported through Arc; do not\nreject it merely because it is not an Azure VM.\n\nWhen `TargetManagedIdentityPrincipalId` was supplied, require an exact object-ID\nmatch. If Arc enrollment or the SQL primary identity is missing, return one\n`Needs input` result containing every missing prerequisite and the Microsoft\nLearn portal steps. Do not automate the documented registry route.\n\nVerify or create `Storage Blob Data Contributor` for that principal at\n`StorageAccountResourceId`. Wait for role propagation by retrying the\nnon-destructive target metadata read only after credential creation; do not use\narbitrary sleep loops.\n\n### Phase 3 - Manifest and overwrite decision\n\nUse one deterministic file per database:\n\n```text\n\u003CLocalBackupRoot>\\\u003Cvalidated-database-artifact-name>_migration.bak\n\u003CResolvedContainerUrl>\u002F\u003Cencoded-artifact-name>\u002F\u003Cencoded-migration-utc>\u002F\u003Cencoded-backup-file-name>\n```\n\nNever interpolate a SQL database name directly into a filesystem path or Blob\nURL. Derive a separate deterministic ASCII artifact name, validate it against a\nstrict allowlist, retain its mapping to the source and target database names in\nthe manifest, and verify the resolved local file remains directly beneath\n`LocalBackupRoot`. Percent-encode each Blob object path segment independently;\ndo not encode the complete URL as one string and do not allow a database name to\nintroduce `\u002F`, `\\`, `#`, `%`, a query, or a fragment.\n\nIf the local file exists and `OverwriteLocalBackup=false`, stop before backup and\nask for a different root or explicit overwrite acceptance. If overwrite is\naccepted, use `INIT, SKIP`; otherwise use `INIT` only for a path proven absent.\nNever append with `NOINIT`.\n\n### Phase 4 - Local backup\n\nRun `BACKUP DATABASE ... TO DISK`, followed by local `RESTORE VERIFYONLY` and\n`RESTORE HEADERONLY`. Record the database name, backup type, backup start\u002Ffinish,\nbackup set GUID, database version, first\u002Flast LSN, size, local path, and file hash.\nMaterialize escaped SQL identifiers and literals in PowerShell before creating an\nexpandable here-string. Do not put nested `.Replace()` expressions inside the\nhere-string, and pass the backup path through a T-SQL variable.\n\n### Phase 5 - AzCopy upload\n\nUse `azcopy copy` for the single file with an HTTPS destination that contains no\nquery string. Set `--from-to=LocalBlob`, `--overwrite=false`, and\n`--check-length=true`. Require exit code zero, exactly one\n`Final Job Status: Completed` line, exactly one completed file transfer, and zero\nfor every reported skipped-transfer count. Reject prefix statuses such as\n`CompletedWithSkipped`. Then use\nEntra-authenticated `azcopy list` to prove the exact Blob exists and its content\nlength equals the local file length. Use `--machine-readable` for exact-URL\nlistings; do not use a valueless `--properties` option. Treat a successful exact\nlisting containing the expected `Content Length` as proof even when AzCopy omits\nthe filename. A pre-existing Blob path blocks the run. If post-upload listing\ncannot prove the expected length, never rerun `azcopy copy`; rerun only the\nnon-destructive listing.\n\n### Phase 6 - Target credential\n\nRun the executable credential reconciler in the command reference. Only its\n`Absent` branch may create the URL-scoped server credential, using exactly:\n\n```sql\nCREATE CREDENTIAL [https:\u002F\u002F\u003Caccount>.blob.core.windows.net\u002F\u003Ccontainer>]\n    WITH IDENTITY = 'Managed Identity';\n```\n\nEnable trace flag 4675 for the credential-creation session so a missing primary\nidentity is surfaced. If an exact URL credential already exists, reuse it only\nwhen `credential_identity = 'Managed Identity'`. Classify credential state as\n`Absent`, `Matching`, or `Conflicting`; create only for `Absent`, reuse only for\n`Matching`, and for `Conflicting` report the exact existing name and identity and\nstop without altering or dropping it. Any repair is a separate mutation requiring\nexplicit definition and approval. Never include a\n`SECRET` clause.\n\n### Phase 7 - Restore\n\nRun `RESTORE HEADERONLY`, `RESTORE FILELISTONLY`, and `RESTORE VERIFYONLY` from\nthe Blob URL. Map every logical file to a validated target path. Restore with\n`RECOVERY`, `CHECKSUM`, `STATS = 10`, and `MOVE` for every file.\n\nIf `OverwriteExistingTarget=false`, any target database or physical-file\ncollision blocks restore. If overwrite was explicitly accepted, show the final\ndatabase and file mapping immediately before using `REPLACE`; do not drop the\ntarget database automatically.\n\n### Phase 8 - Complete\n\nRequire the target database to be `ONLINE`. Report the source backup metadata,\nlocal file path and hash, AzCopy job ID, Blob URL and size, target identity\nprincipal ID, credential identity, restore timestamps, target paths, and final\ndatabase state. Do not delete the local backup, Blob, or managed-identity\ncredential. Do not switch application connections automatically.\n\nPreserve `TargetAuthentication` in the immutable post-migration validation\nhandoff. Include `TargetUser` only when that mode is `Entra`, identify the target\ntype as `SQL VM`, and pass the verified reusable target connection handle when\navailable. If that handle later becomes unavailable, validation must retain a\n`Windows` handoff with `-E` instead of changing the target identity to Entra.\n\n## Result format\n\nReport `Needs input`, `Ready`, `Blocked`, `Running`, `Completed`, or `Failed`.\nReserve `Blocked` for a technical gate that was executed and failed. Include one\nrow per database with local backup, AzCopy upload, target credential, restore,\nand final-state status, plus the exact next technical action for failures.\n\n## References\n\n- [Command execution reference — discovery and setup](references\u002Fcommand-execution-discovery.md)\n- [Command execution reference — backup and restore](references\u002Fcommand-execution-backup-restore.md)\n- [Managed identity support for backup and restore](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Ftroubleshoot\u002Fsql\u002Freleases\u002Fsqlserver-2022\u002Fmicrosoft-entra-managed-identity-support-for-backup-restore-database-ekm-akv)\n- [SQL Server 2025 Arc backup to URL with managed identity](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Fsql-server\u002Fazure-arc\u002Fbackup-to-url)\n- [Set up managed identity for SQL Server 2025 enabled by Azure Arc](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Fsql-server\u002Fazure-arc\u002Fmicrosoft-entra-authentication-with-managed-identity)\n- [Authorize AzCopy with a user identity](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fstorage\u002Fcommon\u002Fstorage-use-azcopy-authorize-user-identity)\n- [Upload files with AzCopy](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fstorage\u002Fcommon\u002Fstorage-use-azcopy-blobs-upload)\n- [Run an Azure Resource Graph query with Azure CLI](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fazure\u002Fgovernance\u002Fresource-graph\u002Ffirst-query-azurecli)\n- [BACKUP](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Ft-sql\u002Fstatements\u002Fbackup-transact-sql?view=sql-server-ver17)\n- [RESTORE](https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fsql\u002Ft-sql\u002Fstatements\u002Frestore-statements-transact-sql?view=sql-server-ver17)",{"name":5,"description":7},"main","d2b16500cb10bf44117390e08717ca731032d423","corenote\u002Fmigration\u002Fskills\u002Fsql-backup-restore-to-azure-sql-vm-migration",0,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-01 23:31:12",{"source":8,"skillName":5,"commands":50,"prompt":60,"zipAvailable":61},[51,54,57],{"tool":52,"command":53},"npx","npx skills add microsoft\u002Fsqlcon-eu-2026-demos --skill sql-backup-restore-to-azure-sql-vm-migration",{"tool":55,"command":56},"bunx","bunx skills add microsoft\u002Fsqlcon-eu-2026-demos --skill sql-backup-restore-to-azure-sql-vm-migration",{"tool":58,"command":59},"pnpm","pnpm dlx skills add microsoft\u002Fsqlcon-eu-2026-demos --skill sql-backup-restore-to-azure-sql-vm-migration","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fsql-backup-restore-to-azure-sql-vm-migration\u002FSKILL.md",true,[63,69,73,77],{"path":64,"resourceType":65,"resourceTypeDesc":66,"sizeBytes":67,"sourceHtmlUrl":68},"references\u002Fattribution.md","REFERENCE","参考文档",1950,"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fcloud\u002Fgoogle-cloud-waf-cost-optimization\u002Freferences\u002Fattribution.md",{"path":70,"resourceType":65,"resourceTypeDesc":66,"sizeBytes":71,"sourceHtmlUrl":72},"references\u002Fcommand-execution-backup-restore.md",24746,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fsql-backup-restore-to-azure-sql-vm-migration\u002Freferences\u002Fcommand-execution-backup-restore.md",{"path":74,"resourceType":65,"resourceTypeDesc":66,"sizeBytes":75,"sourceHtmlUrl":76},"references\u002Fcommand-execution-discovery.md",31698,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fsql-backup-restore-to-azure-sql-vm-migration\u002Freferences\u002Fcommand-execution-discovery.md",{"path":78,"resourceType":65,"resourceTypeDesc":66,"sizeBytes":79,"sourceHtmlUrl":80},"skill-contract.yml",4041,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fsql-backup-restore-to-azure-sql-vm-migration\u002Fskill-contract.yml",[82,91,103,113,124,133],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":89,"publishedAt":35},"01M69AGTKN8F66BXE45KQ3MDMX","keynote-demo-app","Build or extend a SQLCon EU 2026 keynote demo application so it looks and behaves like the other keynote apps. Use when creating a new demo view (invoices, operations, orders), restyling an existing app to match, adding a deliberate database anti-pattern for a troubleshooting demo, or wiring an app to Azure SQL or Fabric SQL with managed identity. Triggers include \"make this look like the keynote app\", \"build a demo view\", \"add the slow query demo\", \"match Caldova styling\".","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fshared\u002FSKILL.md",[88],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[90,33,29,30],"keynote demo app",{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":99,"publishedAt":35},"01M69AGRAPA61AN2A2N2RF6NCJ","validate-post-migration-data","Validate data and schema after migrating SQL Server to Azure SQL Database, Azure SQL Managed Instance, or SQL Server on Azure VM. Use after migration, restore, BACPAC import, LRS completion, cutover validation, row-count comparison, or source-target reconciliation.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fvalidate-post-migration-data\u002FSKILL.md",[97,98],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},[100,101,34,30,102,29],"validate","validate post migration data","azure sql database",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":111,"publishedAt":35},"01M69AGNG0HQK50EW1CNEFTR1N","sql-server-to-sql-mi-lrs-migration","Migrate SQL Server databases to Azure SQL Managed Instance with Log Replay Service (LRS) using managed identity for Blob access. Use for SQL Server to SQL MI, LRS, log replay, continuous restore, or low-downtime backup-chain migrations.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fsql-server-to-sql-mi-lrs-migration\u002FSKILL.md",[109,110],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},[112,34,30,29,33],"sql server to sql mi lrs migration",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":121,"publishedAt":35},"01M69AGJC50G0YX7VQ52SQ0AD0","sql-bacpac-to-azure-sql-db-migration","Migrate one or all user databases from SQL Server to Azure SQL Database with an offline BACPAC workflow. Use for BACPAC, SqlPackage export\u002Fimport, bulk database migration, or offline Azure SQL Database migration requests.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Fsql-bacpac-to-azure-sql-db-migration\u002FSKILL.md",[119,120],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},[122,30,29,34,102,123],"sql bacpac to azure sql db migration","workflow",{"skillNo":125,"name":126,"nameZh":6,"description":127,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":128,"categories":129,"keywords":131,"publishedAt":35},"01M69AGDP6XXM1YW7X1VV1QKE5","run-migration-assessment","Route generic or unresolved SQL Server assessment, readiness, compatibility, cost, and SKU recommendation requests. Use for bare server names or whenever Azure versus local\u002Fon-premises is not explicit; ask which source applies, then delegate.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Frun-migration-assessment\u002FSKILL.md",[130],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[132,34,30],"run migration assessment",{"skillNo":134,"name":135,"nameZh":6,"description":136,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":137,"categories":138,"keywords":139,"publishedAt":35},"01M69AGBJN9ESKFXD8YXB7J20W","recommend-sku-sizing","Collect performance data and calculate Azure SQL SKU recommendations only after the source is explicitly confirmed local\u002Fon-premises. Never use for a generic SKU request or bare server name; route unresolved requests through run-migration-assessment.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fsqlcon-eu-2026-demos\u002Fblob\u002Fmain\u002Fcorenote\u002Fmigration\u002Fskills\u002Frecommend-sku-sizing\u002FSKILL.md",[],[140,141,30,29],"recommend sku sizing","performance"]