Coming Soon: PowerShell Blogging Week

Beginning March 30th and running until April 4th, a handful of PowerShell MVPs and enthusiasts will be taking part in PowerShell Blogging Week. This is the first time that we are attempting this and what we have in store if a weeks worth of topics about various pieces of PowerShell.

What are we covering? Well, that will remain a secret until each article is published. Just be sure to watch Twitter with the hashtag #PSBlogWeek.

What I can do is show you who is writing during the week so you can better watch for those articles!

Name

Twitter

Blog

Adam Bertram

@adbertram

http://www.adamtheautomator.com

Mike F. Robbins

@mikefrobbins

http://mikefrobbins.com/

Boe Prox

@proxb

https://learn-powershell.net/

Francois-Xavier Cat

@lazywinadm

http://www.lazywinadmin.com/

June Blender

@juneb_get_help

http://www.sapien.com/blog/

Jeffrey Hicks

@JeffHicks

http://jdhitsolutions.com/

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

Slides and Example Code From Nebraska.Code() Conference Session Available

I had the great opportunity to speak at Nebraska.Code() over the weekend in which I talked about Trend Reporting using PowerShell and SQL. This was a great opportunity and my 1st conference speaking gig that I have done. I appreciate everyone who attended and provided some excellent feedback during the session.

My slide deck and code examples are available below on Nebraska.Code’s github repo to download. Feel free to check them out and let me know what you think!

https://github.com/nebraskacode/2015-Slides-and-Demos/tree/master/Trend_Reporting_Using%20SQL_and_PowerShell

Posted in powershell | Tagged , , , | 1 Comment

MCPMag Articles on Exploring PowerShell

My series of articles for this month on MCPMag.com talk about exploring PowerShell using a few of the available cmdlets. I’ll update the links as each new article goes live below.

Exploring PowerShell, Part 1: Using Get-Command

Exploring PowerShell, Part 2: Learn the Commands Using Get-Help

Exploring PowerShell, Part 3: Using Get-Member To Dig into .NET Objects

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

Checking for a TCP Listener Connection

I’ve been spending some time re-writing my PoshChat project to replace various things that I feel could have been written better as well as trying to knock out some of the issues that I had in the beginning but just never got around to fixing. One of those items was how I was using the System.Net.Sockets.TcpListener and setting it up to listen for new connections and then handling those connections (usually in another runspace) so I still have the room to handle other new connections.

The ‘Old” Way

The big issue here is that I was using the AcceptTCPClient() method, which presents a blocking call on the console. This means that I cannot do anything else at all, which really wasn’t an issue for me because I had all of this operating in its own runspace. The code snippet below shows the setting up of the runspace that will be handling the listener as well as when connections happen.

$SharedData = [HashTable]::Synchronized(@{})
$Listener = [HashTable]::Synchronized(@{})

#Initial runspace creation to set up server listener 
$NewRunspace = [RunSpaceFactory]::CreateRunspace()
$NewRunspace.Open()
$NewRunspace.SessionStateProxy.setVariable("sharedData", $sharedData)
$NewRunspace.SessionStateProxy.setVariable("Listener", $Listener)
$NewPowerShell = [PowerShell]::Create()
$NewPowerShell.Runspace = $NewRunspace
$sb = {
     $Listener['listener'] = [System.Net.Sockets.TcpListener]15600
     $Listener['listener'].Start()
    while($true) {
    [byte[]]$byte = New-Object byte[] 1024
    $client = $Listener['listener'].AcceptTcpClient()
    If ($client -ne $Null) {
        $stream = $client.GetStream()
        # ... #
    } Else {
        #Connection to server closed
        Break
    }
    }#End While
}
$Handle = $NewPowerShell.AddScript($sb).BeginInvoke()

You can see where I begin using AcceptTCPClient() which presents the blocking call. What happens is that at this point I have no way to break out of this call. Even if I were to change the $True to $False in my While() {} statement, it wouldn’t matter because of the blocking call. Obviously, this presents an issue if I wanted to halt my chat server which would mean completely halting the PowerShell process to effectively stop the listener.

The “New” Way using Pending()

