none
UPDATE строк в БД MSSQL. PowerShell RRS feed

  • Вопрос

  • Всем привет.
    Используем MSSQL 2008R2,
    PowerShell 2.0.
    Суть: Есть код, который каждую секунду снимает список процессов на тачке и записывает их в скульную БД.
    Пример записи: 

    ProcessID   NAME    VMName  Start                 Close
    724 MsMpEng.exe NS1 Jan 21 2015 12:28PM Jan 21 2015 12:28PM
    1344    taskhost.exe    NS1 Jan 21 2015 12:28PM Jan 21 2015 12:28PM
    1648    armsvc.exe          NS1     Jan 21 2015 12:28PM Jan 21 2015 12:28PM
    

    (Кривовато но думаю суть ясна).
    Где ProcessID = ID процесса в винде
    Name = Имени процесса
    VMName = Имени машины
    2 столбца Start и Close = открытию процесса и закрытию.
    Проблема 1: Close заполняется при записи в таблицу(Понимаю криво видимо сделал Create(не понимаю как поправить). То есть вроде бы процесс открылся и должна произойти запись только в Start(Но нигде не стоит таких условий, как поставить не могу сообразить).
    Проблема 2: Нужно что бы при открытии процесса время записывалось в столбец "Start", при закрытии процесса он находился по таблице и писал дату и время закрытия в Close(Совсем не понимаю как это сделать).

    Create таблицы

    CREATE TABLE [dbo].[Tableqw](
    	[ProcessID] [varchar](max) NULL,
    	[NAME] [varchar](max) NULL,
    	[VMName] [varchar](max) NULL,
    	[Start] [varchar](40) NOT NULL,
    	[Close] [varchar](40) NOT NULL
    ) ON [PRIMARY]
    GO
    SET ANSI_PADDING OFF
    GO
    ALTER TABLE [dbo].[Tableqw] ADD  DEFAULT (getdate()) FOR [Start]
    GO
    ALTER TABLE [dbo].[Tableqw] ADD  DEFAULT (getdate()) FOR [Close]
    GO
    Часть кода:
    function getlist(){
     if($procListPrev) {
      [bool] 0 
      } 
      {[bool] 1}
     }
    #Если условия выполняються, отрабатываем код.
     $procListPrev = Get-WmiObject Win32_Process -Filter "Name like '%.exe'" | Where {$Exclude -notcontains $_.ProcessName} | Select Name,@{n="ID";e={$_.ProcessId}}
      while (getlist){
         Start-Sleep 1
      $procList = Get-WmiObject Win32_Process -Filter "Name like '%.exe'" | Where {$Exclude -notcontains $_.ProcessName} | Select Name,@{n="ID";e={$_.ProcessId}}
      $diff = Compare-Object -ReferenceObject $procList -DifferenceObject $procListPrev -Property ID -PassThru
       #Цикл записи в БД
       foreach ($proc in $diff) 
       {      
    if($proc -ne $null) 
    {
    $proc | Foreach {
    $SqlCmd.commandtext = "INSERT INTO baza.dbo.Tableqw (ProcessID, Name , VMName) VALUES ('$($_.ID)','$($_.Name)','$env:COMPUTERNAME')"
    $SqlCmd.executenonquery()  
         }
         }
           }
    $procListPrev = $procList
     }
    #Закрываем подключение к SQL.
    $SQLConnection.close()

    Заранее всем благодарен за помощь.


    22 января 2015 г. 6:45

Ответы

  • 1) При первичном запуске скрипта заполняем таблицу с процессами

    $proc = Get-WmiObject Win32_Process -Filter "Name like '%.exe'" | Where {$Exclude -notcontains $_.ProcessName}	 
    $proc | Foreach {
    	$Time = [System.Management.ManagementDateTimeConverter]::ToDateTime($_.CreationDate)
    	$SqlCmd.commandtext = "INSERT INTO baza.dbo.Tableqw (ProcessID, Name , VMName, Start, Close) VALUES ('$($_.ID)','$($_.Name)','$env:COMPUTERNAME', '$Time', '')"
    	$SqlCmd.executenonquery()  
    }

    2) Код ниже создает подписку на два события: Запуск и Завершение процесса

    3) Убрать значения по умолчанию для Start&Close и разрешить пустые значения

    ##New Process
    $WMI = @{
        Query = "Select * From Win32_ProcessStartTrace"
        Action = {
    		$ID = $event.SourceEventArgs.NewEvent.ProcessID
    		$Name = $event.SourceEventArgs.NewEvent.ProcessName
    		$Time = [datetime]::FromFileTime($event.SourceEventArgs.NewEvent.TIME_CREATED)
    		$SqlCmd.commandtext = "INSERT INTO baza.dbo.Tableqw (ProcessID, Name , VMName, Start, Close) VALUES ('$ID','$Name','$env:COMPUTERNAME','$Time','')"
    		$SqlCmd.executenonquery()  
        }
        SourceIdentifier = "Process.Created"
    }
    Register-WMIEvent @WMI | Out-Null
     
    ##Process End
    $WMI = @{
        Query = "Select * From Win32_ProcessStartTrace"
        Action = {
    		$ID = $event.SourceEventArgs.NewEvent.ProcessID
    		$Name = $event.SourceEventArgs.NewEvent.ProcessName
    		$Time = [datetime]::FromFileTime($event.SourceEventArgs.NewEvent.TIME_CREATED)
    		$SqlCmd.commandtext = "UPDATE baza.dbo.Tableqw SET Close = ""$Time"" WHERE ProcessID = ""$ID"""
    		$SqlCmd.executenonquery()
        }
        SourceIdentifier = "Process.Deleted"
    }
    Register-WMIEvent @WMI | Out-Null


    • Изменено KazunEditor 22 января 2015 г. 8:19
    • Помечено в качестве ответа Proflexs 22 января 2015 г. 9:22
    • Снята пометка об ответе Proflexs 27 января 2015 г. 9:25
    • Помечено в качестве ответа Proflexs 29 января 2015 г. 6:22
    22 января 2015 г. 8:13
    Отвечающий

