Room Finder: cómo corregir la ciudad duplicada en Outlook (Exchange Online) normalizando el atributo City con Get‑Place/Set‑Place

Si en el Room Finder de Outlook (Exchange Online) ves una ciudad duplicada en All Cities —una con salas y otra vacía—, la causa casi siempre es un valor incoherente en el atributo City de alguna sala. A continuación te explico cómo detectarlo, corregirlo y evitar que vuelva a ocurrir.

Índice

Contexto y síntoma

En la experiencia de reserva de salas (Room Finder / Buscar salas) el servicio agrupa automáticamente las salas por su atributo de lugar (City). Cuando dos salas comparten una ciudad escrita de forma distinta —por ejemplo, con un espacio inicial (" Roundlake") o doble espacio, mayúsculas inconstantes o caracteres “invisibles”— el servicio interpreta que se trata de ciudades diferentes. El resultado es una ciudad “duplicada” bajo All Cities, donde una entrada suele aparecer vacía (sin salas) o con un subconjunto de salas que no debería estar separado.

Causa principal: valores inconsistentes de City

El caso más frecuente es un espacio en blanco al inicio o al final del nombre de la ciudad. Por ejemplo:

  • " Roundlake" (nota el espacio inicial)
  • "Roundlake " (espacio final)
  • "Roundlake" (valor correcto)

Room Finder trata cada variante como una ciudad distinta, por lo que verás “Roundlake” dos veces (o más). Este problema también puede aparecer por:

  • Mayúsculas/minúsculas inconsistentes (roundlake vs. Roundlake).
  • Espacios dobles o caracteres separadores no convencionales (p. ej., no‑breaking space U+00A0).
  • Salas con City vacío o nulo (se agrupan de forma distinta o pueden quedar “sucias” en los filtros).

Diagnóstico rápido con PowerShell (EXO V3)

Conéctate a Exchange Online PowerShell y ejecuta estas comprobaciones. Necesitas permisos para leer y actualizar lugares (Places).

# Conexión (si aún no lo has hecho)
Connect-ExchangeOnline

1) Listar salas con su ciudad actual
Get-ExoMailbox -RecipientTypeDetails RoomMailbox |
  Sort-Object DisplayName |
  Get-Place |
  Format-Table DisplayName, Building, Floor, City

Busca espacios iniciales/finales u otras incoherencias:

# 2) Detectar espacios al inicio o al final
Get-ExoMailbox -RecipientTypeDetails RoomMailbox |
  Get-Place |
  Where-Object { $_.City -match '^\s+|\s+$' } |
  Format-Table DisplayName, City

Para visualizar “duplicados lógicos” (ciudades que solo difieren por espacios), agrupa por el valor normalizado con Trim():

$places = Get-ExoMailbox -RecipientTypeDetails RoomMailbox | Get-Place
$places | Group-Object { $_.City.Trim() } |
  Select-Object Name, Count,
    @{n='Salas';e={$_.Group.DisplayName -join ', '}} |
  Format-Table -AutoSize

Tabla de referencia: síntoma → causa → cómo comprobar

SíntomaCausa probableComprobación
Ciudad duplicada bajo All CitiesEspacio inicial/final o doble espacio en CityWhere-Object { $_.City -match '^\s+|\s+$' }
Dos ciudades con grafías casi igualesMayúsculas/minúsculas inconsistentesComparar $.City vs. $.City.ToLower()
Ciudad “vacía” sin salasSalas antiguas con City vacío o valor ocultoFiltrar [string]::IsNullOrWhiteSpace($_.City)
Ciudad separada pese a “mismos” caracteresSeparadores Unicode (p. ej., NBSP)Normalizar con regex \p{Zs} y Trim()

Solución recomendada: normalizar City

Corrección mínima (para una ciudad concreta)

Si sabes cuál debe ser el valor definitivo (por ejemplo, Roundlake), corrige solo las entradas que difieran por espacios:

# Normalizar a "Roundlake"
$target = "Roundlake"
Get-ExoMailbox -RecipientTypeDetails RoomMailbox |
  Get-Place |
  Where-Object { $.City -ne $target -and $.City.Trim() -eq $target } |
  ForEach-Object {
    Set-Place -Identity $_.Identity -City $target
  }

Notas prácticas:

  • -Identity de Set-Place acepta el buzón de la sala (alias/SMTP). Si lo necesitas, usa PrimarySmtpAddress.
  • Si también hay variaciones de mayúsculas (roundlake), añade un filtro a .ToLower() para cubrirlas.

Corrección robusta (cubriendo espacios & mayúsculas & separadores)

La siguiente función normaliza el nombre de ciudad eliminando espacios extra (incluidos separadores Unicode), recortando extremos y, opcionalmente, homogeneizando el caso:

function Normalize-City {
  param([string]$City, [switch]$ToTitleCase)

  if ([string]::IsNullOrWhiteSpace($City)) { return $null }

  # Sustituye cualquier secuencia de separadores de espacio Unicode por un solo espacio
  $c = $City -replace '\p{Zs}+', ' '
  $c = $c.Trim()

  if ($ToTitleCase) {
    $ti = [System.Globalization.CultureInfo]::InvariantCulture.TextInfo
    $c = $ti.ToTitleCase($c.ToLower())
  }
  return $c
}

Vista previa de normalización (no cambia nada aún)
$preview = Get-ExoMailbox -RecipientTypeDetails RoomMailbox |
  Get-Place |
  Select-Object Identity, DisplayName, City,
    @{n='CityNormalized';e={ Normalize-City -City $_.City -ToTitleCase }}

$preview | Where-Object { $.City -ne $.CityNormalized } |
  Format-Table DisplayName, City, CityNormalized -AutoSize

Si la vista previa es correcta, aplica los cambios:

$preview | Where-Object { $.City -ne $.CityNormalized } |
  ForEach-Object {
    Set-Place -Identity $.Identity -City $.CityNormalized
  }

Estrategia por “lista canónica” (recomendado en organizaciones grandes)

Para evitar variaciones futuras, define una lista canónica de ciudades permitidas (por ejemplo, las de tu directorio corporativo) y haz que el script solo aplique valores de esa lista. Así previenes “Londres”, “London”, “LON”, etc.

# Ejemplo simple de lista canónica
$CanonicalCities = @(
  "Roundlake",
  "Madrid",
  "Buenos Aires",
  "Ciudad de México",
  "Santiago"
)

$places = Get-ExoMailbox -RecipientTypeDetails RoomMailbox | Get-Place

foreach ($p in $places) {
  $normalized = Normalize-City -City $p.City -ToTitleCase
  if ($null -ne $normalized) {
    # Encuentra la mejor coincidencia exacta tras normalizar
    $match = $CanonicalCities | Where-Object { $_ -eq $normalized }
    if ($match) {
      if ($p.City -ne $match) {
        Set-Place -Identity $p.Identity -City $match
      }
    } else {
      # Opcional: reporta valores no canónicos para revisión manual
      [PSCustomObject]@{
        Identity = $p.Identity
        DisplayName = $p.DisplayName
        CityOriginal = $p.City
        CityNormalized = $normalized
        Status = "No coincide con lista canónica"
      }
    }
  }
}

Validación tras el cambio

  • Propagación: la actualización puede tardar en reflejarse en Room Finder. La mayoría de cambios se ven pronto, pero presupón que puede llevar hasta ~24 horas en el servicio y clientes.
  • Clientes: cierra y vuelve a abrir Outlook; en clientes de escritorio, las cachés de sala/ubicación pueden diferirse del servicio por un tiempo.
  • Revisión: vuelve a ejecutar los listados de diagnóstico para confirmar que ya no hay variaciones de City.

Checklist de “si el problema persiste”

La duplicidad de ciudades rara vez está relacionada con Room Lists, pero ya que participan en la experiencia de búsqueda, conviene revisarlas:

# Ver listas de salas existentes
Get-DistributionGroup -RecipientTypeDetails RoomList |
  Format-Table DisplayName, PrimarySmtpAddress

Ver miembros de una lista de salas concreta
Get-DistributionGroupMember -Identity "<RoomListName>" |
  Format-Table Name, PrimarySmtpAddress

Comprueba además:

  • Que todas las salas relevantes tienen City asignado y normalizado (Set-Place -City).
  • Que no quedaron salas obsoletas o de prueba con valores “raros”.
  • Que no hay mayúsculas/minúsculas diversas para la misma ciudad (decide una convención y aplícala en lote).

Qué no suele ayudar

  • Limpiar LocationMRU en el registro del equipo cliente solo afecta a sugerencias locales de ubicación en Outlook. No modifica ni la lista de ciudades ni los atributos de los lugares en el servicio.
  • Eliminar “la ciudad” desde el cliente: no existe un objeto de ciudad independiente que puedas borrar. La lista se construye a partir del atributo City de cada sala.

Buenas prácticas para evitar regresiones

  1. Automatiza la normalización en tu proceso de alta de salas:
    • Valida la ciudad contra una lista canónica.
    • Aplica Trim() y normaliza separadores.
    • Unifica el caso (p. ej., Title Case o mayúsculas).
  2. Audita periódicamente (por ejemplo, semanalmente) y envía un reporte con diferencias detectadas.
  3. Documenta un estándar (nombres oficiales de ciudades, acentos, idioma) y compártelo con quien crea/edita salas.

Script de auditoría listo para usar

Este guion genera un informe de posibles incoherencias y propone el valor normalizado:

# Requiere: Connect-ExchangeOnline

