Handle Hitch Knot for Pulling Thin Rope

If you’ve ever tried to pull hard on thin rope (maybe to tighten slack in a line), you’ve probably wrapped the rope around your hand and felt it dig in as it constricted around your fingers.

Here’s a knot that solves the problem – I call it the Handle Hitch. I couldn’t find it anywhere else – if you’ve heard of it and it has a name, I’d love to know.

With slippery rope (i.e.: paracord), it isn’t suitable for massive loads due to its similarity to the sheepshank. However, it unquestionably improves your ability to grip a line.

Wrap the cord around your hand

The first step is to wrap the cord around your hand. I find it useful to wrap from the outside in.

image

image

 

Create a bight in the exiting rope

And tuck it between your fingers and the series of strands on the back of your hand.

image

image

 

Pull the bight forward

image

 

Create a loop in the standing end

Create this loop in a similar way that you create the loop in a sheepshank. The bight we previously created is on the right, the sheepshank loop is on the left.

image

 

Pass the bight through the sheepshank loop

As you do with the bight in either end of a sheepshank.

image

 

Tighten the sheepshank loop

image

 

Let go of the standing end, and pull

image

 

Once the rope is under tension, it can accommodate medium loads. With paracord, I found the bight would slip out of the sheepshank loop with about 100lbs of pulling force – a similar failure mode to the sheepshank, but far greater than what is comfortable to pull by just wrapping the rope around your hand.

For loads greater than that, you really would want something more secure – for example, using a strong stick or your pocket knife in a Marlinspike hitch.

Here’s a video of tying this knot:

Gregg Shorthand from a regular QWERTY Computer Keyboard

 

Download – Gregg Shorthand Keyboard:

ShorthandKeyboard.exe, 720kb.
ShorthandKeyboard.ahk (AutoHotkey script source, 19kb)

 

 

If you’ve got an interest in languages, writing, and computers – you may have stumbled into the crazy world of Shorthand and stenography. Pitman, Gregg, Teeline, and others.

File:Gregg shorthand A Christmas Carol.jpg

(Image courtesy of Wikipedia)

Pitman shorthand isn’t very practical in modern society because it relies heavily on thick vs. thin lines. Today’s writing instruments offer very little variation in that regard – because the days of the flexible fountain pen have tragically long since passed. (Of course, you could argue that shorthand in general isn’t practical in modern society, but then you wouldn’t be reading this post.)

Gregg shorthand is entirely possible in today’s world of boring pens and pencils. The speed of Gregg Shorthand comes primarily from:

  1. Alternative letter forms that are faster and easier to write than our traditional alphabet.
  2. A list of “brief forms” (abbreviations) for common words. For example, “men.” instead of “morning”.

For the first step, learning the letter forms is quite easy and takes very little practice. For the second step, most of the refinement in Gregg Shorthand over time has primarily been tweaking the brief forms: how many, and what they are. Learning the brief forms is not easy, and takes a lot of memorization and work.

Since shorthand is a skill subject, it requires REGULAR practice, preferably on a daily basis.  Forty-five minutes to an hour a day would be a good goal if you can squeeze it in.

http://shorthandshorthandshorthand.com/Starting_Out.htm

A person writing regular "longhand” can reasonably get to 50 WPM just writing out regular words as fast as they can. Add in a more efficient symbol system, and then you’re maybe at 70 WPM.

Most speed improvement in Gregg Shorthand comes from the second step – learning the brief forms. That’s what will take a stenographer from 50 WPM to 200 WPM.

Now, you may look at these numbers and think – “I can already type 80 WPM longhand!" In that case, you’ve elevated the symbol system speed improvements from our traditional alphabet to another level. Instead of writing the entire outline of letters (or even faster swooshy shapes), you just flick your fingers in a certain way.

To improve either your Gregg Shorthand skills, or regular typing skills, you may be able to increase your speed even further through regular learning and use of brief forms. But how? By integrating it into your regular daily typing, that’s how.

Attached to this post is a simple “Shorthand Keyboard” application to let you do exactly that.

This application converts the 147 Gregg Shorthand Diamond Jubilee brief forms into their longhand equivalents. You can type shorthand all day, but your [email | blog | Twitter | whatever] readers get the English equivalent. If you type the longhand equivalent of a brief form on accident (or you didn’t know it), the application gives you a simple on-screen reminder.

image

So when you type: “Ths application converts the 147 Gregg shorthand diamond jubilee brief forms into their longhand equivalents. U k type shorthand all day, bt u-r [email | blog | Twitter | whatev] readers get the English equivalent. If u type the longhand equivalent o a brief form on accident (or u didn’t know t), the application gives u a simple on-screen reminder”, you get the paragraph above.

The application doesn’t replace the brief forms by default, since that tends to conflict too often with stuff you type regularly. Instead, you press your Caps Lock key, enter the brief form, and then any non-alphabetic character (such as a space or a period).

Minor notes:

  • If you want to combine brief forms (such as You + r = Your), use a dash character: [Caps]u-r[Space] = “your ”
  • If you want your replacement to be capitalized, end it with a right-shift. [Caps]u[Right-Shift][Space] = “You “
  • The Gregg Shorthand dot symbol (to add an “ing” to whatever word you just wrote) isn’t supported, since that conflicts with ending sentences. It is implemented for “men. = morning” and “th. = think”, though, as these are the common ones. “A” and “an” are so quick to type anyways that the dot equivalent is not a useful speed gain.
    Enjoy!

Fixing KeePass’ Slow Startup Performance

If you don’t use a Password Manager to store your login information for websites, first go read this: http://www.troyhunt.com/2011/03/only-secure-password-is-one-you-cant.html.

I’ve been using KeePass for my password manager for years, but noticed that their Professional Edition had a pretty brutal startup delay. As in – launch KeePass and wait 80 seconds for the window to open. While password security is important, that kind of delay will make even the most security-conscious person start thinking about using ‘123456’ for their password instead.

Surprisingly, I hadn’t seen many complaints online (and certainly no solutions), so I decided to see what Process Monitor might say. After setting an application filter for ‘keepass.exe’, here was the answer:

image

At 7:14 and 10 seconds, it starts enumerating the files in the directory where it is installed. And then doing this for every subdirectory. On my machine, that results in processing over 1600 files – as it was a random ‘Tools’ directory with all kinds of junk and support files.

At 7:14 and 55 seconds, it finally completes. And then creates a PluginCache file.

image

If I were a betting man, I’d say that it was looking at each of those 1600 files trying to figure out if they were some sort of KeePass plugin or not. Which takes a long time. This seems even more likely when you load the program a second time. It doesn’t take nearly as long to start because computers are quicker to read files a second time with the assistance of filesystem and hard drive caches.

Fortunately, this is simple to verify:

image

After rebooting to clear the caches (there are more elegant ways), our suspicions are confirmed. Only 2 seconds to launch – the highlighted line is when Keepass brought up its UI:

image

So there are two solutions:

Disable Plugins

If you don’t need plugins, you can just disable them.

Move KeePass

If you need / want plugins, create a subdirectory in your Tools directory for KeePass. For example, c:\Users\Lee\Tools\KeePass. When KeePass launches, it will still scrub through that whole directory and its subdirectories – but there will only be a few files there. Then, put a launcher script in your Tools folder:

:: keepass.cmd

start %~dp0\keepass\keepass %*

Texting Yourself Sports Alerts with PowerShell

You’ve probably been in the situation of wanting to alert yourself when any update happens to a sports game, UPS package tracking status, or something else.

By combining Invoke-WebRequest’s beautiful support for HTML parsing with Send-MailMessage’s ability to send email messages – this becomes incredibly easy and useful.

(Note: this script also uses Watch-Command, a script from the PowerShell Cookbook.)

 

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
$content = ""
while($true
)
{
   
Watch-Command -ScriptBlock
 {

        ## Fetch the current box score for the game
        $r = Invoke-WebRequest http://www.tsn.ca/MENS_WORLD/scores/boxscore/?id=2388586

        ## The score is in a DIV with the class ‘boxScoreBg’, almost certainly different
        ## for your scenario
        $result = $r.ParsedHtml.Body.getElementsByClassName("boxScoreBg"
)

        ## Extract out what text you care about
        $SCRIPT:content = (@($result)[0].innerText -split "`r`n" | ? { $_ })[5..6] -join "`r`n"

        ## And use that to monitor
        $SCRIPT:content

    } -UntilChanged -DelaySeconds 30

    ## Every cell provider has an email address that you can send to
    ## so that it will be delivered as a text message.
    $params =
 @{
        To 
= "4255551212@txt.att.net"
        From = "my.email@host.com"
        Subject = "Hockey Score Update"
        Body = $SCRIPT:content
        SmtpServer = "mysmtpserver"
    }

    Send-MailMessage @params
}

Using PowerShell to Compare / Diff Files

