locked
recursively check all folders and export the list of last created files in each folder RRS feed

  • Question

  • Hello

    I need a PowerShell code for this purpose:

    There is a folder containing database backup files. I need to recursively check all folders and export the list of last backup files in each folder.

    I have a stupid code here that contains my idea. please help me to correct it:

    Get-ChildItem D:\backups -rec | if ($_.PSIsContainer) {Sort CreationTime -Descending | Select Name -First 1} 
    else {select-object FullName, LastWriteTime, Length | export-csv -notypeinformation -delimiter '|' -path file.csv}

    Thanks in advance

    Tuesday, May 22, 2018 2:05 PM

Answers

  • Here's your answer:

    [Cmdletbinding()]
    param(
                                    #optional parameter with value
        [Parameter(Position=0,Mandatory=$false,ValueFromPipeline=$true)]$path="D:\Cloud\OneDrive\AllFotosHistorical", #D:\backups
        [Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true)]$OutPutFilepath="D:\Output.csv" #output file full path
    )
    
    function Get-LastestWroteFile{
       [Cmdletbinding()]
        param(
            [Parameter(Position=0,Mandatory=$true)]$Folder
        )
        begin{
            $Latest = Get-ChildItem $Folder.FullName -File | select FullName, CreationTime, LastAccessTime, LastWriteTime, Attributes,  @{N='SizeInMb';E={$_.Length/1mb}},Name | Sort-Object CreationTime | select -First 1
        }
        process{
            #bubble comparison. let them here for general culture.
            ##get today's date and take it out 5 years.
            #$Latest=(Get-Date).AddYears(-5)
            #foreach($file in $AllFiles){
            #    if($file -gt $Latest){
            #        $latest =$file.LastWriteDate
            #        $LatestFile =$file;
            #    }
            #}
        }
        end{
            #new custom object with 3 props.
            if($Latest){
                return New-Object PSobject -Property @{"FullName"=$latest.Name; LastWriteTime = $latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; }
            }
        }
    }
    
    $OutPut=@()
    Get-ChildItem -Directory -Path $path -Recurse | foreach{
        $OutPut+= Get-LastestWroteFile $_
    }
    
    $OutPut | ConvertTo-Csv -NoTypeInformation -delimiter '|' | Out-File -FilePath $OutPutFilepath

    Save this into a text file and save it with extension ps1. (ex: <NameYouGave.ps1>)

    Change the lines 4 and 5 and run it on a PowerShell console  .\<NameYouGave.ps1>

    if it doesn't run...

    Open an elevated Powershell console (open as administrator) and run:

    dir <NameYouGave> | unblock-file
    .\<NameYouGave>.ps1




    • Proposed as answer by j0rt3g4 Wednesday, May 23, 2018 4:58 AM
    • Edited by j0rt3g4 Wednesday, May 23, 2018 5:01 AM
    • Marked as answer by Ghasem Shams Wednesday, May 23, 2018 10:46 AM
    Wednesday, May 23, 2018 4:54 AM
  • On the END Part

      if($Latest){
                return New-Object PSobject -Property @{"FullName"=$latest.Name; LastWriteTime = $latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; }
            }


    In the $latest part add the else part{}

    if($Latest){ return New-Object PSobject -Property @{"FullName"=$latest.Name; LastWriteTime = $latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; } }

    else{

    #what should happen if it's null

    return New-Object PSobject -Property @{"FullName"=$null; LastWriteTime = $null;"Folder"=$folder.FullName;SizeInMB =0}

    }

    And on this Line:

    $Latest = Get-ChildItem $Folder.FullName -File | select FullName, CreationTime, LastAccessTime, LastWriteTime, Attributes,  @{N='SizeInMb';E={$_.Length/1mb}},Name | Sort-Object CreationTime | select -First 1

    You can also do this:

    $Latest = Get-ChildItem $Folder.FullName -File | select FullName, CreationTime, LastAccessTime, LastWriteTime, Attributes,  @{N='SizeInMb';E={$_.Length/1mb}},Name | Sort-Object CreationTime -Descending | select -First 1

    And that makes the fix, instead of getting the last one, it's easier to get the 1st. (I think it would be faster).

    • Marked as answer by Ghasem Shams Thursday, May 24, 2018 2:44 AM
    Wednesday, May 23, 2018 5:51 PM

All replies

  • Nope.  Not even close.

    I recommend starting by learning basic PowerShell.

    Here is something to give you an idea.

    Get all directories.  Get the newest file in each directory.  Output the results to a CSV.

    You should also look up CSV and learn what it is and how it is intended to work.

    https://en.wikipedia.org/wiki/Comma-separated_values


    \_(ツ)_/

    Tuesday, May 22, 2018 2:44 PM
  • 1. You cannot pipe to If, you need to pipe to Foreach

    2. If you add the -File parameter to Get-ChildItem it will return only files, so no need to do an If Statement

    Below is a starter, you can work on only retrieving the latest file :-)

    get-childitem F:\ -recurse -file | Select -Property FullName,LastWriteTime,Length

    But rethinking on your question, you may need to retrieve all files and folders

    Get-ChildItem F:\ -Recurse | Foreach {
      if ($_.PSIsContainer) {
        # Folder
      }
      else {
        # File
      }
    }


    If you find that my post has answered your question, please mark it as the answer. If you find my post to be helpful in anyway, please click vote as helpful. (99,108,97,121,109,97,110,50,64,110,121,99,97,112,46,114,114,46,99,111,109|%{[char]$_})-join''


    • Edited by clayman2 Tuesday, May 22, 2018 2:50 PM typo
    Tuesday, May 22, 2018 2:47 PM

  • Get-ChildItem F:\ -Recurse | Foreach {
      if ($_.PSIsContainer) {
        # Folder
      }
      else {
        # File
      }
    }


    Thanks dear clayman

    that was a help, but now I find out that I need to give the output of #folder part to file part and then print them. how can I do that?

    Get-ChildItem F:\ -Recurse | Foreach {
      if ($_.PSIsContainer) {
       Sort CreationTime -Descending | Select Name -First 1
      }
      else {
        select-object FullName, LastWriteTime, Length | export-csv -notypeinformation -delimiter '|' -path file.csv
      }

    Is there a way in powershell to print in file every time code founds a result or we have to write whole result once?

    Tuesday, May 22, 2018 3:33 PM
  • Here's your answer:

    [Cmdletbinding()]
    param(
                                    #optional parameter with value
        [Parameter(Position=0,Mandatory=$false,ValueFromPipeline=$true)]$path="D:\Cloud\OneDrive\AllFotosHistorical", #D:\backups
        [Parameter(Position=1,Mandatory=$false,ValueFromPipeline=$true)]$OutPutFilepath="D:\Output.csv" #output file full path
    )
    
    function Get-LastestWroteFile{
       [Cmdletbinding()]
        param(
            [Parameter(Position=0,Mandatory=$true)]$Folder
        )
        begin{
            $Latest = Get-ChildItem $Folder.FullName -File | select FullName, CreationTime, LastAccessTime, LastWriteTime, Attributes,  @{N='SizeInMb';E={$_.Length/1mb}},Name | Sort-Object CreationTime | select -First 1
        }
        process{
            #bubble comparison. let them here for general culture.
            ##get today's date and take it out 5 years.
            #$Latest=(Get-Date).AddYears(-5)
            #foreach($file in $AllFiles){
            #    if($file -gt $Latest){
            #        $latest =$file.LastWriteDate
            #        $LatestFile =$file;
            #    }
            #}
        }
        end{
            #new custom object with 3 props.
            if($Latest){
                return New-Object PSobject -Property @{"FullName"=$latest.Name; LastWriteTime = $latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; }
            }
        }
    }
    
    $OutPut=@()
    Get-ChildItem -Directory -Path $path -Recurse | foreach{
        $OutPut+= Get-LastestWroteFile $_
    }
    
    $OutPut | ConvertTo-Csv -NoTypeInformation -delimiter '|' | Out-File -FilePath $OutPutFilepath

    Save this into a text file and save it with extension ps1. (ex: <NameYouGave.ps1>)

    Change the lines 4 and 5 and run it on a PowerShell console  .\<NameYouGave.ps1>

    if it doesn't run...

    Open an elevated Powershell console (open as administrator) and run:

    dir <NameYouGave> | unblock-file
    .\<NameYouGave>.ps1




    • Proposed as answer by j0rt3g4 Wednesday, May 23, 2018 4:58 AM
    • Edited by j0rt3g4 Wednesday, May 23, 2018 5:01 AM
    • Marked as answer by Ghasem Shams Wednesday, May 23, 2018 10:46 AM
    Wednesday, May 23, 2018 4:54 AM
  • Thanks, Thanks, Thanks

    Every thing works great, Just I changed "First" to "Last". because I needed newest backup files in folder. 

    Thanks again dear j0rt3g4.

    Wednesday, May 23, 2018 10:48 AM
  • On the END Part

      if($Latest){
                return New-Object PSobject -Property @{"FullName"=$latest.Name; LastWriteTime = $latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; }
            }


    In the $latest part add the else part{}

    if($Latest){ return New-Object PSobject -Property @{"FullName"=$latest.Name; LastWriteTime = $latest.LastWriteTime;"Folder"=$folder.FullName;"SizeInMB" =[math]::Round($Latest.SizeInMB,3)} #FileInfo=$Latest; } }

    else{

    #what should happen if it's null

    return New-Object PSobject -Property @{"FullName"=$null; LastWriteTime = $null;"Folder"=$folder.FullName;SizeInMB =0}

    }

    And on this Line:

    $Latest = Get-ChildItem $Folder.FullName -File | select FullName, CreationTime, LastAccessTime, LastWriteTime, Attributes,  @{N='SizeInMb';E={$_.Length/1mb}},Name | Sort-Object CreationTime | select -First 1

    You can also do this:

    $Latest = Get-ChildItem $Folder.FullName -File | select FullName, CreationTime, LastAccessTime, LastWriteTime, Attributes,  @{N='SizeInMb';E={$_.Length/1mb}},Name | Sort-Object CreationTime -Descending | select -First 1

    And that makes the fix, instead of getting the last one, it's easier to get the 1st. (I think it would be faster).

    • Marked as answer by Ghasem Shams Thursday, May 24, 2018 2:44 AM
    Wednesday, May 23, 2018 5:51 PM
  • Thanks again dear

    1- If I need to list the folders that has no created backup file in it during last 24 hour, can I add the code in Process part?

    2-If I need to add more than one $path how can I do that?


    Thursday, May 24, 2018 3:15 AM
  • 1. In another script or function that does exactly the commented part (bubble code)

    2. you can give as an object (path1,path2) and change everything on the script and name it as a function

    function Get-CreatedDateByFolder{
        <script>
    }
    
    foreach($item in $path){
        Get-CreatedDateByFolder -path $item
    }
    


    Thursday, May 24, 2018 5:40 AM