– Jan's Cloud – online Gedankenstütze ;)

1. August 2018

Exchange Server 2019 Preview verfügbar

Filed under: Exchange,PowerShell,Windows Server — Schlagwörter: , , , — Jan Mischo @ 14:37

Am 24.07.2018 wurde die Exchange Server 2019 Preview für die Allgemeinheit veröffentlicht

Da es grade sehr heiß ist und in der Ferienzeit scheinbar alle im Urlaub sind, habe ich meine riesige Exchange Demoumgebung doch direkt einmal auf die Exchange Server 2019 Preview upgedatet. 🙂

Bei der Installation in die bestehende Exchange Organisation hat sich im Vergleich zu den letzten beiden Exchange Versionen eigentlich nichts getan. Die Vorraussetzungen sind ebenfalls nahezu geich geblieben und wären namentlich:

Getreu dem Dinner for one Motto „The same procedure as every year“ sieht das GUI Setup dem der alten Versionen ziemlich ähnlich. Damit alle beruhigt sind, bei der Installation per Commandline hat sich auch nichts getan.

Nach der Installation geht es ebenfalls ziemlich genau so weiter wie bei einer Migration von Exchange 2013 auf 2016:

#Auslesen der Exchange Server
$Exch2016 = Get-ExchangeServer | ? AdminDisplayVersion -match "Version 15.1"
$Exch2019 = Get-ExchangeServer | ? AdminDisplayVersion -match "Version 15.2"
#Auslesen des konfigurierten SplitDNS FQDNs
$vDirHost = $(Get-OwaVirtualDirectory -Server $Exch2016).InternalURL.Host

#Mailboxdatenbanken auf dem Exchange 2019 trennen
Get-MailboxDatabase -Server $Exch2019 | Dismount-Database -Confirm:$false
#Mailboxdatenbanken umbenennen, verschieben und einbinden
foreach ($DB in $(Get-MailboxDatabase -Server $Exch2019)) { $i = $i + 1; Set-MailboxDatabase -Identity $DB -Name Exch2019DB0$i; Move-Databasepath -Identity $DB -edbfilepath "D:\ExchangeDB\Exch2019DB0$i\Exch2019DB0$i.edb" -logfolderpath "D:\ExchangeLOG\Exch2019DB0$i" -confirm:$false; Mount-Database -Identity Exch2019DB0$i -confirm:$false }

#Neuen Receiveconnector "Internet" erstellen und in meinem Fall der Firewall erlauben anonym Mails einzuliefern
New-ReceiveConnector -Name "Internet" -Usage Custom  -TransportRole FrontendTransport -PermissionGroups AnonymousUsers -Bindings 0.0.0.0:25 -RemoteIpRanges $((Get-NetRoute -ifIndex $(Get-NetIPAddress -InterfaceAlias "LAN" -AddressFamily "IPv4").ifIndex | ? DestinationPrefix -eq "0.0.0.0/0").NextHop)
#Dem Sendeconnector "Internet" den neuen Exchange hinzufügen
Get-SendConnector -Identity "Internet" | Set-SendConnector -SourceTransportServers $Exch2016, $Exch2019

#IMAP und POP Zertifikats CN anpassen, da ich ein Wildcard Zertifikat nutze
Set-ImapSettings -Server $Exch2019 -X509CertificateName $vDirHost
Set-PopSettings -Server $Exch2019 -X509CertificateName $vDirHost

# IMAP und POP Dienste neu starten
Restart-Service MSExchangeIMAP4BE
Restart-Service MSExchangeImap4
Restart-Service MSExchangeIMAP4BE
Restart-Service MSExchangePop3

#Virtuelle Verzeichnisse konfigurieren
Get-OwaVirtualDirectory -Server $Exch2019 | Set-OwaVirtualDirectory -InternalUrl "https://$vDirHost/owa" -ExternalUrl "https://$vDirHost/owa"
Get-EcpVirtualDirectory -Server $Exch2019 | Set-EcpVirtualDirectory -InternalUrl "https://$vDirHost/ecp" -ExternalUrl "https://$vDirHost/ecp"
Get-OABVirtualDirectory -Server $Exch2019 | Set-OABVirtualDirectory -InternalURL "https://$vDirHost/OAB" -ExternalURL "https://$vDirHost/OAB"
Get-ActiveSyncVirtualDirectory -Server $Exch2019 | Set-ActiveSyncVirtualDirectory -InternalURL "https://$vDirHost/Microsoft-Server-ActiveSync" -ExternalURL "https://$vDirHost/Microsoft-Server-ActiveSync"
Get-WEbServicesVirtualDirectory -Server $Exch2019 | Set-WEbServicesVirtualDirectory -InternalURL "https://$vDirHost/EWS/Exchange.asmx" -ExternalURL "https://$vDirHost/EWS/Exchange.asmx"
Get-MapiVirtualDirectory -Server $Exch2019 | Set-MapiVirtualDirectory -InternalURL "https://$vDirHost/mapi" -ExternalURL "https://$vDirHost/mapi"
Get-ClientAccessService -Identity $Exch2019.Name | Set-ClientAccessService -AutodiscoverServiceInternalUri https://$vDirHost/autodiscover/autodiscover.xml
Get-OutlookAnywhere -Server $Exch2019 | Set-OutlookAnywhere -ExternalHostname $vDirHost -InternalHostname $vDirHost -ExternalClientsRequireSsl:$true -InternalClientsRequireSsl:$true -ExternalClientAuthenticationMethod "Ntlm"

