Recentelijk had ik de behoefte om een symbolische link te maken tijdens het uitvoeren van een scan op een aantal systemen en ontdekte dat er geen native manier was in PowerShell om dit te bereiken. Nu kan ik mklink.exe gebruiken om dit te laten werken, maar dit werkt alleen onder cmd.exe. Dit betekent dat ik mklink.exe niet kan aanroepen onder PowerShell.
mklink.exe
In plaats daarvan moet ik eerst cmd.exe aanroepen gevolgd door mklink.exe om toegang te krijgen tot het commando.
cmd.exe /c mklink.exe
Dus je zou denken dat ik tevreden zou zijn met dit resultaat. Nou, dat ben ik niet. Ik zou niet eerst cmd.exe hoeven aan te roepen voordat ik mklink.exe gebruik om een symbolische koppeling te maken. En dankzij het gebruik van Pinvoke om in de Win32 API te komen, hoef ik dit lot niet te accepteren!
Ga ik naar pinvoke.net, zie ik onder de kernel32 dat er een functie is genaamd CreateSymbolicLink die voldoet aan wat ik zoek.
De basis van wat ik nodig heb staat hieronder:
public static extern bool CreateSymbolicLink(strin
Ik moest het sleutelwoord ‘public’ aan het begin toevoegen, zodat deze functie beschikbaar is als ik hem aan mijn sessie toevoeg. Dit is niet alle code, alleen wat beschikbaar was op de site. Ik moest een beetje C# coderen om hier een type van te maken dat ik in mijn PowerShell sessie kan importeren met 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
Nu heb ik een type dat kan worden gebruikt om een symbolische koppeling te maken. Het enige dat nodig is, is een Pad dat voor de koppeling moet worden gebruikt en de eigenlijke SymNaam, en dan een 0 (Bestand) of een 1 (Directory) om te bepalen wat voor soort symbolische koppeling er wordt gemaakt. De resulterende waarde is een booleaanse waarde die gemakkelijk kan worden toegevoegd aan een If/Else statement om de rest van de acties af te handelen.
::CreateSymbolicLink('C:\Users\Administrator\Desktop\SQL2008Install',"\dc1\SharedStorage\SQL 2008",1)
Als u naar de symbolische koppeling SQL2008Install kijkt, ziet u aan de attributen dat het een symbolische koppeling is, aangezien deze is gelabeld als een ReparsePoint:
Daarmee heb ik nu een symbolische koppeling op mijn bureaublad die verwijst naar de SQL2008-installatiemap op mijn externe server.
Omdat deze methode wat werk vereist, is het niet meer dan logisch dat dit een functie kan worden die herbruikbaar is.
New-SymLink
Deze functie doet in principe wat ik heb laten zien, maar in een functievorm die overdraagbaar is en gemakkelijker te gebruiken. Hiermee kunt u een symbolische koppeling maken voor een map of een bestand.
Het begin van mijn functie bestaat uit controleren of ik mijn pinvoke-type al heb geladen en zo niet, het type toevoegen met 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); } }"@ }}
Het procesblok (ik sta pijplijninvoer toe voor de parameter Pad) is waar ik mijn type gebruik om de symbolische koppeling te maken en kijk of er problemen optreden tijdens dit proces. Als extra wordt een object uitgevoerd met de symbolische koppeling en het doelpad waarnaar de koppeling verwijst.
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) } }}
Laat dit eens in actie zien!
New-SymLink -Path "C:\Users\Administrator\Downloads" -SymName Downloads -Directory -Verbose
En daarmee heeft de functie een symbolische koppeling gemaakt voor mijn downloads-map op mijn bureaublad. De link om deze functie te downloaden staat hieronder. Laat me weten wat je van deze functie vindt!
Download
Script Repository