Another Way to Show Bitwise Operation Results

This is something that came to me as I was working to do some bitwise operations for a project that had a lot of pInvoke stuff and required that I do some shifting of bits. Being that I wasn’t all that familiar with this (I’m more familiar with BOR, BAND and XOR), I wanted to learn more about the before and after of the binary representation of the data.

What is a bitwise operation you ask? Well, it is

a bitwise operation operates on one or more bit patterns or binary numerals at the level of their individual bits. It is a fast, primitive action directly supported by the processor, and is used to manipulate values for comparisons and calculations. –From Wikipedia Article on Bitwise Operations

I decided that it would be nice to have a function that would allow you to provide the parameters needed for a bitwise operation, but rather than just outputting a value as a result of the operation, it would instead show you more information about the results such as showing the values in binary and hex form. But that wasn’t all I wanted. I saw the about_Comparison_Operators help file and liked the examples that they showed when doing an operation.

image

Putting this all together led me to a function I wrote called Invoke-BitwiseOperation which accepts a –First and –Second parameter which is for the two values, a –BitwiseOperator parameter that accepts the following values: BAND,BOR,BXOR,BNOT,SHL,SHR and finally there is the –Graphical parameter which gives you the output like you see in the help files.

I start out by using a helper function called ConvertToBinary which takes an integer, converts it to a binary form and then uses a RegEx pattern to split out the binary data into chunks of 8.

Function ConvertToBinary {
    Param(
        [parameter(ValueFromPipeline=$True)]
        $Item
    )
    Process {
        $String = [Convert]::ToString($Item,2)
        $Reverse = -join (-join $string[$String.length..0] -split '(?<=\G.{8})').PadRight(8,'0')
        -join $Reverse[$Reverse.length..0] -split '(?<=\G.{8})'
    }
}

(8956 | ConvertToBinary) -join ' '

bitwise_2

I opted to not join the output prior so I could do some more stuff with the collection of values later on in my code.

If ($BitWiseOperator -eq 'BNOT') {
    $Result = [Math]::Abs((Invoke-Expression "-$($BitWiseOperator) $($First)"))
} Else {
    If ($PSBoundParameters.ContainsKey('First') -AND $PSBoundParameters.ContainsKey('Second')){
        $Result = Invoke-Expression "$($First) -$($BitWiseOperator) $($Second)"
    } Else {
        Write-Warning "You must specify both a First and Second parameter!"
        BREAK
    }
}
$First_Bin = $First | ConvertToBinary
$First_Hex = "0x{0:x}" -f $First
If ($PSBoundParameters.ContainsKey('Second') -AND $BitWiseOperator -notmatch 'SHL|SHR') {
    $Second_Bin = $Second | ConvertToBinary
    $Second_Hex = "0x{0:x}" -f $Second
}
$Result_Bin = $Result | ConvertToBinary   
$Result_Hex = "0x{0:x}" -f $Result

This portion looks at what kind of Bitwise operator that I specified and takes an action based on that, such as when using BNOT. I also perform the conversion of the values to binary and also convert the data to hex for later use.

If ($PSBoundParameters.ContainsKey('Graphical')) {
    $Padding = '00000000'
    $FirstList = New-Object System.Collections.ArrayList
    $SecondList = New-Object System.Collections.ArrayList
    $ResultList = New-Object System.Collections.ArrayList

    $FirstHex = "0x{0:x}" -f $First
    $SecondHex = "0x{0:x}" -f $Second
    $ResultHex = "0x{0:x}" -f $Result
 
    $First_Bin | ForEach {
        [void]$FirstList.Add($_)
    }
    $Second_Bin | ForEach {
        [void]$SecondList.Add($_)
    }
    $Result_Bin | ForEach {
        [void]$ResultList.Add($_)
    }
   


    $Count = $FirstList, $SecondList, $ResultList | ForEach {
        [pscustomobject]@{
            Count = $_.count
        }
    } | Sort Count -Descending | Select -First 1 -ExpandProperty Count
 
    $FirstList, $SecondList, $ResultList | ForEach {
        $ToPad = $Count - $_.Count
        If ($ToPad -gt 0) {                
            For ($i=1; $i -le $ToPad; $i++) {
                $_.Insert(0,$Padding)
            }
        }
    }
 
    $Line = '-' * (($ResultList -join ' ').Length)
 
 
    "$($FirstList -join ' ')  ($First, $($FirstHex)"
    If ($BitWiseOperator -notmatch 'BNOT|SHL|SHR') {
        "$($SecondList -join ' ')  ($Second, $($SecondHex)"
    }
    "$line  $BitWiseOperator"
    "$($ResultList -join ' ')  ($result, $($ResultHex)"
 
} Else {
    [pscustomobject]@{
        First = $First
        First_Bin = $First_Bin
        First_Hex = $First_Hex
        BitWiseOperator = $BitWiseOperator
        Second = $Second
        Second_Bin = $Second_Bin
        Second_Hex = $Second_Hex
        Result = $Result
        Result_Bin = $Result_Bin
        Result_Hex = $Result_Hex
    }
}

The final portion of the script takes a turn based on if the –Graphical parameter is used or not. If used, some more data processing occurs so it can display the data like what you saw in the help file. Otherwise, it just outputs an object with the converted values. Some examples are shown below.

Invoke-BitWiseOperation -First 32 -Second 16 -BitWiseOperator SHL –Graphical

Bitwise_demo

Invoke-BitWiseOperation -First 7 -BitWiseOperator BNOT

Bitwise_demo

Download Invoke-BitwiseOperation

https://gallery.technet.microsoft.com/scriptcenter/Invoke-BitwiseOperation-bc2f3c80

Posted in powershell | Tagged , , , | 4 Comments

Port Checking and Implementing Pipeline Support in Functions on MCPMag

I’ve had a couple of other articles come out on MCPMag with one that deals with port checking using PowerShell while the latest one talks about implementing pipeline support in a PowerShell function. Check them out and let me know what you think!

Port Checking Using PowerShell

Building PowerShell Functions That Support the Pipeline

Posted in powershell | Tagged , , , , | Leave a comment

Looking at Local Accounts Using PowerShell on MCPMag

I have a couple of articles out on MCPMag.com talking about working with local user accounts and reporting on accounts. Check the out and let me know what you think!

Reporting on Local Accounts Using PowerShell

Managing Local User Accounts with PowerShell

Posted in powershell | Tagged , , | Leave a comment

A Look at Implementing $Using: Support in PowerShell for PoshRSJob

After I made my initial release of PoshRSJob, one of the things left that I wanted to accomplish was implementing the $Using: scope that is found when using Invoke-Command or Start-Job which allows you to use an existing variable in the current console session and send that over to the scriptblock for the PSJob. This is pretty cool and allows for easier flow of sending data to a scriptblock in a PSJob. Naturally, if my module was going to be an alternative to the current infrastructure, it needed this capability as well. The problem is that determining how this works isn’t quite as easy as it seems. A couple of options would include looking at using RegEx or the PSParser to maybe make this happen. I will say that to provide support for PowerShell V2, I had to resort to these approaches, but more on that later.

After some digging  around in the language using DotPeek, I found where call was being made to take an existing scriptblock (with parameters) that have $Using and then does some conversion behind the scenes that will add the variable automatically to the Param() block and adjusts the $Using: variable within the scriptblock as well.

Of course, converting this C# code to PowerShell isn’t always straight forward, especially when we cannot just use some of the methods that they use without bringing some reflection skills into play.

V3+ Attempt

So, lets get going with taking the following scriptblock and converting it so we can take advantage of $Using: and see how it works.

## Scriptblock
$Data = 42
$Computername = $env:COMPUTERNAME
$ScriptBlock = {
    [pscustomobject]@{
        Computername = $Using:Computername
        Output = ($Using:Data * 2)
    }
}

Here we have our data and then our script block which contains our $Using: variables. Note that in this example I do not have anything in a Param() block (I will show another example after this with a Param() block) so we will have an extra step at the end to build this out.

Next up is using some AST magic (System.Management.Automation.Language.UsingExpressionAst) to parse out the Using variables by looking at the AST on the script block:

$UsingVariables = $ScriptBlock.ast.FindAll({
    $args[0] -is [System.Management.Automation.Language.UsingExpressionAst]
},$True)

What that gives us is the following output:

image