#Zertifikatskette und eigentliches Wildcard Zertifikat aus C:\Install\Zertifikate einlesen
$Zertifikat = (Get-ChildItem -Path C:\Install\Zertifikate\1Comodo_RootCA.crt)
$Zertifikat | Import-Certificate -CertStoreLocation Cert:\LocalMachine\Root | Out-Null
$Zertifikat = (Get-ChildItem -Path C:\Install\Zertifikate\2Comodo_Intermediate_1.crt)
$Zertifikat | Import-Certificate -CertStoreLocation Cert:\LocalMachine\CA | Out-Null
$Zertifikat = (Get-ChildItem -Path C:\Install\Zertifikate\3Comodo_Intermediate_2.crt)
$Zertifikat | Import-Certificate -CertStoreLocation Cert:\LocalMachine\CA | Out-Null
$Zertifikat = Import-pfxCertificate -FilePath "C:\Install\Zertifikate\04Wildcard.pfx" -CertStoreLocation Cert:\LocalMachine\My -Password $(ConvertTo-SecureString "Kennwort1" -AsPlainText -Force)
Enable-ExchangeCertificate -Thumbprint $Zertifikat.Thumbprint -Services IIS, IMAP, POP, SMTP -Force -Confirm:$false

#An dieser Stelle wäre es Zeit die IP Adresse im DNS von $vDirHost auf den neuen Exchange Server zu schwenken
#Sowie den DNS Cache am Server sowie Client zu löschen
#Sowie einen heißen, schwarzen Kaffee zu trinken!

#Migrations Mailbox verschieben
#https://technet.microsoft.com/en-us/library/mt441791(v=exchg.150)
Get-Mailbox -Identity Migration* -Arbitration | New-MoveRequest -TargetDatabase Exch2019DB01

#Test User verschieben
New-MoveRequest Toni.Test -TargetDatabase Exch2019DB01

#Outlook testen... Outlook kann während dem gesamten Verschiebevorgang offen sein. Nach Abschluss ist ebenfalls kein Neustart mehr notwendig

#Arbitration Postfächer, alle anderen Postfächer und die öffentlichen Ordner Postfächer verschieben
Get-Mailbox -Server $Exch2016 -Arbitration | New-MoveRequest -TargetDatabase Exch2019DB01
Get-Mailbox -Server $Exch2016 | New-MoveRequest -TargetDatabase Exch2019DB01
Get-Mailbox -PublicFolder | New-MoveRequest -TargetDatabase Exch2019DB01
Get-Mailbox -AuditLog | New-MoveRequest -TargetDatabase Exch2019DB01

#Aufräumen
Get-MoveRequest | Remove-MoveRequest -Confirm:$false

#Exchange 2016 deinstallieren

Aufgrund des Hinweises von Sebastian Röhner im Kommentar, habe ich die Umgebung noch einmal neu aufgebaut und die Mailbox eines Testusers direkt verschoben ohne vorher das Migrationspostfach (Migration Mailbox) zu verschieben. Was soll ich sagen, es hat erneut ohne Probleme funktionert. Dennoch werde ich in Zukunft wohl den Microsoft-Weg, wie in https://technet.microsoft.com/en-us/library/mt441791(v=exchg.150) beschrieben gehen. Daher ist das Script auch ein wenig ergänzt worden.

Nochmals ein „Danke“ an Sebastian Röhner für den Hinweis!

MoveRequest MigrationMailbox

MoveRequest MigrationMailbox

 

 

 

 

 

Da bleibt ja eigenltich nur die Frage nach den Änderungen oder Neuerungen… Auf den ersten Blick wären da:

  • Support von Windows Server 2016 (2019 vermutlich auch?) Core
  • Einem in der Preview nicht funktionierenden SSD Cache
  • Indexierung nicht mehr im Dateisystem sondern in der Datenbnak
  • Unterstützung von 48 Prozessoren und 256GB RAM
  • Es gibt keine UM (Unified Messaging) Rolle mehr mit Exchange 2019
halo i bims exchange server 2019 preview

halo i bims exchange server 2019 preview

 

23. Juli 2018

Migration von Exchange 2010 zu 2016

Filed under: Exchange,Windows Server — Schlagwörter: , , , , — Jan Mischo @ 11:37

Das Ende von Exchange 2010 steht „kurz“ bevor, daher hier noch einmal ein kleines How-To für die Migration von Exchange 2010 zu Exchange 2016.

Wie hier bereits erwähnt, werden mit dem Exchange 2010 SP3 RollUp 22 (endlich) Windows Server 2016 Domain Controller in der Active Directory Gesamtstruktur (Forest) unterstützt. Daher ist es jetzt möglich, die alten DCs und Exchange Server in „einem Schritt“ abzulösen. Das ist insbesondere bei Small Business Servern 2011 sehr hilfreich. 🙂 Somit steht einer Migration von Exchange auf SBS 2011 zu Exchange 2016 auf Server 2016 nichts mehr im Weg.

Die Systemanforderungen hat jedermann / jedefrau natürlich gelesen / überflogen. Die Installation der Vorbereitungen sowie des eigentlichen Exchange Servers 2016 (mit dem aktuellesten CU!) setze ich hier an dieser Stelle einmal ganz dreist voraus, so dass direkt mit den Vorbereitungen des Updates der Exchange Organisation losgelegt werden kann. Dazu sollte als erstes am Exchange 2010, sofern noch möglich, eine weitere Mailboxdatenbank mit einem Proxy-Postfach für die öffentlichen Ordner angelegt werden.

$Ex2010 = Get-ExchangeServer | ? AdminDisplayVersion -like "Version 14.3*"
$Ex2016 = Get-ExchangeServer | ? AdminDisplayVersion -like "Version 15.1*"
New-MailboxDatabase -Server $Ex2010  -Name PFProxyDatabase -IsExcludedFromProvisioning $true
Set-MailboxDatabase PFProxyDatabase -CircularLoggingEnabled $true
Mount-Database PFProxyDatabase

# Hier könnte man mit Invoke-Command die Mailbox vom Exchange 2016 auf dem 2010 erstellen, oder einfach und schnell die EMC auf dem Exchange 2010 öffnen und die Befehle dort ausführen. 😉
New-Mailbox -Name PFProxyMailbox1 -Database PFProxyDatabase -UserPrincipalName PFProxyMailbox1@[Domain].[tld] -Password $(ConvertTo-SecureString G3he!mesPW -AsPlainText -Force)
Set-Mailbox -Identity PFProxyMailbox1 -HiddenFromAddressListsEnabled $true
Vorbereitung Exchange 2010 PFProxyMailbox

Vorbereitung Exchange 2010 PFProxyMailbox

 

 

 

 

Sollte es auf dem Exchange Server 2010 (Standard) bereits 5 Datenbanken (z.B. 4x Postfachdatenbank / 1x öffentliche Ordner Datenbank) geben, bleibt nicht viel anderes übrig, wie die PFProxyMailbox1 in einer bestehenden Datenbank zu erzeugen. Wer möchte, der darf natürlich eine Datenbank leer räumen, diese löschen und dann die PFProxyDatabase samt PFProxyMailbox1 erstellen.

Weiter geht die wilde Migration von Exchange am neuen Server, wo die eben erstellte öffentliche Ordner Proxy-Mailbox (PFProxyMailbox1) zum Einsatz kommt und später die Zugriffe auf den legacy Exchange Server ermöglicht bis die öffentlichen Ordner komplett in die neue modern Public Folder übertragen wurden. Da es bei vielen Migrationen immer mal wieder zu Problemen mit MAPI over HTTP gekommen ist, bin ich dazu übergegangen und habe es für die Dauer der Migration deaktiviert. Nach erfolgreicher Deinstallation des legacy Servers aktiviere ich es dann wieder.

Set-OrganizationConfig -MapiHttpEnabled $false
Set-OrganizationConfig -PublicFoldersEnabled Remote -RemotePublicFolderMailboxes PFProxyMailbox1

# Zum Prüfen:
Get-OrganizationConfig | fl *PublicFolder*
Exchange 2016 Remote Public Folder aktivieren

Exchange 2016 Remote Public Folder aktivieren

 

 

 

 

Im nächsten Schritt wäre es sehr hilfreich, wenn der Exchange 2010 bereits nach Best Practice konfiguriert ist und die internen URLs der virtuellen Verzeichnisse gleich denen der externen URLs sind (SplitDNS). Sollte dies nicht der Fall sein – Don’t Panic! Dann wird SplitDNS eben umgehend eingeführt: https://jans.cloud/2014/09/exchange-2007-2010-2013-2016-virtuelle-verzeichnisse-zertifikate-splitdns/

# Ggfs. noch die erste / einzige Datenbank umbenennen und verschieben
Dismount-Database -Identity "Mailbox Database *" -Confirm:$false
Get-MailboxDatabase | Set-MailboxDatabase -name "Exch2016DB01"
Move-Databasepath -Identity "Exch2016DB01" -edbfilepath "d:\ExchangeDBs\Exch2016DB01\Exch2016DB01.edb" -logfolderpath "d:\ExchangeLogs\Exch2016DB01" -Confirm:$False
# Je nach Speicherplatz evtl. Umlaufprotokollierung für die Dauer der Migration aktivieren
# Get-MailboxDatabase | Set-MailboxDatabase -CircularLoggingEnabled $true
Mount-Database -Identity "Exch2016DB01" -Confirm:$false

# Receive Connector für den Mail-Empfang erstellen
New-ReceiveConnector -Name "Internet" -Usage Custom  -TransportRole FrontendTransport -PermissionGroups AnonymousUsers -Bindings 0.0.0.0:25 -RemoteIpRanges [IP der Firewall / SPAM Filter]

# Offline Adressbuch setzen
$OAB = Get-OfflineAddressBook | ? Identity -like "*(Ex2013)"
foreach ($Ex in Get-ExchangeServer ) { Get-MailboxDatabase -Server $Ex.Name | Set-MailboxDatabase -OfflineAddressBook $OAB }    

# Exportiertes Zertifikat vom Exchange 2010 installieren
$Cert = Import-PFXCertificate -FilePath "[Pfad zum Zertifikat].pfx" -CertStoreLocation Cert:\LocalMachine\My -Password $(ConvertTo-SecureString G3he!mesPW -AsPlainText -Force)

Get-OwaVirtualDirectory -Server $Ex2016 | Set-OwaVirtualDirectory -InternalUrl 'https://owa.[Domain].[tld]/owa' -ExternalUrl 'https://owa.[Domain].[tld]/owa'
Get-EcpVirtualDirectory -Server $Ex2016 | Set-EcpVirtualDirectory -InternalUrl 'https://owa.[Domain].[tld]/ecp' -ExternalUrl 'https://owa.[Domain].[tld]/ecp'
Get-OABVirtualDirectory -Server $Ex2016 | Set-OABVirtualDirectory -InternalURL 'https://owa.[Domain].[tld]/OAB' -ExternalURL 'https://owa.[Domain].[tld]/OAB'
Get-ActiveSyncVirtualDirectory -Server $Ex2016 | Set-ActiveSyncVirtualDirectory -InternalURL 'https://owa.[Domain].[tld]/Microsoft-Server-ActiveSync' -ExternalURL 'https://owa.[Domain].[tld]/Microsoft-Server-ActiveSync'
Get-WEbServicesVirtualDirectory -Server $Ex2016 | Set-WEbServicesVirtualDirectory -InternalURL 'https://owa.[Domain].[tld]/EWS/Exchange.asmx' -ExternalURL 'https://owa.[Domain].[tld]/EWS/Exchange.asmx'
Get-MapiVirtualDirectory -Server $Ex2016 | Set-MapiVirtualDirectory -InternalURL 'https://owa.[Domain].[tld]/mapi' -ExternalURL 'https://owa.[Domain].[tld]/mapi'
Get-ClientAccessService -Identity $Ex2016.Name | Set-ClientAccessService -AutodiscoverServiceInternalUri https://owa.[Domain].[tld]/autodiscover/autodiscover.xml

Get-OutlookAnywhere -Server $Ex2016 | Set-OutlookAnywhere -ExternalHostname owa.[Domain].[tld] -InternalHostname owa.[Domain].[tld] -ExternalClientsRequireSsl:$true -InternalClientsRequireSsl:$true -ExternalClientAuthenticationMethod 'Ntlm'

Enable-ExchangeCertificate -Thumbprint $Cert.Thumbprint -Services IIS, POP, SMTP, IMAP -Confirm:$false -Force
SplitDNS virtuelle Verzeichnisse

SplitDNS virtuelle Verzeichnisse

 

 

 

 

 

 

 

Bevor die erste Mailbox verschoben werden kann, sollte der neue Exchange Server noch zum bestehenden Sende Connector hinzugefügt werden. Sobald das erledigt ist, wird die erste Test-Mailbox verschoben und an einem Test Client die Hostsdatei bearbeitet sowie Outlook gestartet.

Get-SendConnector | Set-SendConnector -SourceTransportServers $(Get-ExchangeServer)

$Ex2016MBX = Get-MailboxDatabase -Server $Ex2016
New-MoveRequest Test.User -TargetDatabase $Ex2016MBX

Am oben genannten Test Client kann jetzt vorsichtshalber einmal die HOSTS-Datei bearbeitet werden und um die Einträge

  • [IP des Exchange 2016] owa.[DOMAIN].[tld]
  • [IP des Exchange 2016] autodiscover.[DOMAIN].[tld]

ergänzt werden.

HOSTS Datei am Test Client

HOSTS Datei am Test Client

 

 

 

Meldet sich der auserkorene Test User jetzt am Test Client an und öffnet Outlook, so sollte er zum letzten Mal in seinem Leben die folgende Nachricht erhalten:

Migration von Exchange am Client

Migration von Exchange am Client

 

 

 

 

Nach Bestätigung eben dieser Nachricht öffnet Outlook die Mailbox auf dem neuen Server und proxied die öffentlichen Ordner per PFProxyMailbox1 auf den legacy Server. Sobald der Test User sich vom ordnungsgemäßen Funktionieren des neuen Exchanges überzeugt hat, sollten die für SplitDNS konfigurierten Einträge auf den neuen Exchange Server geändert werden. Es kann nicht schaden die DNS Server Dienste einmal neu zu starten. Danach können die restlichen Postfächer inkl. der Arbitration-Mailboxes (Systempostfächer) verschoben werden.

Get-Mailbox -Server $Ex2010 -Arbitration | New-MoveRequest -TargetDatabase $Ex2016MBX
Get-Mailbox -Server $Ex2010 | New-MoveRequest -TargetDatabase $Ex2016MBX

# Mit einer kleinen Schleife lässt sich jetzt z.B. automatisch prüfen, ob alle Move Requests fertig sind..
do { Start-Sleep -Seconds 60; Get-MoveRequest | ? Status -ne "Completed" | Get-MoveRequestStatistics } until (!$(Get-MoveRequest | ? Status -ne "Completed"))

Während die Postfächer verschoben werden, kann an der Firewall / am SPAM Filter der Mailflow bereits auf den neuen Exchange gelenkt werden. Ist dies geschehen, kann mit der Überführung der alten öffentlichen Ordner in die neue modern Public Folder Strukturen begonnen werden -> KLICK 🙂

P.S.: Am Test Client sollte ASAP nach dem Test die HOSTS Datei wieder in den Ursprungszustand zurückversetzt werden. Es ist ja nicht so, dass einem so eine HOSTS Datei noch nie auf die eigenen Füße gefallen ist. 😉

18. Juli 2018

Unnötige Windows Server 2016 Dienste deaktivieren

Deaktivieren der nicht benötigten Windows Server 2016 Dienste (Manager für heruntergeladene Karten, Xbox Live Authentifizierungs-Manager, Xbox Live-Spiele speicher, usw.)

Kurz und schmerzlos:

$cred = Get-Credential
foreach ($Server in $(Get-ADComputer -SearchBase "OU=Meine OU,DC=Meine Domäne,DC=Meine TLD" -Filter 'OperatingSystem -like "Windows Server 2016*"')) {
    Write-Host "Verbinde mit Server:" $Server.DNSHostName
    Invoke-Command -ComputerName $Server.DNSHostName -Credential $cred -ScriptBlock {
        Write-Host "`tDeaktiviere Dienste..."
        Set-Service -Name "MapsBroker" -StartupType Disabled
        Set-Service -Name "XblAuthManager" -StartupType Disabled
        Set-Service -Name "XblGameSave" -StartupType Disabled

        Write-Host "`tDeaktiviere per User Dienste..."
        if(Test-Path -Path HKLM:\SYSTEM\CurrentControlSet\Services\OneSyncSvc_*) {
	        $TempSVC = (Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services\OneSyncSvc_*)
	        foreach ($SVC in $TempSVC) {
		        $SVC = "$($SVC.PSParentPath)\$($SVC.PSChildName)"
		        Set-ItemProperty -Path $SVC -Name "Start" -Value 4
	        }
        }
        Write-Host "`tDeaktiviere geplante Tasks..."
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Maps\" -TaskName "MapsToastTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\XblGameSave\" -TaskName "XblGameSaveTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\XblGameSave\" -TaskName "XblGameSaveTaskLogon" | Out-Null
    }
}

Vor einiger Zeit hatte ich über das Citrix Optimizer Tool geschrieben. Das deaktiviert unterm Strich ebenfalls einige Dienste und nimmt weitere Einstellungen vor. Ebenfalls hat Microsoft eine Liste mit Diensten veröffentlicht die deaktiviert werden sollten / können:

Hier einmal das „volle Programm“ an überflüssigen / unnötigen Windows Server 2016 Diensten:

$cred = Get-Credential
foreach ($Server in $(Get-ADComputer -SearchBase "OU=Meine OU,DC=Meine Domäne,DC=Meine TLD" -Filter 'OperatingSystem -like "Windows Server 2016*"')) {
    Write-Host "Verbinde mit Server:" $Server.DNSHostName
    Invoke-Command -ComputerName $Server.DNSHostName -Credential $cred -ScriptBlock {
        Write-Host "`tDeaktiviere Dienste..."
        Set-Service -Name "Audiosrv" -StartupType Disabled
        Set-Service -Name "AudioEndpointBuilder" -StartupType Disabled
        Set-Service -Name "AxInstSV" -StartupType Disabled
        Set-Service -Name "bthserv" -StartupType Disabled
        Set-Service -Name "CDPUserSvc" -StartupType Disabled
        Set-Service -Name "dmwappushservice" -StartupType Disabled
        Set-Service -Name "FrameServer" -StartupType Disabled
        Set-Service -Name "icssvc" -StartupType Disabled
        Set-Service -Name "lltdsvc" -StartupType Disabled
        Set-Service -Name "lfsvc" -StartupType Disabled
        Set-Service -Name "MapsBroker" -StartupType Disabled
        Set-Service -Name "NcbService" -StartupType Disabled
        Set-Service -Name "PcaSvc" -StartupType Disabled
        Set-Service -Name "QWAVE" -StartupType Disabled
        Set-Service -Name "RmSvc" -StartupType Disabled
        Set-Service -Name "SensorDataService" -StartupType Disabled
        Set-Service -Name "SensorService" -StartupType Disabled
        Set-Service -Name "SensrSvc" -StartupType Disabled
        Set-Service -Name "SharedAccess" -StartupType Disabled
        Set-Service -Name "ShellHWDetection" -StartupType Disabled
        Set-Service -Name "SSDPSRV" -StartupType Disabled
        Set-Service -Name "stisvc" -StartupType Disabled
        Set-Service -Name "TabletInputService" -StartupType Disabled
        Set-Service -Name "upnphost" -StartupType Disabled
        Set-Service -Name "WalletService" -StartupType Disabled
        Set-Service -Name "WiaRpc" -StartupType Disabled
        Set-Service -Name "wisvc" -StartupType Disabled
        Set-Service -Name "wlidsvc" -StartupType Disabled
        Set-Service -Name "WpnService" -StartupType Disabled
        Set-Service -Name "XblAuthManager" -StartupType Disabled
        Set-Service -Name "XblGameSave" -StartupType Disabled

        Write-Host "`tDeaktiviere User Dienste..."
        if(Test-Path -Path HKLM:\SYSTEM\CurrentControlSet\Services\CDPUserSvc_*) {
	        $TempSVC = (Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services\CDPUserSvc_*)
	        foreach ($SVC in $TempSVC) {
		        $SVC = "$($SVC.PSParentPath)\$($SVC.PSChildName)"
		        Set-ItemProperty -Path $SVC -Name "Start" -Value 4
	        }
        }
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NgcSvc" -Name "Start" -Value 4
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\OneSyncSvc" -Name "Start" -Value 4
        if(Test-Path -Path HKLM:\SYSTEM\CurrentControlSet\Services\OneSyncSvc_*) {
	        $TempSVC = (Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services\OneSyncSvc_*)
	        foreach ($SVC in $TempSVC) {
		        $SVC = "$($SVC.PSParentPath)\$($SVC.PSChildName)"
		        Set-ItemProperty -Path $SVC -Name "Start" -Value 4
	        }
        }
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\PimIndexMaintenanceSvc" -Name "Start" -Value 4
        if(Test-Path -Path HKLM:\SYSTEM\CurrentControlSet\Services\PimIndexMaintenanceSvc_*) {
	        $TempSVC = (Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services\PimIndexMaintenanceSvc_*)
	        foreach ($SVC in $TempSVC) {
		        $SVC = "$($SVC.PSParentPath)\$($SVC.PSChildName)"
		        Set-ItemProperty -Path $SVC -Name "Start" -Value 4
	        }
        }
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\UserDataSvc" -Name "Start" -Value 4
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\UnistoreSvc" -Name "Start" -Value 4
        if(Test-Path -Path HKLM:\SYSTEM\CurrentControlSet\Services\UnistoreSvc_*) {
	        $TempSVC = (Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services\UnistoreSvc_*)
	        foreach ($SVC in $TempSVC) {
		        $SVC = "$($SVC.PSParentPath)\$($SVC.PSChildName)"
		        Set-ItemProperty -Path $SVC -Name "Start" -Value 4
	        }
        }
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\WpnUserService" -Name "Start" -Value 4
        if(Test-Path -Path HKLM:\SYSTEM\CurrentControlSet\Services\WpnUserService_*) {
	        $TempSVC = (Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services\WpnUserService_*)
	        foreach ($SVC in $TempSVC) {
		        $SVC = "$($SVC.PSParentPath)\$($SVC.PSChildName)"
		        Set-ItemProperty -Path $SVC -Name "Start" -Value 4
	        }
        }

        Write-Host "`tDeaktiviere geplante Tasks..."
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Application Experience\" -TaskName "Microsoft Compatibility Appraiser" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Application Experience\" -TaskName "ProgramDataUpdater" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\AppID\" -TaskName "EDP Policy Manager" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\AppID\" -TaskName "SmartScreenSpecific" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\ApplicationData\" -TaskName "CleanupTemporaryState" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\ApplicationData\" -TaskName "DsSvcCleanup" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Autochk\" -TaskName "Proxy" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Bluetooth\" -TaskName "UninstallDeviceTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\CloudExperienceHost\" -TaskName "CreateObjectTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Customer Experience Improvement Program\" -TaskName "Consolidator" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Customer Experience Improvement Program\" -TaskName "KernelCeipTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Customer Experience Improvement Program\" -TaskName "UsbCeip" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Diagnosis\" -TaskName "Scheduled" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Location\" -TaskName "Notifications" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Location\" -TaskName "WindowsActionDialog" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Maintenance\" -TaskName "WinSAT" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Maps\" -TaskName "MapsToastTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Mobile Broadband Accounts\" -TaskName "MNO Metadata Parser" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\NetTrace\" -TaskName "GatherNetworkInfo" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Power Efficiency Diagnostics\" -TaskName "AnalyzeSystem" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Ras\" -TaskName "MobilityManager" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\SpacePort\" -TaskName "SpaceAgentTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\SpacePort\" -TaskName "SpaceManagerTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Speech\" -TaskName "SpeechModelDownloadTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Storage Tiers Management\" -TaskName "Storage Tiers Management Initialization" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\WDI\" -TaskName "ResolutionHost" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\Windows\Workplace Join\" -TaskName "Automatic-Device-Join" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\XblGameSave\" -TaskName "XblGameSaveTask" | Out-Null
        Disable-ScheduledTask -TaskPath "\Microsoft\XblGameSave\" -TaskName "XblGameSaveTaskLogon" | Out-Null
    }
}

Hier das Script als Textdatei zum Download: Windows Server 2016 Dienste deaktivieren

16. Juli 2018

Exchange und Remotedesktopgateway über eine IP veröffentlichen

Mit dem Netscaler VPX Express (Freemium) Exchange und Remotedekstopgateway bzw. Outlook WebApp, Outlook Anywhere, Exchange ActiveSync, Remotedesktopgateway und die Remotedesktop Web Services über eine öffentliche IP betreiben

Ich komme häufig in Kundenumgebungen, in denen es nur noch eine freie externe IP Adresse gibt, und dennoch die Exchange- sowie Remotedesktopdienste nach außen veröffentlicht werden sollen. Hier kann man jetzt „unschön“ ansetzen und die Ports für Exchange oder RDS auf z.B. 10443 verbiegen und damit in diverse andere Probleme laufen oder man bedient sich dem kostenlosen Netscaler VPX Freemium (formerly known as Netscaler VPX Express) und größtenteils dem Content Switching.

