Relative path powershell

Ed7 96 Reputation points
2021-12-02T09:33:24.81+00:00

Hello,

I need to construct a relative path from the directory at the top of the tree...
For example, if the file in question lives at absolute path C:\Users\MyUsername\Desktop\test.txt, and I decide that the root directory is C:\Users\MyUsername, the relative path would be Desktop\test.txt, which is what should be stored in the CSV.

I am going to check for several folders and its contents
In one variable can I use such as this: $variabel1 = "<pathtofolder1>","<pathtofolder2>","<pathtofolder3>"

Could you tell how I can do it whithin my current script please?

Here is my current powershell script:

$root = "C:\Users\"
$hasher = [System.Security.Cryptography.SHA256]::Create()
$AllFiles = @()

foreach ($file in get-childitem $root -recurse | Select-Object FullName, Directory, Name, PSIsContainer, Length, CreationTime, LastAccessTime, LastWriteTime, Path)

{
$acl = get-acl $file.fullname | select-object path,owner,accesstostring,group
$obj = new-object psObject
$obj | Add-Member -membertype noteproperty -name FilePathandName -Value $file.FullName
$obj | Add-Member -MemberType noteproperty -Name Path -Value $file.path
$obj | Add-Member -membertype noteproperty -name Name -Value $file.Name
$obj | Add-Member -MemberType noteproperty -Name Hash -Value $builder.ToString()
$obj | Add-Member -membertype noteproperty -name CreationTime -Value $file.CreationTime
$obj | Add-Member -MemberType noteproperty -Name LastAccessTime -Value $file.LastAccessTime
$obj | Add-Member -MemberType noteproperty -Name LastWriteTime -Value $file.LastWriteTime
$obj | Add-Member -MemberType noteproperty -Name Owner -Value $acl.owner
$obj | Add-Member -MemberType noteproperty -Name Group -Value $acl.group
$AllFiles += $obj

if(!$file.PsIsContainer)
{
$inputStream = New-Object IO.StreamReader $file.fullname
$hashBytes = $hasher.ComputeHash($inputStream.BaseStream)
$inputStream.Close()

$builder = New-Object System.Text.StringBuilder
$hashBytes | Foreach-Object { [void] $builder.Append($_.ToString("X2")) }
$obj | Add-Member -MemberType noteproperty -Name MD5Hash -Value $builder.ToString()
}
}

$AllFiles += $obj

$AllFiles |Export-Csv $report –NoTypeInformation

Microsoft 365 and Office Development Other
Windows for business Windows Server User experience PowerShell
Windows for business Windows Server User experience Other
Community Center Not monitored
0 comments No comments
{count} vote

5 answers

Sort by: Most helpful
  1. Clément BETACORNE 2,496 Reputation points
    2021-12-02T15:33:39.29+00:00

    Hello,

    You can use substring to achieve what you want, for example before writing the path attribute on your custom object you can do that :

    $Root = "C:\Users\"
    
    $items = Get-ChildItem -Path $Root -Recurse -File
    
    foreach($item in $items) {
        $relativePath = $item.FullName.Substring($Root.Length)
        $obj | Add-Member -MemberType noteproperty -Name Path -Value $relativePath
    }
    

    Regards,

    0 comments No comments

  2. Ed7 96 Reputation points
    2021-12-03T09:19:43.61+00:00

    HI @Clément BETACORNE ,

    Using the info you provided I can get the relative path, however it does keep one relative path using diferent paths.

    154746-image.png

    0 comments No comments

  3. MotoX80 36,291 Reputation points
    2021-12-03T16:30:18.82+00:00

    Your script is missing the $report variable, and you reference $builder before you create the object.
    Your Select-object references a path value, but Get-Childitem objects do not have a path value.
    You add the obj to AllFiles before you do the container processing.

    Give this script a try. It excludes the username from the relative path.

    $root = "C:\Users\"
    $report = "c:\temp\files.csv"
    $hasher = [System.Security.Cryptography.SHA256]::Create()
    $AllFiles = @()
    
    
    foreach ($file in get-childitem $root -recurse | Select-Object FullName, Directory, Name, PSIsContainer, Length, CreationTime, LastAccessTime, LastWriteTime)      # no path  , Path)
    
    {
        $file.fullname
        $acl = get-acl $file.fullname | select-object path,owner,accesstostring,group
        $obj = new-object psObject
        $obj | Add-Member -membertype noteproperty -name FilePathandName -Value $file.FullName
        # file does not have a path value   $obj | Add-Member -MemberType noteproperty -Name Path -Value $file.path
        $rp = $file.FullName.Substring($root.length)               # omit C:\users
        if ($rp.IndexOf("\") -lt 0) {                              # are looking the user itself? 
            $rp = ""                                               # there is no relative path  
        } else {
            $rp = $rp.Substring($rp.IndexOf("\") + 1)              # pick whatever come after the first slash 
        }
        $obj | Add-Member -MemberType noteproperty -Name RelativePath -Value $rp
        $obj | Add-Member -membertype noteproperty -name Name -Value $file.Name
        #  builder????     $obj | Add-Member -MemberType noteproperty -Name Hash -Value $builder.ToString()
        $obj | Add-Member -membertype noteproperty -name CreationTime -Value $file.CreationTime
        $obj | Add-Member -MemberType noteproperty -Name LastAccessTime -Value $file.LastAccessTime
        $obj | Add-Member -MemberType noteproperty -Name LastWriteTime -Value $file.LastWriteTime
        $obj | Add-Member -MemberType noteproperty -Name Owner -Value $acl.owner
        $obj | Add-Member -MemberType noteproperty -Name Group -Value $acl.group
        # not here     $AllFiles += $obj
    
        if(!$file.PsIsContainer)
        {
            "It's a container"
            $inputStream = New-Object IO.StreamReader $file.fullname
            $hashBytes = $hasher.ComputeHash($inputStream.BaseStream)
            $inputStream.Close()
    
            $builder = New-Object System.Text.StringBuilder
            $hashBytes | Foreach-Object { [void] $builder.Append($_.ToString("X2")) }
            $obj | Add-Member -MemberType noteproperty -Name MD5Hash -Value $builder.ToString()
        } else {
            $obj | Add-Member -MemberType noteproperty -Name MD5Hash -Value ""      # blank value because t does not apply 
        }
        $AllFiles += $obj                         # Add the object after all properties are built 
    
    }
    
    #  this would add the last obect twice.     $AllFiles += $obj
    
    
    $AllFiles |Export-Csv $report –NoTypeInformation
    
    0 comments No comments

  4. Jose Antonio Silva 11 Reputation points
    2021-12-03T21:48:43.153+00:00

    @Ed7
    Not sure what you looking for with that relative path, but ended up using your script to create a script for me too:
    154875-md5report.png

    param (  
        $root = "C:\Users\$env:USERNAME\",  
        $report = "$Env:TEMP\report-$env:USERNAME.csv"  
    )  
      
    $hasher = [System.Security.Cryptography.SHA256]::Create()  
      
    get-childitem $root -recurse |   
        Select-Object FullName, Name, PSIsContainer, Length, CreationTime, LastAccessTime, LastWriteTime |   
        foreach {   
            $file = $_  
            $acl = get-acl $file.fullname | select-object owner,group #,accesstostring  
            #merge attributes  
            $acl | get-member -MemberType NoteProperty | %{ Add-Member -InputObject $file -NotePropertyName $_.Name -NotePropertyValue $acl.$($_.Name)}  
              
            # add relative path  
            Add-Member -InputObject $file -NotePropertyName Path -NotePropertyValue $file.FullName.Replace($root,'')   
          
            # MD5Hash  
            $md5 = if(!$file.PsIsContainer) {  
                $inputStream = New-Object IO.StreamReader $_.fullname  
                $hashBytes = $hasher.ComputeHash($inputStream.BaseStream)  
                $inputStream.Close()  
      
                $builder = New-Object System.Text.StringBuilder  
                $hashBytes | Foreach-Object { [void] $builder.Append($_.ToString("X2")) }  
                $builder.ToString()  
            }  
            else {  
                ''  
            }  
            Add-Member -InputObject $file -NotePropertyName MD5Hash -NotePropertyValue $md5  
            $file  
        } |   
        Export-Csv -NoTypeInformation -Path $report  
      
    Write-host "Exported to $report" -ForegroundColor Green  
    #test  
    gc $report | convertfrom-csv | sort path | select name,length, MD5Hash, owner, path | ft  
       
    
    0 comments No comments

  5. Ed7 96 Reputation points
    2021-12-06T11:39:37.27+00:00

    Thank you guys for your help. It really worked as expected. Much appreciatted.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.