copy a directory tree without files.

This topic contains 11 replies, has 2 voices, and was last updated by  Amit 2 months, 3 weeks ago.

  • Author
    Posts
  • #79738

    Amit
    Participant

    Hello,

    I am new to Powershell and I need some help. I have a root directory with a lot of sub directories and files that also contain sub directories and files and so on. It's a quite big tree.
    I actually want to write a script that tells me what types of files any directory contains.

    Path\test
    │ hallo.pptx
    │ hallo.txt
    │ hmm.bmp
    │ refe.pub
    │ set
    │ ta ch.txt
    │ tach.txt
    │ test.docx
    │ test1.txt
    │ tree.txt
    │ tzzz.xlsx
    │ wwwet.zip

    ├───12
    │ │ rv.docx
    │ │ 443g.bmp
    │ │
    │ └───45gg
    └───3da
    │ rrr.pub
    │ bla.docx
    │ f.txt

    ├───32.45
    └───3543
    I wrote short function that just reads all the files in a test directory and create an extentions.txt with all types of extentions in that directory.

    Now I would like to mirror this root directory with all sub directories just without files.
    The next step would be to run my function for each sub directory.
    so I later have something that looks like this:

    mirror-Path\test
    │ extentions.txt

    ├───12
    │ │ extentions.txt
    │ │
    │ └───45gg
    │ extentions.txt

    └───3da
    │ extentions.txt

    ├───32.45
    │ extentions.txt

    └───3543
    extentions.txt

    I actually have no idea how to create this mirror directory system. It would be great to get some help.

    thanks
    Amit

  • #79744

    Rick
    Participant

    Robocopy is your friend for this.

    Robocopy source destination /S /E /XF *.*
    
    • #79745

      Amit
      Participant

      great!! only one short line.
      is there also a way to run my function over those directories?

      thanks a lot
      Amit

  • #79748

    Rick
    Participant
    Function get-extensions {....
    }
    
    Get-ChildItem | where {$_.PSIsContainer} | % {
    Get-extensions $_.FullName
    }
    
    • #79847

      Amit
      Participant

      I tried to use this short way with the pipelines, but it went wrong and I don't really know how to fit my function to the way with the pipelines.
      I tried to pass the function an array as parameter but for some reason it is undefined inside the function but it contains everything it should outside the function

      function write_extentions_to_txt([string]$mir_path, [string]$main_path, [string[]]$sub_directories){
      
      	write-host "print array inside the function $sub_directories"
              $sub_directory = -join $sub_directories[0]
              dir -name -file -path "$main_path\$sub_directory" > "$mir_path\$sub_directory\dir.txt"
      
      	#declare methode_variables
      	$extentions = @()
      	$helping_arr =@()
      	$ext =@()
      
      	#read dir.txt and write extentions to array
      	foreach($line in Get-Content "C:\Users\amit\Desktop\test_mirror\12\dir.txt") {
      		$helping_arr = $line -split ""
      		[array]::Reverse($helping_arr)
      		$file_name_reversed= -join $helping_arr
      		$ext = @($file_name_reversed.split('.'))
      		$ext_str_reversed= -join $ext[0]
      		$helping_arr = $ext_str_reversed -split ""
      		[array]::Reverse($helping_arr)
      		$ext_str= -join $helping_arr
      		$extentions += $ext_str
      	}
      
      	#write extentions from array to extentions.txt
      	$extentions = $extentions | select -uniq
      	foreach($i in $extentions){$i >> "C:\Users\amit\Desktop\test_mirror\12\extentions.txt"}
      }
      

      And here I fill the array

      #create array of directory paths
      $sub_directories =@()
      dir -Path $source  -directory -name -recurse > directories.txt
      foreach($line in Get-Content "directories.txt"){
      	$sub_directories += $line
      	write-host "hola $sub_directories"
      }
      write-host "print array outside the function $sub_directories"
      
      
      write_extentions_to_txt($dest, $source, $sub_directories)
      

      thanks
      Amit

  • #79867

    Rick
    Participant

    If you could give us an example of what the extension.txt file looks like that might help. If you're just looking for a extensions.txt file in every folder listing the unique extensions you could just do this. If a folder is empty it doesn't create a extensions.txt file. If you need empty directories included just remove the "-and $_.GetFiles().Count -gt 0" from the 1st line. I also exclude the extensions.txt from being included in the unique extensions list.

    Get-ChildItem -Path $source -Recurse | where {$_.PSIsContainer -and $_.GetFiles().Count -gt 0 } | % {
    Get-ChildItem -path $_.FullName | ? { $_.Name -notmatch "extensions.txt"} | select Extension -Unique | Out-File -FilePath "$($_.FullName)\Extensions.txt"
    }
    

    Hope this helps.

  • #79874

    Amit
    Participant

    here you have an example for the test directory. It contains all the extentions listed in the test directory you see in the OT.
    (except of set, it's a bug but I can live with it right now)

    path/test/extentions.txt:
    pptx
    txt
    bmp
    pub
    set
    lnk
    docx
    xlsx
    zip

    I will try to apply the code above and will post if it works.

    • #79903

      Amit
      Participant

      I really don't get the Point with the scope of variables in PS. So I reduced any unnecessary code from the example above just to make sure there is no other mistake and I really don't understand it.

      function doSomething{
      param([string]$dest, [string]$source, [string[]] $sub_directories)
      write-host "directories: $sub_directories"
      write-host "source: $source"
      write-host "destination: $dest"
      }
      
      
      #mirror the directory system
      $source = "C:\Users\u9189\Desktop\test"
      $dest = "C:\Users\u9189\Desktop\test_mirror"
      
      
      #create array of directory paths
      $sub_directories =@()
      dir -Path $source  -directory -name -recurse > directories.txt
      foreach($line in Get-Content "directories.txt"){
      	$sub_directories += $line
      	
      }
      write-host "source before calling function: $source"
      write-host "sub_directories before calling function: $sub_directories"
      write-host "Enter function:"
      doSomething($dest, $source, $sub_directories)
      write-host "left function:"
      write-host "source after calling function: $source"
      write-host "sub_directories after calling function: $sub_directories"
      
      Read-Host "Press Enter to exit..."
      exit
      

      source before calling function: C:\Users\amit\Desktop\test
      sub_directories before calling function: 12 3da 12\45gg 3da\32.45 3da\3543
      Enter function:
      directories:
      source:
      destination: C:\Users\amit\Desktop\test_mirror C:\Users\amit\Desktop\test System.Object[]
      left function:
      source after calling function: C:\Users\amit\Desktop\test
      sub_directories after calling function: 12 3da 12\45gg 3da\32.45 3da\3543
      Press Enter to exit...:

      If the syntax is wrong then why is it wrong for $source but not for $destination?

  • #79913

    Rick
    Participant

    Sorry if I am not understanding the question and my code isn't understandable. I'm just trying to help. To mirror folders including subdirectories I suggest using robocopy and not powershell. You just run "robocopy /s /e /xf *.*" This could also be called from powershell if you prefer.

    To get a unique extensions.txt file in every non-empty folder in every subdirectory run the code below. Here is an overview of what it's doing.

    #Recursively grabbing all files and folders from the $source path.
    # Get-Childitem -path $source -recurse
    
    # Select only directories,(PSIsContainer) and directories that have files,(Getfiles)
    # where {$_.PSIsContainer -and $_.GetFiles().Count -gt 0 } 
    
    # Get the items,(files) in the folder list from the above filtered get-childitem command
    #Get-ChildItem -path $_.FullName
    
    # Exclude the extensions.txt file
    # ? { $_.Name -notmatch "extensions.txt"}
    
    # select only the unqiue extensions in that folder
    # select Extension -Unique 
    
    # Export the results to extensions.txt file in the current folder.
    # Out-File -FilePath "$($_.FullName)\Extensions.txt"
    
    Get-ChildItem -Path $source -Recurse | where {$_.PSIsContainer -and $_.GetFiles().Count -gt 0 } | % {
    Get-ChildItem -path $_.FullName | ? { $_.Name -notmatch "extensions.txt"} | select Extension -Unique | Out-File -FilePath "$($_.FullName)\Extensions.txt"
    }
  • #79915

    Rick
    Participant

    Sorry if I am double posting but I don't see my post in this list even though it says I posted last.
    Sorry if I am not understanding the question and my code isn't understandable. I'm just trying to help. To mirror folders including subdirectories I suggest using robocopy and not powershell. You just run "robocopy /s /e /xf *.*" This could also be called from powershell if you prefer.

    To get a unique extensions.txt file in every non-empty folder in every subdirectory run the code below. Here is an overview of what it's doing.

    #Recursively grabbing all files and folders from the $source path.
    # Get-Childitem -path $source -recurse
    
    # Select only directories,(PSIsContainer) and directories that have files,(Getfiles)
    # where {$_.PSIsContainer -and $_.GetFiles().Count -gt 0 } 
    
    # Get the items,(files) in the folder list from the above filtered get-childitem command
    # Get-ChildItem -path $_.FullName
    
    # Exclude the extensions.txt file
    # ? { $_.Name -notmatch "extensions.txt"}
    
    # select only the unqiue extensions in that folder
    # select Extension -Unique 
    
    # Export the results to extensions.txt file in the current folder.
    # Out-File -FilePath "$($_.FullName)\Extensions.txt"
    
    Get-ChildItem -Path $source -Recurse | where {$_.PSIsContainer -and $_.GetFiles().Count -gt 0 } | % {
    Get-ChildItem -path $_.FullName | ? { $_.Name -notmatch "extensions.txt"} | select Extension -Unique | Out-File -FilePath "$($_.FullName)\Extensions.txt"
    }
  • #79934

    Rick
    Participant

    If you wanted the powershell script to create the same directory structure it scanned from $source you could add this line before the 2nd Get-Childitem. It will create the same directory structure in $dest as found in $source without any files.

    new-item -ItemType Directory "$dest$(Split-path $_.FullName -Resolve -NoQualifier)" -force
    
  • #80330

    Amit
    Participant

    I couldn't reach Powershell.org the last days. I kind of found a worksaround. This piece of code actually works fine except for paths that are longer then 260chars.
    Here's the complete script:

    function write_extentions_to_txt{
    	$source = "C:\Users\...\test"
    	$dest = "C:\Users\...\test_mirror"
    	robocopy $source $dest /e /xf *.*
    	dir -Path $source  -directory -name -recurse > $dest\directories.txt
    
    	$sub_directories =@()
    	$sub_directories += ""
    	foreach($line in Get-Content "$dest\directories.txt"){
    		$sub_directories += $line
    	}
    	
    	foreach($directory in $sub_directories){
    		$sub_directory= -join $directory
    		$old_extention_file = "$dest\$sub_directory\extentions.txt"	
    		#remove extentions.txt and create write dir.txt
    		if (Test-Path $old_extention_file) {
    				Remove-Item $old_extention_file
    		}
    		
    		
    		dir -name -file -path "$source\$sub_directory" > "$dest\$sub_directory\dir.txt"
    		$extentions = @()
    		$helping_arr =@()
    		$ext =@()
    		#read dir.txt and write extentions to array
    		foreach($line in Get-Content "$dest\$sub_directory\dir.txt") {
    			$helping_arr = $line -split ""
    			[array]::Reverse($helping_arr)
    			$file_name_reversed= -join $helping_arr
    			$ext = @($file_name_reversed.split('.'))
    			$ext_str_reversed= -join $ext[0]
    			$helping_arr = $ext_str_reversed -split ""
    			[array]::Reverse($helping_arr)
    			$ext_str= -join $helping_arr
    			$extentions += $ext_str
    		}
    		#write extentions from array to extentions.txt
    		$extentions = $extentions | select -uniq
    		foreach($i in $extentions){$i >> "$dest\$sub_directory\extentions.txt"}
    		#delete dir.txt
    	    Remove-Item -Path "$dest\$sub_directory\dir.txt"	
    	}
    }
    
    write_extentions_to_txt
    
    Read-Host "Press Enter to exit..."
    exit

    Still would like to understand your way so I am Playing around with your code. I understand it now in general but I don't really get how to fit it. Guess that you have to know what kind of functions and attributes already exists in PS.
    Btw what do you mean with robocopy is not Powershell?

You must be logged in to reply to this topic.