четверг, 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 на запись

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


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

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

Аудит представляет собой клиент-серверное приложение.

Сервер: MS SQL сервер, для хранения событий, с развернутым на нем Reporting Services, для отчетов аудита.

Клиент: Скрипт написанный на PowerShell который периодически просматривает встроенный журнал операций на файловых ресурсах, сортирует и конвертирует события в удобный формат. После чего подключается к серверной части (MS SQL server) и записывает в базу события.



Настройка Сервера:
Для работы необходимо создать Базу данных на сервере MS SQL
Описывать данный процесс не имеет смысл, инструкция по грамотному созданию баз данных на MS SQL сервере достойна отдельной статьи.
Перейдем сразу к вводным, есть MS SQL сервер "prm-test-sql" и база "audit_adm"

Перейдем к созданию рабочей таблицы в базе, для облегчения процедуры я подготовил пару запросов, которые необходимо выполнить в базе "audit_adm"

CREATE TABLE  audit_fs ( Ind int IDENTITY Primary Key, SubjectUserName nchar(100) COLLATE Cyrillic_General_CI_AS,  IpAddress char(20) ,ShareName nchar(100) COLLATE Cyrillic_General_CI_AS, ShareLocalPath nchar(250) COLLATE Cyrillic_General_CI_AS, RelativeTargetName nchar(2048) COLLATE Cyrillic_General_CI_AS, AccessMask char(20),DateEvent DateTime,SRV char(100));
CREATE INDEX ShareName ON audit_fs (ShareName)

Запрос создаст специально подготовленную таблицу для работы с клиентом (записи событий)
С настроенными колонками и индексами для оптимальной работы базы с отчетами.
Под итожим: сервер "prm-test-sql", база "audit_adm", таблица "audit_fs"

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


Запрос для обрезания логов на 180 дей:
delete From [audit_adm].[dbo].[audit_fs]  where DateEvent <= cast (dateadd (day, -180, GETDATE()) as DATE)

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