A programming question that I’m sure everyone has been asked at some point during the interview is ‘Pascal’s Triangle’. Besides solving it, nothing would impress your interviewer more than solving it in PowerShell, with support for massively huge numbers. Wikipedia could probably explain this better than I can, but the premise is simple: start with ‘1’, then each row is one element longer than the previous and is made up of the to values above it added together (Except for the values on either end, which are always 1).
raw
function Pascals-Triangle
{
    [CmdLetBinding()]
    param
    (
        # Single parameter is the number of levels
        [Parameter(Mandatory=$true)][ValidateRange(1, [int]::MaxValue)][int]$Levels
    )
    process
    {
        # Create a dummy previous array, just so that we know what is going on.
        $prev = [System.Numerics.BigInteger[]]::new(0)

        # Now for each level
        for($l = 0; $l -lt $Levels; $l++)
        {
            # Create the current working array
            $current = [System.Numerics.BigInteger[]]::new($prev.Length + 1)
            
            # We know for sure that the first and the last element are 1 (This avoids bounds checking in the loop below)
            $current[0] = 1
            $current[$current.Length - 1] = 1

            # Now for all other elements add the previous two together
            for($i = 1; $i -lt $current.Length - 1; $i++)
            {
                $current[$i] = $prev[$i - 1] + $prev[$i]
            }

            # Write out our result
            Write-Output ([string]::Join(' ', $current))

            # Set the previous to the current for the next iteration
            $prev = $current
        }

    }
}

                            
                        
This is most likely the solution that any interviewer would be expecting, because it is by far the simplest to follow. The idea is simple, start with an array of zero length and for every level of the triangle allocate an array which is 1 element longer, and populate it by adding together elements from the previous array. I’m not sure why, but whenever I got this question in college I wanted to do it recursively, which totally screwed me. Also, the reason behind using ‘BigInteger’, is that these number expand very rapidly. Try it out with ‘int’ or even ‘ulong’, and you wont be able to do too many levels. Anyway, the results in powershell end up looking like this.
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
So now, to mix things up, lets do it in a way that doesn’t require us to keep reallocating arrays. This next solution does the whole thing in place, reusing the same array each time. This is not a big deal, because we always know how long the array needs to be when we start. (Length = Levels). We can just go through and add up the values of the previous row each time.
raw
function Pascals-Triangle2
{
    [CmdLetBinding()]
    param
    (
        # Single parameter is the number of levels
        [Parameter(Mandatory=$true)][ValidateRange(1, [int]::MaxValue)][int]$Levels
    )
    process
    {
        # Create our working array
        $row = [System.Numerics.BigInteger[]]::new($Levels)

        # Now for each level
        for($l = 1; $l -le $Levels; $l++)
        {
            # The first index is always 1, and set our previous
            $iPrevious = $row[0] = 1
            for($i = 1; $i -lt $l; $i++)
            {
                # Back up the current value
                $temp = $row[$i]

                # Add in the previous value
                $row[$i] += $iPrevious

                # Swap out the previous
                $iPrevious = $temp
            }

            # Write out our result
            Write-Output ([string]::Join(' ', ($row | select -First $l)))
        }

    }
}
        
                            
                        
And there we have it. So what about a more obfuscated version for those really hard core interviewees? Lets do it. Taking solution 2 and squishing everything together as much as possible we get a horribly confusing solution.
raw
function Pascals-Triangle3
{
    [CmdLetBinding()]
    param
    (
        # Single parameter is the number of levels
        [Parameter(Mandatory=$true)][ValidateRange(1, [int]::MaxValue)][int]$Levels
    )
    process
    {
        ($r=[System.Numerics.BigInteger[]]::new(($l=$Levels)+1))[0]=1
        1..$l|%{"$($r|?{$_-ne0})";$t=1;1..$_|%{$a=$r[$_];$r[$_]+=$t;$t=$a}}
    }
}
                            
                        
Im sure everyone is better at code golf than I am, but this solution already confuses so it should be a good start.



Here is one to get the people going. Have you ever had an issue, where you tried to mount too many disks on your machine at one time, and ran out of driver letters? Well have no fear. It is a totally normal problem. Instead of mounting to drive letters... of which there are only 26. We can add access paths to partitions on the disk. You know what the best news is? The limit on access paths is totally crazy. I have once mounted 50 disks at the same time, and everything still seemed to work.
So here is the rub. This example is going to use a bunch of powershell cmdlets. But all of these are just wrappers around the root\microsoft\windows\storage CIM namespace. We could do this the badass way using only CIM, but it would be much longer, and I need something to write about tomorrow.
Anyway, this is what the code looks like.
raw
#
# Mount a virtual hard disk to a folder
#
function Mount-VHDToFolder
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory=$true)][String]$Image,
        [Parameter(Mandatory=$true)][String]$MountFolder
    )
    process
    {
        try
        {
            # Gets a mounted disk image
            $mountedDisk = Mount-DiskImage -ImagePath $Image -NoDriveLetter -PassThru -ErrorAction Stop | Get-DiskImage
        }
        catch
        {
            Write-Error "Failed to mount disk"
            return
        }

        # Get all of the partitions
        $partitions = Get-Partition -DiskNumber $mountedDisk.Number

        foreach($partition in $partitions)
        {
            $partFolder = Join-Path $MountFolder $partition.PartitionNumber

            # Clean up this folder if it exists
            if(Test-Path $partFolder)
            {
                rmdir -Force $partFolder
            }

            # Make the new folder
            mkdir $partFolder | Out-Null

            try
            {
                # Add the access path for the disk
                Add-PartitionAccessPath -InputObject $partition -AccessPath $partFolder -ErrorAction Stop
            }
            catch
            {
                Write-Warning "Could not add access path '$($partFolder)' for partition '$($partition.PartitionNumber)'"
            }
        }
    }
}
                            
                        
This is going to create a folder for each partition number in the mount folder which you provide. It will try to add an access path for each partition. FYI, the reason I check if the folder exists, and delete it, is because AddAccessPath will fail if there is a broken symbolic link on the folder. AKA, you dismounted a disk which was using that folder as an access path without removing the access path first.
And there you have it! It is pretty simple really. Mounting the disk image gives us a MSFT_Disk cim object. We can use that disk to get all of the related MSFT_Partition cim objects. The MSFT_Partition object has a method called "AddAccessPath". Powershell wraps all of this stuff up for us super nicely so we won't need to mess with it.



So here we are again. A long adventure to get some food has been completed. The TV blaring Season 5 of New Girl. I think to myself, you know what would go really well with this Shawarma? If I could finally read an IPv6 address without looking like an idiot. So here goes. IPv4 is simple, 32 bits of easy to understand goodness. Every single IPv4 address is made up of 4 bytes. For example "192.168.1.1". There is no shorthand either, that is the address, that's it. There is no better way to write it. Ok, so now that that is out of the picture, what is IPv6.
IPv6 is 128 bits of a little bit more confusing. Well actually, it's not the address that is confusing, it's the notation. When you see IPv6, a lot of times you see things like "::1" and "FE80::1". What does that even mean. How is that 128 bits. How will we ever know. So the secret is in the "::", which is pretty much just shorthand for "a lot of zeros go here".
For example: if we take the address "::1", it actually expands out to "0000:0000:0000:0000:0000:0000:0000:0001". Literally just means fill in this space with zeros. Another example: "FE80::1" becomes "FE80:0000:0000:0000:0000:0000:0000:0001". Just FYI, you are only allowed to use the "::" once, otherwise addresses would be unreadable. ("::1::") So before anything, here is a function to automate that, because it drives me nuts.
raw
#
# Expand an IPv6 address. For example ::1 becomes 0000:0000:0000:0000:0000:0000:0000:0001
#
function Expand-IPV6
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, 
                   Position = 0,
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)][String]$IPv6
    )
    process
    {
        $count = 0
        $loc = -1

        # Count the number of colons, and keep track of the double colon
        for($i = 0; $i -lt $IPv6.Length; $i++) 
        { 
            if($IPv6[$i] -eq ':') 
            {
                $count++
                if(($i - 1) -ge 0 -and $IPv6[$i-1] -eq ':')
                {
                    $loc = $i
                }
            }
        }

        # If we didnt find a double colon and the count isn't 7, then throw an exception
        if($loc -lt 0 -and $count -ne 7)
        {
            throw "Invalid IPv6 Address"
        }

        # Add in any missing colons if we had a double
        $cleaned = $IPv6
        if($count -lt 7)
        {
            $cleaned = $IPv6.Substring(0, $loc) + (':'*(7-$count)) + $IPv6.Substring($loc)
        }

        # Parse current values in fill in new IP with hex numbers padded to 4 digits
        $result = @()
        foreach($splt in $cleaned -split ':')
        {
            $val = 0
            $r = [int]::TryParse($splt, [System.Globalization.NumberStyles]::HexNumber, [System.Globalization.CultureInfo]::InvariantCulture, [ref]$val)
            $result += ('{0:X4}' -f $val)
        }

        return $result -join ':'
    }
}
                            
                        
So this does the expansions work for us, because it’s a pain in the butt to deal with these addresses in their short form. Also, I know the code is gross and I apologize for that, but there is more to come. Ok, so now, what happens if we have an IPv4 address and we need to turn it into IPv6. Boom, its easy. The last 32 bits of the IPv6 address are equal to our IPv4 address, and the 16 bits preceding those are all set to 1. Easy enough! That means, the IP address 1.1.1.1 would turn into "::FFFF:0101:0101" or "0000:0000:0000:0000:0000:FFFF:0101:0101" in full form. So how do we make that happen?
raw
# Map an IPv4 address to IPv6
function Map-IPv4ToIPv6
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, 
            Position = 0,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true)][String]$IPv4
    )
    process
    {
        # Split on the dots
        $split = $IPv4 -split '\.'
        if($split.Length -ne 4)
        {
            throw 'Not a valid IPv4 Address'
        }

        # Parse into numbers
        $vals = @()
        foreach($v in $split)
        {
            $vals += [int]::Parse($v)
        }

        # Return as shorthand ipv6
        return "::FFFF:{0:X2}{1:X2}:{2:X2}{3:X2}" -f $vals
    }
}
                            
                        
BOOM, mission accomplished. Hopefully (it worked in a few tests). Also, for completeness, here is a function which turns an IPv4 address which is represented in IPv6 back into an IPv4 address.
raw
#
# Transforms an IPv4 address which is represented in IPv6 back into IPv4
#
function Map-IPv6ToIPv4
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, 
            Position = 0,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true)][String]$IPv6
    )
    process
    {
        # Get the expanded form
        $expanded = Expand-IPV6 $IPv6
        $split = $expanded.Split(':')

        # Make sure this is valid...
        $is4MappedTo6 = $split[5] -match 'FFFF'
        if(-not $is4MappedTo6)
        {
            throw 'This is not an IPv4 Address mapped to IPv6'
        }

        # Parse each byte as an integer
        $addr = @()
        for($i = 0; $i -lt 8; $i+=2)
        {
            $addr += [int]::Parse(($split[6 + [math]::Floor(($i / 4))][($i % 4)..(($i%4)+1)] -join ''), [System.Globalization.NumberStyles]::HexNumber)
        }

        return $addr -join '.'
    }
}
                            
                        
The classes built in to handle IP addresses are definitely much smarter, and the way to go. But this was a sad attempt at a way to do it in Powershell!



