Office 365 Exchange Online Powershell unter Windows 10 Verbindung herstellen

Die Office 365 Exchange Online Powershell benötigt eigentlich keine Powershell Modul-Installation, weil zu Exchange nur eine Remote-Session hergestellt wird.

Anders sieht da aus, wenn man die MFA (Mehr-Faktor-Authentifizierung) eingeschaltet hat. Dazu unten mehr.

Exchange Online Powershell ohne MFA

$credential = Get-Credential
$exchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $credential -Authentication "Basic" -AllowRedirection
Import-PSSession $exchangeSession -DisableNameChecking -AllowClobber

Das erste Kommando fragt die Credentials ab und speichert diese in der Variable $credential, das zweite verwendet diese für die Verbindung und das dritte importiert die Remote-Sitzung.

Exchange Online Powershell mit 2FA (Mehr-Faktor Authentifizierung)

Hierfür muss man zuerst doch noch manuell ein Modul herunterladen, das „Exchange Online Remote PowerShell-Modul„. Man findet den Download für die Offline-Installation innerhalb seines Office 365 Portals in der EAC. Mann kann diese Spezial-Powershell aber auch direkt ohne Umwege herunterladen und starten; der Link dazu steht weiter unten.

Office 365 Portal > Exchange Administrator Center (EAC) > Hybrid > „Konfigurieren“ (‚Das Exchange Online-PowerShell-Modul unterstützt mehrstufige Authentifizierung.‘)

Hat man das Modul heruntergeladen und installiert, sollte man einmal sein WinRM-Konfiguration testen. Ein lauffähiges WinRM-System mit eingeschalteter Basic-Authentifizierung (Default) ist Voraussetzung.

WinRM-Konfiguration in der Powershell „als Administrator“ anschauen:

winrm get winrm/config/client/auth

Sollte da „Basic = false“ in der Ausgabe stehen, muss man zwingend Basic-Auth einschalten:

winrm set winrm/config/client/auth @{Basic="true"}

Dann kann man auch schon endlich fast eine Verbindung herstellen; dazu das „Microsoft Exchange Online Powershell Module“ im Startmenü öffnen. Dier hier ist der direkte Download-Link zur Exchange Shell:

https://cmdletpswmodule.blob.core.windows.net/exopsmodule/Microsoft.Online.CSE.PSModule.Client.application

In der neuen Exchange-Powershell tippt man dann:

Connect-EXOPSSession -UserPrincipalName <[email protected]>

Und schon stehen einem die altbekannten CMDlets wie Get-Mailbox, Get-DistributionGroup oder Get-MailboxPermission zur Verfügung.

Office 365 Powershell Zugänge unter Windows 10 (1809+)

Nachdem der letze Beitrag zum Thema Office 365 Powershell ja mittlerweile veraltet ist, hier die aktuelle Methode eine Verbindung zu Office 365 herzustellen.

„Heute“ nutzt man direkt die AzureAD Module die man via NuGet installiert und nicht mehr die MSOnline „Extra“ Shell.

Installation des AzureAD Module (Lizenzen, Office 365 Benutzer …)

  1. Öffnen der Powershell „Als Administrator“ und das Modul installieren:
PS C:\> Install-Module -Name AzureAD

Nicht vertrauenswürdiges Repository
Sie installieren die Module aus einem nicht vertrauenswürdigen Repository. Wenn Sie diesem Repository vertrauen, ändern
 Sie dessen InstallationPolicy-Wert, indem Sie das Set-PSRepository-Cmdlet ausführen. Möchten Sie die Module von
'PSGallery' wirklich installieren?
[J] Ja  [A] Ja, alle  [N] Nein  [K] Nein, keine  [H] Anhalten  [?] Hilfe (Standard ist "N"): j
PS C:\>

2. Herstellen der Verbindung zum AzureAD (Office 365)

PS C:\> Connect-AzureAD

Account                     Environment TenantId                             TenantDomain    AccountType
-------                     ----------- --------                             ------------    -----------
<UPN>> AzureCloud  affeaffe-b00b54e0e-a0c4-a5b16ca62f5b <DOMAIN> User
PS C:\>

… fertig. Und schon kann man mit den AzureAD-CMDlets wie Get-AzureADUser, Get-AzureADUserLicenseDetail und allen anderen loslegen.

Eine Liste aller CMDlets gibt es mit:

Get-Command -Module AzureAD

Windows Server 2016 RDS Effekte (Black Screen, Startmenü defekt)

Problem:

Ein Terminal Server (RDS Session Host) zeigt nach einiger Zeit verschiedene Effekte, wie z.B. „schwarzer Bildschirm nach der Anmeldung“, „nicht mehr funktionierendes Startmenü“, allgemeine Performance- oder Anmeldeprobleme.

Dies betrifft übrigens nicht zwingend nur RDS Sitzungshosts, sondern prinzipiell alle Windows Server 2016 Maschinen, auf Terminalservern (insbesondere mit User Profile Disks, UPDs) ist das ganze aufgrund potenziell größerer Anmelde-/Benutzeranzahl nur deutlich wahrscheinlicher anzutreffen.

Lösung:

Schuld könnte ein Bug sein, welcher dafür sorgt, dass bei der Benutzeranmeldung erstellte Firewall-Regeln beim löschen des Benutzerprofils (hier kommen die UPDs ins Spiel, unter Einsatz dieser wird das Profil nämlich bei der Abmeldung automatisch wieder vom Server gelöscht) nicht mehr entfernt werden.

Das verursacht einen Registry-Bloat in 

HKLM:\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules

und/oder

HKLM:\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\Configurable\System

Sind diese Keys bereits „überfüllt“, kann es gut sein, dass sich die Werte nicht mehr per GUI (regedit) entfernen lassen – der Key lädt schlichtweg Ewigkeiten und stürzt bei zu wenig RAM ab.

Abhilfe schafft unser kleines PowerShell-Script, das die Einträge nacheinander löscht:

$profiles = get-wmiobject -class win32_userprofile
Clear-Host
Write-Host "`n`n`n`n`n`n`n`n"
Write-Host "Getting Firewall Rules..."
$Rules1 = Get-NetFirewallRule -All | 
  Where-Object {$profiles.sid -notcontains $_.owner -and $_.owner }
$Rules1Count = $Rules1.count
Write-Host "" $Rules1Count "Rules`n"

Write-Host "Getting Firewall Rules from ConfigurableServiceStore..."
$Rules2 = Get-NetFirewallRule -All -PolicyStore ConfigurableServiceStore | 
  Where-Object { $profiles.sid -notcontains $_.owner -and $_.owner }
$Rules2Count = $Rules2.count
Write-Host "" $Rules2Count "Rules`n"

$Total = $Rules1.count + $Rules2.count
Write-Host "Deleting" $Total "Firewall Rules:" -ForegroundColor Green

$Result = Measure-Command {

  $start = (Get-Date)
  $i = 0.0

  foreach($rule1 in $Rules1){

    # action
    Remove-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules" -Name $rule1.name

    # progress
    $i = $i + 1.0
    $prct = $i / $total * 100.0
    $elapsed = (Get-Date) - $start
    $totaltime = ($elapsed.TotalSeconds) / ($prct / 100.0)
    $remain = $totaltime - $elapsed.TotalSeconds
    $eta = (Get-Date).AddSeconds($remain)

    # display
    $prctnice = [math]::round($prct,2) 
    $elapsednice = $([string]::Format("{0:d2}:{1:d2}:{2:d2}", $elapsed.hours, $elapsed.minutes, $elapsed.seconds))
    $speed = $i/$elapsed.totalminutes
    $speednice = [math]::round($speed,2) 
    Write-Progress -Activity "Deleting Rules ETA $eta elapsed $elapsednice loops/min $speednice" -Status "$prctnice" -PercentComplete $prct -SecondsRemaining $remain
  }

  foreach($rule2 in $Rules2) {

    # action  
    Remove-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\RestrictedServices\Configurable\System" -Name $rule2.name

    # progress
    $i = $i + 1.0
    $prct = $i / $total * 100.0
    $elapsed = (Get-Date) - $start
    $totaltime = ($elapsed.TotalSeconds) / ($prct / 100.0)
    $remain = $totaltime - $elapsed.TotalSeconds
    $eta = (Get-Date).AddSeconds($remain)

    # display
    $prctnice = [math]::round($prct,2) 
    $elapsednice = $([string]::Format("{0:d2}:{1:d2}:{2:d2}", $elapsed.hours, $elapsed.minutes, $elapsed.seconds))
    $speed = $i/$elapsed.totalminutes
    $speednice = [math]::round($speed,2) 
    Write-Progress -Activity "Deleting Rules from ConfugurableServiceStore ETA $eta elapsed $elapsednice loops/min $speednice" -Status "$prctnice" -PercentComplete $prct -secondsremaining $remain
  }
}

