PowerShell Get-ChildItem con una matriz de cadenas comodín

Resuelto FMFF asked hace 10 meses • 1 respuestas

Tengo una carpeta con un montón de archivos .BAK de SQL Server de varias bases de datos. Los nombres de los archivos .BAK siguen cambiando todos los días.

De ellos, solo estoy interesado en los archivos BAK más recientes de 3 o 4 bases de datos paraRestore-SqlDatabase .

Esto es lo que tengo hasta ahora:

$databases = @('Orders', 'Items', 'Returns')
$BackupPath  = '\\BACKUPSERVER\BackupData\'
$latestBackupFile = Get-ChildItem $BackupPath -Attributes !Directory *$databases[0]* | Sort-Object -Descending -Property LastWriteTime | Select-Object -First 1
$latestBackupFile
#Restore-SqlDatabase -ServerInstance "my-vm" -Database "Orders" -BackupFile "\\BACKUPSERVER\BackupData\AODA2.Orders.2024-01-15.22-23-13.BAK" -ReplaceDatabase
#Restore-SqlDatabase -ServerInstance "my-vm" -Database "Items" -BackupFile "\\BACKUPSERVER\BackupData\MMMWW.Items.2024-01-15.22-23-13.BAK" -ReplaceDatabase

El Restore-SqlDatabasecomando funciona cuando se ejecuta por sí solo; Lo he incluido en el script anterior para contexto.

*$databases[0]*- Esto no da como resultado una cadena comodín como*Orders* esperaba.

No estoy seguro de cómo crear un bucle ForEach para a) recorrer la $databasesmatriz para obtener la cadena comodín como *Orders*, etc. y b) recorrer el último archivo .BAK para cada uno de esos comodines para construir el*Items**Returns*Restore-SqlDatabase comando.

Soy nuevo en PowerShell; ¿Como hacer esto? Gracias.

FMFF avatar Feb 17 '24 02:02 FMFF
Aceptado

PowerShell tiene dos gramáticas distintas, descritas en la documentación como "modos de análisis" :

  • Modo argumento:
    • se aplica a todo lo que sigue inmediatamente al nombre de un comando, incluido su *$database[0]*argumento
  • Modo de expresión:
    • se aplica a casi todo lo demás y funciona exactamente como se espera: $databases[0]se interpretaría como una operación de índice de matriz

Cuando PowerShell encuentra un llamado "token de palabra simple" en modo argumento, lo interpreta automáticamente como el contenido de una expresión literal de cadena expandible.

En otras palabras, el argumento *$databases[0]*se interpreta igual que si hubiera escrito "*$databases[0]*".

En un literal de cadena expandible, solo se reconocen y expanden expresiones de variables simples , por lo que PowerShell intenta evaluar $databasespor sí solo sin considerar [0].

Puede escapar de las reglas de interpolación de cadenas envolviendo la expresión con el operador de subexpresión $():

"*$($databases[0])*"

Es bueno saberlo, pero realmente no lo necesitas aquí : ¡necesitas un bucle!

No estoy seguro de cómo crear un bucle ForEach

La foreachdeclaración de bucle en PowerShell es bastante sencilla:

foreach ($item in $collection) {
  # work with each $item here
}

Intentemos eso con tu $databasesmatriz:

foreach ($databaseName in $databases) {
  # find the latest backup file containing the db name in its file name
  $latestBackupFile = Get-ChildItem $BackupPath -File -Filter "*$databaseName*.bak" | Sort-Object -Descending -Property LastWriteTime | Select-Object -First 1

  if ($latestBackupFile) {
    Restore-SqlDatabase -ServerInstance "my-vm" -Database $databaseName -BackupFile $latestBackupFile.FullName -ReplaceDatabase
  }
  else {
    Write-Warning "Unable to locate backup file for database $databaseName"
  }
}

Dado que ya no dependemos de un indexador de matriz, $databaseNameahora se puede expandir la cadena de filtro como se esperaba: en la primera iteración la $databaseNamevariable tendrá el valor "Orders", por lo que la expresión del argumento -Filter "*$databaseName*.bak"dará como resultado la cadena de filtro.*Orders*.bak

Por último, si necesita rellenar el nombre de la base de datos con caracteres que de otro modo podrían interpretarse como parte de la ruta de la variable, puede calificar la ruta de la variable con {}:

# underscore _ below would have been interpreted as part of the variable path expression `$databaseName_` if not for the curly brackets
... -Filter "*${databaseName}_*.bak" 
Mathias R. Jessen avatar Feb 16 '2024 20:02 Mathias R. Jessen