Can't retrieve "non-permission" folders specifyng depth

This topic contains 7 replies, has 3 voices, and was last updated by  Octavio 4 months, 1 week ago.

  • Author
    Posts
  • #69783

    Octavio
    Participant

    Hello there, i am facing a problem that i could not resolve, and i am stucked
    I made a function that return all the directories and subdirectories of a given path and depth.
    I know that in Powershell V5 the -depth parameter is included in the gci cmdlet, but im dealing with old windows servers (with PS v2), so i have to
    make a compatible function with old versions

    The problem is, that i want to list ALL subdirectories (inlcuding those were i don´t haver permission).
    But, the issue is that i don´t retrieve those folders were i dont have permission. Those folders remains like hidden.

    The only solution i found, i to use -recurse, which doesn´t solve my problem, cause -recurse go through all the directories untill end.

    So basically, i need a way to list ALL directories (also those directories i dont have permission) until the -depth value that i put.

    I transcribe the part that does this task

    ....
    if ($depth){
    	for($i=1;$i -le $depth;$i++){
    	
    		$actualSubdirectory=$symbol * $i
    		$subfolders+= Get-ChildItem $drive$actualSubdirectory -ErrorVariable +err
    			-ErrorAction SilentlyContinue | ? {$_.psiscontainer -eq $true} | 
    				Select-Object -ExpandProperty FullName 
    	}
    }
    elseif (-not $depth){
    
        # 
            $subfolders = Get-ChildItem $drive -Recurse -ErrorVariable +err `
    			-ErrorAction SilentlyContinue | ? {$_.psiscontainer -eq $true} | 
    				Select-Object -ExpandProperty FullName
    }
    ....   	
    

    example:
    $symbol='*\'
    $drive='C:\temp\carpeta1'

    I will apreciatte any help in advance.
    Thanks a lot!

  • #69798

    Rob Simmers
    Participant

    If you want to specify depth, you'd have to implement recursion manually. I would have to imagine that someone has done this before, but this is a basic example:

    function Get-ChildItemCustom {
        [CmdLetBinding()]
        param (
            $Path,
            $Depth 
        )
        begin {
            
        }
        process {
            foreach ($item in Get-ChildItem -Path $Path ) {
                if ($item.PSIsContainer) {
                    Write-Verbose (($item.fullname -split '\\').Count)
                    if (($item.fullname -split '\\').Count -le $Depth) {
                        Get-ChildItemCustom -Path $item.FullName
                    }
                    else {
                        Write-Verbose "Stopping because of depth param"
                    }
                    
                }
                else {
                    $item
                }
            }
        }
        end {
            
        }
    }
    
    Get-ChildItemCustom -Path C:\Windows -Depth 3 -Verbose
    

    Output:

    C:\Windows\Provisioning\categories.xml                              
    C:\Windows\Provisioning\IccidToRegion.xml                           
    C:\Windows\Provisioning\Microsoft-Common-Provisioning.dat           
    C:\Windows\Provisioning\Microsoft-Desktop-Provisioning.dat          
    VERBOSE: 3
    VERBOSE: 4
    VERBOSE: Stopping because of depth param
    C:\Windows\Registration\R000000000001.clb                           
    C:\Windows\Registration\R00000000000c.clb                           
    C:\Windows\Registration\R00000000000d.clb                           
    C:\Windows\Registration\{02D4B3F1-FD88-11D1-960D-00805FC79235}.{D...
    VERBOSE: 3
    VERBOSE: 4
    VERBOSE: Stopping because of depth param
    VERBOSE: 4
    VERBOSE: Stopping because of depth param
    VERBOSE: 4
    VERBOSE: Stopping because of depth param
    C:\Windows\rescache\ResCache.mni          
    
    • #69829

      Octavio
      Participant

      Rob Simmers, it´s very near what i am looking for. A recursive way

      I was trying tu modify it, so i can receive a PS custom object.

       foreach ($item in (Get-ChildItem $drive -ErrorAction SilentlyContinue | Where-Object {$_.psiscontainer -eq $true})){
                              if (($item.FullName -split "\\").Count -le $depth){
      
                                      $hashTable=@{
                                          Folders=Get-ChildItem -Path $item.FullName -ErrorAction SilentlyContinue -ErrorVariable +err
                                          Errors=$err
                                      }
                                      $prop=New-Object -TypeName psobject -Property $hashTable
                                      $script:folderArray+=$prop
      
      
      
                                      get-AclLocallyLocal -drive $item.FullName
                              }
                              else{
      
                                  break;
                              }
                      }
                       return $script:folderArray
      

      But i get the result more than one time. I get a line for each recursive pass.
      And also i dont retrieve a folder that i haver permission
      Here is the structure and the result i get

      C:\Windows\Temp\Folder
             Folder 1 (No Permission)
             Folder 2 (with permission)
      
      Get-AclLocallyLocal C:\Windows\Temp\Folder\ -depth 5
      

      Result:

      Errors                                                           Folders
      ------                                                           -------
      {Access to the path 'C:\Windows\Temp\Folder\Folder1' is denied.}
      {Access to the path 'C:\Windows\Temp\Folder\Folder1' is denied.}
      {Access to the path 'C:\Windows\Temp\Folder\Folder1' is denied.}
      {Access to the path 'C:\Windows\Temp\Folder\Folder1' is denied.}
      {Access to the path 'C:\Windows\Temp\Folder\Folder1' is denied.}
      
  • #69816

    Chris Bakker
    Participant

    isnt this what your looking for?

    Get-ChildItem d:\ -Directory -Depth 2

    • #69832

      Octavio
      Participant

      Chris Bakker, yeap. But i´m dealing with windows servers 2003, which have powershell v2, and therefore do not have the -depth parameter 🙁

  • #69861

    Rob Simmers
    Participant

    There are several bad practices in your code.

    • $script:folderArray+=$prop is writing to a global variable versus having a function return results.
      function Get-ChildItemCustom {
          [CmdLetBinding()]
          param (
              $Path,
              $Depth 
          )
          begin {
              
          }
          process {
              #Everything that occurs in the loop is written to $results, no need to +=
              $results = foreach ($item in Get-ChildItem -Path $Path ) {
                  if ($item.PSIsContainer) {
                      Write-Verbose (($item.fullname -split '\\').Count)
                      if (($item.fullname -split '\\').Count -le $Depth) {
                          Get-ChildItemCustom -Path $item.FullName
                      }
                      else {
                          Write-Verbose "Stopping because of depth param"
                      }
                  }
                  else {
                      $item.fullname
                  }
              }
          }
          end {
              $results
          }
      }
      
      
      $myResults = Get-ChildItemCustom -Path C:\Windows -Depth 3 
      $myResults
      
    • break; will break the current loop which you need the loop to continue for each item, break stops the enumeration
    • $err is unnecessary. The $Error global variable will contain any failures that occured. You may want to add $Error.Clear() to the begin{} block to clear existing errors and it any Get-ChildItem failure will be logged there. I've had a seperate function that parsed the $Error varaible to get Get-ChildItem failures
      PS C:\Users\Rob> $Error.Clear()
      
      PS C:\Users\Rob> #run code
      
      PS C:\Users\Rob> $Error
      Get-ChildItem : Access to the path 'C:\Windows\Prefetch' is denied.
      At line:12 char:38
      +         $results = foreach ($item in Get-ChildItem -Path $Path ) {
      +                                      ~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : PermissionDenied: (C:\Windows\Prefetch:String) [Get-ChildItem], UnauthorizedAccessException
          + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
       
      Get-ChildItem : Access to the path 'C:\Windows\ModemLogs' is denied.
      At line:12 char:38
      +         $results = foreach ($item in Get-ChildItem -Path $Path ) {
      +                                      ~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : PermissionDenied: (C:\Windows\ModemLogs:String) [Get-ChildItem], UnauthorizedAccessException
          + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
       
      Get-ChildItem : Access to the path 'C:\Windows\Minidump' is denied.
      At line:12 char:38
      +         $results = foreach ($item in Get-ChildItem -Path $Path ) {
      +                                      ~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : PermissionDenied: (C:\Windows\Minidump:String) [Get-ChildItem], UnauthorizedAccessException
          + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
       
      Get-ChildItem : Access to the path 'C:\Windows\LiveKernelReports' is denied.
      At line:12 char:38
      +         $results = foreach ($item in Get-ChildItem -Path $Path ) {
      +                                      ~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : PermissionDenied: (C:\Windows\LiveKernelReports:String) [Get-ChildItem], UnauthorizedAccessException
          + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
       
      Get-ChildItem : Access to the path 'C:\Windows\InfusedApps' is denied.
      At line:12 char:38
      +         $results = foreach ($item in Get-ChildItem -Path $Path ) {
      +                                      ~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : PermissionDenied: (C:\Windows\InfusedApps:String) [Get-ChildItem], UnauthorizedAccessException
          + FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
      
    • #70128

      Octavio
      Participant

      Rob, thangs again for your quickly help !!. Really apreciatted.

      I was using your workarround, and change the output to a customobject.

      function Get-AclLocallyLocal_test2 {
      
       [CmdLetBinding()]
          param(
              [Parameter(Mandatory=$true)]
              [String]$drive,
              [Parameter(Mandatory=$false)]
              [int]$depth 
      
          )
      
          BEGIN{
              
          }#BEGIN
                  
      
          PROCESS {
              
              foreach($item in get-childitem -path $drive -ErrorAction SilentlyContinue){
                      
                      
                      #if is directory
                      if ($item.psiscontainer){
                             
                              #if amount of directories are equal or lower than specified depth
                        if(($item.fullname -split '\\').count -le $depth){
                              
                              
                                                                          
      
                              $aclLocalyHashtable=@{
                                  Directory=$item.fullname
                                  
                              }
                              $aclLocallyObject = new-object -TypeName psobject -Property $aclLocalyHashtable
                              $aclLocallyObject          
                              Get-AclLocallyLocal_test2 $item.fullname -depth $depth
      
                              
                          }    
                          elseif(!($item.fullname -split '\\').count -le $depth){
                              continue
                          }
                      }#if psiscontainer    
                      else{
                          continue
                      }
                  
                  }#foreach   
      
      
          }#PROCESS   
      
          END{
      
                         
              #$aclLocallyObject
              
          }#END
          
      }  
      

      But i cant manage the errors within the script.
      I dont know if it is posible to return a customobject with 2 keys
      Directory (all directories)
      Errors ( a nested customobject in this key, with the errors details)
      I write it here to graphic what i am trying to say (sorry if i am doing wrong.I´m trying to do my best and learn)

      function Get-AclLocallyLocal_test3 {
      
       [CmdLetBinding()]
          param(
              [Parameter(Mandatory=$true)]
              [String]$drive,
              [Parameter(Mandatory=$false)]
              [int]$depth 
      
          )
      
          BEGIN{
              
          }#BEGIN
                  
      
          PROCESS {
              
              foreach($item in get-childitem -path $drive -ErrorAction SilentlyContinue -ErrorVariable +err){
                      
                      
                      #if is directory
                      if ($item.psiscontainer){
                             
                              #if amount of directories are equal or lower than specified depth
                        if(($item.fullname -split '\\').count -le $depth){
                              
                              if ($err){
                                  $errors=@{
                                  Target=$err.Get_categoryinfo().TargetName
                                  Category=$err.Get_categoryinfo().Category
                                  Reason=$err.Get_categoryinfo().Reason
                                  }
                              }
                                                      
      
                              $aclLocalyHashtable=@{
                                  Directory=$item.fullname
                                  Error=$errors
                              }
                              $aclLocallyObject = new-object -TypeName psobject -Property $aclLocalyHashtable
                              $aclLocallyObject          
                              $err.clear()
                              Get-AclLocallyLocal_test2 $item.fullname -depth $depth
      
                              
                          }    
                          elseif(!($item.fullname -split '\\').count -le $depth){
                              continue
                          }
                      }#if psiscontainer    
                      else{
                          continue
                      }
                  
                  }#foreach   
      
      
          }#PROCESS   
      
          END{
              
             
              
          }#END
          
      }  
      
  • #72667

    Octavio
    Participant

    Sorry to be such a bore, but i´m trying hard to resolve it.

    I know im near, but i can´t get a hashtable of the directories and the directories with no permissions.
    I only get the hashtable with directories, and in the errors column i receive nothing.
    Here is my code

    ## Get-AclLocallyLocal
    function Get-AclLocallyLocal_test2 {
    
     [CmdLetBinding()]
        param(
            [Parameter(Mandatory=$true)]
            [String]$drive,
            [Parameter(Mandatory=$false)]
            [int]$depth 
    
        )
    
        BEGIN{
            
        }#BEGIN
                
    
        PROCESS {
            
            foreach($item in get-childitem -path $drive -ErrorAction SilentlyContinue -ErrorVariable +err){
                    
                    
                    #if is directory
                    if ($item.psiscontainer){
                           
                      #if amount of directories are equal or lower than specified depth
                      if(($item.fullname -split '\\').count -le $depth){
                            
                            
                                                                        
    
                            $aclLocalyHashtable=@{
                                Directory=$item.fullname
                                Error=""
                            }
                            $aclLocallyObject = new-object -TypeName psobject -Property $aclLocalyHashtable
                            $aclLocallyObject   
                            Get-AclLocallyLocal_test2 $item.fullname -depth $depth
    
                            
                        }    
                        elseif(!($item.fullname -split '\\').count -le $depth){
                            continue
                        }
                    }#if psiscontainer    
                    else{
                        continue
                    }
                
                }#foreach   
    
    
        }#PROCESS   
    
        END{
                   
            #$aclLocallyObject
            
        }#END
        
    }  
    
    Get-AclLocallyLocal_test2 -drive "C:\temp\CarpetaPrueba" -depth 5
    

    And here is the output:

    Error Directory
    ----- ---------
          C:\temp\CarpetaPrueba\Carpeta1
          C:\temp\CarpetaPrueba\Carpeta2
          C:\temp\CarpetaPrueba\Carpeta3
    

    Again, sorry to bother you, but i really need this.
    Thanks a lot.

You must be logged in to reply to this topic.