Send-MailMessage'dan devam: Graph API'yi kullanarak PowerShell'den E-posta Gönderme


Temel Kimlik Doğrulamanın Kullanımdan Kaldırılması

Daha önce tartışıldığı gibi Microsoft, temel kimlik doğrulamayı kullanmayı bırakıp modern kimlik doğrulamayı kullanmaya başlamanın gerekliliği konusunda yüksek sesle davul çalıyor. Bu büyük bir sorun çünkü bilgisayar korsanları parola sprey saldırıları gibi tekniklerle Office 365 hesaplarını ve kiracılarını tehlikeye atmaya devam ediyor. Modern kimlik doğrulamasına geçmek ve çok faktörlü kimlik doğrulamayla mümkün olduğu kadar çok hesabı korumak (özellikle Azure AD Güvenlik Varsayılanları tarafından zorunlu kılınan yönetici hesapları) atılması gereken doğru adımlardır.

Güncelleme (25 Eylül 2021): Microsoft'un e-posta bağlantı protokolleri için temel kimlik doğrulamayı devre dışı bırakmaya yönelik en son planı, SMTP AUTH'u hariç tutuyor. Microsoft şimdilik IMAP4 ve POP3 gibi protokoller için temel kimlik doğrulamayı kaldırmaya odaklanıyor, ancak SMTP AUTH için temel kimlik doğrulamayı kaldırmak üzere geri dönecekler. Bu nedenle, zamanı geldiğinde üretimde bu protokolü nasıl değiştireceğinizi düşünmek akıllıca olacaktır.

Güncelleme (15 Kasım 2022): Grafiği kullanarak e-posta göndermenin üç yolu vardır. Burada açıklanan API'yi kullanmak bunlardan biridir. Tüm ayrıntılar için bu makaleyi okuyun.

Send-MailMessage Bilmecesi

Büyük ölçüde geçmiş nedeniyle, Exchange Online çok çeşitli bağlantı protokollerini destekler. Microsoft, müşterileri hiç kullanmadıkları protokoller için temel kimlik doğrulamasını devre dışı bırakmaya ikna etme konusunda bazı ilerlemeler kaydediyor ve modern kimlik doğrulama için OAuth 2.0'ı kullanacak şekilde POP3 ve IMAP4 gibi eski protokolleri yükseltti. Bu blogda tartışıldığı gibi, kiracıların Send-MailMessage cmdlet'ini çağıran PowerShell komut dosyalarını bulmaları ve sonunda kodu e-posta göndermek için daha modern bir yöntemle yükseltmeleri gerekecektir.

Send-MailMessage cmdlet'i, temel kimlik doğrulamayı kullanarak e-posta göndermek için SMTP AUTH protokolüne bağlıdır. Microsoft, Nisan 2020'de SMTP AUTH için OAuth 2.0 desteğini duyurdu ancak bu, kullanıma hazır bir yedek cmdlet'in mevcut olduğu anlamına gelmiyor. Microsoft, duyurunun "IMAP ve SMTP [AUTH] için OAuth'u etkinleştiren etkileşimli uygulamalara yönelik olduğunu" söylüyor. Aslında bu, e-posta gönderen, okuyan veya başka şekilde işleyen posta istemcileri veya diğer uygulamalar anlamına gelir. Başvurulan sayfaya hızlı bir gezi, bunun bir PowerShell betiğindeki birkaç kod satırını değiştirmekten daha fazlası anlamına geldiğine şüphe bırakmaz.

Send-MailMessage için belirgin bir değişiklik mevcut değilse, temel kimlik doğrulamayı ortadan kaldırmak istiyorsanız ancak e-posta göndermek için cmdlet'i kullanan bir sürü komut dosyasına sahipseniz ne yapmalısınız? Bu bir bilmece.

Grafiğe Girin

Microsoft'un SMTP AUTH hakkındaki notu, insanları e-posta göndermenin alternatif bir yöntemi olarak Microsoft Graph API'ye yönlendiriyor. SendMail çağrısı Graph Outlook API'nin bir parçasıdır. Tüm Graph API çağrıları gibi PowerShell aracılığıyla çağrılabilir.

SendMail, onu çağıran uygulamanın sahip olduğu izinlere bağlı olarak iki şekilde kullanılabilir:

  • Uygulamanın Mail.Send uygulama izni varsa uygulama, kuruluştaki herhangi bir kullanıcı veya paylaşılan posta kutusu (ancak grup posta kutusu değil) olarak e-posta gönderebilir. Bir yöneticinin, uygulama izinlerini kullanması için uygulamaya izin vermesi gerekir.
  • Uygulamanın Mail.Send yetkilendirilmiş izni varsa uygulama, oturum açmış kullanıcı olarak posta gönderebilir.

Bu nedenle, e-posta göndermek için bir uygulama izni kullanmak son derece güçlüdür (veya tehlikelidir). Grafik, posta kutuları için mevcut olan Exchange Farklı Gönder veya Adına Gönder izinlerini yok sayar ve herhangi bir kullanıcının veya paylaşılan posta kutusunun kimliğine bürünerek, sanki mesaj bu posta kutusundan geliyormuş gibi e-posta gönderebilir.

PowerShell Komut Dosyalarını Send-MailMessage'dan Dönüştürme

Bir betiği "klasik: Send-MailMessage kodundan SendMail çağrılarını kullanmak üzere dönüştürmenin ne kadar kolay olduğunu test etmek için, yeni kullanıcılara nasıl hoş geldiniz mesajı gönderileceğini göstermek üzere yazılmış örnek bir betik aldım. Dönüşümdeki temel adımlar şunlardır:

  • Azure AD'de kayıtlı bir uygulama oluşturun.
  • Mail.Send Graph (uygulama veya yetkilendirilmiş) iznini uygulamaya atayın.
  • Uygulama tanımlayıcısı ve kiracı tanımlayıcısına ilişkin GUID'leri not edin ve bir uygulama sırrı oluşturun (uygulama izni kullanılıyorsa).
  • Komut dosyasına, bir erişim belirteci oluşturmak için kod ekleyin ve Send-MailMessage'e çağrılacak kodu SendMail'in eşdeğeriyle değiştirin.

Öncelikle uygulama iznini kullanmaya bakalım. Erişim belirteci oluşturma kodu aşağıda gösterilene benzer. Uygulama kimliği ($AppId) ve kiracı tanımlayıcısı ($TenantId) için iletilen değerler kuruluşunuzda farklı olacaktır.

$AppId = "980e01d1-ce75-46ba-a054-4b61c787f682"
$AppSecret = "~_Q2.IPI3kpbmhOG.VtCb1r0_J9G4-D8jG"
$TenantId = "b562313f-14fc-43a2-9a7a-d2e27f4f3478"

# Construct URI and body needed for authentication
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$body = @{
    client_id     = $AppId
    scope         = "https://graph.microsoft.com/.default"
    client_secret = $AppSecret
    grant_type    = "client_credentials"
}

$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
# Unpack Access Token
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
$Headers = @{
            'Content-Type'  = "application\json"
            'Authorization' = "Bearer $Token" }

Geçerli bir erişim belirtecinin güvenliği sağlandığında, komut dosyası artık belirteçte kodlanmış izinleri kullanarak Graph API çağrıları yapabilir. Komut dosyası, yakın zamanda oluşturulan kullanıcı hesapları kümesini bulur ve özelleştirilmiş bir karşılama mesajı oluşturmak için her kullanıcı arasında döngü yapar. Send-MailMessage'i kullanmak için bunların çoğunun yapılması gerekiyor, dolayısıyla değişen kısım, işi SendMail ile yapmak için kodlu mesaj oluşturmak ve göndermek için parametrelerin oluşturulmasını değiştirmektir. .

Akışta aşağıdaki adımlar gerçekleşir:

  • $MsgFrom değişkenini (mesajı gönderen kişi) gönderen için geçerli bir e-posta adresiyle doldurun. SendMail API'si (uygulama izniyle) herhangi bir geçerli (lisanslı) posta kutusu olarak gönderebildiğinden, ikincil proxy adresleri de dahil olmak üzere herhangi bir kullanıcı veya paylaşılan posta kutusu için bir SMTP proxy adresi kullanabilirsiniz. Önemli olan, kullanılan adresin desteklenen bir posta kutusu türü için çözümlenebilir olmasıdır. SendMail, mesajı göndermeye çalıştığında göndereni doğrular ve gönderenin adresi kiracı dizininde bulunamazsa 404 hatası döndürür.
  • İletinin özelleştirilmiş HMTL gövdesini oluşturmak için yakın zamanda oluşturulan posta kutuları kümesinde dolaşın. Ardından, iletinin gövdesini (Kime ve CC alıcıları ve ileti konusu), bir eki ve iletiyi Exchange Online'a göndermek için kullanılan komutları tanımlayan JSON biçimli bir parametre yapısını doldurun. Dağıtım gruplarını, posta kişilerini, konuk hesaplarını ve Microsoft 365 Gruplarını içerebilecek adreslerin birincil SMTP adreslerini kullandığınızdan emin olun.
  • Parametreleri işlemek ve mesajı göndermek için Invoke-RestMethod cmdlet'ini çağırın.
