Monday, July 09, 2012

Cygwin SSH to manage Windows from Linux

Managing Windows from Linux servers might be tricky but our old friend SSH could help us run remote commands. Here I present a Plain Old Bash Recipe (POB) prepared just for Cygwin to get SSH working. It should be of course idempotent. In addition I am presenting a VBS script to install cygwin from MS command line. It would be great if both could be integrated but at the moment I have no time for more.

Unfortunately fully automation of a cygwin plus OpenSSH installation in Windows is really difficult to achieve. For one we need to run the command line prompt as administrator and that is not available in "unnatended mode". Interaction will be needed. With Virtualization you can build templates and use them at least to avoid normal (not disaster related) installations or re-installations but having idempotent recipes should be the way to go, anyway move on!.

Cygwin uses Windows users and so this procedure assumes you provide a valid local Windows user and password.
  1. Download the cygwin into c:\scripts\setup.exe
  2. Install cygwin from Windows command prompt by running the below script (cscript c:\scripts\cygwin-install.vbs):
    ' c:\scripts\cygwin-install.vbs
    ' @author Nestor Urquiza
    ' @date 20120706
    ' @description: Based on several snippets of code from the web:
    ' Functions 
    'Necessary as cygwin setup aborts when a package is already installed
    On Error Resume Next
    Function wget(URL)
      ' Fetch the file
      Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP")
  "GET", URL, false
      'Wscript.Echo objXMLHTTP.Status
      If objXMLHTTP.Status = 200 Then
        Set objADOStream = CreateObject("ADODB.Stream")
        objADOStream.Type = 1 'adTypeBinary
        objADOStream.Write objXMLHTTP.ResponseBody
        objADOStream.Position = 0    'Set the stream position to the start
        Set objFSO = Createobject("Scripting.FileSystemObject")
        parts = split(URL,"/") 
        saveTo = parts(ubound(parts))
        If objFSO.Fileexists(saveTo) Then objFSO.DeleteFile saveTo
        Set objFSO = Nothing
        objADOStream.SaveToFile saveTo
        Set objADOStream = Nothing
        Err.Raise 8 'Bad response ' objXMLHTTP.Status & ' from ' & URL
      End if
      Set objXMLHTTP = Nothing  
    End Function
    Function installPackage(package)
      Wscript.Echo "-----------Installing " & package
      Set objShell = CreateObject("WScript.Shell") "c:\scripts\setup.exe -n -q -s -P " & package, 0, True
      objShell = Nothing
    End Function 
    'currentPath = CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(".")
    'Wscript.Echo currentPath
    'Download cygwin
    wget ""
    'Install Cygwin if not present and download specific packages
    ' Done
  3. Start cygwin as Administrator. Right click C:\cygwin\Cygwin.bat and select Run as Administrator"
  4. Run the below script from cygwin (/usr/tmp/
    #!/usr/bin/bash -e
    # /usr/tmp/
    # @author Nestor Urquiza
    # @date 20120709
    # @description Set up SSH access for Cygwin
    USAGE="Usage: `basename $0` <ssh user> <ssh password>"
    if [ $# -ne "2" ] 
     echo $USAGE
         exit 1 
    #install a package manager
    wget -O apt-cyg
    chmod +x apt-cyg
    mv apt-cyg /usr/bin/
    #install needed packages via apt-cyg
    #/usr/bin/apt-cyg remove openssh
    /usr/bin/apt-cyg install openssh
    /usr/bin/apt-cyg install tcl
    /usr/bin/apt-cyg install expect
    /usr/bin/apt-cyg install pwgen
    /usr/bin/apt-cyg install vim
    /usr/bin/apt-cyg install screen
    #clean any previous openssh configuration
    net start|grep sshd && net stop sshd
    reg query $reg_sshd_key 2&>1 && reg delete $reg_sshd_key /f
    sc query ssd 2&>1 && sc delete sshd
    ps -ef | grep sshd | awk  '{print $2}' | xargs kill -9
    cygrunsrv --list | grep sshd && cygrunsrv --stop sshd && cygrunsrv --remove sshd
    net user | grep sshd && net user sshd /delete
    net user | grep cyg_server && net user cyg_server /delete
    grep $SSH_USER /etc/passwd || mkpasswd -l -u $SSH_USER >> /etc/passwd
    sed "/sshd.*/d"  /etc/passwd > tmp_passwd &&   mv tmp_passwd  /etc/passwd
    sed "/cyg_server.*/d"  /etc/passwd > tmp_passwd &&   mv tmp_passwd  /etc/passwd
    #configure openssh
    ssh-host-config -y -w `pwgen -y -N 1 10`
    #start ssh
    net start sshd
    /usr/bin/expect -c "
      spawn /usr/bin/passwd $SSH_USER
      expect \"password:\" {
        send \"$SSH_PWD\n\"
        expect \"password:\" {
          send \"$SSH_PWD\n\"
  5. Authorize your public key in the remote windows server. Run the below from the client machine:
    ssh-copy-id -i ~/.ssh/
  6. You should be able to run a remote command in windows from your linux box. For example let us list which version of VBS the windows box is running:
    ssh "/cygdrive/c/Windows/System32/cscript.exe"
This is of course handy for absolutely every automation in Windows Servers. One showcase of it would be backup procedures for MSSQL Server which run in Windows and which you want to trigger from Linux for example.

No comments: