J'utilise ce morceau de code (simplifié) pour extraire un ensemble de tables à partir de SQL Server avec bcp.
$OutputDirectory = "c:\junk\"
$ServerOption = "-SServerName"
$TargetDatabase = "Content.dbo."
$ExtractTables = @(
"Page"
, "ChecklistItemCategory"
, "ChecklistItem"
)
for ($i=0; $i -le $ExtractTables.Length – 1; $i++) {
$InputFullTableName = "$TargetDatabase$($ExtractTables[$i])"
$OutputFullFileName = "$OutputDirectory$($ExtractTables[$i])"
bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
}
Cela fonctionne très bien, mais certaines tables doivent maintenant être extraites via des vues, d'autres non. J'ai donc besoin d'une structure de données qui ressemble à ceci:
"Page" "vExtractPage"
, "ChecklistItemCategory" "ChecklistItemCategory"
, "ChecklistItem" "vExtractChecklistItem"
Je cherchais des hachages, mais je ne trouve rien sur la façon de passer en boucle dans un hachage. Quelle serait la bonne chose à faire ici? Peut-être juste utiliser un tableau, mais avec les deux valeurs, séparées par un espace?
Ou est-ce que je manque quelque chose d'évident?
La réponse de Christian fonctionne bien et montre comment vous pouvez parcourir chaque élément de la table de hachage en utilisant la méthode GetEnumerator
. Vous pouvez également effectuer une boucle à l'aide de la propriété keys
. Voici un exemple comment:
$hash = @{
a = 1
b = 2
c = 3
}
$hash.Keys | % { "key = $_ , value = " + $hash.Item($_) }
Sortie:
key = c , value = 3
key = a , value = 1
key = b , value = 2
Un raccourci n'est pas préférable pour les scripts; c'est moins lisible. L'opérateur% {} est considéré comme un raccourci. Voici comment procéder dans un script pour en améliorer la lisibilité et la réutilisabilité:
PS> $hash = @{
a = 1
b = 2
c = 3
}
PS> $hash
Name Value
---- -----
c 3
b 2
a 1
Note: préférence personnelle; la syntaxe est plus facile à lire
La méthode GetEnumerator () se ferait comme suit:
foreach ($h in $hash.GetEnumerator()) {
Write-Host "$($h.Name): $($h.Value)"
}
Sortie:
c: 3
b: 2
a: 1
La méthode des clés se ferait comme indiqué:
foreach ($h in $hash.Keys) {
Write-Host "${h}: $($hash.Item($h))"
}
Sortie:
c: 3
b: 2
a: 1
Faites attention à trier votre hashtable ...
Sort-Object peut le changer en tableau:
PS> $hash.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Hashtable System.Object
PS> $hash = $hash.GetEnumerator() | Sort-Object Name
PS> $hash.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Ceci et d'autres boucles PowerShell sont disponibles sur mon blog.
À propos de la boucle dans un hachage:
$Q = @{"ONE"="1";"TWO"="2";"THREE"="3"}
$Q.GETENUMERATOR() | % { $_.VALUE }
1
3
2
$Q.GETENUMERATOR() | % { $_.key }
ONE
THREE
TWO
Vous pouvez aussi le faire sans variable
@{
'foo' = 222
'bar' = 333
'baz' = 444
'qux' = 555
} | % getEnumerator | % {
$_.key
$_.value
}
Voici un autre moyen rapide, en utilisant simplement la clé comme index dans la table de hachage pour obtenir la valeur:
$hash = @{
'a' = 1;
'b' = 2;
'c' = 3
};
foreach($key in $hash.keys) {
Write-Host ("Key = " + $key + " and Value = " + $hash[$key]);
}
Si vous utilisez PowerShell v3, vous pouvez utiliser JSON au lieu d'une table de hachage et le convertir en objet avec Convert-FromJson :
@'
[
{
FileName = "Page";
ObjectName = "vExtractPage";
},
{
ObjectName = "ChecklistItemCategory";
},
{
ObjectName = "ChecklistItem";
},
]
'@ |
Convert-FromJson |
ForEach-Object {
$InputFullTableName = '{0}{1}' -f $TargetDatabase,$_.ObjectName
# In strict mode, you can't reference a property that doesn't exist,
#so check if it has an explicit filename firest.
$outputFileName = $_.ObjectName
if( $_ | Get-Member FileName )
{
$outputFileName = $_.FileName
}
$OutputFullFileName = Join-Path $OutputDirectory $outputFileName
bcp $InputFullTableName out $OutputFullFileName -T -c $ServerOption
}
Je préfère cette variante de la méthode énumérateur avec un pipeline, car vous n'avez pas à vous référer à la table de hachage dans foreach (testé dans PowerShell 5):
$hash = @{
'a' = 3
'b' = 2
'c' = 1
}
$hash.getEnumerator() | foreach {
Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}
Sortie:
Key = c and Value = 1
Key = b and Value = 2
Key = a and Value = 3
Maintenant, ceci n'a pas été délibérément trié sur la valeur, l'énumérateur renvoie simplement les objets dans l'ordre inverse.
Mais puisqu'il s'agit d'un pipeline, je peux maintenant trier les objets reçus de l'énumérateur en fonction de la valeur:
$hash.getEnumerator() | sort-object -Property value -Desc | foreach {
Write-Host ("Key = " + $_.key + " and Value = " + $_.value);
}
Sortie:
Key = a and Value = 3
Key = b and Value = 2
Key = c and Value = 1