2009-05-03 15 views
17

Ho uno script PowerShell che sta camminando su un albero di directory e talvolta ho file ausiliari collegati in modo fisso che non devono essere elaborati. C'è un modo semplice per scoprire se un file (ovvero,) è un collegamento reale o no?Scoprire se un file è un collegamento simbolico in PowerShell

In caso contrario, sarebbe più semplice con collegamenti simbolici (symlink)?

risposta

30

Prova questo:

function Test-ReparsePoint([string]$path) { 
    $file = Get-Item $path -Force -ea SilentlyContinue 
    return [bool]($file.Attributes -band [IO.FileAttributes]::ReparsePoint) 
} 

Si tratta di un'implementazione piuttosto limitata, ma dovrebbe fare il trucco. Si noti che questo non fa distinzione tra un collegamento fisico e un collegamento simbolico. Sotto, entrambi approfittano semplicemente di NTFS reparse points, IIRC.

+0

Gli hard link sono semplicemente voci di file aggiuntive nella MFT e in quanto tali appaiono come normali file, a meno che qualcuno non guardi il numero di collegamenti a quel file. Ma finora non ho provato un collegamento simbolico. Effettivamente ha impostato l'attributo ReparsePoint. Grazie.(Anche se i collegamenti simbolici sono più complessi da gestire, poiché non ho le autorizzazioni per crearli di default: /) – Joey

+2

Penso che non sia vero che i collegamenti fisici e i link simbolici utilizzano lo stesso meccanismo. Come ha sottolineato Johannes, i collegamenti fissi sono solo un'altra voce nella MFT. Un collegamento simbolico è un punto di analisi. Sono diversi. http://stackoverflow.com/questions/817794/find-out-whether-a-file-is-a-symlink-in-powershell/2255548#2255548 – Cheeso

+0

E 'possibile inoltre verificare se il link simbolico è ancora valido? (O in altre parole, se la directory di destinazione non è stata cancellata) –

3

I miei risultati su Vista, utilizzando lo script PowerShell di Keith Hill per testare i collegamenti simbolici e collegamenti fisici:

c:\markus\other>mklink symlink.doc \temp\2006rsltns.doc 
symbolic link created for symlink.doc <<===>> \temp\2006rsltns.doc 

c:\markus\other>fsutil hardlink create HARDLINK.doc \temp\2006rsltns.doc 
Hardlink created for c:\markus\other\HARDLINK.doc <<===>> c:\temp\2006rsltns.doc 

c:\markus\other>dir 
Volume in drive C has no label. 
Volume Serial Number is C8BC-2EBD 

Directory of c:\markus\other 

02/12/2010 05:21 PM <DIR>   . 
02/12/2010 05:21 PM <DIR>   .. 
01/10/2006 06:12 PM   25,088 HARDLINK.doc 
02/12/2010 05:21 PM <SYMLINK>  symlink.doc [\temp\2006rsltns.doc] 
       2 File(s)   25,088 bytes 
       2 Dir(s) 6,805,803,008 bytes free 

c:\markus\other>powershell \script\IsSymLink.ps1 HARDLINK.doc 
False 

c:\\markus\other>powershell \script\IsSymLink.ps1 symlink.doc 
True 

Esso dimostra che i link simbolici sono punti di analisi, e hanno il ReparsePoint FileAttribute impostato il bit, mentre collegamenti fisici non lo fanno.

2

Il seguente script di PowerShell elencherà tutti i file in una directory o directory con l'opzione -recurse. Elencherà il nome del file, che si tratti di un file normale o di un file hardlink, e della dimensione, separati da due punti.

Deve essere eseguito dalla riga di comando di PowerShell. Non importa da quale directory lo si esegue come è impostato nello script.

Utilizza l'utilità fslink fornita con Windows e la esegue su ogni file utilizzando gli switch hardlink e list e conta le righe di output. Se due o più è un file hardlink.

Ovviamente è possibile modificare la directory dalla quale inizia la ricerca modificando il comando c:\windows\system. Inoltre, lo script scrive semplicemente i risultati in un file, c:\hardlinks.txt. Puoi cambiare il nome o semplicemente eliminare tutto dal carattere> e verrà visualizzato sullo schermo.

Get-ChildItem -path C:\Windows\system -file -recurse -force | 
    foreach-object { 
     if ((fsutil hardlink list $_.fullname).count -ge 2) { 
      $_.PSChildname + ":Hardlinked:" + $_.Length 
     } else { 
      $_.PSChildname + ":RegularFile:" + $_.Length 
     } 
    } > c:\hardlinks.txt 
10

Utilizzare Where-Object per cercare l'attributo file ReparsePoint.

Get-ChildItem | Where-Object { $_.Attributes -match "ReparsePoint" } 
+1

Implementazione molto più semplice (+1) – user66001

+0

@ user66001 - Più semplice sì, ma un'avvertenza è che questo sarà molto più lento per le strutture di cartelle di grandi dimensioni. –

+0

Rispetto alle altre risposte (che esistevano quando è stato effettuato il mio commento)? – user66001

6

Se avete PowerShell 5+ seguente one-liner elenca in modo ricorsivo tutti i collegamenti fisici di file, giunzioni di directory ei link simbolici e ai loro obiettivi a partire da d:\Temp\:

dir 'd:\Temp' -recurse -force | ?{$_.LinkType} | select FullName,LinkType,Target 

uscita:

FullName        LinkType  Target 
--------        --------  ------ 
D:\Temp\MyJunctionDir     Junction  {D:\exp\junction_target_dir} 
D:\Temp\MySymLinkDir     SymbolicLink {D:\exp\symlink_target_dir} 
D:\Temp\MyHardLinkFile.txt    HardLink  {D:\temp\MyHardLinkFile2.txt, D:\exp\hlink_target.xml} 
D:\Temp\MyHardLinkFile2.txt    HardLink  {D:\temp\MyHardLinkFile.txt, D:\exp\hlink_target.xml} 
D:\Temp\MySymLinkFile.txt    SymbolicLink {D:\exp\symlink_target.xml} 
D:\Temp\MySymLinkDir\MySymLinkFile2.txt SymbolicLink {D:\temp\normal file.txt} 

Se ci si preoccupa di più destinazioni per collegamenti fissi, utilizzare questa variante che elenca le schede separate da tabulazione:

dir 'd:\Temp' -recurse -force | ?{$_.LinkType} | select FullName,LinkType,@{ Name = "Targets"; Expression={$_.Target -join "`t"} } 

Potrebbe essere necessario disporre dei privilegi di amministratore per eseguire questo script, ad esempio C:\.