A set of functions that enable you to make use of multiple local SMB servers (eg ssh -L), or get explorer to interact with samba shares of other machines on non-standard ports
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
#Required: | |
Install-Module -Name LoopbackAdapter -MinimumVersion 1.2.0.0 | |
#run in admin terminal | |
#you do NOT need to disable/remove SMB 1.0/CIFS | |
#Troubleshooting: | |
#You can check [attempted] forwardings and [successful] listeners here, respectively | |
netsh interface portproxy show v4tov4 | |
netstat -an | sls ':445' | |
#With the server running (or `ssh -L` tunnel to the SMB on another network listening) | |
#you can check whether both the unforwarded and forwarded ports are operating with | |
Test-NetConnection -ComputerName IP -Port PORT | |
#This might be needed if the above shows forwardings are present, server is accessible, yet the port isn't listening. | |
#I'm only including it because it was mentioned in a tutorial I came across; | |
#like the SMB1.0 note above, I did not need to do it at all for my script to work | |
#and it runs fine (on my Win10 19044) with a stock/opposing setup. | |
# | |
#lanmanserver (local SMB) may be stealing ports (all interfaces) before iphlpsvc (netsh portproxy) can | |
#So add iphlpsvc as a dependant, takes effect upon reboot | |
sc.exe ` | |
config ` | |
lanmanserver ` | |
depend= ` | |
((&{ Get-Service -Name lanmanserver -RequiredServices | %{ $_.Name }; 'iphlpsvc'}) -join '/') | |
#similarly apparently workstation might be problematic | |
sc.exe ` | |
config ` | |
lanmanworkstation ` | |
depend= ` | |
((&{ Get-Service -Name lanmanworkstation -RequiredServices | %{ $_.Name }; 'iphlpsvc'}) -join '/') | |
#To Undo | |
sc.exe ` | |
config ` | |
lanmanserver ` | |
depend= ` | |
((Get-Service -Name lanmanserver -RequiredServices | %{ $_.Name } | ?{ $_ -ne 'iphlpsvc' }) -join '/') | |
sc.exe ` | |
config ` | |
lanmanworkstation ` | |
depend= ` | |
((Get-Service -Name lanmanworkstation -RequiredServices | %{ $_.Name } | ?{ $_ -ne 'iphlpsvc' }) -join '/') | |
#> | |
Import-Module -Name LoopbackAdapter | |
#Creates a link between this new hostname's ip's SMB port and the given destination ip/port | |
#Effectively making it so that you can visit \\newhost | |
#this is achieved by | |
#-adding a loopback device with the given IP | |
#-using netsh portproxy to link this IP's 445 with the destination | |
#-calling Add-Host so you no longer need to rememeber this IP | |
# (I attempt to detect clashes, but be careful of subnet intrusion, | |
# and arbituary windows limitations like 127.x.x.x not being available) | |
# | |
#The server does not need to be available at time of creation, it will merely be inaccessible | |
Function Create-Host { Param( | |
[Parameter(Mandatory=$true)]$Name, | |
[Parameter(Mandatory=$true)]$Ip, | |
[Parameter(Mandatory=$true)]$Dest, | |
[Parameter(Mandatory=$true)]$Port, | |
[switch]$Force | |
) | |
if ( | |
(Get-NetIPAddress -IPAddress $Ip -ErrorAction SilentlyContinue) -or | |
(Test-Connection $Ip -Quiet) | |
) { | |
throw "$Ip exists" | |
} | |
netsh ` | |
interface portproxy ` | |
add v4tov4 ` | |
listenaddress=$Ip ` | |
listenport=445 ` | |
connectaddress=$Dest ` | |
connectport=$Port | |
if (!$?) { | |
return | |
} | |
Add-Host ` | |
-Name $Name ` | |
-Ip $Ip ` | |
-Comment 'Loopback machine for custom SMB' ` | |
-Force:$Force | |
#the -PassThru of the cmdlets following this one return absolute junk so we cannot do it in one chain | |
$adapter = New-LoopbackAdapter -Name $Name -Force:$Force | |
$adapter ` | |
| Disable-NetAdapterBinding ` | |
-ComponentID ms_msclient,ms_pacer,ms_server,ms_lltdio,ms_rspndr | |
$adapter ` | |
| Set-DnsClient ` | |
-RegisterThisConnectionsAddress $False ` | |
-PassThru ` | |
| Set-NetIPInterface ` | |
-InterfaceMetric '254' ` | |
-WeakHostSend Enabled ` | |
-WeakHostReceive Enabled ` | |
-Dhcp Disabled | |
#this breaks hostname resolution, it also doesnt seem necessary as everything works | |
#(just keeping it here as it was present in a different tutorial I saw) | |
# -SkipAsSource $True | |
$adapter ` | |
| New-NetIPAddress ` | |
-IPAddress $Ip ` | |
-PrefixLength 32 ` | |
-AddressFamily IPv4 ` | |
| Out-Null | |
'Reboot your machine' | |
} | |
#cleans up after Create-Host | |
#NB Create-Host is persistent across reboots, you only need to call it once | |
#this is for when you will no longer be using the host at all | |
Function Retire-Host { Param( | |
[Parameter(Mandatory=$true)]$Name, | |
[switch]$Force | |
) | |
netsh ` | |
interface portproxy ` | |
delete v4tov4 ` | |
listenaddress=$(Reach-Host -Name $Name -Local) ` | |
listenport=445 | |
if (!$?) { | |
return | |
} | |
Remove-Host -Name $Name -Force:$Force | |
Remove-LoopbackAdapter -Name $Name -Force:$Force | |
} | |
#internal function for grabbing hosts from the hosts file | |
Function Local-Hosts { Param( | |
[Parameter(Mandatory=$true)]$Name, | |
[switch]$NotMatch | |
) | |
Select-String ` | |
-Path "$([Environment]::SystemDirectory)\drivers\etc\hosts" ` | |
-Pattern "^\s*([a-f0-9:.]+)\s+$([regex]::Escape($Name))(\s|$)" ` | |
-NotMatch:$NotMatch | |
} | |
#detects whether a hostname resolves on your machine | |
#-Local forces use only of the hosts file, ignoring DNS | |
Function Reach-Host { Param( | |
[Parameter(Mandatory=$true)]$Name, | |
[switch]$Local | |
) | |
if ($Local) { | |
Local-Hosts -Name $Name ` | |
| %{ $_.Matches.Groups[1].Value } | |
return | |
} | |
try { | |
Resolve-DnsName $Name -ErrorAction SilentlyContinue ` | |
| %{ $_.IPAddress } | |
} | |
catch { | |
} | |
} | |
#Adds the hostname to your hosts file with the given IP, adding any comment alongside | |
#without -Force I make sure you're not blocking any reachable hostname | |
Function Add-Host { Param( | |
[Parameter(Mandatory=$true)]$Name, | |
[Parameter(Mandatory=$true)]$Ip, | |
[switch]$Force, | |
$Comment='' | |
) | |
$exists = Reach-Host -Name $Name | |
if ($exists) { | |
if (!$Force) { | |
throw $exists | |
} | |
if (Local-Hosts -Name $Name) { | |
Remove-Host -Name $Name -Force | |
} | |
} | |
if ($Comment) { | |
$Comment = '#' + $Comment | |
} | |
[System.IO.File]::AppendAllText( | |
"$([Environment]::SystemDirectory)\drivers\etc\hosts", | |
("`r`n" + $Ip,$Name,$Comment -join "`t"), | |
[System.Text.Encoding]::ASCII | |
) | |
} | |
#Removes the hostname from the hosts file | |
#-Force skips the check that the host is actually present there | |
Function Remove-Host { Param( | |
[Parameter(Mandatory=$true)]$Name, | |
[switch]$Force | |
) | |
if ($Force) { | |
} | |
elseif (Local-Hosts -Name $Name) { | |
} | |
else { | |
throw "$Name not present" | |
} | |
[System.IO.File]::WriteAllLines( | |
"$([Environment]::SystemDirectory)\drivers\etc\hosts", | |
(Local-Hosts -Name $Name -NotMatch | %{ $_.Line }), | |
[System.Text.Encoding]::ASCII | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if you had created some hosts with ports like so | |
#Create-Host -Name 'frodo' -Ip '10.254.0.1' -Dest '127.0.0.1' -Port 21112 | |
#Create-Host -Name 'bilbo' -Ip '10.254.0.2' -Dest '127.0.0.1' -Port 21212 | |
#and there are some other services like RDP and SOCKS you want | |
#you can run this to attach an array of disks | |
# @{ | |
# H = '\\frodo\USER' | |
# G = '\\bilbo\shared$' | |
# I = '\\frodo\dbapps$' | |
# J = '\\frodo\joint$' | |
# P = '\\bilbo\public$' | |
# }.GetEnumerator() ` | |
# | ConnectSMB ` | |
# -server middle.earth ` | |
# -domain shire ` | |
# -account USER ` | |
# -socks 21012 ` | |
# -forwards @{ | |
# 21112 = 'frodo:445' | |
# 21212 = 'bilbo:445' | |
# 21312 = 'eyeofsauron:3389' | |
# } | |
#see the hardcoded.ps1 for a discription of what the function does (that was actually written first, before I generalised it here) | |
Function ConnectSMB { Param( | |
[Parameter(Mandatory=$true)][string]$server, | |
[string]$user, | |
[int]$socks, | |
[Parameter(Mandatory=$true)][System.Collections.Hashtable]$forwards, | |
[string]$domain, | |
[string]$account, | |
[Parameter(ValueFromPipeline=$true)][System.Collections.DictionaryEntry[]]$Input | |
) | |
Begin { | |
$success = @($socks) | |
$ssh = Start-Process ` | |
-NoNewWindow ` | |
-PassThru ` | |
ssh ` | |
( | |
$forwards.GetEnumerator() ` | |
| &{ | |
Begin { | |
if ($user) { | |
$server = "$user@$server" | |
} | |
$args = [System.Collections.ArrayList]@($server) | |
if ($socks) { | |
$args.AddRange(('-D',$socks)) | |
} | |
} | |
Process { | |
$args.AddRange(('-L', "$($_.Key):$($_.Value)")) | |
if (!$success[0]) { | |
$success[0] = ($_.Value -split ':')[-1] | |
} | |
} | |
End { | |
$args.AddRange(( | |
'-o', 'ExitOnForwardFailure=yes', | |
'-q', | |
'read; kill $PPID' | |
)) | |
$args | |
} | |
} | |
) | |
if (!$success[0]) { | |
throw 'Add some forwardings' | |
} | |
$tmp = $Global:ProgressPreference | |
$Global:ProgressPreference = 'SilentlyContinue' | |
try { | |
while (!(Test-NetConnection ` | |
-InformationLevel Quiet ` | |
-ComputerName localhost ` | |
-Port $success[0] ` | |
-WarningAction SilentlyContinue | |
)) { | |
if ($ssh.HasExited) { | |
throw 'SSH failed to connect!' | |
} | |
} | |
$ErrorActionPreference = 'Stop' | |
if (!$account) { | |
$account = $user | |
} | |
if ($domain) { | |
$account = "$domain\$account" | |
} | |
$credential = Get-Credential $account | |
} | |
catch { | |
if (!$ssh.HasExited) { | |
$ssh.Kill() | |
} | |
throw $_ | |
} | |
finally { | |
$Global:ProgressPreference = $tmp | |
} | |
} | |
Process { | |
try { | |
New-PSDrive ` | |
-PSPRovider FileSystem ` | |
-Name $_.Key ` | |
-Root $_.Value ` | |
-Credential $credential ` | |
-Persist | |
} | |
catch { | |
if (!$ssh.HasExited) { | |
$ssh.Kill() | |
} | |
throw $_ | |
} | |
} | |
End { | |
'Drives connected! Press enter when done.' | |
$ssh | Wait-Process | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#runs an ssh instance in the background, whilst still asking for ssh authentication if needed | |
#attaching SMB hosts on the other side to ports previously expected via Create-Host in attachsmb.ps1 | |
#as well as SOCKS and an RDP server | |
#when connected it will prompt for smb credentials and use these to hook up a number of network drives | |
#when done you simply hit enter in the terminal and the drives all detach and the ssh session is closed | |
# | |
#this is a hardcoded version of the example given in the generalised sshsmb script | |
#as you can see it's much simpler and more appropriate to use something like this if only ever using one configuration | |
#especially if passing around this script in an organisation (where users would really only be changing their username) | |
Function ConnectSMB { Param([Parameter(Mandatory=$true)]$user) | |
$ssh = Start-Process -NoNewWindow -PassThru ` | |
ssh ("$user@middle.earth", | |
'-D', '21012', | |
'-L', '21112:frodo:445', | |
'-L', '21212:bilbo:445', | |
'-L', '21312:eyeofsauron:3389', | |
'-o', 'ExitOnForwardFailure=yes', | |
'-q', | |
'read; kill $PPID') | |
$tmp = $Global:ProgressPreference | |
$Global:ProgressPreference = 'SilentlyContinue' | |
try { | |
while (!(Test-NetConnection ` | |
-InformationLevel Quiet ` | |
-ComputerName localhost ` | |
-Port 21012 ` | |
-WarningAction SilentlyContinue | |
)) { | |
if ($ssh.HasExited) { | |
throw 'SSH failed to connect!' | |
} | |
} | |
} | |
finally { | |
$Global:ProgressPreference = $tmp | |
} | |
try { | |
$ErrorActionPreference = 'Stop' | |
$cred = Get-Credential "shire\$user" | |
New-PSDrive -Name H -PSPRovider FileSystem -Root "\\frodo\$user" -Credential $cred -Persist | |
New-PSDrive -Name G -PSPRovider FileSystem -Root '\\bilbo\shared$' -Credential $cred -Persist | |
New-PSDrive -Name I -PSPRovider FileSystem -Root '\\frodo\dbapps$' -Credential $cred -Persist | |
New-PSDrive -Name J -PSPRovider FileSystem -Root '\\frodo\joint$' -Credential $cred -Persist | |
New-PSDrive -Name P -PSPRovider FileSystem -Root '\\bilbo\public$' -Credential $cred -Persist | |
'Drives connected! Press enter when done.' | |
$ssh | Wait-Process | |
} | |
finally { | |
if (!$ssh.HasExited) { | |
$ssh.Kill() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment