PowerShell Problem Solver: Finding Long File Names

Here’s another problem that recently came across my desk. The need was to identify files with long names. Even if you don’t have this need, these problem solving articles will hopefully demonstrate PowerShell techniques and concepts that you can use in other projects or tasks. With that in mind, let’s walk through the process. You can follow along typing commands in either the console or the PowerShell ISE.

An Easy Way to Obtain the File Length in PowerShell

To make our PowerShell code re-usable, let’s define a variable for a folder we want to check.

$path = "c:\work"

You can verify by getting all files within that path.

dir $path -file -Recurse

We’re going to look at all files, but you could just as easily limit your search to files of a specific type or name. When approaching a PowerShell problem, it is helpful to look at a single, representative object to discover what you can use. I’m going to look at a single file.

PS C:\> get-item C:\work\ComputerData.xml | Select Name
Name
----
ComputerData.xml

The name property is a string object that has a single property of length.

PS C:\> $file = get-item C:\work\ComputerData.xml
PS C:\> $file.name
ComputerData.xml
PS C:\> $file.name.length
16

In PowerShell you can keep expanding properties like I’ve done here. But don’t confuse this property with the length property of the file itself, which is the file size. We can take the next step and use a custom property with Select-Object.

PS C:\> get-item C:\work\ComputerData.xml | Select Name,@{Name="NameLength";Expression={$_.name.length}}
Name NameLength
---- ----------
ComputerData.xml 16

Now that we know how to get the value for one item, we can expand this and get it for all items. I’ll test using a subset of files.

dir $path -file -recurse | Select Name,@{Name="NameLength";Expression={$_.name.length}} -first 10

Obtaining a value for all items in Windows PowerShell. (Image Credit: Jeffery Hicks)
Obtaining a value for all items in Windows PowerShell. (Image Credit: Jeffery Hicks)

This command sends an object to the pipeline that we can sort.

dir $path -file -recurse |
Select Name,@{Name="NameLength";Expression={$_.name.length}} -first 10 |
Sort NameLength -Descending

Sending objects to the pipeline to sort. (Image Credit: Jeffery Hicks)
Sending objects to the pipeline to sort. (Image Credit: Jeffery Hicks)

Now that we have something that works for a sample, we can expand our search and get the top 10 longest file names in the specified path.

dir $path -file -recurse |
Select Directory,Name,@{Name="NameLength";Expression={$_.name.length}} |
Sort NameLength -Descending |
Select -first 10

Obtaining the top 10 longest file names. (Image Credit: Jeffery Hicks)
Obtaining the top 10 longest file names. (Image Credit: Jeffery Hicks)

Even though we’ve been looking at file name we could extend the concept for full path.

dir $path -file -recurse |
Select FullName,@{Name="NameLength";Expression={$_.fullname.length}} |
Sort NameLength -Descending |
Select -first 10

Including the entire file path for longest file names in Windows PowerShell. (Image Credit: Jeffery Hicks)
Including the entire file path for longest file names in Windows PowerShell. (Image Credit: Jeffery Hicks)

I created a test file and folder with a ridiculous length to demonstrate.

Using the Add-Member cmdlet to add a custom property to the file object

PowerShell almost always has alternatives. This is a good thing because you might have different requirements for how you want to use this information. Another technique is to add a custom property to the file object with the Add-Member cmdlet.

dir $path -file -recurse |
Add-Member -MemberType ScriptProperty -Name NameLength -value {$this.name.length} -PassThru -force |
Sort NameLength -Descending |
Select -first 10

Using the Add-Member cmdlet to add a custom property. (Image Credit: Jeffery Hicks)
Using the Add-Member cmdlet to add a custom property. (Image Credit: Jeffery Hicks)

Add-Member is a very handy cmdlet and I encourage you to read the help and examples. In this particular scenario I’m defining a calculated property. The value will come from evaluating the script block. In this syntax you can use $this to reference the current object in the pipeline. Don’t use $_ or $psitem. You won’t get an error but you also won’t get a value. And be sure to use –Passthru if you are piping you command to another step as I’m doing. If you don’t use –Passthru, then the rest of the expression will not do anything since there will be nothing in the pipeline.
Using Add-Member makes the property part of the object, even if you don’t see it as part of the output. It is there, but you have to ask for it if you want it.

pdir $path -file -recurse |
Add-Member -MemberType ScriptProperty -Name NameLength -value {$this.name.length} -PassThru -force |
Sort NameLength -Descending |
Select -first 10 -property Directory,Name,NameLength,CreationTime,LastWriteTime

Using Add-Member in Windows PowerShell. (Image Credit: Jeffery Hicks)
Using Add-Member in Windows PowerShell. (Image Credit: Jeffery Hicks)

Or maybe you want to filter on this new, custom property.

dir $path -file -recurse |
Add-Member -MemberType ScriptProperty -Name NameLength -value {$this.name.length} -PassThru -force |
where {$_.NameLength -ge 80 } | Select fullname

Using Add-Member to filter a new, custom property in PowerShell. (Image Credit: Jeffery Hicks)
Using Add-Member to filter a new, custom property in PowerShell. (Image Credit: Jeffery Hicks)

Another alternative is to use a custom sort property. Instead of using a property name, you can define a custom property using a hashtable defined like this:

@{Expression={ some scriptblock }}

The scriptblock can use $_ to reference the current object in the pipeline. Here’s how we could apply this to the problem at hand.

dir $path -file -recurse |
Sort @{Expression={$_.name.length}} -Descending |
Select -first 10

Referencing the current object in the pipeline in PowerShell. (Image Credit: Jeffery Hicks)
Referencing the current object in the pipeline in PowerShell. (Image Credit: Jeffery Hicks)

This approach still gives us the full file object, but there is no property to indicate the file name length. This is where alternatives are helpful. Do you only need to find file objects based on the length of the file name, or do you want to know the file name length as well?

The most important element in solving PowerShell problems is to start small and work your way out. If you tried to come up with my final command in your first attempt, you might have struggled. Start small and test with a subset of whatever it is you’re working with. Once the command works with 10 items, it should work with 100 or 1,000.

Comments have been disabled