Update configuration files using PowerShell


 

Hi Readers,

We will see in this post on how we can edit web.config or other configuration files using PowerShell. There are already several posts available on internet which shows this functionality, however I faced difficulties in updating connection string in the configuration file as they are not direct. Below steps will help you in updating the connection strings as well.

Sample configuration file is shown below. Other sections of web.config file are not shown in this blog for simplicity.

   1: <configuration>
   2:   <connectionStrings>
   3:     <add name="TestDBEntities" connectionString="metadata=res://*/TestProject.csdl|res://*/TestProject.ssdl|res://*/TestProject.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=SQL01;initial catalog=TestDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
   4:   </connectionStrings>
   5:   <appSettings>
   6:     <add key="SCVMMServerName" value="VMM01" />
   7:     <add key="SCVMMServerPort" value="8100" />
   8:   </appSettings>
   9: </configuration>

We will try to update ‘appSettings’ section and connectionStrings section of this configuration file.

1. Read configuration file in a XML variable

   1: $webConfig = 'C:\inetpub\wwwroot\VMMService\Web.config'
   2: $doc = (Get-Content $webConfig) -as [Xml]

2. Update ‘appSettings’ Section

   1: $obj = $doc.configuration.appSettings.add | where {$_.Key -eq 'SCVMMServerName'}
   2: $obj.value = 'CPVMM02'

3. Update ‘connectionStrings’ section. Here is the tweak, you have to read the root element and then modify the connection string as shown below:-

   1: $root = $doc.get_DocumentElement();
   2: $newCon = $root.connectionStrings.add.connectionString.Replace('data source=SQL01','data source=SQL02');
   3: $root.connectionStrings.add.connectionString = $newCon

4. Save the configuration file

   1: $doc.Save($webConfig)

The combined code will look like below:-

   1: $webConfig = 'C:\inetpub\wwwroot\TestService\Web.config'
   2: $doc = (Get-Content $webConfig) -as [Xml]
   3: $obj = $doc.configuration.appSettings.add | where {$_.Key -eq 'SCVMMServerName'}
   4: $obj.value = 'CPVMM02'
   5:  
   6: $root = $doc.get_DocumentElement();
   7: $newCon = $root.connectionStrings.add.connectionString.Replace('data source=SQL01','data source=SQL02');
   8: $root.connectionStrings.add.connectionString = $newCon
   9:  
  10: $doc.Save($webConfig)

The updated XML will contain modified values as shown below:-

   1: <configuration>
   2:   <connectionStrings>
   3:     <add name="TestDBEntities" connectionString="metadata=res://*/TestProject.csdl|res://*/TestProject.ssdl|res://*/TestProject.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=SQL02;initial catalog=TestDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
   4:   </connectionStrings>
   5:   <appSettings>
   6:     <add key="SCVMMServerName" value="VMM02" />
   7:     <add key="SCVMMServerPort" value="8100" />
   8:   </appSettings>
   9: </configuration>

Let me know if there are some sections of configuration file which you are finding difficult to update and I will add them here in this blog 🙂 Happy Scripting!!!


