Redact powershell output

I'd like to change every 3-4, 7-8, 11-12, 15-16... character in a line of output into two X's.
abcdefghijklmnopqrstuvwxyz  -->abXXefXXijXXmnXXqrXXuvXXyz
Get-CimInstance Win32_OperatingSystem |FL
SystemDirectory : C:\windows\system32
Organization    : Example.com
BuildNumber     : 7601
RegisteredUser  : Example User
SerialNumber    : 00392-918-5000002-888888
Version         : 6.1.7601
Becomes:

Get-CimInstance Win32_OperatingSystem |FL

SystemDirectory : C:XXinXXwsXXysXXm3X
Organization    : ExXXplXXcoXX
BuildNumber     : 76XX
RegisteredUser  : ExXXplXXUsXX
SerialNumber    : 00XX2-XX8-XX00XX2-XX88XX
Version         : 6.XX76XX
It seems simple, but the solution is eluding me.
-rich
LVL 38
Rich RumbleSecurity SamuraiAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

footechCommented:
@Gaurav - I think you misread the question.

@richrumble - Doesn't seem simple to me.  :)
I think it would actually be easier if it was just pure text that was being output, but from your example you're looking to redact just the values of properties of any returned objects.  To do this, you would have to create new calculated properties (redacted) from all of the existing properties, and you'd really only be able to do this if the property value was a string.
footechCommented:
Here's an example of redacting a string (not polished).
function redact
{
[cmdletbinding()]
Param (
    [Parameter(ValueFromPipeline = $true)]
    [string[]]$s
)

End {
    $s = $s -split "`r?`n"
    foreach ( $a in $s )
    {
        if ( $a )
        {
            0..($a.length-1) | ForEach -Begin `
            {
                $change = $false
            } -Process `
            {
                if ($_ % 2 -eq 0 -and $_ -ne 0)
                {
                    $change = -not $change
                }
                if ( $change -and $a.Substring($_,1) -ne " " -and $a.Substring($_,1) -notmatch "\r|\n")
                {
                    $a = $a.Remove($_,1).Insert($_,"X")
                }
            } -End `
            {
                "$a"
            }
        }
    }
}
}

Open in new window


Example output:
PS C:\temp>  redact (Get-CimInstance win32_operatingsystem | fl | Out-String)
SyXXemXXreXXorX : XX\WXXdoXX\sXXteXX2
OrXXniXXtiXX    : 
BuXXdNXXbeX     : XX01
ReXXstXXedXXer  : XXtrXXufXXn
SeXXalXXmbXX    : XX42XXOEXX91XX40XX84XX8
VeXXioX         : XX1.XX01

PS C:\temp>  Get-CimInstance win32_operatingsystem | fl | Out-String | redact
SyXXemXXreXXorX : XX\WXXdoXX\sXXteXX2
OrXXniXXtiXX    : 
BuXXdNXXbeX     : XX01
ReXXstXXedXXer  : XXtrXXufXXn
SeXXalXXmbXX    : XX42XXOEXX91XX40XX84XX8
VeXXioX         : XX1.XX01

Open in new window

OWASP: Forgery and Phishing

Learn the techniques to avoid forgery and phishing attacks and the types of attacks an application or network may face.

aikimarkCommented:
I think he just needs the values altered, not the names
footechCommented:
I agree, but doing that is even more difficult as I described above.  I didn't have time to do everything, and wanted to get the function posted, which at least could be used to redact string values (in other words, it's a piece of the puzzle).  If I get time later, I'll see about pushing on.
Rich RumbleSecurity SamuraiAuthor Commented:
Yes, I'd prefer the string side of the output, should the "redact" start on the right-side of the colon perhaps? I've been looking for $_.something() to apply the function to the right side of data. I know you can do math on Bytes when looking at HDD space, but I guess you have to specify the free/used/total items themselves. https://technet.microsoft.com/en-us/library/ee692684.aspx
Something in this has to be useful
https://blogs.technet.microsoft.com/heyscriptingguy/2011/09/21/two-simple-powershell-methods-to-remove-the-last-letter-of-a-string/
-rich
footechCommented:
Starting on the right side of the colon would only apply when you're displaying things in list format.  Keep in mind that PowerShell is all about objects (and their properties), not just outputting text.
footechCommented:
This works pretty well.
function Redact-String
{
[cmdletbinding()]
Param (
    [Parameter(ValueFromPipeline = $true)]
    [string[]]$s
)

End {
    $s = $s -split "\r?\n"
    foreach ( $line in $s )
    {
        if ( $line )
        {
            0..($line.length-1) | ForEach -Begin `
            {
                $change = $false
            } -Process `
            {
                if ($_ % 2 -eq 0 -and $_ -ne 0)
                {
                    $change = -not $change
                }
                if ( $change -and $line.Substring($_,1) -ne " " -and $line.Substring($_,1) -notmatch "\r|\n")
                {
                    $line = $line.Remove($_,1).Insert($_,"X")
                }
            } -End `
            {
                "$line"
            }
        }
    }
}
}

function Redact-Properties
{
[cmdletbinding()]
Param (
    [Parameter(ValueFromPipeline = $true)]
    $obj
)

Begin {
    $Select = @()
}
Process {
    # Get a listing of all property names
    $Props = $obj | Get-Member -MemberType *Property* | Select -ExpandProperty Name
    
    # Dynamically generate all the calculated properties
    for ($i=0; $i -lt $Props.Count; $i++)
    {
        $propHash = Invoke-Expression "@{n='$($Props[$i])';e={ `$_.'$($Props[$i])' | Redact-String }}"
        $Select += $propHash
    }
    $obj | Select $Select
}
}

Open in new window


Usage (after running code above to create the functions):
gwmi win32_operatingsystem | Redact-Properties

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Rich RumbleSecurity SamuraiAuthor Commented:
Awesome work, thanks!
footechCommented:
You're welcome.

One improvement - remove the Begin block from the Redact-Properties function, and add $Select = @() (line 46 above) into the beginning of the Process block.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.