Splatting versus Calculated properties

Looking for comments/opinions on the use of splatting versus calculated properties. Which is a better practice and which offers the best performance? I am about to inherit a large script that uses mostly calculated properties from Select-Object … I am leaning toward converting to Splatting through foreach-object but don’t want to go through the effort if it is a wast of time.

For me, it is much easier to read/understand using splatting and I am leaning towards that.

Thoughts, opinions??

Thanks in advance.

I tend to think that the opposite of Calculated Properties is rather a PSCustomObject than Splatting.

And even for those options I’d say that there is no general this is good and the other is bad. It depends on the case. If I have some data I import from a CSV file and only want to add another property calculated from one or more properties of the imported data I’d rather use a Calculated Property. If create the data from scratch it may be easier to write and easier to maintain for the future to use a PSCustomObject.

If I missunderstood your question you may elaborate a little more detailed and maybe share an example to illustrate your point of view.

Thanks Olaf. Here is an example of what I am going to inherit, and what I was “thinking” of changing it to, IE Splatting. Although I find Splatting much easier to read, I am also interested in your thoughts on performance over one versus the other.

I left out the try catch blocks to keep it short/simple.

From:

$AuditData = Get-WinEvent -LogName 'Security' -ComputerName $System -FilterXPath $XPath -ErrorAction Stop | 
	Select-Object @{Label='Event ID';Expression={$_.Id}}
	@{Label='Machine Name';Expression={$_.MachineName}}, 
	@{Label='Details';Expression={$_.Message}}, 
	@{Label='Time Created';Expression={$_.TimeCreated}}, 
	@{Label='User Name';Expression={$_.Properties[1].Value}},
	TaskDisplayName, 
	LevelDisplayName

To:

$AuditData = @()
Get-WinEvent -LogName 'Security' -ComputerName $System -FilterXPath $XPath -ErrorAction Stop | 
	foreach-object {
		$Info = [PSCustomObject][Ordered] @{
		'Event ID' 			= $_.Id
		'Machine Name' 		= $_.MachineName
		'Details' 			= $_.Message
		'Time Created' 		= $_.TimeCreated
		'User Name' 		= $_.Properties[1].Value
		'Task DisplayName' 	= $_.TaskDisplayName
		'Level DisplayName'	= $_.LevelDisplayName 
	}
	$AuditData += $Info
}

The end result for the data gathered will be piped to ConvertTo-HTML to create an HTML report from the huge script that audits a bunch of stuff.

If you have error handling to do, ForEach-Object would be a better choice, but IMO with array building, its gonna effect performance(using arraylist will help here).

Its better to take a chunk, may be above one and test using Measure-Command.

OK, we are definitely talking about Calculated Properties vs PSCustomObjects - not Splatting. :wink:

But I’d stick to the statement I made earlier - it depends on the specific case. If the code you inherit does its job why bother and change it? I’d put my energy into something more rewarding. :wink:

Topic Performance: IF performance really matters - in most cases I experienced so far it didn’t matter enough to put too much energy to it - you should measure it. Try different approaches and measure it. You may try to avoid the pipeline in general for loops with a large amount of elements because it’s mostly more time consuming than a foreach loop for example.

You may also avoid building arrays the way you did in your example ($AuditData += $Info). That’s actually creating a new array with the added elements overwriting the old array with the same name. Instead assign the whole command to a variable. PowerShell will create an array for you automatically.

1 Like

Thanks for the comments/suggestions. Yes, the code works, but due to its massive size, I was hoping to get a significant performance gain. Shortly after my last post, I did do a few Measure-Commands and the difference was not significant for the ones I tested. I will keep poking around on that and avoid the Array declarations and get those gains.

Also, to kvprasoon comment on error handling, there is extensive error handling … I did leave all that out (try catch blocks) for simplicity of posting/reading.

Thanks again.

Quick update. After playing with Measure-Command, the difference between the two methods was insignificant, maybe a few tenths of second difference. Interestingly, I would have thought Olaf’s suggestion to ditch the array declaration and assign to a variable would have made a big difference. However, it did not. I picked what I felt was the most intense query out of all of them in the script.

Seconds for the two methods using the array declaration:
14.5222798 seconds, 382 objects returned
14.7504026 seconds, 382 objects returned

Seconds for the two methods using a variable versus array:
14.7361648 seconds, 382 objects returned
14.4598421 seconds, 382 objects returned

Hmmm … we are talking about 15 seconds … what kind of improvement did you expect? :wink: Would it really matter even if it would have been 50% or more? … it’s just seconds. How much time did you spend to figure that out?

That’s what I meant with “IF performance really matters” for example … if a task runs as a scheduled task and is not about to interfear with the next occurence of the same task it doesn’t matter how long it takes.

well, time complexity comes when you expect the possibility of the input data increases in future.
a simple example.

Absolutely true. But still … the amount of input data would need to increase exponentially to come to a point where it really matters.
In my experiences the most time consuming actions are usually file system actions or the access of network ressources. If you have something like this in scripts you should try to speed this up.

Just to be clear, the overall HUGE script takes many minutes to run (10+) depending on event log size’s and the performance of the system, and no, it is not run from a task. All I really wanted to do was make sure the difference between the two methods was not significant to something like using a FilterHashTable for Get-WinEvent which GREATLY increases performance. Now that I have my data, I am moving on with my life. Sorry for all the banter and many thanks for all the input.

:rofl: :rofl: :rofl: :+1:t4: :+1:t4: :+1:t4:

There’s nothing you should be sorry about … sometimes we need external input. :+1:t4: