====== Microsoft Exchange ====== ===== Ящики ===== # Посмотреть, кто имеет доступ к ящику username Get-MailboxPermission username | ft user,accessrights -AutoSize # Посмотреть доступ для учётки к ящикам get-mailbox | Get-MailboxPermission -User Username -ResultSize Unlimited | ft Identity,AccessRights -AutoSize # Вывести список ящиков, в которые имеет доступ учетка Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission -User S-1-5-21-606747145-1343024091-1708537768-16143 | ft -wrap # Удалить учетку с правами FullAccess изо всех ящиков Get-Mailbox -ResultSize Unlimited | Remove-MailboxPermission -User S-1-5-21-606747145-1343024091-1708537768-16143 -AccessRights FullAccess -Confirm:$False # Проверить ящик на ошибки (можно и базу), без исправления (-DetectOnly) New-MailboxRepairRequest –Mailbox user7@domain28.lab –CorruptionType SearchFolder, AggregateCounts, ProvisionedFolder, FolderView -DetectOnly # Проверить статус проверки ящика Get-MailboxRepairRequest –Mailbox user7@domain28.lab ==== Фильтр csv-отчёта и выгрузка ящиков ==== $t = get-date -Format yyyy-MM dir "$env:USERPROFILE\desktop\$t-*.csv" -OutVariable f $f = import-csv $f -Delimiter ";" | where -Property "Рекомендован к отключению" -eq "рекомендован, аккаунт отключен" | select -ExpandProperty Команда $fname = "$env:USERPROFILE\desktop\$t-filtered.txt" # примерный результат работы фильтра #New-MailboxExportRequest -Mailbox "userone@domain.ru" -FilePath "\\domain.ru\main\backups\filesarchive\PST\auto-export\userone20190521-1204.pst" #New-MailboxExportRequest -Mailbox "usertwo@domain.ru" -FilePath "\\domain.ru\main\backups\filesarchive\PST\auto-export\usertwo20190521-1224.pst" #New-MailboxExportRequest -Mailbox "userthree@domain.ru" -FilePath "\\domain.ru\main\backups\filesarchive\PST\auto-export\userthree20190521-1505.pst" echo ' # Загрузить модуль Exchange Import-Module "$env:ExchangeInstallPath\Bin\RemoteExchange.ps1" Connect-ExchangeServer -auto'`n | Out-File $fname $f | Out-File -Append $fname echo ' # Вывести список экспортируемых ящиков Get-MailboxExportRequest | select Mailbox,Status | fl # Возобновить экспорт ящиков, закончившихся неудачей Get-MailboxExportRequest -Status Failed | Resume-MailboxExportRequest # Очистить очередь на экспорт, добавив информацию в файл Get-MailboxExportRequest -Status Completed | %{$_| fl | out-file "\\minprom.gov.ru\main\backups\filesarchive\PST\auto-export\log.txt" -append; Disable-Mailbox $_.Mailbox -Confirm:$false; Remove-MailboxExportRequest -Identity $_ -Confirm:$false}' | Out-File -Append $fname Invoke-Item $fname ==== При сбое выгрузки ящика ==== # Отчёт по сбойному запросу выгрузки Get-MailboxExportRequest -Status Failed |Get-MailboxExportRequestStatistics -IncludeReport |fl > c:\temp\usernameExport-report.txt # Подкрутить параметры запроса Get-MailboxExportRequest -Status Failed |Set-MailboxExportRequest -BadItemLimit 9999 -AcceptLargeDataLoss # Продолжить запрос Get-MailboxExportRequest -Status Failed |Resume-MailboxExportRequest https://www.stellarinfo.com/article/new-mailboxexportrequest-failed.php ==== Запрет группы отправителей ==== # Сделать группу New-DistributionGroup -Name senders.banned -OrganizationalUnit "domain.ru/Почта/Списки рассылок" -SamAccountName senders.banned -Type "Security" # Скрыть из адресной книги Set-DistributionGroup senders.banned -HiddenFromAddressListsEnabled $True # Внести в список запрещённых отправителей ящика Set-Mailbox i.petrov -RejectMessagesFromDLMembers (Get-DistributionGroup senders.banned) Затем нужно добавить отправителей в группу. В ящиках есть 3 параметра, касающихся запрета на получение: * RejectMessagesFrom - только единичные пользователи * RejectMessagesFromDLMembers - группы * RejectMessagesFromSendersOrMembers - сюда автоматически копируется всё из предыдущих параметров # Получить список всех запрещённых отправителей (Get-Mailbox i.petrov).RejectMessagesFromSendersOrMembers |select name ==== Удаление адресов X400 ==== # Предварительный отчёт для ящиков $allmailboxes = get-mailbox -ResultSize Unlimited $report = @() foreach ($mbx in $allmailboxes) { $smtpaddr,$x400addr = ($mbx.emailaddresses).where({$_ -notmatch "x400:"}, 'split') $str = [pscustomobject]@{ Name = $mbx.name Alias = $mbx.alias SMTP = $smtpaddr -join "`n" X400 = ($x400addr -join "`n").ToString() } $report += $str } $report |sort name |Export-Csv "c:\temp\MailboxesX400report.csv" -Delimiter ';' -NoTypeInformation -Encoding UTF8 # Удалить адреса X400 из ящиков foreach ($mbx in (get-mailbox -ResultSize Unlimited)) { $smtpaddr = ($mbx.emailaddresses).where{$_ -notmatch "x400:"} set-mailbox $mbx.Identity -emailaddresses $smtpaddr } # Удалить адреса X400 из групп рассылки foreach ($dg in (Get-DistributionGroup -ResultSize Unlimited)) { $smtpaddr = ($dg.emailaddresses).where{$_ -notmatch "x400:"} set-DistributionGroup $dg.Identity -emailaddresses $smtpaddr } ==== Управление адресами ==== # Добавить адрес к ящику set-mailbox ivanov -EmailAddresses @{add="sidorov@example.com"} # Удалить пользователя из прав на отправку в группе рассылки (пользователь не существует в AD) Remove-ADPermission DG-marketing -User "S-1-5-21-1482476501-1004336348-839522115-5731" -Extendedrights "Send As" -Confirm:$false ==== PST ==== Подключить в Outlook Add-type -assembly "Microsoft.Office.Interop.Outlook" > $null $outlook = new-object -comobject outlook.application $namespace = $outlook.GetNameSpace("MAPI") dir "$env:userprofile\Documents\Файлы Outlook\*.pst" |% {$namespace.AddStore($_.FullName)} ===== Права ===== # Убрать права юзера на ящик get-mailboxpermission -identity mailboxowner -user user | remove-mailboxpermission # Выдать полные права на календарь (-AccessRights Reviewer - чтение) Add-MailboxFolderPermission -Identity mailboxowner:\Календарь -User user -AccessRights Owner # Дать права Full Access группе на ящик Add-MailboxPermission "mailboxName" -User "groupName" -AccessRights "FullAccess" # дать права группе на отправку от имени ящика get-mailbox "mailboxName" |Add-ADPermission -User "groupName" -ExtendedRights "Send As" ===== Календари ===== # Посмотреть доступ для учётки Username к каким-либо календарям ForEach ($mbx in Get-Mailbox -ResultSize Unlimited) {Get-MailboxFolderPermission ($mbx.Name + ":\Календарь") | Where-Object {$_.User -like "Username"} | Select @{Name="Calendar Of";expression={($mbx.name)}},User,AccessRights} # Посмотреть, кто имеет к календарю учётки Username Get-MailboxFolderPermission Username:\Календарь | ft user,accessrights -AutoSize # Выгрузить список пользователей, имеющих права на календарь # с нестандартным именем "Общий календарь" Get-MailboxFolderPermission "Username:\Название учётки - Общий календарь" | select User,AccessRights | sort User | Out-File -Encoding UTF8 $env:userprofile\desktop\username-cal-users.txt ===== Письма ===== # Удалить из всех ящиков письмо с определённой темой за определённый день, от определённого адреса и где нет вложений .xlsx Get-Mailbox -ResultSize unlimited |Search-Mailbox -SearchQuery ` 'Subject:"Вниманию руководителей структурных подразделений" AND Received:"16.11.2022" AND from:"pr@example.com" NOT Attachment:"*.xlsx"' ` -DeleteContent -Force # Найти письма в ящике и скопировать результаты в другой ящик Search-Mailbox username -SearchQuery 'from:"someone@domain.ru" AND sent:"07.04.2020"' -TargetMailbox admin -TargetFolder "SearchQueries" # Удалить письмо из ящика пользователя search-mailbox username -SearchQuery 'from:"someone" AND subject:"Табель за апрель, 1-я половина" AND sent:"07.04.2020"' -DeleteContent -Force # Поиск письма в транспортных журналах (RecipientStatus - причина отлупа) Get-MessageTrackingLog -Sender "sender@domain.ru" |select RecipientStatus $mbx = Get-Mailbox -ResultSize unlimited # Найти, у кого есть письмо с определённой темой $mbx | Search-Mailbox -SearchQuery 'subject:"Объяснительная Вселенная унитазов"' -EstimateResultOnly |? ResultItemsCount -ne 0 RunspaceId : 12345678-1234-1234-1234-123456789012 Identity : domain.ru/Kontora/1_Users/Горчакова Мариэтта Петровна TargetMailbox : Success : True TargetFolder : ResultItemsCount : 1 ResultItemsSize : 36.08 KB (36,948 bytes) RunspaceId : 12345678-1234-1234-1234-123456789013 Identity : domain.ru/Kontora/1_Users/Саруманов Сергей Викторович TargetMailbox : Success : True TargetFolder : ResultItemsCount : 1 ResultItemsSize : 44.68 KB (45,749 bytes) A space between two keywords or two //property:value// expressions is the same as using **AND.** For example, //%%from:"Sara Davis" subject:reorganization%%// returns all messages sent by Sara Davis that contain the word **reorganization** in the subject line.\\ [[https://learn.microsoft.com/en-us/powershell/module/exchange/search-mailbox?view=exchange-ps|Search-Mailbox]]\\ [[https://docs.microsoft.com/en-US/exchange/security-and-compliance/in-place-ediscovery/message-properties-and-search-operators|Свойства и операторы поиска]] ===== Переадресация ===== # Установить переадресацию Set-Mailbox "Выскина Анна Алексеевна" -ForwardingAddress "Розова Виктория Викторовна" # Переадресация с одновременным хранением в первоначальном ящике Set-Mailbox "Выскина Анна Алексеевна" -DeliverToMailboxAndForward $true -ForwardingAddress "Розова Виктория Викторовна" # Заполнить обоснование в AD (В поле "Почтовый ящик") Set-ADUser (Get-ADUser -filter "name -eq 'Выскина Анна Алексеевна'" -Properties postOfficeBox) -replace @{postOfficeBox="СЗ №07/1 - 1234 от 13.05.2021"} -Confirm:$false # Занести в переменную адреса ящика $addr = (Get-ADUser -filter "name -eq 'Киренко Петр Александрович'" -Properties proxyaddresses).proxyaddresses -replace "^smtp:" # Добавить эти адреса другому ящику (делать только после удаления исходного) Set-Mailbox "Гончарова Маргарита Борисовна" -EmailAddresses @{add=$addr} # Убрать ВСЕ переадресации с ящика и убрать обоснование в поле "Почтовый ящик" в AD $user = "Копач Олег Сергеевич" Set-Mailbox $user -DeliverToMailboxAndForward $false -ForwardingSMTPAddress $null -ForwardingAddress $null Set-ADUser (Get-ADUser -filter "name -eq `'$user`'" -Properties postOfficeBox) -clear 'postOfficeBox' -Confirm:$false Есть 2 типа переадресации: - ForwardingAddress – Задаётся администратором, у пользователя нет доступа к этой настройке. - ForwardingSMTPAddress – Пользователь может задать эту переадресацию в Outlook web access (OWA) # Убрать все переадресации в ящике Set-Mailbox paulie -ForwardingAddress $NULL -ForwardingSmtpAddress $NULL https://learn.microsoft.com/en-us/exchange/recipients/user-mailboxes/email-addresses\\ https://learn.microsoft.com/en-us/exchange/recipients/user-mailboxes/email-forwarding\\ https://www.tachytelic.net/2019/06/remove-forwarding-office-365-powershell ===== Группы рассылки ===== Динамическая группа рассылки, получатели берутся из OU=Company,DC=domain,DC=ru, слать на неё разрешено только группе MailRights-DDG-allstaff-sendto. Из списка рассылки исключен генеральный директор и его заместители. # Группа с правами на отправку New-DistributionGroup -Name "MailRights-DDG-allstaff-sendto" -OrganizationalUnit "OU=Mail,DC=domain,DC=ru" -SamAccountName "MailRights-DDG-allstaff-sendto" -Type "Security" Set-DistributionGroup MailRights-DDG-allstaff-sendto -HiddenFromAddressListsEnabled $true # Сама группа рассылки New-DynamicDistributionGroup -Name "DDG-allstaff" -Alias "allstaff" -DisplayName "Все сотрудники" -RecipientContainer "OU=Company,DC=domain,DC=ru" ` -OrganizationalUnit "OU=Mail,DC=domain,DC=ru" -RecipientFilter {title -notlike "*Заместитель Генерального директора*" -and title -ne "Генеральный директор"} # Оставшиеся параметры Set-DynamicDistributionGroup -Identity "DDG-allstaff" -AcceptMessagesOnlyFromDLMembers "MailRights-DDG-allstaff-sendto" -Notes "Все, кроме ГД и заместителей" Фильтр получателей с исключением, например, когда нужно исключить всех замов, но одного включить. Set-DistributionGroup DDG-allstaff -RecipientFilter { (title -notlike "*Заместитель Генерального директора*" -and title -ne "Генеральный директор") -or ` (name -eq "Рассылкин Иван Иванович") } ==== Список членов динамической группы рассылки ==== $ddg = Get-DynamicDistributionGroup -Identity "DDG-allstaff" Get-Recipient -RecipientPreviewFilter $ddg.RecipientFilter -OrganizationalUnit $ddg.RecipientContainer # Тестирование работы фильтра Get-Recipient -RecipientPreviewFilter {title -ne 'Генеральный директор'} |? name -match "Иванов" ==== Добавить пользователя в статическую группу рассылки ==== Add-DistributionGroupMember -Identity group -Member ivanovii -BypassSecurityGroupManagerCheck ==== Включить возможность слать извне на группу рассылки ==== Set-DistributionGroup -Identity group -RequireSenderAuthenticationEnabled $false ===== Настройка сервера ===== $server = "srv-mbx01" # Информация о лицензии Get-ExchangeServer $server | fl Name,Edition,*Trial* # Ввести ключ Set-ExchangeServer $server -ProductKey 12345-12345-12345-12345-12345 # Просмотр настройки фильтров на Edge (сама настройка - Set-) Get-ContentFilterConfig Get-RecipientFilterConfig Get-SenderFilterConfig # Content filter приходится выключать, т. к. слишком часто отбрасывает нужные письма. Get-ContentFilterConfig -SCLRejectEnabled $false -SCLDeleteEnabled $false -SCLQuarantineEnabled $false # Либо настраивать какой-нибудь ящик как карантинный, но потом возиться с письмами, которые туда попадают. # Письма от user@sender.ru и user@sender2.ru - ошибка "451 4.3.2 System not accepting network messages - Content Filter Agent" # На Edge: Set-ContentFilterConfig –BypassedSenderDomains @{Add="sender.ru", "sender2.ru"} # Если нужно убрать адреса из списка Set-ContentFilterConfig –BypassedSenderDomains @{Remove="sender.ru", "sender2.ru"} ===== Коннекторы ===== # Посмотреть FQDN и ограничения на размер сообщений Get-SendConnector |select identity,fqdn,maxmessagesize Get-ReceiveConnector |select identity,fqdn,maxmessagesize # Задать ограничение в 30 МБ для сообщений Get-SendConnector |% {Set-SendConnector $_ -MaxMessageSize 30MB} Get-ReceiveConnector |% {Set-ReceiveConnector $_ -MaxMessageSize 30MB} ===== Пересоздание подписки на Edge ===== Проверка Test-EdgeSynchronization |select name,syncstatus,FailureDetail,@{n="LastSync";e={($_.LastSynchronizedUtc).addhours(3)}} Name SyncStatus FailureDetail LastSync ---- ---------- ------------- -------- srv-edge2 Normal 31.01.2023 15:55:13 # удалить подписку на Edge и на транспорте get-edgesubscription | remove-edgesubscription # сформировать файл на Edge New-EdgeSubscription -FileName c:\temp\ES.xml # скопировать файл с Edge на Транспорт # на транспорте создаем подписку New-EdgeSubscription -FileData ([byte[]]$(Get-Content -Path "c:\temp\ES.xml" -Encoding Byte -ReadCount 0)) -Site "Default-First-Site-Name" # Установить максимальный размер отправляемых сообщений на 30Mb Get-SendConnector |% {Set-SendConnector $_ -MaxMessageSize 30MB} # Задать FQDN как edge.domain.ru Get-SendConnector |? name -match '^EdgeSync' |Set-SendConnector -Fqdn 'edge.domain.ru' # Синхронизировать изменения Start-EdgeSynchronization # Тест Test-EdgeSynchronization ===== Замена SSL-сертификатов ===== # Import-Module "$env:ExchangeInstallPath\Bin\RemoteExchange.ps1" # Connect-ExchangeServer -auto $mailServers = (Get-ExchangeServer |? IsMailboxServer).name $certFile = "\\domain.ru\fs\share\cert\2022\cert.pfx" $certPass = Read-Host "Введите пароль сертификата" # Импорт $mailServers |% { Import-ExchangeCertificate -Server $_ -FileName $certFile -Password (ConvertTo-SecureString -String "$certPass" -AsPlainText -Force) } # Включить новый сертификат для служб Get-ExchangeCertificate # выяснить Thumbprint нового и старого сертификата для следующих команд $thumbprintNew = "A9B662C98263911226A81EC5BA4AFCA958A237BC" $thumbprintOld = "D1C6ED2B39A19BFEF0216B94E2D74E77B044F7B4" $mailServers |% { Enable-ExchangeCertificate -Thumbprint $thumbprintNew -Services IIS,SMTP -Server $_ -DoNotRequireSsl } # Удалить старый $mailServers |% { Remove-ExchangeCertificate -Thumbprint $thumbprintOld -Server $_ } ### На Edge - скопировать сертификат в c:\temp\cert.pfx ### $certFile = "c:\temp\cert.pfx" $certPass = Read-Host "Введите пароль сертификата" Import-ExchangeCertificate -FileName $certFile -Password (ConvertTo-SecureString -String "$certPass" -AsPlainText -Force) Get-ExchangeCertificate $thumbprintNew = "A9B662C98263911226A81EC5BA4AFCA958A237BC" $thumbprintOld = "D1C6ED2B39A19BFEF0216B94E2D74E77B044F7B4" Enable-ExchangeCertificate -Thumbprint $thumbprintNew -Services SMTP Remove-ExchangeCertificate -Thumbprint $thumbprintOld https://docs.microsoft.com/en-us/powershell/module/exchange/import-exchangecertificate?view=exchange-ps\\ https://docs.microsoft.com/en-us/exchange/architecture/client-access/assign-certificates-to-services?view=exchserver-2019 ==== ASSERT: HMACprovider.GetCertificates:ProtectionCertificates.Length<1 ==== После удаления сертификата, привязанного только к SMTP, перестала работать OWA и ECP. Ошибка после попытки логина: ASSERT: HMACprovider.GetCertificates:ProtectionCertificates.Length<1 Выдаётся ошибка при попытке вывести сертификат из конфигурации аутентификации приложений: (Get-AuthConfig).CurrentCertificateThumbprint | Get-ExchangeCertificate | Format-List # A special Rpc error occurs on server WS-MS1: The certificate with thumbprint D7482B97190A5517B581A6A768AF356C13887918 w # as not found. # + CategoryInfo : NotSpecified: (:) [Get-ExchangeCertificate], InvalidOperationException # + FullyQualifiedErrorId : [Server=WS-MS1,RequestId=15314839-d0a6-4b13-ab88-da483bbbc78c,TimeStamp=01.09.2023 5:41: # 47] [FailureCategory=Cmdlet-InvalidOperationException] CFD7CD37,Microsoft.Exchange.Management.SystemConfigurationT # asks.GetExchangeCertificate # + PSComputerName : ws-ms1.example.com При попытке создать новый сертификат говорится, что сертификат уже есть: New-ExchangeCertificate -KeySize 2048 -PrivateKeyExportable $true ` -SubjectName "cn=Microsoft Exchange Server Auth Certificate" -FriendlyName "Microsoft Exchange Server Auth Certificate" -DomainName @() # Confirm # Overwrite the existing default SMTP certificate? # Current certificate: 'F7630C1126AC09F9BB9152CFA5623D06D7089E7C' (expires 16.01.2028 8:54:05) # Replace it with certificate: '11C2C4B244066744CA8CA65701D4A85D99693677' (expires 01.09.2028 8:42:11) # [Y] Yes [A] Yes to All [N] No [L] No to All [?] Help (default is "Y"): n Поэтому удаляем только что созданный сертификат и привязываем тот, который уже есть и публикуем его: # Удаление Remove-ExchangeCertificate 11C2C4B244066744CA8CA65701D4A85D99693677 # Привязка Set-AuthConfig -NewCertificateThumbprint F7630C1126AC09F9BB9152CFA5623D06D7089E7C ` -NewCertificateEffectiveDate (Get-Date) # Confirm # The new certificate effective date is not at least "48" hours in the future and may not be deployed on all necessary # servers. Do you wish to continue? # [Y] Yes [A] Yes to All [N] No [L] No to All [?] Help (default is "Y"): y # Публикация Set-AuthConfig -PublishCertificate Сертификат уже распространился на все почтовые сервера, теперь нужно перезапустить пулы __на каждом сервере__. Restart-WebAppPool MSExchangeOWAAppPool Restart-WebAppPool MSExchangeECPAppPool [[https://learn.microsoft.com/en-us/exchange/troubleshoot/administration/cannot-access-owa-or-ecp-if-oauth-expired|Can't sign in to Outlook on the web or EAC if Exchange Server OAuth certificate is expired]]\\ ===== Очередь ===== # Удалить письма от определённого адресата со всех серверов HubTransport (-withNDR - без отчёта о недоставке) Get-ExchangeServer |? IsHubTransportServer |Get-Queue |get-message |? fromaddress -eq 'user@domain.ru' |Remove-Message -withNDR $false -Confirm:$false # С Edge Get-Queue |get-message |? fromaddress -eq 'user@domain.ru' |Remove-Message -withNDR $false -Confirm:$false ===== Информация ===== В Exchange management shell # Версия Exchange (https://docs.microsoft.com/en-us/Exchange/new-features/build-numbers-and-release-dates) (Get-Command Exsetup.exe).FileVersionInfo ProductVersion FileVersion FileName -------------- ----------- -------- 15.00.1497.033 15.00.1497.033 c:\Program Files\Microsoft\Exchange Server\V15\bin\ExSetup.exe ===== Прочее ===== ==== Чистка логов на серверах ==== $hosts = "ex1","ex2","ex3" Invoke-Command -computername $hosts -command { $t = get-date # Чистка логов IIS - оставляем 7 дней gci 'C:\inetpub\logs\LogFiles' -Include '*.log' -Recurse |? LastWriteTime -LT $t.AddDays(-7) |Remove-Item # Чистка логов Exchange - оставляем 3 месяца gci 'C:\Program Files\Microsoft\Exchange Server\V15\Logging' -Include '*.log', '*.blg' -Recurse |? LastWriteTime -LT $t.AddMonths(-3) |Remove-Item } ==== Срок хранения транспортных журналов ==== # Просмотр настроек Get-TransportService |select *tracking* # Изменение Set-TransportService srv-edge2 -MessageTrackingLogMaxAge 100 -MessageTrackingLogMaxDirectorySize 5GB -MessageTrackingLogMaxFileSize 30MB ==== Запустить Exchange shell в Powershell ==== Нужно, чтобы на компе админа были установлены компоненты управления. Import-Module "$env:ExchangeInstallPath\Bin\RemoteExchange.ps1" Connect-ExchangeServer -auto Другой способ (для 2013): Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Support,Microsoft.Exchange.Management.PowerShell.E2010,Microsoft.Exchange.Management.PowerShell.SnapIn [[http://hkeylocalmachine.com/?p=180|How do I add the Exchange PowerShell module into a standard PowerShell session]] ==== Connect to Exchange servers using remote PowerShell ==== В данном случае в конторе три сервера - exch1, exch2, exch3, перебор до первого, с кем удастся установить соединение. $c = 1 do {$pssession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://exch$($c).domain.ru/PowerShell/ -Authentication Kerberos -ErrorAction SilentlyContinue; $c++} until ($? -or $c -gt 3) if (!$?) {write-host -fore red "Не удалось подключиться ни к одному серверу Exchange"; sleep 2; exit} Import-PSSession $pssession -DisableNameChecking -ErrorAction SilentlyContinue > $null if (!$?) {write-host -fore red "Ошибка импорта удалённой сессии Powershell"; sleep 2; exit} # do some work Remove-PSSession $Session https://docs.microsoft.com/en-us/powershell/exchange/exchange-server/connect-to-exchange-servers-using-remote-powershell?view=exchange-ps ==== Ссылка создания шаблонного письма ==== mailto:mail@domain.ru?subject=Привет%20всем&body=Здравствуйте!%20Как%20вы%20поживаете?%20%0A%0DУ%20меня%20всё%20нормально.%0A%0DПишите. ==== Предуведомление о спаме ==== Идея - добавлять предуведомление в тело письма после пограничного антиспама, добавляющего тэги в тему ([Spam], [Phishing] и т. п.). Реализуется правилом на сервере Exchange с действием Prepend the disclaimer. Примерное содержание уведомления:

Внимание!

Антиспам-система предприятия распознала это письмо из внешней почты как подозрительное.

Подобные письма могут содержать вредоносные вложения, ссылки на сайты злоумышленников или заведомо ложную информацию.

Будьте осторожны:

Для получения дополнительной информации обращайтесь в Управление безопасности.

https://batishchev.ru/blog/all/kenk-klms-disclaimer/ ==== Поиск ящика, которому принадлежит адрес ==== Get-Recipient |? emailaddresses -match 'pass' |select name,emailaddresses ===== Отчёты ===== Кол-во отправленных и полученных писем за прошлый месяц на Exchange Edge Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 $reportpath = "C:\scripts\Send-Receive-statistics" #за весь прошлый месяц $startdate = ((get-date -day 1).AddMonths(-1)).Date $enddate = ((get-date -day 1).date).AddSeconds(-1) $mailboxes = ((get-messagetrackinglog -Start $startdate -End $enddate -ResultSize unlimited | ? EventId -match "SEND|RECEIVE" |select -expand Recipients) -split ', ') -match '@domain.ru' |sort -Unique $report = @() foreach ($mbx in $mailboxes) { $mbxstat = '' |select 'Адрес','Кол-во полученных сообщений','Кол-во отправленных сообщений' $mbxstat.'Адрес' = $mbx.tolower() $mbxstat.'Кол-во полученных сообщений' = (Get-MessageTrackingLog -Start $startdate -End $enddate -EventId "RECEIVE" -Recipients $mbx -ResultSize Unlimited).count $mbxstat.'Кол-во отправленных сообщений' = (Get-MessageTrackingLog -Start $startdate -End $enddate -EventId "SEND" -Sender $mbx -ResultSize Unlimited).count $report += $mbxstat } $mark = (get-date).ToString("yyyy-MM-dd") $report |Export-Csv -Path "$reportpath\$mark-mailboxes-send-receive-stat-$($startdate.ToString("MMMM-yyyy")).csv" -Delimiter ';' -Encoding UTF8 -NoTypeInformation #$report |sort 'Имя' |Export-Excel -Path "$reportpath\$mark-mailboxes-send-receive-stat-$($startdate.ToString("MMMM-yyyy")).xlsx" -AutoSize -FreezeTopRow -AutoFilter -BoldTopRow sleep 30 $attach = (gci "$reportpath\*.csv" |sort creationtime |select -last 1).fullname $mailbody = "

Отчёт по отправленным и полученным письмам за период с $($startdate.ToString()) по $($enddate.ToString())

" $mailbody += "

Общее количество адресов в отчёте - $($expomailboxes.Count)`.

" $mailbody += "

Отчёт сформирован скриптом $($PSScriptRoot + '\' + $MyInvocation.MyCommand) на компьютере $($env:COMPUTERNAME).

" Send-MailMessage -SmtpServer mail.domain.ru -From "support@domain.ru" -To 'admin@domain.ru' -Subject "Exchange Edge - статистика по отправленным и полученным письмам" -Body "$mailbody" -Attachments "$attach" -Encoding UTF8 -bodyashtml
===== Статьи ===== [[http://www.michev.info/Blog/Post/1516/quickly-list-all-mailboxes-to-which-a-particular-user-has-access|Quickly list all mailboxes to which a particular user has access]] [[http://www.powertheshell.com/displaying-complete-results/|Displaying Complete Results]] [[https://www.codetwo.com/admins-blog/new-mailboxrepairrequest-the-successor-of-the-isinteg-tool/|New-MailboxRepairRequest – the successor of the Isinteg tool]] ===== Autodiscover ===== Порядок поиска автонастройки клиентами, каждый следующий способ используется после неудачного использования предыдущего: - SCP (Service Connection Point), для доменных клиентов. Путь (MMC Sites and Services): //CN=CAS01,CN=Autodiscover,CN=Protocols,CN=CAS01,CN=Servers,CN=Exchange Administrative Group (ABCDE123456),CN=Administrative Groups,CN=Domain,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domain,DC=ru//\\ Клиенты читают 3 атрибута:\\ **serviceBindingInformation** – FQDN CAS-сервера (%%https:///autodiscover/autodiscover.xml%%)\\ **keywords** - сайт, где находится CAS (к CAS в другом сайте Outlook подключаться не будет)\\ **WhenCreated** - дата создания сервера, клиент будет сначала подключаться к самому старому. Клиент получает URLs точек Autodiscover, пытается скачать XML с настройками, открывая URLs по очереди. # Получить список серверов Get-ClientAccessServer | fl Name,AutoDiscoverServiceInternalUri,AutoDiscoverSiteScope,WhenCreated - Внешние клиенты обращаются в DNS за стандартными URLs службы Autodiscover:\\ //%%https:///autodiscover/autodiscover.xml%%//\\ //%%https://autodiscover./autodiscover/autodiscover.xml%%//\\ Если по HTTPS URLs не отвечают, они опрашиваются по HTTP, который используется только для редиректа на HTTPS. - Поиск в DNS [[http://support.microsoft.com/?kbid=940881|SRV-записи службы Autodiscover]] вида\\ //_autodiscover._tcp.//\\ Запись может указывать на любой URL. - [[http://technet.microsoft.com/en-us/library/cc511507.aspx|Поиск локального файла с настройками]]. Варианты публикации Autodiscover - 1 сертификат с полями SAN, когда Autodiscover сидит на отдельном от всех остальных служб адресе (https://autodiscover.domain.ru/autodiscover/autodiscover.xml, все остальные - https://mail.domain.ru/*/) - 1 сертификат без SAN - самый экономный вариант, используется вариант поиска по SRV-записи. Для этого нужно править SCP и [[http://support.microsoft.com/kb/939184|обновлять старые 2007-е Аутлуки]]. - 2 сертификата без поля SAN - публикация на отдельном адресе autodiscover.xml, например, https://autodiscover.domain.ru/autodiscover/autodiscover.xml. Используется, если по какой-то причине клиенты не умеют читать поле SAN в сертификате. Требуется 2 внешних адреса. - Поиск Autodiscover через HTTP-редирект - то же, что и пред. пункт, но публикация по HTTP, который редиректит на https://mail.domain.ru/autodiscover/autodiscover.xml. В этом случае также требуется 2 внешних адреса. Особенности подключения к CAS Если настройки SCP никогда не менялись, все клиенты сайта будут ходить через один единственный сервер (т. к. они всегда выбирают самый старый CAS), тем самым излишне нагружая его. Рекомендация - использовать имя балансировщика CAS серверов в AutoDiscoverServiceInternalUri. При переезде серверов Exchange в другой сайт надо учитывать, что свойство **msExchangeServerSite** в схеме AD (ADSIEdit -> Configuration container -> CN=Services, CN=Microsoft Exchange,CN=First Organization,CN=Administrative Groups,CN=Exchange Administrative Group …,CN=Servers,CN=Server) обновляется автоматически при перезапуске службы NetLogon, в отличие от ключа **Keywords**, будет криво работать. Проксирование запросов * CAS2013 перенаправляет запросы пользователя на MBX2013 * CAS2017/2010, если ящики уже мигрировали на MBX2013 и этот CAS обновлён до версии, поддерживающей coexistence), перенаправляет запросы на CAS2013. * CAS2013 в обратном случае будет слать запросы на CAS2010, но на CAS2007 не будет - запросы будет обрабатывать MBX2013. http://www.alexxhost.ru/search/label/Autodiscover ===== Решение проблем ===== ==== Get-MailboxExportRequest is not recognized as the name of a cmdlet ==== EAC -> permissions -> admin roles -> Organization Management -> Edit -> Roles:Add -> click Mailbox Import Export -> Add -> OK -> Save. ==== Не работает POP3 и IMAP ==== На локальном сервере работает, извне - нет. Причина - не работали компоненты PopProxy и ImapProxy. Set-ServerComponentState -Identity srv.domain.ru -State Active -Requester HealthAPI -Component Imapproxy Set-ServerComponentState -Identity srv.domain.ru -State Active -Requester HealthAPI -Component PopProxy ==== Учётка в AD блокируется с серверов Exchange ==== ++++ Удобный скрипт поиска времени блокировки на контроллерах домена | <# .SYNOPSIS This function will locate the computer that processed a failed user logon attempt which caused the user account to become locked out. .DESCRIPTION This function will locate the computer that processed a failed user logon attempt which caused the user account to become locked out. The locked out location is found by querying the PDC Emulator for locked out events (4740). The function will display the BadPasswordTime attribute on all of the domain controllers to add in further troubleshooting. .EXAMPLE PS C:\>Get-LockedOutLocation -Identity Joe.Davis This example will find the locked out location for Joe Davis. .NOTE This function is only compatible with an environment where the domain controller with the PDCe role to be running Windows Server 2008 SP2 and up. The script is also dependent the ActiveDirectory PowerShell module, which requires the AD Web services to be running on at least one domain controller. Author: Jason Walker Last Modified: 3/20/2013 #> Function Get-LockedOutLocation { [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [String]$Identity ) Begin { $DCCounter = 0 $LockedOutStats = @() Try { Import-Module ActiveDirectory -ErrorAction Stop } Catch { Write-Warning $_ Break } } Process { #Get all domain controllers in domain $DomainControllers = Get-ADDomainController -Filter * $PDCEmulator = $DomainControllers | Where-Object { $_.OperationMasterRoles -contains "PDCEmulator" } Write-Verbose "Finding the domain controllers in the domain" ForEach($DC in $DomainControllers) { $DCCounter++ Write-Progress -Activity "Contacting DCs for lockout info" -Status "Querying $($DC.Hostname)" -PercentComplete (($DCCounter/$DomainControllers.Count) * 100) Try { $UserInfo = Get-ADUser -Identity $Identity -Server $DC.Hostname -Properties AccountLockoutTime,LastBadPasswordAttempt,BadPwdCount,LockedOut -ErrorAction Stop } Catch { Write-Warning $_ Continue } if ($UserInfo.LastBadPasswordAttempt) { $LockedOutStats += New-Object -TypeName PSObject -Property @{ Name = $UserInfo.SamAccountName SID = $UserInfo.SID.Value LockedOut = $UserInfo.LockedOut BadPwdCount = $UserInfo.BadPwdCount BadPasswordTime = $UserInfo.BadPasswordTime DomainController = $DC.Hostname AccountLockoutTime = $UserInfo.AccountLockoutTime LastBadPasswordAttempt = ($UserInfo.LastBadPasswordAttempt).ToLocalTime() } } } $LockedOutStats | Format-Table -Property Name,LockedOut,DomainController,BadPwdCount,AccountLockoutTime,LastBadPasswordAttempt -AutoSize #Get User Info Try { Write-Verbose "Querying event log on $($PDCEmulator.HostName)" $LockedOutEvents = Get-WinEvent -ComputerName $PDCEmulator.HostName -FilterHashtable @{LogName='Security';Id=4740} -ErrorAction Stop | Sort-Object -Property TimeCreated -Descending } Catch { Write-Warning $_ Continue } ForEach ($Event in $LockedOutEvents) { if ($Event | Where {$_.Properties[2].value -match $UserInfo.SID.Value}) { $Event | Select-Object -Property @( @{Label = 'User'; Expression = {$_.Properties[0].Value}} @{Label = 'DomainController'; Expression = {$_.MachineName}} @{Label = 'EventId'; Expression = {$_.Id}} @{Label = 'LockedOutTimeStamp'; Expression = {$_.TimeCreated}} @{Label = 'Message'; Expression = {$_.Message -split "`r" | Select -First 1}} @{Label = 'LockedOutLocation'; Expression = {$_.Properties[1].Value}} ) } } } } ++++ https://github.com/a118n/poweradmin/blob/master/Get-LockedOutLocation.ps1 Потом нужно смотреть в логи IIS на соответствующем сервере, путь C:\inetpub\logs\LogFiles\W3SVCx Учитывать, что время в логах IIS в UTC (т. е. нужно вычесть 3 часа). ==== Outlook - ошибка сертификата безопасности прокси-сервера ==== Ошибка возникла после замены сертификата wildcard на прокси-сервере, через который идут клиентские подключения, на обычный Let's Encrypt. При запуске Outlook у некоторых пользователей возникает ошибка вида {{:service:pasted:20221226-120003.png}} Оказалось, что в Exchange существует параметр для Outlook Anywhere, который необходим старым клиентам для корректного подключения. Новые клиенты (Outlook 2016) игнорируют этот параметр, поэтому на них ошибка не возникает. PS>Get-OutlookProvider Name Server CertPrincipalName TTL ---- ------ ----------------- --- exch 1 expr msstd:*.example.ru 1 WEB 1 В интернете есть [[https://community.spiceworks.com/topic/2254121-outlook-error-to-exchange-saying-wrong-ssl-certificate-name|рекомендация по удалению]] CertPrincipalName, но это не исправляет ситуацию. Нужно просто переделать имя на реальное вместо wildcard. PS>Set-OutlookProvider EXPR -CertPrincipalName:msstd:mail.example.ru [[https://learn.microsoft.com/en-us/answers/questions/146023/question-on-set-outlookprovider-expr.html|Question on Set-OutlookProvider EXPR]] ==== После смены внутреннего сертификата невозможно зайти на OWA и EAC ==== После ввода логина и пароля выбрасывает опять на страницу входа.\\ Решение - поставить тот же сертификат на сайт "Exchange Back End" в IIS, привязка на порт 444. {{:service:pasted:20230116-080659.png}} {{:service:pasted:20230116-080837.png}} {{:service:pasted:20230116-081001.png}} Затем нужно перезапустить IIS. https://learn.microsoft.com/en-us/exchange/troubleshoot/client-connectivity/owa-ecp-ems-cannot-connect-after-self-signed-certificate-removed ==== Autodiscover - разрешить этому веб-сайту выполнить настройку параметров сервера? ==== После переключения имени autodiscover.example.com на реверс-прокси с серверов напрямую (DNS round robin), начало выдаваться сообщение: {{:service:pasted:20230117-140349.png}} Если выбрать "больше не спрашивать", то в реестре по пути ''HKEY_CURRENT_USER\Software\Microsoft\Office\\Outlook\AutoDiscover\RedirectServers'' образуется ключ autodiscover.example.com типа REG_NONE. Собственно, решение - добавить всем этот ключ (политика на пользователя). function Set-AutodiscoverKey { param($key,$addr) if ((gci Registry::$key).property -notcontains $addr) { Write-Host -fore red "No record $addr, adding it to $($key.name)" $null = New-ItemProperty ` -Path Registry::$key\RedirectServers ` -Name $addr ` -type None ` -Value ([byte[]]@()) ` -Force } else { Write-Host -fore green "The record $addr exists in $($key.name)" } } $addresses = "mail.example.com","autodiscover.example.com" $reg = (gci Registry::HKCU\SOFTWARE\Microsoft\Office\*\Outlook\*) -match "autodiscover" if (!$reg) {exit} foreach ($key in $reg) { $addresses |% { Set-AutodiscoverKey $key $_ } } [[https://learn.microsoft.com/ru-ru/outlook/troubleshoot/connectivity/how-to-suppress-autodiscover-redirect-warning|Подавление предупреждения перенаправления автообнаружения в Outlook]]\\ [[https://learn.microsoft.com/ru-ru/outlook/troubleshoot/profiles-and-accounts/unexpected-autodiscover-behavior?source=recommendations|Неожиданное поведение автообнаружения, когда есть настройки в разделе \Autodiscover]] ==== Невозможно удалить сертификат из Exchange Admin Center ==== При попытке удалить сертификат появляется ошибка: {{:service:pasted:20230130-103336.png}} Дело в том, что сертификат на подмену уже есть и привязан к службам. Решить проблему можно обходным путём, но не надо, т. к. перестанут ходить письма, например, с внутренних серверов на Edge: mmc.exe -> Add/remove snap-ins -> certificates -> computer account -> local computer.\\ Look under Console root -> Certificates -> Personal -> Certificates. Сначала нужно привязать новый сертификат с службе, например, SMTP, и потом переделать подписку, если нужно. Enable-ExchangeCertificate -Thumbprint -Services SMTP Иначе письма будут застревать в очереди внутренних серверов. https://learn.microsoft.com/en-us/answers/questions/911472/no-edgesync-credentials-were-found-for-edge-transp ==== Exchange Edge блокирует легитимные вложения ==== Не приходит вложение filename.xlsx.zip, заменяется на txt с содержимым "Вложение было удалено". В списке расширений фильтра вложений это сочетание отсутсвует. ++++ Список расширений в Attachment filter| (Get-AttachmentFilterEntry).name |sort *.ade *.adp *.app *.asx *.bas *.bat *.chm *.cmd *.com *.cpl *.crt *.csh *.exe *.fxp *.hlp *.hta *.inf *.ins *.isp *.js *.jse *.ksh *.lnk *.mda *.mdb *.mde *.mdt *.mdw *.mdz *.msc *.msi *.msp *.mst *.ops *.pcd *.pif *.prf *.prg *.ps1 *.ps11 *.ps11xml *.ps1xml *.ps2 *.ps2xml *.psc1 *.psc2 *.reg *.scf *.scr *.sct *.shb *.shs *.url *.vb *.vbe *.vbs *.wsc *.wsf *.wsh *.xnk application/hta application/javascript application/msaccess application/prg application/x-javascript application/x-msdownload message/partial text/javascript text/scriptlet x-internet-signup ++++ Решение: выключить фильтр Disable-TransportAgent "Attachment Filtering Agent" и перенести все расширения в Каспер. {{:service:pasted:20230130-142749.png?600}}