$end = Get-Date
Write-Host end $end 
Write-Host eta $eta

Write-Host $result.minutes min $result.seconds sec

Achtung: bei einem bereits länger laufenden Terminalserver, kann das Script schonmal so ein paar Stunden brauchen um alle Regeln zu entfernen. In einem Fall hier knapp 4 Stunden für etwa 95000 Regeln. Je nach CPU kann das natürlich etwas schneller gehen oder länger dauern – es wird wirklich fertig.

Aus jenen Performancegründen löscht das Script die Registry-Werte direkt, anstatt das eigentlich korrekte Remove-NetFirewallRule Cmdlet zu verwenden.

PHP 7.x auf Windows Server 2016 mit IIS installieren, Schritt für Schritt

Installieren wir ein aktuelles PHP (7.2 in diesem Fall) auf einem Windows Server 2016 in 64bit. Da wir den IIS nutzen und ein lokales CGI-Script-Handling einrichten wollen, nutzen wir die NTS (Non Thread Safe) Variante.

Auf die Unterschiede zwischen „Thread Safe“ und „Non Thread Safe“ gehen wir hier nich genauer ein. Schnelle Admins wissen aber:

  • Apache + LoadModule: Thread Safe
  • Apache + FastCGI: Non-Thread Safe
  • IIS: Thread Safe
  • IIS + FastCGI: Non-Thread Safe « Diese Anleitung

Installation von PHP 7.2 auf Windows Serrver 2016 (IIS)

  1. Windows Server 2016 installieren+updaten, IIS und Tools hinzufügen. Die Installation dauert einen Moment. Der Telnet-Client ist nicht zwingend notwendig, aber oft hilfreich.
    PS C:\> Import-Module servermanager
    PS C:\> Install-WindowsFeature -name web-server,web-cgi –IncludeManagementTools
    PS C:\> Add-WindowsFeature telnet-client
  2. PHP herunterladen und installieren: https://windows.php.net/download/. „VC15 x86 Non Thread Safe„. Wir empfehlen 32bit (x86) wegen der Extensions, es gibt noch nicht alle Extensions in x64. Jetzt grade aktuell war PHP in der Version 7.2.9.
  3. Visual C++ 2015 Runtime Update 3 RC (oder auch gleich 2017) in x86 und x64 herunterladen und installieren: https://www.microsoft.com/DE-de/download/details.aspx?id=52685
  4. Die PHP ZIP-Datei  (als Administrator) entpacken (z.B. „%Program Files (x86)%\PHP“)
  5. Kopieren der „php.ini-development“ in die „php.ini“
    PS C:\Program Files (x86)\php-nts-x86> Copy-Item .\php.ini-development .\php.ini2
  6. PHP.ini bearbeiten
    error_log = C:\inetpub\logs\php_errors.log
    max_execution_time = 60
    max_input_time = 90
    memory_limit = 256M
    default_charset = "UTF-8"
    upload_tmp_dir = "C:\inetpub\temp\IIS Temporary Compressed Files"
    upload_max_filesize = 16M
    allow_url_fopen = Off
    extension=php_wincache.dll
  7. Den PHP Interpreter zur System-PATH-Variable hinzufügen
    1. Systemeigenschaften > Erweitert > Umgebungsvariablen > Systemvariablen > Eintrag „Path“ bearbeiten > Neu > <PFAD ZU PHP> einfügen > OK > OK
  8. „Wincache Extensian for PHP“ 2.0 in 64bit herunterladen: https://www.iis.net/downloads/microsoft/wincache-extension (Aktuell: „wincache-2.0.0.8-dev-7.1-nts-vc14-x64.exe“) und in den PHP-Pfad nach \ext entpacken
  9. PHP im IIS konfigurieren
    1. „Internetinformationsdienste (IIS)-Manager“ starten > Links den Server auswählen (oberste Ebene) > „Handlerzuordnungen“ öffnen
    2. „Modulzuordnung hinzufügen“:
      1. Anforderungspfad: *.php
      2. Modul: FastCgiModule
      3. Ausführbare Datei: „C:\Program Files (x86)\<PHP-PFAD>\php-cgi.exe“
      4. Name: PHP
      5. Einschränkungen: „Handler nur bei folgender Zuordnung aufrufen“ auf „Datei oder Ordner“ stellen
  10. Standartdokument(e) hinzufügen
    1. Internetinformationsdienste (IIS)-Manager“ starten > Links den Server auswählen (oberste Ebene) >Standdartdokument
    2. Hinzufügen > „index.php“
  11. Schon fertig 🙂