With this information, I now need to go and grab the actual values for each variable and then put that into an object that includes what the converted $Using variable will look like in the new script block.

$UsingVariableData = ForEach ($Var in $UsingVariables) {
    Try {
        $Value = Get-Variable -Name $Var.SubExpression.VariablePath.UserPath -ErrorAction Stop
        [pscustomobject]@{
            Name = $Var.SubExpression.Extent.Text
            Value = $Value.Value
            NewName = ('$__using_{0}' -f $Var.SubExpression.VariablePath.UserPath)
            NewVarName = ('__using_{0}' -f $Var.SubExpression.VariablePath.UserPath)
        }
    } Catch {
        Throw "$($Var.SubExpression.Extent.Text) is not a valid Using: variable!"
    }
}

image

Notice how these are now renamed with the $__using_ now instead of their original name. This is important with how we convert the script block later on. Keep in mind that the original script block still has the original values.

Now we start setting up for the script block conversion by creating a couple of collections to hold some data. One of those required is a Tuple type that will hold a particular AST type of VariableExpressionAST.

$List = New-Object 'System.Collections.Generic.List`1[System.Management.Automation.Language.VariableExpressionAst]'
$Params = New-Object System.Collections.ArrayList

Assuming that we have Using variables, we can begin adding each item into our list collection.

If ($UsingVariables) {        
    ForEach ($Ast in $UsingVariables) {
        [void]$list.Add($Ast.SubExpression)
    }

With that done, next up is to work with our soon to be new parameters and adding the current values with the new values into our created Tuple.

[void]$Params.AddRange(($UsingVariableData.NewName | Select -Unique))
$NewParams = $Params -join ', '
$Tuple=[Tuple]::Create($list,$NewParams)

image

Now for some fun stuff! We need to use Reflection to hook into a nonpublic method that basically does all of the magic of converting the script block data into something that will be usable.

$bindingFlags = [Reflection.BindingFlags]"Default,NonPublic,Instance"
$GetWithInputHandlingForInvokeCommandImpl = ($ScriptBlock.ast.gettype().GetMethod('GetWithInputHandlingForInvokeCommandImpl',$bindingFlags))
$StringScriptBlock = $GetWithInputHandlingForInvokeCommandImpl.Invoke($ScriptBlock.ast,@($Tuple

))

image

Pretty cool, right? As I mentioned earlier, we need to build out a param() block still. This is due to one not already existing. Had I added a Param() block in the script block:

$ScriptBlock = {
    Param($Param1)
    [pscustomobject]@{
        Computername = $Using:Computername
        Output = ($Using:Data * 2)
    }
}

The output would look more like this:

image

Note how the $Param1 has been pushed to the very end while all of the new $__using variables are near the beginning.

Ok, with that out of the way, we will go back to dealing with our first example and adding our new Param() block.

If (-NOT $ScriptBlock.Ast.ParamBlock) {
    Write-Verbose "Creating Param() block" -Verbose
    $StringScriptBlock = "Param($($NewParams))`n$($StringScriptBlock)"
    [scriptblock]::Create($StringScriptBlock)
} Else {
    Write-Verbose "Param() will be magically updated!" -Verbose
    [scriptblock]::Create($StringScriptBlock)
}
}

And with that, we now have a script block that has been completely converted to support the $Using: variables! Of course, since I am using a nonpublic method to accomplish this, it does mean that this could be changed in a future release and could potentially break what I am doing.

What about V2 you ask? Well, since we do not have access to AST or the nonpublic method of ‘GetWithInputHandlingForInvokeCommandImpl’ to use for the conversion, we must resort to doing some of our own magic using the PSParser and RegEx.

V2 Using Attempt

We are going to use the same script block with just a minor change to full support V2:

$Data = 42
$Computername = $env:COMPUTERNAME
$ScriptBlock = {
    Param($TestParam)
    New-Object PSObject -Property @{
        Computername = $Using:Computername
        Output = ($Using:Data * 2)
    }
}

I am also going to use a function as well to make working with PSParser easier to convert a script block.

