Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
|
microsoft_exchange [2026/01/14 09:54] jango [Public Folder] |
microsoft_exchange [2026/02/27 09:40] (aktuell) jango [EMS] |
||
|---|---|---|---|
| Zeile 315: | Zeile 315: | ||
| ====Logs==== | ====Logs==== | ||
| + | |||
| + | Send und ReceiveLog | ||
| + | |||
| + | < | ||
| + | # Frontend Transport | ||
| + | C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd\ProtocolLog | ||
| + | # Hub Transport | ||
| + | C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\Hub\ProtocolLog | ||
| + | </ | ||
| Aufgaben kann man mit [[coding: | Aufgaben kann man mit [[coding: | ||
| Zeile 383: | Zeile 392: | ||
| <code powershell> | <code powershell> | ||
| # alle public folder | # alle public folder | ||
| - | get-publicfolder | + | Get-PublicFolder |
| + | # Nur Top-Level | ||
| + | Get-PublicFolder -ResultSize Unlimited -Recurse | select Name, | ||
| + | |||
| + | Add-PublicFolderClientPermission -Identity \My-Folder -User test.user -AccessRights Editor|Owner|Publisher | ||
| + | Get-PublicFolderClientPermission -Identity \My-Folder | ||
| + | Remove-PublicFolderClientPermission -Identity \My-Folder -User test.user | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | RunspaceId | ||
| + | Identity | ||
| + | Name : IPM_SUBTREE | ||
| + | MailEnabled | ||
| + | MailRecipientGuid | ||
| + | ParentPath | ||
| + | LostAndFoundFolderOriginalPath : | ||
| + | ContentMailboxName | ||
| + | ContentMailboxGuid | ||
| + | EformsLocaleId | ||
| + | PerUserReadStateEnabled | ||
| + | EntryId | ||
| + | DumpsterEntryId | ||
| + | ParentFolder | ||
| + | OrganizationId | ||
| + | AgeLimit | ||
| + | RetainDeletedItemsFor | ||
| + | ProhibitPostQuota | ||
| + | IssueWarningQuota | ||
| + | MaxItemSize | ||
| + | LastMovedTime | ||
| + | AdminFolderFlags | ||
| + | FolderSize | ||
| + | HasSubfolders | ||
| + | FolderClass | ||
| + | FolderPath | ||
| + | AssociatedDumpsterFolders | ||
| + | DefaultFolderType | ||
| + | ExtendedFolderFlags | ||
| + | MailboxOwnerId | ||
| + | IsValid | ||
| + | ObjectState | ||
| + | </ | ||
| + | |||
| + | bzw. | ||
| + | |||
| + | < | ||
| + | RunspaceId | ||
| + | Identity | ||
| + | Name : DUMMY-Newsletter | ||
| + | MailEnabled | ||
| + | MailRecipientGuid | ||
| + | ParentPath | ||
| + | LostAndFoundFolderOriginalPath : | ||
| + | ContentMailboxName | ||
| + | ContentMailboxGuid | ||
| + | EformsLocaleId | ||
| + | PerUserReadStateEnabled | ||
| + | EntryId | ||
| + | DumpsterEntryId | ||
| + | ParentFolder | ||
| + | OrganizationId | ||
| + | AgeLimit | ||
| + | RetainDeletedItemsFor | ||
| + | ProhibitPostQuota | ||
| + | IssueWarningQuota | ||
| + | MaxItemSize | ||
| + | LastMovedTime | ||
| + | AdminFolderFlags | ||
| + | FolderSize | ||
| + | HasSubfolders | ||
| + | FolderClass | ||
| + | FolderPath | ||
| + | AssociatedDumpsterFolders | ||
| + | DefaultFolderType | ||
| + | ExtendedFolderFlags | ||
| + | MailboxOwnerId | ||
| + | IsValid | ||
| + | ObjectState | ||
| + | </ | ||
| + | |||
| + | ===Test Script=== | ||
| + | |||
| + | <code powershell> | ||
| + | # EWS Config | ||
| + | $MailboxForAutodiscover = " | ||
| + | $UseDefaultCredentials | ||
| + | $EwsCred = Get-Credential | ||
| + | |||
| + | function Get-PublicFolderFolderClassEws { | ||
| + | param([Parameter(Mandatory)][string]$PfPath) | ||
| + | |||
| + | # DLL laden (Standardpfad; | ||
| + | $dll = " | ||
| + | if (-not (" | ||
| + | if (-not (Test-Path $dll)) { return $null } | ||
| + | Add-Type -Path $dll | ||
| + | } | ||
| + | |||
| + | $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService( | ||
| + | [Microsoft.Exchange.WebServices.Data.ExchangeVersion]:: | ||
| + | ) | ||
| + | |||
| + | if ($UseDefaultCredentials) { | ||
| + | $service.UseDefaultCredentials = $true | ||
| + | } else { | ||
| + | $service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials( | ||
| + | $EwsCred.UserName, | ||
| + | ) | ||
| + | } | ||
| + | |||
| + | $service.AutodiscoverUrl($MailboxForAutodiscover, | ||
| + | |||
| + | $current = [Microsoft.Exchange.WebServices.Data.Folder]:: | ||
| + | $service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]:: | ||
| + | ) | ||
| + | |||
| + | foreach ($seg in $PfPath.Trim(" | ||
| + | $view = New-Object Microsoft.Exchange.WebServices.Data.FolderView(100) | ||
| + | $filter = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo( | ||
| + | [Microsoft.Exchange.WebServices.Data.FolderSchema]:: | ||
| + | ) | ||
| + | $res = $service.FindFolders($current.Id, | ||
| + | if ($res.TotalCount -lt 1) { return $null } | ||
| + | $current = $res.Folders[0] | ||
| + | } | ||
| + | |||
| + | return $current.FolderClass | ||
| + | } | ||
| + | |||
| + | function Show-Subs { | ||
| + | param( | ||
| + | [Parameter(Mandatory)] $ParentEntryId, | ||
| + | [int] $Level = 1 | ||
| + | ) | ||
| + | |||
| + | $subs = Get-PublicFolder -ResultSize Unlimited -Recurse | Where-Object { $_.ParentFolder -eq $ParentEntryId } | ||
| + | |||
| + | foreach ($sub in $subs) { | ||
| + | |||
| + | $perms = Get-PublicFolderClientPermission -Identity $sub.Identity -ErrorAction SilentlyContinue | ||
| + | $owners = $perms | Where-Object { $_.AccessRights -contains " | ||
| + | if (-not $owners) { $owners = "< | ||
| + | $permString = ($perms | ForEach-Object { " | ||
| + | |||
| + | #Write-Host (" | ||
| + | Write-Host (" | ||
| + | Write-Host ("{0}- EntryId: {1}" -f (" | ||
| + | Write-Host ("{0}- ParentFolder: | ||
| + | |||
| + | Write-Host ("{0}- Owner(s): {1}" -f (" | ||
| + | Write-Host ("{0}- Permissions: | ||
| + | |||
| + | $addr = Get-MailPublicFolder -Identity $sub.Identity -ErrorAction SilentlyContinue | ||
| + | if ($addr -and $addr.PrimarySmtpAddress) { | ||
| + | Write-Host ("{0}- Address: {1}" -f (" | ||
| + | } else { | ||
| + | Write-Host ("{0}- Address: ---" -f (" | ||
| + | } | ||
| + | |||
| + | $type = Get-PublicFolderFolderClassEws -PfPath $sub.Identity | ||
| + | if (-not $type) { $type = "< | ||
| + | Write-Host ("{0}- Type: {1}" -f (" | ||
| + | |||
| + | Show-Subs -ParentEntryId $sub.EntryId -Level ($Level + 1) | ||
| + | |||
| + | } | ||
| + | } | ||
| + | |||
| + | Get-PublicFolder -ResultSize Unlimited -Recurse | Where-Object { $_.ParentPath -eq " | ||
| + | | ||
| + | $curr = $_ | ||
| + | | ||
| + | $perms = Get-PublicFolderClientPermission -Identity $curr.Identity -ErrorAction SilentlyContinue | ||
| + | $owners = $perms | Where-Object { $_.AccessRights -contains " | ||
| + | if (-not $owners) { $owners = "< | ||
| + | $permString = ($perms | ForEach-Object { " | ||
| + | |||
| + | #Write-Host " | ||
| + | Write-Host " | ||
| + | Write-Host "`t- EntryId: $($curr.EntryId)" | ||
| + | Write-Host "`t- ParentFolder: | ||
| + | Write-Host ("`t- Owner(s): {0}" -f ($owners -join ', ')) | ||
| + | Write-Host ("`t- Permissions: | ||
| + | |||
| + | try { | ||
| + | $addr = Get-MailPublicFolder -Identity $curr.Identity -ErrorAction SilentlyContinue | ||
| + | if ($addr -and $addr.PrimarySmtpAddress) { | ||
| + | Write-Host ("`t- Address: {0}" -f ($addr.PrimarySmtpAddress)) | ||
| + | } else { | ||
| + | Write-Host ("`t- Address: ---") | ||
| + | } | ||
| + | } catch {} | ||
| + | |||
| + | $type = Get-PublicFolderFolderClassEws -PfPath $curr.Identity | ||
| + | if (-not $type) { $type = "< | ||
| + | Write-Host ("`t- Type: {0}" -f $type) | ||
| + | |||
| + | Show-Subs -ParentEntryId $curr.EntryId -Level 1 | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | ====Mail enabled==== | ||
| + | |||
| + | <code powershell> | ||
| # nur mailaktivierte öffentliche Ordner | # nur mailaktivierte öffentliche Ordner | ||
| - | get-mailpublicfolder | + | Get-MailPublicFolder |
| + | </ | ||
| - | Get-MailPublicFolder | + | < |
| + | RunspaceId | ||
| + | Contacts | ||
| + | ContentMailbox | ||
| + | DeliverToMailboxAndForward | ||
| + | ExternalEmailAddress | ||
| + | EntryId | ||
| + | OnPremisesObjectId | ||
| + | IgnoreMissingFolderLink | ||
| + | ForwardingAddress | ||
| + | PhoneticDisplayName | ||
| + | AcceptMessagesOnlyFrom | ||
| + | AcceptMessagesOnlyFromDLMembers | ||
| + | AcceptMessagesOnlyFromSendersOrMembers : {} | ||
| + | AddressListMembership | ||
| + | AdministrativeUnits | ||
| + | Alias : EventConfig_NOTES1 | ||
| + | ArbitrationMailbox | ||
| + | BypassModerationFromSendersOrMembers | ||
| + | OrganizationalUnit | ||
| + | CustomAttribute1 | ||
| + | CustomAttribute10 | ||
| + | CustomAttribute11 | ||
| + | CustomAttribute12 | ||
| + | CustomAttribute13 | ||
| + | CustomAttribute14 | ||
| + | CustomAttribute15 | ||
| + | CustomAttribute2 | ||
| + | CustomAttribute3 | ||
| + | CustomAttribute4 | ||
| + | CustomAttribute5 | ||
| + | CustomAttribute6 | ||
| + | CustomAttribute7 | ||
| + | CustomAttribute8 | ||
| + | CustomAttribute9 | ||
| + | ExtensionCustomAttribute1 | ||
| + | ExtensionCustomAttribute2 | ||
| + | ExtensionCustomAttribute3 | ||
| + | ExtensionCustomAttribute4 | ||
| + | ExtensionCustomAttribute5 | ||
| + | DisplayName | ||
| + | EmailAddresses | ||
| + | ; | ||
| + | GrantSendOnBehalfTo | ||
| + | ExternalDirectoryObjectId | ||
| + | HiddenFromAddressListsEnabled | ||
| + | LastExchangeChangedTime | ||
| + | LegacyExchangeDN | ||
| + | MaxSendSize | ||
| + | MaxReceiveSize | ||
| + | ModeratedBy | ||
| + | ModerationEnabled | ||
| + | PoliciesIncluded | ||
| + | PoliciesExcluded | ||
| + | EmailAddressPolicyEnabled | ||
| + | PrimarySmtpAddress | ||
| + | RecipientType | ||
| + | RecipientTypeDetails | ||
| + | RejectMessagesFrom | ||
| + | RejectMessagesFromDLMembers | ||
| + | RejectMessagesFromSendersOrMembers | ||
| + | RequireSenderAuthenticationEnabled | ||
| + | SimpleDisplayName | ||
| + | SendModerationNotifications | ||
| + | UMDtmfMap | ||
| + | WindowsEmailAddress | ||
| + | MailTip | ||
| + | MailTipTranslations | ||
| + | Identity | ||
| + | IsValid | ||
| + | ExchangeVersion | ||
| + | Name : EventConfig_NOTES1 | ||
| + | DistinguishedName | ||
| + | Guid : 3845b437-d154-47ac-b6bf-f3f0b5dedb4b | ||
| + | ObjectCategory | ||
| + | ObjectClass | ||
| + | WhenChanged | ||
| + | WhenCreated | ||
| + | WhenChangedUTC | ||
| + | WhenCreatedUTC | ||
| + | OrganizationId | ||
| + | Id : d2000.local/ | ||
| + | OriginatingServer | ||
| + | ObjectState | ||
| </ | </ | ||
| + | |||
| + | =====OWA Proxy===== | ||
| + | |||
| + | <code python> | ||
| + | import os | ||
| + | import re | ||
| + | import logging | ||
| + | from urllib.parse import urljoin, urlparse | ||
| + | |||
| + | import httpx | ||
| + | from flask import Flask, request, redirect, make_response, | ||
| + | |||
| + | from ldap3 import Server, Connection, ALL, SIMPLE | ||
| + | from ldap3.core.exceptions import LDAPException | ||
| + | |||
| + | from logging.handlers import RotatingFileHandler | ||
| + | |||
| + | EXCHANGE_BASE = " | ||
| + | ALLOWED_PREFIXES = ("/ | ||
| + | LDAP_HOST = " | ||
| + | LDAP_PORT = 636 | ||
| + | LDAP_USE_SSL = True | ||
| + | UPN_SUFFIX = " | ||
| + | |||
| + | app = Flask(__name__) | ||
| + | app.secret_key = os.urandom(32) | ||
| + | |||
| + | app.config.update( | ||
| + | SESSION_COOKIE_HTTPONLY = True, # damit JS das session cookie nicht auslesen kann | ||
| + | SESSION_COOKIE_SECURE = True, # session cookie NUR bei HTTPS setzen! | ||
| + | SESSION_COOKIE_SAMESITE = " | ||
| + | ) | ||
| + | |||
| + | LOG_DIR = " | ||
| + | LOG_FILE = os.path.join(LOG_DIR, | ||
| + | |||
| + | os.makedirs(LOG_DIR, | ||
| + | |||
| + | LOG_FORMAT = ( | ||
| + | " | ||
| + | " | ||
| + | ) | ||
| + | |||
| + | def setup_logging(app: | ||
| + | # Root logger (greift auch fur viele Library-Logs) | ||
| + | root = logging.getLogger() | ||
| + | root.setLevel(logging.INFO) | ||
| + | |||
| + | formatter = logging.Formatter(LOG_FORMAT) | ||
| + | |||
| + | # File logging mit Rotation: 10 MB pro File, 10 Backups | ||
| + | file_handler = RotatingFileHandler( | ||
| + | LOG_FILE, maxBytes=10 * 1024 * 1024, backupCount=10, | ||
| + | ) | ||
| + | file_handler.setLevel(logging.INFO) | ||
| + | file_handler.setFormatter(formatter) | ||
| + | |||
| + | # Optional: weiterhin Konsole (systemd/ | ||
| + | stream_handler = logging.StreamHandler() | ||
| + | stream_handler.setLevel(logging.INFO) | ||
| + | stream_handler.setFormatter(formatter) | ||
| + | |||
| + | # Doppelte Handler verhindern (wichtig bei Reload / Import) | ||
| + | def _dedupe(logger: | ||
| + | keep = [] | ||
| + | for h in logger.handlers: | ||
| + | # behalten, wenn gleicher Typ/Target | ||
| + | keep.append(h) | ||
| + | logger.handlers = keep | ||
| + | |||
| + | # Root: einmal sauber setzen | ||
| + | root.handlers.clear() | ||
| + | root.addHandler(file_handler) | ||
| + | root.addHandler(stream_handler) | ||
| + | |||
| + | # Flask app.logger nutzt teilweise eigene Handler: auf Root " | ||
| + | app.logger.handlers.clear() | ||
| + | app.logger.propagate = True | ||
| + | app.logger.setLevel(logging.INFO) | ||
| + | |||
| + | # Werkzeug (HTTP request logs) ebenfalls in Datei | ||
| + | werkzeug_logger = logging.getLogger(" | ||
| + | werkzeug_logger.setLevel(logging.INFO) | ||
| + | werkzeug_logger.propagate = True | ||
| + | |||
| + | # | ||
| + | # | ||
| + | setup_logging(app) | ||
| + | |||
| + | # keep-alive/ | ||
| + | HTTP = httpx.Client( | ||
| + | verify=True, | ||
| + | timeout=60.0, | ||
| + | follow_redirects=False, | ||
| + | headers={" | ||
| + | ) | ||
| + | |||
| + | LOGIN_PAGE = """ | ||
| + | < | ||
| + | <html lang=" | ||
| + | < | ||
| + | <meta charset=" | ||
| + | <meta name=" | ||
| + | < | ||
| + | < | ||
| + | body { font-family: | ||
| + | .card { border: 1px solid #ddd; border-radius: | ||
| + | |||
| + | form { display: grid; gap: 10px; } | ||
| + | |||
| + | label { margin: 0; font-weight: | ||
| + | input { | ||
| + | width: 100%; | ||
| + | padding: 10px; | ||
| + | border-radius: | ||
| + | border: 1px solid #ccc; | ||
| + | box-sizing: border-box; | ||
| + | margin: 0; | ||
| + | } | ||
| + | |||
| + | button { margin-top: 6px; width: 100%; padding: 10px; border-radius: | ||
| + | .err { color: #b00020; margin-top: 6px; } | ||
| + | small { color:#666; margin-top: 8px; display: | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <div class=" | ||
| + | < | ||
| + | < | ||
| + | <form method=" | ||
| + | <input type=" | ||
| + | < | ||
| + | <input name=" | ||
| + | < | ||
| + | <input name=" | ||
| + | <button type=" | ||
| + | {% if error %}<div class=" | ||
| + | < | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | """ | ||
| + | |||
| + | # in memory creds (single process only) | ||
| + | # session darf NUR die SID und KEIN passwort enthalten!!! | ||
| + | _CREDS = {} | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | def is_allowed_path(path: | ||
| + | return any(path.startswith(p) for p in ALLOWED_PREFIXES) | ||
| + | |||
| + | def to_upn(user_input: | ||
| + | u = (user_input or "" | ||
| + | if " | ||
| + | u = u.split(" | ||
| + | if " | ||
| + | u = f" | ||
| + | return u | ||
| + | |||
| + | # simple bind mit UPN des benutzer | ||
| + | def ldap_check(username: | ||
| + | server = Server(LDAP_HOST, | ||
| + | upn = to_upn(username) | ||
| + | try: | ||
| + | conn = Connection( | ||
| + | server, | ||
| + | user=upn, | ||
| + | password=password, | ||
| + | authentication=SIMPLE, | ||
| + | auto_bind=True, | ||
| + | ) | ||
| + | conn.unbind() | ||
| + | app.logger.info(" | ||
| + | return True | ||
| + | except LDAPException as e: | ||
| + | app.logger.warning(" | ||
| + | return False | ||
| + | except Exception: | ||
| + | app.logger.exception(" | ||
| + | return False | ||
| + | |||
| + | def rewrite_location(location: | ||
| + | if not location: | ||
| + | return location | ||
| + | try: | ||
| + | parsed = urlparse(location) | ||
| + | if parsed.scheme and parsed.netloc: | ||
| + | backend_origin = f" | ||
| + | if location.startswith(backend_origin): | ||
| + | return location.replace(backend_origin, | ||
| + | return location | ||
| + | except Exception: | ||
| + | return location | ||
| + | |||
| + | def get_creds(): | ||
| + | sid = session.get(" | ||
| + | if not sid: | ||
| + | return None | ||
| + | return _CREDS.get(sid) | ||
| + | |||
| + | # vor JEDER anfrage den pfad testen - ZERO TRUST! | ||
| + | # "/ | ||
| + | # "/" | ||
| + | # ohne creds -> redirect auf "/ | ||
| + | @app.before_request | ||
| + | def guard(): | ||
| + | if request.path.startswith("/ | ||
| + | return None | ||
| + | if request.path == "/" | ||
| + | return redirect("/ | ||
| + | if not is_allowed_path(request.path): | ||
| + | return ("Not Found", | ||
| + | if not get_creds(): | ||
| + | return redirect(url_for(" | ||
| + | |||
| + | def get_client_ip() -> str: | ||
| + | xff = request.headers.get(" | ||
| + | if xff: | ||
| + | return xff.split("," | ||
| + | return request.remote_addr or "" | ||
| + | |||
| + | def get_ua() -> str: | ||
| + | return request.headers.get(" | ||
| + | |||
| + | @app.route("/ | ||
| + | def login(): | ||
| + | next_url = request.values.get(" | ||
| + | if request.method == " | ||
| + | return render_template_string(LOGIN_PAGE, | ||
| + | username = request.form.get(" | ||
| + | password = request.form.get(" | ||
| + | ip = get_client_ip() | ||
| + | ua = get_ua() | ||
| + | upn = to_upn(username) | ||
| + | app.logger.info(" | ||
| + | if not username or not password: | ||
| + | return render_template_string(LOGIN_PAGE, | ||
| + | if not ldap_check(username, | ||
| + | return render_template_string(LOGIN_PAGE, | ||
| + | sid = os.urandom(16).hex() | ||
| + | session[" | ||
| + | _CREDS[sid] = (username, password) | ||
| + | return redirect(next_url) | ||
| + | |||
| + | @app.route("/ | ||
| + | def logout(): | ||
| + | sid = session.pop(" | ||
| + | if sid: | ||
| + | _CREDS.pop(sid, | ||
| + | return redirect("/ | ||
| + | |||
| + | @app.route("/", | ||
| + | @app.route("/< | ||
| + | def proxy(anypath: | ||
| + | creds = get_creds() | ||
| + | if not creds: | ||
| + | return redirect(url_for(" | ||
| + | username, password = creds | ||
| + | basic_user = to_upn(username) | ||
| + | target_path = "/" | ||
| + | backend_url = urljoin(EXCHANGE_BASE.rstrip("/" | ||
| + | hop_by_hop = { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | headers = {k: v for k, v in request.headers.items() if k.lower() not in hop_by_hop} | ||
| + | headers.pop(" | ||
| + | headers[" | ||
| + | headers[" | ||
| + | data = request.get_data() if request.method in (" | ||
| + | public_origin = f" | ||
| + | try: | ||
| + | # backend request mit BASIC AUTH | ||
| + | resp = HTTP.request( | ||
| + | method=request.method, | ||
| + | url=backend_url, | ||
| + | params=request.args, | ||
| + | headers=headers, | ||
| + | content=data, | ||
| + | auth=(basic_user, | ||
| + | ) | ||
| + | except httpx.RequestError as e: | ||
| + | app.logger.error(" | ||
| + | return (" | ||
| + | if resp.status_code == 401: | ||
| + | app.logger.warning( | ||
| + | "401 from Exchange url=%s basic_user=%s WWW-Authenticate=%s", | ||
| + | backend_url, | ||
| + | ) | ||
| + | if resp.status_code >= 500 and "/ | ||
| + | app.logger.warning(" | ||
| + | out = make_response(resp.content, | ||
| + | excluded = {" | ||
| + | for k, v in resp.headers.items(): | ||
| + | if k.lower() in excluded: | ||
| + | continue | ||
| + | out.headers[k] = v | ||
| + | if " | ||
| + | out.headers[" | ||
| + | set_cookies = resp.headers.get_list(" | ||
| + | if not set_cookies and " | ||
| + | set_cookies = [resp.headers[" | ||
| + | for c in set_cookies: | ||
| + | fixed = re.sub(r"; | ||
| + | out.headers.add(" | ||
| + | return out | ||
| + | |||
| + | mysslcontext = (' | ||
| + | |||
| + | if __name__ == " | ||
| + | # | ||
| + | app.run(host=" | ||
| + | </ | ||
| + | |||
| + | ====IIS Website==== | ||
| + | |||
| + | <code powershell> | ||
| + | Import-Module WebAdministration | ||
| + | |||
| + | New-Item -Path " | ||
| + | New-Website -Name " | ||
| + | New-WebBinding -Name " | ||
| + | |||
| + | Get-ExchangeCertificate | ft Thumbprint, | ||
| + | $thumb = " | ||
| + | |||
| + | # falls schon mal was auf 4443 hängt, vorher löschen: | ||
| + | # netsh http delete sslcert ipport=0.0.0.0: | ||
| + | |||
| + | netsh http add sslcert ipport=0.0.0.0: | ||
| + | |||
| + | New-OwaVirtualDirectory -WebSiteName " | ||
| + | |||
| + | Set-OwaVirtualDirectory " | ||
| + | |||
| + | iisreset | ||
| + | </ | ||
| + | =====EMS===== | ||
| + | |||
| + | < | ||
| + | Get-ReceiveConnector | ft name, | ||
| + | Get-SendConnector | ft name, | ||
| + | Get-TransportConfig | fl MaxReceiveSize, | ||
| + | Get-Mailbox | ft Name, | ||
| + | |||
| + | Get-OwaVirtualDirectory | Select Name, | ||
| + | Set-OwaVirtualDirectory -Identity " | ||
| + | Set-OwaVirtualDirectory " | ||
| + | </ | ||
| + | |||
| =====Links===== | =====Links===== | ||