递归逻辑

Recursion Logic

I've been working on a PowerShell script that will preserve directory structure when cabbing nested folders. I'm having a bit of difficulty getting the recursion logic right, though.

This is a rough, so there isn't any try/catch error code yet. I've commented out the Remove-Item to prevent accidental runs.

The logic I worked out for this is as follows.

function Chkfordir ($clevel)
{
    $dir = dir $clevel | ? { $_.PSIsContainer -eq $true } #Does Current Level have Folders?
    if($dir -ne $null)    # Yes
    {
        Chkfordir $dir        #Go Deeper
    }
    if ($dir -eq $null)   #Deepest Branch
    {
        return                # Go Back One Level and begin Cabbing
    }

    $dir | % { 
        Compress-Directory $_.FullName (".\" + [string]$_.Name + ".cab")
        echo ($_.FullName + ".cab" >> .\cleaf.log"
        #Remove-Item -Recurse $_.FullName
        return
    } 
}

The function call Compress-Directory is from here.

Edit Changes:

Will Re-Post Code Soon (08/18)

Edit 08/18 So I finally had a chance to test it and the logic seems to work now. There were some problems.

Most of the difficulty came with a powershell gotcha and the unnoticed problem that Compress-Directory is not path independent. Looks like I'll be needing to re-write this function later to be path independent.

The powershell gotcha was in a type change for a value on the pipeline. Apparently after returning from a function directory items are changed from System.IO.FileInfo to System.IO.DirectoryInfo with differently named member functions.

Echo was replaced with Add-Content as the redirection operators don't work in powershell.

There were some unaccounted states to contend with as well. A leaf directory which had no files would cause Compress-Directory to error or complete silently with no file creation (thus not preserving hierarchy).

Solution was to add an Add-Content for leaf folders before return, and moved Add-Content to before the Compress-Directory so there is at least one file in each directory.

I've included my current version below but it is a work in progress.

function Chkfordir ($clevel)
{
    $dir = dir $clevel | ? { $_.PSIsContainer -eq $true } # Get Folders?
    if ($dir -eq $null) {  #Check if deepest branch
        Add-Content (Join-Path $_.PSPath "\leaf.log") ([string]$_.FullName + ".cab")
        return $_                # Return one level up and cab
    }

    $dir | % { #for each sub go deeper
        Chkfordir $_.FullName
        Add-Content (Join-Path $_.PSParentPath "\branch.log") ([string]$_.FullName + ".cab")
        Compress-Directory $_.FullName ([string]$_.Name + ".cab")
        #Remove-Item $_.FullName -recurse
    }          
}

需要对每个子目录进行递归,递归调用后进行压缩returns:

function Chkfordir($clevel) {
    Get-ChildItem $clevel |
        Where-Object { $_.PSIsContainer } |
        ForEach-Object {
            Chkfordir $_
            Compress-Directory ...
            ...
        }
}

这样你会先自动下降,然后在你创建档案时return。