function Set-AppSetting { <# .SYNOPSIS Sets an appSetting Key/Value pair in the specified file. Filepath defaults to the 64 bit machine config. .DESCRIPTION Set an appSetting key/value pair in the specified config file. Will default to the global 64 bit machine.config file if no config file value specified. Will not tickle files where no values have changed. Can connect to remote computers as well. .PARAMETER key [string] The appSetting key .PARAMETER value [string] The appSetting value to set, if it's different than the existing file .PARAMETER filePath [string] The location to change settings in. Defaults to the global 64bit machine.config file. .PARAMETER ComputerName [string] The computer to connect to. Defaults to localhost .PARAMETER Force [switch] Allow forcing the write of the process. This is due to the option for ShouldProcess. .PARAMETER UpdateOnly [switch] Only updates a key's value if it exists. Will not create the missing AppSetting key. #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact='None')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess", "", Justification = "Internal function uses the SupportsShouldProcess flag, not us, this is good and proper")] param ( [Parameter(Mandatory = $true)] [string]$key, [Parameter(Mandatory = $true)] [AllowEmptyString()] [string]$value, [Parameter(Mandatory = $false)] [Alias("Path")] [string]$FilePath = (Get-DotNetConfigPath -use64Bit $true), [Parameter(Mandatory = $false)] [string]$ComputerName = "localhost", [Parameter(Mandatory = $false)] [switch]$Force, [Parameter(Mandatory = $false)] [switch]$UpdateOnly ) $logLead = (Get-LogLeadName) #region guard clauses # If a computername was provided, modify the filepath to be a UNC path. if((![string]::IsNullOrWhiteSpace($ComputerName)) -and ($ComputerName -ne "localhost")) { $FilePath = (Get-UncPath -filePath $FilePath -ComputerName $ComputerName) } if (!(Test-Path -PathType Leaf -Path $FilePath)) { Write-Warning "$logLead : Could not find a file at [$FilePath]. Execution cannot continue." return ## exit early } Write-Verbose "$logLead : Reading Config file at [$FilePath]"; $isLikelyXml = $false $isLikelyJson = $false $fileContent = Get-Content -Path $FilePath -Raw $firstCharacter = $fileContent[0] if ($firstCharacter -eq '<') { $isLikelyXml = $true } if (($firstCharacter -eq '{') -or ($firstCharacter -eq '[')) { $isLikelyJson = $true } #endregion guard clauses if ($isLikelyXml) { $xml = [xml]$fileContent if(!$xml) { throw "$logLead : Config at [$FilePath] expected to be xml but could not be parsed as xml." } Write-Verbose "$logLead : Ensuring configuration root node exists..."; if(!$xml.configuration){ throw "$logLead : How does $FilePath not have a root element??" } Invoke-CommandWithRetry -MaxRetries 3 -SecondsDelay 1 -Arguments @($key, $value, $filePath, $Force, $UpdateOnly) -ScriptBlock { param($key, $value, $filePath, $Force, $UpdateOnly) Set-AppSettingPrivateXml -key $key -value $value -FilePath $filePath -Force:$Force -UpdateOnly:$UpdateOnly } return } if ($isLikelyJson) { try { # See if we can parse this as a json object (ConvertFrom-Json -InputObject $fileContent) | Out-Null } catch { Write-Host "$logLead : $($_.Exception.Message)" throw "$logLead : Config at [$FilePath] expected to be json but could not be parsed as json." } Invoke-CommandWithRetry -MaxRetries 3 -SecondsDelay 1 -Arguments @($key, $value, $filePath, $Force, $UpdateOnly) -ScriptBlock { param($key, $value, $filePath, $Force, $UpdateOnly) Set-AppSettingPrivateJson -Key $key -value $value -FilePath $filePath -Force:$Force -UpdateOnly:$UpdateOnly } return } throw "$logLead : Could not process file [$FilePath] as presented. Does not appear to be a valid file type" }