none
Сверка значений в базе SQL и на Сервере RRS feed

  • Вопрос

  • Добрый день, коллеги!

    Была поставлена задача, написать скрипт, который каждую пятницу собирал имена ScheduleTask и учетные записи, от кого данные Task работают, со всех серверов в домене. Данный скрипт написан, занесен в планировщик заданий и работает успешно:

    cls
    
    
    $SQLQuery = "INSERT  [dbo].[schsrvinfo] VALUES "
    $conn=new-object System.Data.SqlClient.SQLConnection 
    $ConnectionString = "Server=UKM-SDBS10\SQLEXPRESS;Database=Schtask;Integrated Security=True;Connect Timeout=0"
    $conn.ConnectionString=$ConnectionString 
    $conn.Open()
    $cmd = $conn.CreateCommand()
    $date = Get-Date -Format s
    $commandText=""
    $isFirst = $true
    
    $AliveServers = @()
    #Adjusting ErrorActionPreference to stop on all errors
    $TempErrAct = $ErrorActionPreference
    $ErrorActionPreference = "Stop"
    #Defining Schedule.Service Variable
    $SchedService = New-Object -ComObject Schedule.Service
    
    $servers = get-adcomputer -filter 'Operatingsystem -like "Windows Server*"' -Properties LastLogonTimestamp,LastLogon | ?{ (($_.DistinguishedName -like "*OU=NSK,DC=int,DC=nsk,DC=corp") -or ($_.DistinguishedName -like "*OU=nsk-cls,DC=int,DC=nsk,DC=corp") -or ($_.DistinguishedName -like "*OU=NSK-MOF,DC=int,DC=nsk,DC=corp") -and ($_.enabled -eq "$true") -and ($([DateTime]::FromFileTime($_.LastLogonTimestamp)) -gt $(get-date).AddDays(-60)))}
    #$servers = get-adcomputer -filter 'Operatingsystem -like "Windows Server*"' -Properties LastLogonTimestamp,LastLogon | ?{ (($_.DistinguishedName -like "*OU=SGP,DC=int,DC=mechel,DC=corp") -or ($_.DistinguishedName -like "*OU=BAR,DC=int,DC=mechel,DC=corp") -and ($_.enabled -eq "$true"))}
    
    foreach ($server in $servers) {
    
    $testconnection = Test-Connection -Count 1 -ComputerName $server.Name -ErrorAction SilentlyContinue
    
    if ($testconnection -ne $null) {$Aliveservers += $server.name} else {$server.name >> "C:\Scripts\get-scheduled task\notPingedComputers.txt"}
    
    }
    
    Foreach ($Computer in $Aliveservers)
    {
                    
                       Write-Host "Проверяю сервер $Computer"
                    $desk = Get-ADComputer $Computer -Prop description #| select Name,Description 
                    try {
                            $uniq = (Get-WmiObject -Class Win32_OperatingSystem -ComputerName $Computer -ErrorAction SilentlyContinue).SerialNumber
                            $service = Get-WMIObject Win32_Service -ComputerName $Computer -ErrorAction SilentlyContinue | where {($_.startname -like "*nsk*")} 
                        }
                    catch [System.UnauthorizedAccessException]
                    {
                        $Computer >> "C:\Scripts\get-scheduled task\NotAccessToServer.txt"
                    }
                    finally {
                                Write-Host ″Finish.″
                            }
    
    Try
    {
    #Connecting to the Schedule.Service COM Object on $Computer"
    $SchedService.Connect($Computer)
    $TaskFolder = $SchedService.GetFolder("")
    $RootTasks = $TaskFolder.GetTasks("")
    Foreach ($Task in $RootTasks)
    {
    Switch ($Task.State)
    {
    0 {$Status = "Unknown"}
    1 {$Status = "Disabled"}
    2 {$Status = "Queued"}
    3 {$Status = "Ready"}
    4 {$Status = "Running"}
    }#End Switch ($Task.State)
    $Xml = $Task.Xml
    #The code below parses the Xml String Data for the "RunAs User" that is returned from the Schedule.Service COM Object
    [String]$RunUser = $Xml[(($Xml.LastIndexOf("<UserId>"))+8)..(($Xml.LastIndexOf("</UserId>"))-1)]
                                    [String]$Commands = $Xml[(($Xml.LastIndexOf("<Command>"))+9)..(($Xml.LastIndexOf("</Command>"))-1)]
    $RunUser = $RunUser.Replace(" ","").ToUpper()
                                    $Commands = $Commands.Replace(" ","").ToUpper()
    $Result = New-Object PSObject -Property @{
    ServerName=$Computer
    TaskName=$Task.Name
                                    Command=$Commands
    RunAs=$RunUser 
    Enabled=$Task.Enabled
    Status=$Status
    LastRunTime=$Task.LastRunTime
    Result=$Task.LastTaskResult
    NextRunTime=$Task.NextRunTime
    }#End $Result = New-Object
    
                                       if ($Result.RunAs -like "*NSK*")
                                       {
           
                                            
                                            $conn2 = new-object System.Data.SqlClient.SQLConnection 
                                            $conn2.ConnectionString=$ConnectionString 
                                            $conn2.Open()
                                            $cmdtemp = $conn2.CreateCommand()
    
                                            $commandText2 = -join("select  * from [dbo].[schsrvinfo] where ServerName = '",$Result.Servername,"' and TaskName = '",$Result.TaskName,"' and [UniqID] = '",$uniq,"'")
                                            $cmdtemp.CommandText  = $commandText2
                                            write-Host "BEGIN - '$cmdtemp.ExecuteReader()'"                                                                              
                                            $count = $cmdtemp.ExecuteReader()
                                            write-Host "END - '$cmdtemp.ExecuteReader()'"   
                                            if ($count.HasRows -eq $false)
                                            {
                                                $commandText = "('" + $date + "', '" + $Result.Servername + "','" + $Result.TaskName + "','" + $Result.RunAs + "','" + $Result.Enabled + "','" + $Result.Status + "','" + $Result.Command + "','" + $desk.Description + "','" + $uniq + "','" + $service.DisplayName + "','" + $service.startname + "')"
                                                $commandText >> "C:\Scripts\get-scheduled task\Computers_SchedTask2.txt"
                                                $SQLQuery = -join("INSERT  [dbo].[schsrvinfo] VALUES ", $commandText)
                                                $cmd.CommandText = $SQLQuery
                                                write-Host "BEGIN - '$cmd.ExecuteNonQuery()'"   
                                                $cmd.ExecuteNonQuery()
                                                write-Host "END - '$cmd.ExecuteNonQuery()'" 
                                            }
                                            else {Write-Warning "ТАКАЯ ЗАПИСЬ ЕСТЬ В БАЗЕ ДАННЫХ -> $cmd"}
                                            $count.Close()
                                            $count.Dispose()
                                            $conn2.Close()
                                       }
                                    else {"На сервере $Computer - RunAs не соотвествует - MECHEL"}
    
    
                                   }#End Foreach ($Task in $RootTasks)
    }#End Try
    Catch
    {
    $Error[0].Exception.Message
    }
                }
    
    $ErrorActionPreference = $TempErrAct
            $conn.Close() 

    Собственно в базе уже есть значения, по которым видны Task, теперь стоит задача, добавить в этот скрипт такую возможность, которая проверяла, был ли удален Task.

    То есть, сейчас в базе есть данные по серверам  и их таскам, в следующую пятницу скрипт опять выгружает эти данные и вносит в базу, но допустим в четверг какой то из тасков удалили, вот нужно, чтобы скрипт внес эту информацию, в новый столбец который я создам в базе.

    Подскажите как это можно реализовать?

    19 марта 2017 г. 7:38

Ответы

  • Добавить колонку IsDelete = 0|1  : 0 - не удалена, 1 - удалена

    Вставить после $isFirst = $true :
    $compare = @()
    
    Вставить после if ($Result.RunAs -like "*NSK*") { :
    
    $compare += [pscustomobject]@{
    	ServerName = $Result.Servername
    	TaskName = $Result.TaskName
    	UniqID = $uniq
    }
    
    Вставить перед foreach ($server in $servers) {:
    
    $dt = New-Object System.Data.DataTable
    $conn2 = new-object System.Data.SqlClient.SQLConnection 
    $conn2.ConnectionString=$ConnectionString 
    $conn2.Open()
    $cmdtemp = $conn2.CreateCommand()
    $commandText2 = "Select * From [dbo].[schsrvinfo] Where [ServerName] IS NOT NULL and [TaskName] IS NOT NULL and [UniqID] IS NOT NULL and IsDelete != 1"
    $cmdtemp.CommandText  = $commandText2
    $er = $cmdtemp.ExecuteReader()
    $dt.Load($er)
    $conn2.Close()
    
    $r = $er | Select ServerName,TaskName,UniqID
    
    Вставить после цикла foreach:
    Compare-Object $compare $r -Property ServerName,TaskName,UniqID | Where {$_.SideIndicator -eq "<="} | Foreach {
        $SQLQuery = UPDATE [dbo].[schsrvinfo] SET [IsDelete]=1 WHERE [Column] Where [ServerName]='$($_.ServerName)' and [TaskName]='$($_.TaskName)' and [UniqID]='$($_.UniqID)'"
        $cmd.CommandText = $SQLQuery
        $cmd.ExecuteNonQuery()
    }
    

    • Помечено в качестве ответа eclegolas 20 марта 2017 г. 12:32
    19 марта 2017 г. 15:56
    Отвечающий
  • 1) IsDelete типа int

    2) Вставить перед foreach ($server in $servers) {: - По-русски написал ПЕРЕД , а не после.

    3) Проверить в SQL Management Studio запрос Select
    4) Попробовать указать:  [dbo].[schsrvinfo].[IsDelete]
    • Изменено KazunEditor 20 марта 2017 г. 6:11
    • Помечено в качестве ответа eclegolas 20 марта 2017 г. 12:32
    20 марта 2017 г. 6:08
    Отвечающий

Все ответы

  • Добавить колонку IsDelete = 0|1  : 0 - не удалена, 1 - удалена

    Вставить после $isFirst = $true :
    $compare = @()
    
    Вставить после if ($Result.RunAs -like "*NSK*") { :
    
    $compare += [pscustomobject]@{
    	ServerName = $Result.Servername
    	TaskName = $Result.TaskName
    	UniqID = $uniq
    }
    
    Вставить перед foreach ($server in $servers) {:
    
    $dt = New-Object System.Data.DataTable
    $conn2 = new-object System.Data.SqlClient.SQLConnection 
    $conn2.ConnectionString=$ConnectionString 
    $conn2.Open()
    $cmdtemp = $conn2.CreateCommand()
    $commandText2 = "Select * From [dbo].[schsrvinfo] Where [ServerName] IS NOT NULL and [TaskName] IS NOT NULL and [UniqID] IS NOT NULL and IsDelete != 1"
    $cmdtemp.CommandText  = $commandText2
    $er = $cmdtemp.ExecuteReader()
    $dt.Load($er)
    $conn2.Close()
    
    $r = $er | Select ServerName,TaskName,UniqID
    
    Вставить после цикла foreach:
    Compare-Object $compare $r -Property ServerName,TaskName,UniqID | Where {$_.SideIndicator -eq "<="} | Foreach {
        $SQLQuery = UPDATE [dbo].[schsrvinfo] SET [IsDelete]=1 WHERE [Column] Where [ServerName]='$($_.ServerName)' and [TaskName]='$($_.TaskName)' and [UniqID]='$($_.UniqID)'"
        $cmd.CommandText = $SQLQuery
        $cmd.ExecuteNonQuery()
    }
    

    • Помечено в качестве ответа eclegolas 20 марта 2017 г. 12:32
    19 марта 2017 г. 15:56
    Отвечающий
  • Добрый день!

    Спасибо за ответ. Но к сожалению не работает, в коде:

    foreach ($server in $servers) {
    
    $dt = New-Object System.Data.DataTable
    $conn2 = new-object System.Data.SqlClient.SQLConnection 
    $conn2.ConnectionString=$ConnectionString 
    $conn2.Open()
    $cmdtemp = $conn2.CreateCommand()
    $commandText2 = "Select * From [dbo].[schsrvinfo] Where [ServerName] IS NOT NULL and [TaskName] IS NOT NULL and [UniqID] IS NOT NULL and IsDelete != 1"
    $cmdtemp.CommandText  = $commandText2
    $er = $cmdtemp.ExecuteReader()
    $dt.Load($er)
    $conn2.Close()


    Выполняется ошибка:

    Исключение при вызове "ExecuteReader" с "0" аргументами: "Invalid column name 'IsDelete'."
    C:\Scripts\get-scheduled task\test_1.ps1:34 знак:1
    + $er = $cmdtemp.ExecuteReader()
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
        + FullyQualifiedErrorId : SqlException

    Причем, такой столбец я создал:

    Подскажите пожалуйста, что я делаю не так?)

    20 марта 2017 г. 5:49
  • 1) IsDelete типа int

    2) Вставить перед foreach ($server in $servers) {: - По-русски написал ПЕРЕД , а не после.

    3) Проверить в SQL Management Studio запрос Select
    4) Попробовать указать:  [dbo].[schsrvinfo].[IsDelete]
    • Изменено KazunEditor 20 марта 2017 г. 6:11
    • Помечено в качестве ответа eclegolas 20 марта 2017 г. 12:32
    20 марта 2017 г. 6:08
    Отвечающий