Ich würde an dieser Stelle einfach mal voraussetzen, dass der Exchange Server entsprechend sauber mit Split DNS konfiguriert ist, die Remotedesktopdienste ebenfalls funktionstüchtig sind und der Netscaler grundkonfiguriert ist. Ebenfalls sollte es ein vertrauenswürdiges SAN Zertifikat mit den passenden FQDNs geben. In meinem Beispiel:

  • „app.<domain>.<tld>“
  • „autodiscover.<domain>.<tld>“
  • „outlook.<domain>.<tld>“

Dieses Zertifikat muss im ersten Step auf dem Netscaler installiert werden. Dazu kann man sich zum Beispiel dem Citrix Knowledge Center bedienen: https://support.citrix.com/article/CTX205404

Der Einfachheit halber starte ich direkt mal mit dem Weg über das Command Line Interface bzw. per SSH. Evtl. wird der Beitrag ja später noch um eine GUI Variante erweitert. 🙂 Also legen wir als erstes die Server im Load Balancing an, erstellen die Dienste sowie die Load Balancing Virtual Servers (GUI: Traffic Management -> Server bzw. -> Services bzw. -> Virtual Servers):

add server SRV_EXCHSRV <IP ADRESSE DES EXCHANGES>
add server SRV_CBSRV <IP ADRESSE DES RDGW / RDWEB>

add service SVC_Exchange_SSL SRV_EXCHSRV SSL 443 -gslb NONE -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport YES -sp OFF -cltTimeout 180 -svrTimeout 360 -CKA YES -TCPB YES -CMP NO
add service SVC_RDWeb-RDGW_SSL SRV_CBSRV SSL 443 -gslb NONE -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport YES -sp OFF -cltTimeout 180 -svrTimeout 360 -CKA YES -TCPB YES -CMP NO
add service SVC_RDWeb-RDGW_UDP-3391 SRV_CBSRV UDP 3391 -gslb NONE -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport NO -sp OFF -cltTimeout 120 -svrTimeout 120 -CKA YES -TCPB YES -CMP NO

add lb vserver LB_VS_Exchange SSL 0.0.0.0 0 -persistenceType NONE -cltTimeout 180
add lb vserver LB_VS_RDWeb-RDGW SSL 0.0.0.0 0 -persistenceType SOURCEIP -cltTimeout 180
add lb vserver LB_VS_RDWeb-RDGW-UDP UDP 0.0.0.0 0 -persistenceType SOURCEIP -cltTimeout 120
bind lb vserver LB_VS_Exchange SVC_Exchange_SSL
bind lb vserver LB_VS_RDWeb-RDGW SVC_RDWeb-RDGW_SSL
bind lb vserver LB_VS_RDWeb-RDGW-UDP SVC_RDWeb-RDGW_UDP-3391

set ssl vserver LB_VS_Exchange -ssl3 DISABLED
set ssl vserver LB_VS_RDWeb-RDGW -ssl3 DISABLED
bind ssl vserver LB_VS_Exchange -certkeyName <NAME DES IMPORTIERTEN ZERTIFIKATES>
bind ssl vserver LB_VS_RDWeb-RDGW -certkeyName <NAME DES IMPORTIERTEN ZERTIFIKATES>

Damit die Server nicht „blank“ per http(s) erreichbar sind, schränke ich den Zugriff auf die gewollten Verzeichnisse des WebServer (IIS) ein (GUI: AppExpert -> Pattern Sets bzw. -> Rewrite -> Actions / Policies):

add policy patset patt_set_rdweb_path
add policy patset patt_set_exchange_path

bind policy patset patt_set_rdweb_path "/" -index 4
bind policy patset patt_set_rdweb_path "/rpcwithcert" -index 1
bind policy patset patt_set_rdweb_path "/rpc" -index 2
bind policy patset patt_set_rdweb_path "/rdweb" -index 3
bind policy patset patt_set_exchange_path "/mapi" -index 1
bind policy patset patt_set_exchange_path "/ecp" -index 2
bind policy patset patt_set_exchange_path "/owa" -index 3
bind policy patset patt_set_exchange_path "/oab" -index 4
bind policy patset patt_set_exchange_path "/ews" -index 5
bind policy patset patt_set_exchange_path "/autodiscover" -index 6
bind policy patset patt_set_exchange_path "/rpcwithcert" -index 7
bind policy patset patt_set_exchange_path "/rpc" -index 8
bind policy patset patt_set_exchange_path "/microsoft-server-activesync" -index 9

add rewrite action rew_act_exchange_invalid_path replace http.REQ.URL.PATH "\"/owa\""
add rewrite action rew_act_rdweb_invalid_path replace http.REQ.URL.PATH "\"/rdweb\""

add rewrite policy rew_pol_exchange_invalid_path "!http.REQ.URL.PATH.TO_LOWER.CONTAINS_ANY(\"patt_set_exchange_path\")" rew_act_exchange_invalid_path
add rewrite policy rew_pol_rdweb_invalid_path "!http.REQ.URL.PATH.TO_LOWER.CONTAINS_ANY(\"patt_set_rdweb_path\")" rew_act_rdweb_invalid_path

