My requirement is, I have a properties file say C:\google\configuration\backup\configuration.properties with content shown below
backup.path = C:\\ProgramData\\google\\backup
backup.volume.guid = \\\\?\\Volume{49e5d325-8065-49f4-bf0d-r4be94cc1feb}\\
backup.max.count = 10
I have a method that takes key and value as input.
function Script:change_or_replace_value([string]$key, [string]$value) {
$origional_file_content = Get-Content $CONF_FILE_LOCATION
$key_value_map = ConvertFrom-StringData($origional_file_content -join [Environment]::NewLine)
$old_value = $key_value_map.$key
$Old_file_pattern = "$key = $old_value"
$new_file_pattern = "$key = $value"
$origional_file_content | ForEach-Object {$_ -Replace $Old_file_pattern, $new_file_pattern} | Set-Content $NEW_FILE_LOCATION
}
backup.path = C:\\ProgramData\\google\\backup
backup.volume.guid = \\\\?\\Volume{111111-222-222-444-r4be94cc1feb}\\
backup.max.count = 10
backup.path = C:\\ProgramData\\google\\backup
backup.max.count = 10
If the value is empty delete the line else replace the text for the given key.
Your current approach has two problems, based on your attempt to update the properties by string manipulation via the file content as a single string:
In the ForEach-Object
script block you'd need a different command to eliminate a line, because the -replace
operator always returns something: if the regex pattern doesn't match the input, the input string is passed through.
You're missing an additional string-replacement step: ConvertFrom-StringData
considers \
an escape character, so any pair of \\
in the input file turns into a single \
in the resulting hashtable. Therefore, you'll also have to double the \\
in $oldvalue
and $value
in order for the string replacement on the original file content to work.
Also, -replace
, because it expects regex (regular expression) as the search operand, requires metacharachters such as \
to be escaped by \
-escaping them; you could do that with [regex]::Escape($Old_file_pattern)
.
I suggest a different approach that avoids these problems, namely:
Directly modify the hashtable that ConvertFrom-StringData
returns.
Then serialize the updated hashtable to the output file, using string formatting.
\
in the values again by using the [string]
type's .Replace()
method, which operates on literal strings and is simpler (and faster) in this case; however, you could also use the somewhat counter-intuitive -replace '\\', '\\'
# Assign your real path here.
$OCUM_CONF_FILE_LOCATION = 'in.properties'
# Only for demonstration here: create a sample input file.
@'
backup.path = C:\\ProgramData\\google\\backup
backup.volume.guid = \\\\?\\Volume{49e5d325-8065-49f4-bf0d-r4be94cc1feb}\\
backup.max.count = 10
'@ > $OCUM_CONF_FILE_LOCATION
# Function which either updates, adds, or removes an entry.
# NOTE:
# * This function updates input file $OCUM_CONF_FILE_LOCATION *in place*.
# To be safe, be sure to have a backup copy before you try this.
# * Set-Content's default character encoding is used to save the updated file.
# Use the -Encoding parameter as needed.
function Update-PropertiesFile ([string]$key, [string]$value) {
$ht = ConvertFrom-StringData (Get-Content -Raw $OCUM_CONF_FILE_LOCATION)
if ($ht.Contains($key)) { # update or delete existing entry
if ('' -eq $value) { $ht.Remove($key) }
else { $ht[$key] = $value }
} elseif ('' -eq $value) { # entry to remove not found
Write-Warning "No entry with key '$key' found; nothing to remove."
return
} else { # new entry
$ht[$key] = $value
}
# Serialize the updated hashtable back to the input file.
Set-Content $OCUM_CONF_FILE_LOCATION -Value $(
foreach ($key in $ht.Keys) {
'{0} = {1}' -f $key, $ht[$key].Replace('\', '\\')
}
)
}