8

I'm pretty new to powershell, so I won't be surprised at all if I'm going about this all wrong. I'm trying to create a function that, when executed, prints results formatted as a table. Maybe it would even be possible to pipe those results to another function for further analysis.

Here's what I have so far. This is a simple function that iterates through a list of paths and collects the name of the directory and the number of items in that directory, putting the data in a hashtable, and returning an array of hashtables:

function Check-Paths(){ $paths = "C:\code\DirA", "C:\code\DirB" $dirs = @() foreach ($path in $paths){ if (Test-Path $path){ $len = (ls -path $path).length } else{ $len = 0 } $dirName = ($path -split "\\")[-1] $dirInfo = @{DirName = $dirName; NumItems = $len} $dirs += $dirInfo } return $dirs } 

That seems straightforward enough. However, when I go run the command, this is what I get:

PS > Check-Paths Name Value ---- ----- DirName DirA NumItems 0 DirName DirB NumItems 0 

What I want is this:

DirName NumItems ------- -------- DirA 0 DirB 0 

I could just hack my function to use a write statement, but I think there must be a much better way to do this. Is there a way to get the data formatted as a table, even better if that can be such that it can be piped to another method?

2 Answers 2

14

How 'bout using

return new-object psobject -Property $dirs 

That would return an object whose properties match the items in the hashtable. Then you can use the built-in powershell formatting cmdlets to make it look like you want. since you only have 2 properties, it will be formatted as a table by default.

EDIT: Here's how the whole thing would look (After the various suggestions):

function Check-Paths(){ $paths = "C:\code\DirA", "C:\code\DirB" $dirs = @() foreach ($path in $paths){ if (Test-Path $path){ $len = (ls -path $path).length } else{ $len = 0 } $dirName = ($path -split "\\")[-1] new-object psobject -property @{DirName = $dirName; NumItems = $len} } } 
Sign up to request clarification or add additional context in comments.

5 Comments

Since it's already a hash table, using new-object is perfect, but it seems like you'd want to move that up inside the loop, and lose the return, so it outputs one object per path.
Good point. I forgot the code was accumulating them. I'd put the new-object (without the return) in place of the line with $dirs += and then omit the return at the end.
@MikeShepard what does your finished function look like? I've tried putting together your answer with the suggestions in the comments, but I can't seem to come up with something that works.
@Mike that works great! I'm amazed that by simply calling new-object within the foreach loop, it's able to put the items in a collection and return the collection. That feels like a lot of magic to me.
It's implicitly doing a write-object (which it does for every statement that you don't "consume" the result). All of the stuff in the output stream is the "return" of the function.
2

Here's a one liner that will give you the number of children for each folder.

"C:\code\DirA", "C:\code\DirB" | ? {Test-Path $_} | Get-Item | select -property Name, @{ Name="NumOfItems" ; Expression = {$_.GetFileSystemInfos().Count} } 

It passes an array of strings to Where-Object to select the ones that exist. The path strings that exist are passed to Get-Item to get the FileSystemObjects which get passed to Select-Object to create PSCustomObject objects. The PSCustomObjects have two properties, the name of the directory and the number of children.

If you want the outputted table columns closer together you can pipe the above to: Format-Table -AutoSize

Example usage and output:

dir | ? {$_.PsIsContainer} | select -property Name, @{ Name="NumOfItems" ; Expression = {$_.GetFileSystemInfos().Count} } | Format-Table -AutoSize Name NumOfItems ---- ---------- Desktop 12 Favorites 3 My Documents 3 Start Menu 2 

4 Comments

You don't need $_ to gi, just gi would do. And maybe just remove the test-path and do gi -ea silentlycontinue and Name should have been DirName
@manojlds I figured Name was good enough. Less code yields the same result, a field showing the directories name. I would of started out with DirectoryInfo's in the first place but I just modeled it after what the original script was doing.
I meant - c:\test | gi. Remove the foreach-object. gi take pipeline input right, so there is no need to wrap it with foreach. But once you do wrap it, you have to supply the $_
@manojlds $_ is required for Get-Item. Just | % {Get-Item} | doesn't work. Unless I remove ForEach-Object... Which I like better :-)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.