Every once in a while, you end up on a friend's computer and you think to yourself, what is the most annoying thing I can do RIGHT NOW. Well don't even worry, here is a super quick way to make some gigantic files. Of course, it starts with opening up PowerShell. (You can do the same thing on a Unix machine with 'cat'). Ok let's do it.
raw
'a' * 1000 > temp.txt
Get-Content temp.txt >> temp.txt
                            
                        
  1. Writes the letter 'a' to a file named temp.txt 1000 times.
  2. Reads temp.txt line by line, and appends it to the end of temp.txt
Pretty simple right!? Just a never ending loop of file writing. You can event do it in a single line.
raw
'a' * 1000 > temp.txt; gc temp.txt >> temp.txt
                            
                        
The real question is, how fast does this baby go. So here we go, a test which lets this run for 30 seconds, then kills it.
raw
$job = Start-Job -ScriptBlock {'a' * 1000 > temp.txt; Get-Content temp.txt >> temp.txt}
Wait-Job -Job $job -Timeout 30
Stop-Job -Job $job
                            
                        
This made me a nice 1.4GB text file. Also tried for 120 seconds, and ended up with a 5.2GB file. So there you have it. Fun time with files.



Here is a quick one. I couldn't find a great way to find the amount of free space which exists on a disk with powershell. I am sure there is a good option, but anway, here is a great solution with uses P/Invoke. This will uses the kernel32 function: GetDiskFreeSpaceEx to figure out how much free space is on a drive. It seems to work pretty well. One catch, P/Invoke in powershell is weird. You pretty much need to go compile the C#.
raw
#
# Gets the amount of free disk space.
#
function Get-DiskFreeSpace
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory = $false)]$Directory = $pwd
    )
    process
    {
        # Name of the P/Invoke we are going to use
        $name = 'GetDiskFreeSpaceEx'

        # The dll the funciton is in
        $dll = 'kernel32.dll'

        # The P/Invoke function definition
        $def = "[DllImport(`"$dll`")]
        public static extern bool $name(string lpDirectoryName,
           out ulong lpFreeBytesAvailable, 
           out ulong lpTotalNumberOfBytes, 
           out ulong lpTotalNumberOfFreeBytes);"

        # First try to see if this already exists
        $type = 'Microsoft.PowerShell.Commands.AddType.AutoGeneratedTypes.GetStorageFreeType' -as [type]
        
        # If not, new up a runtime type with this function definition
        if(-not $type)
        {
            $type = Add-Type -MemberDefinition $def -Name "GetStorageFreeType" -PassThru
        }

        $freeBytes = [uint64]0
        $totalBytes = [uint64]0
        $totalFreeBytes = [uint64]0

        # Do the P/Invoke
        $res = $type::GetDiskFreeSpaceEx($Directory, [ref] $freeBytes, [ref] $totalBytes, [ref] $totalFreeBytes)

        # Get the total free bytes
        return $totalFreeBytes
    }
}
                            
                        



Have you ever thought to yourself, "How does a deprecated standard like SHA1 work, and how could it be implemented in powershell?". Well look no further. Actually, it was a litte harder than it seems, since powershell REALLY loves signed numbers. Lets take for example: 0xFFFFFFFF, which one would assume is ?equal to 4294967295?. Well.. Check out this simple line of code.
raw
#This wont throw an exception right?
[uint32]0xFFFFFFFF
                            
                        
Well, in powershell this just throws an exception. You know why!? Because under the hood, PShelly goes OH "0xFFFFFFFF", that's 32 bits. Let me stick it in a 32 bit signed integer. But wait... "0xFFFFFFFF" is just 32 1s. But oh crap, in 2s complement, that's -1. So in powershell 0xFFFFFFFF == -1. So now its pretty clear why the above code throws an exception, there is no unsigned value to represent -1. Seriously, just go type "0xFFFFFFFF" into powershell. So.. because of that, everything here has to be done in a 64 bit integer.
raw
#
# Implemenation of SHA1
#
function SHA1
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory = $false, Position=1)][string]$Str
    )
    process
    {
        #
        # Truncate a value to UInt32
        #
        function TUI
        {
            param($val)
            process
            {
                [uint64]($val -band (((-bnot [uint64]0)) -shr 32))
            }
        }

        #
        # Get a 32 bit value from a byte array
        #
        function GetBigEndianUInt
        {
            param
            (
                [byte[]]$bytes,
                [int]$index
            )
            process
            {
                return ([uint64]$bytes[$index] -shl 24) -bor ([uint64]$bytes[$index+1] -shl 16) -bor ([uint64]$bytes[$index+2] -shl 8) -bor ([uint64]$bytes[$index+3])
            }
        }

        #
        # Left rotate
        #
        function LeftRotate
        {
            param
            (
                [uint64]$val,
                [int]$amount
            )
            process
            {
                $res = TUI ([uint64]$val -shr (32 - $amount))
                $res = $res -bor ($val -shl $amount)
                return TUI $res
            }
        }

        # Initialize constants
        $h0 = TUI 0x67452301
        $h1 = TUI 0xEFCDAB89
        $h2 = TUI 0x98BADCFE
        $h3 = TUI 0x10325476
        $h4 = TUI 0xC3D2E1F0
        
        # Get the message bytes
        $message = [System.Text.ASCIIEncoding]::ASCII.GetBytes($Str)

        # Get the length in bytes which we need. Message length + 0x80 + (64bit message len)
        $len = ($message.Length + 9)
        
        # Get the padded length of our our byte array
        if($len % 64 -ne 0){
            $len += (64 - ($len % 64))
        }

        # Copy the bytes in the message to our byte array
        $bytes = ([byte[]]0 * $len)
        for($i = 0; $i -lt $message.Length; $i++){
            $bytes[$i] = [byte]$message[$i]
        }

        # Pad the message with 1000 0000
        $bytes[$i] = 128

        # The message length in bits
        $bitLen = $message.Length * 8

        # Set the last [uint64] as the messsage length. (We only do 32 bits)
        $bytes[$len-1] = [byte]($bitLen -band 0xFF)
        $bytes[$len-2] = [byte](($bitLen -shr 8) -band 0xFF)
        $bytes[$len-3] = [byte](($bitLen -shr 16) -band 0xFF)
        $bytes[$len-4] = [byte](($bitLen -shr 24) -band 0xFF)

        # Divide the message into 512 bit chunks
        for($chunk = 0; $chunk -lt $bytes.Length; $chunk += 64)
        {
            $w = ([uint64[]]0 * 80)

            # Copy the chunk into our working array as uints
            for($i = 0; $i -lt 16; $i++){
                $w[$i] = GetBigEndianUInt -bytes $bytes -index ($i*4 + $chunk)
            }

            for($i = 16; $i -lt 80; $i++){
                $w[$i] = LeftRotate -val (TUI ($w[$i-3] -bxor $w[$i-8] -bxor $w[$i-14] -bxor $w[$i-16])) -amount 1
            }

            $a = TUI $h0
            $b = TUI $h1
            $c = TUI $h2
            $d = TUI $h3
            $e = TUI $h4

            # A bunch of crazy stuff
            for($i = 0; $i -lt 80; $i++){
                $k=0
                if($i -lt 20){
                    $f = TUI (($b -band $c) -bor ((-bnot $b) -band $d))
                    $k = TUI 0x5A827999
                }
                elseif($i -lt 40){
                    $f = TUI ($b -bxor $c -bxor $d)
                    $k = TUI 0x6ED9EBA1
                }
                elseif($i -lt 60){
                    $f = TUI (($b -band $c) -bor ($b -band $d) -bor ($c -band $d))
                    $k = TUI 0x8F1BBCDC
                }
                else{
                    $f = TUI ($b -bxor $c -bxor $d)
                    $k = TUI 0xCA62C1D6
                }
            
                $temp = TUI ((LeftRotate -val $a -amount 5) + $f + $e + $k + $w[$i])

                $e = $d
                $d = $c
                $c = LeftRotate -val $b -amount 30
                $b = $a
                $a = $temp
            }

            $h0 = TUI ($h0 + $a)
            $h1 = TUI ($h1 + $b)
            $h2 = TUI ($h2 + $c)
            $h3 = TUI ($h3 + $d)
            $h4 = TUI ($h4 + $e)   
        }

        '{0:X8}{1:X8}{2:X8}{3:X8}{4:X8}' -f $h0, $h1, $h2, $h3, $h4
    }
}
                            
                        
There it is. I may have overused my TUI(To uint) function a little bit, since values larger than 32 bits could actually cause problems. I got most of the implementation details from the wikipedia artical on SHA1.



Powershell Cim Tree

Jul16.16 12AM

Sometimes you are just bored. And all you really want to do is list out all of the cim namespaces on your machine. Cool right? YEA. So here is a powershell script which produces output similar to the "tree" command, except for all of your cim namespaces and classes. This should help figure out what actually exists. This should probably be run as administrator, depends on which stuff you are trying to look at. Anyway, here it is!
raw
#
# Generate a tree from cim namespaces and classes
#
function Get-CimTree
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory=$false, Position=0)][string]$NameSpace = 'Root',
        [switch]$IncludeClasses = $false
    )
    process
    {
        # Constants
        $tbend = '├'
        $cbend = '└'
        $pipe = '│'
        $flat = '─'
        $tabWidth = 4

        # Function to write a namespace. Takes the tabs stack, and the namespace name
        function writeNamespace($tabStack, $ns)
        {
            # Write the list of tabs
            function writeTabStack($ts)
            {
                $output = ''
                for($t = 0; $t -lt $ts.Length; $t++)
                {
                    $val = $ts[$t]
                    
                    # Transform previous tabs, to make our tree look more like a tree
                    if($t -lt $ts.Length - 1)
                    {
                        switch($val)
                        {
                            2 { $val = 1 }
                            3 { $val = 0 } 
                        }
                    }

                    # Get the starting and sperator characters for the tab
                    switch($val)
                    {
                        0 { $start = ' '; $sep = ' ' }
                        1 { $start = $pipe; $sep = ' ' }
                        2 { $start = $tbend; $sep = $flat }
                        3 { $start = $cbend; $sep = $flat }
                    }

                    # Add to the outptu line
                    $output += $start + ($sep * ($tabWidth - 1))
                }

                Write-Host $output -NoNewline
            }

            # Write the tab stack
            writeTabStack $tabStack

            # Write the namespace name
            Write-Host $ns

            $classes = @()

            # Get all of the classes in the namespace if we need them
            if($IncludeClasses)
            {
                $classes = Get-CimClass -Namespace $ns
            }

            # Get all of the namespaces in the current namespace
            $namespaces = Get-CimInstance -Namespace $ns -ClassName __NameSpace -ErrorAction Ignore

            # If the query failed, just continue
            if(-not $namespaces)
            {
                return
            }
           
            for($i = 0; $i -lt $namespaces.Length; $i++)
            {
                # If it's the last element, use an angled branch
                $tsAdd = 2
                if($i -eq $namespaces.Length -1 -and $classes.Length -eq 0)
                {
                    $tsAdd = 3
                }

                writeNamespace -tabStack ($tabStack + $tsAdd) -ns ($ns + '/' + $namespaces[$i].Name)
            }

            # Write all of the classes
            for($i = 0; $i -lt $classes.Length; $i++)
            {
                # If it's the last element, use an angled branch
                $tsAdd = 2
                if($i -eq $classes.Length - 1)
                {
                    $tsAdd = 3
                }

                writeTabStack ($tabStack + $tsAdd)
                Write-Host $classes[$i].CimClassName
            }
        }

        # Write the initial namespace to kick things off
        writeNamespace -tabStack @() -ns $NameSpace
    }
}
                            
                        
When you run this thing, you will get output in this form:
Root
├───Root/subscription
├───Root/DEFAULT
├───Root/CIMV2
│   ├───Root/CIMV2/mdm
│   │   ├───Root/CIMV2/mdm/dmmap
│   │   └───Root/CIMV2/mdm/MS_409
│   ├───Root/CIMV2/Security
│   │   ├───Root/CIMV2/Security/MicrosoftTpm
│   │   └───Root/CIMV2/Security/MicrosoftVolumeEncryption
│   ├───Root/CIMV2/power
│   ├───Root/CIMV2/ms_409
│   ├───Root/CIMV2/TerminalServices
│   └───Root/CIMV2/Applications
├───Root/msdtc
├───Root/Cli
├───Root/SECURITY
├───Root/HyperVCluster
├───Root/SecurityCenter2
├───Root/RSOP
│   └───Root/RSOP/Computer
├───Root/PEH
├───Root/StandardCimv2
│   ├───Root/StandardCimv2/MS_409
│   └───Root/StandardCimv2/embedded
├───Root/WMI
├───Root/directory
├───Root/Policy
├───Root/virtualization
├───Root/Interop
├───Root/Hardware
├───Root/ServiceModel
├───Root/SecurityCenter
├───Root/Microsoft
│   ├───Root/Microsoft/HomeNet
│   ├───Root/Microsoft/protectionManagement
│   ├───Root/Microsoft/Windows
│   │   ├───Root/Microsoft/Windows/RemoteAccess
│   │   ├───Root/Microsoft/Windows/Dns
│   │   ├───Root/Microsoft/Windows/Powershellv3
│   │   ├───Root/Microsoft/Windows/Hgs
│   │   ├───Root/Microsoft/Windows/WindowsUpdate
│   │   ├───Root/Microsoft/Windows/DeviceGuard
│   │   ├───Root/Microsoft/Windows/TaskScheduler
│   │   ├───Root/Microsoft/Windows/DesiredStateConfigurationProxy
│   │   ├───Root/Microsoft/Windows/SmbWitness
│   │   ├───Root/Microsoft/Windows/Wdac
│   │   ├───Root/Microsoft/Windows/winrm
│   │   ├───Root/Microsoft/Windows/AppBackgroundTask
│   │   ├───Root/Microsoft/Windows/PS_MMAgent
│   │   ├───Root/Microsoft/Windows/Storage
│   │   │   ├───Root/Microsoft/Windows/Storage/PT
│   │   │   ├───Root/Microsoft/Windows/Storage/MS_409
│   │   │   └───Root/Microsoft/Windows/Storage/Providers_v2
│   │   ├───Root/Microsoft/Windows/HardwareManagement
│   │   ├───Root/Microsoft/Windows/SMB
│   │   ├───Root/Microsoft/Windows/EventTracingManagement
│   │   ├───Root/Microsoft/Windows/DesiredStateConfiguration
│   │   ├───Root/Microsoft/Windows/CI
│   │   └───Root/Microsoft/Windows/Defender
│   ├───Root/Microsoft/SecurityClient
│   └───Root/Microsoft/Uev
├───Root/aspnet
└───Root/Appv
Gosh I know, the code is a total mess... That's because I am really hungry. You can also print out all of the classes, but the output gets HUGE. To be honest, the whole reason for this, is that I needed to figure out how to mount an iso to a folder from the command line, and I hate constantly searching online for these things. Its way easier to find out what is really going on when you can see the whole tree. Also trees are cool...



Alright. I was in a bit of a groove last night. I was up till 3, but I do have something amazing to show for it. Like literally fantastic. I have no idea how humanity got to this point without some of this code. So without further ado how about some scripts for doing color conversions in powershell. They aren't commented amazingly. Well the first one is ok. But the other ones suck. Anyway, here it is. These are based entirely off of the wikipedia article on HSV and HSL. I did my best to use those formulas exaclty so everything *SHOULD* work.
raw
#
# All of these functions are based on the formulas provided on WikiPedia for color conversions
# So check them out for more info https://en.wikipedia.org/wiki/HSL_and_HSV
#

#
# Converts from Hue Saturation Lightness to RGB
#
function Convert-HSLToRGB
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)][ValidateRange(0, 360)][double]$Hue,
        [Parameter(Mandatory = $true, Position = 1, ValueFromPipelineByPropertyName = $true)][ValidateRange(0, 1)][double]$Saturation,
        [Parameter(Mandatory = $true, Position = 2, ValueFromPipelineByPropertyName = $true)][ValidateRange(0, 1)][double]$Lightness
    )
    process
    {
        # You will need to check wikipedia for this. Essentially
        # We take a cube, and project it on to a 2d surface.
        # Which gives us a hexagon. Seriously, look at wikipedia. 
        # It weird to think about, but imaging a rubix cube, sitting on one of its corners.
        # If you look directly down at it there will be one corner in the middle, and 6 along the side
        # The chroma is the distance from the center of the hexagon
        # The Hue is our angle along this hexagon.
        # WIKIPEDIA LOOK AT IT.

        # Calculate the chroma
        $chroma = (1 - [Math]::Abs(2.0*$Lightness - 1.0)) * $Saturation
        
        # Figure out which section of the hexagon we are in. (6 sections)
        $H = $Hue / 60.0
        $X = $chroma * (1.0 - [Math]::Abs($H % 2 - 1))

        # Get value for lightness
        $m = $Lightness - 0.5 * $chroma
        $rgb = @($m, $m, $m)

        # UGH this part.
        # ok. So this is what happens. [R, G, B] is definited peicewise.
        # 0 <= H < 1 then [C, X, 0]
        # 1 <= H < 2 then [X, C, 0]
        # 2 <= H < 3 then [0, C, X]
        # 3 <= H < 4 then [0, X, C]
        # 4 <= H < 5 then [X, 0, C]
        # 5 <= H < 6 then [C, 0, X]
        # So these calculate the index of the x value and the c value
        $xIndex = (7 - [Math]::Floor($H)) % 3
        $cIndex = [int]($H / 2) % 3

        # Add the values in
        $rgb[$xIndex] += $X
        $rgb[$cIndex] += $chroma

        # Return the value
        return [pscustomobject]@{red = [int]($rgb[0] * 255); green = [int]($rgb[1] * 255); blue = [int]($rgb[2] * 255)}
    }
}

#
# Converts from Hue Saturation Value to RGB
#
function Convert-HSVToRGB
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)][ValidateRange(0, 360)][double]$Hue,
        [Parameter(Mandatory = $true, Position = 1, ValueFromPipelineByPropertyName = $true)][ValidateRange(0, 1)][double]$Saturation,
        [Parameter(Mandatory = $true, Position = 2, ValueFromPipelineByPropertyName = $true)][ValidateRange(0, 1)][double]$Value
    )
    process
    {
        # This one works very similar to the funciton above, so take a look there for comments
        $chroma = $Value * $Saturation
        $H = $Hue / 60.0
        $X = $chroma * (1.0 - [Math]::Abs($H % 2 - 1))

        $m = $Value - $chroma
        $rgb = @($m, $m, $m)

        $xIndex = (7 - [Math]::Floor($H)) % 3
        $cIndex = [int]($H / 2) % 3

        $rgb[$xIndex] += $X
        $rgb[$cIndex] += $chroma

        return [pscustomobject]@{red = [int]($rgb[0] * 255); green = [int]($rgb[1] * 255); blue = [int]($rgb[2] * 255)}
    }
}

#
# Converts from RGB to Hue Saturation Value
#
function Convert-RGBToHSV
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Red,
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Green,
        [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Blue
    )
    process
    {
        $arry = @(($red / 255), ($green / 255), ($blue / 255))
        $max = 0
        $min = 0
        for($i = 1; $i -lt $arry.Length; $i++)
        {
            if($arry[$i] -gt $arry[$max])
            {
                $max = $i
            }

            if($arry[$i] -lt $arry[$min])
            {
                $min = $i
            }
        }
        $C = $arry[$max] - $arry[$min]
        $hue = 0
        $saturation = 0
        if(0 -ne $C)
        {
            $hue = ($arry[($max + 4) % 3] - $arry[($max+5) % 3]) / $C

            if(0 -eq $max)
            {
                $hue %= 6
            }
            else
            {
                $hue += 2*$max
            }

            $hue *= 60
            $value = $arry[$max]
            $saturation = $C / $value
        }
        return [pscustomobject]@{hue = $hue; saturation = $saturation; value = $value}
    }
}

#
# Converts from RGB to Hue Saturation Lightness
#
function Convert-RGBToHSL
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Red,
        [Parameter(Mandatory=$true, Position=1, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Green,
        [Parameter(Mandatory=$true, Position=2, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Blue
    )
    process
    {
        $arry = @(($red / 255), ($green / 255), ($blue / 255))
        $max = 0
        $min = 0
        for($i = 1; $i -lt $arry.Length; $i++)
        {
            if($arry[$i] -gt $arry[$max])
            {
                $max = $i
            }

            if($arry[$i] -lt $arry[$min])
            {
                $min = $i
            }
        }
        $C = $arry[$max] - $arry[$min]
        $hue = 0
        $lightness = 0
        if(0 -ne $C)
        {
            $hue = ($arry[($max + 4) % 3] - $arry[($max+5) % 3]) / $C

            if(0 -eq $max)
            {
                $hue %= 6
            }
            else
            {
                $hue += 2*$max
            }

            $hue *= 60
            $lightness = 0.5 * ($arry[$min] + $arry[$max])
            $saturation = $C / (1 - [Math]::Abs(2.0 * $lightness - 1))
        }
        return [pscustomobject]@{hue = $hue; saturation = $saturation; lightness = $lightness}
    }
}

#
# Splits an integer RGB value into 3 parts
#
function Split-RGB
{
    param
    (
        [Parameter(Mandatory=$true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)][ValidateRange(0, 0xFFFFFF)][int]$RGB
    )
    process
    {
        return [pscustomobject]@{red = ($RGB -shr 16); green = (($RGB -shr 8) -band 0xFF); blue = ($RGB -band 0xFF)}
    }
}

#
# Combines the rgb components into a single value
#
function Join-RGB
{
    param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Red,
        [Parameter(Mandatory=$true, Position=1, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Green,
        [Parameter(Mandatory=$true, Position=2, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Blue
    )
    process
    {
        return ($Red -shl 16) -bor ($Green -shl 8) -bor $Blue
    }
}

#
# Just gets an rgb color object
#
function Get-RGBColor
{
    param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Red,
        [Parameter(Mandatory=$true, Position=1, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Green,
        [Parameter(Mandatory=$true, Position=2, ValueFromPipelineByPropertyName=$true)][ValidateRange(0, 0xFF)][int]$Blue
    )
    process
    {
        return [pscustomobject]@{red = $Red; green = $Green; blue = $Blue}
    }
}

# Test
# Join-RGB -Red 45 -Green 32 -Blue 222 | Split-RGB | Join-RGB | Split-RGB
# Get-RGBColor 10 20 30 | Convert-RGBToHSL | Convert-HSLToRGB
# Get-RGBColor 10 20 30 | Convert-RGBToHSV | Convert-HSVToRGB
# Get-RGBColor 10 20 30 | Convert-RGBToHSV | Convert-HSVToRGB | Convert-RGBToHSL | Convert-HSLToRGB
                            
                        
So yea. There is it. I hope someone can make use of these things. I don't really have I use for them, just a need to fight something throught until it is done. So my issue is that I was working on a side project, and we were using an external web service, which always returned colors in HSL. To be honest, I had no idea what that was, so I did some reading and had to write a function to convert to RGB. RGB makes SO much more sense... to me.



private static void FizzBuzz2() { Console.WriteLine( string.Join( Environment.NewLine, Enumerable.Range(1, 100) .Select( i => string.Join( string.Empty, i % 3 == 0 ? "fizz" : null, i % 5 == 0 ? "buzz" : null, !(i % 5 == 0 || i % 3 == 0) ? $"{i}" : null)))); }
raw
#
# Make bootable USB
# - use with caution
#
function Make-BootableUsb
{
    [CmdLetBinding()]
    param
    (
        [Parameter(Mandatory=$true)][String]$FileName,
        [Parameter(Mandatory=$true)][String]$DriveLetter
    )
    process
    {
        # Must be admin
        if(-not (Get-IsAdministrator))
        {
            throw 'Please try again as Administrator'
        }

        # sanity check
        if(-not (Test-Path $FileName))
        {
            throw "Could not find file $FileName"
        }

        # More sanity check
        if(-not $DriveLetter)
        {
            throw "Drive letter is not good"
        }

        # Get rid of colon for now
        $DriveLetter = $DriveLetter.TrimEnd(':')

        # Get the MSFT_PARTITION cim instance for the drive letter we want to destroy
		# This just needs to be one of the partitions on our USB. If there are multiple, we will kill them
		# DO NOT EXPECT YOUR STUFF TO LIVE
        $driveVolume = Get-CimInstance msft_partition -Namespace Root\Microsoft\Windows\Storage | Where DriveLetter -Match $DriveLetter

        # Could not find, exit
        if(-not $DriveVolume)
        {
            throw "Could not find disk $DriveLetter"
        }

        # The meat of this thing
        try
        {
            # Mount the disk image
            $MntfileInfo = Mount-DiskImage $FileName -PassThru

            # Get the drive letter of the volume
            $Mntvolume = ($MntfileInfo | Get-Volume).DriveLetter

            # Get the disk number of the USB
            $disk = Get-Disk -Number $driveVolume.DiskNumber
            
            # Destroy the file system on the disk. Remove everything
            $cleaned = $disk | Clear-Disk -RemoveData -PassThru -Confirm

            # Create a new partition and assign the previous drive letter
            $newPart = $cleaned | New-Partition -DriveLetter $driveVolume.DriveLetter -IsActive -UseMaximumSize
            
            #Create and NTFS filesystem on that disk
            $formatted = $newPart | Format-Volume -FileSystem NTFS
            
            # Make sure we actually made everything
            $dir = "$($driveVolume.DriveLetter):"
            if(-not (Test-Path $dir))
            {
                throw "well, we screwed up your drive"
            }

            # Move onto our empty disk
            pushd $dir
                
                # Write an MBR
                Invoke-Command -ScriptBlock { iex "bootsect.exe /nt60 $dir /force"}

                # Copy the image
                Invoke-Command -ScriptBlock {iex "xcopy /y /e /s $($Mntvolume):\ $dir\"}

            popd

            Write-Output "DONE"
        }
        finally
        {
            # Clean up
            if($MntfileInfo)
            {
                $MntfileInfo | Dismount-DiskImage
            }
        }
    }

}

#
# True if the user is in the admin role
#
function Get-IsAdministrator
{
    [CmdletBinding()]
    param
    (
    )
    process
    {
        foreach($role in Get-UserRoles)
        {
            if($role -match 'Administrator')
            {
                return $true
            }
        }
        return $false
    }
}

##
## Gets all user roles
##
function Get-UserRoles
{
    [CmdletBinding()]
    param
    (
    )
    process
    {
        $principal = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent();
        $roles = [System.Enum]::GetValues([Security.Principal.WindowsBuiltInRole])

        $output = @()
        foreach($role in $roles)
        {
            if($principal.IsInRole($role))
            {
                $output += $role
            }
        }

        return $output
    }
}
                            
                        
So what really happens here? There are 3 functions:
  • Get-UserRoles
  • Get-IsAdministrator
  • Make-BootableUsb
The first one Get-UserRoles just asks the OS what roles the current user is in. The second one Get-IsAdministrator is mostly just a wrapper around the first one, which checks to see if the user has the administrator role The last one is the big one. Make-BootableUsb Actually makes a bootable USB. This was a scary one to test... was super afraid that I was going to format my C: drive. Actually funny story, I did accidently format one of my drives while trying to automate something with DISKPART once. Oh that brings me to another point. You can see we don't use DISKPART here. At first I was going to, but why not use the PowerShell functions that are available.
Anyway, I think the code is pretty well documented. So it should be decently simple to understand. Most importantly, this does actually completely clear and format a disk, so use with caution, it is totally possible that it could mess up and delete something important.



Powershell FizzBuzz

Jul05.16 12AM

So lets say you are on a flight from DC to Seattle, and you forgot to download music to your phone. What a crappy hypothetical situation. Luckily, you have your trusty laptop, and a lack of creativity. So here we go, lets write FizzBuzz in powershell. The rules are simple. For all of the numbers between 1 and 100:
  • If the number is divisible by 3, print 'fizz'
  • If the number is divisible by 5, print 'buzz'
  • If the number is divisible by both 3 and 5, print 'fizzbuzz'
  • Otherwise print the number
Simple enough. The program practically writes itself. What recruiter wouldn't be impressed by fizzbuzz in powershell.
raw
for($i = 1; $i -le 100; $i++)
{
    if($i % 3 -eq 0)
    {
        Write-Host 'fizz' -NoNewline
    }
    if($i % 5 -eq 0)
    {
        Write-Host 'buzz' -NoNewline
    }
    elseif($i % 3 -ne 0)
    {
        Write-Host $i -NoNewline
    }
    Write-Host
}
                            
                        
Great that took about 30 seconds. So let's try something a little harder. Lets squish this into one confusing line. That's what scripting languages are for anyway right? You aren't cool until you can sqeeze a script down into a tiny confusing line of code.
raw
(1..100) | ForEach-Object { $out = $null; if($_ % 3 -eq 0){$out = 'fizz'} if($_ % 5 -eq 0){$out += 'buzz'} if(-not $out){$out = $_} $out}
                            
                        
Thats better. But I don't think its confusing enough yet. Lets use some of the preset aliases: '%' and 'oh'. '%' is short for "ForEach-Object" and 'oh' is short for "Out-Host". Where does that put us?
raw
(1..100)|%({if(-not($_%3)){$$='fizz'}if(-not($_%5)){$$+='buzz'}if(-not$$){$$=$_}$$|oh;$$=$__})
                            
                        
Now that's a mess. I am sure we can make this even shorter, but I am a little too sleepy now. Anyway, there is the elusive 1 liner powershell fizzbuzz solution.



© 2017 - Peter Sulucz | disclaimer

log in