PowerShell Get-ChildItem con una matriz de cadenas comodín
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-SqlDatabase
comando 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 $databases
matriz 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.
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
- se aplica a todo lo que sigue inmediatamente al nombre de un comando, incluido su
- 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
- se aplica a casi todo lo demás y funciona exactamente como se espera:
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 $databases
por 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 foreach
declaración de bucle en PowerShell es bastante sencilla:
foreach ($item in $collection) {
# work with each $item here
}
Intentemos eso con tu $databases
matriz:
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, $databaseName
ahora se puede expandir la cadena de filtro como se esperaba: en la primera iteración la $databaseName
variable 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"