У меня такой код:
$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;
Когда я пытаюсь использовать одно из свойств в строке, выполните команду:
& "$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'"
Он пытается просто использовать значение, $DatabaseSettings
а не значение $DatabaseSettings[0].DatabaseName
, которое недопустимо.
Мой обходной путь - скопировать его в новую переменную.
Как я могу получить доступ к свойству объекта непосредственно в строке с двойными кавычками?
источник
@Joey имеет правильный ответ, но просто чтобы добавить немного больше о том, почему вам нужно принудительно выполнить оценку
$()
:Ваш примерный код содержит двусмысленность, которая указывает на то, почему создатели PowerShell, возможно, решили ограничить расширение простыми ссылками на переменные и не поддерживать доступ к свойствам (в стороне: расширение строки выполняется путем вызова
ToString()
метода объекта, который может объяснить некоторые "странные" результаты).Ваш пример содержится в самом конце командной строки:
Если бы свойства объектов были расширены по умолчанию, вышеуказанное разрешило бы
так как объект ссылается
$LogFileName
не будет иметь свойствоldf
,$null
(или пустая строка) будет заменена на переменную.источник
@Joey имеет хороший ответ. Есть еще один способ с более .NET-видом с эквивалентом String.Format, я предпочитаю его при доступе к свойствам объектов:
Вещи о машине:
Создайте объект:
Интерполировать строку:
Выходы:
источник
write-host "foo = {0}" -f $foo
поскольку PowerShell будет рассматривать-f
какForegroundColor
параметр дляwrite-host
. В этом примере вам потребуетсяwrite-host ( "foo = {0}" -f $foo )
. Это стандартное поведение PowerShell, но его стоит отметить.String.Format
.Expression
другойArgument
(до конца команды).Примечание к документации:
Get-Help about_Quoting_Rules
охватывает интерполяцию строк, но, начиная с PSv5, не углубленно.Для того, чтобы дополнить полезный ответ Джой с прагматическим резюме в PowerShell в разложении строки (строка интерполяция в двойных кавычках строки ( в
"...")
том числе в двойных кавычках здесь-строк ):Только ссылки , такие как
$foo
,$global:foo
(или$script:foo
, ...) и$env:PATH
(переменные среды) признаются , когда непосредственно встраивается в"..."
строке - то есть, только ссылочная переменная сама расширяется, независимо от того, что следует.Чтобы отличить имя переменной от последующих символов в строке, заключите его в
{
и}
; например,${foo}
.Это особенно важно , если имя переменной сопровождается
:
, в PowerShell иначе бы рассмотреть все между$
и в области видимости спецификатор, как правило , вызывает интерполяцию неудачу ; например, ломается, но работает по назначению. ( В качестве альтернативы, экранирующего : ).:
"$HOME: where the heart is."
"${HOME}: where the heart is."
`
:
"$HOME`: where the heart is."
Чтобы рассматривать a
$
или a"
как литерал , добавьте к нему escape-символ.`
( обратная кавычка ); например:"`$HOME's value: `"$HOME`""
Для чего -то еще, в том числе с использованием индексов массива и доступ к переменной объекта в свойства , необходимо заключить выражение
$(...)
, то оператор подвыражения (например,"PS version: $($PSVersionTable.PSVersion)"
или"1st el.: $($someArray[0])"
)$(...)
even позволяет вставлять вывод целых командных строк в строки с двойными кавычками (например,"Today is $((Get-Date).ToString('d'))."
).Результаты интерполяции не обязательно выглядят так же, как формат вывода по умолчанию (то, что вы бы увидели, если бы вы напечатали переменную / подвыражение непосредственно в консоли, например, что включает средство форматирования по умолчанию; см.
Get-Help about_format.ps1xml
):Коллекции , включая массивы, преобразуются в строки путем помещения одного пробела между строковыми представлениями элементов (по умолчанию; можно указать другой разделитель путем установки
$OFS
) Например,"array: $(@(1, 2, 3))"
даетarray: 1 2 3
Экземпляры любого другого типа (включая элементы коллекций, которые сами не являются коллекциями) преобразовываются в строку либо путем вызова
IFormattable.ToString()
метода с инвариантной культурой , если тип экземпляра поддерживаетIFormattable
интерфейс [1] , либо путем вызова.psobject.ToString()
, который в большинстве случаев просто вызывает базовый типа .NET в.ToString()
методе [2] , которые могут или не могут дать содержательное представления: если а (непримитивный) тип специально не переопределил.ToString()
метод, все , что вы получите это полное имя типа (например,"hashtable: $(@{ key = 'value' })"
выходыhashtable: System.Collections.Hashtable
).Для того, чтобы получить тот же результат , как и в консоли , используйте подвыражения и трубу
Out-String
и применить ,.Trim()
чтобы удалить любые начальные и конечные пустые строки, если это необходимо; например,"hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"
дает:[1] Это, возможно, удивительное поведение означает, что для типов, которые поддерживают представления,
$obj.ToString()
зависящие от языка и региональных параметров , дает представление, соответствующее текущей культуре , тогда как"$obj"
(строковая интерполяция) всегда приводит к представлению, инвариантному для культуры - см. Этот мой ответ .[2] Важные переопределения:
* Ранее обсуждавшаяся строковая форма коллекций (разделенный пробелами список элементов, а не что-то подобное
System.Object[]
).* The hashtable- как представление
[pscustomobject]
экземпляров (объяснено здесь ) , а не пустая строка .источник