Schlagwort-Archive: Windows

Ranttime #10 – Übertriebene Usability: FreeDownloadManager

Der FreeDownloadManager war immer meine Software der Wahl wenn es darum ging unter Windows größere Mengen an Dateien aus dem Internet zu laden. Mit der neuen Version hat man aber „die Usability verbessert“. Oder anders gesagt: Alle Funktionen entfernt um die Oberfläche Idiotensicher zu machen.

BitNotice #95 – Windows 10 Shenanigans | Edge vs. Firefox | Cortana-Spaß

BitNotice #95 - Windows 10 Shenanigans | Edge vs. Firefox | Cortana-Spaß

(37 MB) 00:34:43

2015-08-21 15:36 🛈

Irgnedwo zwischen BitNotice und Ranttime: Ein Linux-User installiert Windows 10.
16:42 Spaß mit Cortana
27:50 Microsoft Edge vs. Mozilla Firefox

Software als Windows-Service

Programme starten ist toll. Einige müssen aber immer wieder gestartet werden, hierzu nutzt man unter Windows so genannte „Dienste“. Leider sind das unter Windows NT (also auch z.B. Windows 7/8/10, Windows Server 2008/2012) keine einfachen Programme, sondern erfordern spezielle Registrierungen. Leider gent so etwas (soweit mir bekannt) nicht mit Hausmitteln.

Abhilfe schafft ein kleines Tool: winserv verwandelt ein beliebiges Programm in einen passenden Dienst. Hierbei gibt es folgende Modi:

install richtet ein Programm als Dienst ein
configure ändert einen vorhandenen Dienst
uninstall entfernt den Dienst

Zum Anlegen gibt man folgende Parameter:

-displayname Angezeigter Name des Dienstes
-description Beschreibung (das, was in der Diensteverwaltung in der zweiten Spalte steht)
-start Start-Art des Dienstes – „auto“ „demand“ oder „disabled“ (Bedeutung selbstredend, oder?)

Beispiel:

winserv install testdienst -displayname "Test-Dienst" -description "Test 123" -start auto c:\BLA.EXE

Alternativ kann man auch einen Geplanten Task mit dem Trigger „Bei Systemstart“ verwenden, hier muss man jedoch auf die komfortableren Prüf- und Verwaltungsfunktionen des Dienst-Managers verzichten.

Q’n’D Windows-Shutdown-Daemon in PHP

Alles in Deckung, ich mache wieder unschönes Zeugs. Ich hatte ja bereits erklärt wie man über RPC/Samba einen Windows-PC von Linux herunterfahren kann. Leider ist die Installation von Samba aus Embedded-Systemen eine eher ungünstige Sache und ist in meinem Fall wegen Speichermangel nicht drin. Allerdings ist sowohl auf dem Embedded-System als auch dem betroffenen Rechner PHP verfügbar. I aim to misbehave.

Auf dem herunterzufahrenden Windows-Rechner wird per PHP ein TCP-Socket geöffnet. Dieser Code basiert auf einem Beispiel von Michael Kliewe. Um Scriptkiddies nicht direkt Zugang zu geben ist etwas (sehr schlechte) Challenge-Response-Authentifizierung drin – nunja, ist kein kritisches System. Wird der Client bestätigt folgt ein simples Shutdown per exec. Nicht viel, aber schnell Fertig und funktioniert:

<?php
class SocketChatServer {
    private $address = '0.0.0.0';   // 0.0.0.0 means all available interfaces
    private $port = 12345;          // the TCP port that should be used
    private $maxClients = 10;
 
    private $clients;
    private $socket;
    
    private $salt = 'YourSalt';
    private $pass = 'YourSecret';
 
    public function __construct() {
        // Set time limit to indefinite execution
        set_time_limit(0);
        error_reporting(E_ALL ^ E_NOTICE);
    }
 
    public function start() {
        // Create a TCP Stream socket
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        // Bind the socket to an address/port
        socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1);
        socket_bind($this->socket, $this->address, $this->port);
        // Start listening for connections
        socket_listen($this->socket, $this->maxClients);
 
 
        $this->clients = array('0' => array('socket' => $this->socket));
 
        while (true) {
            // Setup clients listen socket for reading
            $read[0] = $this->socket;
            for($i=1; $i<count ($this->clients)+1; ++$i) {
                if($this->clients[$i] != NULL) {
                    $read[$i+1] = $this->clients[$i]['socket'];
                }
            }
 
            // Set up a blocking call to socket_select()
            $ready = socket_select($read, $write = NULL, $except = NULL, $tv_sec = NULL);
 
            /* if a new connection is being made add it to the client array */
            if(in_array($this->socket, $read)) {
                for($i=1; $i < $this->maxClients+1; ++$i) {
                    if(!isset($this->clients[$i])) {
                        $this->clients[$i]['socket'] = socket_accept($this->socket);
                        socket_getpeername($this->clients[$i]['socket'], $ip);
                        $this->clients[$i]['ipaddy'] = $ip;
 
                        socket_write($this->clients[$i]['socket'], 'Welcome to the Shutdown Control System'."\r\n");
                        socket_write($this->clients[$i]['socket'], 'Your personal code is '.md5($this->salt.strftime('%Y-%m-%d').$ip)."\r\n");
 
                        $this->log("New client #$i connected: " . $this->clients[$i]['ipaddy']);
                        break;
                    } elseif($i == $this->maxClients - 1) {
                        $this->log('Too many Clients connected!');
                    }
 
                    if($ready < 1) {
                        continue;
                    }
                }
            }
 
            // If a client is trying to write - handle it now
            for($i=1; $i<$this->maxClients+1; ++$i) {
                if(in_array($this->clients[$i]['socket'], $read)) {
                    $data = @socket_read($this->clients[$i]['socket'], 1024, PHP_NORMAL_READ);
 
                    if($data === FALSE) {
                        unset($this->clients[$i]);
                        $this->log('Client disconnected!');
                        continue;
                    }
 
                    $data = trim($data);
 
                    if(!empty($data)) {
                        switch ($data) {
                            case 'exit':
                            case 'quit':
                                socket_write($this->clients[$i]['socket'], "Disconnecting without any action, Goodbye.\r\n");
                                $this->log("Client #$i is exiting");
                                unset($this->clients[$i]);
                                continue;
                            case 'shutdown-'.md5($this->pass.md5($this->salt.strftime('%Y-%m-%d').$ip)):
                                // first write a message to all connected clients
                                for($j=1; $j < $this->maxClients+1; ++$j) {
                                    if(isset($this->clients[$j]['socket'])) {
                                        if($this->clients[$j]['socket'] != $this->socket) {
                                            socket_write($this->clients[$j]['socket'], "System will be shut down now...\r\n");
                                        }
                                    }
                                }
                                // Close the master sockets, server termination requested
                                exec('shutdown /s /t 15 /c "System wurde per Fernbedienung ausgeschaltet"');
                                $this->log("Terminated server (requested by client #$i)");
                                exit;
                            case 'whoami':
                                // first write a message to all connected clients
                                socket_write($this->clients[$i]['socket'], "You are registred with the source IP ".$this->clients[$i]['ipaddy']." - your Code was ".md5($this->salt.strftime('%Y-%m-%d').$ip)." \r\n");
                                
                                break(2);
                            default:
                                for($j=1; $j < $this->maxClients+1; ++$j) {
                                    if(isset($this->clients[$j]['socket'])) {
                                        if(($this->clients[$j]['socket'] != $this->socket)) {
                                            $this->log($this->clients[$i]['ipaddy'] . ' is sending a message to ' . $this->clients[$j]['ipaddy'] . '!');
                                            socket_write($this->clients[$j]['socket'], '[' . $this->clients[$i]['ipaddy'] . '] says: ' . $data . "\r\n");
                                        }
                                    }
                                }
                                break(2);
                        }
                    }
                }
            }
        } // end while
    }
 
    private function log($msg) {
        // instead of echoing to console we could write this to a database or a textfile
        echo "[".date('Y-m-d H:i:s')."] " . $msg . "\r\n";
    }
}

