WPKG with winexe

You can use Samba's preexec directive to launch a script when a PC connects to Samba. To launch WPKG on a Windows machine which connects to Samba, we will use the below script and winexe.

Features

  • Will run software installation on Windows PCs (except XP Home, which does not support remote administration) without any additional client-side configuration - note the following requirements:
    • Workstation and Server services must be enabled
    • File and Printer Sharing must be enabled
    • Remote IPC and Remote Admin shares must be enabled (i.e. "Use simple file sharing" must be disabled - this is found in: Control Panel\Folder Options\View\Use simple file sharing). To check that these shares are available, execute the "net share" command in a command window. "ADMIN$" and "IPC$" should then be displayed in the results.
    • A local Windows user account with both administrative privileges and a non-empty password

Installation

  • Copy/paste/save the below script on your Samba server. Note: the script should have UNIX end-of-line characters. If you use Windows, make sure your editor saves the script with UNIX end-of-line characters; if it's saved with Windows end-of-line characters, it will not work.
  • Edit these variables:
    • WINUSER, PASSWORD - user which will start software installation (must have admin privileges),
    • LOGPATH - where to store our logs,
    • WINEXE - winexe binary,
    • TIMEOUT - winexe 0.90 has some bug which prevents it from exiting in some circumstances. Makes sure it's killed if it ever happens for you.
    • IGNOREIPS - don't try to start software installation on these IP addresses
  • down in the script, correct \\\\branchdc\\unattended paths to point to your server and software/wpkg share
  • Create a LOGPATH directory (default: /var/log/wpkg)
  • to smb.conf, add this to the [global] section:
root preexec = /root/scripts/wpkg-preexec.sh %I %m %S &
  • That's it!

Testing

In your server terminal/shell, start:

/root/scripts/wpkg-preexec.sh 192.168.145.150 pc-name-test netlogon

Meaning of command line arguments:

  • "192.168.145.150" - start software deployment on 192.168.145.150
  • "pc-name-test.log" - everything will be logged to /var/log/pc-name-test.log
  • "netlogon" - when a PC connects to this share, we deploy software on this PC


In a different terminal on that server, cd to /var/log/wpkg and see the logfiles (pc-name-test.log and wpkg.log).


Some more info

  • prevents from starting multiple WPKG instances on a single Windows PC
  • new software deployment is started by Samba in two cases:
    • PC connects to [netlogon] share (happens automatically for domain PCs which are turned on; nobody has to log in)
    • if /var/log/wpkg/<workstation>.log is not present, or is older than 24 hours
  • security: the script has admin username/password, so make sure to keep it in a directory which is accessible by root only
  • security: winexe will present username/password in ps output. If it's a concern for you (i.e. unprivileged users can view process list on that server), you have to modify the script to use --authentication-file with winexe
  • if you have WPKG Client running, but would rather disable it from this script, you can add these lines just before "net use \\\\branchdc\..." in the script:
taskkill /F /IM wpkgsrv.exe
sc config wpkgservice start= disabled

Script source

#!/bin/bash

# Launches wpkg.js on a remote Windows machine
# Author: Tomasz Chmielewski (tch .at. wpkg .dot. org)

HOST_IP=$1
HOST_NAME=$2
SHARE=$3

WINUSER='DOMAIN\Administrator'
PASSWORD='secretpass'
LOGPATH=/var/log/wpkg
WINEXE=/opt/winexe

TIMEOUT=3600	# winexe seem to hang sometimes - kill it after 1 hour if it's still there

IGNOREIPS="192.168.111. 127.0.0.1 192.168.128.10"


# No need to change anything below
if [ "x$HOST_IP" == "x" -o "x$HOST_NAME" == "x" ] ; then
cat <<EOF
This script launches WPKG on a specified machine.

Usage:

    $0 <host_ip> <host_name>

EOF
exit 0
fi

# We don't want to execute winexe on nagios, PDC etc.
IGNORE=0
for IGNOREIP in $IGNOREIPS; do
    echo $HOST_IP | grep -q $IGNOREIP
    if [ $? -eq 0 ] ; then
	IGNORE=1
    fi
done

if [ $IGNORE -eq 1 ] ; then
    exit 0
fi


# The main "launch wpkg" function
launch_wpkg()
{
$WINEXE --debug-stderr --system -U "$WINUSER%$PASSWORD" //$HOST_IP \
cmd.exe <<EOF &>"$LOGPATH/$HOST_NAME.log"
net use \\\\branchdc\\unattended /user:$WINUSER $PASSWORD
cscript \\\\branchdc\\unattended\\packages\\wpkg\\wpkg.js /synchronize /nonotify /debug
net use /delete \\\\branchdc\\unattended
echo wpkg_run_is_done
exit 0
EOF
if [ $? -eq 0 ] ; then
    echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) WPKG execution finished" >>$LOGPATH/wpkg.log
elif [ $? -eq 1 ] ; then
    echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) cscript was already running" >>$LOGPATH/wpkg.log
else
    echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) unspecified error code" >>$LOGPATH/wpkg.log
fi
echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) processing done" >>$LOGPATH/wpkg.log
}

echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) starting processing (share hit: $SHARE)" >>$LOGPATH/wpkg.log

UPDATE=0
if [ "$SHARE" == "netlogon" ] ; then
    UPDATE=1
else
    grep -q "wpkg_run_is_done" $LOGPATH/$HOST_NAME.log
    if [ $? -ne 0 ] ; then
	UPDATE=1
    else
	STAMP=$(find $LOGPATH -mtime +0 -name $HOST_NAME.log)
	if [ "x$STAMP" != x ] ; then
	    UPDATE=1
	fi
    fi
fi

# Check if the host was updated in the past 24 hours
if [ $UPDATE -eq 1 ] ; then
    ps aux | grep winexe | grep -q $HOST_IP
    if [ $? -ne 0 ] ; then
	if [ "$SHARE" == "netlogon" ] ; then
            echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) netlogon share hit - starting WPKG" >>$LOGPATH/wpkg.log
	else
            echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) not updated during the last 24 h - starting WPKG" >>$LOGPATH/wpkg.log
	fi
        launch_wpkg &
	WINEXEPID=$!
	while [ $TIMEOUT -gt 0 ] ; do
	    sleep 10
	    ps -C winexe | grep -q $WINEXEPID
	    if [ $? -gt 0 ] ; then
		echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) process finished - winexe ended" >>$LOGPATH/wpkg.log
		exit
	    else
		TIMEOUT=$((TIMEOUT-10))
	    fi
	    if [ $TIMEOUT -le 0 ] ; then
		kill $WINEXEPID
		echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) killed winexe after inactivity timeout" >>$LOGPATH/wpkg.log
	    fi
	done
    else
        echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) winexe already running" >>$LOGPATH/wpkg.log
        echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) processing done" >>$LOGPATH/wpkg.log
    fi
else
    echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) updated during the past 24 hours - skipping an update" >>$LOGPATH/wpkg.log
    echo "$(date) $HOST_NAME (IP: $HOST_IP, PID: $$) processing done" >>$LOGPATH/wpkg.log
fi

Alternative solution for the winexe hang problem

If the script stated by winexe exits ASAP, than it seems to solve the problem (at least it solved for me). You must make two script.

wpkg-runner.cmd

@echo off
start /b \\server\path\to\wpkg.cmd %1
exit

wpkg.cmd

@echo off
cscript \\server\path\to\wpkg.js /synchronize /debug /nonotify > \\server\path\to\logs\%1.txt
exit

In your shell script start wpkg-runner.cmd like this:

winexe ... "cmd /c start \\\\install\\wpkg\\wpkg-runner.cmd $REMOTE_ADDR"