0

I am trying to use a powershell script to change the password between two strings, I am running into two issues.

  1. A complex password seems to break my regex, If I use something as simple as "TestPassword" the regex does what I expect. However using a more complex password "6QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI=" it breaks and results in
SSLEnabled="true" keystoreFile="C:\cert.pfx" $16QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI=" keystoreType="PKCS12"/>

instead of

SSLEnabled="true" keystoreFile="C:\cert.pfx" keystorePass="6QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI=" keystoreType="PKCS12"/>
  1. I want to be less specific for the second match grouo, for example at the moment I must specify '" keystoreType' but I would prefer to be less specific and only specify the ending quote. This way if I change the position of the keystoreType parameter in the future I don't have to worry about changing the regex to suit.

Bellow is my powershell as it stands:

#Set new password in server.xml
$pass='6QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI='
$server_xml=".\server.xml"
(Get-Content $server_xml) -replace '(keystorePass=")(.*)(" keystoreType)',('$1{0}$3' -f "$pass") | Set-Content $server_xml

Bellow is an extract from my xml:

<Connector port="443" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;"
                   maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false"
                   maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443"
                   acceptCount="100" disableUploadTimeout="true" bindOnInit="false" secure="true" scheme="https"
                   proxyName="test.example.com" proxyPort="443"
                   SSLEnabled="true" keystoreFile="C:\cert.pfx" keystorePass="123abc" keystoreType="PKCS12"/>
1
  • 2
    You might also consider using an xml parser. Commented Dec 18, 2020 at 12:34

2 Answers 2

1

Parse

As pointed out by @the four bird and @codextor in the comments; peeking and poking directly into a serialized string (e.g. XML) using string methods (like -Replace) is a bad idea. Instead you should use the related parser for searching and replacing which has an easier syntax, takes care of both your issues and other pitfalls (e.g. double quotes $pass='Test"123').

Security

There is even a protentional security risk by ignoring the related parsers as a user (which is assumed only allowed to supply a password) could inject a new property in your xml (connector) by supplying a password like:

$pass = 'MyPass" maxParameterCount="0'

Examples

$Xml = [Xml]'<Connector port="443" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^&#x5c;&#x60;&quot;&lt;&gt;" maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false" maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443" acceptCount="100" disableUploadTimeout="true" bindOnInit="false" secure="true" scheme="https" proxyName="test.example.com" proxyPort="443" SSLEnabled="true" keystoreFile="C:\cert.pfx" keystorePass="123abc" keystoreType="PKCS12"/>'

$Xml.Connector.keystorePass = '6QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI='

$Xml.Connector

port                  : 443
relaxedPathChars      : []|
relaxedQueryChars     : []|{}^\`"<>
maxThreads            : 150
minSpareThreads       : 25
connectionTimeout     : 20000
enableLookups         : false
maxHttpHeaderSize     : 8192
protocol              : HTTP/1.1
useBodyEncodingForURI : true
redirectPort          : 8443
acceptCount           : 100
disableUploadTimeout  : true
bindOnInit            : false
secure                : true
scheme                : https
proxyName             : test.example.com
proxyPort             : 443
SSLEnabled            : true
keystoreFile          : C:\cert.pfx
keystorePass          : 6QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI=
keystoreType          : PKCS12

$Xml.OuterXml

<Connector port="443" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`&quot;&lt;&gt;" maxThreads="150" minSpareThreads="25" connectionTimeout="20000" enableLookups="false" maxHttpHeaderSize="8192" protocol="HTTP/1.1" useBodyEncodingForURI="true" redirectPort="8443" acceptCount="100" disableUploadTimeout="true" bindOnInit="false" secure="true" scheme="https" proxyName="test.example.com" proxyPort="443" SSLEnabled="true" keystoreFile="C:\cert.pfx" keystorePass="6QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI=" keystoreType="PKCS12" />

Addendum

(based on the additional info in the comments)

If there are more connectors in your xml, as e.g.:

$Xml = [Xml]'
    <Connectors>
        <Connector
            port="80"
            keystorePass="Pass1" />
        <Connector
            port="443"
            keystorePass="Pass2" />
    </Connectors>'

You might address the connectors like:

$Xml.Connectors.Connector[0].keystorePass = 'Pass80'
$Xml.Connectors.Connector.Where{ $_.port -eq '443' }.SetAttribute('keystorePass', 'Pass443')

$Xml.OuterXml

<Connectors><Connector port="80" keystorePass="Pass80" /><Connector port="443" keystorePass="Pass443" /></Connectors>
Sign up to request clarification or add additional context in comments.

1 Comment

That does look like a less error prone and cleaner solution. What if for instance there were multiple connectors? Some of which may be commented out and not containing a password field.
1

This person had a similar issue that I was able to use the regex in my code:

Hide passwords in string

I ended up with the following:

#Set new password in server.xml
$pass='6QAfD5PmMhWzUxTq1FO1bGJQQXRXu6tizN29h6MRUSI='
$server_xml=".\server.xml"
(Get-Content $server_xml) -replace '(?:(?<=keystorePass=")\S+(?="))',("$pass") | Set-Content $server_xml

1 Comment

It's great that you were able to find a working solution. But I'd suggest you to consider reading the server.xml file as an XML object in PowerShell, and then traverse it's node tree. That way you won't have to rely on regular expressions, which can reduce possibilities of error in your code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.