diff --git a/README.md b/README.md
index 9fb2d0f3976adcf027a096ff6e851dc25ebacce1..077798cbdf2eaab943cf3292e8491596299bb40d 100644
--- a/README.md
+++ b/README.md
@@ -20,32 +20,12 @@ Install the requirements.
 **Required** minimal packages:
 
 ```
-apt install python3 python3-dev python3-setuptools python3-pip
-```
-
-**Optional** packages (these packages will probably be outdated in debian/ubuntu, and may break scripts):
-
-```
-apt install python3-ldap3 python3-gssapi python3-tabulate
+apt install python3 python3-dev python3-setuptools python3-pip libacl1-dev libkrb5-dev
 ```
 
 ### git / pip
 
-**Required** for modules installation via `pip`:
-
-```
-apt install libkrb5-dev                      # required for `gssapi` module
-```
-
-**Required** modules in local lib directory:
-
-```
-/usr/bin/pip3 install --upgrade pip
-/usr/bin/pip3 install -r requirements-git.txt -t lib/git
-/usr/bin/pip3 install -r requirements-pip.txt -t lib/pip
-```
-
-**Alternative** install from a clean venv (may be needed if you have any conflicting outdated modules installed as packages):
+**Recommended** install from a clean venv (may be needed if you have any conflicting outdated modules installed as packages):
 
 ```
 python3 -m venv venv
@@ -57,6 +37,14 @@ deactivate
 rm -r venv
 ```
 
+**Alternative** modules in local lib directory (this will probably not work):
+
+```
+/usr/bin/pip3 install -r requirements-git.txt -t lib/git
+/usr/bin/pip3 install -r requirements-pip.txt -t lib/pip
+```
+
+
 ## modules
 
 Store or load modules in these directories:
diff --git a/bin/slaptail.py b/bin/slaptail.py
new file mode 100755
index 0000000000000000000000000000000000000000..75d3c2aa52204f9c9f088957b92e52d5fa029c59
--- /dev/null
+++ b/bin/slaptail.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+
+import sys
+import time
+import subprocess
+import select
+import re
+import argparse
+
+update_every = 0.001
+log_path = '/var/log/'
+log_file = 'slapd'
+log_file_path = log_path + log_file
+rgx = dict()
+connections = dict()
+rgx['conn'] = re.compile(r'conn=(?P<conn>[0-9]+)(?P<closed> .*?=.*? closed)?')
+
+
+def sleep(start_time):
+    """After hard work, take a nap"""
+    current_time = time.perf_counter()
+    elapsed_time = current_time - start_time
+    sleep_time = update_every - elapsed_time
+
+    if sleep_time > 0:
+        time.sleep(sleep_time)
+
+
+def parse(line):
+    """Parse line and print"""
+    connect = rgx['connect'].search(line)
+
+    if(connect):
+        ip = connect.group('ip')
+        port = connect.group('port')
+        connection_id = connect.group('conn')
+
+        if connection_id not in connections:
+            connections[connection_id] = ip, port
+
+        print(len(connections), ip, port, line, end='')
+
+    else:
+        conn = rgx['conn'].search(line)
+
+        if(conn):
+            connection_id = conn.group('conn')
+
+            if connection_id in connections:
+                ip, port = connections[connection_id]
+
+                print(len(connections), ip, port, line, end='')
+
+                if conn.group('closed'):
+                    del connections[connection_id]
+
+
+def tail_input(fin):
+    """Open input file in tail mode"""
+    poll = select.poll()
+    poll.register(fin.stdout)
+
+    try:
+        while True:
+            start_time = time.perf_counter()
+
+            if poll.poll(1):
+                line = fin.stdout.readline().decode('utf-8')
+
+                parse(line)
+
+            sleep(start_time)
+
+    except KeyboardInterrupt:
+        sys.stdout.flush()
+        pass
+
+
+def read_input(fin):
+    """Read from input file"""
+    try:
+        for line in fin:
+            parse(line)
+    except KeyboardInterrupt:
+        sys.stdout.flush()
+        pass
+
+
+def main():
+    """Open file in non blocking mode and parse it"""
+    parser = argparse.ArgumentParser(
+        add_help=False,
+        description='Parse from file or stdin'
+    )
+    parser.add_argument(
+        '-f', '--follow',
+        dest='follow', action='store_const', const=True,
+        help='Output appended data as the file grows'
+    )
+    parser.add_argument(
+        'pattern',
+        type=str,
+        help='Regex pattern'
+    )
+    parser.add_argument(
+        'file',
+        nargs='?', type=str,
+        help='File to open'
+    )
+    parser.add_argument(
+        '-h', '--help',
+        action='help',
+        help='Show this help message and exit'
+    )
+    arg = vars(parser.parse_args())
+
+    rgx['connect'] = re.compile(''.join([r'conn=(?P<conn>[0-9]+).+?ACCEPT from IP=(?P<ip>',
+                                arg['pattern'], r'):[0-9]+ \(IP=0\.0\.0\.0:(?P<port>[0-9]+)\)']))
+
+    if arg['follow']:
+        if arg['file']:
+            path = arg['file']
+        else:
+            path = log_file_path
+
+        fin = subprocess.Popen(['tail', '-F', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        tail_input(fin)
+
+    else:
+        if arg['file']:
+            with open(arg['file'], 'r') as fin:
+                read_input(fin)
+        else:
+            fin = sys.stdin
+            read_input(fin)
+
+    sys.exit(0)
+
+
+if __name__ == '__main__':
+    main()
+    sys.exit(0)
diff --git a/bin/sync-winhosts.py b/bin/sync-winhosts.py
new file mode 100755
index 0000000000000000000000000000000000000000..3eae7e3717f6654d80db90f5f42ad6b771864900
--- /dev/null
+++ b/bin/sync-winhosts.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python3
+
+import lib_path
+import lib
+#import dphysldap
+import ssl
+import os
+
+from datetime import datetime
+from itertools import count, filterfalse
+from ldap3 import Server, Connection, ALL, Tls, SASL, GSSAPI, ServerPool, RANDOM
+
+# ldap                  = dphysldap.Ldap(ca_certs_file=".\\ca-certificates.crt")
+main_windows_netgroup = "windows"
+windows_log_path      = "c:\\scratch\\"
+unix_log_path         = "/var/log/usradm/"
+log_file              = "sync-winhosts.log"
+ca_certs_file         = "/etc/ssl/certs/ca-certificates.crt"
+
+def connect_ldap(server_names, base):
+    """Connet to the ldap server"""
+    server_names = server_names
+    base = base
+    tls = Tls(
+        validate=ssl.CERT_REQUIRED,
+        version=ssl.PROTOCOL_TLSv1_2,
+        ca_certs_file=ca_certs_file)
+    servers = [Server(s, tls=tls, get_info=ALL) for s in server_names]
+    server_pool = ServerPool(
+        servers,
+        pool_strategy=RANDOM,
+        active=True,
+        exhaust=False)
+    connection = Connection(
+        server_pool,
+        user='ldapadmin/phd-systemxen.ethz.ch',
+        authentication=SASL,
+        sasl_mechanism=GSSAPI,
+        auto_bind='NONE',
+        version=3,
+        client_strategy='SYNC')
+    connection.open()
+    connection.start_tls()
+    connection.bind()
+    user_classes = ['posixAccount', 'dphysUser', 'inetOrgPerson', 'shadowAccount']
+    group_classes = ['posixGroup', 'dphysGroup']
+    obj_user = None
+    obj_group = None
+
+    return connection
+
+def get_netgroups(cn_name):
+    """Get the nisnetgroups"""
+    windows_netgroups = []
+
+    search_filter = "(&(objectClass=nisNetgroup)(cn="+ cn_name +"))"
+    ldap.search(search_base="ou=netgroup,dc=phys,dc=ethz,dc=ch", search_filter=search_filter, attributes=['memberNisNetgroup'])
+    found_groups = ldap.entries
+
+    for found_group in found_groups:
+        windows_netgroups += found_group['memberNisNetgroup']
+
+    return windows_netgroups
+
+def get_netgroup_members(group_name):
+    """Get windows clients of specific nisnetgroup"""
+    windows_clients = []
+
+    search_filter = "(&(objectClass=nisNetgroup)(cn="+ group_name +"))"
+    ldap.search(search_base="ou=netgroup,dc=phys,dc=ethz,dc=ch", search_filter=search_filter, attributes=['nisNetgroupTriple'])
+    found_groups = ldap.entries
+
+    for found_group in found_groups:
+        for client_fqdn in found_group['nisNetgroupTriple']:
+            client_temp = client_fqdn.replace('(','')
+            client_ldap = client_temp.replace('.ethz.ch,-,-)','') + '$'
+            windows_clients.append(client_ldap)
+
+    return windows_clients
+
+def get_netgroup_clients(main_windows_netgroup):
+    """Get all windows clients from nisnetgroup"""
+    clients_netgroup = []
+
+    windows_netgroups = get_netgroups(main_windows_netgroup)
+
+    for windows_netgroup in windows_netgroups:
+        clients_netgroup += get_netgroup_members(windows_netgroup)
+
+    return clients_netgroup
+
+
+def get_ldap_clients():
+    """Get Windows clients in LDAP"""
+    windows_clients = []
+
+    search_filter = "(objectClass=device)"
+    ldap.search(search_base="ou=ad,dc=phys,dc=ethz,dc=ch", search_filter=search_filter, attributes=['cn'])
+    found_clients = ldap.entries
+
+    for client in found_clients:
+        windows_clients.append(str(client['cn']))
+
+    return windows_clients
+
+def sync_clients(clients_netgroup, clients_ldap):
+    """Synchronisation der windows clients im ldap zur master db nisnetgroup"""
+    remove_clients_from_ldap(list(set(clients_ldap) - set(clients_netgroup)))
+    add_clients_to_ldap(list(set(clients_netgroup) - set(clients_ldap)))
+
+def remove_clients_from_ldap(clients):
+    """Remove old obsolet Computers"""
+    write_log("Remove " + str(len(clients)) + " clients from ldap.", True)
+    for client in clients:
+        write_output("remove client "+ client +" from ldap.....", False)
+        delete_windows_host(client)
+
+def add_clients_to_ldap(clients):
+    """Add new Windows Computers to Ldap"""
+    write_log("Add " + str(len(clients)) + " clients to ldap.", True)
+    for client in clients:
+        write_output("add client "+ client + " to ldap.....", False)
+        create_windows_host(client)
+
+def create_windows_host(computername):
+    """create windows host in ldap"""
+    hostname         = computername
+    host_dn          = "uid="+ hostname +",ou=ad,dc=phys,dc=ethz,dc=ch"
+    host_objectClass = ["device","posixAccount"]
+    host_gidNumber   = "60000"
+    host_home        = "/home/" + hostname
+    host_cn          = hostname
+    host_uidNumber   = new_uidNumber()
+    host_attrib      = {'gidNumber':host_gidNumber,'homeDirectory':host_home, 'cn':host_cn, 'uidNumber':host_uidNumber}
+
+    ldap.add(host_dn, host_objectClass, host_attrib)
+    write_output(str(ldap.result['description']), True, False)
+
+def new_uidNumber():
+    """check next free uidNumber and return it"""
+    used_nr = []
+
+    ldap.search("ou=ad,dc=phys,dc=ethz,dc=ch", search_filter="(objectClass=device)", attributes=['uid' ,'uidNumber'])
+    entries = ldap.entries
+
+    for entrie in entries:
+        nr = str(entrie['uidNumber'])
+        used_nr.append(int(nr))
+
+    free_nr = next(filterfalse(set(used_nr).__contains__, count(60001)))
+
+    return str(free_nr)
+
+def delete_windows_host(computername):
+    """remove windows host in ldap"""
+    hostname = computername
+    host_dn  = "uid="+ hostname +",ou=ad,dc=phys,dc=ethz,dc=ch"
+
+    ldap.delete(host_dn)
+    write_output(str(ldap.result['description']), True, False)
+
+def write_log(message,new_line,with_timestamp=True):
+    """write output to logfile"""
+    if os.name == "nt":
+        logfile_path = windows_log_path + log_file
+    else:
+        logfile_path = unix_log_path + log_file
+
+    if with_timestamp:
+        log_message = datetime.now().strftime('%d-%m-%Y %H:%M:%S') + ": " + message
+    else:
+        log_message = message
+
+    if new_line:
+        log_message += "\n"
+
+    f = open(logfile_path, "a+")
+    f.write(log_message)
+
+def write_output(message, new_line,with_timestamp=True):
+    """wirte output to standardout and logfile"""
+    write_log(message, new_line, with_timestamp)
+    if new_line:
+        message += "\n"
+    print(message, end='')
+
+###############
+#
+# Start Script
+#
+###############
+write_log("", True)
+write_log("Start Sync-Windowshost",True)
+write_log("",True)
+
+# LDAP Connection
+write_log("Start connection to LDAP",True)
+ldap = connect_ldap(["phd-aa1.ethz.ch","phd-aa2.ethz.ch","phd-aa3.ethz.ch"],'ou=ldap,dc=phys,dc=ethz,dc=ch')
+
+# Get all Clients from nis Netgroup
+write_log("Get from Netgroup all clients",True)
+clients_netgroup = get_netgroup_clients(main_windows_netgroup)
+#clients_netgroup = ['peter$', 'heidi$', 'geisse$']
+write_log("found "+ str(len(clients_netgroup))+ " clients in netgroup",True)
+
+# Get all Clients for LDAP
+write_log ("Get from LDAP all clients",True)
+clients_ldap = get_ldap_clients()
+write_log("found "+ str(len(clients_ldap))+ " clients in ldap",True)
+
+# Synchrnisation von netgroup auf ldap
+write_log("Start Sync",True)
+sync_clients(clients_netgroup, clients_ldap)
+
+write_log("",True)
+write_log("End Sync-Windowshost",True)
+write_log("",True)