Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I query a temporary PS-Drive while returning files with a name relative to the drive?

I am trying to create a script where I will be searching the file servers for non inherited permissions. I have run into the 260 character limit for file names as a result. A suggestion I saw, that I thought would help, a couple of times was to create some non persistent PS Drives a couple of levels deep and query those.

Problem is when I use Get-ChildItem against the new PS Drives it is returning object with the full network path and not using the name I assigned it.

# Cycle the folders
Get-ChildItem $rootPath -Directory | select -first 1 | ForEach-Object{
    $target = $_

    # Create a PS Drive for each sub directory and get all the folders
    [void](New-PSDrive -Name $target.Name -PSProvider FileSystem $target.FullName)

    # Get the file objects. 
    Get-ChildItem "$($target.Name):\" -Recurse
}

I am sure that if I created some proper persistent network drives with a drive letter I would not have this issue.

Hopefully I just didn't miss it but Technet for New-PSDrive was not 100% clear about this scenario.

I am looking for a way to make ps-drive and reference there folders while returning paths relative to the new drive name. Consider the output from a psdrive I made (G:) then one of my mapped network drives (M:).

PS M:\> Get-ChildItem G:\

    Directory: \\server01\COMMON\Folder

Mode                LastWriteTime     Length Name                                                                                                            
----                -------------     ------ ----                                                                                                            
d----         6/18/2011   8:14 AM            Folder 1                                                                                                          
d----         6/18/2011   8:14 AM            Folder 2 

PS M:\> Get-ChildItem M:\

    Directory: M:\

Mode                LastWriteTime     Length Name                                                                                                            
----                -------------     ------ ----                                                                                                            
d----          5/8/2015  11:00 AM            Backup                                                                                                          
d----          5/8/2015  11:00 AM            covers                                                                                                          
d----          5/8/2015  11:00 AM            drop                                                                                                            
d----          5/8/2015  11:00 AM            Expense         

I am aware that multiple workarounds exists for my exact situation but I would like to understand the behavior that I am showing with New-PSDrive.

like image 489
Matt Avatar asked Jan 15 '16 13:01

Matt


People also ask

What does the command Get-PSDrive do?

The Get-PSDrive cmdlet gets the drives in the current session. You can get a particular drive or all drives in the session. This cmdlet gets the following types of drives: Windows logical drives on the computer, including drives mapped to network shares.

What is PSDrive in PowerShell?

Windows PowerShell uses the noun, PSDrive, for commands that work with Windows PowerShell drives. For a list of the Windows PowerShell drives in your Windows PowerShell session, use the Get-PSDrive cmdlet.

Can you use Net use in PowerShell?

Although we can use Net Use in PowerShell, there is a more powerful alternative, the New-PSDrive cmdlet. With the New-PSDrive cmdlet, we cannot only map network drives but also create drive mappings to local folders or registry keys on our computer.


2 Answers

Looks like you are mixing up two different things: PowerShell path and Provider path. PowerShell paths are not visible outside of PowerShell.

New-PSDrive X FileSystem C:\Windows
(Get-Item X:\System32\notepad.exe).get_Length() #OK
([IO.FileInfo]'X:\System32\notepad.exe').get_Length() #Error

But Get-Item X:\System32\notepad.exe managed to create a FileInfo object, which represents some file. So, what file is represented by the resulting FileInfo object?

(Get-Item X:\System32\notepad.exe).FullName
# C:\Windows\System32\notepad.exe

Since the FileInfo object knows nothing about PowerShell drive X:, it has to store a path, which internally uses the file system API which it can understand. You can use Convert-Path cmdlet to convert PowerShell path to Provider path:

Convert-Path X:\System32\notepad.exe
# C:\Windows\System32\notepad.exe

Same happens when you create the PowerShell drive, which point to some network path:

New-PSDrive Y FileSystem \\Computer\Share
Get-ChildItem Y:\

Returned FileInfo and DirectoryInfo objects know nothing about Y:, so they can not have paths relative to that PowerShell drive. Internally used file system API will not understand them.

Things changes when you use the -Persist option. In that case real mapped drives will be created, which can be understood by file system API outside of PowerShell.

New-PSDrive Z FileSystem \\Computer\Share -Persist|Format-Table *Root
# Root        : Z:\
# DisplayRoot : \\Computer\Share

As you can see, the Root will be not \\Computer\Share as you ask in New-PSDrive cmdlet, but Z:\. Since Z: is a real drive in this case, FileInfo and DirectoryInfo objects returned by Get-Item or Get-ChildItem cmdlet can have paths relative to it.

like image 73
user4003407 Avatar answered Sep 22 '22 02:09

user4003407


haven't tested, but if you're not opposed to using 'subst' something like this might work for you

function Get-FreeDriveLetter {
    $drives = [io.driveinfo]::getdrives() | % {$_.name[0]}
    $alpha = 65..90 | % { [char]$_ }
    $avail = diff $drives $alpha | select -ExpandProperty inputobject
    $drive = $avail[0] + ':'
    $drive
}

$file = gi 'C:\temp\file.txt'
$fullname = $file.FullName

if ($fullname.length -gt 240) {
    $drive = Get-FreeDriveLetter
    $path = Split-Path $fullname
    subst $drive $path
    $subst = $true
    rv path
    $fullname = Join-Path $drive $(Split-Path $fullname -Leaf)
}

$fullname
like image 31
Anthony Stringer Avatar answered Sep 21 '22 02:09

Anthony Stringer