Function IsExistingParamBlock {
    Param([scriptblock]$ScriptBlock)
    $errors = [System.Management.Automation.PSParseError[]] @()
    $Tokens = [Management.Automation.PsParser]::Tokenize($ScriptBlock.tostring(), [ref] $errors)       
    $Finding=$True
    For ($i=0;$i -lt $Tokens.count; $i++) {       
        If ($Tokens[$i].Content -eq 'Param' -AND $Tokens[$i].Type -eq 'Keyword') {
            $HasParam = $True
            BREAK
        }
    }
    If ($HasParam) {
        $True
    } Else {
        $False
    }
}

Now we start pulling the $Using: variables by using the PSParser and looking at the tokens. I will also go ahead and pull the actual values of each variable and do the naming conversion just like I did with the previous example.

$errors = [System.Management.Automation.PSParseError[]] @()
$Tokens = [Management.Automation.PsParser]::Tokenize($ScriptBlock.tostring(), [ref] $errors)
$UsingVariables = $Tokens | Where {
    $_.Content -match '^Using:' -AND $_.Type -eq 'Variable'
}
$UsingVariable = $UsingVariables | ForEach {
    $Name = $_.Content -replace 'Using:'
    New-Object PSObject -Property @{
        Name = $Name
        NewName = '$__using_{0}' -f $Name
        Value = (Get-Variable -Name $Name).Value
        NewVarName = ('__using_{0}') -f $Name
    }
}

image

Now we get to the meaty part of this article by using quite a bit of code to work through the script block conversion.

$StringBuilder = New-Object System.Text.StringBuilder
$UsingHash = @{}
$UsingVariable | ForEach {
    $UsingHash["Using:$($_.Name)"] = $_.NewVarName
}
$HasParam = IsExistingParamBlock -ScriptBlock $ScriptBlock
$Params = New-Object System.Collections.ArrayList
If ($Script:Add_) {
    [void]$Params.Add('$_')
}
If ($UsingVariable) {        
    [void]$Params.AddRange(($UsingVariable | Select -expand NewName))
} 
$NewParams = $Params -join ', '  
If (-Not $HasParam) {
    [void]$StringBuilder.Append("Param($($NewParams))")
}
For ($i=0;$i -lt $Tokens.count; $i++){
    #Write-Verbose "Type: $($Tokens[$i].Type)"
    #Write-Verbose "Previous Line: $($Previous.StartLine) -- Current Line: $($Tokens[$i].StartLine)"
    If ($Previous.StartLine -eq $Tokens[$i].StartLine) {
        $Space = " " * [int]($Tokens[$i].StartColumn - $Previous.EndColumn)
        [void]$StringBuilder.Append($Space)
    }
    Switch ($Tokens[$i].Type) {
        'NewLine' {[void]$StringBuilder.Append("`n")}
        'Variable' {
            If ($UsingHash[$Tokens[$i].Content]) {
                [void]$StringBuilder.Append(("`${0}" -f $UsingHash[$Tokens[$i].Content]))
            } Else {
                [void]$StringBuilder.Append(("`${0}" -f $Tokens[$i].Content))
            }
        }
        'String' {
            [void]$StringBuilder.Append(("`"{0}`"" -f $Tokens[$i].Content))
        }
        'GroupStart' {
            $Script:GroupStart++
            If ($Script:AddUsing -AND $Script:GroupStart -eq 1) {
                $Script:AddUsing = $False
                [void]$StringBuilder.Append($Tokens[$i].Content)                    
                If ($HasParam) {
                    [void]$StringBuilder.Append("$($NewParams),")
                }
            } Else {
                [void]$StringBuilder.Append($Tokens[$i].Content)
            }
        }
        'GroupEnd' {
            $Script:GroupStart--
            If ($Script:GroupStart -eq 0) {
                $Script:Param = $False
                [void]$StringBuilder.Append($Tokens[$i].Content)
            } Else {
                [void]$StringBuilder.Append($Tokens[$i].Content)
            }
        }
        'KeyWord' {
            If ($Tokens[$i].Content -eq 'Param') {
                $Script:Param = $True
                $Script:AddUsing = $True
                $Script:GroupStart=0
                [void]$StringBuilder.Append($Tokens[$i].Content)
            } Else {
                [void]$StringBuilder.Append($Tokens[$i].Content)
            }                
        }
        Default {
            [void]$StringBuilder.Append($Tokens[$i].Content)         
        }
    } 
    $Previous = $Tokens[$i]   
}

Now we take that string and make it into a script block.

[scriptblock]::Create($StringBuilder.ToString())

image

Of course, using the PSParser does mean that it is possible for things to get missed if the variables are nested deep in something such as this:

Write-Verbose $($Using:Computername) –Verbose

Our $Using:Computername variable will be completely skipped, thus making it harder to go through with the conversion. Just something to keep in mind if you are using V2 and trying to get PoshRSJob to work properly.

This is definitely a one-off thing that I am doing, but wanted to share some of how I was able to provide some $Using support in my module. Hopefully this provides a little more insight into that and maybe gets you looking to explore more about the internals of PowerShell!

Posted in powershell | Tagged , , , | 1 Comment

Latest Updates to PoshRSJob

I felt the need to make a follow up to address some new updates to my module, PoshRSJob. I had my initial post which covered most of the basics of this module and covered the majority of the functions which are available to use.

Better Pipeline Support for Variables in Scriptblock

Previously, If you wanted to send the piped data into the scriptblock (which is a big thing for this project), you had to specify a Param() block in the scriptblock and specify a variable that would serve as the data coming from the pipeline into Start-RSJob like this:

1..10 | Start-RSjob -ScriptBlock {
    Param($Number)
    [pscustomobject] @{
        Number = $Number
        DoubleIt = ($Number * 2)
    }
}

This way is no longer supported (if enough people want it back, then I will look at adding it back in) and has now been replaced by the removal of the Param() block and just using $_ in your scriptblock.

1..10 | Start-RSjob -ScriptBlock {
    [pscustomobject] @{
        Number = $_
        DoubleIt = ($_ * 2)
    }
}

image

We now have a much cleaner approach of handling the data coming from the pipeline which means less code to write. Don’t worry if you use another $_ in a ForEach block as it will handled appropriately.

The Param() block will still exist if you have data coming from the –ArgumentList parameter and also keep in mind that $Using: is still available as well in PowerShell V2 and above.

$Test = 42
$AnotherTest = 7
$String = 'SomeString'
$ProcName = 'powershell_ise'
$ScriptBlock = {
    Param($y,$z)
    [pscustomobject] @{
        Test = $y
        Proc = (Get-Process -Name $Using:ProcName)
        String = $Using:String
        AnotherTest = ($z+$_)
        PipedObject = $_
    }
}

1..5|Start-RSJob $ScriptBlock -ArgumentList $test, $anothertest

Get-RSJob | Receive-RSJob

image

A New Function

The second thing that I am going to highlight is a new function called Wait-RSJob, which as it sounds, will wait for the RSJobs to finish up before allowing access to the console again. It will also output the RSJob type by default which is useful if you wanted to chain some commands together. There is also a timeout which means that it will stop waiting for the RSJob to finish and allow access to the console again. If you have ever used Wait-Job, then you are already an expert at using this function.

A quick example is right here:

1..10 | Start-RSJob -ScriptBlock {
    Start-Sleep -Seconds (Get-Random (5..10))
    $_
} |Wait-RSJob

image

Chaining the commands together:

1..10 | Start-RSJob -ScriptBlock {
    Start-Sleep -Seconds (Get-Random (5..10))
    $_
} |Wait-RSJob | Receive-RSJob

image

Lastly, using the timeout parameter for 4 seconds:

1..10 | Start-RSJob -ScriptBlock {
    Start-Sleep -Seconds (Get-Random (5..10))
    $_
} |Wait-RSJob -Timeout 4

image

This function comes courtesy of Ryan Bushe who was nice enough to put this together.

Pester Testing

Thanks goes out to Warren, AKA psCookieMonster for taking the time to set up some Pester and AppVeyor testing out on Github. Pester is something that I want to work more with and is definitely on my TODO list.

Bugs and Other Things

Besides those additions, the rest of the things that have been added were mostly bug fixes in various parts of code as well as some behind the scenes tweaks.

Hopefully those of you who are using this module have been enjoying it and find it useful in your day to day activities! As always, if you run into issues, have requests for improvement, just let me know or you can work on it yourself and submit a Pull Request out on Github.

PoshRSJob Site

Posted in powershell | Tagged , | 4 Comments