$MsgFrom = “HRWelcomeMailbox@office365itpros.com”
$ccRecipient1 = “Kim.Akers@office365itpros.com”
$ccRecipient2 = “James.Ryan@Office365itpros.com”
# Define attachment to send to new users
$AttachmentFile = "C:\temp\WelcomeToOffice365ITPros.docx"
$ContentBase64 = [convert]::ToBase64String( [system.io.file]::readallbytes($AttachmentFile))
ForEach ($User in $Users) {
      $EmailRecipient = $User.PrimarySmtpAddress
      Write-Host "Sending welcome email to" $User.DisplayName
      $MsgSubject = "A Hundred Thousand Welcomes to " + $User.DisplayName
      $htmlHeaderUser = "<h2>New User " + $User.DisplayName + "</h2>"
      $htmlline1 = "<p><b>Welcome to Office 365</b></p>"
      $htmlline2 = "<p>You can open Office Online by clicking <a href=https://www.office.com/?auth=2>here</a> </p>"
      $htmlline3 = "<p>Have a great time and be sure to call the help desk if you need assistance.</p>"
      $htmlbody = $htmlheaderUser + $htmlline1 + $htmlline2 + $htmlline3 + "<p>"
      $HtmlMsg = "</body></html>" + $HtmlHead + $HtmlBody
# Create message body and properties and send
        $MessageParams = @{
          "URI"         = "https://graph.microsoft.com/v1.0/users/$MsgFrom/sendMail"
          "Headers"     = $Headers
          "Method"      = "POST"
          "ContentType" = 'application/json'
          "Body" = (@{
                "message" = @{
                "subject" = $MsgSubject
                "body"    = @{
                    "contentType" = 'HTML' 
                     "content"     = $htmlMsg }
         "attachments" = @(
             @{
              "@odata.type" = "#microsoft.graph.fileAttachment"
              "name" = $AttachmentFile
              "contentType" = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
              "contentBytes" = $ContentBase64 })  
           "toRecipients" = @(
           @{
             "emailAddress" = @{"address" = $EmailRecipient }
           } ) 
          "ccRecipients" = @(
           @{
             "emailAddress" = @{"address" = $ccRecipient1 }
           } ,
            @{
             "emailAddress" = @{"address" = $ccRecipient2 }
           } )       
         }
      }) | ConvertTo-JSON -Depth 6
   }   # Send the message
   Invoke-RestMethod @Messageparams
}

Komut dosyasının tamamını GitHub'dan indirebilirsiniz. Sizin de fark edeceğiniz gibi, bir mesaja eklenti eklemek Send-MailMessage'de olduğu kadar kolay değildir. Dikkat edilmesi gereken iki nokta şunlardır:

  • Mesaj gönderirken ek yüklemek, 3 MB'a kadar olan eklerle çalışır. 150 MB'a kadar daha büyük ekler göndermeniz gerekiyorsa bunları farklı bir yaklaşım kullanarak yüklemeniz gerekir (Microsoft'un notuna bakın). Elbette, posta kutusu ve kuruluş sınırları gibi diğer faktörler de maksimum ileti boyutunu etkiler.
  • İçerik türü, ekin MIME türüdür (unutmayın, e-posta kullanıyoruz, bu nedenle ek içeriğinin Base64 kodlu olması gerekir). Burada bulunan MIME türlerinin listesini faydalı buldum. Olası tüm ek türlerini test etmedim, ancak sorunlarla karşılaştığımda bazen resmi MIME türünün işe yaramadığı durumlarda "çok parçalı/karışık" içerik türünün işe yaradığını biliyorum.

Mail.Send API, iletilerde x başlıklarını ayarlayabilir; bu, Send-MailMessage cmdlet'inin yapamayacağı bir şeydir. İnsanların (artık kullanımdan kaldırılmış olan) .Net SmtpClient sınıfını komut dosyalarında e-posta oluşturmak ve göndermek için kullanmasının bir nedeni de budur. Bunun yerine Grafiği kullanmak için bu komut dosyalarını dönüştürmelisiniz.

O Büyük İzin Sorusu

Kuruluştaki herhangi bir posta kutusuna e-posta gönderebilecek bir uygulamaya sahip olma konusunda endişelenmiyorsanız, tüm komut dosyalarını yükseltmek için aynı uygulamayı temel olarak kullanmak kolay olacaktır. Erişim belirtecinin güvenliğini sağlamaya yönelik kod aynı kalır ve her komut dosyasına yapıştırılabilir. Daha sonra geri kalan görev, Send-MailMessage kodunu SendMail'i kullanacak şekilde güncellemektir.

Çok güçlü bir posta gönderme uygulamasına sahip olmak, programcıların hayatını kolaylaştıracaktır (veya en azından dönüşümü kolaylaştıracaktır), ancak uygulamanın kötüye kullanılamayacağına dair bir garanti verilmediği sürece kurumsal güvenlik ekibi tarafından kabul edilebilir görülmeyebilir. Böyle bir garantinin imkansız olduğu göz önüne alındığında sorunun nerede olduğunu görebilirsiniz.

Uygulama Tarafından Kullanılan Posta Kutularını Kısıtlamak için Uygulama Erişim Politikası Kullanma

Çözümlerden biri, uygulamanın yalnızca belirli posta kutularına erişmesine izin vermek için bir uygulama erişim ilkesi kullanmaktır. Bir uygulama erişim politikası üç unsuru birleştirir:

  • Erişimi reddetmeyi veya erişime izin vermeyi tanımlar.
  • Azure AD'de kayıtlı bir veya daha fazla uygulamayı kapsar.
  • Posta özellikli bir güvenlik grubunun üyeleri veya bireysel kullanıcılar (güvenlik ilkesine sahip nesneler) için posta kutularına yapılan Exchange Web Hizmetleri veya Graph API çağrıları için geçerlidir.

Böylece, bir dizi posta kutusuna erişimi kısıtlamak için bir uygulama erişim politikası oluşturabiliriz. Örneğin:

New-ApplicationAccessPolicy -AppId 970e01d1-ce75-46ba-a054-4b61c787f682 -PolicyScopeGroupId SendMailApp.Control@office365itpros.com -AccessRight RestrictAccess -Description "Restrict access to app allowed to send email using the Graph SendMail API"

Bu politika, 970e01d1-ce75-46ba-a054-4b61c787f682 tanımlayıcısına sahip Uygulamaya SendMailApp.Control@office365itpros.com güvenlik grubunda tanımlanan posta kutularına erişimi kısıtlar. Politika oluşturulduktan sonra, SendMail API çağrısını kullanarak e-posta göndermek için yalnızca güvenlik grubu üyelerinin posta kutuları kullanılabilir. Başka bir hesap kullanarak e-posta göndermeye çalışmak, politikanın posta kutusuna erişimi reddetmesi nedeniyle SendMail çağrılırken 403 hatasına neden olur.

Exchange Online, kontrollerin daha iyi performans göstermesini sağlamak için erişim ilkeleri için grup üyeliğini önbelleğe alır ve üyelik değişikliklerinin etkili olması için bir saat kadar beklemeniz gerekebilir, ancak ilke kısıtlamaları çok iyi çalışır.

Yetki Verilen İzinleri Kullan

Başka bir seçenek de, Mail.Send iznine sahip bir Azure AD kayıtlı uygulamasını kullanmaktır. Bu, oturum açılmış hesaba e-posta gönderme olanağını kısıtlar, böylece Send-MailMessage'in çalışma şekliyle daha uyumlu olur. Mesajı oluşturma ve gönderme kodu aynı kalır; Değişen tek şey, uygulamanın kimlik doğrulaması sırasında Azure AD tarafından oluşturulan erişim belirtecinin kullanımını oturum açmış bir kullanıcıyla kısıtlamasıdır. Çoğu durumda, SendMail API'sini çağırmak için yetkilendirilmiş iznin kullanılması daha iyi bir seçenektir. Tabii kiracıdaki herkes gibi mesaj gönderebilmek istemiyorsanız.

İlgili makaleler