Di recente, ho avuto la necessità di creare un link simbolico durante l’esecuzione di una scansione su alcuni sistemi e ho scoperto che non c’era un modo nativo in PowerShell per farlo. Ora posso usare mklink.exe per farlo funzionare, ma questo funzionerà solo sotto cmd.exe. Questo significa che non posso effettivamente chiamare mklink.exe sotto PowerShell.
mklink.exe
Invece, devo prima chiamare cmd.exe seguito da mklink.exe per accedere al comando.
cmd.exe /c mklink.exe
Potreste quindi pensare che sarei soddisfatto di questo risultato. Beh, non lo sono. Non dovrei contare sul fatto di chiamare cmd.exe prima di usare mklink.exe per creare un collegamento simbolico. E grazie all’uso di Pinvoke per entrare nelle API Win32, non devo accettare questo destino!
Andando su pinvoke.net, vedo sotto il kernel32 che c’è una funzione chiamata CreateSymbolicLink che soddisfa quello che sto cercando.
Le basi di ciò di cui ho bisogno sono qui sotto:
public static extern bool CreateSymbolicLink(strin
Ho dovuto aggiungere la parola chiave ‘public’ all’inizio così questa funzione sarà disponibile quando la aggiungerò nella mia sessione. Questo non è tutto il codice, solo quello che era disponibile sul sito. Ho dovuto fare un po’ di codifica C# per trasformarlo in un tipo che posso importare nella mia sessione PowerShell usando Add-Type.
Add-Type @"using System;using System.Runtime.InteropServices; namespace mklink{ public class symlink { public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); }}"@
| get-member -static
Ora ho un tipo che può essere usato per creare un link simbolico. Tutto ciò che richiede è un Path da usare per il collegamento e il SymName attuale e poi uno 0 (File) o un 1 (Directory) per decidere che tipo di collegamento simbolico verrà creato. Il valore risultante è un valore booleano che può essere facilmente aggiunto in una dichiarazione If/Else per gestire il resto delle azioni.
::CreateSymbolicLink('C:\Users\Administrator\Desktop\SQL2008Install',"\dc1\SharedStorage\SQL 2008",1)
Guardando il link simbolico SQL2008Install, si vede dagli attributi che è un link simbolico poiché è etichettato come ReparsePoint:
Con questo, ora ho un link simbolico sul mio desktop che punta alla cartella di installazione di SQL2008 sul mio server remoto.
Poiché questo metodo richiede un po’ di lavoro, è naturale che questo possa diventare una funzione riutilizzabile.
New-SymLink
Questa funzione fondamentalmente fa quello che vi ho mostrato, ma in una forma di funzione che è portatile e più facile da usare. Questo vi permette di creare un link simbolico sia per una directory che per un file.
La parte iniziale della mia funzione consiste nel controllare se ho già caricato il mio tipo pinvoke e, in caso contrario, aggiungere il tipo usando Add-Type.
Begin { Try { $null = } Catch { Add-Type @" using System; using System.Runtime.InteropServices; namespace mklink { public class symlink { public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); } }"@ }}
Il blocco di processo (sto permettendo l’input della pipeline per il parametro Path) è dove uso il mio tipo per creare il link simbolico e osservare eventuali problemi durante questo processo. Come elemento aggiunto, produrrò un oggetto che mostra il link simbolico e il percorso di destinazione a cui il link fa riferimento.
Process { #Assume target Symlink is on current directory if not giving full path or UNC If ($SymName -notmatch "^(?::\)|(?:\\\w+\$)") { $SymName = "{0}\{1}" -f $pwd,$SymName } $Flag = @{ File = 0 Directory = 1 } If ($PScmdlet.ShouldProcess($Path,'Create Symbolic Link')) { Try { $return = ::CreateSymbolicLink($SymName,$Path,$Flag) If ($return) { $object = New-Object PSObject -Property @{ SymLink = $SymName Target = $Path Type = $PScmdlet.ParameterSetName } $object.pstypenames.insert(0,'System.File.SymbolicLink') $object } Else { Throw "Unable to create symbolic link!" } } Catch { Write-warning ("{0}: {1}" -f $path,$_.Exception.Message) } }}
Vediamolo in azione!
New-SymLink -Path "C:\Users\Administrator\Downloads" -SymName Downloads -Directory -Verbose
E con questo, la funzione crea un link simbolico per la mia cartella dei download sul mio desktop. Il link per scaricare questa funzione è qui sotto. Fatemi sapere cosa ne pensate di questa funzione!
Download
Script Repository