J'ai le code suivant:
$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;
Lorsque j'essaie d'utiliser l'une des propriétés d'une commande d'exécution de chaîne:
& "$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'"
Il essaie simplement d'utiliser la valeur de $DatabaseSettings
plutôt que la valeur de $DatabaseSettings[0].DatabaseName
, qui n'est pas valide.
Ma solution consiste à le copier dans une nouvelle variable.
Comment accéder directement à la propriété de l'objet dans une chaîne entre guillemets doubles?
Lorsque vous placez un nom de variable dans une chaîne entre guillemets, il sera remplacé par la valeur de cette variable:
$foo = 2
"$foo"
devient
"2"
Si vous ne voulez pas que vous ayez à utiliser des guillemets simples:
$foo = 2
'$foo'
Cependant, si vous souhaitez accéder aux propriétés ou utiliser des index sur des variables dans une chaîne entre guillemets doubles, vous devez placer cette sous-expression dans $()
:
$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 ne développe les variables que dans ces cas, rien de plus. Pour forcer l'évaluation d'expressions plus complexes, y compris des index, des propriétés ou même des calculs complets, vous devez les inclure dans l'opérateur de sous-expression $( )
, ce qui fait que l'expression à l'intérieur est évaluée et incorporée dans la chaîne.
@Joey a la bonne réponse, mais juste pour ajouter un peu plus pourquoi vous devez forcer l'évaluation avec $()
:
Votre exemple de code contient une ambiguïté qui explique pourquoi les fabricants de PowerShell ont peut-être choisi de limiter l'expansion à de simples références de variables et de ne pas prendre également en charge l'accès aux propriétés (en tant que côté: l'expansion de chaîne se fait en appelant la fonction ToString()
méthode sur l'objet, ce qui peut expliquer certains résultats "bizarres").
Votre exemple contenu à la toute fin de la ligne de commande:
...\$LogFileName.ldf
Si les propriétés des objets étaient développées par défaut, ce qui précède se résoudrait en
...\
puisque l'objet référencé par $LogFileName
n'aurait pas de propriété appelée ldf
, $null
(ou une chaîne vide) remplacerait la variable.
@Joey a une bonne réponse. Il y a une autre façon avec un look plus .NET avec un équivalent String.Format, je le préfère lors de l'accès aux propriétés sur les objets:
À propos d'une voiture:
$properties = @{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; }
Créez un objet:
$car = New-Object -typename psobject -Property $properties
Interpoler une chaîne:
"The {0} car is a Nice {1} that is {2}" -f $car.color, $car.type, $car.package
Les sorties:
# The red car is a Nice sedan that is fully loaded
Note de documentation: Get-Help about_Quoting_Rules
couvre l'interpolation de chaînes, mais, à partir de PSv5, pas en profondeur.
Pour compléter réponse utile de Joey avec un résumé pragmatique de PowerShell string expansion (interpolation de chaîne dans entre guillemets chaînes, y compris entre guillemets ici-chaînes ):
Seules les références telles que $foo
, $global:foo
(Ou $script:foo
, ...) et $env:PATH
(variables d'environnement) sont reconnues lorsque directement incorporé dans une chaîne "..."
- c'est-à-dire que seule la référence de variable elle-même est étendu, indépendamment de ce qui suit.
Pour lever l'ambiguïté d'un nom de variable à partir des caractères suivants de la chaîne, le placer entre {
Et }
; par exemple, ${foo}
.
Ceci est particulièrement important si le nom de la variable est suivi d'un :
, Car PowerShell considérerait autrement tout entre le $
Et le :
A scope spécificateur, provoquant généralement l'interpolation échec; Par exemple, "$HOME: where the heart is."
se casse, mais "${HOME}: where the heart is."
fonctionne comme prévu.
(Alternativement, `
- échapper à :
: "$HOME`: where the heart is."
).
Pour traiter un $
Ou un "
Comme un littéral, préfixez-le avec caractère d'échappement. `
(a backtick); par exemple.:"`$HOME's value: `"$HOME`""
Pour toute autre chose, y compris l'utilisation des indices de tableau et l'accès aux propriétés d'une variable objet , vous devez mettre l'expression entre $(...)
, l'opérateur sous-expression (par exemple, "PS version: $($PSVersionTable.PSVersion)"
ou "1st el.: $($someArray[0])"
)
$(...)
vous permet même d'incorporer la sortie de lignes de commande entières dans des chaînes entre guillemets doubles (par exemple, "Today is $((Get-Date).ToString('d'))."
). Les résultats d'interpolation ne ressemblent pas nécessairement au format de sortie par défaut (ce que vous verriez si vous imprimiez la variable/sous-expression directement sur la console, par exemple, qui implique le formateur par défaut; voir Get-Help about_format.ps1xml
):
Les collections , y compris les tableaux, sont converties en chaînes en en plaçant un espace unique entre les représentations de chaîne des éléments (par défaut; un séparateur différent peut être spécifié en définissant $OFS
) Par exemple, "array: $(@(1, 2, 3))"
donne array: 1 2 3
Les instances de tout autre type (y compris les éléments de collections qui ne sont pas elles-mêmes des collections) sont stringifiées par oui appel de la méthode IFormattable.ToString()
avec la culture invariante, si le type de l'instance prend en charge le IFormattable
interface[1], ou en appelant .psobject.ToString()
, qui dans la plupart des cas appelle simplement la méthode .ToString()
du type .NET sous-jacent [2], qui peut ou non donner une représentation significative: à moins qu'un type (non primitif) ait spécifiquement outrepassé la méthode .ToString()
, tout ce que vous obtiendrez sera le complet nom du type = (par exemple, "hashtable: $(@{ key = 'value' })"
donne hashtable: System.Collections.Hashtable
).
Pour obtenir la même sortie que dans la console , utilisez une sous-expression et un tuyau vers Out-String
et appliquez .Trim()
pour supprimer les lignes vides de début et de fin, si vous le souhaitez; par exemple.,"hashtable:`n$((@{ key = 'value' } | Out-String).Trim())"
donne:
hashtable:
Name Value
---- -----
key value
[1] Ce comportement peut-être surprenant signifie que, pour les types qui prennent en charge les représentations sensibles à la culture, $obj.ToString()
donne une actuelle - représentation appropriée à la culture, tandis que "$obj"
(interpolation de chaîne) donne toujours une représentation invariante de la culture - voir cette réponse à moi.
[2] Remplacements notables:
* La chaîne de caractères précédemment discutée de collections (liste d'éléments séparés par des espaces plutôt que quelque chose comme System.Object[]
).
* La table de hachage - comme représentation des instances de [pscustomobject]
(Expliquée ici ) plutôt que la chaîne vide.