Last active
June 30, 2017 20:43
-
-
Save Diagonactic/7182862f01f521aa302730b26a787023 to your computer and use it in GitHub Desktop.
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
<# | |
.SYNOPSIS | |
Looks up the first virtual machine and attempts to connect to it with Secure Shell using Public/Private Key Authentication | |
.DESCRIPTION | |
Used to make a connection to a Virtual Machine that has a DHCP address which changes often. Works in a non-elevated prompt, however, requires that the user be able to elevate | |
a session (ie. the user must know an Administrator password or be logged in as an administrative user in a non-elevated prompt). The script will elevate the user for the purpose | |
of getting the Hyper-V IP address, but will run the Secure Shell session as the non-elevated user if the session isn't elevated. | |
The script has the following requirements: | |
1. The SSH.EXE file must be in the $env:PATH or the directory that the script is executed from. | |
2. A private key with the file name 'id_rsa' that can be used to connect to the host is located either in $env:USERPROFILE\.ssh or within the Bash on Windows "root" user's | |
~/.ssh folder named 'id_rsa'. Note that the keypair doesn't have to be an RSA keypair, that filename was just used because it was what mine was named. | |
If the $env:USERPROFILE\.ssh folder isn't there, it'll be created and the script will attempt to copy the .ssh file from the Bash on Windows root folder. | |
The detected IP address is outputted before connecting since you might need it for something else (or just to verify that it's the right place). | |
If you have more than one VM and the target VM isn't the first (at $Index 0), you can run (in an elevated Powershell prompt): | |
(Get-VM | ?{$_.ReplicationMode -ne "Replica"} | Select -ExpandProperty NetworkAdapters | Select IPAddresses).IPAddresses | |
This will get a list of IP addresses assigned to the Virtual Machines on your computer. The Index will be the line number with the first line being 0. | |
.PARAMETER UserId | |
Specifies the user ID to login to the SSH session with | |
.PARAMETER VmIndex | |
Specifies the index of the Virtual Machine (default is 0) | |
#> | |
param( | |
[Parameter(Mandatory=$true, Position=0)][string]$UserId, | |
[int]$VmIndex=0 | |
) | |
Function Get-ElevantedCommandLine { | |
[OutputType([string])] | |
param ( | |
[Parameter(Mandatory = $true, Position=0)][string]$InputFile, | |
[Parameter(Mandatory = $true, Position=1)][string]$OutputFile, | |
[Parameter(Mandatory = $true, Position=2)][string]$ErrorFile, | |
[Parameter(Mandatory = $true, Position=3)][ScriptBlock] $ScriptBlock | |
) | |
process { | |
$Local:subCommand = "Set-Location '$($pwd.Path)'; `$output = Import-CliXml '$inputFile' | & { $($scriptblock.ToString()) } 2>&1 ; Out-File -FilePath '$errorFile' -InputObject `$error;Export-CliXml -Depth 1 -In `$output '$outputFile';" | |
return "-NonInteractive -NoProfile -EncodedCommand $([Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Local:subCommand)))" | |
} | |
} | |
Function Invoke-ElevatedCommand { | |
param ( | |
[Parameter(Mandatory = $true)][ScriptBlock] $Scriptblock, | |
[Parameter(ValueFromPipeline = $true)]$InputObject | |
) | |
begin { | |
Set-StrictMode -Version Latest | |
$inputItems = New-Object System.Collections.ArrayList | |
} | |
process { | |
$null = $inputItems.Add($inputObject) | |
} | |
end { | |
$outputFile = [IO.Path]::GetTempFileName() | |
$inputFile = [IO.Path]::GetTempFileName() | |
$errorFile = [IO.Path]::GetTempFileName() | |
$inputItems.ToArray() | Export-CliXml -Depth 1 $inputFile | |
$Local:commandLine = Get-ElevantedCommandLine $Local:inputfile $Local:outputfile $Local:errorFile -ScriptBlock $scriptBlock | |
(Start-Process -FilePath (Get-Command powershell).Definition -ArgumentList $Local:commandLine -Passthru -Verb RunAs -WindowStyle "Hidden").WaitForExit() | |
$errorMessage = $(gc $errorFile | Out-String) | |
if($errorMessage) { Write-Error -Message $errorMessage } else { | |
if((Get-Item $outputFile).Length -gt 0) { | |
Import-CliXml $outputFile | |
} | |
} | |
Remove-Item $outputFile, $inputFile, $errorFile | |
} | |
} | |
function Test-Administrator { | |
return (New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) | |
} | |
function Get-CommandLocalOrPath { | |
[OutputType([string])] | |
param ( | |
[Parameter(Mandatory=$true, Position=0)][string]$FileName | |
) | |
process { | |
$Local:retVal = ".\$FileName" | |
if (Test-Path "$Local:retVal" -PathType Leaf) { | |
return "$Local:retVal" | |
} | |
else { | |
$Local:retVal = (Get-Command $FileName -ErrorAction SilentlyContinue).Source | |
if (-not ([string]::IsNullOrWhiteSpace($Local:retVal))) { | |
if (Test-Path "$Local:retVal" -ErrorAction Ignore -PathType Leaf) { | |
return "$Local:retVal" | |
} | |
} | |
} | |
return $null | |
} | |
} | |
$Script:Ssh = Get-CommandLocalOrPath -FileName "ssh.exe" | |
if ($Script:Ssh -eq $null) { | |
Write-Host "Secure Shell client is not installed or not in path" | |
exit | |
} | |
$Script:BashOnWindowsKeyFile = [System.IO.Path]::Combine("$env:LOCALAPPDATA", "Lxss\root\.ssh\id_rsa") | |
$Script:LocalSshPath = [System.IO.Path]::Combine("$env:USERPROFILE", ".ssh") | |
$Script:LocalSshKeyFile = [System.IO.Path]::Combine("$env:USERPROFILE", ".ssh\id_rsa") | |
if (-not (Test-Path "$Script:LocalSshPath" -PathType Container)) { | |
Write-Host "An SSH directory was not found in your home drive - Attempting to create it" | |
mkdir "$Script:LocalSshPath" | |
$Local:Success = $? | |
if (-not ($Local:Success)) { | |
Write-Host "Couldn't create '$env:LocalSshPath'. Please create this manually and copy your private key to this folder" | |
exit | |
} | |
} | |
if (-not (Test-Path "$env:HOME\.ssh\id_rsa" -PathType Leaf)) { | |
if (-not (Test-Path "$Local:BashOnWindowsKeyFile" -PathType Leaf)) { | |
Write-Host "'id_rsa' file does not exist in Bash on Windows Profile. Copy your private key to '$Script:LocalSshKeyFile'" | |
exit | |
} | |
Copy "$Script:BashOnWindowsKeyFile" "$Script:LocalSshKeyFile" | |
$Local:Success = $? | |
if (-not ($Local:Success)) { | |
Write-Host "Couldn't copy '$Script:BashOnWindowsKeyFile' to '$Script:LocalSshKeyFile'. Please create this manually and copy your private key to this folder" | |
exit | |
} | |
} | |
$VirtualIP = $null | |
if (-not (Test-Administrator)) { | |
$VirtualIP = Invoke-ElevatedCommand {(Get-VM | ?{$_.ReplicationMode -ne "Replica"} | Select -ExpandProperty NetworkAdapters | Select IPAddresses).IPAddresses[$VmIndex]} | |
} | |
else { | |
$VirtualIP = (Get-VM | ?{$_.ReplicationMode -ne "Replica"} | Select -ExpandProperty NetworkAdapters | Select IPAddresses).IPAddresses[$VmIndex] | |
} | |
if ($VirtualIP -eq $null) { | |
Write-Host "Couldn't detect IP address of virtual host" | |
exit | |
} | |
Write-Host "Virtual Machine detected at IP address $VirtualIP" | |
$Script:OldHomePath = $env:HOME | |
$env:HOME = $env:USERPROFILE | |
. "$Script:Ssh" $UserId@$VirtualIP -i $Script:LocalSshKeyFile | |
$env:HOME = $Script:OldHomePath |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment