0

PowerShell – CannotConvertArgumentNoMessage Where Object Error

This is an interesting tale from a customer who was trying to get a list of Outlook clients that were connecting to their Exchange 2010 servers.  They wanted to validate the Outlook versions that were connecting, due to Exchange 2013 requirements and also that Outlook 2010 must have SP2 installed at this time.

A quick search of the interwebs turned up a script, and they though all was golden at that point!  However when they ran it they got some nasty read errors stating CannotConvertArgumentNoMessage and the parameter could not be bound.

The below is the relevant section of the script, the rest was removed for clarity.  The script saves the name of a RPC Client Access (RCA) log file from the Exchange 2010 CAS server to the $LogFile variable.  Since the RCA log has 5 header lines we need to trim that off and re-work the header so that the CSV import is successful.  One of the headers will be called operation – that is the one we want to look at here.

Just like Highlander, a CSV expects only one (header line), so we skip past the first 4 lines and manipulate the fifth line as that will become the header for the CSV.   Finally the log is imported using the saved path and replacement header, and then piped to the Where-Object cmdlet.  The intent is to filter only the connect operations else there will be unwanted hits for every operation a client attempts.

$LogFile = Get-Item 'C:Program FilesMicrosoftExchange ServerV14LoggingRPC Client AccessRCA_20150119-1.LOG'

 

$ReplacementHeader = (Get-Content -Path $LogFile -TotalCount 5 | Select-Object -Skip 4) -Replace "#Fields: " -split ','

 

Import-Csv -Path $LogFile -Header $ReplacementHeader| Where-Object operation -eq 'Connect'

 

Looks good! But running the script produces the below error:

Where-Object : Cannot Bind Parameter

The full error for reference:

Where-Object : Cannot bind parameter 'FilterScript'. Cannot convert the "operation" value of type "System.String" to type "System.Management.Automation.ScriptBlock".
At C:ScriptsGet-RCA-Users-1.1.ps1:5 char:67
+ Import-Csv -Path $LogFile -Header $ReplacementHeader| Where-Object <<<<  operation -eq 'Connect'
+ CategoryInfo          : InvalidArgument: (:) [Where-Object], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.WhereObjectCommand

Picking The Error Apart

Picking this error apart shows that Where-Object is not happy with what it is being asked to do.  It does not seem to find the operation column.  Is there not an operation column in the CSV that was created?

Let’s change the third line of the script so that Where-Object is removed and pipe the object to Get-Member instead so we can see what PowerShell knows:

Import-Csv -Path $LogFile -Header $ReplacementHeader | Get-Member

Yes Virginia - There Is An Operation Object

See the big yellow arrow above? That shows that there *IS* an operation column.

Can we use Select-Object to manipulate it?

Import-Csv -Path $LogFile -Header $ReplacementHeader | Select-Object operation

Select-Object Cmdlet Works Just Fine

Yes, that works!  The Select-Object cmdlet works, and we proved the object is there with the Get-Member cmdlet so what is up with the Where-Object statement?

It is a story of cut and paste...

Joys Of Leveraging Existing Content

One of the great things about scripting and the Internet is the ability to easily grab existing scripts and plagiarise  re-use them.  The issue here is that the script was from a 3rd party blog that did not state what version of PowerShell the author had tested it on, and was assuming that every one was on the latest version; PowerShell 3 at the time.  PowerShell 3 has some cool new features, and one change is around the Where-Object cmdlet.

In PowerShell 3, the Where clause was simplified so that the curly brackets are not longer mandatory and neither is the $_ placeholder.  Yes it makes it easier for new to product people on the latest versions, but causes interoperability challenges too.

In this case Exchange 2010 was installed onto Windows 2012.  Note there was no R2 listed there as that is not a supported OS for that version of Exchange.  PowerShell 2.0 is currently installed.  We can check quickly by using either Get-Host cmdlet or checking the $PSVersionTable variable.

Checking PowerShell Version Using Get-Host And $PSVersionTable

Once we know the issue, fixing it is easy.  Note that the third line has been modified to kick it old skool and uses curly quotes and $_ holder.

Script Updated With Old Skool Where Clause

$LogFile = Get-Item 'C:Program FilesMicrosoftExchange ServerV14LoggingRPC Client AccessRCA_20150119-1.LOG'

$ReplacementHeader = (Get-Content -Path $LogFile -TotalCount 5 | Select-Object -Skip 4) -Replace "#Fields: " -split ','

Import-Csv -Path $LogFile -Header $ReplacementHeader| Where-Object {$_.operation -eq 'Connect'}

 

And we can see that the script now completes, and shows only the lines were the operation result equals “Connect”.

Expected Data Now Returned Using Updated Where Clause

Cheers,

Rhoderick

Rhoderick Milne [MSFT]

Leave a Reply

Your email address will not be published. Required fields are marked *