你怎么能在一个双引号string中使用对象的属性?

我有以下代码:

$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; 

当我尝试使用string执行命令中的某个属性时:

 & "$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 ,这是无效的。
我的解决方法是将其复制到一个新的variables。

如何直接在双引号string中访问对象的属性?

当你在一个双引号string中包含一个variables名时,它将被该variables的值replace:

 $foo = 2 "$foo" 

 "2" 

如果你不想要你用单引号:

 $foo = 2 '$foo' 

但是,如果要访问属性或在双引号string中使用variables的索引,则必须将该子expression式放在$()

 $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只在这些情况下扩展variables,仅此而已。 为了强制评估更复杂的expression式,包括索引,属性甚至完整的计算,必须将这些expression式包含在子expression式运算符$( ) ,这会导致内部expression式被计算并embedded到string中。

@Joey有正确的答案,但只是为了增加一点,为什么你需要用$()强制进行评估:

您的示例代码包含一个含糊不清的地方,指出为什么PowerShell的制作者可能select将扩展限制为仅仅是variables引用,而不支持对属性的访问(另外:通过调用ToString()方法完成string扩展对象,这可以解释一些“奇怪”的结果)。

你的例子包含在命令行的最后:

 ...\$LogFileName.ldf 

如果默认扩展对象的属性,则上面的内容将parsing为

 ...\ 

由于$LogFileName引用的对象不会有一个名为ldf的属性, $null (或一个空string)将被replace为该variables。

@Joey有一个很好的答案。 有更多的.NET外观与String.Format等价物的另一种方式,我更喜欢当访问对象的属性:

关于汽车的事情:

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

创build一个对象:

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

插入一个string:

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

输出:

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

文档说明: Get-Help about_Quoting_Rules涵盖了string插值,但从PSv5开始并不深入。

PowerShell的string扩展双引号string中的string插值,包括双引号string )中的实用摘要来补充Joey的有用答案 :

  • 直接embedded到"..."string中时,只会识别$foo$global:foo (或$script:foo ,…)和$env:PATH (环境variables)等引用也就是说,variables引用本身被扩展,而不pipe下面的内容如何。

    • 为了消除string中后续字符的variables名请将其放在{} ; 例如${foo}
      如果variables名后跟一个: ,PowerShell会考虑$: 范围说明符之间的所有内容,通常会导致插值失败 ,这一点尤其重要。 例如"$HOME: where the heart is." rest,但是"${HOME}: where the heart is." 按预期工作。
      (或者, `暴露:: "$HOME`: where the heart is." )。

    • 把一个$或者一个"作为一个字面值 ,用escape char。反引号 )作为前缀,例如:
      "`$HOME's value: `"$HOME`""

  • 对于其他任何事情,包括使用数组下标和访问对象variables的属性 ,必须将expression式包含在$(...)子expression式运算符 (例如, "PS version: $($PSVersionTable.PSVersion)""1st el.: $($someArray[0])"

    • 使用$(...)甚至可以将整个命令行的输出embedded到双引号string中(例如"Today is $((Get-Date).ToString('d'))." )。
  • 插值结果不一定与默认的输出格式相同 (例如,如果将variables/子expression式直接输出到控制台,例如涉及默认格式化程序,请参阅Get-Help about_format.ps1xml ):

    • 集合 (包括数组)通过在元素的string表示之间放置一个空格来转换为string(默认情况下,可以通过设置$OFS来指定不同的分隔符)例如: "array: $(@(1, 2, 3))" yield array: 1 2 3

    • 如果实例types支持IFormttable接口[1]或者通过调用带有不变文化IFormattable.ToString()方法,则 任何其他types的实例(包括不是本身集合的集合的元素)都会被IFormattable.ToString().psobject.ToString() ,在大多数情况下,它只是调用底层.NETtypes的.ToString()方法 [2] ,它可能会或可能不会提供有意义的表示forms:除非(非原始types)types明确地覆盖了.ToString()方法,所有你会得到的是完整的types名称 (例如, "hashtable: $(@{ key = 'value' })"产生hashtable: System.Collections.Hashtable )。

    • 获得与控制台相同的输出 ,使用子expression式和pipe道Out-String ,如果需要,应用.Trim()删除任何前导和尾随的空行。 例如,
      "hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"产生:

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

[1]这也许令人惊讶的行为意味着,对于支持文化敏感表示的types, $obj.ToString()产生一个当前的文化适当的表示,而"$obj" (string内插)总是导致文化不变代表 – 看到我的这个答案 。

[2]值得注意的例外:
string展开[pscustomobject]通过.psobject.ToString() ( 在这里解释)产生一个类似于散列表的表示,而调用.ToString()直接产生空string