function Normalize-City {
  param([string]$City)
  if ([string]::IsNullOrWhiteSpace($City)) { return $null }
  $c = $City -replace '\p{Zs}+', ' '
  $c = $c.Trim()
  return $c
}

$report = Get-ExoMailbox -RecipientTypeDetails RoomMailbox |
  Get-Place |
  Select-Object Identity, DisplayName, @{n='CityOriginal';e={$_.City}},
    @{n='CityNormalized';e={ Normalize-City -City $_.City }},
    @{n='TieneEspaciosExtremos';e={ $_.City -match '^\s+|\s+$' }},
    @{n='LowerCase';e={ $_.City.ToLower() }},
    @{n='TrimLower';e={ (Normalize-City -City $_.City).ToLower() }}

$report |
  Sort-Object CityNormalized, DisplayName |
  Format-Table -AutoSize

Corrección masiva con salvaguardas

Este ejemplo solo corrige valores en los que la normalización no cambia el “contenido” (es decir, quita espacios o separadores raros), sin forzar cambios de idioma o de nomenclatura:

$places = Get-ExoMailbox -RecipientTypeDetails RoomMailbox | Get-Place

foreach ($p in $places) {
  $original = $p.City
  $normalized = $null
  if (-not [string]::IsNullOrWhiteSpace($original)) {
    $normalized = ($original -replace '\p{Zs}+', ' ').Trim()
  }

  # Solo corrige si el valor difiere por espacios/separadores
  if ($null -ne $normalized -and $original -ne $normalized) {
    Write-Host "Set-Place -Identity $($p.Identity) -City '$normalized'"
    Set-Place -Identity $p.Identity -City $normalized
  }
}

Deshacer cambios (rollback)

Antes de aplicar correcciones masivas, exporta un CSV con el valor original para poder revertir si es necesario:

$backup = Get-ExoMailbox -RecipientTypeDetails RoomMailbox |
  Get-Place |
  Select-Object Identity, DisplayName, City

$path = Join-Path $env:TEMP "backup-places-$(Get-Date -Format 'yyyyMMdd-HHmmss').csv"
$backup | Export-Csv -Path $path -NoTypeInformation -Encoding UTF8
Write-Host "Copia de seguridad guardada en $path"

Para restaurar desde el CSV:

$restore = Import-Csv $path
$restore | ForEach-Object {
  Set-Place -Identity $.Identity -City $.City
}

Verificación de extremo a extremo

  1. Ejecuta el inventario y confirma que todas las salas de la ciudad comparten exactamente el mismo City.
  2. Comprueba Room Lists (si las usas) para asegurar que las salas correctas están en la lista adecuada.
  3. Valida en Outlook Web y en Outlook para escritorio que solo aparece una entrada de la ciudad en All Cities.

Preguntas frecuentes

¿Puedo “borrar” la ciudad vacía?
No directamente. La lista de ciudades se genera a partir de los valores City de las salas. Al normalizar los valores, la ciudad duplicada desaparece sola.

¿Cuánto tarda en actualizarse?
Depende de la propagación del servicio y de la caché del cliente. Considera que puede tardar hasta ~24 horas en verse reflejado en todos los clientes.

¿Las mayúsculas importan?
Según el cliente, pueden generar agrupaciones separadas si coexisten con espacios u otros caracteres. Estandariza el caso para evitar sorpresas.

¿Debo tocar las Room Lists?
No para resolver la duplicación de ciudades, pero sí conviene revisar membresías si, además, notas que faltan salas al filtrar por listas.

Resumen ejecutivo

  • Problema: Ciudad duplicada en Room Finder causada por espacios, separadores o variaciones en City de las salas.
  • Solución: Auditar con Get-Place, normalizar (recortar/unificar) con Set-Place y permitir la propagación.
  • Soporte: Revisar Room Lists si aún aparece una ciudad “fantasma” y asegurar membresías correctas.

Apéndice: diferencias útiles y consideraciones

  • Get-Place vs. Get-ExoMailbox: el primero devuelve metadatos físicos (City, Building, Floor); el segundo identifica buzones de tipo sala para encadenar el pipeline.
  • Campo correcto a editar: Set-Place -City (no confundas con propiedades de dirección en otras herramientas).
  • Permisos: asegúrate de tener privilegios para administrar lugares (admin de Exchange o permisos delegados adecuados).
  • Internacionalización: decide si tu estándar incluye acentos y títulos de caso; aplícalo consistentemente.
  • Control de calidad continuo: agenda un trabajo periódico que ejecute la auditoría y te alerte de nuevas desviaciones.

Conclusión: la duplicación de ciudades en Room Finder no es un misterio del servicio, sino la consecuencia de datos inconsistentes. Con una auditoría breve y una normalización cuidadosa de City, la experiencia de reserva vuelve a ser coherente y fácil de usar.

Índice