Comments (28)

  1. Santosh@CA says:

    Hi Sonam,

    Many thanks for this article. I was really facing this challenge for automating the Web.config Transformation process. Your article really helped me to to tackle that challenge. Awesome..Keep on writing such nice articles.

  2. Sam says:

    I need to edit the below xml file, but could not able to do so… I need to edit only the newVersion value where then name is B… how can i achieve this..

    <?xml version="1.0"?>

    <configuration>

    <runtime>

    <legacyCorruptedStateExceptionsPolicy enabled="true" />

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

    <dependentAssembly>

    <assemblyIdentity name="A"

     publicKeyToken="585a888b4a9ba2e3"

     culture="neutral" />

    <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534"

    newVersion="4.0.0.103"/>

    </dependentAssembly>

    <dependentAssembly>

    <assemblyIdentity name="B"

     publicKeyToken="22955931b98512b6"

     culture="neutral" />

    <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534"

    newVersion="4.0.0.103"/>

    </dependentAssembly>

    <dependentAssembly>

    <assemblyIdentity name="C"

     publicKeyToken="4ab506411d17b07e"

     culture="neutral" />

    <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534"

    newVersion="4.0.0.103"/>

    </dependentAssembly>

    </assemblyBinding>

    </runtime>

    </configuration>

  3. Sonam Rastogi says:

    Hi,

    For XML files, please refer this blog :- blogs.msdn.com/…/update-xml-file-using-powershell.aspx

  4. Same says:

    Thank you Sonam for your reply. I need to change newVersion to the number value in whole document wherever newVersion is occuring. Please help. I have gone through your other blog for XML files, but couldnt not succeed.

  5. Sonam Rastogi says:

    Hope this will help. thanks.

    $path = 'C:Users<UserName>DesktopVariable.xml'

    $xml = [xml](Get-Content $path)

    $NewVersionUpdatedValue = 'MyNewVersion'

    $daNodes = $xml.configuration.runtime.assemblyBinding.dependentAssembly

    foreach($node in $daNodes)

    {

       if($node.assemblyIdentity.name -eq 'B')

       {

           $updateNode = $node.bindingRedirect

           $updateNode.newVersion = $NewVersionUpdatedValue

       }

    }

    $xml.Save($path)

  6. Sonam Rastogi says:

    I have also updated the post to consider this scenario. Thanks.

    blogs.msdn.com/…/update-xml-file-using-powershell.aspx

  7. Sam says:

    Many thanks Sonam. For some reason, I am getting this below error when I tried your method. I have changed the script like this…

    $path = 'C:Users<UserName>DesktopVariable.xml'

    $xml = [xml](Get-Content $path)

    $NewVersionUpdatedValue = 'MyNewVersion'

    $NewVersionUpdatedValue2 = 'MyNewVersion2'

    $daNodes = $xml.configuration.runtime.assemblyBinding.dependentAssembly

    foreach($node in $daNodes)

    {

      if($node.assemblyIdentity.name -eq 'A' -or $node.assemblyIdentity.name -eq 'B' -or

      {

          $updateNode = $node.bindingRedirect

          $updateNode.newVersion = $NewVersionUpdatedValue

      }

      if($node.assemblyIdentity.name -eq 'C' -or $node.assemblyIdentity.name -eq 'D' -or

      {

          $updateNode = $node.bindingRedirect

          $updateNode.newVersion = $NewVersionUpdatedValue2

      }

    }

    $xml.Save($path)

    =============================

    Error in powershell:

    Cannot convert value "System.Object[]" to type "System.Xml.XmlDocument". Error: "Name cannot begin with the '<'

    character, hexadecimal value 0x3C. Line 725, position 8."

    At C:UsersakolaDesktoptest2.ps1:2 char:1

    + $xml = [xml](Get-Content $path)

    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

       + CategoryInfo          : InvalidArgument: (:) [], RuntimeException

       + FullyQualifiedErrorId : InvalidCastToXmlDocument

    You cannot call a method on a null-valued expression.

    At C:UsersakolaDesktoptest2.ps1:13 char:1

    + $xml.Save($path)

    + ~~~~~~~~~~~~~~~~

       + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    ================================

  8. Sam says:

    by the way… its a config file but xml file

  9. Sam says:

    I am so sorry…i am so messed up with this frustration today…  correction… its a config file but not the xml file…

  10. Sonam Rastogi says:

    Hi,

    Given below config file saved as 'MyConfig.config'

    <?xml version="1.0"?>

    <configuration>

     <runtime>

       <legacyCorruptedStateExceptionsPolicy enabled="true" />

       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

         <dependentAssembly>

           <assemblyIdentity name="A" publicKeyToken="585a888b4a9ba2e3" culture="neutral" />

           <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534" newVersion="4.0.0.0" />

         </dependentAssembly>

         <dependentAssembly>

           <assemblyIdentity name="B" publicKeyToken="22955931b98512b6" culture="neutral" />

           <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534" newVersion="4.0.0.0" />

         </dependentAssembly>

         <dependentAssembly>

           <assemblyIdentity name="C" publicKeyToken="4ab506411d17b07e" culture="neutral" />

           <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534" newVersion="4.0.0.0" />

         </dependentAssembly>

       </assemblyBinding>

     </runtime>

    </configuration>

    This PowerShell code works absolutely fine.

    $path = 'C:MyConfig.config'

    $xml = [xml](Get-Content $path)

    $NewVersionUpdatedValue = 'MyNewVersion'

    $NewVersionUpdatedValue2 = 'MyNewVersion2'

    $daNodes = $xml.configuration.runtime.assemblyBinding.dependentAssembly

    foreach($node in $daNodes)

    {

      if($node.assemblyIdentity.name -eq 'A' -or $node.assemblyIdentity.name -eq 'B')

      {

          $updateNode = $node.bindingRedirect

          $updateNode.newVersion = $NewVersionUpdatedValue

      }

      elseif($node.assemblyIdentity.name -eq 'C' -or $node.assemblyIdentity.name -eq 'D')

      {

          $updateNode = $node.bindingRedirect

          $updateNode.newVersion = $NewVersionUpdatedValue2

          break

      }

    }

    $xml.Save($path)

    The final Config will look like below:-

    <?xml version="1.0"?>

    <configuration>

     <runtime>

       <legacyCorruptedStateExceptionsPolicy enabled="true" />

       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

         <dependentAssembly>

           <assemblyIdentity name="A" publicKeyToken="585a888b4a9ba2e3" culture="neutral" />

           <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534" newVersion="MyNewVersion" />

         </dependentAssembly>

         <dependentAssembly>

           <assemblyIdentity name="B" publicKeyToken="22955931b98512b6" culture="neutral" />

           <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534" newVersion="MyNewVersion" />

         </dependentAssembly>

         <dependentAssembly>

           <assemblyIdentity name="C" publicKeyToken="4ab506411d17b07e" culture="neutral" />

           <bindingRedirect oldVersion="0.0.0.0-65534.65534.65534.65534" newVersion="MyNewVersion2" />

         </dependentAssembly>

       </assemblyBinding>

     </runtime>

    </configuration>

  11. Sam says:

    Thanks a bunch !!….  It works perfectly fine without any issues… Thanks again !!

    1. I am glad it helped.

  12. Jonas says:

    Hi!

    Thank you for the great guide, however, I cannot seem to apply it to my problem.

    I want to add a DbProvider under DbProviderFactories in System.data. How can do I proceed?

  13. Sonam Rastogi says:

    Please Share the sample input and output config file.

  14. Anonymous says:

    Nice Article..

  15. r.ranjan says:

    Great Article. Helped a lot.

  16. Bernd says:

    How do you update the "data source" when you do not know its value? That would be worth a post!

  17. When you update – there is always an old value and a new value. You will always be aware of the new value to be updated. The value can be direct or can be read through some file or database.

  18. AKSHAY says:

    Hi sonam, Thanks for the post. It helped alot. I have a query as i am automating the whole deployment process , i dont want use hard coded path in the script. Is there any way to to assign the values to new variable using the priviously declared variables. EG. $servicepath has the path where the service is installed. I want assign the same path to a new variable to edit the config.

  19. Hi Akshay,

    You can do $webConfig = $servicePath in your script.

  20. Akshay says:

    Hey Sonam,

    already tried that. Actually it was the Scope of the variable that was creating trouble. Resolved it for now,the other thing that is troubling me now is i need to run the .bat file which installs the service. My code for it is:

    $command = {

    cd "$using:installpath$using:servicename"

    ./Installer.bat

    }

    Invoke-Command -Session $mysession1 -ScriptBlock $command

    "<b>The error I get is: The term './Installer.bat' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was

    included, verify that the path is correct and try again."</b>

    can you help on how to run a .bat file?

    Thanks (in advance)

  21. Please try Start-Process cmdlet

  22. sandhya says:

    Thanks a lot for this article. I have to edit my below connection string in an automated process.

    I had followed your article and edited the powershell script like this:
    1: $webConfig = ‘C:\inetpub\wwwroot\TestService\Web.config’
    2: $doc = (Get-Content $webConfig) -as [Xml]
    5:
    6: $root = $doc.get_DocumentElement();
    7: $newCon = $root.connectionStrings.add.connectionString.Replace(‘data source=10.0.1.4′,’data source=accdbsrv24.database.windows.net,1433′,’initial catalog=AdventureWorks’,’initial catalog=accdb24′,’Uid=sa’,Uid=’sandhya’,’Password=demo@pass1′,’Password=mama@12345′);
    8: $root.connectionStrings.add.connectionString = $newCon
    10: $doc.Save($webConfig)

    Please guide me, is it correct or wrong?

    1. replied in another message below.

  23. sandhya says:

    Thanks a lot for this article. I have to edit my below connection string in an automated process.

    I had followed your article and edited the powershell script like this:
    1: $webConfig = ‘C:\inetpub\wwwroot\cloudshop\Web.config’
    2: $doc = (Get-Content $webConfig) -as [Xml]
    5:
    6: $root = $doc.get_DocumentElement();
    7: $newCon = $root.connectionStrings.add.connectionString.Replace(‘data source=10.0.1.4′,’data source=accdbsrv24.database.windows.net,1433′,’initial catalog=AdventureWorks’,’initial catalog=accdb24′,’Uid=sa’,Uid=’sandhya’,’Password=demo@pass1′,’Password=mama@12345′);
    8: $root.connectionStrings.add.connectionString = $newCon
    10: $doc.Save($webConfig)

    Please guide me, is it correct or wrong?

    1. Hi Sandhya,

      The syntax that you have used is wrong in replace method.
      It should be .Replace(‘old value’,’new value’)

      Below should work for you :-
      $newCon = $root.connectionStrings.add.connectionString.Replace(‘data source=SQL01;initial catalog=TestDB;integrated security=True′,’data source=accdbsrv24.database.windows.net,1433,initial catalog=AdventureWorks,initial catalog=accdb24,Uid=sa,Uid=sandhya,Password=demo@pass1′);

      1. Iyyappan says:

        Hi,

        This logic worked for me, but I am facing an issue like when I am saving the XML with $doc.save(“File path”), It is changing the &qout; into double qoutes (“), How to prevent it?.

        1. Please provide sample code and file.