jwhit265
jwhit265

Reputation: 31

Powershell regex for replacing text between two strings

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"/>

Upvotes: 0

Views: 264

Answers (2)

iRon
iRon

Reputation: 23862

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>

Upvotes: 1

jwhit265
jwhit265

Reputation: 31

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

Upvotes: 1

Related Questions