Нужно оживить паблик, поэтому немного административных скриптов.

1. Получить сетевые настройки и конфиги доменных компов
2. Поменять шлюз по умолчанию на доменных компах
3. Получить статистику по почтовым ящикам

1. Получить сетевые настройки и конфиги доменных компов.


Обходит доменные компьютеры и собирает с них информацию. На выходе выбрасывается полноценный объект. Компьютер должен быть включен конечно же. Сценарий содержит пример работы через WMI. Запускать с домена.

# запрашиваем кредиталы доменного админа
$cred = Get-Credential
<anchor>habracut</anchor>
$Clients = Get-ADComputer -Filter * | Sort-Object name | Select-Object name
$CompData = @()

foreach ($cli in $Clients)    {
    if (( Test-Connection $cli.Name -Count 2 -Quiet ) -eq 'True')       {
        if ($cli.name -ne $env:COMPUTERNAME)        {
            #получаем информацию по WMI
            $os = Get-WmiObject -ComputerName $cli.name Win32_OperatingSystem -Credential $cred
            $net = Get-WmiObject -Class Win32_NetWorkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName $cli.name  -Credential $cred
            $nic = Get-WmiObject -Class Win32_NetWorkAdapter -ComputerName $cli.name  -Credential $cred | where {$_.adaptertype -eq 'Ethernet 802.3'} | where { $_.NetEnabled -eq 'True'}
            $disk = Get-WmiObject -Class Win32_DiskDrive -ComputerName $cli.name -Credential $cred 

            $props = [ordered]@{ Name=$os.CSName
                        OSName=$os.Caption
                        OSSN=$os.SerialNumber
                        OSVersion=$os.Version
                        OSSystemDirectory=$os.SystemDirectory
                        OSBuild=$os.BuildNumber
                        OSMUI=$os.MUILanguages
                        OSBootDevice=$os.BootDevice
                        NICNetConnectionID=$nic.NetConnectionID
                        NICName=$nic.Name
                        NICDeviceID=$nic.DeviceID
                        NICAdapterType=$nic.AdapterType
                        NICIndex=$nic.Index
                        NICInterfaceIndex=$nic.InterfaceIndex
                        NICMAC=$nic.MACAddress
                        NICManufacturer=$nic.Manufacturer
                        NICNetEnabled=$nic.NetEnabled
                        NICPhysical=$nic.PhysicalAdapter
                        NICProductName=$nic.ProductName
                        NICServiceName=$nic.ServiceName
                        NICSpeed=$nic.Speed
                        NetDHCPEnabled=$net.DHCPEnabled
                        NetIPAddress=$net.IPAddress
                        NetDefaultGateway=$net.DefaultIPGateway
                        DiskName=$disk.Caption 
                        DiskStatus=$disk.Status 
                        DiskDeviceId=$disk.deviceid 
                        DiskSerialNumber=$disk.serialnumber 
                        DiskSize=$disk.size 
                        }

            $obj = New-Object -TypeName PSObject -Property $props
            $CompData += $obj
        }
    }
}

$CompData

2. Поменять шлюз по умолчанию


Модифицируем предыдущий скрипт так чтобы он менял шлюз по умолчанию. (обязательно все проверяйте в своей среде перед запуском на живой системе!) Использует в для смены шлюза вызовы WMI т.к. через повершелл нужно удалить и снова создать адаптер, что приведет к потери связи с компьютером. Проверялся на Powershell 4 и 3, win 2012 и 8.

$cred = Get-Credential

$OldGateway = '192.168.30.1'
$NewGateway = '192.168.30.50'

$Clients = Get-ADComputer -Filter * | Sort-Object name | Select-Object name
$CompData = @()

foreach ($cli in $Clients)
{
    if (( Test-Connection $cli.Name -Count 2 -Quiet ) -eq 'True')
    {
        if ($cli.name -ne $env:COMPUTERNAME)
        {
            $os = Get-WmiObject -ComputerName $cli.name Win32_OperatingSystem -Credential $cred
            $net = Get-WmiObject -Class Win32_NetWorkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName $cli.name  -Credential $cred
            $nic = Get-WmiObject -Class Win32_NetWorkAdapter -ComputerName $cli.name  -Credential $cred | where {$_.adaptertype -eq 'Ethernet 802.3'} | where { $_.NetEnabled -eq 'True'}
            $disk = Get-WmiObject -Class Win32_DiskDrive -ComputerName $cli.name -Credential $cred 

            $props = [ordered]@{ Name=$os.CSName
                        OSName=$os.Caption
                        OSSN=$os.SerialNumber
                        OSVersion=$os.Version
                        OSSystemDirectory=$os.SystemDirectory
                        OSBuild=$os.BuildNumber
                        OSMUI=$os.MUILanguages
                        OSBootDevice=$os.BootDevice
                        NICNetConnectionID=$nic.NetConnectionID
                        NICName=$nic.Name
                        NICDeviceID=$nic.DeviceID
                        NICAdapterType=$nic.AdapterType
                        NICIndex=$nic.Index
                        NICInterfaceIndex=$nic.InterfaceIndex
                        NICMAC=$nic.MACAddress
                        NICManufacturer=$nic.Manufacturer
                        NICNetEnabled=$nic.NetEnabled
                        NICPhysical=$nic.PhysicalAdapter
                        NICProductName=$nic.ProductName
                        NICServiceName=$nic.ServiceName
                        NICSpeed=$nic.Speed
                        NetDHCPEnabled=$net.DHCPEnabled
                        NetIPAddress=$net.IPAddress
                        NetDefaultGateway=$net.DefaultIPGateway
                        DiskName=$disk.Caption 
                        DiskStatus=$disk.Status 
                        DiskDeviceId=$disk.deviceid 
                        DiskSerialNumber=$disk.serialnumber 
                        DiskSize=$disk.size 
                        }

            $obj = New-Object -TypeName PSObject -Property $props

            $CompData += $obj
        }
    }
}

#$CompData
################################################################

# Меняем шлюз
foreach($Co in $CompData) {
         if ($Co.NetDefaultGateway = $OldGateway)       {
            $Co.Name
            $Co.netdefaultgateway

            $NWCards = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $co.Name -Credential $cred | where{ $_.ipenabled -eq $true }
            foreach ($nwc in $NWCards)       {
                $gateway = $nwc.defaultipgateway
                if ($gateway -eq $OldGateway)       {
                    $nwc.setgateways($NewGateway)
                }
            }
         }
}

3. Получить статистику по почтовым ящикам


Собирает статистику топ ящиков по размеру, топ ящиков по количеству писем, топ ящиков по удаленым айтемам (purge корзины 2 еще не произошел, только удаление писем пользователем), после формирует «красивый» отчет в HTML и отправляет на почту и складывает в папочку. Использовался как ежемесячный репортер состояния базы, устанавливался в таск шедалер. Запускать на сервере exchange. Проверялось на Exchange 2010.

<# 
    по умолчанию выбирает по 25 топ мэйлбоксов
    сохрание отчета на диск отключено
#>

Param (  [int]$TopCount = 25,
        [boolean]$SaveReport = $false,
        [string]$ReportPath = 'C:\Reports\MailboxReport.html',
        [boolean]$SendReport = $true,
        [string]$ReportMail1 = 'admin@mail.local'
    )

# check snapin present
$EX2010 = $false

$snaps = Get-PSSnapin
foreach( $snap in $snaps )  {
    if ($snap.Name -eq 'Microsoft.Exchange.Management.PowerShell.E2010')   {
        $EX2010 = $true
    }
}

if ($EX2010 -eq $false) {
    Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
}

$boxes = Get-Mailbox | Get-MailboxStatistics | sort TotalItemSize -Descending
$TotalSize = $boxes | sort TotalItemSize -Descending | select -First $TopCount

# самые толстые ящики
$Size = @()
foreach ($box in $TotalSize)  {
    $propsTotalSize = [ordered]@{   DisplayName=$box.DisplayName
                                    User=$box.LastLoggedOnUserAccount
                                    Database=$box.Database
                                    TotalSize=$box.TotalItemSize
                                    ItemCount=$box.ItemCount
                                    DeletedItemCount=$box.DeletedItemCount
                                    TotalDeletedSize=$box.TotalDeletedItemSize
                        }
            $obj = New-Object -TypeName PSObject -Property $propsTotalSize
            $Size += $obj
}

# топ удаленых без purge
$Deleted = $boxes | sort TotalDeletedItemSize -Descending | select -First $TopCount
$Del = @()
foreach ($box in $Deleted)   {
    $propsDeleted = [ordered]@{   DisplayName=$box.DisplayName
                                  User=$box.LastLoggedOnUserAccount
                                  Database=$box.Database
                                  TotalSize=$box.TotalItemSize
                                  ItemCount=$box.ItemCount
                                  DeletedItemCount=$box.DeletedItemCount
                                  TotalDeletedSize=$box.TotalDeletedItemSize
                        }
            $obj = New-Object -TypeName PSObject -Property $propsDeleted
            $Del += $obj
}

# топ по количеству писем, слишком много индикатор что пользователь сваливает все в кучу и нуждается в автоматических правилах
$Top = $boxes | sort ItemCount -Descending | select -First $TopCount
$TopItems = @()
foreach ($box in $Top)  {
    $propsTopItems = [ordered]@{   DisplayName=$box.DisplayName
                                   User=$box.LastLoggedOnUserAccount
                                   Database=$box.Database
                                   TotalSize=$box.TotalItemSize
                                   ItemCount=$box.ItemCount
                                   DeletedItemCount=$box.DeletedItemCount
                                   TotalDeletedSize=$box.TotalDeletedItemSize
                        }
            $obj = New-Object -TypeName PSObject -Property $propsTopItems
            $TopItems += $obj
}

##### HTML generating
Write-Verbose 'HTML fragment producing'
$fragTopItems = $TopItems | ConvertTo-Html -As table -Fragment -PreContent '<h2>Топ ящиков по количеству писем (items count)</h2>' | Out-String
$fragTopSizes =     $Size | ConvertTo-Html -As table -Fragment -PreContent '<h2>Топ ящиков по размеру</h2>' | Out-String
$fragTopDelItems =   $Del | ConvertTo-Html -As table -Fragment -PreContent '<h2>Топ ящиков по удаленным письмам (purge еще не было)</h2>' | Out-String

