Skip to content

Instantly share code, notes, and snippets.

@erenon
Created May 13, 2013 06:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erenon/5566493 to your computer and use it in GitHub Desktop.
Save erenon/5566493 to your computer and use it in GitHub Desktop.
IRF homework snippets.
# OVERVIEW:
# parse command line
# write output header
# create filter string
# read csv -> machines
# for machine in machines
# Get-WSManInstance wmicimv2/*
# -ComputerName ...
# -Enumerate
# -Filter
# "SELECT LogFile, SourceName, EventIdentifier, Type
# FROM Win32_NTLogEvent
# WHERE LogFile = ... AND SourceName = ... AND TimeGenerated >= ... AND TimeGenerated <= ..."
# -Dialect WQL
# sort results by LogFile, SourceName, EventIdentifier
#
# set counter = 0
# for result results
# if different than the previous
# write previous to output file
# counter++
# write last
<#
.SYNOPSIS
Retrieves types of logged events of remote hosts.
.DESCRIPTION
It's tough to summarize the events of a large log file manually. It's even more tedious
if there are multiple hosts to manage. This script provides a quick glance of such log files.
It reads the remote host information (machine name, credentials, etc.) from a .csv file
then queries each remote hosts using Win RM (Get-WSManInstance). The results are grouped by
host and type (source, envent identifier, type) then get printed to the output .csv file.
.PARAMETER Machines
Input file containing access information about the remote machines. The file must contain the following columns:
* machineName
* port
* protocol
* user
* password
Example input file:
machineName,port,protocol,user,password
192.168.250.128,5985,http,administrator,password
server01,5986,https,meres,password2
.PARAMETER OutFile
Output file of the collected event groups. The output file will contain the following fields:
* Machine
* Log
* Source
* Id
* Type
* NumberOfEvents
Example output file:
"Machine","Log","Source","Id","Type","NumberOfEvents"
"192.168.1.1","Application","Defrag","258","Information","15"
"192.168.1.1","Application","ESENT","326","Information","30"
"192.168.1.1","Application","ESENT","105","Information","9"
"server01","Application","gpupdate","98","Warning","3"
.PARAMETER Log
Log file to check. Accepted values are 'Application' and 'System'.
.PARAMETER Source
Enumeration of log sources (logging applications) to check.
.PARAMETER From
If specified, only newer than $From log enries will be considered.
.PARAMETER To
If specified, only older than $To log entries will be considered.
.EXAMPLE
Get-RemoteEventId -Machines machines.csv -OutFile out.csv
Query machines listed in machines.csv, write output to out.csv
.EXAMPLE
Get-RemoteEventId -Machines machines.csv -OutFile out.csv -Log Application -Source ESENT, sshd -From 2013.04.07.18:00 -To 2013.04.07.21:00
Query machines listed in machines.csv, write output to out.csv;
Read the Application log only, consider log entries of `ESENT` and `sshd`,
which occured between 2013.04.07.18:00 and 2013.04.07.21:00 only.
.NOTES
* Retriving and processing of large logfiles takes time. To speed thing up, narrow your search.
* Upon unreachable remote host error message is printed, then the collecting proceeds.
* If it's permitted, the output file will be overwritten (error message is prompted otherwise).
* Author, maintainer and contact person of this script: Benedek Thaler <thaler@thaler.hu>
.LINK
* http://technet.microsoft.com/en-us/library/hh849864.aspx
#>
Function Get-RemoteEventId
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[ValidateScript({Test-Path $_ -PathType 'Leaf'})]
[String]
$Machines
,
[Parameter(Mandatory=$true)]
[String]
$OutFile
,
[Parameter(Mandatory=$false)]
[ValidateSet("Application", "System")]
[String]
$Log
,
[Parameter(Mandatory=$false)]
[String[]]
$Source
,
[Parameter(Mandatory=$false)]
[DateTime]
$From
,
[Parameter(Mandatory=$false)]
[DateTime]
$To
)
Process
{
# Small helper function to write output .csv file
Function Write-Outfile {
Param (
[Parameter(Mandatory=$true)]
[String[]]
$Items
,
[Parameter(Mandatory=$false)]
[Boolean]
$Append = $true
)
Process {
$line = '"' + ($Items -join '","') + '"'
Try {
if ($Append) {
$line | Out-File -FilePath $OutFile -Encoding utf8 -Append
} else {
$line | Out-File -FilePath $OutFile -Encoding utf8
}
} Catch {
Write-Error ('Failed to write outfile: ' + $OutFile)
Break
}
}
}
# Write output header, break if failed to write
Write-Outfile 'Machine', 'Log', 'Source', 'Id', 'Type', 'NumberOfEvents' -Append $false
# Create WQL filter
$filter = 'SELECT LogFile, SourceName, EventIdentifier, Type FROM Win32_NTLogEvent '
# Filter by the name of the log file
if ($Log) {
$filterItems += @( "LogFile = '" + $Log + "'" )
}
# Filter by source names, concatenated by OR
if ($Source) {
$Source | ForEach-Object {
$conditions += @( "(SourceName = '" + $_ + "')" )
}
$filterItems += @( $conditions -join ' OR ' );
}
# Filter by date
# WinRM/WQL understands the following format only:
#
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa387237%28v=vs.85%29.aspx
#
if ($From) {
$wbemTime = New-Object -ComObject wbemscripting.swbemdatetime
$wbemTime.SetVarDate($From)
$filterItems += @( "TimeGenerated >= '" + $wbemTime.Value + "'" );
}
if ($To) {
$wbemTime = New-Object -ComObject wbemscripting.swbemdatetime
$wbemTime.SetVarDate($To)
$filterItems += @( "TimeGenerated <= '" + $wbemTime.Value + "'" );
}
# concat filter terms by AND
if ($filterItems) {
$filter += 'WHERE ' + ($filterItems -join ' AND ' )
}
Write-Verbose ('Using filter: ' + $filter)
# Read input file
Import-Csv -Path $Machines | ForEach-Object {
# The next foreach will shadow $_, save machineName
$machineName = $_.machineName
# Assemble credential object
$password = ConvertTo-SecureString –String $_.password –AsPlainText -Force
$credential = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $_.user, $password
$eventCounter = 0
$prevItem = @{ LogFile = $false; SourceName = $false; EventIdentifier = $false; Type = $false }
# Try Get-WSManInstance query
# Then sort the results (to apply unique grouping)
# Group and count the records
# Write out the processed groups
Try {
$entries = Get-WSManInstance `
-ComputerName $machineName `
-OptionSet @{ Address = '*'; Transport = $_.protocol } `
-Port $_.port `
-ResourceUri 'wmicimv2/*' `
-Enumerate `
-Authentication Negotiate `
-Credential $credential `
-Filter $filter `
-Dialect WQL |
Sort-Object LogFile, SourceName, EventIdentifier |
ForEach-Object {
# different entry -> start new group
if (
$_.LogFile -ne $prevItem.LogFile `
-or $_.SourceName -ne $prevItem.SourceName `
-or $_.EventIdentifier -ne $prevItem.EventIdentifier
) {
# write out group if it contains events
if ($eventCounter -gt 0) {
# export to csv
Write-Outfile `
$machineName, `
$prevItem.LogFile, `
$prevItem.SourceName, `
$prevItem.EventIdentifier, `
$prevItem.Type, `
$eventCounter
Write-Verbose 'Write group'
}
# reset counter and prevItem
$eventCounter = 0
$prevItem.LogFile = $_.LogFile
$prevItem.SourceName = $_.SourceName
$prevItem.EventIdentifier = $_.EventIdentifier
$prevItem.Type = $_.Type
}
# count the events of the group
$eventCounter++
}
# export last group to csv
if ($eventCounter -gt 0) {
Write-Outfile `
$machineName, `
$prevItem.LogFile, `
$prevItem.SourceName, `
$prevItem.EventIdentifier, `
$prevItem.Type, `
$eventCounter
}
} Catch {
Write-Error ('Get-WSManInstance query failed for host: ' + $machineName)
}
}
}
}
#!/usr/bin/python3
'''
IRF Homework #1 -- Nameday at Superhotels
Author:
Thaler, Benedek EDDO10
Created:
2013. 03. 22.
'''
import sys
import os
import argparse
from datetime import date, datetime
import csv
import subprocess
'''
LDAP Host location
Uses the format which `ldapsearch -H` accepts
'''
g_ldap_host = 'ldap://192.168.1.69:389'
def parse_args(args):
'''
Parses command line arguments
Prints usage and terminates if parsing fails.
Args:
args: Command line arguments, whitout the script name, e.g: sys.argv[1:]
Returns:
argparse.Namespace object with the following field:
[datetime.date] d: date
[_io.TextIOWrapper] n: input database
[_io.TextIOWrapper] o: output database
'''
parser = argparse.ArgumentParser()
# add arguments
# -n: input database
parser.add_argument(
'-n',
nargs = 1,
type = argparse.FileType('rt', 1),
required = True,
help = 'Path to the nameday database',
metavar = 'HR_db'
)
# -o: output file
parser.add_argument(
'-o',
nargs = 1,
type = argparse.FileType('w'),
required = True,
help = 'Path to the output file',
metavar = 'greetings_list'
)
# -d: date
parser.add_argument(
'-d',
nargs = 1,
default = [date.today()],
type = make_date_from_string,
required = False,
help = 'Date of namedays to search for',
metavar = 'date'
)
return parser.parse_args(args)
def make_date_from_string(date_str):
'''
Creates datetime.date from string
Used by parse_args
Args:
date_str: Date string
Returns:
datetime.date: Date
'''
return datetime.strptime(date_str, '%Y.%m.%d.').date()
def make_csv_filter(index, value):
'''
Creates a filter function
Args:
index: list index to check
value: list value to compare
Returns:
Filter function
'''
def filter(list):
'''
Filter function
Args:
list: list to check
Returns:
true if the given list at the given index has the given value, false otherwise
'''
return (list[index] == value)
return filter
def read_csv(file, filter):
'''
Reads the input CSV file
Args:
file: input CSV file
filter: result includes opted in rows only
Returns:
Dictionary of LDAP dn keys pointing to name lists
Example: {'dn1': [name1, name2], 'dn2': [name3]}
Raises:
Exception: if header is invalid
'''
reader = csv.reader(file, delimiter = ',', quotechar = '"', skipinitialspace = True)
header = next(reader)
# Check header
if header != ['DN', 'DAY', 'NAME']:
raise Exception('Invalid input database header. Database schema should be: DN, DAY, NAME')
dn_to_names = []
# for every row
for row in reader:
if (filter(row)): # check if passes filter
dn_to_names.append((row[0], row[2].split(';'))) # append to result
return dn_to_names
def ldap_search(host, baseDn, names):
'''
Searches names in a subtree on an LDAP host
Example ldapsearch command:
ldapsearch
-H ldap://192.168.1.71:389
-x
-b "ou=Japan,ou=Asia,ou=Hotels,dc=irf,dc=local"
-s sub
"(&(objectclass=person)(|(givenName=Sarah)(givenName=Sophie)))"
dn mail
Args:
host: LDAP host to query
baseDn: Distinguished Name of the subtree to search in
names: list of names to search
Returns:
List of dictionaries with `dn` and `mail` keys.
Example: [
{'dn': 'person_dn_1', 'mail': 'person_mail_1'},
{'dn': 'person_dn_2', 'mail': 'person_mail_2'}
]
Raises:
Exception: if the LDAP query (ldapsearch) fails
'''
# build filter string
filter = '(&(objectclass=person)(|'
# append names
for name in names:
filter += '(givenName={0})'.format(name)
filter += '))'
# launch query
try:
response = subprocess.check_output(
[
'ldapsearch',
'-H', host,
'-x',
'-o', 'ldif-wrap=no',
'-b', baseDn,
'-s', 'sub',
filter,
'dn', 'mail'
],
universal_newlines = True
)
except subprocess.CalledProcessError as ex:
raise Exception('LDAP query failed')
# process response
results = []
# for every row
for row in response.splitlines():
# drop row if starts with #
if (len(row) > 0 and row[0] != '#'):
# if starts with `dn:`, create new entry
if (row.find('dn:') == 0):
results.append({'dn' : row[4:]})
# if starts with `mail:`, append to the latest entry
elif (row.find('mail:') == 0):
results[-1]['mail'] = row[6:]
return results
if __name__ == '__main__':
'''
This module reads a CSV birthday database,
searches an LDAP host for persons by name and DN
and prints a CSV of DN,EMAIL rows.
Command line arguments:
-h, --help show help message and exit
-n HR_db Path to the nameday database
-o greetings_list Path to the output file
-d date Date of namedays to search for
Input database example:
DN, DAY, NAME
"ou=France,ou=Europe,ou=Hotels,dc=irf,dc=local", "03.10", "Jean;Pierre"
"ou=Osaka,ou=Japan,ou=Asia,ou=Hotels,dc=irf,dc=local", "03.11", "Asao"
Output example:
"DN, EMAIL"
"cn=cbentley1,ou=Osaka,ou=Japan,ou=Asia,ou=Hotels,dc=irf,dc=local",cbentley1@superhotels.com
"cn=cbloss,ou=Osaka,ou=Japan,ou=Asia,ou=Hotels,dc=irf,dc=local",cbloss@superhotels.com
'''
# read args
input = parse_args(sys.argv[1:])
inputFile = input.n[0]
inputDate = input.d[0]
outputFile = input.o[0]
# read input CSV
try:
dn_to_names = read_csv(inputFile, make_csv_filter(1, inputDate.strftime('%m.%d')))
except Exception as ex:
sys.exit(ex)
# write output header
# Please note: csv writerow (output_writer.writerow(['DN', 'EMAIL'])) won't do it
# We need a space after the comma to conform to the specification
outputFile.write('DN, EMAIL' + os.linesep)
# init CSV writer
output_writer = csv.writer(outputFile, delimiter=',', quotechar = '"')
# iterate on dns
for (dn, names) in dn_to_names:
# get celebrants from LDAP
try:
celebrants = ldap_search(g_ldap_host, dn, names)
except Exception as ex:
sys.exit(ex)
# print returned celebrants
for celebrant in celebrants:
dn = celebrant['dn'] if 'dn' in celebrant else ''
mail = celebrant['mail'] if 'mail' in celebrant else ''
output_writer.writerow([dn, mail])
Import-Module .\Get-RemoteEventId.ps1
# this is an example for calling the script
Get-RemoteEventId -OutFile events.csv -Machines machines.csv
# Change the order of mandatory parameters, add -Source filter
Get-RemoteEventId -Machines machines.csv -Source "Defrag", "gpupdate" -OutFile events.csv
# try to add some other, important cases
# CORRECT USAGES
Write-Host 'Correct usage tests'
# Use -Verbose
Get-RemoteEventId -Machines machines.csv -OutFile out.csv -Verbose
# Use filter -From
Get-RemoteEventId -Machines machines.csv -OutFile out.csv -Verbose -From 2013.04.09.18:00
# Use filter -TO
Get-RemoteEventId -Machines machines.csv -OutFile out.csv -Verbose -To 2013.04.09.18:00
# Use both -From and -To
Get-RemoteEventId -Machines machines.csv -OutFile out.csv -Verbose -From 2013.04.09.18:00 -To 2013.04.09.18:30
# Use filter -Log
Get-RemoteEventId -Machines machines.csv -OutFile out.csv -Log System
# Use filter -Source
Get-RemoteEventId -Machines machines.csv -OutFile out.csv -Source ESENT, sshd
# INCORRECT USAGES
Write-Host 'Incorrect usage tests'
# nonexistent input
Get-RemoteEventId -Machines invalid_machines.csv -OutFile out.csv
# output not writeable
Get-RemoteEventId -Machines machines.csv -OutFile C:\Windows\invalid_out.csv
#!/bin/bash
# important test cases
# correct usage
echo -e "Correct Usages:"
# specify input, output, date
./greetings.py -o greetings.csv -n names.csv -d 2015.01.21.
echo -ne '.'
# specify input, output; omit date
./greetings.py -n names.csv -o greeting-people.csv
echo -ne '.'
# match multiple names
./greetings.py -n names.csv -o greeting-people.csv -d 2015.03.13.
echo -ne '.'
# incorrect usage
echo -e "\n\nIncorrect Usages:\n"
# omit output
./greetings.py -n names.csv
# omit input
./greetings.py -o greetings.csv
# input file not found
./greetings.py -n invalid_names.csv -o greeting-people.csv
# output file not writeable
./greetings.py -n names.csv -o /root/greeting-people.csv
# invalid date format
./greetings.py -o greetings.csv -d 13.03.2015.
#!/bin/bash
dir="$( cd "$( dirname "$0" )" && pwd )"
app="java -jar $dir/../dist/irfhf3-1.0.jar"
id=0
let "port = $$+1000"
cd $dir
# save logfile, remove orginal
save() {
cp log/log.log $1.txt
rm log/log.log
}
# check whether log contains the given string
contains() {
grep "$2" "$1.txt" > /dev/null && echo -ne "." && return 0
echo -e "\n[FAIL] String '$2' not found in $1.log\n"
}
# silently terminates process
term() {
kill -9 $1
wait $1 2> /dev/null
}
# 1
((id++))
$app > /dev/null 2> /dev/null
save $id
contains $id "ERROR GameEnvironment: Failed to start GameEnvironment -- expected 1 argument, 0 given"
# 2
((id++))
$app foo > /dev/null 2> /dev/null
save $id
contains $id "ERROR GameEnvironment: Failed to start GameEnvironment -- invalid port number given"
# 3
((id++))
$app 80 > /dev/null 2> /dev/null
save $id
contains $id "ERROR GameEnvironment: Failed to start GameEnvironment -- unable to open server socket"
# 4
((id++))
# no idea how to trigger IOException
echo -ne "."
# 5
((id++))
$app $port > /dev/null 2> /dev/null &
pid=$!
sleep 0.5
term $pid
save $id
contains $id "INFO GameEnvironment: GameEnvironment Started -- listens on port $port"
# 6
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 0.5
telnet 127.0.0.1 $port > /dev/null 2> /dev/null <<< "q\n"
sleep 0.1
term $server_pid
save $id
contains $id "INFO GameSession: Client connected -- "
# 7
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 0.5
telnet 127.0.0.1 $port > /dev/null 2> /dev/null <<< "q\n"
sleep 0.1
term $server_pid
save $id
contains $id "ERROR GameSession: Failed to read socket, disconnecting client"
# 8
((id++))
# no idea how to trigger "failed to close socket"
echo -ne "."
# 9
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 1
(echo "x"; sleep 0.1;) | telnet 127.0.0.1 $port > /dev/null 2> /dev/null
term $server_pid
save $id
contains $id "DEBUG GameSession: Failed to choose game"
# 10
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 1
(echo "b"; sleep 0.1;) | telnet 127.0.0.1 $port > /dev/null 2> /dev/null
term $server_pid
save $id
contains $id "INFO GameSession: Game choosed: BattleshipGame"
# 11
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 1
(echo "m"; sleep 0.1;) | telnet 127.0.0.1 $port > /dev/null 2> /dev/null
term $server_pid
save $id
contains $id "INFO GameSession: Game choosed: MineSweeper"
# 12
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 1
(echo "b"; sleep 0.1; echo "name"; sleep 0.1; echo "q"; sleep 0.1) | telnet 127.0.0.1 $port > /dev/null 2> /dev/null
term $server_pid
save $id
contains $id "DEBUG GameSession: Game exited: BattleshipGame"
# 13
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 1
(echo "m"; sleep 0.1; echo ""; sleep 0.1; echo "quit"; sleep 0.1) | telnet 127.0.0.1 $port > /dev/null 2> /dev/null
term $server_pid
save $id
contains $id "DEBUG GameSession: Game exited: MineSweeper"
# 14
((id++))
$app $port > /dev/null 2> /dev/null &
server_pid=$!
sleep 1
(echo "q"; sleep 0.1;) | telnet 127.0.0.1 $port > /dev/null 2> /dev/null
term $server_pid
save $id
contains $id "INFO GameSession: Client exited -- "
# end
rm -r log/
echo -e '\n[DONE]'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment