help - obtener ayuda de un comando powershell
¿Cómo se puede usar la propiedad de un objeto en una cadena de comillas dobles? (4)
@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.
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 intento 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?
@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
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.
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 alcance , 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''))."
).
- El uso de
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))"
yieldsarray: 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 interfazIFormattable
[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'' })"
yieldhashtable: System.Collections.Hashtable
).Para obtener el mismo resultado que en la consola , use una subexpresión y
.Trim()
aOut-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 here ) en lugar de la cadena vacía .