Лучший отвечающий
Проверить логинился ли пользователь в течении 90 дней

Вопрос
-
Доброго времени суток.
Есть сверхзадача - проверить подключался ли пользователь хоть раз за 90 дней по vpn.
Суть вопроса:
VPN предоставляется по срадствам Cisco ASA 5520. Логи её складываются на СХД. Имя файла лога имеет вид:
asa5520-20140915.gz(архивный) asa5520-20140916.gz asa5520-20140917.gz ... и т.д. 90 файлов за 90 дней . Хотелось бы для пользователей группы VPN в AD (Windows Server 2012 уровень функциональности 2012) проверить логинился ли он хоть раз в течении 90 дней. Строка коннекта в логе имеет вид:
Sep 14 21:03:41 10.206.25.6 Sep 14 2014 21:03:40: %ASA-4-722051: Group <GrPol_business-2> User <ivan.ivanov> IP <xxx.xxx.xxx.xxx> Address <10.200.224.125> assigned to session
Как я себе это вижу:
получить всех пользователей группы, получить текущую дату и просмотреть все 90 файлов коннектился ли пользователь со своим SamAccountName хоть раз за это время и результат выдать в файл и отправиь по почте. Дело в том что логи очень большие и пользователей порядка 100 да к тому же логи архивированы...
Возможно ли это реализовать на PoSh 4.0. Прошу не ругать за наглость - вы уж помогите кто чем может.
30 сентября 2014 г. 7:20
Ответы
-
Примерно так можно получить список всех пользователей, присутствующих в логах:
-89..0|ForEach-Object { $Date=Get-Date }{ $FileName=$Date.AddDays($_).ToString('a\sa5520-yyyyMMdd.\g\z') $File=[System.IO.File]::OpenRead($filename) try{ $ByteStream=New-Object System.IO.Compression.GZipStream $File,([System.IO.Compression.CompressionMode]::Decompress) try{ $StringStream=New-Object System.IO.StreamReader $ByteStream try{ while(($String=$StringStream.ReadLine())-ne$null){ $String } }finally{ $StringStream.Close() } }finally{ $ByteStream.Close() } }finally{ $File.Close() } }|ForEach-Object { if($_-match'User <([^>]+)>'){ $Matches[1] } }|Select-Object -Unique
- Предложено в качестве ответа Vector BCOModerator 1 октября 2014 г. 7:23
- Помечено в качестве ответа KazunEditor 9 октября 2014 г. 7:23
30 сентября 2014 г. 18:00 -
$group = Get-ADGroupMember ADministrators -Recursive | Foreach {$_.SamAccountName} $vpn = -89..0|ForEach-Object {Остальная часть кода выше Compare-Object $group $vpn | Where {$_.SideIndicator -eq "<="}
- Предложено в качестве ответа Vector BCOModerator 1 октября 2014 г. 7:23
- Помечено в качестве ответа KazunEditor 9 октября 2014 г. 7:23
1 октября 2014 г. 7:01Отвечающий -
Можно при первом запросе кешировать результат в файл, а при повторном просто брать из кеша.
-89..0|ForEach-Object { $LogsPath='C:\Logs' $CachePath=$LogsPath $Date=Get-Date }{ $FileName=$Date.AddDays($_).ToString('a\sa5520-yyyyMMdd.\g\z') $CacheFile=Join-Path $CachePath ($FileName+'.cache') if((Test-Path $CacheFile)){ Get-Content $CacheFile }else{ $LogFile=Join-Path $LogsPath $FileName &{ $File=[System.IO.File]::OpenRead($LogFile) try{ $ByteStream=New-Object System.IO.Compression.GZipStream $File,([System.IO.Compression.CompressionMode]::Decompress) try{ $StringStream=New-Object System.IO.StreamReader $ByteStream try{ while(($String=$StringStream.ReadLine())-ne$null){ $String } }finally{ $StringStream.Close() } }finally{ $ByteStream.Close() } }finally{ $File.Close() } }|ForEach-Object { if($_-match'User <([^>]+)>'){ $Matches[1] } }|Select-Object -Unique|Tee-Object $CacheFile } }|Select-Object -Unique
- Помечено в качестве ответа KazunEditor 9 октября 2014 г. 7:24
2 октября 2014 г. 6:07
Все ответы
-
Примерно так можно получить список всех пользователей, присутствующих в логах:
-89..0|ForEach-Object { $Date=Get-Date }{ $FileName=$Date.AddDays($_).ToString('a\sa5520-yyyyMMdd.\g\z') $File=[System.IO.File]::OpenRead($filename) try{ $ByteStream=New-Object System.IO.Compression.GZipStream $File,([System.IO.Compression.CompressionMode]::Decompress) try{ $StringStream=New-Object System.IO.StreamReader $ByteStream try{ while(($String=$StringStream.ReadLine())-ne$null){ $String } }finally{ $StringStream.Close() } }finally{ $ByteStream.Close() } }finally{ $File.Close() } }|ForEach-Object { if($_-match'User <([^>]+)>'){ $Matches[1] } }|Select-Object -Unique
- Предложено в качестве ответа Vector BCOModerator 1 октября 2014 г. 7:23
- Помечено в качестве ответа KazunEditor 9 октября 2014 г. 7:23
30 сентября 2014 г. 18:00 -
А как прикрутить сюда выборку из группы безопасности SamAccountName пользователей и проверку тех кого нет???1 октября 2014 г. 5:16
-
$group = Get-ADGroupMember ADministrators -Recursive | Foreach {$_.SamAccountName} $vpn = -89..0|ForEach-Object {Остальная часть кода выше Compare-Object $group $vpn | Where {$_.SideIndicator -eq "<="}
- Предложено в качестве ответа Vector BCOModerator 1 октября 2014 г. 7:23
- Помечено в качестве ответа KazunEditor 9 октября 2014 г. 7:23
1 октября 2014 г. 7:01Отвечающий -
получился такой скрипт:
$group = Get-ADGroupMember vpn-business -Recursive | Foreach {$_.SamAccountName}
$vpn = -89..0|ForEach-Object
{
$Date=Get-Date
{
$FileName=$Date.AddDays($_).ToString('a\sa5520-yyyyMMdd.\g\z')
$File=[System.IO.File]::OpenRead($filename)
try{
$ByteStream=New-Object System.IO.Compression.GZipStream $File,([System.IO.Compression.CompressionMode]::Decompress)
try{
$StringStream=New-Object System.IO.StreamReader $ByteStream
try{
while(($String=$StringStream.ReadLine())-ne$null){
$String
}
}finally{
$StringStream.Close()
}
}finally{
$ByteStream.Close()
}
}finally{
$File.Close()
}
}|ForEach-Object {
if($_-match'User <([^>]+)>'){
$Matches[1]
}
}|Select-Object -Unique
Compare-Object $group $vpn | Where {$_.SideIndicator -eq "<="
}
}но он выводит:
cmdlet ForEach-Object at command pipeline position 1
Supply values for the following parameters:
Process[0]:не подскажите как указать ему путь к требуемым файлам?
1 октября 2014 г. 8:46 -
Ему требуется не путь, а указать scriptblock. Это от того, что скрипт даже правильно скопировать не смогли.
$vpn = -89..0|ForEach-Object { - Фигурная скобка должна быть на той же строке, а не на новой.
1 октября 2014 г. 9:03Отвечающий -
Ваша правда!
А не подскажете как указать ему путь где хрантся файлы? А то он у меня исчет файлы в профиле пользователя от которого запускается скрипт...
1 октября 2014 г. 9:56 -
$FileName= "C:\folder\" + $Date.AddDays($_).ToString('a\sa5520-yyyyMMdd.\g\z')1 октября 2014 г. 10:05Отвечающий
-
Отлично! Работает!!!
Не сочтите за нахальство но уважаемый Kazun а Вы не подскажите как распаралелить процесс а то поиск занимает часы т.к. в файлах в среднем 400 000 строк... Ещё раз огромное спасибо!!!!
1 октября 2014 г. 12:38 -
Вопрос в том, что является узким местом в данном случае. Если это дисковый ввод/вывод, то его вряд ли получится распараллелить. Возможно имеет смысл по каждому лог-файлу один раз построить выжимку, которая бы содержала только имена пользователей, а потом с этими выжимками работать.1 октября 2014 г. 19:14
-
а как это реализовать не подскажите?2 октября 2014 г. 5:25
-
Можно при первом запросе кешировать результат в файл, а при повторном просто брать из кеша.
-89..0|ForEach-Object { $LogsPath='C:\Logs' $CachePath=$LogsPath $Date=Get-Date }{ $FileName=$Date.AddDays($_).ToString('a\sa5520-yyyyMMdd.\g\z') $CacheFile=Join-Path $CachePath ($FileName+'.cache') if((Test-Path $CacheFile)){ Get-Content $CacheFile }else{ $LogFile=Join-Path $LogsPath $FileName &{ $File=[System.IO.File]::OpenRead($LogFile) try{ $ByteStream=New-Object System.IO.Compression.GZipStream $File,([System.IO.Compression.CompressionMode]::Decompress) try{ $StringStream=New-Object System.IO.StreamReader $ByteStream try{ while(($String=$StringStream.ReadLine())-ne$null){ $String } }finally{ $StringStream.Close() } }finally{ $ByteStream.Close() } }finally{ $File.Close() } }|ForEach-Object { if($_-match'User <([^>]+)>'){ $Matches[1] } }|Select-Object -Unique|Tee-Object $CacheFile } }|Select-Object -Unique
- Помечено в качестве ответа KazunEditor 9 октября 2014 г. 7:24
2 октября 2014 г. 6:07 -
Выдаёт ошибку:
Exception calling "OpenRead" with "1" argument(s): "The given path's format is not supported."
At line:15 char:13
+ $File=[System.IO.File]::OpenRead($LogFile)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
You cannot call a method on a null-valued expression.
At line:31 char:17
+ $File.Close()
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
New-Object : Exception calling ".ctor" with "2" argument(s): "Value cannot be null.
Parameter name: stream"
At line:17 char:29
+ $ByteStream=New-Object System.IO.Compression.GZipStream $File,([ ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand2 октября 2014 г. 6:27 -
Покажите конкретный путь, который получается в переменной $LogFile.2 октября 2014 г. 6:31
-
PS C:\Users\administrator> $LogsPath
C:\111\Logs2 октября 2014 г. 6:59 -
Не $LogsPath, а $LogFile.2 октября 2014 г. 7:03
-
Пардон
Вот:
PS C:\Users\administrator> $LogFile
C:\111\Logs\C:\111\asa\asa5520-20141002.gz2 октября 2014 г. 8:52 -
Путь к папке с логами я вынес в отдельную переменную $LogsPath, так что его не нужно добавлять к переменной $FileName. Переменная $FileName должна содержать только имя файла.
- Изменено PetSerAl 2 октября 2014 г. 8:59
2 октября 2014 г. 8:58 -
Мне кажется можно сделать проще, если циска авторизуется на AD то можно взять параметр LastLogon из AD
function Get-ADUserLastLogon([string]$userName)
{
$dcs = Get-ADDomainController -Filter {Name -like "*"}
$time = 0
foreach($dc in $dcs)
{
$hostname = $dc.HostName
$user = Get-ADUser $userName | Get-ADObject -Properties lastLogon
if($user.LastLogon -gt $time)
{
$time = $user.LastLogon
}
}
$dt = [DateTime]::FromFileTime($time)
Write-Host $username "last logged on at:" $dt }
Get-ADUserLastLogon -UserName SaraDavisMCITP, MCTS, OCA.
2 октября 2014 г. 9:09 -
Я думал над этим.
Дело в том что эта функция не всегда корректно отрабатывает
2 октября 2014 г. 9:17 -
Ой да!!!
Написал Вам а потом полез смотреть - действительно я лоханулся!!!
2 октября 2014 г. 9:19 -
get-adgroupMember GROUPNAME | foreach {
$user = Get-ADUser $_.SamAccountName
$user.SamAccountName
}MCITP, MCTS, OCA.
2 октября 2014 г. 9:28 -
Обычно когда берется время входа оно берется с одного контроллера домена, а пользователь мог авторизоваться на другом. В этом скрипте опрашиваются все контроллеры и сравнивается время входа.
MCITP, MCTS, OCA.
2 октября 2014 г. 9:32 -
Спасибо за ответ.
Но дело в том что они могут так же логинится не только через впн но и на работе в нутри сети. Так что это не подходит
2 октября 2014 г. 10:50 -
Ну скрипт отработал.Не скажу что стало быстрее. А подскажите как теперь сравнить вывод скрипта с членами группы впн???3 октября 2014 г. 7:10
-
При первом вызове он и не должен работать быстрее, зато последующие вызовы должны брать результат из кэша, если Вы его не удалили. Как сравнивать Вам уже отвечали:
$group = Get-ADGroupMember ADministrators -Recursive | Foreach {$_.SamAccountName} $vpn = -89..0|ForEach-Object {Остальная часть кода выше Compare-Object $group $vpn | Where {$_.SideIndicator -eq "<="}
3 октября 2014 г. 20:48