Куда я попал?
SECURITM это SGRC система, ? автоматизирующая процессы в службах информационной безопасности. SECURITM помогает построить и управлять ИСПДн, КИИ, ГИС, СМИБ/СУИБ, банковскими системами защиты.
А еще SECURITM это место для обмена опытом и наработками для служб безопасности.

Уведомление пользователей о предстоящей смене пароля

Цель: сократить трудозатраты служб ИБ и ИТ на обслуживание учетных записей с просроченными паролями

В заметке пример скрипта, который отправляет пользователям инструкцию по смене пароля по электронной почте за 5 дней до срока окончания действия пароля.
Область действия: Вся организация
Классификация
Тип
Техническая ?
Удерживающая ?
Реализация
Автоматически
Периодичность
По событию
Ответственный
Не определено
Инструменты
Не определено

Ресурсная оценка

Качественная оценка

Количественная оценка

Итоговая оценка

Стоимость

Трудозатраты

Сложность

Стоимость, тыс. руб

Трудозатраты, дней/ год

CAPEX

?
Неизвестно
Неизвестно
Неизвестно
Неизвестно
Неизвестно
Отсутствует

OPEX

?
Неизвестно
Неизвестно
Неизвестно
Неизвестно
Неизвестно

Связанные риски

Ничего не найдено

Заметки

3
1 год назад

Скрипт уведомления о заканчивающемся пароле

Скрипт уведомляет пользователей Active Directory о заканчивающемся сроке действия пароля.
  • Если срок действия пароля истекает менее чем через 5 дней, пользователю отправляется e-mail с предупреждением и инструкцией в картинках, как поменять пароль. 
    В письме применяются встроенные (inline) изображения;
  • Уведомление каждому пользователю отправляется только один раз;
  • Логи выполнения сохраняются в подпапку _logs, хранится последние 30 журналов;
  • В подпапке work создается рабочее хранилище с целью обеспечения единоразовой отправки.
  • Список исключений как по логину, так и по ФИО пользователей размещается в папке с скриптом в файле exclude.txt
Дополнительные файлы (html форма письма и изображения) в вложении к заметке

# PowerShell
$Error.clear()
$elevel = 0

$mailto=@('infosec@mycorp.local')

Function Log($str) {
  Write-Output "$(Get-Date -Format 'dd.MM.yy HH:mm:ss') -> $str"
}

Function Ending([int]$d, [string[]]$ends = ('ок','ка','ки')) {
  $y = $d % 10
  If ($d -ge 10 -and [int]($d / 10 % 10) -eq 1) {$ends[0]} ElseIf ($y -eq 1) {$ends[1]} ElseIf ((2,3,4) -eq $y) {$ends[2]} Else {$ends[0]}
}

. "$PSScriptRoot\Send-MailMessage.ps1" # Вспомогательный скрипт для отправки электронной почты

$now = Get-Date
$nowplus = $now.AddDays(5)

$workdir = "$PSScriptRoot\work"
$usersdir = "$workdir\SamAccountName"

$workdir,$usersdir | ? {-not (Test-Path -LiteralPath $_ -Type Container)} | % {
  try {
    New-Item -Path $_ -ItemType Directory -Force -ErrorAction Stop | Out-Null
  }
  catch {
    Log "Cannot create workdir `"$_`""
    $elevel = 1
  }
}

If ($elevel -eq 0) {
  $EmailToUsr = @{
    To = $mailto
    Bcc = 'infosec@mycorp.ru'
    From = 'Отдел информационной безопасности <infosec@mycorp.ru>'
    Subject = 'Срок действия Вашего пароля скоро закончится'
    BodyAsHtml = $true
    SMTPServer = 'mail'
    Priority = 'High'
    InlineAttachments = @{
      img01 = "$PSScriptRoot\html\ctrl+alt+del.png"
      img02 = "$PSScriptRoot\html\change1.png"
      img03 = "$PSScriptRoot\html\change2.png"
    }
  }
  if ($debug) {$EmailToUsr.Remove('Bcc')}

  $EmailToUsrTemplate = "$PSScriptRoot\html\EmailToUsr.html"
  $EmailTemplate = If (Test-Path -LiteralPath $EmailToUsrTemplate -Type Leaf) {Get-Content -LiteralPath $EmailToUsrTemplate} Else {$null}

  $excludeFile = "$PSScriptRoot\exclude.txt"
  $exclude = If (Test-Path -LiteralPath $excludeFile -Type Leaf) {Get-Content -LiteralPath $excludeFile | % {$_.Trim()} | ? {$_ -and (-not $_.StartsWith("#"))}} Else {$null}
  $sentall = @()
  $usersall = @()

  Get-ADUser -Filter {Enabled -eq $true -and PasswordNeverExpires -eq $false} -Properties ObjectGUID,SamAccountName,UserPrincipalName,DisplayName,mail,msDS-UserPasswordExpiryTimeComputed | `
  ? {$exclude -notcontains $_.SamAccountName -and $exclude -notcontains $_.DisplayName -and $_.'msDS-UserPasswordExpiryTimeComputed' -ge $now.ToFileTime() -and $_.'msDS-UserPasswordExpiryTimeComputed' -le $nowplus.ToFileTime()} | `
  Select-Object -Property ObjectGUID,SamAccountName,UserPrincipalName,DisplayName,mail,@{Name='Expiry'; Expression={[datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}} | % {
    $sentall+= "$($_.ObjectGUID)_$(Get-Date $_.Expiry -Format 'yyyyMMdd').txt"
    $sentfile = "$workdir\$($sentall[-1])"

    $usersall+= "$($_.SamAccountName).txt"
    $userfile = "$usersdir\$($usersall[-1])"

    $days = ($_.Expiry-$now).Days
    If ($days -eq 0) {$dtxt = 'сегодня'}
    ElseIf ($days -eq 1) {$dtxt = 'завтра'}
    Else {$dtxt = "через $days $(Ending $days @('дней','день','дня'))"}

    try {
      Set-Content -Value "Пароль истекает $($dtxt)" -LiteralPath $userfile -Encoding UTF8 -Force
      $Acl = Get-Acl -LiteralPath $userfile
      $Ar = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $_.UserPrincipalName, 'Read,Delete', 'Allow'
      $Acl.SetAccessRule($Ar)
      Set-Acl -LiteralPath $userfile -AclObject $Acl
    }
    catch {
      Log "[err] Error write `"$userfile`" file"
      $elevel = 1
      If (Test-Path -LiteralPath $userfile -Type Leaf) {Remove-Item -LiteralPath $userfile -Force}
    }

    If (-not (Test-Path -LiteralPath $sentfile -Type Leaf)) {
      If (-not $debug -and [bool]($_.mail -as [Net.Mail.MailAddress])) {$EmailToUsr.To = "$($_.DisplayName) <$($_.mail)>"}
      $EmailToUsr.Body = ($EmailTemplate.replace('<!--LOGIN-->', $_.SamAccountName).replace('<!--NAME-->', $_.DisplayName).replace('<!--DAYS-->', $dtxt) | Out-String)
      try {
       Send-MailMessage @EmailToUsr -ErrorAction Stop
       Set-Content -Value $_.Expiry -LiteralPath $sentfile -Encoding UTF8 -Force
       Log "Mail sent to $($EmailToUsr.To)"
      }
      catch {
       Log "[err] Error sending mail to $($EmailToUsr.To)"
       $elevel = 1
      }
    }
    Else {
      Log "[inf] Alert already sent to $($_.DisplayName) <$($_.mail)>"
    }
  }

  If ($sentall) {Remove-Item -Path "$workdir\*.txt" -Exclude $sentall -Force}
  If ($usersall) {Remove-Item -Path "$usersdir\*.txt" -Exclude $usersall -Force}
}

Log 'Done.'

If ($Error) {
  $elevel = 1
  $Error
}
exit $elevel

Для просмотра файла необходимо авторизоваться!

Пример письма
1 год назад

Скрипт для отправки писем

# PowerShell
#requires -Version 2.0

function Send-MailMessage
{
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true)]
        [Alias('PsPath')]
        [ValidateNotNullOrEmpty()]
        [string[]]
        ${Attachments},

        [ValidateNotNullOrEmpty()]
        [Collections.HashTable]
        ${InlineAttachments},
        
        [ValidateNotNullOrEmpty()]
        [Net.Mail.MailAddress[]]
        ${Bcc},
    
        [Parameter(Position=2)]
        [ValidateNotNullOrEmpty()]
        [string]
        ${Body},
        
        [Alias('BAH')]
        [switch]
        ${BodyAsHtml},
    
        [ValidateNotNullOrEmpty()]
        [Net.Mail.MailAddress[]]
        ${Cc},
    
        [Alias('DNO')]
        [ValidateNotNullOrEmpty()]
        [Net.Mail.DeliveryNotificationOptions]
        ${DeliveryNotificationOption},
    
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [Net.Mail.MailAddress]
        ${From},
    
        [Parameter(Mandatory = $true, Position = 3)]
        [Alias('ComputerName')]
        [string]
        ${SmtpServer},
    
        [ValidateNotNullOrEmpty()]
        [Net.Mail.MailPriority]
        ${Priority},
        
        [Parameter(Mandatory=$true, Position=1)]
        [Alias('sub')]
        [ValidateNotNullOrEmpty()]
        [string]
        ${Subject},
    
        [Parameter(Mandatory=$true, Position=0)]
        [Net.Mail.MailAddress[]]
        ${To},
    
        [ValidateNotNullOrEmpty()]
        [Management.Automation.PSCredential]
        ${Credential},
    
        [switch]
        ${UseSsl},
    
        [ValidateRange(0, 2147483647)]
        [int]
        ${Port} = 25
    )
    
    begin
    {
        function FileNameToContentType
        {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory = $true)]
                [string]
                $FileName
            )

            $mimeMappings = @{
                '.png' = 'image/png'
            }

            $extension = [System.IO.Path]::GetExtension($FileName)
            $contentType = $mimeMappings[$extension]

            if ([string]::IsNullOrEmpty($contentType))
            {
                return New-Object System.Net.Mime.ContentType
            }
            else
            {
                return New-Object System.Net.Mime.ContentType($contentType)
            }
        }

        try
        {
            $_smtpClient = New-Object Net.Mail.SmtpClient
        
            $_smtpClient.Host = $SmtpServer
            $_smtpClient.Port = $Port
            $_smtpClient.EnableSsl = $UseSsl

            if ($null -ne $Credential)
            {
                # In PowerShell 2.0, assigning the results of GetNetworkCredential() to the SMTP client sometimes fails (with gmail, in testing), but
                # building a new NetworkCredential object containing only the UserName and Password works okay.

                $_tempCred = $Credential.GetNetworkCredential()
                $_smtpClient.Credentials = New-Object Net.NetworkCredential($Credential.UserName, $_tempCred.Password)
            }
            else
            {
                $_smtpClient.UseDefaultCredentials = $true
            }

            $_message = New-Object Net.Mail.MailMessage
        
            $_message.From = $From
            $_message.Subject = $Subject

            $Encode = [Text.Encoding]::GetEncoding("UTF-8");
            if ($BodyAsHtml)
            {
#                $_bodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, 'text/html')
                $_bodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, $encode, 'text/html')
            }
            else
            {
#                $_bodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, 'text/plain')
                $_bodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, $encode, 'text/plain')
            }   

            $_message.AlternateViews.Add($_bodyPart)

            if ($PSBoundParameters.ContainsKey('DeliveryNotificationOption')) { $_message.DeliveryNotificationOptions = $DeliveryNotificationOption }
            if ($PSBoundParameters.ContainsKey('Priority')) { $_message.Priority = $Priority }

            foreach ($_address in $To)
            {
                if (-not $_message.To.Contains($_address)) { $_message.To.Add($_address) }
            }

            if ($null -ne $Cc)
            {
                foreach ($_address in $Cc)
                {
                    if (-not $_message.CC.Contains($_address)) { $_message.CC.Add($_address) }
                }
            }

            if ($null -ne $Bcc)
            {
                foreach ($_address in $Bcc)
                {
                    if (-not $_message.Bcc.Contains($_address)) { $_message.Bcc.Add($_address) }
                }
            }
        }
        catch
        {
            $_message.Dispose()
            throw
        }

        if ($PSBoundParameters.ContainsKey('InlineAttachments'))
        {
            foreach ($_entry in $InlineAttachments.GetEnumerator())
            {
                $_file = $_entry.Value.ToString()
                
                if ([string]::IsNullOrEmpty($_file))
                {
                    $_message.Dispose()
                    throw "Send-MailMessage: Values in the InlineAttachments table cannot be null."
                }

                try
                {
                    $_contentType = FileNameToContentType -FileName $_file
                    $_attachment = New-Object Net.Mail.LinkedResource($_file, $_contentType)
                    $_attachment.ContentId = $_entry.Key

                    $_bodyPart.LinkedResources.Add($_attachment)
                }
                catch
                {
                    $_message.Dispose()
                    throw
                }
            }
        }
    }

    process
    {
        if ($null -ne $Attachments)
        {
            foreach ($_file in $Attachments)
            {
                try
                {
                    $_contentType = FileNameToContentType -FileName $_file
                    $_message.Attachments.Add((New-Object Net.Mail.Attachment($_file, $_contentType)))
                }
                catch
                {
                    $_message.Dispose()
                    throw
                }
            }
        }
    }
    
    end
    {
        try
        {
            $_smtpClient.Send($_message)
        }
        catch
        {
            throw
        }
        finally
        {
            $_message.Dispose()
        }
    }

} # function Send-MailMessage
1 год назад
Дополнения к скрипту
  • html форма для письма
  • изображения для вставки в письмо

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