Redact powershell output

Rich Rumble
Rich Rumble used Ask the Experts™
on
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
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Top Expert 2014

Commented:
@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.
Top Expert 2014

Commented:
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

Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

Top Expert 2014

Commented:
I think he just needs the values altered, not the names
Top Expert 2014

Commented:
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 Samurai
Top Expert 2006

Author

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
Top Expert 2014

Commented:
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.
Top Expert 2014
Commented:
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

Rich RumbleSecurity Samurai
Top Expert 2006

Author

Commented:
Awesome work, thanks!
Top Expert 2014

Commented:
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.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial