4
\$\begingroup\$

I wrote a PowerShell script for a superuser question:

list of all files and directories under a path recursively, without recursing into junction points or links

I have a strong feeling that my code is way too complicated for such a simple task.

function Recurse($path) {

  $fc = new-object -com scripting.filesystemobject
  $folder = $fc.getfolder($path)

  foreach ($i in $folder.files) { $i | select Path }

  foreach ($i in $folder.subfolders) {
    $i | select Path        
    if ( (get-item $i.path).Attributes.ToString().Contains("ReparsePoint") -eq $false) {        
        Recurse($i.path)
    }
  }
}

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
$outputlist = Recurse($scriptPath) | Out-File -Filepath .\outputlist.txt 

Short instructions on how to use the script:

  1. Paste the code into a text file and save it as PowerShell (.ps1) script
  2. Place the script inside a folder to list all files+folder recursively without junction folder loops
  3. Execute the script. A new file called outputlist.txt at the same location will appear

Questions:

  1. Can I simplify this PowerShell script anyhow?
  2. Is there a better Out-command where no blank spaces are appended after every line?
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Here's a shot at it: (Requires PowerShell v3 or higher)

The idea here is to get all non-reparsepoint directories first. For each directory, recurse into the subdirectory and then output the files at the current level.

In it's simplest form, it looks like this:

function Get-ChildItemNoReparsePoint($Path)
{
    Get-ChildItem -Path $Path -Attributes !ReparsePoint -Directory | foreach { 
        Get-ChildItemNoReparsePoint $_.Fullname
    }
    Get-ChildItem -File $Path  
}

A more full example is shown below:

We hook into the powershell help system by adding specially formatted comment.

By adding the [CmdletBinding()] attribute, we get access to the powershell common parameters (Get-Help about_Common_Parameters).

By adding the OutputType attribute, you get tab completion after the command in the pipeline. (try 'Get-ChildItemNoReparsePoint| Foreach <tab>')

The Parameter attribute enables usage of the function in a pipeline (together with the PSPath alias).

function Get-ChildItemNoReparsePoint
{
<#
.SYNOPSIS
    Gets all files of a directory recursivly, excluding reparse points
.OUTPUTS
    System.IO.FileInfo
.EXAMPLE
dir | Get-ChildItemNoReparsePoint 
.EXAMPLE
Get-ChildItemNoReparsePoint ~/Documents | Foreach FullName | Set-Content thefiles.txt
.EXAMPLE
Get-ChildItemNoReparsePoint ~/Documents -OutVariable files | Foreach FullName | Set-Content thefiles.txt
$files | Group-Object Extension
#>
[CmdletBinding()]
[OutputType([System.IO.FileInfo])]
param(
    [Parameter(ValueFromPipelineByPropertyName)]
    [Alias('PSPath')]
    # Specifies a path to one or more locations.
    [string[]]$Path=$pwd
)
process
{
    Get-ChildItem -Path $Path -Attributes !ReparsePoint -Directory | Get-ChildItemNoReparsePoint       
    Get-ChildItem -File $Path
}

Set-Content can be used instead of Out-File to bypass PowerShell's formatting step.

Get-NonReparsePointDirectoryFiles | foreach FullName | Set-Content -PassThru thefiles.txt
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.