{"id":2598,"date":"2026-06-15T09:03:00","date_gmt":"2026-06-15T09:03:00","guid":{"rendered":"https:\/\/www.mainmind.com\/blog\/?p=2598"},"modified":"2026-06-08T08:27:58","modified_gmt":"2026-06-08T08:27:58","slug":"delete-backup-vault-powershell","status":"publish","type":"post","link":"https:\/\/www.mainmind.com\/blog\/delete-backup-vault-powershell\/","title":{"rendered":"Delete-BackupVault.ps1: el script que ojal\u00e1 hubiera tenido antes"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Si alguna vez has intentado eliminar un Recovery Services Vault en Azure a mano, sabes exactamente de qu\u00e9 va este post. Entras al portal con toda la confianza del mundo, le das a \u00abEliminar vault\u00bb\u2026 y Azure te dice que no. Que hay elementos de backup activos. Vale, los eliminas. Que hay servidores MAB registrados. Los das de baja. Que el Soft Delete sigue activo. Lo desactivas. Que hay elementos en estado \u00abpendiente de borrado\u00bb. Los restauras para poder borrarlos. Que\u2026<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En alg\u00fan punto de ese proceso \u2014habitualmente el cuarto o quinto intento\u2014 uno piensa que tiene que haber una forma mejor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Este script es esa forma mejor.<\/p>\n\n\n\n<!--more-->\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Qu\u00e9 hace (en dos frases)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Delete-BackupVault.ps1<\/strong> es un script de PowerShell que elimina completamente un Recovery Services Vault de Azure, incluyendo todos sus datos de backup, contenedores registrados, agentes MARS\/MABS\/DPM y configuraci\u00f3n de ASR. Lo hace de forma interactiva: te pide el tenant, la suscripci\u00f3n y el vault \u2014sin hardcodear nada\u2014 y al final te pide confirmaci\u00f3n antes de hacer cualquier cosa destructiva.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Antes de empezar: requisitos<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Solo necesitas dos cosas instaladas en tu m\u00e1quina:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>PowerShell 7 o superior<\/strong> \u2014 si tienes la versi\u00f3n incluida con Windows (la 5.1), actualiza antes de seguir. Descarga en <a href=\"https:\/\/aka.ms\/powershell\">aka.ms\/powershell<\/a>.<\/li>\n\n\n\n<li><strong>M\u00f3dulos Az de Azure<\/strong> \u2014 el script los instala y actualiza autom\u00e1ticamente si detecta que no est\u00e1n o est\u00e1n desactualizados. Nada que hacer aqu\u00ed.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">En cuanto a permisos, la cuenta con la que te autentiques necesita tener el rol <strong>Contributor<\/strong> o <strong>Backup Contributor<\/strong> sobre el vault (o la suscripci\u00f3n). Sin ese rol, el script lo detecta y te explica exactamente d\u00f3nde asignarlo, pero no podr\u00e1 continuar.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">C\u00f3mo usarlo<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. Descarga el script<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Gu\u00e1rdalo en una carpeta local de tu equipo. Importante: <strong>no lo ejecutes desde una unidad de red<\/strong> (ruta UNC tipo <code>\\\\servidor\\carpeta\\<\/code>), ya que PowerShell aplica restricciones adicionales en ese contexto.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Abre PowerShell 7<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Puedes encontrarlo en el men\u00fa de inicio como \u00abPowerShell 7\u00bb o ejecutar <code>pwsh<\/code> desde cualquier terminal. Navega a la carpeta donde guardaste el script:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\ncd C:\\Scripts\n\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">3. Ejecuta el script<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n.\\Delete_BackupVault.ps1\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Lo primero que ver\u00e1s es el aviso de ATENCI\u00d3N en rojo. No est\u00e1 de adorno: este script hace cosas irreversibles, as\u00ed que vale la pena recordarlo en cada ejecuci\u00f3n.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"376\" src=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_01-1024x376.jpg\" alt=\"azure_ps_delete_backups_01 sobre azure_ps_delete_vault\" class=\"wp-image-2602\" srcset=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_01-1024x376.jpg 1024w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_01-300x110.jpg 300w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_01-768x282.jpg 768w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_01.jpg 1304w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\">4. Primer login: autenticaci\u00f3n gen\u00e9rica<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">El script te pedir\u00e1 que abras <code>https:\/\/login.microsoft.com\/device<\/code> en un navegador e introduzcas el c\u00f3digo que aparece en consola. Este primer login es sin tenant espec\u00edfico \u2014su \u00fanico prop\u00f3sito es poder listar los tenants a los que tienes acceso.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n&#x5B;Login to Azure] To sign in, use a web browser to open the page\nhttps:\/\/login.microsoft.com\/device and enter the code ABCD1234\n\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">5. Selecciona el tenant<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Una vez autenticado, el script muestra todos los tenants disponibles con su nombre, dominio e ID:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nTenants disponibles:\n  &#x5B;1] Empresa Ejemplo  |  empresa.com  |  ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n  &#x5B;2] Otro Tenant      |  otro.com     |  ID: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Introduce el n\u00famero correspondiente.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"401\" src=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_02-1024x401.jpg\" alt=\"azure_ps_delete_backups_02 sobre azure_ps_delete_vault\" class=\"wp-image-2605\" srcset=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_02-1024x401.jpg 1024w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_02-300x118.jpg 300w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_02-768x301.jpg 768w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_02.jpg 1314w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\">6. Segundo login: autenticaci\u00f3n en el tenant elegido<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Si el tenant tiene MFA o pol\u00edticas de Acceso Condicional, Azure requerir\u00e1 un segundo login espec\u00edfico para ese tenant. Es el comportamiento esperado y correcto. Repite el proceso del c\u00f3digo en el navegador.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7. Selecciona la suscripci\u00f3n<\/h3>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nSuscripciones disponibles:\n  &#x5B;1] Mi Suscripcion Azure  |  ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">8. Selecciona el vault<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">El script lista todos los Recovery Services Vaults de esa suscripci\u00f3n:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nVaults disponibles:\n  &#x5B;1] BackupGeneral  |  Resource Group: rg-produccion  |  Region: westeurope\n  &#x5B;2] BackupTest     |  Resource Group: rg-desarrollo   |  Region: northeurope\n\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">9. Confirma antes de proceder<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">El script muestra un resumen completo de lo que va a borrar y espera que escribas <code>SI<\/code> (en may\u00fasculas) para continuar. Cualquier otra cosa cancela la operaci\u00f3n sin tocar nada.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n==================================================\n  ATENCION: OPERACION DESTRUCTIVA E IRREVERSIBLE\n==================================================\n  Tenant      : Empresa Ejemplo (empresa.com)\n  Tenant ID   : xxxxxxxx-...\n  Suscripcion : Mi Suscripcion Azure\n  Sub ID      : xxxxxxxx-...\n  Vault       : BackupGeneral\n  Grupo       : rg-produccion\n==================================================\n\nEscribe &#039;SI&#039; para confirmar y continuar, cualquier otra cosa cancela:\n\n<\/pre><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"899\" height=\"741\" src=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_04.jpg\" alt=\"azure_ps_delete_backups_04 sobre azure_ps_delete_vault\" class=\"wp-image-2603\" srcset=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_04.jpg 899w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_04-300x247.jpg 300w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_04-768x633.jpg 768w\" sizes=\"auto, (max-width: 899px) 100vw, 899px\" \/><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\">10. El script trabaja solo<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A partir de aqu\u00ed el proceso es autom\u00e1tico. El script va informando de cada paso: desactiva Soft Delete y Enhanced Security, elimina los items de backup por tipo (VM, SQL, SAP HANA, Azure Files), da de baja los contenedores MARS\/MAB\/DPM, limpia configuraci\u00f3n ASR y Private Endpoints, y por \u00faltimo borra el vault v\u00eda REST API.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Si al finalizar la limpieza detecta elementos que no pudo eliminar (por ejemplo, por permisos insuficientes), te avisa antes de intentar el borrado del vault y te pregunta si quieres continuar de todas formas o cancelar.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Lo que me cost\u00f3 m\u00e1s trabajo (y por qu\u00e9 el script es as\u00ed)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Este script no sali\u00f3 a la primera. Hubo varios problemas que llevaron m\u00e1s tiempo del esperado.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El primero fue la autenticaci\u00f3n en entornos multi-tenant. Si tienes varias cuentas de Azure cacheadas, el m\u00f3dulo Az intentaba usar credenciales del token cache de WAM y fallaba con errores de <code>SharedTokenCacheCredential<\/code>. La soluci\u00f3n fue desactivar WAM completamente (<code>Update-AzConfig -EnableLoginByWam $false<\/code>), usar <code>-Scope Process<\/code> para que todo quede en memoria sin afectar otras sesiones, y forzar la autenticaci\u00f3n por c\u00f3digo de dispositivo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El segundo fue el problema del \u00abMAB server BadRequest\u00bb. Cuando un vault tiene un agente MARS con elementos en estado soft-deleted, Azure rechaza cualquier intento de dar de baja el servidor hasta que restauras esos elementos, los eliminas definitivamente y <em>despu\u00e9s<\/em> desactivas Enhanced Security. El orden importa, y la documentaci\u00f3n oficial no lo deja muy claro.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">El tercero, m\u00e1s reciente: <code>Get-AzRecoveryServicesVault<\/code> devolv\u00eda vac\u00edo en algunos entornos aunque el vault exist\u00eda y los permisos eran correctos. Resulta que el m\u00f3dulo Az.RecoveryServices a veces no respeta el contexto de <code>-Scope Process<\/code> cuando hay m\u00faltiples contextos cargados. La soluci\u00f3n fue usar <code>-DefaultProfile $context<\/code> expl\u00edcitamente y a\u00f1adir un fallback que consulta la REST API de ARM directamente para listar vaults sin depender del m\u00f3dulo.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Errores con buena pinta<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">En lugar de escupir el JSON crudo del error de Azure (que es lo habitual), el script detecta el tipo de error y lo formatea:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para errores de permisos (<code>AuthorizationFailed<\/code>), en lugar de esto:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n{&quot;error&quot;:{&quot;code&quot;:&quot;AuthorizationFailed&quot;,&quot;message&quot;:&quot;The client &#039;kds@tenant.com&#039; with object id &#039;...&#039; does not have authorization...&quot;}}\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Muestra esto:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n  +--------------------------------------------------------------------------+\n  | PERMISOS INSUFICIENTES                                                   |\n  |--------------------------------------------------------------------------|\n  | Cuenta  : kds@tenant.com                                                 |\n  | Accion  : Microsoft.RecoveryServices\/vaults\/read                         |\n  | Recurso : \/subscriptions\/957f03b7-...                                    |\n  |--------------------------------------------------------------------------|\n  | SOLUCION:                                                                |\n  | Azure Portal &gt; Recurso &gt; Control de acceso (IAM)                        |\n  | &gt; Agregar asignacion de rol                                              |\n  | &gt; Rol: Contributor o Backup Contributor                                  |\n  | &gt; Cuenta: kds@tenant.com                                                 |\n  +--------------------------------------------------------------------------+\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Son peque\u00f1as cosas, pero cuando est\u00e1s a las 11 de la noche intentando liberar recursos de un cliente, se agradece.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"889\" height=\"564\" src=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_03.jpg\" alt=\"azure_ps_delete_backups_03 sobre azure_ps_delete_vault\" class=\"wp-image-2604\" srcset=\"https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_03.jpg 889w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_03-300x190.jpg 300w, https:\/\/www.mainmind.com\/blog\/wp-content\/uploads\/2026\/azure_ps_delete_vault\/azure_ps_delete_backups_03-768x487.jpg 768w\" sizes=\"auto, (max-width: 889px) 100vw, 889px\" \/><\/figure>\n<\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Descarga<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El script est\u00e1 disponible para descarga directa. Solo necesitas guardarlo y ejecutarlo con PowerShell 7 tal como se describe arriba.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Recuerda:<\/strong> este script elimina datos de forma permanente. \u00dasalo solo cuando est\u00e9s completamente seguro de que el vault y todos sus backups son prescindibles. No hay vuelta atr\u00e1s.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">\u00bfPreguntas o mejoras?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Si lo pruebas y encuentras alg\u00fan caso que no est\u00e9 cubierto, o tienes un entorno con alguna configuraci\u00f3n especial (DPM, CMK, Private Link, etc.), escr\u00edbeme. El script ha pasado por bastantes iteraciones reales y cada error nuevo encontrado ha acabado en una mejora.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/mainmind83\/PowerShell\/blob\/main\/Azure\/Delete_backups\" data-type=\"link\" data-id=\"https:\/\/github.com\/mainmind83\/PowerShell\/blob\/main\/Azure\/Delete_backups\">Descargar script en powershell de Github<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Script PowerShell interactivo para eliminar Recovery Services Vaults de Azure gestionando MARS, MAB, soft delete y Enhanced Security de forma autom\u00e1tica<\/p>\n","protected":false},"author":1,"featured_media":2600,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[1074,155,720,1073,1072,123,1071],"class_list":["post-2598","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud","tag-automatizacion-azure","tag-azure","tag-azure-backup","tag-eliminar-vault-azure","tag-mars-agent","tag-powershell","tag-recovery-services"],"_links":{"self":[{"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/posts\/2598","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/comments?post=2598"}],"version-history":[{"count":1,"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/posts\/2598\/revisions"}],"predecessor-version":[{"id":2606,"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/posts\/2598\/revisions\/2606"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/media\/2600"}],"wp:attachment":[{"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/media?parent=2598"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/categories?post=2598"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mainmind.com\/blog\/wp-json\/wp\/v2\/tags?post=2598"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}