¿Cómo se puede usar la propiedad de un objeto en una cadena de comillas dobles?

Tengo el siguiente código:

$DatabaseSettings = @(); $NewDatabaseSetting = "" | select DatabaseName, DataFile, LogFile, LiveBackupPath; $NewDatabaseSetting.DatabaseName = "LiveEmployees_PD"; $NewDatabaseSetting.DataFile = "LiveEmployees_PD_Data"; $NewDatabaseSetting.LogFile = "LiveEmployees_PD_Log"; $NewDatabaseSetting.LiveBackupPath = '\\LiveServer\LiveEmployeesBackups'; $DatabaseSettings += $NewDatabaseSetting; 

Cuando bash usar una de las propiedades en un comando de ejecución de cadena:

 & "$SQlBackupExePath\SQLBackupC.exe" -I $InstanceName -SQL ` "RESTORE DATABASE $DatabaseSettings[0].DatabaseName FROM DISK = '$tempPath\$LatestFullBackupFile' WITH NORECOVERY, REPLACE, MOVE '$DataFileName' TO '$DataFilegroupFolder\$DataFileName.mdf', MOVE '$LogFileName' TO '$LogFilegroupFolder\$LogFileName.ldf'" 

Intenta usar el valor de $DatabaseSettings lugar del valor de $DatabaseSettings[0].DatabaseName , que no es válido.
Mi solución es hacer que se copie en una nueva variable.

¿Cómo puedo acceder a la propiedad del objeto directamente en una cadena de comillas dobles?

    Cuando encierra un nombre de variable en una cadena de comillas dobles, se reemplazará por el valor de esa variable:

     $foo = 2 "$foo" 

    se convierte

     "2" 

    Si no quiere que tenga que usar comillas simples:

     $foo = 2 '$foo' 

    Sin embargo, si desea acceder a propiedades, o usar índices en variables en una cadena de comillas dobles, debe incluir esa subexpresión en $() :

     $foo = 1,2,3 "$foo[1]" # yields "1 2 3[1]" "$($foo[1])" # yields "2" $bar = "abc" "$bar.Length" # yields "abc.Length" "$($bar.Length)" # yields "3" 

    Powershell solo expande variables en esos casos, nada más. Para forzar la evaluación de expresiones más complejas, incluidos índices, propiedades o incluso cálculos completos, debe encerrarlos en el operador de subexpresión $( ) que hace que la expresión interna se evalúe y se incruste en la cadena.

    @Joey tiene la respuesta correcta, pero solo para agregar un poco más sobre por qué necesita forzar la evaluación con $() :

    Su código de ejemplo contiene una ambigüedad que apunta a por qué los creadores de PowerShell pueden haber elegido limitar la expansión a meras referencias de variables y no admitir el acceso a las propiedades (como ToString() : la expansión de cadenas se realiza llamando al método ToString() en el objeto, que puede explicar algunos resultados “impares”).

    Su ejemplo se encuentra al final de la línea de comando:

     ...\$LogFileName.ldf 

    Si las propiedades de los objetos se expandieron por defecto, lo anterior resolvería

     ...\ 

    dado que el objeto referenciado por $LogFileName no tendría una propiedad llamada ldf , $null (o una cadena vacía) se sustituiría por la variable.

    @Joey tiene una buena respuesta. Hay otra manera con un aspecto más .NET con un equivalente de String.Format, lo prefiero al acceder a las propiedades en los objetos:

    Cosas sobre un auto:

     $properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; } 

    Crea un objeto:

     $car = New-Object -typename psobject -Property $properties 

    Interpolar una cadena:

     "The {0} car is a nice {1} that is {2}" -f $car.color, $car.type, $car.package 

    Productos:

     # The red car is a nice sedan that is fully loaded 

    Nota de documentación: Get-Help about_Quoting_Rules cubre la interpolación de cadenas, pero, a partir de PSv5, no en profundidad.

    Para complementar la útil respuesta de Joey con un resumen pragmático de la expansión de cadenas de PowerShell (interpolación de cadenas en cadenas de comillas dobles , incluso en cadenas de caracteres dobles aquí citadas):

    • Solo las referencias como $foo , $global:foo (o $script:foo , …) y $env:PATH (variables de entorno) se reconocen cuando se incrustan directamente en una cadena "..." , es decir, solo el la referencia variable en sí misma se expande, independientemente de lo que sigue.

      • Para eliminar la ambigüedad de un nombre de variable de los caracteres subsiguientes en la cadena, enciérrelo en { y } ; por ejemplo, ${foo} .
        Esto es especialmente importante si el nombre de la variable va seguido de un : , ya que PowerShell consideraría todo lo demás entre el $ y el : un especificador de scope , normalmente haciendo que la interpolación falle ; por ejemplo, "$HOME: where the heart is." se rompe, pero "${HOME}: where the heart is." funciona según lo previsto.
        (Alternativamente, ` -escape the : "$HOME`: where the heart is." ).

      • Para tratar un $ o un " como un literal , prefímalo con escape char. ` (Un backtick ), por ejemplo:
        "`$HOME's value: `"$HOME`""

    • Para cualquier otra cosa, incluido el uso de subíndices de matriz y el acceso a las propiedades de una variable de objeto, debe encerrar la expresión en $(...) , el operador de subexpresión (por ejemplo, "PS version: $($PSVersionTable.PSVersion)" o "1st el.: $($someArray[0])" )

      • El uso de $(...) incluso le permite insertar el resultado de líneas de comando completas en cadenas de comillas dobles (por ejemplo, "Today is $((Get-Date).ToString('d'))." ).
    • Los resultados de interpolación no necesariamente tienen el mismo aspecto que el formato de salida predeterminado (lo que vería si imprimiera la variable / subexpresión directamente a la consola, por ejemplo, que implica el formateador predeterminado; consulte Get-Help about_format.ps1xml ):

      • Las colecciones , incluidas las matrices, se convierten en cadenas al colocar un espacio único entre las representaciones de cadena de los elementos (de manera predeterminada, se puede especificar un separador diferente al establecer $OFS ). Por ejemplo, "array: $(@(1, 2, 3))" yields array: 1 2 3

      • Las instancias de cualquier otro tipo (incluidos los elementos de colecciones que no son colecciones) se codifican llamando al método IFormattable.ToString() con el cultivo invariable , si el tipo de instancia admite la interfaz IFormattable [1] o llamando .psobject.ToString() , que en la mayoría de los casos simplemente invoca el método .ToString() del tipo .NET subyacente [2] , que puede dar o no una representación significativa: a menos que un tipo (no primitivo) haya anulado específicamente el .ToString() método, todo lo que obtendrá es el nombre de tipo completo (por ejemplo, "hashtable: $(@{ key = 'value' })" yield hashtable: System.Collections.Hashtable ).

      • Para obtener el mismo resultado que en la consola , use una subexpresión y .Trim() a Out-String y aplique .Trim() para eliminar las líneas vacías .Trim() y finales, si lo desea; p.ej,
        "hashtable:`n$((@{ key = 'value' } | Out-String).Trim())" produce:

         hashtable: Name Value ---- ----- key value 

    [1] Este comportamiento quizás sorprendente significa que, para los tipos que admiten representaciones sensibles a la cultura, $obj.ToString() produce una representación actual apropiada para el cultivo, mientras que "$obj" (interpolación de cadenas) siempre da como resultado una cultura invariante representación – ver esta respuesta mía.

    [2] anulaciones notables:
    * La cadena de colecciones previamente discutida (lista de elementos separados por espacios en lugar de algo así como System.Object[] ).
    * La representación de tipo [pscustomobject] instancias [pscustomobject] (explicado aquí ) en lugar de la cadena vacía .