среда, 30 мая 2018 г.

Выгрузка членов групп (более 1500)/ export members tools

Инструмент имеет простенький интерфейс и уже готов к работе без доп. модулей для PS
Сохраните скрипт ( [любое имя].ps1 ) в директорию доступную для записи и выгружайте на здоровье. :)

Поиск групп осуществляется по началу имени группы, если потребуется выгрузить членов по нескольким группам, просто укажите начало имени групп и скрипт найдет все. После чего выгрузит по каждой группе в отдельную [имя группы].csv в директории скрипта.

ЗЫ. Для ускорения поиска групп можно указать OU в которой будет выполнятся поиск в переменной LDAP_DIR в самом начале в в виде LDAP пути (пример: "LDAP://OU=[my OU],DC=[my DC]" ).

$LDAP_DIR = ""

###Функция для получения членов групп более 1500
function Get_MemGr {
$AdsPath = [string]$Args
$range = -1
$GroupMember =$Null
Do {
$range += 15
$Filter = "(objectClass=*)"
$Properties = "member;range=" + ($range - 14) + "-" + $range
$Searcher = New-Object DirectoryServices.DirectorySearcher($AdsPath, $Filter, $Properties, "Base")
$Group = $Null
$Group = $Searcher.FindOne().Properties
[string]$NameVal = ($Group.PropertyNames -match "member")
if ( $Group -ne $null){$GroupMember += $Group.$NameVal}
} While ( $Group -ne $null )
return $GroupMember
}
###


########

For($Flag_end -eq 'end'){
Clear-Host
Write-Host "Добро пожаловать`nУтилита для выгрузки пользователей и из группы`nГотова к работе" -ForegroundColor green
if ($LDAP_DIR -ne ""){Write-Host "Сканируемая директория:" ($LDAP_DIR -replace "LDAP://" -replace ",DC=.+$" -replace "^.+=")}ELSE{Write-Host "Сканируемая директория: Весь домен" }
Write-Host "Директория для выгрузки:" (%{(Get-Location).Path})
Write-Host "Введите имя группы или начало её имени" -ForegroundColor yellow
$PRX = Read-Host

#Выход если введена переменная выхода
if ($PRX -eq 'end' -or $PRX -eq '*' -or $PRX -eq " " -or $PRX -eq ""){exit}

###################################

$search = New-Object system.DirectoryServices.DirectorySearcher
if ($LDAP_DIR -ne ""){$search.SearchRoot = $LDAP_DIR}
$search.Filter = "(&(objectCategory=Group)(cn=$PRX*))"
$search.PageSize = 100000
$Group_list = $search.Findall() | %{$_.path}
if($Group_list.Count -ne 0){
$Count_members = 0

foreach($GRP in $Group_list){

$Members = $Null
$Name_Group = $GRP -replace 'LDAP://CN=' -replace '[(].+$' -replace ',OU.+$'
Write-Host "\\" $Name_Group
$PATH = ".\" + $Name_Group + ".csv"
$Members = Get_MemGr $GRP
$Count_members = $Members.count

For([INT]$IND=0;$IND -lt $Members.Count;$IND++){
$ADobj = 'LDAP://' + $Members[$IND]
$ADobj =[ADSI] $ADobj
[string]$Members[$IND] = $ADobj.name + ';' + $ADobj.sAMAccountName + ';' + $ADobj.mail + ';' + $ADobj.company + ';'+ $ADobj.department + ';' + $ADobj.title + ';' + $ADobj.l + ';' + $ADobj.streetAddress + ';' + $ADobj.physicalDeliveryOfficeName
$Count_members--
Write-Host $Count_members : $ADobj.name
}

Set-Content -Path $PATH -Value $Members
sleep 2
}

}

}

воскресенье, 19 марта 2017 г.

четверг, 2 июня 2016 г.

Проверка запуска приложения / Application start check

#проверка запуска приложения
#Уведомление по почте о закрытие и запуске приложения

#Имя хоста
$hosted = [Сервер приложения]
#Имя процесса без расширения! (без ".exe")
$app = [Имя приложения]
#Получатели
$recipiens = [Адрес получателя уведомлений]
$Sender = [Адрес отправителя уведомлений]
$SMTP_SRV = [Почтовый сервер]

#######################################################
$encoding = ([System.Text.Encoding]::Unicode)

$TEST_PROCESS = $NULL
$TEST_PATH_BAD = $NULL
$TEST_PATH_GOD = $NULL

#Пути для флагов закрытия и открытия приложения
$TEST_PATH_BAD = ($env:TMP + '\' + $hosted + '_' + $app + '.BFL')
$TEST_PATH_GOD = ($env:TMP + '\' + $hosted + '_' + $app + '.GFL')

        #Бесконечный цикл проверки с интервалом 30 сек
        Do{

$TEST_PROCESS = Get-Process -ComputerName $hosted -name $app

IF ( ($TEST_PROCESS -eq $NULL) -AND ((Test-Path -Path $TEST_PATH_BAD) -eq $False) ){
send-mailmessage -smtpServer $SMTP_SRV -Encoding ([System.Text.Encoding]::Unicode) -to $recipiens -from $Sender -subject "Внимание! Приложение не запущено" -body ("Зафиксировано закрытие приложения" + "`nСервер: " + $hosted + "`nПриложение: " + $app + "`n`nВременной штамп: " + (Get-Date -UFormat "%d.%m.%Y - %H:%M:%S") )

#Установка флага, приложение не запущено
Set-Content -Path $TEST_PATH_BAD -Value (get-date)
Remove-Item -Force -Path $TEST_PATH_GOD
}ELSEIF( ($TEST_PROCESS -ne $NULL) -AND ((Test-Path -Path $TEST_PATH_GOD) -eq $False) ){
send-mailmessage -smtpServer $SMTP_SRV -Encoding ([System.Text.Encoding]::Unicode) -to $recipiens -from $Sender -subject "Приложение успешно запущено" -body ("Зафиксирован запуск приложения" + "`nСервер: " + $hosted + "`nПриложение: " + $app + "`n`nВременной штамп: " + (Get-Date -UFormat "%d.%m.%Y - %H:%M:%S") )


#Установка флага, приложение запущено
Set-Content -Path $TEST_PATH_GOD -Value (get-date)
Remove-Item -Force -Path $TEST_PATH_BAD
}


sleep 30
    }While($Stop_Flag -eq $NUll)





Получить атрибуты пользователя / Get user attributes

#Функция поиска уч записи по логину и возврат её атрибута
Function Search_login {
    $dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
    $root = $dom.GetDirectoryEntry()
    $search = [System.DirectoryServices.DirectorySearcher]$root
    $search.Filter = "(sAMAccountName=$args)"
    $obj=[ADSI] ($search.FindAll() | %{$_.path})
    #возвращаемый атрибут Name
    [string]$obj.Name
}

#Вызов функции
Search_login [Лоин]

четверг, 26 мая 2016 г.

PowerShell модуль для SQL / PowerShell module for SQL

Добрый день

В этой записе я хочу представить модуль для PowerShell для работы с базами данных, такие как SQL

Все что требуется для работы этого модуля это установлены на компьютер framework не ниже 3.5 и просто подгрузив его в консоль PowerShell или в отдельный скрипт мы получим возможность работы с SQL базами.

Скопируйте и сохраните код в текстовый файл, например SQLDataTools, с расширением psm1

Код модуля:
    function Get-DatabaseData {
        [CmdletBinding()]
        param (
            [string]$connectionString,
            [string]$query,
            [switch]$isSQLServer
        )
        if ($isSQLServer) {
            Write-Verbose 'in SQL Server mode'
            $connection = New-Object System.Data.SqlClient.SqlConnection
        } else {
            Write-Verbose 'in OleDB mode'
            $connection = New-Object System.Data.OleDb.OleDbConnection
        }
        $connection.ConnectionString = $connectionString
        $command = $connection.CreateCommand()
        $command.CommandText = $query
        if ($isSQLServer) {
            $adapter = New-Object System.Data.SqlClient.SqlDataAdapter $command
        } else {
            $adapter = New-Object System.Data.OleDb.OleDbDataAdapter $command
        }
        $dataset = New-Object System.Data.DataSet
        $adapter.Fill($dataset)
        $dataset.Tables[0]
    }
    function Invoke-DatabaseQuery {
        [CmdletBinding()]
        param (
            [string]$connectionString,
            [string]$query,
            [switch]$isSQLServer
        )
        if ($isSQLServer) {
            Write-Verbose 'in SQL Server mode'
            $connection = New-Object System.Data.SqlClient.SqlConnection
        } else {
            Write-Verbose 'in OleDB mode'
            $connection = New-Object System.Data.OleDb.OleDbConnection
        }
        $connection.ConnectionString = $connectionString
        $command = $connection.CreateCommand()
        $command.CommandText = $query
        $connection.Open()
        $command.ExecuteNonQuery()
        $connection.close()
    }


Что бы подгрузить модуль используйте командлет
Import-Module (" [путь к файлу] \SQLDataTools.psm1")

А так же переменные и готовые функции для выполнения различных запросов
$SQl_Server = 'prm-test-sql'
$SQLDateBase = 'audit_adm'

#функция выполнения запроса на SQL сервере
function SET_Query {Invoke-DatabaseQuery -verbose -connectionString ('Server=' + $SQl_Server + ';Database=' + $SQLDateBase + ';Trusted_Connection=True;') -isSQLServer -query $args[0]} 
#Функция получения данных от SQL сервера
function GET_Query {Get-DatabaseData -connectionString  ('Server=' + $SQl_Server + ';Database=' + $SQLDateBase + ';Trusted_Connection=True;') -isSQLServer -Query $Args[0]}

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

GET_Query 'select TOP 10 * From Audit_adm.dbo.Audit_fs'

SET_Query 'delete From Audit_adm.dbo.Audit_fs where DateEvent <= cast (dateadd (day, -180, GETDATE()) as DATE)'




Расшифровка AccessMask в событиях аудита файловых ресурсов


Для 2012 Windows

Чтение
  <Data Name="AccessMask">0x100080</Data>

Удаление
  <Data Name="AccessMask">0x10080</Data>

Запись
  <Data Name="AccessMask">0x2</Data>

Переименование (Перемещение) куда
  <Data Name="AccessMask">0x100180</Data>

Переименование (Перемещение) откуда
  <Data Name="AccessMask">0x110080</Data>

Для 2008 Windows

'0x12019f', Запись
'0x20',Переименование (Перемещение) куда
'0x110080', Переименование (Перемещение) откуда
'0x10080', Удаление

ч2. Аудит сетевых файловых ресурсов / Audit network file shares

 Добрый день, в этой заметке пойдет речь о второй части централизованном аудите сетевых файловых ресурсах в большой организации.
Клиентская часть

Первым делом необходимо включить ведение штатного аудита объектов в локальной политике файлового сервера:
 Вызываем консоль "Локальных политик" командой "gpedit.msc"
WIN+R >> вставить "gpedit.msc" >> ввод

По пути
– Computer Configuration
  – Windows Settings
     – Security Settings
        – Local Policies
           – Audio Policy
                 – Audit object Access
необходимо установить флаг Success.




Создаем папку с путем "C:\Scripts\"
В ней текстовый файл с именем, например audit_shared и расширением "ps1"
в него необходимо записать следующий код и сохранить

#Что бы сразу начать загружать события установим время начала загрузки событий -1 секунду с момента запуска

$Start_Time = (Get-Date).AddSeconds(-1)
#Необходимо получить версию ОС, так как на 2008 и 2012 журналы событий ведутся по #разному
$OS = (Get-WmiObject Win32_OperatingSystem).version


#Вводные переменные, сервер база и тп., последняя строчка преобразует все в правильный вид
$SQl_Server = 'prm-test-sql'
$SQLDateBase = 'audit_adm'
$BD_Table = 'audit_fs'
$BD_Table = $SQLDateBase + '.dbo.' + $BD_Table

#Подгружаем модуль для работы с SQL, про него можно прочитать тут
Import-Module ("C:\Scripts\SQLDataTools\SQLDataTools.psm1")

#Описываем функцию запросов к базе, что бы упростить структуру скрипта
function Query {Invoke-DatabaseQuery -verbose -connectionString ('Server=' + $SQl_Server + ';Database=' + $SQLDateBase + ';Trusted_Connection=True;') -isSQLServer -query $args[0]}

#Описываем функцию которая будет непосредственно загружать  события в базу
function Create_Query {
$STR_Q = $Null
[string]$STR_Q = 'INSERT INTO ' + $BD_Table + ' (SubjectUserName,IpAddress,ShareName,ShareLocalPath,RelativeTargetName,AccessMask,DateEvent,SRV) VALUES (N''' + $args[0] + ''',''' + $args[1] + ''',N''' + $args[2] + ''',N''' + $args[3] + ''',N''' + $args[4] + ''',''' + $args[5] + ''',''' + $args[6] + ''',''' + $args[7] + ''') ;'
Query $STR_Q
}


#Запускаем цикл загрузки и обработки событий из журнала Security с ID 5145
        Do{

$Events= $NUll
# Загрузка событий журнала, в зависимости от ОС. Маски указаны в запросе
if( $OS -match '6.1'){$Events = Get-WinEvent -FilterHashtable @{LogName="Security";ID=5145;StartTime=$Start_Time;Data="0x12019f","0x20","0x110080","0x10080"} }
if( $OS -match '6.3'){$Events = Get-WinEvent -FilterHashtable @{LogName="Security";ID=5145;StartTime=$Start_Time;Data="0x10080","0x2","0x100180","0x110080"} }


    #######################
    If ($Events -ne $Null){

#####
foreach ($Event in $Events){
if ($Events[0] -ne $Null) {
#$Start_Time = (($Events[0]).TimeCreated).AddMilliseconds(1)

$Start_Time = (($Events[0]).TimeCreated).AddMilliseconds(1)
$Start_Time = (($Start_Time).DateTime + '.' + ($Start_Time.Millisecond))

}

$AccessMask = $NUll
$AccessMask = [string](($Event.ToXml() -split "</Data>" | where {$_ -match "AccessMask"}) -replace "^.+>")

$SubjectUserName = $NUll
$IpAddress = $NUll
$ShareName = $NUll
$ShareLocalPath = $NUll
$RelativeTargetName = $NUll


$SubjectUserName = [string](($Event.ToXml() -split "</Data>" | where {$_ -match "SubjectUserName"}) -replace "^.+>")
$IpAddress = [string](($Event.ToXml() -split "</Data>" | where {$_ -match "IpAddress"}) -replace "^.+>")
$ShareName = [string](($Event.ToXml() -split "</Data>" | where {$_ -match "ShareName"}) -replace "^.+>")
$ShareLocalPath = [string](($Event.ToXml() -split "</Data>" | where {$_ -match "ShareLocalPath"}) -replace "^.+>")
$RelativeTargetName = [string](($Event.ToXml() -split "</Data>" | where {$_ -match "RelativeTargetName"}) -replace "^.+>")

$ShareLocalPath = $ShareLocalPath -replace '\\..\\'
$ShareName = $ShareName -replace "[\\*]"

    #условие исключающее не нужные сетевые ресурсы, а также логины пользователей
    if(($ShareName -ne 'IPC$') -and ($SubjectUserName -notmatch "s-")) {

        #Условие исключающее служебные файлы
        if ( ($RelativeTargetName -notmatch "Thumbs.db") -and ($RelativeTargetName -notmatch ".*tmp") -and ($RelativeTargetName -notmatch ".*~$*") -and ($RelativeTargetName -notmatch ".*~lock*")) {
          
            #У каждого события в журнале есть Маска, именно они определяют, что произошло с объектом. Расщифровку можно посмотреть тут
            #Расшифровка масок, в зависимости от ОС
            if( $OS -match '6.1'){$AccessMask = $AccessMask -replace '0x10080','delete' -replace '0x12019f','write' -replace '0x20','moveTo' -replace '0x110080','moveFrom' }
            if( $OS -match '6.3'){$AccessMask = $AccessMask -replace '0x10080','delete' -replace '0x2','write' -replace '0x100180','moveTo' -replace '0x110080','moveFrom' }
          
          
            Write-Host (($Event.TimeCreated).DateTime + ":" + ($Event.TimeCreated).Millisecond) $SubjectUserName $ShareName\$RelativeTargetName $AccessMask

            Create_Query $SubjectUserName $IpAddress $ShareName $ShareLocalPath $RelativeTargetName $AccessMask $Event.TimeCreated $env:computername

        }

  
    }
}

    }
    #######################

#Удаление старых записей старше 180 дней
#Query ('delete From ' + $BD_Table + ' where DateEvent <= cast (dateadd (day, -180, GETDATE()) as DATE)')
echo ("==" + $Start_Time + ":" + $Start_Time.Millisecond)
#Пауза 10 сек перед новым проходом
sleep 10
    }While($Stop_Flag -eq $NUll)

После чего, создаем задание в Task Scheduler с расписание после старта компьютера
 

Не мало важно учесть при этом от какой уч записи будет выполнятся скрипт, так как этой уч записи необходим доступ к базе SQL на запись

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