Доброго времени суток.

Сегодня нашему администратору потребовалось отслеживать на сетевых ресурсах, сколько Гб использовали сотрудники в своих личных каталогах (дисковое пространство выделено путем подключения сетевого диска). Предполагаем, что предельно допустимый размер личного ресурса равен 1 Гб. В случае если этот размер превышает предел, необходимо сообщить администратору. Также необходимо контролировать резкое увеличение размеров личных ресурсов. Например, если личный каталог сотрудника увеличивается в размере на 200 Мб за неделю, то необходимо оповестить администратора.


Итак, код Powershell’a, который реализовал все вышеуказанные требования:

Функция отправки почты. Функция не унивирсальная, подстроена под задачу. Т.е. принимаем за факт, что тема сообщения, получатель не меняются. Меняется только тело, его то мы и задаем как входящий параметр для функции:

function EmailNotification($Mail_body)
{
  $Sender = "audit@..."
  $Receipt = "levitskaks@gmail.com"
  $Server = "gmail.com.ua"
  $Object = "DirSize: " + (Get-Date)
  $SMTPclient = new-object System.Net.Mail.SmtpClient $Server
  #Specify SMTP port if needed
  $SMTPClient.port = 25
  #Activate SSL if needed
  #$SMTPclient.EnableSsl = $true
  #Specify email account credentials if needed
  $SMTPAuthUsername = "levitskaks@gmail.com"
  $SMTPAuthPassword = "pass"
  $SMTPClient.Credentials = New-Object System.Net.NetworkCredential($SMTPAuthUsername, $SMTPAuthPassword)
  $Message = new-object System.Net.Mail.MailMessage $Sender, $Receipt, $Object, $Mail_body
  #-$Message.IsBodyHtml = $true;
  $SMTPclient.Send($Message)
}


Переходим к основной функции. Входящие параметры:
— исходный каталог. Каталог в котором перечень каталогов под каждого сотрудника;
— предельно-допустимый размер в байтах;
— путь для сохранения лога работы;

function Check-Size-Directory ($dir, $GB, $Logpath) {


Определяем день недели в году. На момент написания скрипта была 47 неделя.
Также нас интересует выполнение проверки — раз в неделю в понедельник. Логика проверки следующая: в четную неделю сохраняется лог работы «0.log». В нечетную неделю сохраняем файл «1.log». Если дата изменения «0.log» больше даты изменения «1.log», то по логически определяем, что последняя неделя была четная. и сверяем в каком каталоге размер увеличился более чем на 200 Мб.

[Int32]$Monday = (Get-Date -UFormat "%w")
    $Monday
    [Int32]$Week = (Get-Date -UFormat "%W")
    $Week
    if ($week%2 -eq 0 -and $Monday -eq 1){
        
        $LogPathFile = $LogPath + "\" + ($week%2).ToString() + ".log"    
        If (!(Test-Path -path $LogPathFile)){
            Write-Host "Создали элемент"
            New-Item -Path $LogPathFile  -ItemType File
        }
        $ToFile = "" | Out-File $LogPathFile
        Write-Host "Четная неделя"
        Get-ChildItem -path $dir | %{
            $dir_property = dir $_.FullName -recurse | where {-Not $_.PSIsContainer}| Measure-Object -Property length -Sum 


Первая требуемая проверка: проверяем каталог на размер больше, чем 1 Гб.

 if ($dir_property.Sum -gt $GB){
                $Mail_body+= "Размер каталога " + $_.FullName + " превышает размер в 1 Гб.`n"
                $Mail_body+= "Размер каталога " + $_.FullName + " составляет " + (($dir_property.Sum)/1024/1024) + " Мб.`n"
                $Mail_body+= "------------------------------------------------------------------------------------------`n"
                <b>$ToFile = $_.DirectoryName + " " + (($dir_property.Sum)/1024/1024) | Out-File $LogPathFile  -Append</b>
            }
            else {
                Write-Host "Все хорошо с каталогом: " $_.FullName
            }
        }
        EmailNotification -Mail_body $Mail_body


Сохраняем имя каталога и его размер через разделитель "|", в последствии через который будем парсить содержимое файла.

<b>$ToFile = $_.DirectoryName + " " + (($dir_property.Sum)/1024/1024) | Out-File $LogPathFile  -Append</b>


Определяем какой файл считаем новым, чтобы проводить сравнение с файлом недельной давности.

$Mail_body = ""
        If ((Get-Item -Path $LogPath\0.log).LastWriteTime -gt (Get-Item -Path $LogPath\1.log).LastWriteTime){
                $log_content = Get-Content (Get-ChildItem -Path $LogPath\0.log)
                foreach ($data in $log_content) 
                {
                    $x = $data.split("|")
                    $xc1 = $x[0]
                    $xc2 = $x[1]
                    $log_content = Get-Content (Get-ChildItem -Path $LogPath\1.log)
                    foreach ($data in $log_content) 
                    {
                        $y = $data.split("|")
                        if ($xc1 -eq $y[0]){
                            if(([Int32]$xc2 - [Int32]$y[1]) -gt 200){
                                $Mail_body += "Резкое увеличение размера каталога: " + $xc1 + "`n Размер на прошлой неделе составил: " + $y[1] + " Мб." + "`n Размер на текущей неделе составил: " + $xc2 + " Мб.`n"
                            }

                        }
                    }

                } 
           EmailNotification -Mail_body $Mail_body
           } 
    }


Проверка четности\нечетности недель проверяется делением по модулю полученной недели в году:

<b>$week%2</b>


Аналогичные проверки для нечетной недели:

    if ($week%2 -eq 1 -and $Monday -eq 1){
        Write-Host "Нечетная неделя"
        $LogPathFile = $LogPath + "\" + ($week%2).ToString() + ".log"
        If (!(Test-Path -path $LogPathFile)){
            Write-Host "Создали элемент"
            New-Item -Path $LogPathFile  -ItemType File
        }
        $ToFile = "" | Out-File $LogPathFile
        
        Get-ChildItem -path $dir | %{
            $dir_property = dir $_.FullName -recurse | where {-Not $_.PSIsContainer}| Measure-Object -Property length -Sum 
    
            if ($dir_property.Sum -gt $GB){
                $Mail_body+= "Размер каталога " + $_.FullName + " превышает размер в 1 Гб.`n"
                $Mail_body+= "Размер каталога " + $_.FullName + " составляет " + (($dir_property.Sum)/1024/1024) + " Мб.`n"
                $Mail_body+= "------------------------------------------------------------------------------------------`n"
                $ToFile = $_.Name + "|" + (($dir_property.Sum)/1024/1024) | Out-File $LogPathFile  -Append
            }
            else {
                Write-Host "Все хорошо с каталогом: " $_.FullName
            }
        }
        EmailNotification -Mail_body $Mail_body
        $Mail_body = ""
        If ((Get-Item -Path $LogPath\1.log).LastWriteTime -gt (Get-Item -Path $LogPath\0.log).LastWriteTime){
                $log_content = Get-Content (Get-ChildItem -Path $LogPath\1.log)
                foreach ($data in $log_content) 
                {
                    $x = $data.split("|")
                    $xc1 = $x[0]
                    $xc2 = $x[1]
                    $log_content = Get-Content (Get-ChildItem -Path $LogPath\0.log)
                    foreach ($data in $log_content) 
                    {
                        $y = $data.split("|")
                        if ($xc1 -eq $y[0]){
                            if(([Int32]$xc2 - [Int32]$y[1]) -gt 200){
                                $Mail_body += "Резкое увеличение размера каталога: " + $xc1 + "`n Размер на прошлой неделе составил: " + $y[1] + " Мб." + "`n Размер на текущей неделе составил: " + $xc2 + " Мб.`n"
                                $Mail_body
                            }

                        }
                    }

                } 
           EmailNotification -Mail_body $Mail_body
           } 
        
       
    }
        
}


Для запуска определяем входящие параметры и запускаем проверку.

#Провериь каталог: не привышает ли он размер в 1 Гб
$GB = 1073741824
$dir = "D:\Program Files"
Check-Size-Directory -dir $dir -GB 107374 -Logpath "D:"


Результат проверки сообщение на почту:

Тема: DirSize: 11/27/2015 11:32:05
Дата: 27 Nov 2015 11:32:05 +0200
От: sizefoldres@gmail.com
Кому: levitskaks@gmail.com

Размер каталога F:\Shared\PrivateData\BRU превышает размер в 1 Гб.
Размер каталога F:\Shared\PrivateData\BRU составляет 1239.06250095367 Мб.


Размер каталога F:\Shared\PrivateData\Danпревышает размер в 1 Гб.
Размер каталога F:\Shared\PrivateData\Dan составляет 1670.62088680267 Мб.


Размер каталога F:\Shared\PrivateData\DYA превышает размер в 1 Гб.
Размер каталога F:\Shared\PrivateData\DYA составляет 7456.12028884888 Мб.


Размер каталога F:\Shared\PrivateData\GLU превышает размер в 1 Гб.
Размер каталога F:\Shared\PrivateData\GLU составляет 2198.93785953522 Мб.



Содержимое файла 0.log:

ActiveX|2.8662109375
AvPinTool|0.5712890625
BDE|10.4070873260498
<b>drivers|6.512216567993</b>
Drv for SecureТoken 337|0.129350662231445
eclipse-standard-kepler-SR2-win32|545.861120223999
flash|122.166826248169
FTP_Drive|0.252327919006348
Install|431.435597419739
Jabber|55.9909982681274
LibreOffice_4_3_4|215.234375
Liga9|336.688585281372
Mail (address_book)|0.141551971435547
nkicntInit|0.166786193847656
powershell_3.0|14.0534420013428
PowerShell_4_0|46.8222227096558
single|630.298968315125
Total Commander|6.67717361450195
WinImage|1.12846660614014
zabbix|1.37527465820313
Документация|0.584843635559
CSPKeyUtil.exe|0.89208984375
jdk-8u65-windows-i586.exe|181.22908782959
jre-8u65-windows-i586.exe|47.8077087402344
LimeActiveXCrypt.cab|5.14455604553223
npp.6.7.4.Installer.exe|7.59689044952393
SkypeSetupFull_6.21.exe|34.3624038696289
winapcupsd-3.14.12.exe|5.84123229980469


Содержимое файла 1.log:

ActiveX|2.8662109375
AvPinTool|0.5712890625
BDE|10.4070873260498
<b>drivers|276.512216567993</b>
Drv for SecureТoken 337|0.129350662231445
eclipse-standard-kepler-SR2-win32|545.861120223999
flash|122.166826248169
FTP_Drive|0.252327919006348
Install|431.435597419739
Jabber|55.9909982681274
LibreOffice_4_3_4|215.234375
Liga9|336.688585281372
Mail (address_book)|0.141551971435547
nkicntInit|0.166786193847656
powershell_3.0|14.0534420013428
PowerShell_4_0|46.8222227096558
single|630.298968315125
Total Commander|6.67717361450195
WinImage|1.12846660614014
zabbix|1.37527465820313
Документация|205.584843635559
CSPKeyUtil.exe|0.89208984375
jdk-8u65-windows-i586.exe|181.22908782959
jre-8u65-windows-i586.exe|47.8077087402344
LimeActiveXCrypt.cab|5.14455604553223
npp.6.7.4.Installer.exe|7.59689044952393
SkypeSetupFull_6.21.exe|34.3624038696289
winapcupsd-3.14.12.exe|5.84123229980469


Результат сравнения двух файлов:

Резкое увеличение размера каталога: D:\Program Files\drivers
Размер на прошлой неделе составил: 6.512216567993Мб.
Размер на текущей неделе составил: 276.512216567993 Мб.

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

Спасибо за внимание.

Комментарии (11)


  1. IvanGalavachov
    02.12.2015 01:43
    +7

    «habracut» поставьте. Ну. пожалуйста!
    image


    1. JunJa
      02.12.2015 09:35
      +1

      Извиняюсь. Поставила :)


      1. IvanGalavachov
        02.12.2015 09:56

        Благодарю.


  1. izac
    02.12.2015 05:45
    +2

    Код и содержание файлов под спойлер-бы.


  1. Dal
    02.12.2015 07:49
    +1

    И все бы еще одним архивчиком выложить.


  1. gotch
    02.12.2015 09:17

    Несколько вопросов — почему не FSRM и почему не Send-MailMessage?
    К слову, метод будет не точен, если встретятся файлы с длиной имени >254 символов. Это же Powershell. )


    1. JunJa
      02.12.2015 09:41
      +1

      Send-MailMessage используется, просто не в данной задаче.

      Каталоги с длиной более 254 символов не встречались. Но если таковые появятся проанализирую такую ситуацию и дополню скрипт.


      1. gotch
        02.12.2015 10:21

        А вы с ними ничего не сделаете. Либо бегать вокруг alphafs.alphaleonis.com, либо poshcode.org/2488, либо robocopy.


        1. n01d
          02.12.2015 10:41

          Очень даже сделаете. Если брать решение на чистом PowerShell, то самый простой вариант — проверять длину пути на каждом шаге и, при превышении определённой отметки (например, 200 символов), монтировать PSDrive на этот путь и дальше работать с ним.


          1. gotch
            02.12.2015 11:17

            Да, это известный костылик, но как-то совсем не $True


  1. n01d
    02.12.2015 10:49

    Функция не унивирсальная, подстроена под задачу.
    Можно сделать гораздо короче и универсальнее при использовании Send-MailMessage (да даже и с вашей функцией можно, при желании) и splatting.
    Планирую как раз написать статью на эту тему.

    Сохраняем имя каталога и его размер через разделитель "|", в последствии через который будем парсить содержимое файла.
    Но зачем? Почему бы не строить красивый PSObject и выгружать его сразу в CSV? С ним потом и работать проще…