Outputting Event Log Events to a Remote SQL Database Using ...SQL Database Using PowerShell...

19
1 | Page Peter McEldowney Mark Waddington | Capstone CSNT 255 Outputting Event Log Events to a Remote SQL Database Using PowerShell Objective: After completing this lab, the Administrator will have the Event Log from the computer of their choice uploading information to a SQL database. The step-by-step outlines how to create the tables that will be used to organize the data and will cover how to create a basic SQL script to create these tables. Within the script to create the tables, indexes will be covered to ensure quick access to the data by a particular column that is indexed and will also cover items to be aware of. After creating these tables, a script to upload the event log items to the SQL server will be created so that the script can be run from any machine to ensure scalability. After the script is created and tested, this step-by-step will go through how to create a trigger that will run the script whenever a new event log entry is created. Requirements: PowerShell 3.0, Microsoft SQL Server [w/ Management Tools] Step 1: Create a diagram of the tables that will be used to store the data Considerations when designing your tables: a) What data is available? b) How will you identify the machine once the data is in the database? c) What log did the data come from and how will this be stored in the database? d) Is there an efficient way to organize the data to make retrieving the data quicker? e) What columns will people be searching from? f) What should the Primary Keys for the table(s) be? g) What should the Foreign Keys be? What is a Primary Key? A primary key is basically an index number. This is the unique number that identifies a particular row. For example, if 2 rows have the same information, how would we identify which row is which? What is a Foreign Key? Foreign Keys refer to data from another table. These are primarily used to link tables. For example, say you have data in one table and the computer that uploaded the data in another. The foreign key in the data table would reference an identifying key in another so that the data can be linked to the associated machine.

Transcript of Outputting Event Log Events to a Remote SQL Database Using ...SQL Database Using PowerShell...

  • 1 | P a g e

    Peter McEldowney

    Mark Waddington | Capstone CSNT 255

    Outputting Event Log Events to a Remote

    SQL Database Using PowerShell

    Objective:

    After completing this lab, the Administrator will have the Event Log from the computer of their

    choice uploading information to a SQL database. The step-by-step outlines how to create the tables that

    will be used to organize the data and will cover how to create a basic SQL script to create these tables.

    Within the script to create the tables, indexes will be covered to ensure quick access to the data by a

    particular column that is indexed and will also cover items to be aware of. After creating these tables, a

    script to upload the event log items to the SQL server will be created so that the script can be run from

    any machine to ensure scalability. After the script is created and tested, this step-by-step will go through

    how to create a trigger that will run the script whenever a new event log entry is created.

    Requirements: PowerShell 3.0, Microsoft SQL Server [w/ Management Tools]

    Step 1: Create a diagram of the tables that will be used to store the data

    Considerations when designing your tables:

    a) What data is available? b) How will you identify the machine once the data is in the database? c) What log did the data come from and how will this be stored in the database? d) Is there an efficient way to organize the data to make retrieving the data quicker? e) What columns will people be searching from? f) What should the Primary Keys for the table(s) be?

    g) What should the Foreign Keys be?

    What is a Primary Key? A primary key is basically an index number. This is the unique number that identifies a particular row.

    For example, if 2 rows have the same information, how would we identify which row is which?

    What is a Foreign Key? Foreign Keys refer to data from another table. These are primarily used to link tables. For example,

    say you have data in one table and the computer that uploaded the data in another. The foreign key

    in the data table would reference an identifying key in another so that the data can be linked to the

    associated machine.

  • 2 | P a g e

    The tables and relationships that are being made are referred to as an Entity-Relation Diagram. Not only

    will creating this make building the SQL script to create the databases easier, but it will also allow for

    future database users to access the data efficiently and know what data is available.

    a) What data is available? The best way to identify the available data is by looking at the data. For

    example, using PowerShell, we can pull event log data and look at what is

    available.

    Try this command in PowerShell to find the available data:

    Ex: Get-EventLog –LogName System –Newest 1 | Format-List

    Now we must decide what information we want to log in our database.

    [Remember: Databases can grow to be massive so far large environment, it may be more efficient to

    only take critical information. In this tutorial, we will be uploading all information because we can.]

  • 3 | P a g e

    We can actually call specific values that are defined by incorporating the text before the pipe | within

    parenthesis () and then appending a period. to identify we want to call a value.

    Ex: (Get-EventLog –LogName System –Newest 1).Index

    Now since we have the information available, we can start grouping particular items together and

    deciding how we want to arrange everything.

    b) Identifying the original machine This can be done within the PowerShell script that will be created in Step 3.

    Try this command in PowerShell for a preview on how this will be accomplished.

    Ex: [Environment]::MachineName

    c) Identifying the originating system log Different logs are kept for different aspects of the system. For example, DNS has

    its own log. PowerShell has its own log, and so do System tasks. The available

    logs on a system can be obtain by running the following:

    Ex: Get-EventLog -LogName *

  • 4 | P a g e

    d) Organizing the Data for efficiency.

    This step all depends on the volume of data that will be stored within the database. For

    centralize Event Log management, it may be beneficial to store only EntryType,

    Message, Source, and Username within 1 table so that less data is retrieved when

    searching for errors.

    An example is portrayed below. Notice how only crucial information is stored in the

    primary table. All other data must be referenced by joining tables together by their

    similar keys (foreign keys).

    e) Frequent columns. Generally people will be searching for information based off specific columns.

    These columns (like name of the computer, the type of entry, source, etc) are

    columns that should contain indexes. An index is simply a tag put onto a column

    so that it is monitored for efficient data retrieval.

    One caution of using indexes is that every time new data is entered, the index

    must be re-evaluated. As you can imagine, this can cause a great deal of

    decreased performance and may even crash systems that are inadequate for

    supporting the amount of data being uploaded.

    Indexes are not required (and are not covered here) but are an important

    aspect to consider if deploying on a large scale as it is much easier to

    incorporate when designing than trying to implement during production.

    f) Primary Keys

    Primary key columns are (as described above) a unique identifying key. No 2

    primary keys in a table can be the same or the data would be inconsistent. This

  • 5 | P a g e

    is why it is best to create a special column for the primary key and set it to auto-

    increment. In the entity-relationship diagram below, you can see how columns

    with PK are identified with some sort of text that is followed by_id

    g) Foreign Keys FK’s should be easy to identify and associate with other tables. The most

    difficult part is coding Foreign Keys.

    One nice part about foreign keys is that you can set constraints on the data that

    is referenced. For example, if we use the code exemplified below, then when

    the referenced data in the other table is deleted, the delete is cascaded that the

    table with the foreign key and all associated data is also removed. This helps

    with normalization to ensure that all data that is stored is related to other data

    and is not just fluff data.

    evl_id_fk INT FOREIGN KEY (evl_id_fk) REFERENCES [evl_data] ON DELETE CASCADE

    Step 2: Create the Database Script [This script should be based off the information outlined in your Entity-Relationship Diagram]

    Considerations when creating the database script:

    a) Identify what type of data will be stored in each column. b) Are there any columns where data entry should be mandatory? c) What are the constraints on the table and how are these foreign keys identified in the script?

    Will a delete of data from one table cascade to the others?

    How to create a SQL database from a script:

    [Reference your diagram and use the tables below to help with data types and optional parameters]

  • 6 | P a g e

    The first item in order is to create the database. This can be done with CREATE DATABASE [dbname];

    You must then USE [dbname]; to work with the database. This is demonstrated on Page 7.

    Generic CREATE TABLE structure for Microsoft SQL Server (or T-SQL):

    CREATE TABLE [table_name]

    (

    [column_name] [data type] [optional parameters] [table delimitated by a comma , to indicate next column]

    index_number INT PRIMARY KEY IDENTITY,

    other_table_index INT FOREIGN KEY (other_column_name) REFERENCES [other_table_name],

    timestamp DATETIME NOT NULL,

    logname VARCHAR(50) NOT NULL,

    username VARCHAR(50)

    )

    What are Data Types?

    A data type is what is held by that particular variable, column, etc. For example, if a column will

    always hold a number, it will have INT (or integer) as its data type to limit what the cell can hold.

    A field can also have DECIMAL(9,2) (where 9,2 represents up to 9 numbers and 2 decimal

    points). Things like DATETIME are data types (DATE only stores the date but DATETIME stores

    both depending on your needs). These can be found very easily through a quick search for

    almost any programming language. Some of the most common data types for SQL are below:

    Syntax Data Type Meaning (remember, variables are a number of your choice)

    INT(n) Integer of n length An Integer is just a whole number (not a fraction)

    CHAR(n) n Characters This is a fixed length field of length n

    VARCHAR(n) Up to n Characters This is a variable length character field with a max length of n

    DECIMAL(n,d) Number with a decimal Use this data type to specify a number of length n with the

    number of decimal points to store as d

    DATE Only stores date This field stores month, day, and year. Nothing more

    DATETIME Stores date and time This field can store date and hour, minute, second, & split second

    There are many more but these should handle your needs for this task.

    What kind of optional parameters are available?

    Parameter Meaning

    PRIMARY KEY A reference number for a row (there cannot be 2 identical values of a primary key)

    IDENTITY(s,i) Indicates that the value should be auto-incremented for each new entry [default (1,1)]

    s = seed [or starting number], i = increment [the number the value goes up by]

    FOREIGN KEY

    (col_name)

    Identifies a relationship to another table

    (with constraints set, value must exist in another table)

    (col_name) references a column in another table

    REFERENCES

    [table_name]

    Comes after a Foreign Key to indicate the table that should be referenced when

    associating the row with another table.

    NOT NULL Specifies that a value must be entered into this column or an error will return.

    CONSTRAINT Indicates that this column is referenced by another table [see below for an example]

    I. Look at your Entity Relationship diagram and decide the data type for each field. The Entity Relationship diagram that has been converted into a SQL script to create tables:

  • 7 | P a g e

    The code for the servers, evl_primary, evl_data, and evl_timestamp table, would resemble:

    Note: These must be executed query by query in SQL Server Management Studio (as an Administrator).

    CREATE DATABASE server_event_logs;

    USE server_event_logs;

    CREATE TABLE [servers] (

    pc_id INT CONSTRAINT pc_id_fk PRIMARY KEY IDENTITY,

    pc_name VARCHAR(100) NOT NULL

    );

    CREATE TABLE [evl_primary] (

    evl_id INT CONSTRAINT evl_id_fk PRIMARY KEY IDENTITY,

    pc_id_fk INT FOREIGN KEY (pc_id_fk) REFERENCES [servers],

    entry_type VARCHAR(50) NOT NULL,

    message VARCHAR(1000) NOT NULL,

    source VARCHAR(100),

    username VARCHAR(100)

    );

    CREATE TABLE [evl_data] (

    data_id INT PRIMARY KEY IDENTITY,

    evl_id_fk INT FOREIGN KEY (pc_id_fk) REFERENCES [servers] ON DELETE CASCADE,

    index_id INT,

    category VARCHAR(100),

    category_num INT,

    replacement_str VARCHAR(100)

    );

    CREATE TABLE [evl_timest] (

    time_id INT PRIMARY KEY IDENTITY,

    evl_id_fk INT FOREIGN KEY (evl_id_fk) REFERENCES [evl_data] ON DELETE CASCADE,

    instance_id INT,

    time_gen DATETIME,

    time_written DATETIME

    );

  • 8 | P a g e

    II. Pay attention to columns that are defined with NOT NULL. These columns must ALWAYS have data inputted or the data entry will fail. This is to make monitoring data entry a

    minimal task.

    [Note: You can also code a database to upload error that happen in SQL but that is beyond

    the scope of this step-by-step.]

    III. Notice the placement of the ON DELETE CASCADE parameters. This means that if data is deleted from one of the associated tables, so will the entry in the evl_primary table. This

    makes removing an event log entry much easier as the database will do it automatically.

    IV. Also, notice the IDENTITY option for the primary keys. This option will auto-increment that column. How to perform this is explained in the table in the beginning of Step 2.

  • 9 | P a g e

    Step 3: Importing the proper SQL PowerShell module and testing connectivity

    The first component of this step is to understand how to manage SQL through PowerShell. Once SQL has

    been installed on a machine, the SQLPS module is made available. Let’s go ahead and import it:

    We can check all the available Cmdlet’s and functions that are available with the following cmdlet:

    Ex: Get-Command –Module SQLPS

    Now since we know what we can do, we must understand what we want to do. This will become

    more apparent the more you work with SQL as you will experience more applications for the various

    available cmdlets (notice how data backups, replication, and availability groups can all be automated).

    For basic queries, let us take a closer look at the Invoke-Sqlcmd cmdlet. Try the following:

  • 10 | P a g e

    Ex: Get-Help Invoke-Sqlcmd

    We can find more specific information about each parameter with the –detailed switch appended.

    Ex: Get-Help Invoke-Sqlcmd –detailed

    Let’s try a basic query. We will insert data into the servers table about the computer that we are

    sending the information from.

    First, we need to define a variable that is a secure string so that it will pass the password

    to the database properly. Otherwise, we will receive authentication errors.

    We can do this with the ConvertTo-SecureString cmdlet:

    Ex: $userpass = ConvertTo-SecureString –String password –AsPlainText –Force

    We now have password stored as a secure string in the $userpass variable. Notice how if we

    call the variable, we cannot see the password, we only get System.Security.SecureString

  • 11 | P a g e

    Next, we will define a variable that holds the Machine Name

    Ex: $pc_name = [Environment]::MachineName

    Notice how this is the same command we used in step 1, only

    we have put the result into the variable $pcname.

    Now if we use the Invoke-Sqlcmd cmdlet,

    we can pass a SQL query to it with our

    variable so that we can query the database.

    When calling a cmdlet such as this, it is important to use the proper parameters with the cmdlet.

    1. First we call the –Database parameter. This is used to signify what database on our SQL server we want to USE when we are sending queries.

    2. The –ServerInstance parameter signifies the machine and Instance Name for our SQL server. This is the name that is

    logged into when SQL Server Management Studio is loaded.

    Check in the start menu under the SQL Server start menu group.

    Start –> All Programs

    –> Microsoft SQL Server

    –> SQL Server Management Studio

    3. Next, we are passing the System.Security.SecureString password that we defined in the variable above.

    [Note: We cannot just pass text here or SQL authentication fails]

    4. To finish the command, we must then pass a query to the server. For example, we can

    “INSERT INTO servers VALUES (‘$pc_name’);”

    Note the syntax that we use. We are INSERTing data INTO the table servers and the

    VALUES we want to insert should be enclosed within quotation marks “, not

    apostrophes ‘. Since the whole statement is in what are some called “double quotes,”

    PowerShell interprets the statement as a string so PS will pass single quotes. PowerShell

    will still pass variables with double quotes.

    This means that we should be passing “INSERT INTO servers VALUES (‘ ‘);”

    1 Invoke-SqlCMD -Database server_event_logs `

    -ServerInstance SCVMM\ADK `

    -Password $userpass `

    -Query "INSERT INTO servers VALUES ('$pc_name');"

    2

    3

    4

  • 12 | P a g e

    [For more information, check out the following (you must have updated your help

    to view this documentation via Update-Help]

    Ex: Get-Help about_Quoting_Rules | more

    Step 4: Create the script that will INSERT the data into the appropriate tables

    One of the most important parts in creating this particular PowerShell script is allowing the

    passing of parameters to the script. This eliminates the need to customize multiple scripts for each log

    and allows you to pass values to the script that can be used during data entry. For this particular script,

    we will be using a [CmdletBinding()] object to pass the name of the log that the event is coming from.

    1 [CmdletBinding()]

    param(

    [Parameter(Mandatory=$true,Position=0)]

    [string]$logname = "System"

    )

    2

    3

    4

    5

    1. CmdletBinding indicates that advanced functionality is available within the script or cmdlet. For example, here we are using this to mandate passing a parameter.

    2. ‘param(‘ is the opening statement of the beginning part of your script or function being created. 3. [Parameter(Mandatory=$true,Position=0)]

    Parameter indicates that this value is passed as a parameter or switch.

    Since Mandatory has the Boolean (1 or 0) value or $true (which is 1), this value must be passed

    for the script or function to execute.

    Position means that the person does not have to specify –logname to pass a value to the

    variable $logname. The string that is passed for the variable must be in the absolute first

    position, which is position 0 (because binary starts counting at 0).

    4. [string]$logname = “System” Here we begin defining variables that are passed to the script or function.

    [string] is the data type that the variable is stored as.

    $logname is the name of the variable where the value is stored.

    For example, if –logname “PowerShell” is passed to the script or function, then if

    $logname is called, it will contain the string “PowerShell”.

    [Note: We use double quotation marks to include everything included

    within so that more than one word can be stored.]

    = “System” means that the variable before the = will have “System” stored as the default string.

    5. ) is simply indicating that it is the end of the parameters. More parameters can be specified but must be included before this end parenthesis specified here. Parameters must be separated by a ,

    In the PowerShell script outlined below, notice how most variables have a specific data type. This helps

    when inputting data to the database because then PowerShell will pass the proper data type to the SQL

    database. One reason why all of the variables have data types is because I was receiving data type errors

    upon entering data into the database.

    As well, notice how # comments are added with a # pound sign # to indicate a comment/ignore this line.

    Each section of code has explanations as to what is being performed in each section.

  • 13 | P a g e

    # set arguments that can be passed to the script #

    1 [CmdletBinding()]

    2 param(

    3 [Parameter(Mandatory=$true,Position=0)]

    4 [string]$logname = "System"

    5 )

    # ensure that SQL powershell module is available #

    6 import-module SQLPS

    # define variables #

    7 $userpass = ConvertTo-SecureString -String 555erv333@ -AsPlainText –Force

    # get pc_id for specific machine #

    8 [string]$pc_name = [Environment]::MachineName

    9 [int]$pc_id_select = (Invoke-SqlCMD -Database server_event_logs -ServerInstance STOUT\ADK -

    Password $userpass -Query "SELECT pc_id FROM servers WHERE pc_name = '$pc_name';").pc_id

    # check for pc_id, put it into variable if it is 0 (or non-existent) #

    10 if ($pc_id_select -eq 0) {

    11 Invoke-SqlCMD -Database server_event_logs -ServerInstance STOUT\ADK -Password $userpass -

    Query "INSERT INTO servers VALUES ('$pc_name');"

    12 [int]$pc_id_select = (Invoke-SqlCMD -Database server_event_logs -ServerInstance STOUT\ADK -

    Password $userpass -Query "SELECT pc_id FROM servers WHERE pc_name = '$pc_name';").pc_id

    13 }

    # get event log into into variables #

    #### table = evl_primary ###

    14 [string]$ev_ent_type = (Get-EventLog -LogName $logname -Newest 1).EntryType

    15 [string]$ev_mess = (Get-EventLog -LogName $logname -Newest 1).Message

    16 [string]$ev_src = (Get-EventLog -LogName $logname -Newest 1).Source

    17 [string]$ev_usr = (Get-EventLog -LogName $logname -Newest 1).Username

    #### table = evl_data ###

    18 [int]$ev_ind = (Get-EventLog -LogName $logname -Newest 1).Index

  • 14 | P a g e

    19 [string]$ev_cat = (Get-EventLog -LogName $logname -Newest 1).Category

    20 [int]$ev_cat_num = (Get-EventLog -LogName $logname -Newest 1).CategoryNumber

    21 [string]$ev_repl_str = (Get-EventLog -LogName $logname -Newest 1).ReplacementStrings

    # input variables to evl_primary table #

    22 Invoke-SqlCMD -Database server_event_logs -ServerInstance STOUT\ADK -Password $userpass `

    23 -Query "INSERT INTO evl_primary (pc_id_fk, entry_type, message, source, username) VALUES

    24 ($pc_id_select, '$ev_ent_type', '$ev_mess', '$ev_src', '$ev_usr');"

    # input variables to evl_data table #

    25 [int]$evl_id_sel = (Invoke-Sqlcmd –Database server_event_logs –ServerInstance STOUT\ADK –

    Password $userpass –Query “SELECT evl_id FROM evl_primary WHERE pc_id_fk =

    $pc_id_select;”).evl_id

    26 Invoke-Sqlcmd –Database server_event_logs –ServerInstance STOUT\ADK –Password $userpass -

    Query "INSERT INTO evl_data (evl_id_fk, index_id, category, category_num, replacement_str)

    VALUES ($evl_id_sel, $ev_ind, '$ev_cat', $ev_cat_num, '$ev_repl_str');"

    ### table = evl_timest ###

    27 [int]$ev_inst_id = (Get-EventLog -LogName $logname -Newest 1).InstanceId

    28 [string]$ev_tim_gen = (Get-EventLog -LogName $logname -Newest 1).TimeGenerated

    29 [string]$ev_tim_writ = (Get-EventLog -LogName $logname -Newest 1).TimeWritten

    # input variables to dbo #

    30 Invoke-SqlCMD -Database server_event_logs -ServerInstance STOUT\ADK -Password $userpass `

    31 -Query "INSERT INTO evl_timest (evl_id_fk, pc_id, instance_id, time_gen, time_written) VALUES

    32 ($evl_id, $pc_id_select, $ev_inst_id, '$ev_tim_gen', '$ev_tim_writ');"

    Step 5: Set a trigger on the Event Log to upload the information upon an event

    a) Go into Event Viewer This can be accomplish via run eventvwr.msc

    or

    This can also be accomplish through

    �Control Panel

    �Administrative Tools

    �Event Viewer

  • 15 | P a g e

    b) Next, expand Windows Logs (or the log of your choice) so that you can view the log

    c) Right click the Event Log of your choice and Select

    � Attach a Task To this Log…

    d) The Name and Description field are only locally

    significant. This means that they are your choice

    and have no bearing on the event.

    e) Click Next because no information about ‘When an Event

    is Logged’ can be changed as this was select

    previously in the right click menu.

    f) Next, we want to start a program because we have a PowerShell script to execute.

  • 16 | P a g e

    g) The next part is the most important part. This is where we choose how to run the script that we have created.

    For the Program/script part, we want to call powershell

    Next we need to know which arguments (or switches, or parameters) that we want to pass to

    powershell.exe so that it will execute properly.

    We can find these optional parameters by running powershell.exe /? from the command prompt.

    [for the full output, run the command in any command prompt window]

  • 17 | P a g e

    As we notice from the previous output, we can bypass the execution of scripts. This is handy

    because now we do not have to change the execution policy

    -ExecutionPolicy Bypass

    Next we notice how we can call a file. We will use this to point the script. In the syntax, it specifies

    that we can use [–File ]

    The square brackets indicate that it is an optional field.

    Here is the syntax for the argument that we are passing.

    We are passing “System” as the “Name of the Log” because

    that is the log we are uploading information from.

    -File C:\scripts\evl2sql.ps1 "Name of the Log"

    Another switch to consider is the –WindowStyle argument. This will allow us to hide this task from

    displaying on the screen whenever an event occurs.

    -WindowStyle Hidden

    To summarize, the final result that will go into Add Arguments box is:

    -ExecutionPolicy Bypass –WindowStyle Hidden -File C:\scripts\evl2sql.ps1 "Name of the Log"

    Pay attention to the order as PowerShell demands a certain order for the arguments passed.

    This is found in the powershell /? output.

    h) The final part is the click Finish. If there are other configurations you would like to perform, check the check box. If not, the Event Log trigger should be functional.

    After Finish is clicked, a window opens that telling that Task Scheduler is where the event can be

    viewed and edited in the future. This is covered in Step 6.

  • 18 | P a g e

    Step 6: Testing Your Setup to Ensure it is Functioning

    Go into Task Scheduler. Here you can view the Event that was

    previously created. [Run � taskschd.msc]

    In the Task Scheduler, go down the hierarchy to

    � Task Scheduler Library

    � Event Viewer Tasks

    The next part involves testing to

    make sure that Events are properly

    being uploaded to the Database.

    This is done with SELECT queries to

    the database.

    This is where the foreign keys come

    into effect.

    If you return no results from your queries, it is time to troubleshoot the script.

    Go into PowerShell and run your script.

    For the script that I have placed in the location C:\scripts\evl2sql.ps1, I run:

    powershell -ExecutionPolicy Bypass -File C:\scripts\evl2sql.ps1 "System"

    Notice how you do not include the –WindowStyle Hidden argument. This is so we can see the output of

    the script so that we can troubleshoot. The output is shown below.

  • 19 | P a g e

    The issue that is happening is on line 58, 59, and 70. We can see that on the 2nd red line of each item

    returning an error. If we edit our script in PowerShell ISE, we can look for errors.

    As for the general information uploaded to the SQL database, we can access it by using SELECT

    statement below.

    SELECT *

    FROM servers, evl_primary

    WHERE servers.pc_id = evl_primary.pc_id_fk;