If you’ve tried to diff files in PowerShell before, you might have seen the Compare-Object cmdlet. The Compare-Object cmdlet lets you compare two sets of items, giving you a report on the differences between those two sets:

PS G:\lee\tools> cd c:\temp
PS C:\temp> $set1 = "A","B","C"
PS C:\temp> $set2 = "C","D","E"
PS C:\temp> Compare-Object $set1 $set2

InputObject SideIndicator
———– ————-
D           =>
E           =>
A           <=
B           <=

From this output, we can see that “A” and “B” only show up in $set1, while “D” and “E” only show up in $set2. For sets of objects, this is all you need to know.

However, one common “set of objects” that people like to compare are lines in text files. When you are comparing lines in a file, you usually don’t care only about the lines that have been added or deleted. You care about where in the file they got added – a situation usually handled by a special-purpose tool such as WinMerge, ExamDiff, WinDiff, or simply the Windows port of diff.exe.

Special-purpose file comparison tools have lots of tricks to compare files efficiently and logically, but PowerShell does let you implement a basic file comparison through a special trick – realizing that the Get-Content cmdlet tags its output objects with the line number they came from.

PS C:\temp> (Get-Content .\test.txt)[5] | Format-List * -Force

PSPath       : C:\temp\test.txt
PSParentPath : C:\temp
PSChildName  : test.txt
PSDrive      : C
PSProvider   : Microsoft.PowerShell.Core\FileSystem
ReadCount    : 6
Length       : 0

That gives the nifty one-liner:

PS C:\temp> Compare-Object (Get-Content files.txt) (Get-Content files2.txt) |
    Sort { $_.InputObject.ReadCount }

InputObject                                                      SideIndicator
———–                                                      ————-
-a—        11/26/2013   9:52 PM          0 files.txt       … <=
-a—        11/26/2013   9:52 PM      75702 files.txt       … =>
-a—        11/26/2013   9:52 PM          0 files2.txt      … =>

If you want to pretty up the output a bit and make the syntax cleaner, let me introduce Compare-File:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
##############################################################################
##
## Compare-File
##
##############################################################################

<#
 
.SYNOPSIS
 
Compares two files, displaying differences in a manner similar to traditional
console-based diff utilities.
 
#>

param(
   
## The first file to compare
    $file1,
   
   
## The second file to compare
    $file2,

    ## The pattern (if any) to use as a filter for file
    ## differences
    $pattern = ".*"
)

## Get the content from each file
$content1 = Get-Content 
$file1
$content2
 = Get-Content $file2

## Compare the two files. Get-Content annotates output objects with
## a ‘ReadCount’ property that represents the line number in the file
## that the text came from.

$comparedLines = Compare-Object $content1 $content2 -IncludeEqual |
    Sort-Object { $_.InputObject.
ReadCount }
   

$lineNumber = 0
$comparedLines | foreach
 {

    ## Keep track of the current line number, using the line
    ## numbers in the "after" file for reference.
    if($_.SideIndicator -eq "==" -or $_.SideIndicator -eq "=>"
)
    {
       
$lineNumber = $_.InputObject.
ReadCount
    }
   
   
## If the text matches the pattern, output a custom object
    ## that displays text like this:
    ##
    ## Line Operation Text
    ## —- ——— —-
    ## 59 added New text added
    ##
    if($_.InputObject -match $pattern
)
    {
       
if($_.SideIndicator -ne "=="
)
        {
           
if($_.SideIndicator -eq "=>"
)
            {
               
$lineOperation = "added"
            }
           
elseif($_.SideIndicator -eq "<="
)
            {
               
$lineOperation = "deleted"
            }
               
           
[PSCustomObject]
 @{
                Line 
= $lineNumber
                Operation = $lineOperation
                Text = $_.InputObject 
            }
        }
    }
}

Getting Started with Guitar

If you’re interested in learning guitar, you might be running into an enormous feeling of dread. How do you get started? What kind of guitar should you get?

Here’s a short guide that can hopefully help get you started.

Buying a Guitar

Guitars can get really expensive. But higher-end guitars end up being a matter of taste (both musically and aesthetically). For your first guitar, you don’t have an opinion, so there’s no need to splurge. After all, you might find out that you don’t end up liking guitar in the end.

For your first guitar, my suggestion is to start relatively cheap. You can get really nice guitars for under $200 (i.e.: your local Guitar Center), and they’ll last anybody for many years in the hobby. The guitar people at the local shops know how to play guitar, so you can even ask them to play the different guitars a bit so you can hear which ones sound nicest to your tastes. They are always really helpful – and if you go on a weeknight, you basically have their undivided attention :)

Also, remember that you won’t be the first one to come to the store with this conundrum. If you go in with a budget, they’ll really be able to help you find the guitar that’s best for you.

I watched a bunch of ‘Buying a new guitar’ YouTube videos, this one represents the situation pretty well: http://www.youtube.com/watch?v=iDz0W8UNgn4.

The one thing they don’t explicitly mention that you want to test with a guitar is making sure every note plays properly. Sometimes, they have issues where the notes at one end of the neck sound great, but as you go through the middle of the neck (or something), they’ll start sounding with a buzz. Sometimes, this is player fault. Sometimes, it’s just something that is due to being set up incorrectly (which can be resolved.) Sometimes, it’s a flaw in the guitar.

If a guitar has fret buzz before being set up by the store, it’s usually a bad sign. They may be able to fix the buzz, but might do so in a way that makes the guitar harder to play in the long run – for example, by raising all of the strings (which makes the guitar harder to play).

Learning to Play

Once you’ve got your brand new guitar (and maybe had it set up), the fun part begins!

Chords

The easiest way to start is to learn how to play guitar chords. These are patterns that you play on the neck of the guitar that sound nice when you strum all (or most) of the strings. YouTube has a lot of great tutorials. Once you start getting good at some, you can start to play along with songs you like – for example: http://www.youtube.com/results?search_query=%22let+it+be%22+guitar+chords. Print out a crib sheet of guitar chords, keep it nearby, and start practicing.

Tab

You can follow along with random YouTube users, but one common way to share musical knowledge is called Tablature – aka "Tab". There is tons of it on the internet. It is usually written as the song’s lyrics, with the chords you need written over the word where you start to strum it:

let_it_be_tab

Listen to songs, play along, and learn to sing along if you are so blessed :)

Keep on Growing

As you learn, it’s easy to get stuck in "bedroom guitar" mode, where you grind on songs alone, get stuck on things, and don’t know where to go next. A next great step is to get a guitar tutor. They are usually $30-$50 per hour, so you can take a lesson every week or two.

In the beginning, you can start with a teacher that is a generalist. Music stores often have recommendations on local tutors (or instructors that rent out space in the local shop), and that is a great place to start. Take trial lessons with a handful of teachers, and find the one that matches your learning style.

A good teacher should push you hard enough that you need to spend a couple of hours on practice for each hour of instruction. If not, you’re just paying to listen to them talk. If that’s happening, there are much more efficient ways to blow your money so go do that instead.

Once you get more accomplished, you might find you like some kinds of music more than others. If that’s the case, you can always specialize – so you can find teachers that focus on Jazz, Classical guitar, Rock, or whatever else interests you.

At some point, tablature isn’t descriptive enough – and your teacher will introduce you to standard music notation.

notes

Standard music notation is challenging to learn at first, but does open your world to a whole new kind of music sharing and knowledge.

In the end, the biggest requirement for growth is practice. If you wonder how long it’ll take you to become a master shredder, you’d better become deeply familiar with the 10,000 hour rule.

Who’s in Your Email Social Network?

Have you ever wondered who’s in your “Email Social Network”?

I was wondering the other day how to find out who I mail the most. With a bit of PowerShell scripting, the answer is a breeze to find out:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
## Connect with Outlook, and open the ‘Sent Items’
$olApp = New-Object -com Outlook.Application 
$namespace = $olApp.GetNamespace("MAPI")
$sentItems = $namespace.GetDefaultFolder(5)

## Go through each item, split out names when there were multiple
## recipients, and clean them up a bit

$sentEverTo = $sentItems.Items | % { $_.To -split ";" } | % { $_.Trim(" ‘") }

## Group by how often you’ve sent mail to them
$sortedTo = $sentEverTo | group

## Explore
$sortedTo | sort Count

More Packet Hacking with PowerShell – UDP Manipulation

In the last post, I talked about how I used PowerShell to "STUN Roll" the open WiFi at DefCon. How much code was that? Was it hard?

stun_roll

It turns out that it was pretty reasonable – less than 60 lines of PowerShell.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
## Convert a string in the form of hexadecimal characters into the
## equivalent bytes.

function ConvertFrom-HexString
{
   
param($HexString
)

    $HexString -split "(..)" | ? { $_ } | % { [Convert]::ToByte($_, 16) }
}

## Get the broadcast address for a subnet.
## Modified from
## http://powershell.com/cs/blogs/tips/archive/2013/06/03/calculate-broadcast-address.aspx

function Get-BroadcastAddress
{
   
$ipConfiguration = Get-WmiObject Win32_NetworkAdapterConfiguration |
        Where-Object IPAddress | Select -First 1
    $ipAddress = @($ipConfiguration.IPAddress)[0]
    $subnetMask = @($ipConfiguration.IPSubnet)[0]

    [UInt32]$ip = [IPAddress]::Parse($IPAddress).Address
   
[UInt32]$subnet = [IPAddress]::Parse($SubnetMask).
Address
   
[UInt32]$broadcast = $ip -band $subnet

    New-Object IPAddress ($broadcast -bor -bnot $subnet)
}

## Send the actual STUN packet for some given text
function Send-StunPacket
{
   
param([string] $Text
)

    ## Some header bytes that I got from reviewing the
    ## hexadecimal packet data in WireShark
    $headerContent = "000100"
 
   
$bytes = ConvertFrom-HexString $headerContent

    ## After the header bytes is the length of the packet
    ## Found by experimentation
    $bytes += [Byte] (4 + $Text.
Length)

    ## And then some more header bytes that I didn’t really know
    ## or care what they did
    $bytes += ConvertFrom-HexString "2112a4426274336f6754616876713150000600"
    $bytes += [Byte] $Text.
Length

    ## Get the bytes for the message, add them to the packet.
    ## This section of the packet is usually for the user’s ID.
    $messageBytes = [System.Text.Encoding]::ASCII.GetBytes($Text
)
   
$bytes += $messageBytes

    ## Configure the destination IP address and port
    $dstPort = 3478
    $endpoint = New-Object System.Net.IPEndPoint (Get-BroadcastAddress),$dstPort

    ## And send the packet
    $udpClient = New-Object System.Net.Sockets.UdpClient
    $null = $udpClient.Send($bytes, $bytes.Length, $endpoint
)
   
$udpClient.
Close()
}

## The payload :)
$lyrics = 
@"
We’re no strangers to love
You know the rules and so do I
A full commitment’s what I’m thinking of
You wouldn’t get this from any other guy
I just wanna tell you how I’m feeling
Gotta make you understand
 
CHORUS
Never gonna give you up,
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry,
Never gonna say goodbye
Never gonna tell a lie and hurt you
 
We’ve known each other for so long
Your heart’s been aching but you’re too shy to say it
Inside we both know what’s been going on
We know the game and we’re gonna play it
And if you ask me how I’m feeling
Don’t tell me you’re too blind to see (CHORUS)
 
CHORUS
(Ooh give you up)
(Ooh give you up)
(Ooh) never gonna give, never gonna give
(give you up)
(Ooh) never gonna give, never gonna give
(give you up)
 
We’ve known each other for so long
Your heart’s been aching but you’re too shy to say it
Inside we both know what’s been going on
We know the game and we’re gonna play it (TO FRONT)
"@

$lines = $lyrics -split "`r`n"
$lines | % { Send-StunPacket $_.Trim() }

 

Happy packet hacking!

Packet Hacking with PowerShell–AKA Mass Defcon Pwnage

Every year, two of the biggest hacking / security conferences take place in Las Vegas: Black Hat, and DefCon.

Both are great experiences, and both have a common theme – hackers (“Intelligent folks that like to make machines do things they weren’t originally designed for”) getting together to educate each other and have fun.

Unsurprisingly, one of the places that people get together to have fun is the free open WiFi.

Aside: Open WiFi led to the nerdiest “social networking” experience I’ve ever had. I was monitoring my hotel network to see how much malicious activity was on it. One of the prominent protocols in a network is LLMNR: a name resolution protocol that queries the local subnet for computers before trying other name resolution protocols. I saw one computer making requests for another laptop (presumably to reconnect a shared drive) – looking for a machine called “johnsmithlaptop”. It was also making LLMNR requests for a couple of servers on the Microsoft internal network. I figured that this was probably John Smith that works in security at Microsoft – who I’d been meaning to catch up with anyways. I sent him a mail asking if he was at BlackHat at my hotel – he was, and we got together for drinks :)

At DefCon, they had two networks: a secure network where you downloaded user certificates and that was monitored for threats very heavily, and another. From the FAQ:

Is there a free network at DEF CON?

Why yes, DEF CON 21 is FULLY network-enabled. Now that we’ve perfected the art of a stable hacker con network, we’re ascending to a higher level – we’re providing you a network that you feel SAFE in using! Since DEF CON 18 we’re WPA2 encrypted over-the-air, with a direct trunk out to the Internet. No peer-to-peer, no sniffing, just straight to the net (and internal servers). We’ll provide login credentials at Registration. We know the 3G airwaves will be saturated so we’re putting our own cred on the line to give you a net that even we would put our own mobile phones on.

If you’re feeling frisky, we’ll still have the traditional "open" network for you – bring your laptop (we’d recommend a clean OS, fully patched–you know the procedure) because we don’t police what happens on that net. Share & enjoy!

So the free open WiFi is pretty frisky. People are constantly monitoring it with their packet analyzer of choice, looking for fun things to do.

In packet analyzers, most protocols have “wizards” coded that will parse the protocol and give you a high-level summary of what that packet was attempting to do. Here’s an example of NTP (Network Time Protocol) traffic being dissected by WireShark:

capture_ntp

Most of the details in the “Info” column are extremely constrained – for example, describing protocol options, or maybe an IP or DNS address. However, I found one protocol during a Google Hangout I was having that supported almost arbitrary text in the “Info”, and decided to have fun. The protocol was STUN – a protocol designed to help applications figure out all of the complicated NAT translation being done to a client.

If you were monitoring the DefCon network at all you might have seen a packet like this fly by:

stun_roll_flyby

If you put a filter on the STUN protocol, the full beauty of the packet hacking would be exposed:

stun_roll

So, that’s how you (Rick) roll on the free network at DefCon.

In the next post, I’ll go through the code that made the magic happen.

Redacting Sensitive Information with PowerShell

You might sometimes run into a situation where you’ve got a serialized object stream, and want to redact sensitive information out of that stream. For example, consider the following object:

001
002
003
004
005
006
007
008
009
$objectToSerialize = [PSCustomObject] @{
    Name 
= "Lee"
    SocialSecurityNumber = "SomeSecretNumber"
    Address = "1234 Something Road"
    GateCode = [PSCustomObject]
 @{
        Prefix 
= 1234
        Password = "SomeSecretPassword"
    }
}

 

In this, you want to remove any property value that says "SomeSecret".

PowerShell makes this fairly easy, since the PSObject special property on every type gives you access to an object’s methods and properties. For each property value, you can check if it contains sensitive information – and if so, redact it.

Some properties are not simple properties, though. They might be objects with multiple writable properties themselves. In that case, you need to go down the worm hole even further.

Here’s a script that demonstrates one approach: Remove-PrivateInformation.ps1

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
param($objectToSerialize)

function CleanObject
{
   
param($objectToClean
)

    foreach($property in $objectToClean.PSObject.Properties)
    {
       
## See if there are any settable properties of this property
        $settableProperties = $property.Value.PSObject.Properties | ? { $_.
IsSettable }
       
if(@($settableProperties).Count -gt 0
)
        {
           
CleanObject $property.
Value
        }

        ## Otherwise, we can clean it
        if($property.IsSettable -and
 
            (
$property.Value -match "SomeSecret"
))
        {
           
$property.Value = "Redacted!"
        }
    }
}

## Assuming you can’t change $objectToSerialize directly. Otherwise, apply CleanObject
## to the object directly.

$serialized = [System.Management.Automation.PSSerializer]::Serialize($objectToSerialize)
$objectToClean = [System.Management.Automation.PSSerializer]::Deserialize($serialized)

CleanObject $objectToClean

$objectToClean

 

And the result:

                                                                                
11 [C:\windows\system32]                                                        
>> $objectToSerialize = [PSCustomObject] @{                                     
>>         Name = "Lee"                                                         
>>         SocialSecurityNumber = "SomeSecretNumber"                            
>>         Address = "1234 Something Road"                                      
>>         GateCode = [PSCustomObject] @{                                       
>>             Prefix = 1234                                                    
>>             Password = "SomeSecretPassword"                                  
>>         }                                                                    
>>     }                                                                        
>>                                                                              
                                                                                
12 [C:\windows\system32]                                                        
>> Remove-PrivateInformation.ps1 $objectToSerialize | Format-List               
                                                                                
                                                                                
Name                 : Lee                                                      
SocialSecurityNumber : Redacted!                                                
Address              : 1234 Something Road                                      
GateCode             : @{Prefix=1234; Password=Redacted!}                       
                                                                                
                                                                                
                                                                                
                                                                                
13 [C:\windows\system32]