¿Usas VHD Set (.vhds) como discos compartidos en clústeres invitados de Hyper‑V y tus CSV aparecen como “Cluster Disk 1/2/3”? Aquí tienes una guía práctica para entender por qué ocurre, cómo renombrarlos de forma fiable y cómo mantener una trazabilidad clara CSV ↔ volumen ↔ archivo .vhds en Windows Server 2022 con PowerShell.
Resumen de la pregunta
En clústeres invitados (VMs que ejecutan Windows Failover Cluster sobre Hyper‑V) es habitual utilizar VHD Set (.vhds
) como discos compartidos y convertirlos a Cluster Shared Volumes (CSV). El problema: cuando se agregan al clúster, PowerShell asigna nombres genéricos como “Cluster Disk 1/2/3” y no hay un cmdlet que proporcione, de forma simple, un mapeo de cada CSV al archivo .vhds subyacente para renombrar con algo significativo (por ejemplo, “Data1”). Además, si cambias manualmente los nombres de carpetas en C:\ClusterStorage
o renombras CSV a mano, puedes perder la relación punto de montaje ↔ CSV ↔ .vhds. La GUI de Failover Cluster Manager deja entrever datos útiles, pero no se exponen de forma directa en PowerShell.
Qué está pasando y por qué no es trivial
- PowerShell no expone un vínculo directo CSV → archivo .vhds para VHD Set. Cmdlets como
Get‑VMHardDiskDrive
pueden mostrar discos compartidos, pero no siempre de forma consistente en todos los entornos/Versiones de Hyper‑V. - La GUI sí “parece saberlo” porque combina información del clúster, del volumen y del registro del invitado. Sin embargo, automatizar esa correlación no es evidente.
- Renombrar CSV es en línea y seguro en general, pero cambia la ruta de la carpeta bajo
C:\ClusterStorage<NombreCSV>\
y cualquier script/servicio que use rutas absolutas puede romperse.
Objetivo
Disponer de una estrategia repetible y automatizable para:
- Asignar a cada CSV un nombre significativo y estable.
- Mantener la trazabilidad con el volumen y, cuando se necesite, con el archivo
.vhds
en el host de Hyper‑V. - Evitar dependencias de APIs no documentadas o inconsistentes.
Estrategia recomendada: propagar el nombre desde la etiqueta del volumen
La forma más robusta y portable es usar la etiqueta del sistema de archivos (NTFS/ReFS) como fuente de verdad. Tú decides el nombre cuando das formato al volumen dentro del invitado, y luego lo usas para renombrar el CSV.
Flujo de trabajo
- En el invitado, al crear/formatear el volumen que se convertirá en CSV, asigna una etiqueta significativa (p. ej., “Data1”).
- Usa PowerShell para leer esa etiqueta y renombrar el CSV con
Rename‑ClusterSharedVolume
.
One‑liner mínimo
# Ejecutar en un nodo del clúster invitado (Windows Server 2022+)
Get-ClusterSharedVolume | ForEach-Object {
$mp = $_.SharedVolumeInfo.FriendlyVolumeName # C:\ClusterStorage<NombreActual>\
$label = (Get-Volume -Path $mp).FileSystemLabel # p. ej., "Data1"
if ($label -and $_.Name -ne $label) {
Rename-ClusterSharedVolume -InputObject $_ -NewName $label
}
}
Ventajas: no necesitas descubrir el archivo .vhds
en el host; el nombre “nace” desde un metadato estable (la etiqueta del volumen) y queda alineado con la carpeta C:\ClusterStorage\
.
Versión endurecida para producción
El siguiente script añade controles: sanitiza el nombre (caracteres inválidos), maneja duplicados, registra cambios y ofrece WhatIf.
function Set-CsvNameFromLabel {
[CmdletBinding(SupportsShouldProcess)]
param(
[int]$MaxLength = 60,
[switch]$AppendUniqueSuffix, # Si hay colisión, añade -2, -3, ...
[switch]$SkipEmptyLabels, # Omite volúmenes sin etiqueta
[switch]$VerboseLog
)```
$existing = @{}
Get-ClusterSharedVolume | ForEach-Object { $existing[$_.Name] = $true }
$changed = @()
Get-ClusterSharedVolume | ForEach-Object {
$csv = $_
$mountPath = $csv.SharedVolumeInfo.FriendlyVolumeName
try {
$label = (Get-Volume -Path $mountPath -ErrorAction Stop).FileSystemLabel
} catch {
if ($VerboseLog) { Write-Warning "No se pudo leer la etiqueta de $mountPath ($($_.Exception.Message))." }
return
}
if ([string]::IsNullOrWhiteSpace($label)) {
if ($SkipEmptyLabels) {
if ($VerboseLog) { Write-Verbose "CSV '$($csv.Name)' sin etiqueta: omitido." }
return
}
else { $label = $csv.Name }
}
# Sanitizar para usar como nombre de carpeta CSV
$safe = $label.Trim()
$safe = $safe -replace '[\\/:*?""<>|]', '-' # caracteres inválidos
$safe = $safe.TrimEnd('.', ' ') # evitar finales problemáticos
if ($safe.Length -gt $MaxLength) { $safe = $safe.Substring(0, $MaxLength) }
# Resolver colisiones de nombres
$target = $safe
$i = 2
while ($existing.ContainsKey($target) -and $target -ne $csv.Name) {
if (-not $AppendUniqueSuffix) {
if ($VerboseLog) { Write-Warning "Colisión: ya existe un CSV llamado '$target'. Use -AppendUniqueSuffix para forzar." }
return
}
$suffix = "-$i"
$maxBase = [Math]::Max(1, $MaxLength - $suffix.Length)
$base = $safe.Substring(0, [Math]::Min($safe.Length, $maxBase))
$target = "$base$suffix"
$i++
}
if ($target -ne $csv.Name) {
if ($PSCmdlet.ShouldProcess("CSV '$($csv.Name)'", "Renombrar a '$target'")) {
Rename-ClusterSharedVolume -InputObject $csv -NewName $target
$existing.Remove($csv.Name) | Out-Null
$existing[$target] = $true
$changed += [pscustomobject]@{
OldName = $csv.Name
NewName = $target
MountPoint = $mountPath
Time = (Get-Date)
}
}
} elseif ($VerboseLog) {
Write-Verbose "CSV '$($csv.Name)' ya coincide con la etiqueta."
}
}
return $changed
```
}
Ejemplo de uso:
Set-CsvNameFromLabel -AppendUniqueSuffix -VerboseLog -WhatIf
Verificación rápida
Get-ClusterSharedVolume | Select-Object Name, @{n='MountPoint';e={$_.SharedVolumeInfo.FriendlyVolumeName}}, OwnerNode
Comprueba que cada Name
coincide con lo que esperabas y que la ruta en C:\ClusterStorage\
refleja el cambio.
Guardar la relación en el momento de creación
Si ya gestionas la creación de .vhds
desde el host Hyper‑V, crea tu fuente de verdad (JSON/CSV/Registro) con:
- Ruta del archivo
.vhds
en el host/Cluster de Hyper‑V. - VMs a las que se adjunta y su posición SCSI (ControllerNumber/ControllerLocation).
- Nombre deseado del CSV (p. ej., derivado del nombre del archivo).
Más tarde, cuando el invitado convierta el disco a CSV, un script leerá ese registro para aplicar el nombre.
Ejemplo para generar el registro en el host
# Ejecutar en hosts de Hyper-V (o desde un nodo del clúster de virtualización)
$map = Get-VM | ForEach-Object {
$vm = $_
Get-VMHardDiskDrive -VMName $vm.Name |
Where-Object { $.SupportPersistentReservations -or $.ShareVirtualDisk } |
Select-Object @{
n='VM';e={$vm.Name}
}, ControllerType, ControllerNumber, ControllerLocation, Path
}
\$map | ConvertTo-Json -Depth 5 | Out-File "C:\vhds-map.json" -Encoding UTF8
Consumir el registro en el invitado
Imagina que guardaste además el nombre deseado para el CSV. El playbook sería:
- Leer
C:\vhds-map.json
(copiado/entregado de forma segura al invitado). - Para cada entrada, localizar el volumen por posición SCSI o tamaño y establecer la etiqueta de volumen.
- Ejecutar
Set-CsvNameFromLabel
para renombrar.
Derivar la relación por GUID de disco/volumen (post‑producción)
Si el entorno ya está en marcha sin metadatos, puedes reconstruir la relación.
En el invitado: descubrir GUIDs desde el recurso de clúster
# Para un CSV concreto
Get-ClusterResource -Name "Cluster Disk 1" | Get-ClusterParameter |
Where-Object { $_.Name -in 'DiskIdGuid','VolumeName' }
Para todos los CSV
Get-ClusterResource | Where-Object ResourceType -eq 'Physical Disk' |
ForEach-Object { $\_ | Get-ClusterParameter |
Where-Object { $\_.Name -in 'DiskIdGuid','VolumeName' } }
Con DiskIdGuid
/VolumeName
podrás localizar el disco/volumen:
$guid = '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'
$disk = Get-Disk | Where-Object { $_.UniqueId -match $guid }
$parts = Get-Partition -DiskNumber $disk.Number
$vol = $parts | Get-Volume
$vol | Select-Object DriveLetter, FileSystem, FileSystemLabel, UniqueId
En el host: enumerar discos compartidos adjuntos a las VMs
Get-VM | ForEach-Object {
$vm = $_
Get-VMHardDiskDrive -VMName $vm.Name |
Where-Object { $.SupportPersistentReservations -or $.ShareVirtualDisk } |
Select-Object @{n='VM';e={$vm.Name}},
ControllerNumber, ControllerLocation, Path
} | Sort-Object VM, ControllerNumber, ControllerLocation
Luego, une la información por posición SCSI, tamaño y orden de creación. No es perfecto, pero funciona en la mayoría de casos. Una vez deducido el nombre “correcto”, aplica la estrategia de etiquetas y renombrado.
Buenas prácticas operativas al renombrar CSV
- Impacto en rutas: renombrar cambia
C:\ClusterStorage<Nombre>\
. Revisa scripts, tareas, servicios y aplicaciones que dependan de rutas absolutas. - Auditoría: registra quién, qué y cuándo renombra (por ejemplo, volcando un JSON con el antes/después).
- Idempotencia: diseña tus scripts para que, si los vuelves a ejecutar, no rompan nada (no renombrar si ya coincide la etiqueta).
- Etiquetas como fuente de verdad: si cambias un nombre, cambia primero la FileSystemLabel y luego sincroniza el CSV.
Playbook rápido reutilizable
- Etiquetar el volumen:
Set-Volume -Path C:\ClusterStorage\ClusterDisk1\ -NewFileSystemLabel "Data1"
- Renombrar CSV desde la etiqueta:
Set-CsvNameFromLabel -AppendUniqueSuffix
- Verificar:
Get-ClusterSharedVolume
y confirmar rutas y consistencia en todos los nodos. - Registrar: guarda el resultado devuelto por la función para auditoría.
Tabla comparativa de estrategias
Estrategia | Automatizable | Esfuerzo inicial | Robustez | Cuándo usar |
---|---|---|---|---|
Propagar desde etiqueta del volumen | Alta | Bajo | Alta | La opción por defecto para la mayoría |
Registro al crear .vhds (fuente de verdad) | Alta | Medio | Muy alta | Entornos gobernados / con CMDB |
Reconstrucción por GUID/posición SCSI | Media | Medio‑alto | Media | Instalaciones existentes sin metadatos |
Marcadores de nombre dentro del volumen
Si no quieres depender de etiquetas (o quieres validación extra), crea un “marcador” en la raíz del CSV, por ejemplo un archivo oculto .csv-name
con el nombre deseado. El flujo:
- Leer el marcador.
- Aplicar esa cadena como etiqueta del volumen (
Set-Volume
). - Ejecutar el renombrado del CSV.
Get-ClusterSharedVolume | ForEach-Object {
$mp = $_.SharedVolumeInfo.FriendlyVolumeName
$marker = Join-Path $mp '.csv-name'
if (Test-Path $marker) {
$desired = (Get-Content $marker -ErrorAction SilentlyContinue | Select-Object -First 1).Trim()
if ($desired) {
Set-Volume -Path $mp -NewFileSystemLabel $desired
}
}
}
Set-CsvNameFromLabel -AppendUniqueSuffix
Operación segura y reversibilidad
- Volver atrás: mantén un backup del listado “antes/después”. Renombrar a su estado anterior es inmediato si conservas ese registro.
- Permisos: ejecuta en un Cluster‑Aware PowerShell con privilegios de Administrador de clúster.
- Ventanas de cambio: aunque renombrar es en línea, hazlo en una ventana controlada y valida que ningún job use rutas antiguas.
Preguntas frecuentes
¿Puedo renombrar CSV desde cualquier nodo? Sí, pero asegúrate de que el clúster está saludable. El cambio se replica.
¿Cambiar la etiqueta del volumen interrumpe E/S? No, es una operación de metadatos. Aun así, aplica prácticas de cambio seguras.
¿Por qué no usar solo la GUI? La GUI sirve para inspección puntual. Para coherencia, auditable y CI/CD, apuesta por scripts idempotentes.
Errores frecuentes y cómo evitarlos
Error | Consecuencia | Prevención |
---|---|---|
Renombrar manualmente carpetas en C:\ClusterStorage | Desalineación nombre ↔ CSV, confusión y scripts rotos | Usa Rename-ClusterSharedVolume ; nunca toques la carpeta a mano |
Asumir que Get-VMHardDiskDrive siempre lista todos los .vhds | Trazabilidad incompleta | Combina con etiquetas, GUIDs y/o registro propio |
Permitir etiquetas vacías o duplicadas | CSV sin nombre significativo o colisiones | Sanitiza y fuerza sufijo único con scripts |
No registrar cambios | Dificultad para auditar o revertir | Guardar JSON con antes/después cada vez |
Alternativa tecnológica: Storage Spaces Direct en clúster invitado
Si el mapeo CSV ↔ .vhds
se convierte en un lastre operativo, valora Storage Spaces Direct (S2D) dentro del clúster invitado. Ya no hay archivos compartidos por VM y el almacenamiento se gestiona internamente por el propio S2D.
Ventajas | Inconvenientes |
---|---|
Simplifica la capa de almacenamiento; elimina la necesidad de mapear a .vhds ; resiliencia y escalabilidad integradas. | Mayor complejidad de diseño; más discos por VM/nodo; curva de aprendizaje y supervisión específicas. |
Conclusión y receta TL;DR
- No hay un cmdlet que diga “Cluster Disk X → …\data1.vhds”.
- La vía práctica y robusta es usar la etiqueta del volumen como fuente de verdad y sincronizar el nombre del CSV con
Rename‑ClusterSharedVolume
. - Si necesitas trazabilidad completa host↔invitado, crea un registro al aprovisionar los VHD Set (VM, posición SCSI, ruta
.vhds
, nombre CSV). - En instalaciones existentes, reconstruye por GUID/posición y estandariza con etiquetas.
- Si el modelo VHD Set es una carga operacional, evalúa S2D en los clústeres invitados.
Apéndice: utilidades adicionales
Listar CSV con su etiqueta y tamaño
Get-ClusterSharedVolume | ForEach-Object {
$mp = $_.SharedVolumeInfo.FriendlyVolumeName
$v = Get-Volume -Path $mp
[pscustomobject]@{
CsvName = $_.Name
Label = $v.FileSystemLabel
FileSystem= $v.FileSystem
SizeGB = [math]::Round(($v.Size/1GB),2)
FreeGB = [math]::Round(($v.SizeRemaining/1GB),2)
Mount = $mp
OwnerNode = $_.OwnerNode
}
} | Sort-Object CsvName | Format-Table -AutoSize
Renombrar etiqueta del volumen de forma segura
# Cambia solo la etiqueta (no el CSV); útil para preparar el renombrado
$mp = (Get-ClusterSharedVolume -Name 'Cluster Disk 1').SharedVolumeInfo.FriendlyVolumeName
Set-Volume -Path $mp -NewFileSystemLabel 'Data1'
Auditoría: exportar antes/después
$before = Get-ClusterSharedVolume | Select-Object Name, @{n='Mount';e={$_.SharedVolumeInfo.FriendlyVolumeName}}
$changes = Set-CsvNameFromLabel -AppendUniqueSuffix
$after = Get-ClusterSharedVolume | Select-Object Name, @{n='Mount';e={$_.SharedVolumeInfo.FriendlyVolumeName}}
\[pscustomobject]@{
Time = Get-Date
Before = \$before
Changes = \$changes
After = \$after
} | ConvertTo-Json -Depth 6 | Out-File "C:\logs\csv-rename-\$(Get-Date -f yyyyMMdd-HHmmss).json"
Tips de resolución de problemas
- Si
Get-Volume -Path
falla, comprueba que el CSV esté en línea y que la ruta termine con\
. - Si la etiqueta no aparece, monta temporalmente el volumen con una letra y revisa permisos del servicio de clúster.
- Si un CSV no puede renombrarse por colisión, usa
-AppendUniqueSuffix
o cambia ligeramente la etiqueta.
Con esta guía y scripts, puedes convertir un “Cluster Disk 3” anónimo en un “Data1” significativo, mantener alineada la carpeta de C:\ClusterStorage
, y conservar la trazabilidad necesaria para operar y auditar tu clúster invitado en Windows Server 2022.