När jag nyligen behövde skapa en symbolisk länk när jag körde en genomsökning av vissa system upptäckte jag att det inte fanns något inhemskt sätt i PowerShell att göra detta. Nu kan jag använda mklink.exe för att få detta att fungera, men detta fungerar endast under cmd.exe. Detta innebär att jag faktiskt inte kan anropa mklink.exe under PowerShell.
mklink.exe
Istället måste jag först anropa cmd.exe följt av mklink.exe för att få åtkomst till kommandot.
cmd.exe /c mklink.exe
Så man skulle kunna tro att jag skulle vara nöjd med detta resultat. Men det är jag inte. Jag borde inte behöva förlita mig på att jag först ringer cmd.exe innan jag använder mklink.exe för att skapa en symbolisk länk. Och tack vare att jag använder Pinvoke för att komma in i Win32 API behöver jag inte acceptera detta öde!
Genom att gå ut på pinvoke.net ser jag under kernel32 att det finns en funktion som heter CreateSymbolicLink som uppfyller det jag letar efter.
De grundläggande delarna av vad jag behöver finns nedan:
public static extern bool CreateSymbolicLink(strin
Jag var tvungen att lägga till nyckelordet ”public” i början så att denna funktion blir tillgänglig när jag lägger till den i min session. Detta är inte hela koden, bara det som fanns tillgängligt på webbplatsen. Jag var tvungen att göra lite C#-kodning för att göra detta till en typ som jag kan importera till min PowerShell-session med hjälp av 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 har jag en typ som kan användas för att skapa en symbolisk länk. Allt som krävs är en Path som ska användas för länken och det faktiska SymName och sedan antingen en 0 (File) eller en 1 (Directory) för att bestämma vilken typ av symbolisk länk som ska skapas. Det resulterande värdet är ett boolskt värde som enkelt kan läggas till i ett If/Else-uttalande för att hantera resten av åtgärderna.
::CreateSymbolicLink('C:\Users\Administrator\Desktop\SQL2008Install',"\dc1\SharedStorage\SQL 2008",1)
Om man tittar på den symboliska länken SQL2008Install ser man genom attributen att det är en symbolisk länk eftersom den är märkt som en ReparsePoint:
Därmed har jag nu en symbolisk länk på mitt skrivbord som pekar på mappen SQL2008Install på min fjärrserver.
Med tanke på att denna metod kräver en del arbete är det naturligt att detta kan bli en funktion som kan återanvändas.
New-SymLink
Denna funktion gör i princip samma sak som jag har visat, men i en funktionsform som är portabel och mer lättanvänd. Den gör det möjligt att skapa en symbolisk länk för antingen en katalog eller en fil.
Den inledande delen av min funktion innebär att jag kontrollerar om jag redan har laddat upp min pinvoke-typ och om inte, lägger jag till typen med hjälp av 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); } }"@ }}
I processblocket (jag tillåter pipelineinmatning för Path-parametern) använder jag min typ för att skapa den symboliska länken och bevakar om det uppstår några problem under denna process. Som ett tillägg kommer jag att ge ut ett objekt som visar den symboliska länken och målvägen som länken hänvisar till.
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) } }}
Låt oss se det här i praktiken!
New-SymLink -Path "C:\Users\Administrator\Downloads" -SymName Downloads -Directory -Verbose
Och med det skapar funktionen en symbolisk länk för min nedladdningsmapp på skrivbordet. Länken för att ladda ner den här funktionen finns nedan. Låt mig veta vad du tycker om den här funktionen!
Download
Script Repository