Azure Devops release - File Transform - Provided node is empty or a comment - azure-devops

I am trying to transform a .config file from an XML transform file in a release stage. I am using the standard File Transform task. I added a transform.xml file (which isnt linked to a legitimate release) to my artifact and can see it. When i try and use it I get the following System.Debug output:
2020-05-01T17:25:21.6011428Z Processing substitution for xml node : connectionStrings
2020-05-01T17:25:21.6022113Z ##[debug]Provided node is empty or a comment.
2020-05-01T17:25:21.6025339Z ##[debug]Provided node is empty or a comment.
2020-05-01T17:25:21.6027416Z ##[debug]Unable to find node with tag 'configSections' in provided xml file.
2020-05-01T17:25:21.6028615Z Skipped Updating file: xxxxxxxx.config
The contents of the transform.xml file are as below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings xdt:Transform="Replace">
<add name="XX" connectionString="user id=XXX;password=XXXXX;data source=XXXXXXXX"/>
</connectionStrings>
</configuration>

Azure Devops release - File Transform - Provided node is empty or a comment
I could not reproduce this issue with following configuration file and your transform file:
Configuration file web.config (code sample from XML transformation example):
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=(LocalDb)\\MSDB;DbFilename=aspcore-local.mdf;" />
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.web>
<authentication mode="None" />
<compilation targetFramework="4.5" debug="true" />
</system.web>
</configuration>
Then create a Web.test.config with your contents of the transform file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings xdt:Transform="Replace">
<add name="XX" connectionString="user id=XXX;password=XXXXX;data source=XXXXXXXX"/>
</connectionStrings>
</configuration>
Note:
XML transformation will be run on the *.config file for transformation configuration files named *.Release.config or *.<stage>.config. So, we could not use the transform.xml instead of *.<stage>.config.
As the test result, the connectionStrings string in the web.config was replaced:
Please check the document File transforms and variable substitution reference for some more details.
Hope this helps.

Related

XDT Transform not working for applicationHost.xdt on Azure - Environment variables are ignored

It seems like environment variables are being ignored in my xdt transform for applicationHost.
I've created the following file applicationHost.xdt on azure in the \home\site folder. It does NOT perform the transform on applicationHost.config
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">>
<system.applicationHost>
<applicationPools>
<add name="%WEBSITE_SITE_NAME%" xdt:Locator="Match(name)">
<recycling disallowOverlappingRotation="true" xdt:Transform="Insert" />
</add>
<add name="%WEBSITE_IIS_SITE_NAME%" xdt:Locator="Match(name)">
<recycling disallowOverlappingRotation="true" xdt:Transform="Insert" />
</add>
</applicationPools>
</system.applicationHost>
</configuration>
If I adjust the %WEBSITE_SITE_NAME% to say "dev-mysitename.com" the transforms work properly.
Why are the Environment variables not working properly? I need this to work so my different environments will work properly.
You cannot use Environment Variables like this. Its just not possible.

App.Exe Config Transform with Azure Devops and Release Variables

I am currently using Azure Devops with an local build agent to deploy a windows service to an internal server and am looking for information on how to transform my MyApp.Exe.config file using the variables defined in my release task.
With web applications, this seems fairly straightforward. I have a parameters.xml file that is used in conjunction with the SetParameters File in my IIS Web Deploy task. This pulls the variables from the release task and updates the web.config accordingly.
However, I can't find a definitive answer on how to do this with a config file for an executable. This document suggests that it should be possible, but looks like I'd need to provide a transform file with the variables already set.
In summary, what I am looking to do is use a Parameters.xml file to transform the config file of an executable using my release variables. How can this be accomplished?
It's unclear in your question which values you're trying to replace in your target file, so it might be important to note:
". . . Variable substitution takes effect only on the applicationSettings, appSettings, connectionStrings, and configSections elements of configuration files. If you are looking to substitute values outside of these elements you can use a (parameters.xml) file, however you will need to use a 3rd party pipeline task to handle the variable substitution. . . ."
If you can't find a 3rd party task
Of course the Document doesn't point us to any favored 3rd party task. So if you can't find a task that operates directly on the parameters.xml file, then you can use the File Transform task to add/replace values in your .config with tokens, and then use the Replace Tokens task to insert your variable values.
Example:
In my sandbox I can replace the xml values in the specified sections in the quoted text above by simply adding the appropriate variable in my pipeline.
Given this is my config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSection>
<section name="entityFramework" />
</configSection>
<connectionStrings>
<add name="DefaultConnection"
connectionString="Data Source=(LocalDB)\LocalDB;FileName=Local.mdf" />
</connectionStrings>
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobstructiveJavascriptEnabled" value="true" />
<add key="AdminUserName" value="__AdminUserName__" />
<!-- Change AdminPassword in this line: -->
<add key="AdminPassword" value="__AdminPassword__" />
</appSettings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.LocalDbConnectionFactory">
<parameters></parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer" />
</providers>
</entityFramework>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<staticContent>
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<mimeMap fileExtension=".woff" mimeType="application/font-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/font-woff" />
</staticContent>
<security>
<requestFiltering>
<!-- change this value -->
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
And GIVEN these variables in yaml:
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
AdminPassword: 'fake password'
maxAllowedContentLength: '25'
And GIVEN this is the yaml task:
- task: FileTransform#1
inputs:
folderPath: '$(System.DefaultWorkingDirectory)/src'
enableXmlTransform: false
fileType: 'xml'
targetFiles: '*.config'
The result is this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSection>
<section name="entityFramework"/>
</configSection>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDB)\LocalDB;FileName=Local.mdf"/>
</connectionStrings>
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobstructiveJavascriptEnabled" value="true"/>
<add key="AdminUserName" value="__AdminUserName__"/>
<add key="AdminPassword" value="fake password"/>
</appSettings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.LocalDbConnectionFactory">
<parameters/>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer"/>
</providers>
</entityFramework>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824"/>
</requestFiltering>
</security>
</system.webServer>
Notice the un-substituted value!!
As stated in the documentation, the value I wanted to change <requestLimits maxAllowedContentLength="1073741824"/> is unchanged b/c it is not defined by a configSection and is not part of the predefined nodes.
Using the 3rd party to substitute outside the defaults
Take the same config file but change the yaml task to include a transformation to the following transform.config
Given the same config file
transform.config
<?xml version="1.0" encoding="utf-8"?>
<!-- For more information on using web.config transformation visit https://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<security>
<requestFiltering>
<!-- change this value -->
<requestLimits maxAllowedContentLength="${maxAllowedContentLength}$" xdt:Transform="Replace" />
</requestFiltering>
</security>
</system.webServer>
</configuration>
New task settings
- task: FileTransform#1
inputs:
folderPath: '$(System.DefaultWorkingDirectory)/src'
enableXmlTransform: true
xmlTransformationRules: '-transform transform.config -xml app.config'
fileType: 'xml'
targetFiles: '*.config'
- task: replacetokens#3
inputs:
rootDirectory: '$(build.sourcesdirectory)/src'
targetFiles: 'app.config'
encoding: 'auto'
writeBOM: false
actionOnMissing: 'warn'
keepToken: false
tokenPrefix: '${'
tokenSuffix: '}$'
And the results are:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSection>
<section name="entityFramework"/>
</configSection>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDB)\LocalDB;FileName=Local.mdf"/>
</connectionStrings>
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobstructiveJavascriptEnabled" value="true"/>
<add key="AdminUserName" value="__AdminUserName__"/>
<add key="AdminPassword" value="fake password"/>
</appSettings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.LocalDbConnectionFactory">
<parameters/>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer"/>
</providers>
</entityFramework>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="25"/>
</requestFiltering>
</security>
</system.webServer>

Comment out appSettings on web.config using PowerShell

I would like to know if someone can perform commenting out this section on appSettings using PowerShell. Sample code below: (just an example, not really my code)
<configuration>
<connectionStrings>
<add name="TestDBEntities" connectionString="metadata=res://*/TestProject.csdl|res://*/TestProject.ssdl|res://*/TestProject.msl;provider=System.Data.SqlClient;provider connection string="data source=SQL01;initial catalog=TestDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
<appSettings>
<add key="SCVMMServerName" value="VMM01" />
<add key="SCVMMServerPort" value="8100" />
</appSettings>
</configuration>
I want to comment out this section:
<add key="SCVMMServerName" value="VMM01" />
resulting like this:
<configuration>
<connectionStrings>
<add name="TestDBEntities" connectionString="metadata=res://*/TestProject.csdl|res://*/TestProject.ssdl|res://*/TestProject.msl;provider=System.Data.SqlClient;provider connection string="data source=SQL01;initial catalog=TestDB;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
<appSettings>
<!--<add key="SCVMMServerName" value="VMM01" />-->
<add key="SCVMMServerPort" value="8100" />
</appSettings>
</configuration>
Hope you guys (especially PowerShell nerds out there) can help me. Thanks a lot!
Try something like this:
$XmlDocument = [xml](Get-Content -Path "U:\test.xml")
$node = $XmlDocument.SelectNodes('//SomeNode') | Where-Object{$_.Key -eq "test2"}
$node.ParentNode.InnerXml = $node.ParentNode.InnerXml.Replace($node.OuterXml, $node.OuterXml.Insert(0, "<!--").Insert($node.OuterXml.Length+4, "-->"))
$XmlDocument.Save("U:\test.xml")
Pretty easy to do in V3 and above.
(Get-Content c:\test.txt).replace('[Add value here]', 'New value') | Set-Content c:\test.txt
Hope that helps!

