По мере роста компании и возникновения большого кол-ва рабочих мест возникла идея сделать ресурс, на котором можно быстро найти информацию по пользователю, ПК и сделать какие-нибудь отчеты.
ПО такое есть, оно сложное и обычно стоит денег. Будем клепать свое и на коленке.
Также накладывается ряд ограничений из-за:
- производительности контролеров домена
- ПО безопасников (нефиг тут запускать левые exe и сервисы), в свое ПО не пустим.
- настроек сетевиков (сложная архитектура на основе VLAN, ACL и запретов всего, что может куда-то коннектиться)
- не прод ресурс на прод системе
- требования безопасников и политика использования программ
Поставленные цели:
1. Куда пользователи ходят
2. Где они забывают выходить
3. Кто логиниться под своим/не своим логином на одном/нескольких ПК
4. Рассадка по местам
5. Отображение на схеме этажа
6. Отчет о рабочем времени (в т.ч. сколько пользователь был «активен» в системе)
7. Делегирование прав для инженеров с целью упрощения диагностики.
Немного о сети:
В сети существуют пользовательские VLAN с авторизацией в AD, связка Computer + User. При провале авторизации пользователи попадают в гостевые VLANs, где у них отсутствуют какие-либо доступы, кроме как выйти из системы.
VLAN максимально /23
Немного о DNS:
DNS AD integrated. DNS scavenging отключен. Соответственно, ввиду пункта выше, возникает очень много проблем с поиском ПК по DNS, дублирование A, PTR записей.
Немного об GPO:
Включена блокировка станции по не активности = 5 минут.
Используется раздел logon/logoff scripts.
Немного об AD:
Доступы на основе групп безопасности. Шаг в сторону считается побегом.
2 домена + Domain Trust
В моем распоряжении есть:
- Шара, куда могут все писать (только создание, запись)
- Виртуалка на базе Windows Server 2012R2
Список используемого ПО:
Windows Server 2012R2 (IIS)
Visual Studio 2012 (Разработка ПО для руководителей и пользователей)
Mysql 5.6 (База данных, в которой я храню данные)
Mysql Work Bench (Построение БД на коленке)
Perl for Windows (Портал + веб-сервис)
И языков программирования:
Perl
C#
Powershell
Для начала нам нужна БД:
--
-- Database: `logon`
--
-- --------------------------------------------------------
--
-- Table structure for table `bcs`
--
CREATE TABLE IF NOT EXISTS `bcs` (
`id` int(11) NOT NULL,
`bc` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `computers`
--
CREATE TABLE IF NOT EXISTS `computers` (
`id` int(11) NOT NULL,
`domain_id` int(11) DEFAULT NULL,
`samaccountname` varchar(15) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `domains`
--
CREATE TABLE IF NOT EXISTS `domains` (
`id` int(11) NOT NULL,
`name` varchar(15) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `events`
--
CREATE TABLE IF NOT EXISTS `events` (
`id` int(11) NOT NULL,
`event` varchar(8) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `groups`
--
CREATE TABLE IF NOT EXISTS `groups` (
`id` int(11) NOT NULL,
`name` varchar(64) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `ipnets`
--
CREATE TABLE IF NOT EXISTS `ipnets` (
`id` int(11) NOT NULL,
`bc_id` int(11) NOT NULL,
`ipnet1` varchar(3) NOT NULL DEFAULT '172',
`ipnet2` varchar(3) NOT NULL DEFAULT '16',
`ipnet3` varchar(3) NOT NULL,
`mask` int(11) NOT NULL DEFAULT '24',
`vid` mediumint(4) DEFAULT NULL,
`name` varchar(20) DEFAULT NULL,
`description` varchar(50) DEFAULT NULL,
`tplname` varchar(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `ips`
--
CREATE TABLE IF NOT EXISTS `ips` (
`id` int(11) NOT NULL,
`ip` varchar(15) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `latestdata`
--
CREATE TABLE IF NOT EXISTS `latestdata` (
`domain_id` int(11) NOT NULL,
`computer_id` int(11) NOT NULL,
`computer_event_id` int(11) DEFAULT NULL,
`computer_dt` datetime DEFAULT NULL,
`ip_id` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`user_event_id` int(11) DEFAULT NULL,
`user_dt` datetime DEFAULT NULL,
`logonid` tinyint(4) DEFAULT NULL,
`logon_dt` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `latestlogons`
--
CREATE TABLE IF NOT EXISTS `latestlogons` (
`domain_id` int(11) NOT NULL,
`computer_id` int(11) NOT NULL,
`ip_id` int(11) DEFAULT NULL,
`user_id` int(11) NOT NULL,
`user_event_id` int(11) DEFAULT NULL,
`user_dt` datetime DEFAULT NULL,
`processlogoff` tinyint(4) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `logoncomputers`
--
CREATE TABLE IF NOT EXISTS `logoncomputers` (
`id` int(11) NOT NULL,
`domain_id` int(11) NOT NULL,
`computer_id` int(11) NOT NULL,
`event_id` int(11) NOT NULL,
`ip_id` int(11) NOT NULL,
`dt` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `logonusers`
--
CREATE TABLE IF NOT EXISTS `logonusers` (
`id` int(11) NOT NULL,
`domain_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`computer_id` int(11) NOT NULL,
`event_id` int(11) NOT NULL,
`ip_id` int(11) NOT NULL,
`dt` datetime DEFAULT '0000-00-00 00:00:00',
`dtnow` datetime DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `membership`
--
CREATE TABLE IF NOT EXISTS `membership` (
`uid` int(11) NOT NULL,
`gid` int(11) NOT NULL,
`used` tinyint(4) NOT NULL,
`user_dt` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL,
`domain_id` int(11) NOT NULL,
`samaccountname` varchar(20) NOT NULL,
`name` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `bcs`
--
ALTER TABLE `bcs`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `computers`
--
ALTER TABLE `computers`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `samaccountname` (`samaccountname`);
--
-- Indexes for table `domains`
--
ALTER TABLE `domains`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `name` (`name`);
--
-- Indexes for table `events`
--
ALTER TABLE `events`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `event` (`event`);
--
-- Indexes for table `groups`
--
ALTER TABLE `groups`
ADD PRIMARY KEY (`id`,`name`),
ADD UNIQUE KEY `name` (`name`);
--
-- Indexes for table `ipnets`
--
ALTER TABLE `ipnets`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `ips`
--
ALTER TABLE `ips`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `ip` (`ip`);
--
-- Indexes for table `latestdata`
--
ALTER TABLE `latestdata`
ADD PRIMARY KEY (`computer_id`);
--
-- Indexes for table `latestlogons`
--
ALTER TABLE `latestlogons`
ADD PRIMARY KEY (`computer_id`,`user_id`);
--
-- Indexes for table `logoncomputers`
--
ALTER TABLE `logoncomputers`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `logonusers`
--
ALTER TABLE `logonusers`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `membership`
--
ALTER TABLE `membership`
ADD PRIMARY KEY (`uid`,`gid`);
--
-- Indexes for table `templatedata`
--
ALTER TABLE `templatedata`
ADD PRIMARY KEY (`template_id`,`row_id`);
--
-- Indexes for table `templates`
--
ALTER TABLE `templates`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `users`
--
ALTER TABLE `users`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `bcs`
--
ALTER TABLE `bcs`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `computers`
--
ALTER TABLE `computers`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `domains`
--
ALTER TABLE `domains`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `events`
--
ALTER TABLE `events`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `groups`
--
ALTER TABLE `groups`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `ipnets`
--
ALTER TABLE `ipnets`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `ips`
--
ALTER TABLE `ips`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `logoncomputers`
--
ALTER TABLE `logoncomputers`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `logonusers`
--
ALTER TABLE `logonusers`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `templates`
--
ALTER TABLE `templates`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
--
-- AUTO_INCREMENT for table `users`
--
ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Далее необходимо писать данные о входах пользователей.
Сделаем 2 скрипта (в каждом домене)
Для пользователя:
set t=%1
ipconfig | find «IPv4» > %temp%tempip.txt
for /f «tokens=1* delims=.: » %%a in (%temp%tempip.txt) do (echo %USERNAME%;%COMPUTERNAME%;%%b;%t%;%DATE%;%TIME% >> \naslog$users%USERNAME%.domain1.ru.txt)
del %temp%tempip.txt
usage \domainnetlogonlogon.cmd logon/logoff
Для ПК:
set t=%1
ipconfig | find «IPv4» > %temp%tempip.txt
for /f «tokens=1* delims=.: » %%a in (%temp%tempip.txt) do (echo %COMPUTERNAME%;%%b;%t%;%DATE%;%TIME% >> \naslog$computers%COMPUTERNAME%.domain1.ru.txt)
del %temp%tempip.txt
Остается распарсить данные и куда-нибудь сохранить.
(2 модуля: пк и пользователи. Код без комментариев.)
import-module activedirectory
[void][system.reflection.Assembly]::LoadWithPartialName("MySql.Data")
$server= "localhost"
$username= "logon"
$password= ""
$database= "logon"
Set-Variable SqlConnection (New-Object MySql.Data.MySqlClient.MySqlConnection) -Scope Global -Option AllScope -Description "Personal variable for Sql Query functions"
$SqlConnection.ConnectionString = "server=$server;user id=$username;password=$password;database=$database;pooling=false;Allow Zero Datetime=True;"
if (-not ($SqlConnection.State -like "Open")) { $SqlConnection.Open() }
function global:Get-SqlDataTable( $Query = $(if (-not ($Query -gt $null)) {Read-Host "Query to run"}) ) {
# if (-not ($SqlConnection.State -like "Open")) { $SqlConnection.Open() }
$SqlCmd = New-Object MySql.Data.MySqlClient.MySqlCommand $Query, $SqlConnection
$SqlAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter
$SqlAdapter.SelectCommand = $SqlCmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet) | Out-Null
return $DataSet.Tables[0]
}
function global:Insert-SqlDataTable( $Query = $(if (-not ($Query -gt $null)) {Read-Host "Query to run"}) ) {
# if (-not ($SqlConnection.State -like "Open")) { $SqlConnection.Open() }
$SqlCmd = New-Object MySql.Data.MySqlClient.MySqlCommand $Query, $SqlConnection
$SqlAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter
$SqlAdapter.InsertCommand = $SqlCmd
$SqlAdapter.InsertCommand.ExecuteNonQuery()
}
$events = Get-SqlDataTable 'select * from events'
$domain = 1;
$fusers = $null
if ((get-childitem \naslog$users | measure).count -gt 0){
$fusers += get-childitem \naslog$users
}
if ((get-childitem \nas.d2.localauth_log$users | measure).count -gt 0){
$fusers += get-childitem \nas.d2.localauth_log$users
}
foreach ($fuser in $fusers){
if ($fuser.name -match "domain1"){
$domain = 1
}
if ($fuser.name -match "domain2"){
$domain = 2
}
write-host domain $domain -foregroundcolor blue
write-host "Пользователь:" $fuser.BaseName -foregroundcolor green
if (!(test-path $fuser.fullname)){continue}
$ustr = get-content $fuser.fullname
$error_code = $null
$res_sql_user = $null
$res_sql_latestdata = $null
$res_sql_latestlogons = $null
foreach ($line in $ustr){
$line1 = $line -replace "['|()]"
$arr = $line1.split(";")
if ($arr[0]){
if ($domain -eq 1){
$uname = (get-aduser $arr[0]).name
}
if ($domain -eq 2){
$uname = (get-aduser $arr[0] -server dc.domain2).name
}
$sql_str = "select id from users where lower(samaccountname) = lower('" + $arr[0] + "') and domain_id = $domain order by id limit 1;";
$userid = (Get-SqlDataTable $sql_str).id
if (!$userid){
$sql_str = "insert into users (domain_id, samaccountname, name) values ($domain, '" + $arr[0] + "', '$uname'); select id from users where lower(samaccountname) = lower('" + $arr[0] + "') and domain_id = $domain order by id limit 1;";
$userid = (Get-SqlDataTable $sql_str).id
}
}
if ($arr[1]){
$compname = $arr[1]
$cdomain = 1
if ($compname -match "cn1"){
$cdomain = 1
}
if ($compname -match "cn2"){
$cdomain = 2
}
$sql_str = "select id from computers where lower(samaccountname) = lower('" + $arr[1] + "') order by id limit 1;";
$computerid = (Get-SqlDataTable $sql_str).id
if (!$computerid){
$sql_str = "insert into computers (domain_id, samaccountname) values ($cdomain, '" + $arr[1] + "'); select id from computers where lower(samaccountname) = lower('" + $arr[1] + "') order by id limit 1;";
$computerid = (Get-SqlDataTable $sql_str).id
write-host $sql_str -foregroundcolor yellow
}
}
$ev = $events | ?{$_.event -eq $arr[3]}
switch(($ev | measure).count){
0 {
write-host $arr[3] "error" -foregroundcolor red
exit
write-host $arr[3] "will be added" -foregroundcolor yellow
$sql_str = "insert into events (event) values ('" + $arr[3] + "')"
Insert-SqlDataTable $sql_str
$events = Get-SqlDataTable 'select * from events'
$sql_str | out-file sql.txt -append
}
1 {
#write-host $arr[3] "select as current" -foregroundcolor white
}
default: {$error_code = 3; write-host $arr[3] "error" -foregroundcolor red; exit}
}
$curip = $arr[2] -replace "Address. . . . . . . . . . . :","" -replace "IPv4 Address. . : ","" -replace "IPv4- ¤аҐб . . . . : ",""
if ($curip){
$sql_str = "select id from ips where lower(ip) = lower('$curip') order by id limit 1;"
$ipid = (Get-SqlDataTable $sql_str).id
if (!$ipid){
$sql_str = "insert into ips (ip) values ('$curip'); select id from ips where lower(ip) = lower('$curip') order by id limit 1;";
write-host $sql_str -foregroundcolor yellow
$ipid = (Get-SqlDataTable $sql_str).id
}
}
if (!$userid){write-host u userid null; exit;}
if (!$computerid){write-host u computerid null; exit;}
if (!$ipid){write-host u ipid null; exit;}
$eventid = ($events | ?{$_.event -eq $arr[3]}).id | select -first 1
#$ip = $arr[2] -replace "Address. . . . . . . . . . . :","" -replace "IPv4 Address. . : ",""
#$dt = "{0:yyyy-MM-dd HH:mm:ss}" -f [datetime](($arr[4] + " " + $arr[5]) -replace '^(.*),.*$','$1')
#$dt = get-date(($arr[4] + " " + $arr[5]) -replace '^(.*),.*$','$1') -format "yyyy-MM-dd hh:mm:ss zzz"
#$dt = get-date(($arr[4] + " " + $arr[5])) -format "yyyy-MM-dd hh:mm:ss zzz"
$t = ($arr[5] -replace '^(.*),.*$','$1').split(":")
$dt = get-date((get-date($arr[4])).Addhours($t[0]).AddMinutes($t[1]).Addseconds($t[2])) -format "yyyy-MM-dd HH:mm:ss"
if ($arr[0]){
if ($domain -eq 1){
$groups = ((Get-ADuser $arr[0] -Property memberof).memberof | %{Get-ADGroup -Identity $_} | sort name).name
}
if ($domain -eq 2){
$groups = ((Get-ADuser $arr[0] -server dc.domain2 -Property memberof).memberof | %{Get-ADGroup -Identity $_ -server dc.domain2 } | sort name).name
}
#$groups = ((Get-ADuser $arr[0] -Property memberof).memberof | %{Get-ADGroup -Identity $_} | sort name).name
$val1 = ""
$val2 = ""
$groupscnt = ($groups | measure).count
#write-host $groupscnt -foregroundcolor red
for ($i = 0; $i -lt $groupscnt; $i++){
$gr = $groups[$i] -replace "'","'"
$sql_str = "select id from groups where name = '$gr'"
$groupid = (Get-SqlDataTable $sql_str).id
if (!$groupid){
$sql_str = "insert into groups (name) values ('$gr');"
$res = Get-SqlDataTable $sql_str
}
$val2 = $val2 + "'" + $gr + "'"
if ($i -lt $groupscnt - 1){$val2 = $val2 + ","}
}
$sql_str = "select id from groups where name in ($val2);"
$groupsid = (Get-SqlDataTable $sql_str).id
$groupscnt = ($groupsid | measure).count
$val3 = ""
for ($i = 0; $i -lt $groupscnt; $i++){
$val3 = $val3 + "($userid, " + $groupsid[$i] + ", 1, '$dt')"
if ($i -lt $groupscnt - 1){$val3 = $val3 + ","}
}
$sql_str = "insert into membership (uid, gid, used, user_dt) values $val3 on duplicate key update used=values(used), user_dt=values(user_dt); update membership SET used=0 WHERE uid = $userid and user_dt != '$dt'"
#$sql_str
$res = Get-SqlDataTable $sql_str
#$res
}
# $datetime = "{0:yyyy-MM-dd hh:mm:ss}" -f [datetime]$dt #::ParseExact($dt, "dd.MM.yyyy hh:mm:ss",$null)
#$datetime = get-date($dt)
# $datetime
$res_sql_user += "insert into logonusers (domain_id, user_id, computer_id, event_id, ip_id, dt) values ($domain, $userid, $computerid, $eventid, $ipid, '$dt');"
$res_sql_latestdata += "insert into latestdata (domain_id, computer_id, user_id, user_event_id, ip_id, user_dt) values ($domain, $computerid, $userid, $eventid, $ipid, '$dt') on duplicate key update computer_id=values(computer_id), user_id=values(user_id), user_event_id=values(user_event_id), user_dt=values(user_dt), ip_id=values(ip_id);"
if ($eventid -eq 2){
$res_sql_latestlogons += "insert into latestlogons (domain_id, computer_id, user_id, user_event_id, ip_id, user_dt, processlogoff) values ($domain, $computerid, $userid, $eventid, $ipid, '$dt', 0) on duplicate key update computer_id=values(computer_id), user_id=values(user_id), user_event_id=values(user_event_id), user_dt=values(user_dt), ip_id=values(ip_id), processlogoff=values(processlogoff);"
}
if ($eventid -eq 1){
$res_sql_latestlogons += "delete from latestlogons where computer_id = $computerid and user_id = $userid limit 1;"
}
# $sql = "insert into logon () values";
}
if (!$error_code){
$out = Insert-SqlDataTable $res_sql_user
$res_sql_user
$out = Insert-SqlDataTable $res_sql_latestdata
$res_sql_latestdata
$out = Insert-SqlDataTable $res_sql_latestlogons
$res_sql_latestlogons
remove-item $fuser.fullname -force
}
}
######################################################################
######################################################################
######################################################################
######################################################################
######################################################################
$fcomputers = $null
if ((get-childitem \naslog$computers | measure).count -gt 0){
$fcomputers += get-childitem \naslog$computers
}
if ((get-childitem \nas.d2.localauth_log$computers | measure).count -gt 0){
$fcomputers += get-childitem \nas.d2.localauth_log$computers
}
foreach ($fcomputer in $fcomputers){
if ($fcomputer.name -match "domain1"){
$domain = 1
}
if ($fcomputer.name -match "domain2"){
$domain = 2
}
write-host domain $domain -foregroundcolor blue
write-host "ПК:" $fcomputer.BaseName -foregroundcolor green
$cstr = get-content $fcomputer.fullname
$error_code = $null
$res_sql_computer = $null
$res_sql_latestdata = $null
foreach ($line in $cstr){
$arr = $line.split(";")
if ($arr[0]){
$sql_str = "select id from computers where lower(samaccountname) = lower('" + $arr[0] + "') order by id limit 1;";
$computerid = (Get-SqlDataTable $sql_str).id
if (!$computerid){
$sql_str = "insert into computers (domain_id, samaccountname) values ($domain, '" + $arr[0] + "'); select id from computers where lower(samaccountname) = lower('" + $arr[0] + "') order by id limit 1;";
$computerid = (Get-SqlDataTable $sql_str).id
}
}
$ev = $events | ?{$_.event -eq $arr[2]}
switch(($ev | measure).count){
0 {
write-host $arr[2] "will be added" -foregroundcolor yellow
#$sql_str = "insert into events (event) values ('" + $arr[2] + "')"
Insert-SqlDataTable $sql_str
$events = Get-SqlDataTable 'select * from events'
$sql_str | out-file sql.txt -append
}
1 {
#write-host $arr[3] "select as current" -foregroundcolor white
}
default: {$error_code = 3; write-host $arr[2] "error" -foregroundcolor red}
}
$curip = $arr[1] -replace "Address. . . . . . . . . . . :","" -replace "IPv4 Address. . : ","" -replace "IPv4- ¤аҐб . . . . : ",""
#write-host $arr[1] $curip
#$error_code = 4
if ($curip){
$sql_str = "select id from ips where lower(ip) = lower('$curip') order by id limit 1;"
$ipid = (Get-SqlDataTable $sql_str).id
if (!$ipid){
$sql_str = "insert into ips (ip) values ('$curip'); select id from ips where lower(ip) = lower('$curip') order by id limit 1;";
$ipid = (Get-SqlDataTable $sql_str).id
}
}
if (!$error_code){
$eventid = ($events | ?{$_.event -eq $arr[2]}).id | select -first 1
if (!$computerid){write-host c computerid null; exit;}
if (!$ipid){write-host c ipid null; exit;}
$t = ($arr[4] -replace '^(.*),.*$','$1').split(":")
$dt = get-date((get-date($arr[3])).Addhours($t[0]).AddMinutes($t[1]).Addseconds($t[2])) -format "yyyy-MM-dd HH:mm:ss"
$res_sql_computer += "insert into logoncomputers (domain_id, computer_id, event_id, ip_id, dt) values ($domain, $computerid, $eventid, $ipid, '$dt');"
$res_sql_latestdata += "insert into latestdata (domain_id, computer_id, computer_event_id, computer_dt, ip_id) values ($domain, $computerid, $eventid, '$dt', $ipid) on duplicate key update computer_id=values(computer_id), computer_event_id=values(computer_event_id), computer_dt=values(computer_dt), ip_id=values(ip_id);"
}
}
if (!$error_code){
$res_sql_computer
$out = Insert-SqlDataTable $res_sql_computer
$res_sql_latestdata
$out = Insert-SqlDataTable $res_sql_latestdata
remove-item $fcomputer.fullname -force
}
}
$SqlConnection.Close()
Теперь у нас данные сохраняются в базу данных. Далее мы можем делать с ними все что угодно:
Динамически формируется их Excel файлов на файловой шаре.
Поиск возможен по:
- Имени пользователя
- IP
- Имени ПК
- Группе
SELECT
(SELECT
COUNT(*)
FROM
latestlogons t
WHERE
t.user_id = ll.user_id) AS cnt,
u.samaccountname,
ll.user_id,
u.name,
c.samaccountname,
ll.computer_id,
i.ip,
ll.user_dt,
bc.bc,
ipn.tplname
FROM
latestlogons ll
JOIN
(SELECT
*
FROM
users
WHERE
id NOT IN (SELECT DISTINCT
u.id
FROM
users u
JOIN membership m ON m.uid = u.id
JOIN groups gr ON gr.id = m.gid
WHERE
gr.name IN ('Domain Admins'))) u ON u.id = ll.user_id
JOIN
computers c ON c.id = ll.computer_id
JOIN
ips i ON i.id = ll.ip_id
ORDER BY cnt DESC , u.samaccountname
SELECT
COUNT(*) AS cnt,
u.samaccountname,
ll.user_id,
u.name,
c.samaccountname,
ll.computer_id,
i.ip
FROM
latestlogons ll
JOIN
users u ON u.id = ll.user_id
JOIN
computers c ON c.id = ll.computer_id
JOIN
ips i ON i.id = ll.ip_id
GROUP BY user_id
ORDER BY cnt DESC
SELECT
d.name,
u.samaccountname,
u.name,
c.samaccountname,
e.event,
lu.dt
FROM
logonusers lu
JOIN
users u ON u.id = lu.user_id
JOIN
computers c ON c.id = lu.computer_id
JOIN
ips i ON i.id = lu.ip_id
JOIN
events e ON e.id = lu.event_id
JOIN
domains d ON d.id = lu.domain_id
WHERE
(i.ip LIKE '172.16.16.%'
OR i.ip LIKE '172.16.32%'
OR i.ip LIKE '172.16.33%'
OR i.ip LIKE '172.16.34%'
OR i.ip LIKE '172.16.35%')
AND lu.dt >= CURDATE() - INTERVAL 1 DAY
AND lu.dt <= CURDATE()
ORDER BY lu.dt
SELECT DISTINCT
c.samaccountname, u.samaccountname, u.name, i.ip
FROM
`latestdata` ld
LEFT JOIN
computers c ON c.id = ld.computer_id
LEFT JOIN
users u ON u.id = ld.user_id
LEFT JOIN
`events` e ON e.id = ld.computer_event_id
LEFT JOIN
`events` e2 ON e2.id = ld.user_event_id
LEFT JOIN
`ips` i ON ld.ip_id = i.id
LEFT JOIN
membership m ON m.uid = u.id
LEFT JOIN
groups g ON g.id = m.gid
WHERE
LOWER(g.name) = LOWER('$key')
Как определить залоченный экран у пользователя
Без аудита событий блокировки экрана можно сделать следующим способом (пишем в файл или используем вебсервис)
void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
{
switch (e.Reason)
{
// ...
case SessionSwitchReason.SessionLock:
// Do whatever you need to do for a lock
// ...
write_event("locked");
//MessageBox.Show("Locked" + DateTime.Now);
break;
case SessionSwitchReason.SessionUnlock:
// Do whatever you need to do for an unlock
// ...
write_event("unlocked");
//MessageBox.Show("UnLocked" + DateTime.Now);
break;
//case SessionSwitchReason.
// ...
}
}
void write_event (string e){
string computer = System.Environment.MachineName;
string user = Environment.UserName;
try
{
StreamWriter w = File.AppendText(@"\naslog$events" + user + @".domain1.ru.txt");
w.WriteLine(computer + ";" + user + ";" + e + ";" + DateTime.Now);
w.Close();
}
catch {}
}
private void Form1_Load(object sender, EventArgs e)
{
this.Opacity = 0;
this.ShowInTaskbar = false;
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(SystemEvents_SessionSwitch);
}
Данное приложение все-таки придется стартовать у пользователей, поэтому добавим возможность апдейтить приложение на лету:
string source = @"\nasuserstat$Dataactive_ws.exe";
string tempdir = System.IO.Path.GetTempPath();
string destFile = System.IO.Path.Combine(tempdir, "active_ws.exe");
if (File.Exists(source))
{
try
{
System.IO.File.Copy(source, destFile, true);
Process.Start(destFile);
}
catch (Exception e)
{
}
}
res = GET(«api/?», «s=status»);
System.Windows.Forms.Label label = new System.Windows.Forms.Label();
label.Text = reader.Value.ToString();
label.Name = "c_" + label.Text;
label.Width = 200;
label.Height = 50;
label.Top = 2 + (label.Height * label_cnt);
label.Left = 2;
label.Font = new System.Drawing.Font("Calibri", 24, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
label.ForeColor = Color.Red;
panel1.Controls.Add(label);
System.Windows.Forms.Button button = new System.Windows.Forms.Button();
button.Name = reader.Value.ToString();
button.Text = "Выполнить выход на данном ПК";
button.Left = 210;
button.Top = label.Top;
button.Font = new System.Drawing.Font("Calibri", 12, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
button.Width = 250;
button.Height = 50;
if (button.Name == System.Environment.MachineName)
{
button.Enabled = false;
button.Text = "Текущий ПК";
}
button.Click += new EventHandler(btn_Click);
panel1.Controls.Add(button);
private void btn_Click(object sender, EventArgs e)
{
string res = null;
foreach (Control item in panel1.Controls.OfType<Control>())
{
if (item.Tag == sender || item == sender)
{
item.Enabled = false;
item.Text = "Выход будет выполнен в течение 2-х минут";
try
{
res = POST("http://api/?", "s=logout&c=" + item.Name); //item.Name - содержит имя ПК
}
catch (Exception exception)
{
}
}
}
}
if (c_logoff == System.Environment.MachineName)
{
Process.Start("shutdown", "-l -f");
}
Старт дан, дальше только полет фантазии.
Автор: po3dno