Все ответы

  • 1) При первичном запуске скрипта заполняем таблицу с процессами

    $proc = Get-WmiObject Win32_Process -Filter "Name like '%.exe'" | Where {$Exclude -notcontains $_.ProcessName}	 
    $proc | Foreach {
    	$Time = [System.Management.ManagementDateTimeConverter]::ToDateTime($_.CreationDate)
    	$SqlCmd.commandtext = "INSERT INTO baza.dbo.Tableqw (ProcessID, Name , VMName, Start, Close) VALUES ('$($_.ID)','$($_.Name)','$env:COMPUTERNAME', '$Time', '')"
    	$SqlCmd.executenonquery()  
    }

    2) Код ниже создает подписку на два события: Запуск и Завершение процесса

    3) Убрать значения по умолчанию для Start&Close и разрешить пустые значения

    ##New Process
    $WMI = @{
        Query = "Select * From Win32_ProcessStartTrace"
        Action = {
    		$ID = $event.SourceEventArgs.NewEvent.ProcessID
    		$Name = $event.SourceEventArgs.NewEvent.ProcessName
    		$Time = [datetime]::FromFileTime($event.SourceEventArgs.NewEvent.TIME_CREATED)
    		$SqlCmd.commandtext = "INSERT INTO baza.dbo.Tableqw (ProcessID, Name , VMName, Start, Close) VALUES ('$ID','$Name','$env:COMPUTERNAME','$Time','')"
    		$SqlCmd.executenonquery()  
        }
        SourceIdentifier = "Process.Created"
    }
    Register-WMIEvent @WMI | Out-Null
     
    ##Process End
    $WMI = @{
        Query = "Select * From Win32_ProcessStartTrace"
        Action = {
    		$ID = $event.SourceEventArgs.NewEvent.ProcessID
    		$Name = $event.SourceEventArgs.NewEvent.ProcessName
    		$Time = [datetime]::FromFileTime($event.SourceEventArgs.NewEvent.TIME_CREATED)
    		$SqlCmd.commandtext = "UPDATE baza.dbo.Tableqw SET Close = ""$Time"" WHERE ProcessID = ""$ID"""
    		$SqlCmd.executenonquery()
        }
        SourceIdentifier = "Process.Deleted"
    }
    Register-WMIEvent @WMI | Out-Null


    • Изменено KazunEditor 22 января 2015 г. 8:19
    • Помечено в качестве ответа Proflexs 22 января 2015 г. 9:22
    • Снята пометка об ответе Proflexs 27 января 2015 г. 9:25
    • Помечено в качестве ответа Proflexs 29 января 2015 г. 6:22
    22 января 2015 г. 8:13
    Отвечающий
  • А если нам нужно что бы именно скуль ставил дату(занесения в базу)?
    22 января 2015 г. 9:21
  • А если нам нужно что бы именно скуль ставил дату(занесения в базу)?
    Добавить дополнительное поле в котором будет проставляться  дата.
    22 января 2015 г. 9:24
    Отвечающий
  • Исключение при вызове "ToDateTime" с "1" аргументами: "Заданный аргумент находится вне диапазона допустимых знач
    ений.
    Имя параметра: dmtfDate"
    C:\Users\User\Desktop\skript\GetProceccWMI.ps1:16 знак:2
    +     $Time = [System.Management.ManagementDateTimeConverter]::ToDateTime($_.Creation ...
    +    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : ArgumentOutOfRangeException

    23 января 2015 г. 12:12
  • Скорее всего попадается процесс у которого свойство CreationDate отсутсутствует, например процесс Idle. Поэтому можно игнорировать данную ошибку.
    23 января 2015 г. 12:27
    Отвечающий
  • Register-WMIEvent : Не удалось подписаться на указанное событие. Подписчик с идентификатором источника "Process.
    Deleted" уже существует.
    C:\Users\User\Desktop\skript\TestTa.ps1:52 знак:1
    + Register-WMIEvent @WMI | Out-Null
    + ~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (System.Management.ManagementEventWatcher:ManagementEventWatcher 
       ) [Register-WmiEvent], ArgumentException
        + FullyQualifiedErrorId : SUBSCRIBER_EXISTS,Microsoft.PowerShell.Commands.RegisterWmiEventCommand
    23 января 2015 г. 12:54
  • Подписчик с идентификатором источника "Process.Deleted" уже существует. - Зачем же дважды выполнять?
    23 января 2015 г. 13:00
    Отвечающий
  • =((
    696	cmd.exe	NS1	01/26/2015 16:20:58	

    Не проставляет время закрытия процесса.
    Код:
    $proc = Get-WmiObject Win32_Process -Filter "Name like '%.exe'" | Where {$Exclude -notcontains $_.ProcessName}	 
    $proc | Foreach {
    	$Time = [System.Management.ManagementDateTimeConverter]::ToDateTime($_.CreationDate)
    	$SqlCmd.commandtext = "INSERT INTO baza.dbo.Table2 (ProcessID, Name , VMName, Start, CloseProc) VALUES ('$($_.ID)','$($_.Name)','$env:COMPUTERNAME', '$Time', '')"
    	$SqlCmd.executenonquery()  
    }
    ##New Process
    $WMI = @{
        Query = "Select * From Win32_ProcessStartTrace"
        Action = {
    		$ID = $event.SourceEventArgs.NewEvent.ProcessID
    		$Name = $event.SourceEventArgs.NewEvent.ProcessName
    		$Time1 = [datetime]::FromFileTime($event.SourceEventArgs.NewEvent.TIME_CREATED)
    		$SqlCmd.commandtext = "INSERT INTO baza.dbo.Table2 (ProcessID, NAME , VMName, Start, CloseProc) VALUES ('$ID','$Name','$env:COMPUTERNAME','$Time1','')"
        	$SqlCmd.executenonquery()  
        
        }
      
    SourceIdentifier = "Process.Created"
    }
    Register-WmiEvent @WMI | Out-Null
    
    ##Process End
    $WMI = @{
        Query = "Select * From Win32_ProcessStartTrace"
        Action = {
    		$ID = $event.SourceEventArgs.NewEvent.ProcessID
    		$Name = $event.SourceEventArgs.NewEvent.ProcessName
    		$Time = [datetime]::FromFileTime($event.SourceEventArgs.NewEvent.TIME_CREATED)
    		$SqlCmd.commandtext = "UPDATE baza.dbo.Table2 SET CloseProc = ""$Time"" WHERE ProcessID = ""$ID"
    		$SqlCmd.executenonquery()
        }
    SourceIdentifier = "Process.Deleted"
    }
    Register-WMIEvent @WMI | Out-Null




    • Изменено Proflexs 26 января 2015 г. 13:38
    26 января 2015 г. 13:26
  • Попробывал так:
    $SqlCmd.commandtext = "UPDATE baza.dbo.Table2 SET CloseProc = '$Time' WHERE ProcessID = '$ID'"

    Проставляет сразу время и в Start и в CloseProc.
    Независимо от того закрылся процесс или еще открыт.
    • Изменено Proflexs 26 января 2015 г. 13:44
    26 января 2015 г. 13:43
  • UP! Актуально.
    27 января 2015 г. 12:15