As part of a writing a decommission server PowerShell script at work, I had a requirement for a quick and easy SSH function to connect to our NetBackup server at work and remove the server from the backup system (Symantec if you’re reading this, please can we have a PowerShell module? *wishful thinking*…). Not quite needing the entire functionality provided by this module (based on the SSH.NET Library), I came across a function on PS Fab. One fantastic thing about this function is that supports the automatic acceptance of an SSH key when you connect to a host for the first time.
I made a few changes to the code, amended comments that referenced plist rather than plink and put it into a more standard function form with examples (that you might be able to add to an existing library). This is the result:
Function Invoke-SSH
{
<#
.SYNOPSIS
Uses Plink.exe to SSH to a host and execute a list of commands.
.DESCRIPTION
Uses Plink.exe to SSH to a host and execute a list of commands.
.PARAMETER hostname
The host you wish to connect to.
.PARAMETER username
Username to connect with.
.PARAMETER password
Password for the specified user account.
.PARAMETER commandArray
A single, or list of commands stored in an array object.
.PARAMETER plinkAndPath
The location of the plink.exe including the executable (e.g. F:\tools\plink.exe)
.PARAMETER connectOnceToAcceptHostKey
If set to true, it will accept the remote host key (use when connecting for the first time)
.EXAMPLE
Invoke-SSH -username root -hostname centos-server -password Abzy4321! -plinkAndPath "F:\tools\plink.exe" -commandArray $commands -connectOnceToAcceptHostKey $true
.EXAMPLE
Invoke-SSH -username root -hostname centos-server -password Abzy4321! -plinkAndPath "F:\tools\plink.exe" -commandArray ifconfig -connectOnceToAcceptHostKey $true
.NOTES
Author: Robin Malik
Source: Modified from: http://www.zerrouki.com/invoke-ssh/
#>
Param(
[Parameter(Mandatory=$true,HelpMessage="Enter a host to connect to.")]
[string]
$hostname,
[Parameter(Mandatory=$true,HelpMessage="Enter a username.")]
[string]
$username,
[Parameter(Mandatory=$true,HelpMessage="Enter the password.")]
[string]
$password,
[Parameter(Mandatory=$true,HelpMessage="Provide a command or comma separated list of commands")]
[array]
$commandArray,
[Parameter(Mandatory=$true,HelpMessage="Path to plink (e.g. F:\tools\plink.exe).")]
[string]
$plinkAndPath,
[Parameter(HelpMessage="Accept host key if connecting for the first time (the default is `$false)")]
[string]
$connectOnceToAcceptHostKey = $false
)
$target = $username + '@' + $hostname
$plinkoptions = "-ssh $target -pw $password"
# On first connect to a host, plink will prompt you to accept the remote host key.
# This section will login and accept the host key then logout:
if($ConnectOnceToAcceptHostKey)
{
$plinkCommand = [string]::Format('echo y | & "{0}" {1} exit', $plinkAndPath, $plinkoptions )
$msg = Invoke-Expression $plinkCommand
}
# Build the SSH Command by looping through the passed value(s). Append exit in order to logout:
$commandArray += "exit"
$commandArray | % { $remoteCommand += [string]::Format('{0}; ', $_) }
# Format the command to pass to plink:
$plinkCommand = [string]::Format('& "{0}" {1} "{2}"', $plinkAndPath, $plinkoptions , $remoteCommand)
# Execute the command and display the output:
$msg = Invoke-Expression $plinkCommand
Write-Output $msg
}
Copy and paste this function into a PowerShell window, and then test it with the below code (changing where appropriate of course):
$plinkAndPath = "F:\tools\plink\plink.exe" $username = "root" $password = "Adk3453#5341!" $hostname = "centos-server" # Commands to execute: $Commands = @() $Commands += "ifconfig" $Commands += "ls" Invoke-SSH -username $username -hostname $hostname -password $password -plinkAndPath $plinkAndPath -commandArray $Commands -connectOnceToAcceptHostKey $true
Though the Sporting-Futures website has improved greatly over the past few years I still had a bit of trouble finding the start list. Here is it (a link that is present on the actual entry form page but nowhere else):
https://secure.onreg.com/onreg2/startlist/index.php?id=1566
Good luck everyone :)
As part of our VM-template, template-VM conversion process at work (which I’ve automated via a webpage as discussed in my previous post “Executing Powershell using PHP and IIS“), I had to find a way to handle the VM question “This VM has questions that must be answered before the operation can continue” when attempting to power the VM on via Start-VM.
I found that handling the question was not possible using a simple try/catch block (the explanation can be found in this excellent post by Clint Bergman). I was however able to catch it using the following block:
try
{
try
{
Start-VM -VM $serverName -ErrorAction Stop -ErrorVariable custErr
}
catch [System.Management.Automation.ActionPreferenceStopException]
{
throw $_.Exception
}
}
catch [VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.VMBlockedByQuestionException]
{
Write-Output "Power on operation triggered a VMBlockedByQuestionException. Answering question with `"I moved it`". <br />"
Get-VMQuestion -VM $serverName | Set-VMQuestion –Option "I moved it" -Confirm:$false
}
It may seem like a lot of work to convert between a VM and template (and vice versa) but in our environment there are a couple of critical steps to the conversation process that must be followed to ensure deploys from these templates don’t break. As there are users outside of the team who update various templates I wanted to provide an easy way for everyone to ensure consistency when doing this, and the best way to do this is of course, automation :)







