Author Posts

June 4, 2016 at 9:44 am

Boy, this time I'm really stumped. I am building an advanced function that will go through an archive folder tree and extract every file that has the archive bit set, then write them to output for inspection (and table of contents). This is only the first of four functions I need to build: the next three are a conditional copy for only files ready to archive, then one to clear the archive bit in all files, and last a function to report the total file count and size in GB so I know when it's time to do the copy to a DVD. I am very close to success, and I have made the core code work for three of these functions. However, all attempts to get an advanced function to perform correctly have been in vain. I have tried everything I can think of, but I'm probably missing something very simple.
Here is thee main code for my "Get-FilesReadyToArchive"

 Get-childItem -Path C:\users\peter\Documents\TestArchive -Recurse | where-Object -Property Attributes -EQ archive | Select-Object @{name='File Name';expression={$_.name}},`
@{name='File Size (KB)';expression={$_.length/1e3}}, @{name='Parent Directory';expression={$_.directoryname}} 

This works:

 PS C:\> Get-childItem -Path C:\users\peter\Documents\TestArchive -Recurse | where-Object -Property Attributes -EQ archive | Select-Object @{name='File Name';expression={$_.name}},`
@{name='File Size (KB)';expression={$_.length/1e3}}, @{name='Parent Directory';expression={$_.directoryname}} 

File Name                                                                            File Size (KB) Parent Directory                                           
———                                                                                  ————– —————-                                           
test_Alyeska pay stubs 2001 (2).TIF                                     1148.51 C:\users\peter\Documents\TestArchive\Bird\Owl              
test_Income Tax Returns -1995; Jason and Jessica.PDF      253.405 C:\users\peter\Documents\TestArchive\Dog\Terrier           
test_Akro Mills catalog.pdf                                                18832.799 C:\users\peter\Documents\TestArchive \Fish\Trout    

Now here is the full script, that just runs with no output:

 
function Get-FilesReadyToArchive
{
    [CmdletBinding()]
    Param
    (
        # Determine path to head directory of archive tree
        [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)] 
        [string]$Path
    )

    Begin
    {$AFiles=Get-ChildItem -Path $Path -Recurse
    }
    Process{ foreach($file in $AFiles){ $file | 
              Where-Object -Property attributes -EQ archive | Select-Object
             @{name='File Name';expression={$_.name}},
             @{name='File Size (KB)';expression={$_.length/1e3}},
             @{name='Parent Directory';expression={$_.directoryname}} | Out-GridView
             
        }
        }    
    End {
        }

This iteration shows a "Foreach" cmdlet. I have tried putting the "Child-Item" cmdlet in the process block, using no "foreach" command, adding explicit write-out commands at the end of the pipeline, and just about everything else. I've found lots of mistakes I've been making, but this one has me stumped.... Peter

June 4, 2016 at 2:25 pm

Your posted code is missing a closing curly brace to end the function block.

When you say "just runs with no output" how are you running this? Pressing play or F5 in ISE? If so, you would only be loading the function into memory, you're not actually executing the function. In the command line section of ISE type the name of your function and give it a Path and stuff will come out (assuming the path isn't empty).

After adding the curly brace and loading it to memory, I ran it on a folder that had 10 files inside and 10 grids popped up. Expected output based on what I see. Keep in mind the Process block will iterate for each $Path you pass to your advanced function.

Also, if you don't need the Begin or End blocks, don't add them. Your function will still work.

June 4, 2016 at 2:31 pm

You need to move a property to the right of Select-Object cmdlet. Without it, Out-Gridview will not display your values. Also, your function is missing a closing curly brace.

$file | 
              Where-Object -Property attributes -EQ archive | 
              Select-Object @{name='File Name';expression={$_.name}},
             @{name='File Size (KB)';expression={$_.length/1e3}},
             @{name='Parent Directory';expression={$_.directoryname}} | Out-GridView

June 6, 2016 at 10:00 pm

Gentlemen: Thanks for your input. I did have a closing curly brace – just missed in when I cut & pasted. And I was using the F5 function in the ISE to run the code, then typing the function name at the prompt in the PS panel. But I believe I have discovered the problem! While trying different versions of code, I had saved the first version of the script as ..ver2 so I could refer back to see what I had already tried. Then in ..ver2 I would try different techniques to get the working code to perform in the function. Well I shot myself in the foot. I had two different scripts with the same function name: Get-FilesReadyToArchive. It's no wonder the Powershell engine was confused, and just kept churning.

I have made many modifications to the code, which now works:

function Get-FilesReadyToArchive
{
    [CmdletBinding()]
    Param
    (
        # Determine path to head directory of archive tree
        [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true)] 
        [string]$Path
    )

    Begin
    {
    }
    Process{$AFiles=Get-ChildItem -Path $Path -Recurse
    
    foreach($file in $Afiles){
        if((Get-ItemProperty -Path $file.FullName).Attributes -band [io.fileattributes]::archive)
        {$hash=[ordered]@{'File Name'=($file).name
                    'File Size (KB)'=($file).Length/1e3
                    'Last Write Time'=($file).LastWriteTime
                    'Parent Directory'=($file).DirectoryName}
           
             $glob=New-Object -TypeName PSObject -Property $hash
              Write-Output $glob}
             
        }
}}
>/pre>
    
I still use the "get-childitem" cmdlet with a "foreach" statement, but the original "where-object" cmdlet was not reporting files that were BOTH archive and readonly. So I borrowed an idea from the Scripting Guy (Jan27th,2011) and used "get-itemproperty" with an if construct which returns every file that has the archive bit set. Thanks for the help..

June 6, 2016 at 11:30 pm

Well done! Thanks for following up and posting the final code.