3

Problem

I am working on a script that has a user provide a specific IP address and I want to mask this IP in some fashion so that it isn't stored in the logs. My problem is, that I can easily do this when I know what the first three values of the IP typically are; however, I want to avoid storing/hard coding those values into the code to if at all possible. I also want to be able to replace the values even if the first three are unknown to me.

Examples:

10.11.12.50 would display as XX.XX.XX.50
10.12.11.23 would also display as XX.XX.XX.23

I have looked up partial string replacements, but none of the questions or problems that I found came close to doing this. I have tried doing things like:

# This ended up replacing all of the numbers
$tempString = $str -replace '[0-9]', 'X'

I know that I am partway there, but I aiming to only replace only the first 3 sets of digits so, basically every digit that is before a '.', but I haven't been able to achieve this.

Question

Is what I'm trying to do possible to achieve with PowerShell? Is there a best practice way of achieving this?

2
  • Use a regular expression replacement pattern Commented Sep 5, 2017 at 13:33
  • Related post - Replace substring in PowerShell Commented Apr 11, 2018 at 9:46

2 Answers 2

3

Here's an example of how you can accomplish this:

Get-Content 'File.txt' |
  ForEach-Object { $_ = $_ -replace '\d{1,3}\.\d{1,3}\.\d{1,3}','xx.xx.xx' }

This example matches a digit 1-3 times, a literal period, and continues that pattern so it'll capture anything from 0-999.0-999.0-999 and replace with xx.xx.xx

Sign up to request clarification or add additional context in comments.

5 Comments

PERFECT!! Thank you. That gave me the control I desired. I tried to choose this as the answer, but it told me that it was too soon to pick an answer
++, but I assume you didn't mean to put the $_ = there (assigning to $_ should generally be avoided, and in this case it would also prevent output).
@mklement0 It's intentional and fine to do if you're going to re-use $_ in the current scriptblock. I don't know his use-case, but it looks like he just wants to obfuscate it in his console output, so my example is partially applicable in his exact use-case.
@TheIncorrigible1: Understood, but note that changes are coming that will produce an editor warning when you assign to $_ (making $_ read-only in the engine was ultimately rejected to avoid break existing code).
@mklement0 very interesting read. Good decision overall, kind of bites for legacy code.
2

TheIncorrigible1's helpful answer is an exact way of solving the problem (replacement only happens if 3 consecutive .-separated groups of 1-3 digits are matched.)

A looser, but shorter solution that replaces everything but the last .-prefixed digit group:

PS> '10.11.12.50' -replace '.+(?=\.\d+$)', 'XX.XX.XX'
XX.XX.XX.50

(?=\.\d+$) is a (positive) lookahead assertion ((?=...)) that matches the enclosed subexpression (a literal . followed by 1 or more digits (\d) at the end of the string ($)), but doesn't capture it as part of the overall match.

The net effect is that only what .+ captured - everything before the lookahead assertion's match - is replaced with 'XX.XX.XX'.

Applied to the above example input string, 10.11.12.50:

  • (?=\.\d+$) matches the .-prefixed digit group at the end, .50.

  • .+ matches everything before .50, which is 10.11.12.

  • Since the (?=...) part isn't captured, it is therefore not included in what is replaced, so it is only substring 10.11.12 that is replaced, namely with XX.XX.XX, yielding XX.XX.XX.50 as a result.

1 Comment

@Brandon: Correct; I've updated the answer again to explain it with a concrete example.

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.