Modify a .Net Applications .exe.config file Settings Value via Powershell

I have a .Net console application which has an App.Config / MyApplicationConsole.exe.config file. This one contains settings set via the properties manager of VS, basically looking something like this:
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="My.Applications.Namespace.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<My.Applications.Namespace.Properties.Settings>
<setting name="SettingsKeyABC" serializeAs="String">
<value>SomeOtherValue</value>
</setting>
<setting name="SettingsKeyXYZ" serializeAs="String">
<value>True</value>
</setting>
</Siemens.Med.CTE.PMP.Applications.JobExecutor.Properties.Settings>
</applicationSettings>
<system.diagnostics>
<trace>
<listeners>
<add name="Gibraltar" type="Gibraltar.Agent.LogListener, Gibraltar.Agent" />
</listeners>
</trace>
</system.diagnostics>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
</configuration>
Now what I want/need to do is modify the ("True") value for the "SettingsKeyXYZ" setting, preferably via powershell (as my colleague set up). Does anyone know how to do this? All I found were sample for Web.Configs which seem a tad different than the ones created by VS.
First, The xml text is not valid. Where's the closing tag of line 10 tag (My.Applications.Namespace.Properties.Settings). I changed line 10 to match the closing tag.
Load the file (as xml), you must put the 'My.Applications.Namespace.Properties.Settings' tag in quotes otherwise powershell will try to parse each value between the dots as a tag), update the value to False and then save the file.
[xml]$xml = Get-Content c:\App.Config
$xml.configuration.applicationSettings.'My.Applications.Namespace.Properties.Settings'.setting.value='False'
$xml.Save('c:\App.Config')

Using xmlpeek in Nant script gives odd error

As part of a CI process I am trying to create a buildlabel which consists of the content of an xml element within an xml structure. For this purpose I am using nant and xmlpeek. My problem is that I get an odd error stating:
"Nodeindex '0' is out of range"
This is only the case if the xml file I am xmlpeeking contains a namespace definition in the root node.
Removing the namespace from the xml file gives me the output I expect.
The nant target that generates the error can be boild down to:
<target name="TDSLabel">
<property name="element" value=""/>
<echo message="Getting element" />
<xmlpeek file="C:\xxx\test1.xml" xpath="//Project/PropertyGroup/ProductVersion" property="element"/>
<echo message="The found element value was: ${element}" />
</target>
and the test1.xml file looks like this:
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProductVersion>9.0.21022</ProductVersion>
</PropertyGroup>
</Project>
You already gave the right hint yourself. It's about the namespace. This should fix it:
<target name="TDSLabel">
<property name="element" value=""/>
<echo message="Getting element" />
<xmlpeek
file="C:\xxx\test1.xml"
xpath="//x:Project/x:PropertyGroup/x:ProductVersion"
property="element"
verbose="true">
<namespaces>
<namespace prefix="x" uri="http://schemas.microsoft.com/developer/msbuild/2003" />
</namespaces>
</xmlpeek>
<echo message="The found element value was: ${element}" />
</target>
Found a similar problem and the anwser to my problem here: XmlPoke and unique nodes. The problem was that I did not include the namespace definition within the xmlpeek element and afterwards omitted the necessary reference to the namespace in my xpath statement:
<xmlpeek file="C:\xxx\test1.xml" xpath="//x:Project/x:PropertyGroup/x:ProductVersion" property="element">
<namespaces>
<namespace prefix="x" uri="http://schemas.microsoft.com/developer/msbuild/2003" />
</namespaces>
</xmlpeek>