Let's say I have an object like this:
$test = @{
ThisIsTheFirstColumn = "ValueInFirstColumn";
ThisIsTheSecondColumn = "ValueInSecondColumn"
}
and I want to end up with:
$test = @{
THIS_IS_THE_FIRST_COLUMN = "ValueInFirstColumn";
THIS_IS_THE_SECOND_COLUMN = "ValueInSecondColumn"
}
without manually coding the new column names.
This shows me the values I want:
$test.PsObject.Properties | where-object { $_.Name -eq "Keys" } | select -expand value | foreach{ ($_.substring(0,1).toupper() + $_.substring(1) -creplace '[^\p{Ll}\s]', '_$&').Trim("_").ToUpper()} | Out-Host
which results in:
THIS_IS_THE_FIRST_COLUMN
THIS_IS_THE_SECOND_COLUMN
but now I can't seem to figure out how to assign these new values back to the object.
You can modify hashtable $test
in place as follows:
foreach($key in @($test.Keys)) { # !! @(...) is required - see below.
$value = $test[$key] # save value
$test.Remove($key) # remove old entry
# Recreate the entry with the transformed name.
$test[($key -creplace '(?<!^)\p{Lu}', '_$&').ToUpper()] = $value
}
@($test.Keys)
creates an array from the existing hashtable keys; @(...)
ensures that the key collection is copied to a static array, because using the .Keys
property directly in a loop that modifies the same hashtable would break.
The loop body saves the value for the input key at hand and then removes the entry under its old name.[1]
The entry is then recreated under its new key name using the desired name transformation:
$key -creplace '(?<!^)\p{Lu}
matches every uppercase letter (\p{Lu}
) in a given key, except at the start of the string ((?<!^)
), and replaces it with _
followed by that letter (_$&
); converting the result to uppercase (.ToUpper()
) yields the desired name.
[1] Removing the old entry before adding the renamed one avoids problems with single-word names such as Simplest
, whose transformed name, SIMPLEST
, is considered the same name due to the case-insensitivity of hasthables in PowerShell. Thus, assigning a value to entry SIMPLEST
while entry Simplest
still exists actually targets the existing entry, and the subsequent $test.Remove($key)
would then simply remove that entry, without having added a new one.
Tip of the hat to JosefZ for pointing out the problem.