Installation von Microsoft SQL Server Treibern für PHP unter Windows/IIS

  1. Download der „Microsoft PHP drivers Version for SQL Server“ (aktuell 7.2): https://github.com/Microsoft/msphpsql/releases
  2. Entpacken von x86\php_pdo*.dll nach <PHPPFAD>\ext
  3. Bearbeiten der PHP.ini
    extension=php_sqlsrv_72_nts.dll
  4. Download und Installation der „Microsoft® ODBC Driver 17 for SQL Server“ in 64bit: https://www.microsoft.com/de-DE/download/details.aspx?id=56567
  5. Webserver neustart mit „IISRESET“
  6. Fertig 🙂

Ob das jeweilige Modul geladen werden konnte, lässt sich an der Kommandozeile mit „php -m“ recht gut überprüfen.

Testen der Installation von PHP auf IIS

In C:\inetpub\wwwroot eine Datei „phpinfo.php“ anlegen mit dem folgenden Inhalt:

<?php
    phpinfo();
?>

Und aufrufen von http://<SERVERNAME>/phpinfo.php

 

In Office 365 mit der Powershell die Benutzerkontaktdaten wie Straße oder Ort Massenhaft ändern

Problem

Es sollen viele oder gleich alle Office 365 Benutzer geändert werden. Wegen eines Umzuges stimmt der Ort nicht mehr, wegen eines verdammten CSV-Ascii-Importfehlers stimmen Sonderzeichen nicht oder es hat sich eine andere Eigenschaft bei vielen Benutzern geändert die nun auf einmal angepasst werden soll.

Lösung

Zuerst muss man sich mit der „Windows Azure Active Directory-Modul für Windows PowerShell“ Powershell mit dem Office365 verbinden:

PS C:\> Connect-MsolService
    • Eigenschaften aller Benutzer sofort ändern (hier: ‚Straße‘)
      PS C:\> Get-MsolUser | Set-MsolUser -Street "Neue Strasse 815"
    • Eigenschaften der Benutzer ändern, die noch die alte Straße eingetragen haben
      PS C:\> Get-MsolUser | ? { $_.StreetAddress -eq 'Alte Adresse' } | Set-MsolUser -StreetAddress 'Neue Adresse'
    • Eigenschaften von nur zwei Benutzern ändern
      PS C:\> Get-MsolUser | ? { $_.UserPrincipalName -eq '[email protected]' -Or $_.UserPrincipalName -eq '[email protected]' } | Set-MsolUser