The solution that I have found involves using the Pending() method of the listener object. By still using a loop and instead calling the Pending() method which will return $True for a connection that is attempting to be made to the listener and $False if no connections are being attempted, we can keep from blocking the runspace and allow us to inject a variable update to halt the loop if we wanted to shut down the server. Let’s give it a shot and see what happens.

First we need to start out listener:

#Create the listener and kick it off
$Listener = [System.Net.Sockets.TcpListener]15600 
$Listener.Start()

image

Ok, now if we check for pending connections, we will get back a False, meaning that there are no connections currently being attempted.

$Listener.Pending()

image

Since that is the case, I would simply start a sleep cycle for a second and check again. But now let’s assume that a connection was attempted (using the code below) and we can check again to see what happens.

#Connect to server
$Server = 'Boe-PC'
$Endpoint = new-object System.Net.IPEndpoint ([ipaddress]::any,$SourcePort)
$Client = [Net.Sockets.TCPClient]$endpoint  
$Client.Connect($Server,15600)

Now we can check for pending connection attempts.

image

Looks like we have a connection being made, so we had better act on it by calling the AcceptTCPClient() method. We also can open up a stream during this process as well.

$Client = $Listener.AcceptTcpClient() 
$ClientConnections = $Client  
$ClientStream = $Client.GetStream()         
Write-Verbose ("[$(Get-Date)] New Connection from {0} <{1}>!" -f 
$Client.Client.RemoteEndPoint.Address, $Client.Client.RemoteEndPoint.Port) –Verbos

e

image

Perfect! Now we can begin doing whatever should be done with this new connection. In this case, I am not going to do anything with it, but in PoshChat, this would get handed off to another runspace to handle the client connection and stream for messaging and the listener would be back watching for new connections.

By watching for Pending() connections, we avoid being blocked by the AcceptTCPClient() method and can then easily close our listener up without completely trashing our current PowerShell console.

Hopefully this approach helps you out if you happen to be working with client connections to a listener and provides a way to more easily handle tracking those new connections to the listener without completely taking away your ability to shut down the listener.

Posted in powershell | Tagged , , , | 1 Comment

A Look at Filtering Performance in PowerShell

While working on a script for work, I ran into a situation where I needed to some filtering on a bunch of data and the thought struck me as to what was the quickest approach to performing a filter of data. We know that Where-Object is the official filtering cmdlet with PowerShell and that it gets the job done without much issue. With PowerShell V4, we also got the .Where() method which is built for Desired State Configuration, but has uses outside of that in terms of performance vs. using Where-Object, but at the expense of having all of the data stored in memory prior to performing the filter whereas Where-Object takes input from the pipeline and processes each item to see what matches the filter.

Edit: I should know better than to write late at night, but thanks to Dave for catching that I didn’t have my TestFunction configured to match our Filter. As mentioned, while the pipeline is an amazing piece of PowerShell, it can be expensive with performance.

Where Do We Begin?

I wanted to just do a simple filter just to see how the performance would be. So with that I will use $%2 which will evaluate each number ($) to $True on odd numbers and $False on even numbers. This will allow me to look to only filter only for odd numbers.

 
1..4|ForEach {
    If ($_%2){
        "{0}: Odd" -f $_
    }Else{
        "{0}: Even" -f $_
    }
}

image

As I said, its very simple with no complexity at all, but it is all I need for testing.

Now that we have that taken care of, the next step is to look at as many possible ways to filter data that I can think of. Now this is an exhaustive list of filtering possibilities, but it has enough ways to show where performance is great down to where it is lacking as we deal with more data.

Next up is looking at those possible filtering techniques which will range from using a cmdlet to a method to some other techniques that you may not have seen before.

The eleven filtering methods that I will be testing are as follows:

  • ForEach() {}
  • | ForEach {}
  • | Where-Object {}
  • .Where({})
  • PowerShell Filter (see below for source code)
  • PowerShell Filter with Parameter (see below for source code)
  • .{Process {}}
  • Using [Predicate[Object]] (see below for source code)
  • .ForEach({})
  • PowerShell Function using parameter (see below for source code)
  • PowerShell Function with Pipeline (see below for source code)

Source Code for Custom Methods

PowerShell Filter

Dating back to V1, this was the original way to send data via the pipeline to a custom command. It is still very much useful with V5 to provide a quick way to filter out data.

 
Filter TestFilter {   
    If ($_%2){$_}
}

PowerShell Filter with Parameter

Because I wanted to include a parameter that lets you set a predicate vs. hard coding one.

 
Filter TestFilter_Predicate {
    Param ($Predicate)   
    If (&$Predicate){$_}
}

Predicate Object

I use this with some of my UIs to quickly filter data; figured it would make for a good filter method here as well.

 
$t = [System.Windows.Data.CollectionViewSource]::GetDefaultView($List)
$t.Filter = [Predicate[Object]]{
    Try {
        $args[0] % 2
    } Catch {$True}
}

PowerShell Function

The PowerShell functions we know and love that supports the pipeline. I’ll test both the pipeline approach as well as using the –InputObject parameter.

Function TestFunction {
    [cmdletbinding()]
    Param(
        [parameter(ValueFromPipeline)]
        $InputObject
    )
    Process {
        If ($_%2){$_}
    }
}
Function TestFunction_param {
    [cmdletbinding()]
    Param(
        $InputObject
    )
    ForEach ($item in $InputObject){
        If ($item%2){$item}
    }
}

Of course, the data returned varies based on how many resources are being consumed on your computer.

Let’s see the data!

I am going to be posting the source code that I will be using to provide the results below so you can take it and use it for your own testing.

I am going to look at running the tests against the following collection of count of numbers: 10,100,1000,10000,100000 and pull only the odd numbers from that list. What we have below are the results of the tests with each count grouped together and sorted from fastest to slowest. The fastest has green font while the slowest one has red font.

Filter1 Filter2

Here we can see that the winners are split between using ForEach(){} and the TestFunction using a parameter while using Where-Object and a Function taking pipeline input (the updated function still wasn’t the fastest approach, but it is no longer in the top two slowest after taking out the unneeded pipeline within the function) turn out to be the slowest approaches (although applying a parameter to our Filter definitely slows it down as we start adding more data). The Filter performed admirably as well as using .{Process{}} to do the filtering. Some of these approaches, such as top two winners, require that you have enough memory to support keeping all of the data prior to performing the filter. If you want just a little bit slower performance (and I do mean a little), you can rely on the pipeline and save memory by using a Filter or looking at .{Process{}} instead.

Of course, a graph can show just how these approaches scale out over the course of adding more data to each set.

FilterGraph

Now let’s break this out to see how each of these handles more data so you can get a better idea as to what is going on.

FilterGraph1 FilterGraph2 FilterGraph3 FilterGraph4 FilterGraph5 FilterGraph6 FilterGraph7 FilterGraph8 FilterGraph9 FilterGraph10 FilterGraph11

Only a few graphs, right?

In the end, what we have seen is that while Where-Object is the most well known filtering approach in PowerShell, if you are really looking to squeeze each and every possible millisecond from your commands, you might want to look at some alternative approaches to filtering your data, such as a Filter if you don’t want to exhaust memory. Some approaches like building out a predicate is probably just silly, but I wanted to use everything that I could think of in my tests, which also doesn’t really do anything all that complex at all.

Unless there is a pressing need to work with a ton of data, I will still rely mostly on Where-Object to accomplish what I need to do. Because it is simple and gets the job done without much thought involved (unless your filtering queries are complex, of course).

The source code for my testing is available below. Give it a shot and let me know how the results look for you. Speaking of which, if you think I missed something or have other recommendations, feel free to let me know or post up your results here!

Source Code

 
Filter TestFilter {   
    If ($_%2){$_}
}
Function TestFunction {
    [cmdletbinding()]
    Param(
        [parameter(ValueFromPipeline)]
        $InputObject
    )
    Process {
        If ($_%2){$_}
    }
}
Function TestFunction_param {
    [cmdletbinding()]
    Param(
        $InputObject
    )
    ForEach ($item in $InputObject){
        If ($item%2){$item}
    }
}
Filter TestFilter_Predicate {
    Param ($Predicate)   
    If (&$Predicate){$_}
}
 