$srv = new SocketChatServer;
$srv->start();
?>

Der Client bastelt sich eine passende Authentifizierung und spielt Zündknopf:

function pc_shutdown() {                                                                                                                                                                                                              
                $pass = 'YoutSecret';                                                                                                                                                                                                         
                                                                                                                                                                                                                                              
                $fp = fsockopen('pc.name', 12345, $errno, $errstr, 2);                                                                                                                                                                              
                if(!$fp) return false;                                                                                                                                                                                                        
                                                                                                                                                                                                                                              
                $line = fgets($fp); //Greeting                                                                                                                                                                                                
                $line = fgets($fp); //Hash                                                                                                                                                                                                    
                                                                                                                                                                                                                                              
                preg_match('/code is ([\w\d]{32})/', $line, $match);                                                                                                                                                                          
                $seed = $match[1];                                                                                                                                                                                                            
                                                                                                                                                                                                                                              
                $cmd = 'shutdown-'.md5($pass.$seed)."\n";                                                                                                                                                                                     
                                                                                                                                                                                                                                              
                fwrite($fp, $cmd);                                                                                                                                                                                                            
                                                                                                                                                                                                                                              
                var_dump(fgets($fp));                                                                                                                                                                                                         
                                                                                                                                                                                                                                              
                fclose($fp);                                                                                                                                                                                                                  
        }

Hoffen wir, dass es läuft und ich nie wieder drauf schauen muss, denn irgendwo tut sowas selbst mir weh 😉

Windows Shutdown per Linux

Ab und an möchte man entfernte Rechner mal runterfahren. Mit Linux-Zielen ist das per ssh üblicherweise kein Problem, möchte man jedoch von einem Linux-PC den Shutdown-Befehl an einen Windows-Rechner geben muss man schon einmal suchen. Abhilfe schafft wie üblich Samba, welches den „net“-Befehl mitbringt. Ein Shutdown sieht dann wie folgt aus:

net rpc SHUTDOWN -C "Grund für den Shutdown" -f -I 127.0.0.1 -U username%password

Logrotate für Windows-Webserver IIS

Seriously, Microsoft? Der in Windows integrierte Webserver IIS kann problemlos vernünftige Log-Dateien erzeugen und besitzt auch eine Funktion diese bei Erreichen einer Zeitspanne oder eines Größenlimits zu schließen und eine neue beginnen. Was leider fehlt: Alte Dateien löschen. Es kommt was kommen musste: Auf einem Produktivserver durfte ich mehr als 100GB an logtechischen Textkauderwelsch finden. Platte voll.

Zwar kann man hier mit der in NTFS verfügbaren Ordnerkompression gegensteuern, eine Dauerlösung ist das aber sicher nicht. Am Ende habe ich auf Basis eines Powershell-Scriptes von Daniel Schroeder aka deadlydog etwas passendes gebastelt um hier Abhilfe zu schaffen. Regelmäßig über die Aufgabenplanung aufgerufen bleibt so der Ordner auf einem erträglichen Maß.

$limit = 15 #Delete Logs after 15 Days
$path = "C:\inetpub\logs\LogFiles\W3SVC1"

# Function to remove all files in the given Path that have not been modified after the given date.
# original written by deadlydog / Daniel Schroeder, http://blog.danskingdom.com/powershell-functions-to-delete-old-files-and-empty-directories/
# Requires Powershell >=2.0
function Remove-FilesNotModifiedAfterDate([parameter(Mandatory)][ValidateScript({Test-Path $_})][string] $Path, [parameter(Mandatory)][DateTime] $DateTime)
{
    Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Remove-Item
    #Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Format-List BaseName,LastWriteTime
}

Remove-FilesNotModifiedAfterDate -Path "$path" -DateTime ((Get-Date).AddDays(1-$limit))

Zum Ausführen wird mindestens PowerShell 2.0 benötigt. Ältere Betriebssysteme wie z.B. 2008R2 bringen nur PowerShell 1 mit, hier muss manuell über das Windows Management Framework aktualisiert werden.

Powershell über Aufgabenplanung (oder Batch) starten

Bild: https://adlerweb.info/blog/wp-content/uploads/2015/03/logpurgetask-279×300.pngMit der Powershell hat Microsoft zwar keine angenehm zu verwendende, aber immerhin sehr mächtige Konsole geschaffen, welche es ermöglicht eine Vielzahl an Aufgaben unter Windows über Scripte zu steuern. Ein Wichtiger Punkt bei der Automatisierung ist natürlich auch das zeitgesteuerte Ausführen –  im Windows-Jargon „Aufgabenplanung“ bzw. früher „Geplanter Task“. Leider lassen sich Powershell-Scripte nicht direkt als Programm ausführen, daher muss man etwas tricksen: Als Programmname gibt man „C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe“ ein – ja, 1.0 ist korrekt, auch neuere Powershell-Versionen sind in diesem Ordner zu finden. Der Pfad zum eigentlichen Script wird als Argument „-File“ hinterlegt – Anführungszeichen bei Bedarf natürlich nicht vergessen. Schon können Scripte zeitgesteuert – oder durch einen der anderen möglichen Trigger – gestartet werden. Die „üblichen“ Fallstricke der Aufgabenplanung (Berechtigungen, lauf ohne Anmeldung, etc) sind natürlich wie immer zu beachten.

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -File "C:\Program Files (x86)\LogPurge\LogPurge.ps1"

winsxs: Und es geht doch kleiner…

Wer ein neueres Windows nutzt wird ihm sicher schon einmal begegnet sein: C:\Windows\winsxs. Der Spielverderber für alle, welche die Systemplatte gerne etwas schlanker hätten. Seit Windows Vista werden hier bei jeder Systemänderung Kopien der installierten Bibliotheken aufbewahrt. Während man bei älteren Windows-Versionen unter C:\Windows\$NtUninstall* ein ähnliches verhalten sah hat sich mit WinSxs einiges geändert. Zum Ersten: Man darf ihn nicht mehr einfach löschen. Wärend auf älteren Versionen die Dateien ausschließlich zur Deinstallation von Updates dienten werden die älteren Kopien unter Vista und höher auch für Programme und zukünftige Updates herangezogen. Ein Entfernen dieser Dateien kann zu Systemfehlern führen. Hinzu kommt, dass die Ordnergröße trügt: Zwar enthält der Ordner alle gezeigten Dateien, teils sind diese aber auch an anderen Stellen der Partition vorhanen. Dies wird durch die Verwendung von Hard-Links erreicht. Das entfernen der Datei im WinSxs-Ordner würde also nicht nur das System destabilisieren sondern zudem nicht einmal den Platz auf der Festplatte freigeben. Auch sollte man davon absehen den Ordner auf eine andere Festplatte oder Partition zu verschieben – dies würde die Links zerstören und entsprechend ebenfalls dem System schaden.

Auch wenn es nach wie vor einem Kampf gegen Windmühlen gleicht gibt es trotzdem einige Kniffe, mit denen man etwas Platz schaffen kann:

Die Datenträgerbereinigung

Meist müde belächelt kann diese ausnahmsweise Weiterhelfen. Unter anderem finden sich hier ab und an Setupdateien, welche wohl auch in WinSxs deponiert sein können. Auf Servern ist diese im Übrigen nicht verfügbar und müsste ggf. über das Feature „Desktopdarstellung“ nachinstalliert werden. Bei Windows Server 2012 versteckt sich dies unter „User Interface and Infrastructure“.

Wenn noch nicht geschehen benötigt man noch ein Update für Windows 7 oder Windows Server 2008 R2 um dem Tool die Updatebereinigung beizubringen. Mehr gibt es im Technet: Win7, Win2008R2, Win12.

Die Service-Packs

Service-Packs enthalten oft eine vielzahl von Updates, welche bereits in der Vergangenheit separat verteilt wurden. Hat man nicht vor ein Downgrade durchzuführen lassen sich diese fest inst System integrieren. Hierzu öffnet man bei aktuellen Windows-Versionen (>=Windows 7 oder >=Windows Server 2008 R2 Service Pack 1) die Konsole als Administrator und verwendet folgenden Befehl:

DISM.exe /Online /Cleanup-Image /spsuperseded

Der Vorgang kann einige Zeit in anspruch nehmen, auch wenn der Fortschritt mit 100% angegeben wird. Ich konnte den Ordner so immerhin von 20,8 auf 16,1GB verkleinern – eine Ersparnis von über 20%.

Die Backups

Hier kommen wir eher in den ungemütlichen Bereich. Microsoft selbst rät davon ab im Ordner manuell herum zu spielen, aber je nach System hat man meist keine andere Wahl mehr als irgendwo notdürftig Platz zu schaffen. In den meisten Fällen sollte es aber problemlos möglich sein den unterordner „Backup“ zu löschen. Hier werden Bibliotheken hersortiert, welche sonst keine Verwendung finden sollten.

…und nu?

Nach wie vor ist mir der Ordner WinSxs ein Dorn im Auge. Eine Windows-Installation, welche mehr als 40GB frisst macht weder virtualisiert noch physikalisch Spaß. Immerhin kann man mit diesen Tricks etwas Platz schaffen und so den Platztod etwas herauszögern. Ansonsten ist es wie immer eine gute Gelegenheit die Windows-Admins mit einem süffisanten „Mit Linux wär‘ das nich‘ passiert“ zu strafen.

Tipp: Hash Check für Windows

Wenn es darum geht die Integrität einer Datei zu prüfen werden meist Hashwerte verwendet. So lässt sich schnell feststellen, ob ein Download beschädigt oder eine Datei seit der letzten Prüfung manipuliert wurde. Da der Hash aus dem Inhalt berechnet wird ist diese Methode deutlich zuverlässiger als das Prüfen von Metadaten wie z.B. Änderungszeit oder Dateigröße.

Unter Windows ist die bekannteste Software für diesen Zweck HashTab. Es fügt in den Dateieigenschaften einen neuen Reiter hinzu, welcher verschiedenste Hash-Werte zum direkten vergleichen anzeigt. Leider ist die Software nur für private Zwecke kostenlos. Die Business-Version ist mit $10 zwar erschwinglich, aber in vielen Firmen ist die Budgetbeschaffung mit etwas Papierkram verbunden, welche man um „mal schnell“ etwas nachzuschauen gerne umgehen möchte.

Auf meiner Suche bin ich auf HashCheck gestolpert. Diese Software steht unter einer BSD-ähnlichen Lizenz und ist somit auch im komerziellen Umfeld ohne Einschränkungen nutzbar. Zwar bietet HashCheck weniger Features als HashTab, die wichtigen MD5- und SHA-1-Prüfsummen sind jedoch vorhanden womit nahezu all meine Anwendungsbereiche abgedeckt sind. Die obligatorische Spende für gute Projekte kann dann noch dem „mal schnell“ in Ruhe erledigt werden.

Bild: https://adlerweb.info/blog/wp-content/uploads/2015/02/hashcheck.png

 

BitNotice #71 – Partitionen vergößern mit GParted

BitNotice #71 - Partitionen vergößern mit GParted

(5 MB) 00:04:44

2014-11-27 19:44 🛈

Festplatten gegen größere Modelle tauschen oder einer Virtuellen Maschine mehr Platz zuteilen geht meist mit wenigen Handgriffen. Ist dies geschehen muss auch noch die Partition und das Dateisystem vergrößert werden. Leider unterstützt Windows diese Funktion erst in den neuesten Versionen, für ältere kann man – wie hier gezeigt – die Software „GParted“ nutzen.

GParted: http://gparted.org

Vergrößern unter Linux:
Ext2/3/4: resize2fs /dev/mapper/partition
XFS: xfs_growfs /dev/mapper/partition
btrfs: btrfs filesystem resize max /mnt/mountpoint
ZFS: zpool set autoexpand=on POOLNAME && zpool online -e POOLNAME /dev/mapper/partition