bind lb vserver LB_VS_Exchange -policyName rew_pol_exchange_invalid_path -priority 100 -gotoPriorityExpression END -type REQUEST
bind lb vserver LB_VS_RDWeb-RDGW -policyName rew_pol_rdweb_invalid_path -priority 100 -gotoPriorityExpression END -type REQUEST

In der GUI müssen die letzten beiden Schritte natürlich unter Traffic Management -> Load Balancing -> Virtual Servers und dann den entsprechenden LB VServern vorgenommen werden. Damit wären die Vorbereitungen der Load Balancing Objekte (Server, Dienste, virtuelle Server) fertig und es geht nahtlos über zum Conten Switching (Traffic Management -> Content Switching -> Policies bzw. Virtual Servers).

add cs policy CS_POL_Exchange -rule "http.REQ.HOSTNAME.TO_LOWER.STARTSWITH(\"outlook.<domain>.<tld>\") || http.REQ.HOSTNAME.TO_LOWER.STARTSWITH(\"autodiscover.<domain>.<tld>.de\")"
add cs policy CS_POL_RDWeb-RDGW1 -rule "http.REQ.HOSTNAME.TO_LOWER.STARTSWITH(\"app.<domain>.<tld>\") && http.REQ.HEADER(\"User-Agent\").SET_TEXT_MODE(IGNORECASE).CONTAINS(\"MS-RDGateway/1.0\")"
add cs policy CS_POL_RDWeb-RDGW2 -rule "http.REQ.HOSTNAME.TO_LOWER.STARTSWITH(\"app.<domain>.<tld>\") && http.REQ.HEADER(\"User-Agent\").SET_TEXT_MODE(IGNORECASE).CONTAINS(\"MSRPC\")"
add cs policy CS_POL_RDWeb-RDGW3 -rule "http.REQ.HOSTNAME.TO_LOWER.STARTSWITH(\"app.<domain>.<tld>\") && http.REQ.URL.REGEX_MATCH(re-^/RDWeb/*-)"

add ns httpProfile nshttp_profile_websocket -webSocket ENABLED

add responder action res_act_http_redirect respondwith q{"HTTP/1.1 301 Moved Permanently\r\nLocation: https://" + HTTP.REQ.HOSTNAME.HTTP_URL_SAFE + "/\r\n\r\n"}
add responder policy res_pol_http_redirect true res_act_http_redirect

add cs vserver cs_EXCH_RDS-SSL SSL <IP ADRESSE DES CONTENT SWITCH VSERVERS> 443 -cltTimeout 180 -caseSensitive OFF -httpProfileName nshttp_profile_websocket
add cs vserver cs_EXCH_RDS-SSL_HTTP_redirect HTTP <IP ADRESSE DES CONTENT SWITCH VSERVERS> 80 -cltTimeout 180
add cs vserver cs_RDS-UDP UDP <IP ADRESSE DES CONTENT SWITCH VSERVERS> 3391 -cltTimeout 120

bind cs vserver cs_EXCH_RDS-SSL -policyName CS_POL_Exchange -targetLBVserver LB_VS_Exchange -priority 5
bind cs vserver cs_EXCH_RDS-SSL -policyName CS_POL_RDWeb-RDGW1 -targetLBVserver LB_VS_RDWeb-RDGW -priority 10
bind cs vserver cs_EXCH_RDS-SSL -policyName CS_POL_RDWeb-RDGW2 -targetLBVserver LB_VS_RDWeb-RDGW -priority 11
bind cs vserver cs_EXCH_RDS-SSL -policyName CS_POL_RDWeb-RDGW3 -targetLBVserver LB_VS_RDWeb-RDGW -priority 12
bind cs vserver cs_EXCH_RDS-SSL_HTTP_redirect -policyName res_pol_http_redirect -priority 100 -gotoPriorityExpression END -type REQUEST
bind cs vserver cs_RDS-UDP -lbvserver LB_VS_RDWeb-RDGW-UDP

set ssl vserver cs_EXCH_RDS-SSL -ssl3 DISABLED
bind ssl vserver cs_EXCH_RDS-SSL -certkeyName <NAME DES IMPORTIERTEN ZERTIFIKATES>

Damit wären wir in der Theorie auch schon fertig. An der Firewall müssten jetzt noch die Ports tcp 80, tcp 443 sowie udp 3391 auf die <IP ADRESSE DES CONTENT SWITCH VSERVERS> genatted werden. Falls es jemanden aufgefallen ist: Ich erstelle ein neues httpProfile und aktiviere dort webSocket. Warum? Ohne aktivierte Web Sockets im http Profil lässt sich von einem „normalen“ Client über die mstsc.exe oder auch über RDWeb problemlos eine Verbindung herstellen. Sollte es Macs oder Clients mit der Microsoft Remotedesktop App geben, so wird man feststellen, dass eine Verbindung über die „modernen“ Clients (Windows 10 mit o.g. App, macOS, iPhone, iPad) nicht zustande kommt, da diese über eine Web Socket Verbindung gehen.

Older Posts »

Powered by WordPress