Synchronizacja danych w AD z MS SQL

Dlaczego ostatnio tak rozpisywałem się odnośnie zarządzania Active Directory z poziomu PowerShella ? Mianowicie przyszło mi zmierzyć się z drobnym projektem, którego celem było zintegrowanie dwóch niezależnych od siebie systemów. Nie mogę podać za wiele szczegółów, ale sytuacja wyglądała następująco: system A musiał synchronizować dane odnośnie kont użytkowników zawartych w bazie danych opartych o MS SQL, z systemem B opartym o pracę na kontrolerze domeny.

Może się wydawać skomplikowane rozwiązanie niemniej dla PowerShella to żadna przeszkoda. Oczywiście można było tutaj skorzystać z gotowych modułów do zarządzania SQL’em oraz Active Directory, ale odebrało by to całą zabawę związaną ze stworzeniem własnego rozwiązania 🙂

Zatem jak więc można rozwiązać powyższy problem ?? Najpierw tworzymy sobie funkcję pozwalającą nam skorzystać z informacji zawartych w bazie danych. Do tego celu tworzymy sobie connection string w celu nawiązania połączenia z bazą danych:

param(
  [string] $dataSource = "TESTSERVER",
  [string] $database = "TESTOWA",
  [string] $sqlCommand
)

$connectionString = "Provider=sqloledb; " +
"Data Source=$dataSource; " +
"Initial Catalog=$database; " +
"Integrated Security=SSPI;"

Następnie tworzymy obiekt połączenia oraz obiekt zapytania do bazy:

$connection = New-Object System.Data.OleDb.OleDbConnection $connectionString
$command = New-Object System.Data.OleDb.OleDbCommand $sqlCommand,$connection

Otwieramy połączenie, tworzymy obiekt OleDbDataAdapter oraz DataSet i wysyłamy zapytanie do serwera:

$connection.Open()
$adapter = New-Object System.Data.OleDb.OleDbDataAdapter $command
$dataset = New-Object System.Data.DataSet
[void] $adapter.Fill($dataSet)
$connection.Close()

Ostatecznie zwracamy wynik zapytania:

$dataSet.Tables | Select-Object -Expand Rows

Pobieramy informacje za pomocą naszej funkcji:

$Users = Get-SqlData –sqlCommand “Select login, imie, nazwisko From Users”

Gdy pobierzemy już konieczne informacje z bazy danych przystąpmy do synchronzacji ich z kontrolerem domeny.

Tworzymy drugą funckję w której najpierw podłączamy się do kontrolera.

param(
  $Users
)
$LDAP = ([ADSI]'LDAP://rootDSE').defaultNamingContext.value
$ADObj = [ADSI]"LDAP://CN=Users,$LDAP"

I dla każdego z użytkowników dokonujemy synchronizacji danych:

ForEach($User in $Users)
{
  if(!([ADSI]"LDAP://CN=$($User.login),CN=Users,$LDAP").distinguishedName)
  {
    $NewCN = $ADObj.Create("User", "CN=$($User.login)")
    $NewCN.put("givenName",$($User.imie))
    $NewCN.put("sn",$($User.nazwisko))
    #ewentualnie synchronizujemy inne potrzebne atrybuty
    $NewCN.SetInfo()
  }
  else
  {
    $CurrentCN = [ADSI]LDAP://CN=$($User.login),CN=Users,$LDAP
    $CurrentCN.put("givenName",$($User.imie))
    $CurrentCN.put("sn",$($User.nazwisko))
    $CurrentCN.SetInfo()
  }
}

Jest to tylko i wyłącznie zarys, a wręcz bym powiedział ogólna koncepcja podejścia do problemu. Niemniej jednak powinna być na tyle zrozumiała, aby pomóc w jego rozwiązaniu.

Cały kod powinien wyglądać następująco:

function Get-SqlData
{
  param(
    [string] $dataSource = "TESTSERVER",
    [string] $database = "TESTOWA",
    [string] $sqlCommand
  )
  $connectionString = "Provider=sqloledb; " +
  "Data Source=$dataSource; " +
  "Initial Catalog=$database; " +
  "Integrated Security=SSPI; "

  $connection = New-Object System.Data.OleDb.OleDbConnection $connectionString
  $command = New-Object System.Data.OleDb.OleDbCommand $sqlCommand,$connection
  $connection.Open()

  $adapter = New-Object System.Data.OleDb.OleDbDataAdapter $command
  $dataset = New-Object System.Data.DataSet
  [void] $adapter.Fill($dataSet)
  $connection.Close()

  $dataSet.Tables | Select-Object -Expand Rows
}

function Set-ADSynch
{
  param(
    $Users
  )

  $LDAP = ([ADSI]'LDAP://rootDSE').defaultNamingContext.value
  $ADObj = [ADSI]LDAP://CN=Users,$LDAP

  ForEach($User in $Users)
  {
    if(!([ADSI]"LDAP://CN=$($User.login),CN=Users,$LDAP").distinguishedName)
    {
      $NewCN = $ADObj.Create("User", "CN=$($User.login)")
      $NewCN.put("givenName",$($User.imie))
      $NewCN.put("sn",$($User.nazwisko))
      #ewentualnie synchronizujemy inne potrzebne atrybuty
      $NewCN.SetInfo()
    }
    else
    {
      $CurrentCN = [ADSI]LDAP://CN=$($User.login),CN=Users,$LDAP
      $CurrentCN.put("givenName",$($User.imie))
      $CurrentCN.put("sn",$($User.nazwisko))
      $CurrentCN.SetInfo()
    }
  }
}

$Users = Get-SqlData –sqlCommand “Select login, imie, nazwisko From Users”
Set-ADSynch –Users $Users
Reklamy

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s