[decimal[]]$Count = 1E1,1E2,1E3,1E4,1E5,1E6
$Data = ForEach ($Item in $Count) {
    $List = 1..$Item
    Write-Verbose "Testing for Count: $($Item)" -Verbose
    $Seconds = (Measure-Command {$List|Where{$_%2}}).TotalSeconds
    [pscustomobject]@{
        Type = 'Where-Object Filter <Pipeline>'
        IsPipeline = $True
        Time_seconds =$Seconds
        Count = $Item
    }
    $Seconds = (Measure-Command {$List.Where({$_%2})}).TotalSeconds
    [pscustomobject]@{
        Type = '.Where() Filter'
        IsPipeline = $False
        Time_seconds =$Seconds
        Count = $Item
    }
 
    $Seconds = (Measure-Command {$List|ForEach{If($_%2){$_}}}).TotalSeconds
    [pscustomobject]@{
        Type = 'ForEach Filter <Pipeline>'
        IsPipeline = $True
        Time_seconds =$Seconds
        Count = $Item
    }
    $Seconds = (Measure-Command {$List.ForEach({If($_%2){$_}})}).TotalSeconds
    [pscustomobject]@{
        Type = '.ForEach Filter'
        IsPipeline = $False
        Time_seconds =$Seconds
        Count = $Item
    }
    $Seconds = (Measure-Command {ForEach ($Item in $List){If($Item%2){$Item}}}).TotalSeconds
    [pscustomobject]@{
        Type = 'ForEach Filter'
        IsPipeline = $False
        Time_seconds =$Seconds
        Count = $Item
    }
 
    $Seconds = (Measure-Command {$list | .{process{If($_%2){$_}}}}).TotalSeconds
    [pscustomobject]@{
        Type = '.{Process{}} Filter <pipeline>'
        IsPipeline = $True
        Time_seconds =$Seconds
        Count = $Item
    }
 
    $Seconds = (Measure-Command {$List|TestFunction}).TotalSeconds
    [pscustomobject]@{
        Type = 'TestFunction Filter <Pipeline>'
        IsPipeline = $True
        Time_seconds =$Seconds
        Count = $Item
    }

    $Seconds = (Measure-Command {TestFunction_param $List}).TotalSeconds
    [pscustomobject]@{
        Type = 'TestFunction Filter'
        IsPipeline = $False
        Time_seconds =$Seconds
        Count = $Item
    }
 
    $Seconds = (Measure-Command {$List|TestFilter}).TotalSeconds
    [pscustomobject]@{
        Type = 'TestFilter Filter <pipeline>'
        IsPipeline = $True
        Time_seconds =$Seconds
        Count = $Item
    }
    $Seconds = (Measure-Command {$List|TestFilter_Predicate -Predicate {$_%2}}).TotalSeconds
    [pscustomobject]@{
        Type = 'TestFilter_Predicate Filter'
        IsPipeline = $False
        Time_seconds =$Seconds
        Count = $Item
    }
    $Seconds = (Measure-Command {
        $t = [System.Windows.Data.CollectionViewSource]::GetDefaultView($List)
        $t.Filter = [Predicate[Object]]{
            Try {
                $args[0] % 2
            } Catch {$True}
        }
    }).TotalSeconds
    [pscustomobject]@{
        Type = 'Predicate Filter'
        IsPipeline = $False
        Time_seconds =$Seconds
        Count = $Item
    }
}
#Send data to CSVs
Remove-Variable List,Count
$data|group count | ForEach {
   
    $temp = ((($_.Group|sort Time_Seconds |ft -auto|out-string) -split '\n')|?{$_ -match '\w|-'})
    For ($i=0;$i -lt $temp.count;$i++) {
        If ($i -eq 2) {
            Write-Host $temp[$i] -fore Green
        } ElseIf ($i -eq ($Temp.Count-1)) {
            Write-Host $temp[$i] -fore Red
        } Else {
            Write-Host $temp[$i]
        }
    }
    Write-Host "`n--------------------------------------------------------`n"
}
Posted in powershell | Tagged , , | 4 Comments