Windows login és az őt felruházó csoporttagságok

Klasszikus probléma, hogy van egy Windows login az SQL szerveren, aki benne van N csoportban, amik benne vannak másik M csoportban, és a répamese jegyében ez összesen nagyon sok csoport lesz. A kérdés pedig az, hogy pontosan melyik csoporttagságán keresztül milyen jogot is szerzett az SQL szerveren. Na, pont erre nyomtam egy lenyűgöző Powershell demót a SQL 2008 R2 bejelentési eseményen, aztán elhagytam a scriptet. Mivel valami dupla mákos hakkolás volt, próbáltam felhajtani, de nem sikerült. Viszont a vicc, hogy ugyanezt a fícsört megtaláltam beleépítve a SQL szerverbe.

A neve xp_logininfo, és két irányba is működik:

exec master..xp_logininfo [EMEA\EBitemo], 'all'

megmondja az összes csoportot, melyen keresztül engem beenged a SQL Server.

exec master..xp_logininfo [EMEA\#DBA_Operators], 'members'

pedig megmondja, h kiket is enged ő be azon a csoporton keresztül.

Ezzel TT felé való négyhónapos adósságomat rendezettnek tekintem :)

Backup listázás PowerShellben

Az SQL 2008 R2 előadásomon a Lurdy Házban mutattam egy PS scriptet, ami a következő igényt elégíti ki: egy fájlrendszeren lakó könyvtárban lévő backup fájlokból kinyalja a backup információkat. Íme a script:

function List-Backups(
[string] $filename, ##fájl vagy könyvtárnév, dir parancs számára emészthető input kell
$Html, ## HTML fájl output neve, .\ prefix kell neki lokális esetén
$servername = '.' ## az SQL Server, aki lefuttatja a restore headeronly parancsot
) {

## a tulajdonságok, amik kellenek - teljes lista a BOL-ban
$proplist = ('Position', 'DatabaseName','ServerName','BackupFinishDate','DatabaseVersion')
## mint fent, csak a filename mezővel prefixeltem. igénytelen, de gyors megoldás,
$proplist2 = ('FileName', 'Position', 'DatabaseName','ServerName','BackupFinishDate','DatabaseVersion')

## ez a tömb tárolja a teljes listát
$allbck = @()

foreach ($file in (dir $filename)) ## ezért kellett dir kompatibilis input
  {
  ## lefut a restore headeronly...
  $backups = invoke-sqlcmd -ServerInstance ".\mysql" -Query "restore headeronly from disk = '$($file.FullName)'"
  $bck = @()
  ## a kiválasztott mezoket eltesszük a $bck változóba.
  ##   Igazából perzisztált scriptben nem illik olyan shortcutokat használni, mint % (foreach) meg ? (where)
  $backups|select $proplist|%{$bck += $_}
  ## hozzáadjuk a fájlnevet is...
  $bck |add-member noteproperty filename $file.FullName
  ## ... és a kibövitett listát eltesszük az összegzett listába
  $allbck += $bck|select $proplist2
  } #foreach $file
## kiírjuk az összegzett listát a standard outputra - ez a függvény kimenete
$allbck
## ha meg lett adva HTML fájlnév, akkor abba is kitoljuk a táblázatot, és meg is nyitjuk. Itt lehetne kezelni a .\ hiányát, de nem tettem, lustaságból
if ($Html)
  {
  $allbck|ConvertTo-Html|Out-file $Html
  ## itt nyitjuk meg, az alkalmazás a default app a megadott kiterjesztéshez, tehát a böngészőnk htm(l)-nél
  invoke-expression $Html
  } #if $html
}  #function List-Backups

## És nézzünk néhány példát is:

## nézzük meg a D:\SQLData\Backups könyvtár tartalmát, HTML-ben is
List-Backups D:\SQLData\Backups .\lista.html
## nézzünk meg egyetlen fájlt a konzolon
List-Backups D:\SQLData\Backups\Full.BAK
##keressük meg a Billing adatbázis legfrissebb full backupját tartalmazó fájlt és a backup pozícióját a megadott könyvtárban
List-Backups D:\SQLData\Backups | ?{$_.DatabaseName -eq 'Billing' -and $_.BackupTypeDescription -eq 'DATABASE'} | `
 Sort -prop BackupFinishDate -desc| select Filename, Position -first 1

Az utolsó parancsba beletoltam több mindent is. A ? (where) a szűrést hivatott bemutatni, a -eq és az -and a vicces operátorokat, amit el is rontottam a demóban, a backtick a többsoros parancs sorvégét jelzi, a többi meg magától értetődő, de azért jó látni, hogy a lehetőségek szinte korlátlanok.

Tárolt eljárások definíciójában keresés

Időről időre visszatérő probléma: melyik tárolt eljárást érinti egy adott tábla módosítása, melyik SP-ben van deprecated (elavult) (NOLOCK) hint, effélék – szóval keresni kell a definíciókban. Ezt sokféleképpen megtehetjük, a legkényelmesebb a definíciók felolvasása. Régebben az INFORMATION_SCHEMA.ROUTINES ANSI standard metatáblát használtam erre, most már váltottam a meglehetősen nem intuitív nevű sys.sql_modules rendszernézetre. A különbség egyébként nem nagy – a standardban csak az első 4000 karakter látszik, a MSSQL-specifikus pedig nvarchar(max), tehát hajszálnyit több fér bele.

Ebből született a tárolt eljárásban stringet kereső tárolt eljárás. Két paramétert vár: a stringet, amire keresni akarunk és az adatbázis nevét, amiben keresni akarunk. Ha az egész szerveren szeretnénk keresni, akkor használhatjuk az undocumented sp_MSforeachdb tárolt eljárást.

CREATE PROCEDURE dbo.spFindTextInSP
@string nvarchar(1000),
@dbname sysname = ''
AS
if (isnull(@dbname,'') = '')
        set @dbname = db_name()
declare @q nvarchar(2000)
set @q = 'select quotename(object_schema_name(object_id,db_id('''+ @dbname + '''))) + ''.'' + quotename(object_name(object_id,db_id(''' + @dbname +  '''))) AS matching_objects from ' + @dbname + '.sys.sql_modules
where definition like ''%' + @string + '%'''
exec(@q)

GO

-- és két minta felhasználás
exec dbo.spFindTextInSp 'alert'
exec dbo.spFindTextInSp 'alert', 'Customer_archiv'

Log shipping PowerShell scripttel

Egy hónapja ígértem meg Tibornak azt a PowerShelles log shipping megoldást, amit használtunk SQL 2000-2005 migrációra. Az alapgondolat a következő: a 2000-es szerveren csinálunk egy log backup jobot, ami már az új szerverre, UNC-n keresztül teszi le a backup fájlokat. Ez egy sima T-SQL job. A 2005-ös szerveren pedig egy Operating System jobstep lakik, ami egy powershell scriptet futtat. A jobstep maga kb. ennyi: powershell.exe D:\mssql\MigrateMyDB.ps1. Ez most egy bedrótozott verzió, de elég egyszerűen átalakítható paraméterezhetővé, és akkor egy scripttel lehet több adatbázist is tutujgatni.
Continue reading ‘Log shipping PowerShell scripttel’ »

Nyelvtörő

Éppen a hülye elnevezésekről beszélgettünk a munkahelyemen, amik már magukban hordozzák az elszúrás lehetőségét (mint pl. a minval változónév a legnagyobb értéknek, a maxval meg a legkisebbnek), amikor megint előkerült kedvenc SQL-es példám, amit a szintaktikai ellenőrző is csak sírva enged át. Gondoltam megosztom veletek, lássátok, hogy igazán rossz kódot még sosem adtak át nektek. Ehhez lépest a DropTable nevű objektum az egyik üzemelő adatbázisban kismiska.

SELECT SELECT SELECT FROM FROM FROM WHERE WHERE LIKE LIKE

Ez így ebben a formában még hibát dob, de ha szépen jelöljük az identifiereket, akkor már lefut:

SELECT [SELECT] [SELECT] FROM [FROM] [FROM] WHERE [WHERE] LIKE [LIKE]

Persze kell alá egy tábla is, esetleg némi adat is:

CREATE TABLE [FROM]
([SELECT] varchar(20),
[WHERE] int,
[LIKE] int)

INSERT INTO [FROM] VALUES('szegyellem magamat', 1, 1)

Így már világos, hogy a SELECT nevű oszlopnak adtunk egy aliast, ami pont a SELECT megint, hasonlóan tettünk a FROM tábla nevével is, a többi meg gyerekjáték innentől kezdve. Szeretném kihangsúlyozni, hogy ez NEM best practice, vagy bármilyen formában követendő példa, hacsak nem akarunk a pokolra jutni közönségszavazat alapján. Inkább rá is teszem a humor cimkét erre a postra.