You can just reference the element with dot notation
$tokens.author.email
Then you could do things like this as well if you wanted to check if the name was empty for example. Note that there is a caveat: Author should exist for this to work exactly as intended.)
If(!$tokens.author.name){$tokens.author.name = "Awesome Sauce"; }
Write-Host ("Author Name: {0}" -f $tokens.author.name)
You can also use hashtable notation as suggested by briantist
$tokens['Author']['Email']
Dynamic replacement
You use the word dynamic but I am not sure how far you want to take that. For now lets assume that the $tokens
elements all exist and we are going to replace the text from a here-string.
$text = @"
/*
Author: __Author.Name__ <__Author.Email__>
Analyst: __Analyst.Name__ <__Analyst.Email__>
Request: __Title__ [__Id__]
*/
"@
$text -replace "__Author\.Name__",$tokens.Author.Name -replace "__Author\.Email__",$tokens.Author.Email `
-replace "__Analyst\.Name__",$tokens.Analyst.Name -replace "__Analyst\.Email__",$tokens.Analyst.Email `
-replace "__Title__",$tokens.Title -replace "__Id__",$tokens.Id
But I feel you mean more dynamic since all of this requires knowing information about the $Tokens
and the the source string. Let me know how we stand now. We could get deeper with this.
Lets get freaky
Let say you know that the hashtable $tokens
and the source $text
have values in common but you don't know the names of them. This will dynamically populate text based on the key names on the hashtables. Currently this only works if there is only one hashtable depth.
ForEach($childKey in $tokens.Keys){
If($tokens[$childKey] -is [System.Collections.Hashtable]){
ForEach($grandChildKey in $tokens[$childKey].Keys){
Write-Host "GrandChildKey = $childKey"
$text = $text -replace "__$childKey\.$($grandChildKey)__", $tokens.$childKey.$grandChildKey
}
} Else {
$text = $text -replace "__$($childKey)__", $tokens.$childKey
}
}
$text
Something else
This borrows from mike z suggestion about Invoke-Expression
as it makes less guess work involved.
$output = $text
$placeHolders = $text | Select-String '__([\w.]+)__' -AllMatches | ForEach-Object{$_.matches} | ForEach-Object{$_.Value}
$placeHolders.count
$placeHolders | ForEach-Object {
$output = $output -replace [regex]::Escape($_), (Invoke-Expression "`$tokens.$($_ -replace "_")")
}
$output
Search the $text
for all strings like something. For every match replace that text with its dot notation equivalent.
Output from either samples should match what you have for Should become: