Categories
IIS Scripts Server Windows

IIS SMTP – Zustellung von “Badmails” erneut versuchen (Script)

Bekommt der IIS SMTP-Dienst seine Mails nicht los, verschiebt er sie in den sogenannten “Badmail”-Ordner und unternimmt keine Zustellversuche mehr.

Damit eine erneute Zustellung versucht wird, müssen folgende Schritte erledigt werden:

  1. Stoppen des SMTP-Dienstes
  2. Aufrufen des “Badmail”-Ordners
  3. Löschen der *.bdr- und *.bdp-Dateien
  4. Entfernen der .BAD-Dateiendung von den übrigen Dateien
  5. Verschieben der Dateien in den “Pickup”-Ordner
  6. Starten des SMTP-Dienstes

Man kann es allerdings auch mit einem PowerShell-Script erledigen. Möglicherweise muss man den Pfad von $mailRootFolder noch anpassen:

$mailRootFolder = "C:\inetpub\mailroot"

Stop-Service "SMTPSVC"

$badMails = Get-ChildItem -Path "$($mailRootFolder)/Badmail"

foreach ($badMail in $badMails) {
	if ($badMail.Name.ToLower().EndsWith(".bdr") -or $badMail.Name.ToLower().EndsWith(".bdp")){
		Remove-Item -Path $badMail.FullName -Confirm:$false
	}
	else {
		Move-Item -Path $badMail.FullName -Destination "$($mailRootFolder)/Pickup"
		Rename-Item -Path "$($mailRootFolder)/Pickup/$($badMail.Name)" -NewName $badMail.Name.Split('.')[0]
	}
}

Start-Service "SMTPSVC"
Categories
Scripts Windows Zabbix

Zabbix Template mit Userparameter (PS-Script) bauen

Generelle Ansprüche an das Template

  • PowerShell-Script erfasst auf Host-Seite die nötigen Daten
  • Ansteuerung über Zabbix-Server mit Parametern (also kein Zabbix Trapper)
  • Verwendung aktueller Best-Practices – sprich am Besten ein “Raw Item” aus dessen Inhalt die anderen Items berechnet werden, um den Datentransfer und die Kommunikation zw. Host und Zabbix-Server so klein wie nur irgendwie möglich zu halten.

Unser Szenario

Im konkreten Beispiel wird ein Script den Inhalt eines Ordners überwachen und uns alarmieren, wenn Inhalte im Ordner älter sind, als eine definierte Zeitspanne. Zusätzlich sollen gewisse Dateien innerhalb des Ordners ignoriert werden.

Schlussfolgerungen

Pfad, Zeitspanne und zu ignorierende Dateien werden als Macros ins Template übernommen und können somit auf Hostebene angepasst werden. Diese Macros werden dann in einem einzigen Item an den Host übergeben, der auf seiner Seite ein Script ausführt und die ganzen benötigten Informationen “raw” zurückgibt. Wir erstellen dann weitere “berechnete Items”, die den Inhalt des “Raw Items” auswerten und damit arbeiten.

Schritt 1: Das Script

Im Installationsverzeichnis von Zabbix (bei uns C:\ZABBIX) legen wir einen Ordner “userparameter” an. Hier wird das Script “Get-OldFilesInFolder.ps1” angelegt:

param(
[string]$sPath = "",
[string]$sFoldersToIgnore = "")

[bool]$bIgnoreSth = $false;

if ($sFoldersToIgnore.Length -gt 0){
    [String[]]$saFoldersToIgnore = $sFoldersToIgnore.Split(",");

    foreach ($sFolder in $saFoldersToIgnore){
        $sFolder = $sFolder.Trim();
    }
    $bIgnoreSth = $true;
}

[int]$iMaxAge = 0
[string]$sOldestFileName = "n/a";

$oaSubFiles = Get-ChildItem -Path $sPath

foreach ($oFile in $oaSubFiles){

    if ($saFoldersToIgnore -match $oFile.Name){
        # Do nothing
    } else {
        
        [TimeSpan]$tsAge = New-TimeSpan -Start $oFile.CreationTime -End (Get-Date)

        if ($tsAge.TotalMinutes -gt $iMaxAge){

            $iMaxAge = $tsAge.TotalMinutes;
            $sOldestFileName = $oFile.FullName.Replace("\", "\\");
        }
    }
}

Write-Host "{""MaxAge"":""$($iMaxAge)"",""FileName"":""$($sOldestFileName)""}";

Entscheidend ist hier unsere letzte Zeile. Wir geben ein (zugegebenermaßen recht einfaches) Json-Objekt zurück. Unser “Raw Item” wird somit nachher mit Json befüllt sein – der wohl sinnvollsten Möglichkeit in Zabbix mit multiplen Daten zu arbeiten.

Der zweite wichtige Punkt ist ganz oben im Script. Im “param()”-Block geben wir die Argumente an, die wir auf dem Zabbix-Host später übergeben müssen.

Schritt 2: Anpassung der zabbix_agentd.conf

Die wichtigste Zeile, die wir hinzufügen müssen, ist folgende:

UserParameter=foldermonitoring.getstatus[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\ZABBIX\userparameter\Get-OldFilesInFolder.ps1" "$1" "$2"
  • Mit [*] geben wir an, dass das Item Parameter unterstützt.
  • Mit dem grün geschriebenen geben wir den Pfad zum Script an
  • Und die gelben Elemente sind die übergebenen Parameter, die auf keinen Fall weniger sein sollten, wie wir beim Item nachher übergeben.

Die zweite Zeile die angepasst werden muss, ist leider folgende:

UnsafeUserParameters=1

Da wir hier später einen Ordnerpfad übergeben, muss diese Option angepasst werden, da sonst die “Backslashes” nicht akzeptiert werden.

Schritt 3: Erstellung des Templates

Um mit der etwas eigenwilligen Benennung von Templates seitens Zabbix compliant zu sein, habe ich das Template “Template Module Windows folder content by Zabbix agent” genannt und in die Gruppe “Templates/Modules” abgelegt. Mehr gehe ich auf das Design des Templates aber gar nicht ein – viel wichtiger sind andere Dinge:

Macros:

Hier erstellen wir nun die drei besagten Macros:

MacroInhaltBeschreibung
{$FOLDERMONITORING.IGNORE}Example,TemplateComma-separated list of ignored Files/Folders
{$FOLDERMONITORING.PATH}C:\TEMPPath to folder getting monitored
{$FOLDERMONITORING.THRESHOLD}30Threshold in seconds

Ist denke ich recht verständlich. Durch die einheitliche Benennung werden Sie später beim Host leichter zu finden sein.

Das Zabbix Raw Item

Nun kommen wir zur Erstellung des “Raw Items” und somit zum Script-Trigger:

  • Name: Whatever floats your Boat
  • Type: Zabbix agent
  • Key: foldermonitoring.getstatus[“{$FOLDERMONITORING.PATH}”,”{$FOLDERMONITORING.IGNORE}”]
    Hier referenzieren wir die Macros. Auch andere Parameter können aber selbstverständlich angegeben werden.
  • Type of information: Text
  • Update interval: 1m (Zabbix Template Guideline)
  • History: 7d (Zabbix Template Guideline)
  • Applications: Zabbix raw items (Zabbix Template Guideline)
  • Description: Hier kann man beschreiben, was Hostseitig in der Config angepasst werden muss, damit das Item funktioniert
  • Enabled: klar.

Damit ist das “Raw Item” schon fertig. Sollten Sie das Template nun an einen Host anbinden, auf dem das Script liegt und die Config entsprechend angepasst wurde, sollten Sie unter “Latest Data” bereits Ihr Json-Objekt sehen.

Die berechneten Items (Dependent item)

Hier werden nun zwei Items erstellt – Bietet sich bei diesem Json-Objekt an:

Dependent Item #1 (Numeric)
  • Name: Whatever floats your boat
  • Type: Dependent item
  • Key: foldermonitoring.age
  • Master item: Auswahl des Raw-Items
  • Type of information: Numeric (unsigned)
  • Units: s (spezielle Unit für Zeitspannen)
  • History: 7d (Zabbix Template Guideline)
  • Trends: Do not keep trends
  • Show value: As is
  • Applications: File monitoring
  • Description: ¯\_(ツ)_/¯
  • Enabled: ja.

Das war jedoch noch nicht alles, wir wechseln stattdessen auf den “Preprocessing”-Reiter, um dem Raw-Item auch den richtigen Wert zu entziehen:

  1. Add -> JSONPath -> $[“MaxAge”]
    Das ist die Json-Property, wie wir Sie im Script erstellten.
  2. Add -> Custom multiplier -> 60
    Hierdurch machen wir aus den Minuten Sekunden.
Dependent ITEM #2 (Text only)
  • Name: Whatever floats your boat
  • Type: Dependent item
  • Key: foldermonitoring.name
  • Master item: Auswahl des Raw-Items
  • Type of information: Text
  • History: 7d (Zabbix Template Guideline)
  • Applications: File monitoring
  • Description: ¯\_(ツ)_/¯
  • Enabled: ja.

Auch hier dann wieder auf den “Preprocessing”-Reiter wechseln und folgendes konfigurieren:

  1. Add -> JSONPath -> $[“FileName”]
    Das ist die Json-Property, wie wir Sie im Script erstellten.

Schritt 4: Funktion prüfen

Falls nicht schon nach Erstellung des “Raw Items” passiert, können Sie nun das Script auf einem Host ablegen, die Config des Agents entsprechend anpassen und in Zabbix dem Host das Template zuordnen. Wenig später (falls die Default-Werte eingehalten wurden, eine Minute später) sollten dann die Werte abgerufen werden und unter “Latest Data” einsehbar sein. Die Macros müssen natürlich angepasst werden.

Schritt 5: Trigger erstellen

Nun können wir wieder auf das Template wechseln, um noch einen Trigger zu erstellen. Schließlich wollen wir ja melden, falls eine Datei tatsächlich älter ist als der im Macro hinterlegte Wert.

Auch hier werden wir wieder Best Practices anwenden – Somit kommen keine {ITEM.LASTVALUEX}-Attribute mehr in den Triggernamen, da diese seit Zabbix 4 (nicht komplett sicher) nicht mehr aktualisiert werden. Stattdessen kommen solche Infos in das Feld “Operational Data”. Gesagt, getan:

  • Name: File in ‘{$FOLDERMONITORING.PATH}’ older than threshold ({$FOLDERMONITORING.THRESHOLD}m)
  • Operational Data: Age: {ITEM.LASTVALUE1}
    Immer klein halten, da es in Dashboards zusätzlich zum Triggernamen in der Zeile angezeigt wird
  • Serverity: Frei wählbar
  • Expression:
    {Template Module Windows folder content by Zabbix agent:foldermonitoring.age.last()}>{$FOLDERMONITORING.THRESHOLD} and {Template Module Windows folder content by Zabbix agent:foldermonitoring.name.strlen()}>0
    Wir prüfen den Namen hier nur, um darauf zugreifen zu können
  • OK event generation: Expression
  • PROBLEM event generation mode: Single
  • OK event closes: All problems
  • Allow manual close: Nein.
  • URL: –
  • Description: Path of File: {ITEM.LASTVALUE2}
    Hier greifen wir nun den Namen ab um ihn anzuzeigen.
  • Enabled: Ja.

Abschluss

Das war es nun – wir haben unser Template erstellt. Was die Komplexität betrifft, war das natürlich gar nichts. Jedoch haben wir hierdurch einen guten Einblick in alle nennenswerten Mechaniken bekommen. Funktionstechnisch kratzen wir hier sicher nur an der Oberfläche.

Categories
Exchange Scripts

OneLiner: Determine the size of a public folder (and it’s subfolder)

We recently had the request to determine the size of a public folder. Not a problem at all, this should do the trick:

[PS] C:\Windows\system32>Get-PublicFolder "\[Foldername]" | Get-PublicFolderStatistics | Select TotalItemSize

… not really. All we get is the summarized size of the items included in this specific folder. Subfolders and items in subfolders will be ignored. But there is another way which will include subfolder sizes. Here you go:

[PS] C:\Windows\system32>Get-PublicFolder "\[Foldername]" -Recurse | Get-PublicFolderStatistics | Measure TotalItemSize -sum

Optically improved version:

[PS] C:\Windows\system32>Get-PublicFolder "\[Foldername]" -Recurse | Get-PublicFolderStatistics | Measure TotalItemSize -sum | Select @{N='Anzahl der Items'; E={$_.Count}}, @{N='Speicher in Byte'; E={$_.Sum}} | fl

Please be aware that this oneliner may takes some time to complete your request.

Categories
Hyper-V Scripts

NIC-Teaming auf Hyper-V Server 2012 (R2) und Core Servern via PowerShell

Wenn an sich mehr Netzwerkbuchsen im Server verbaut sind als für das Teaming benötigt, so müssen als erstes die richtigen Anschlüsse fürs Teaming deklariert werden. Dies ist notwendig da die Benennung in Windows absolut gar nichts mit der physikalischen Anordnung am Server selbst zu tun hat.
Ich habe es mir da sehr einfach gemacht: Alle Netzwerkkabel abgesteckt und dann ein Kabel (möglichst mit DHCP-Server dahinter) nacheinander in jede Teaming-Buchse eingesteckt, immer gefolgt von folgendem PowerShell-Befehl:

Get-NetAdapter -Physical | where {$_.Status -eq "Up"} | Get-NetIPConfiguration
.

Dabei sollte man sich immer die Property “Interface Alias” notieren.

Mit Hilfe dieser Aliase geht es nun zum zweiten PowerShell-Befehl:

$name = "NIC TEAM"
$team = New-NetLbfoTeam -Name $name -TeamNicName ($name) -TeamMembers "InterfaceAlias1","InterfaceAlias2","[...]" -TeamingMode Lacp -LoadBalancingAlgorithm HyperVPort -Confirm $false
.

Hier wird die Option “-TeamMembers” mit den zuvor notierten Aliasen in der angezeigten Schreibweise aufgefüllt.