Write-Verbose 'definiting CSS'
$head = @'
<style>
body { background-color:#ffffff; font-family:Tahoma; font-size:12pt; }
td, th { border:1px solid black; border-collapse:collapse; }
th { color:white; background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
table { font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif; font-size: 14px;
border-radius: 10px; border-spacing: 0; text-align: center; }
th { background: #BCEBDD; color: white; text-shadow: 0 1px 1px #2D2020; padding: 10px 20px; }
th, td { border-style: solid; border-width: 0 1px 1px 0; border-color: white; }
th:first-child, td:first-child { text-align: left; }
th:first-child { border-top-left-radius: 10px; }
th:last-child { border-top-right-radius: 10px; border-right: none; }
td { padding: 10px 20px; background: #F8E391; }
tr:last-child td:first-child { border-radius: 0 0 0 10px; }
tr:last-child td:last-child { border-radius: 0 0 10px 0; }
tr td:last-child { border-right: none; }
</style>
'@

Write-Verbose 'HTML producing'
$Date = Get-Date

if ($SaveReport = $true) {
    $rep = ConvertTo-HTML -head $head -PostContent $fragTopSizes, $fragTopDelItems, $fragTopItems -PreContent "<h1>Отчет по почтовым ящикам $Date</h1>" | Out-String
    $rep | Out-File $ReportPath
}

# Sending Email to admins
if ($SendReport = $true) {
    $encoding = [System.Text.Encoding]::UTF8
    $body = ConvertTo-HTML -head $head -PostContent $fragTopSizes, $fragTopDelItems, $fragTopItems -PreContent "<h1>Отчет по почтовым ящикам $Date</h1>" | Out-String

    Write-Verbose "Sending e-mail"
    $params = @{'To'=$ReportMail1
               'From'='bot@geomex.local'
               'Subject'="Mailbox report $Date"
               'Body'=$Body
               'BodyAsHTML'=$True
               'SMTPServer'='mail.domain.local'}
    Send-MailMessage @params -Encoding $encoding
}

Всех с майскими праздниками.
Поделиться с друзьями
-->

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


  1. AVX
    04.05.2017 09:10
    +3

    Более-менее полезно выглядит только по почтовым ящикам. Остальное — практически неработоспособное решение. Мало того, что «запускать с домена» (что это? с КД запускать чтоли??), так и куча недоработок, которые суммарно не позволят это использовать. Про смену шлюза через доменный скрипт вовсе промолчу — неужто хочется в случае ошибок бегать и менять настройки на сотнях-тысячах компах?
    Подробнее могу про первый подсказать:
    1. Нет смысла собирать информацию с компьютеров, без сброса её в какую-либо базу, или хотя бы текстовый файл. Компьютер может быть выключен, и информации по нему не будет. Поэтому, правильнее сделать список ПК в файле, и периодически прогонять скрипт, пополняя файл данными (ну или базу, если есть).
    2. Нет никакой обработки ошибок. У меня используется подобный скрипт, правда запускаю на своём ПК (учётка имеет адм.права на всех ПК из списка). Так вот, при более чем 3-летней эксплуатации и постоянного «допиливания» выяснилось, что компьютер может быть выключен (нужно периодически опрашивать и дозаписывать отсутствующие данные в файл или базу), на компьютере может не работать WMI (это серьёзные проблемы, и нужно решать, для этого ошибки отлавливать и записывать в лог), на компьютере может даже не работать RPC (при доступности по пингу), и до компьютера могут быть перекрыты какие-либо порты на сетевом оборудовании. Да и много других может быть ошибок, и в некоторых случаях они будут критическими, и скрипт не отработает как надо или запишет в базу мусор. Поэтому используем $ErrorActionPreference, trap и в нужных случаях меняем поведение при обработке.
    3. Мелочь, но: ненужные данные зачем собирать? К примеру, объект $disk будет содержать и всякие картридеры, встроенную память на принтерах, подключенные флешки и прочее. Как минимум можно сделать что-то типа if ($disk.mediatype.Contains(«Fixed») -and ($disk.Size -gt 0)). К тому же объект $disk может оказаться массивом (дисков несколько), и DiskName=$disk.Caption даст ошибку, их нужно всегда перебирать в цикле foreach. (это же и процессоров касается). Да и вместо caption диска лучше взять model (если нужны всё-таки fixed диски).

    Но в качестве заготовки скрипты конечно пойдут, каждый допилит под себя.


  1. pak-nikolai
    04.05.2017 09:40

    обычно перед использованием таких штук надо подумать

    вы кстати как WMI включаете через политики?


  1. brainfair
    04.05.2017 09:49
    +2

    1. Лучше в логон скрипты запихать и логировать в тот же файл.
    2. Тоже самое.
    3. три команды выпелено в большущий скрипт. В Гет-маилбоксес добавте анлимитед.

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


  1. iborzenkov
    04.05.2017 11:49
    +1

    Тут уже высказались выше по поводу всего этого.
    Я хочу спросить по поводу шлюза — чем же вам так не понравился DHCP?


    1. pak-nikolai
      04.05.2017 12:21

      ну надо было, такая задача была. адреса на некоторых машинах были статические


      1. iborzenkov
        04.05.2017 13:37

        Ну так как-бы если на некоторых то это решается привязкой mac-ip


  1. helgisbox
    04.05.2017 13:29

    Больше 12 лет использую WMI как средство администрирования по части сбора и анализа различной статистики с кучи серверов. Был случай, когда экстренно с полуторатысячи клиентских мест он помог собрать нужные сведения.

    Но, надо сказать, никогда не решался скриптом разом и без логгирования править настройки на куче мест. Лень-то она конечно двигатель прогресса, но не все же мы самураи. Преклоняюсь перед «смелостью» автора.


    1. pak-nikolai
      04.05.2017 13:30

      если кто запустит просто так этот скрипт будет конечно атомно ))) поменяется шлюз на ВСЕХ машинах кроме контроллера )))
      ну я думаю что кто на это пойдет настроит фильтр на get-adcomputers


      1. helgisbox
        04.05.2017 13:44

        Скриптам и программам доверяю больше, чем людям, себе же — из всех людей — меньше всего. Потому как себе любимому больше всего позволяю. И поэтому, допустить выполнение действия, которому не придумал отката — не реализую. Иногда бывает помутнение рассудка и можешь просто перепутать. Все мы люди. Хотя все это специфично ;) Если сбить пароль, или настройки кроме сетевых — можно еще раз запустить скрипт и внести изменения обратно. А вот с сетевыми настройками — тут как гильотниа — голова отлетает и обратно ее не пришьешь, если только ножками все не оббежать.