Hi!
Today’s post will be about very interesting thing, named SymLink. What Wikipedia says about it:
In computing, a symbolic link (also symlink or soft link) is the nickname for any file that contains a reference to another file or directory in the form of an absolute or relative path and that affects pathname resolution
It could be a very useful things in different scenarios.
So, how you could create SymLink in Windows? Here an example:
1 |
mklink /D "C:\Users\<yourusername>\Appdata\Local\Plex Media Server" "G:\Plex Media Server" |
But for creating SymLinks you should have permissions. If you use can window way it’s simple:
- Open the Local Group Policy Editor (
gpedit.msc
) - Edit the Create symbolic links policy at:Computer configuration → Windows Settings → Security Settings → Local Policies → User Rights Assignment → Create symbolic links
But if you need to use console way (for example, automatic deploy or similar) it could be a bit complicated. We will use PowerShell to achieve that.
So, here a script that allows us to do that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
function addSymLinkPermissions($accountToAdd){ Write-Host "Checking SymLink permissions.." $sidstr = $null try { $ntprincipal = new-object System.Security.Principal.NTAccount "$accountToAdd" $sid = $ntprincipal.Translate([System.Security.Principal.SecurityIdentifier]) $sidstr = $sid.Value.ToString() } catch { $sidstr = $null } Write-Host "Account: $($accountToAdd)" -ForegroundColor DarkCyan if( [string]::IsNullOrEmpty($sidstr) ) { Write-Host "Account not found!" -ForegroundColor Red exit -1 } Write-Host "Account SID: $($sidstr)" -ForegroundColor DarkCyan $tmp = [System.IO.Path]::GetTempFileName() Write-Host "Export current Local Security Policy" -ForegroundColor DarkCyan secedit.exe /export /cfg "$($tmp)" $c = Get-Content -Path $tmp $currentSetting = "" foreach($s in $c) { if( $s -like "SECreateSymbolicLinkPrivilege*") { $x = $s.split("=",[System.StringSplitOptions]::RemoveEmptyEntries) $currentSetting = $x[1].Trim() } } if( $currentSetting -notlike "*$($sidstr)*" ) { Write-Host "Need to add permissions to SymLink" -ForegroundColor Yellow Write-Host "Modify Setting ""Create SymLink""" -ForegroundColor DarkCyan if( [string]::IsNullOrEmpty($currentSetting) ) { $currentSetting = "*$($sidstr)" } else { $currentSetting = "*$($sidstr),$($currentSetting)" } Write-Host "$currentSetting" $outfile = @" [Unicode] Unicode=yes [Version] signature="`$CHICAGO`$" Revision=1 [Privilege Rights] SECreateSymbolicLinkPrivilege = $($currentSetting) "@ $tmp2 = [System.IO.Path]::GetTempFileName() Write-Host "Import new settings to Local Security Policy" -ForegroundColor DarkCyan $outfile | Set-Content -Path $tmp2 -Encoding Unicode -Force Push-Location (Split-Path $tmp2) try { secedit.exe /configure /db "secedit.sdb" /cfg "$($tmp2)" /areas USER_RIGHTS } finally { Pop-Location } } else { Write-Host "NO ACTIONS REQUIRED! Account already in ""Create SymLink""" -ForegroundColor DarkCyan Write-Host "Account $accountToAdd already has permissions to SymLink" -ForegroundColor Green return $true; } } |
If in two words, the main process could be divided in two steps:
The first one is to load existing Local Security Policy configuration using secedit.exe to the temporary file to check if already have needed permissions:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$tmp = [System.IO.Path]::GetTempFileName() Write-Host "Export current Local Security Policy" -ForegroundColor DarkCyan secedit.exe /export /cfg "$($tmp)" $c = Get-Content -Path $tmp $currentSetting = "" foreach($s in $c) { if( $s -like "SECreateSymbolicLinkPrivilege*") { $x = $s.split("=",[System.StringSplitOptions]::RemoveEmptyEntries) $currentSetting = $x[1].Trim() } } if( $currentSetting -notlike "*$($sidstr)*" ) { Write-Host "Need to add permissions to SymLink" -ForegroundColor Yellow |
And if need to add them, we should create another temporary file with new settings and import it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$outfile = @" [Unicode] Unicode=yes [Version] signature="`$CHICAGO`$" Revision=1 [Privilege Rights] SECreateSymbolicLinkPrivilege = $($currentSetting) "@ $tmp2 = [System.IO.Path]::GetTempFileName() Write-Host "Import new settings to Local Security Policy" -ForegroundColor DarkCyan $outfile | Set-Content -Path $tmp2 -Encoding Unicode -Force Push-Location (Split-Path $tmp2) try { secedit.exe /configure /db "secedit.sdb" /cfg "$($tmp2)" /areas USER_RIGHTS } finally { Pop-Location } |
That’s it 🙂
Thanks for your attention! 🙂