Laerte's profile$hell Your Experience !!...PhotosBlogListsMore Tools Help

Blog


    November 18

    Lendo, Filtrando, Salvando numa tabela do SQL ou em XML…Sushi…Enfim..Fazendo peripécias com o arquivo de trace do SQL Server Profiler usando POWERSHELL!!!!

     

    (english version  post below)

    Requer Powershell V2.0

    Eu tinha um grande problema para ser resolvido. Meus arquivos de trace do profiler eram separados por folder, servidor, nome do trace mas a grande maioria tinha o “enable file rollover” selecionado gerando varias divisões do mesmo arquivo.

    Eramos em três turnos de DBA´s. Cada um gerava seus arquivos de trace conforme precisasse, mas várias vezes tive que acessar os traces gerados pelos outros dba´s juntando algumas colunas que com certeza não eram comuns entre os arquivos. Um era SP_locks por exemplo, o outro duration. Por que eu fazia isso ? Um duration alto que foi pego num trace, eu queria cruzar com o de locks do dia anterior para análise, entre vários outros cruzamentos.

    Isto era realmente complicado de se fazer de uma forma automatizada, uniforme e repetitiva. Até mesmo juntar todos os arquivos do mesmo trace era um trabalho chato. Eu poderia usar a fn_trace_gettable  sem problema algum, mas quando falamos em automatizar este processo a coisa ficava grande em TSQL. Pior ainda se eu precisasse juntar, como eu disse, arquivos de traces diferentes.

    Foi quando resolvi usar powershell

    Um dos parâmetros da função quando comecei a pensar na solução foi gerar os arquivos em tabelas no SQL Server ($filetotable). Este parametro me fala pra pegar cada arquivo e gerar uma tabela. Mas e se eu quisesse todos em uma só tabela ?

    Eu precisava centralizar em uma tabela somente e como eu disse poderiam ser vários arquivos e com eventos e colunas diferentes entre eles.

    Isto começou a se tornar um problema quando eu vi o tamanho do código e das condições que estava ficando minha função. Na verdade eu estava pensando procedural, como eu montava minhas funções em Visual basic.

    Eu tinha esquecido umas das principais caraterísticas do powershell : Consistência.

    Para que eu ia fazer este esfardefuncio pandemonium de código, se a saída de um cmdlet é um objeto (TUDO NO POWERSHELL é objeto) e este pode ser a entrada de outro cmdlet ?

    Vamos ao código e alguns exemplos :

    Primeiramente os parâmetros : A função trabalha com 4 sendo que somente o primeiro é mandatório.

        $TraceFileName = Mandatório Path completo do Arquivo de trace "C:\Temp\Profiler.trc" ou "C:\temp\*.trc"

    Este parâmetro informa qual arquivo será lido. Se for um coloque o nome, se for vários *.trc (podem ser varios arquivos de traces com eventos e colunas diferentes)

    Ex C:\TEMP\TSQL.TRC or C:\TEMP\TEMP\ *.TRC

        $FileToTable = Opicional  Boolean Flag que avisa se o(s) traces(s) vão para tabela(s).

    Cada arquivo de trace será criado com o nome de “POWERSHELLTRACETABLE_" seguido do nome do dito cujo. Veremos abaixo que podemos especificar o servidor e database. Se não for irformado pegará o default (servidor default e database tempdb)

        $ServerName = OPTIONAL Server Name String - If not especified and $FileToTable = true default server will be used

        $DatabaseName = OPTIONAL Database Name String - If not especified and $FileToTable = true TEMPDB will be used

     

    Get-SQLProfiler Script Code  

      1: Function Get-SQLProfiler () 
    
      2: <#
    
      3: ----------------------------------------------------------
    
      4: Load SQL SERVER Profiler Traces Files. (.trc)
    
      5: ----------------------------------------------------------
    
      6: Version 1.0
    
      7: Laerte Poltronieri Junior
    
      8: www.laertejuniordba.spaces.live.com
    
      9: 
    
     10: $TraceFileName   = MANDATORY String Full SQL SERVER Trace File Path  "C:\Temp\Profiler.trc" or "C:\temp\*.trc"   
    
     11: $FileToTable = OPTIONAL Boolean Flag to insert all data into SQL tables, divided by .trc file
    
     12: $ServerName = OPTIONAL Server Name String - If not especified and  $FileToTable = true default server will be used
    
     13: $DatabaseNe = OPTIONAL Database Name String - If not especified and  $FileToTable = true TEMPDB will be used
    
     14: 
    
     15: #>
    
     16: 
    
     17: 
    
     18: {
    
     19: 
    
     20:  [CmdletBinding()]
    
     21:  
    
     22:  PARAM(
    
     23:    [Parameter(Position=1,Mandatory=$true, ValueFromPipelineByPropertyName=$true,HelpMessage="SQL Server Profiler Trace File")]
    
     24:    [Alias("FullName")]
    
     25:    [ValidateScript({$_ -match ".TRC"})]
    
     26:    [String] $TraceFileName,
    
     27:    
    
     28:    [Parameter(Position=2,Mandatory=$false, ValueFromPipelineByPropertyName=$true,HelpMessage="Flag to insert into SQL Table. Default False")]
    
     29:    [Alias("InsertFile")]
    
     30:    [switch] $FileToTable = $false,
    
     31: 
    
     32: 
    
     33:    [Parameter(Position=4,Mandatory=$false, ValueFromPipelineByPropertyName=$true,HelpMessage="Server Name Default Localhost")]
    
     34:    [Alias("SvrName")]
    
     35:    [String] $ServerName = $env:COMPUTERNAME,
    
     36: 
    
     37:    [Parameter(Position=5,Mandatory=$false, ValueFromPipelineByPropertyName=$true,HelpMessage="Database Name Default TEMPDB")]
    
     38:    [Alias("DbName")]
    
     39:    [String] $DatabaseName = "TEMPDB"
    
     40: 
    
     41:    
    
     42:   ) 
    
     43:   
    
     44:  
    
     45:  begin
    
     46:     {
    
     47:  
    
     48:    
    
     49:   $verbosePreference="continue" 
    
     50:   if ($fileToTable -AND $servername -eq $env:COMPUTERNAME -and $DatabaseName -eq  "TEMPDB" ) { 
    
     51:    $msg = "Server and Database parameters are not informed default values will be used : Server " + $env:COMPUTERNAME + " Database : TEMPDB"
    
     52:    write-warning $msg
    
     53:   }  
    
     54: 
    
     55:   
    
     56:   [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfoExtended") | out-null     
    
     57:   [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | out-null     
    
     58:   [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null 
    
     59:  }
    
     60:  process 
    
     61:  {
    
     62: 
    
     63:   try 
    
     64:   {
    
     65:    
    
     66:    # Verify if was passed multples .trc
    
     67:    $MultipleFiles = ($TraceFileName.substring($TraceFileName.length  - 5, 5) -eq "*.trc")
    
     68:    
    
     69:    #Setup Final Result and line number
    
     70:    $LineNumber = 1
    
     71:    $FinalResult = @()
    
     72:    
    
     73:      
    
     74:    # Get All .trc files (one or various)
    
     75:    foreach ($TraceFilePath in Get-ChildItem $TraceFileName -ErrorAction Stop ) {
    
     76:    
    
     77:     try 
    
     78:     {
    
     79:    
    
     80:   
    
     81:      #get trace name to create table
    
     82:      $TraceFileNameTRC = ($TraceFilePath.PSChildName).trim()
    
     83:      $TraceFileNameTRC = $TraceFileNameTRC.Trim()
    
     84: 
    
     85:      [String] $TraceFilePathString = $TraceFilePath
    
     86: 
    
     87:      $TableName = "PowershellTraceTable_" + $TraceFileNameTRC.substring(0,$TraceFileNameTRC.length -4)
    
     88:      
    
     89:      $TraceFileReader = New-Object Microsoft.SqlServer.Management.Trace.TraceFile
    
     90:      $TraceFileReader.InitializeAsReader($TraceFilePathString) 
    
     91:      
    
     92:      if ($TraceFileReader.Read()-eq $true) 
    
     93:      {
    
     94:      
    
     95:       while ($TraceFileReader.Read())
    
     96:       {
    
     97:        
    
     98:       
    
     99:        $ObjectTrace = New-Object PSObject
    
    100:        
    
    101:       
    
    102:        $ObjectTrace | add-member Noteproperty LineNumber   $LineNumber   
    
    103:        $ObjectTrace | add-member Noteproperty TraceFile   $TraceFileNameTRC  
    
    104: 
    
    105:        
    
    106:        $TotalFields = ($TraceFileReader.FieldCount) -1
    
    107: 
    
    108:        for($Count = 0;$Count -le $TotalFields;$Count++)
    
    109:        {
    
    110:         $FieldName = $TraceFileReader.GetName($Count)
    
    111:         $FieldValue = $TraceFileReader.GetValue($TraceFileReader.GetOrdinal($FieldName))
    
    112:         if ($FieldValue -eq $Null){ $FieldValue = ""}
    
    113:          
    
    114:         $ObjectTrace | add-member Noteproperty  $FieldName  $FieldValue
    
    115:        }
    
    116:        
    
    117:        $FinalResult += $ObjectTrace
    
    118:        $LineNumber ++ 
    
    119:       
    
    120:       }
    
    121:       if ($FileToTable)
    
    122:       {
    
    123:       
    
    124:        try {
    
    125:         $SQLConnection = New-Object Microsoft.SqlServer.Management.Common.SqlConnectionInfo
    
    126:         $SQLConnection.ServerName = $ServerName
    
    127:         $SQLConnection.DatabaseName = $DatabaseName
    
    128:         
    
    129:         
    
    130:         $TraceFileWriter = New-Object Microsoft.SqlServer.Management.Trace.TraceTable
    
    131:         
    
    132:                
    
    133:         $TraceFileReader.InitializeAsReader($TraceFilePathString)
    
    134:         $TraceFileWriter.InitializeAsWriter($TraceFileReader,$SQLConnection,$TableName) 
    
    135:        
    
    136:         while ( $TraceFileWriter.Write()) {}
    
    137:        } 
    
    138:        Catch {
    
    139:          $msg = $error[0]
    
    140:          write-warning $msg
    
    141:        }  
    
    142:        Finally {
    
    143:         $TraceFileWriter.close()
    
    144:        } 
    
    145:        
    
    146: 
    
    147:       }
    
    148: 
    
    149:      } 
    
    150:      
    
    151:      
    
    152:     } Catch {
    
    153:         $msg = $error[0]
    
    154:         write-warning $msg  
    
    155:       } Finally {
    
    156:         $TraceFileReader.close() 
    
    157:     }
    
    158:   
    
    159:    } 
    
    160: 
    
    161:    Write-Output $FinalResult   
    
    162:    
    
    163:    
    
    164:   } Catch {
    
    165:      $msg = $error[0]
    
    166:      write-warning $msg  
    
    167:   } Finally {
    
    168:       $TraceFileReader.Dispose 
    
    169:       $TraceFileWriter.Dispose
    
    170:       $SQLConnection.Dispose
    
    171:   }
    
    172:  }  
    
    173:  
    
    174: }
    
    175: 
    
    176: 

    Download script : i6

    Vamos fazer alguns testes :

    Eu criei um powershell módulo de função (.psm1) contendo somente este arquivo, para nossos testes correrem bem.

    No seu Powershell Profiler digite ?

    Import-Module -Name C:\temp\Get-SQLProfiler.psm1 -WarningAction SilentlyContinue  -ErrorAction Stop 

     

       Lendo um arquivo de trace a não inserindo numa tabela do SQL .

    Eu tenho este arquivo de trace C:\Temp\ProfilerTraces\TSQL.trc

    2copy_thumb1

    O arquivo tem as colunas e eventos do SQL Server Profiler template TSQL.

    Execute :

    Get-SQLProfiler "C:\TEMP\ProfilerFiles\TSQL.TRC"

     

    E o resultado será :

    3_thumb2

    As propriedades  LineNumber e TraceFile sempre estarão em qualquer resultado desta função.

    LineNumber é um incremento e TraceFile é o nome do arquivo de trace.

    Lembre-se que todo resultado será com base nas colunas do tracem independente dos arquivos terem colunas diferentes.

    Vamos ver o mesmo resultado só que selecionando as propriedades LineNumber, TraceFile ,EventClass and TextData, filtrando pelo Linenumber menor que 5.

    Get-SQLProfiler "C:\TEMP\ProfilerFiles\TSQL.TRC"  | where-object {$_.LineNumber -le 5} | select LineNumber, TraceFile ,EventClass ,TextData | format-table

     

    4_thumb 

       Lendo um arquivo de trace e inserindo na tabela.

    Vamos usar o exemplo enterior só que  $FiletoTable agora é $true, isso quer dizer que teremos uma tabela no SQL.

    Se não for informado  server e database, uma mensagem de warning será exibida dizendo que os valores default serão usados.

    6copy_thumb

      1: Get-SQLProfiler "C:\TEMP\ProfilerFiles\TSQL.TRC" $true | where-object {$_.LineNumber -le 5} | select LineNumber, TraceFile ,EventClass ,TextData | format-table

    E a tabela no SQL SERVER

    7_thumb2

       Lendo Múltiplos Trace Files e Inserindo numa tabela SQL .

    Digamos que temos varios árquivos SQL Server Profiler trace com rollover. Se quisermos juntá-los simplesmente passe o path dos traces .

      1: Get-SQLProfiler "C:\TEMP\ProfilerFiles\Rollover\*.TRC" $true |  select LineNumber, TraceFile ,EventClass ,TextData | format-table

    A figura abaixo mostra quando o arquivo muda  :

    8_thumb

    Serão criadas uma tabela para cada arquivo. Se você quiser todos os arquivos em uma tabela somente, simplesmente salve esta saida num XML e importe depois (mais 2 linhas). Veremos abaixo como fazer isso .

       Lendo Múltiplos Trace Files com Diferente Eventos e Colunas

    Podemos também juntar arquivos de trace com diferente colunas e eventos. No exemplo abaixo eu juntei um trace  TSQL_SP com TSQL_Locks.

    9_thumb

    Bom Laerte mas se eu juntar vários arquivos com colunas diferentes como eu vou saber as propriedades que estão nele.

    Simples, se você não quiser usar o get-member, ponha um  filtro com linenumber = 1

    LINENUMBER e TRACEFILE sempre serão retorno na  Get-SQLProfiler.

      1: Get-SQLProfiler "C:\TEMP\ProfilerFiles\Merge\*.TRC" | where-object {$_.LineNumber -le 1} | format-table

    10_thumb

    Now just get the list, choose the fields and put in | select.

    Lembre-se que com a opção $FiletoTable true, serão criadas tabelas para cada arquivo de trace.

    “Ha Laerte, mas eu quero centralizar todos meus traces em uma tabela somente”. Eu confesso que primeiramente eu queria fazer isso por parâmetro, mas para que se posso com mais duas linhas fazer isso. Powershell resolve isso  para mim e eu não preciso “Engessar” minha função.

    Primeirament eu crio uma tabela com coluna XML

    USE [tempdb]
    GO

    /****** Object:  Table [dbo].[PowershellProfileTable_XML]    Script Date: 11/18/2009 02:27:39 ******/
    If  EXISTS (Select * FROM sys.objects WHERE Object_id = Object_ID(N'[dbo].[PowershellProfileTable_XML]') And type In (N'U'))
    DROP TABLE [dbo].[PowershellProfileTable_XML]
    GO

    USE [tempdb]
    GO

    /****** Object:  Table [dbo].[PowershellProfileTable_XML]    Script Date: 11/18/2009 02:27:42 ******/
    Set ANSI_NULLS On
    GO

    Set QUOTED_IDENTIFIER On
    GO

    CREATE TABLE [dbo].[PowershellProfileTable_XML](
    [XML] [xml] NULL
    ) On [PRIMARY]

    GO

     

    Agora o powershell vai trabalhar. Somente salvamos em XML…e podemos escolher quais propriedades (colunas).

    (Get-SQLProfiler "C:\TEMP\*.TRC" | Select LIneNumber,EventClass,TextData,NTUserName,LoginName | ConvertTo-Xml -NoTypeInformation).save("c:\temp\teste.xml")
    $XML= "insert into PowershellProfileTable_XML values ('" + ((Get-Content "C:\Temp\teste.xml") -replace "'", "''")  + "')" 
    invoke-sqlcmd -ServerInstance $env:COMPUTERNAME -database "master" -query $xml

     

    E com umas simples Xquery tiramos os dados do campo XML :

    Select t2.Col1.value('(Property[@Name="LineNumber"]/text())[1]', 'int') LineNumber,
        t2.Col1.value('(Property[@Name="EventClass"]/text())[1]', 'nvarchar(255)') EventClass,
        t2.Col1.value('(Property[@Name="TextData"]/text())[1]', 'nvarchar(max)') TextData,
        t2.Col1.value('(Property[@Name="NTUserName"]/text())[1]', 'nvarchar(255)') NtUserName,
        t2.Col1.value('(Property[@Name="LoginName"]/text())[1]', 'nvarchar(255)') LoginName
    FROM dbo.testeXML
    CROSS APPLY xml.nodes('/Objects/Object') As t2(Col1)
    where t2.Col1.value('(Property[@Name="LoginName"]/text())[1]', 'nvarchar(255)') Like '%laerte%'

     

     

    11_thumb2

    Eu não preciso criar mais um parâmetro para fazer esta operação. A característica de CONSISTÊNCIA do powershell faz isso pra mim.

    Eu simplesmente coloco o pipe (|) e posso gravar em XML, filtrar por qualquer propriedade , importar pra tabela SQL, exportar pra TXT..e porque não SUSHI..hehehe.

    Muito obrigado ao meu amigo Shay Levy que sempre tem tempo para me passar seus grandes conhecimentos. Jeffrey Hicks também, com várias dicas de como usar mandatory parameters,meu amigo e companheiro de  SQL SERVER DAY Felipe Ferreira no XQuery e  óbvio o mestre do POWERSHELL com SQL SERVER Chad Miller.

    Bom são 2 da manhã e eu estou ouvindo um som fantástico ( dica de Thomas - @doctordns)

    POWERSHELL ROCKS !!!!!

    “Hey, comin' out around the world be ready for a brand new beat
    Oh, summer's here and the time is right, oh, for dancing in thestreet
    Dancing in Chicago (dancing in the street)
    Down in New Orleans (dancing in the street)
    In New York City (dancing in the street)

    All we need is music, sweet music (sweet, sweet music)
    They'll be music everywhere (everywhere)
    They'll be laughing, singing, music swinging and dancing in thestreet

    It doesn't matter what you wear just as long as you are there
    They're dancing (dancing in the street) oh oh

    This is an invitation across the nation the chance for folks tomeet
    There'll be swinging, swaying, music playing and dancing in thestreet

    Philadelphia, PA now (dancing in the street)
    Baltimore and D.C. (dancing in the street)
    Can't forget them other cities (dancing in the street)”

    Dancing In The Street

    Grateful Dead

    • New blog post: http://tinyurl.com/yhbzuzd - Read, Filter,Save SQL Table, XML.. Sushi.Finally FUN SQL Server Profiler Traces in #POWERSHELL
    Follow me on Twitter


    Read, Filter,Save to SQL Table or XML…Sushi..Anyway FUN with SQL Server Profiler Trace Files in POWERSHELL

     

    Excuse me for English, is by google.

    Requires Powershell V2.0

    It was an annoying proceeding to be done. I had my trace files separated by folder, but as I check Enable File Rollover and it was raised many divisions of the same trace.

    There were three shifts of DBAs. Each placed the need to trace your problem. Sometimes I also look to bring together various files needed to trace the events and different columns in the same. It was really hard to do this

    Some of our servers were very busy and put the trace file for SQL Server table was negated by the overhead generated, so I've had to import to SQL Server later. A simple procedure for fn_trace_gettable to one file, but when you have multiple files becomes complicated to generate a uniform and repetitive script. And worse if I had to join the trace files in a single file ..

    It was then that I decided to use powershell.

    One of the parameters when I began to think of the solution was to be generated tables to the SQL Server  ($filetotable) There was no problem in setting this parameter .

    But I wanted to centralize all the files in a table and as I said, these files could come with different events and columns.

    This became a problem when I began to see as many lines of code and conditions that would have this function. Actually I was thinking procedural, as I did my functions in Visual Basic.

    I forgot one of the main features of Powershell: Consistency.

    Why would I do all this code, if the output of a cmdlet is an object and can be the input of the next cmdlet?

    So..lets go the code and examples :

    First the parameters. The functions works with 4 parameters being one (the first) mandatory.

        $TraceFileName = MANDATORY String Full SQL SERVER Trace File Path "C:\Temp\Profiler.trc" or "C:\temp\*.trc"

    This parameter tells the trace file to be read. If you want more than one file, which as I said may be with different events and columns between them, specify that all *. trc files with the TRC will be read in path. If not only one file.

    Ex C:\TEMP\TSQL.TRC or C:\TEMP\TEMP\ *.TRC

        $FileToTable = OPTIONAL Boolean Flag to insert all data into SQL tables, divided by .trc file

    This parameter specifies if the files read will be sent to tables in SQL Server. Be set up different tables for each file, with the name "POWERSHELLTRACETABLE_" followed by the name of the trace. We will see below that this parameter is set to true, we need to pass the name of the Server and Database for these files. If not informed the default values will be used

        $ServerName = OPTIONAL Server Name String - If not especified and $FileToTable = true default server will be used

        $DatabaseName = OPTIONAL Database Name String - If not especified and $FileToTable = true TEMPDB will be used

     

    Get-SQLProfiler Script Code

      1: Function Get-SQLProfiler () 
    
      2: <#
    
      3: ----------------------------------------------------------
    
      4: Load SQL SERVER Profiler Traces Files. (.trc)
    
      5: ----------------------------------------------------------
    
      6: Version 1.0
    
      7: Laerte Poltronieri Junior
    
      8: www.laertejuniordba.spaces.live.com
    
      9: 
    
     10: $TraceFileName   = MANDATORY String Full SQL SERVER Trace File Path  "C:\Temp\Profiler.trc" or "C:\temp\*.trc"   
    
     11: $FileToTable = OPTIONAL Boolean Flag to insert all data into SQL tables, divided by .trc file
    
     12: $ServerName = OPTIONAL Server Name String - If not especified and  $FileToTable = true default server will be used
    
     13: $DatabaseNe = OPTIONAL Database Name String - If not especified and  $FileToTable = true TEMPDB will be used
    
     14: 
    
     15: #>
    
     16: 
    
     17: 
    
     18: {
    
     19: 
    
     20:  [CmdletBinding()]
    
     21:  
    
     22:  PARAM(
    
     23:    [Parameter(Position=1,Mandatory=$true, ValueFromPipelineByPropertyName=$true,HelpMessage="SQL Server Profiler Trace File")]
    
     24:    [Alias("FullName")]
    
     25:    [ValidateScript({$_ -match ".TRC"})]
    
     26:    [String] $TraceFileName,
    
     27:    
    
     28:    [Parameter(Position=2,Mandatory=$false, ValueFromPipelineByPropertyName=$true,HelpMessage="Flag to insert into SQL Table. Default False")]
    
     29:    [Alias("InsertFile")]
    
     30:    [switch] $FileToTable = $false,
    
     31: 
    
     32: 
    
     33:    [Parameter(Position=4,Mandatory=$false, ValueFromPipelineByPropertyName=$true,HelpMessage="Server Name Default Localhost")]
    
     34:    [Alias("SvrName")]
    
     35:    [String] $ServerName = $env:COMPUTERNAME,
    
     36: 
    
     37:    [Parameter(Position=5,Mandatory=$false, ValueFromPipelineByPropertyName=$true,HelpMessage="Database Name Default TEMPDB")]
    
     38:    [Alias("DbName")]
    
     39:    [String] $DatabaseName = "TEMPDB"
    
     40: 
    
     41:    
    
     42:   ) 
    
     43:   
    
     44:  
    
     45:  begin
    
     46:     {
    
     47:  
    
     48:    
    
     49:   $verbosePreference="continue" 
    
     50:   if ($fileToTable -AND $servername -eq $env:COMPUTERNAME -and $DatabaseName -eq  "TEMPDB" ) { 
    
     51:    $msg = "Server and Database parameters are not informed default values will be used : Server " + $env:COMPUTERNAME + " Database : TEMPDB"
    
     52:    write-warning $msg
    
     53:   }  
    
     54: 
    
     55:   
    
     56:   [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfoExtended") | out-null     
    
     57:   [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | out-null     
    
     58:   [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null 
    
     59:  }
    
     60:  process 
    
     61:  {
    
     62: 
    
     63:   try 
    
     64:   {
    
     65:    
    
     66:    # Verify if was passed multples .trc
    
     67:    $MultipleFiles = ($TraceFileName.substring($TraceFileName.length  - 5, 5) -eq "*.trc")
    
     68:    
    
     69:    #Setup Final Result and line number
    
     70:    $LineNumber = 1
    
     71:    $FinalResult = @()
    
     72:    
    
     73:      
    
     74:    # Get All .trc files (one or various)
    
     75:    foreach ($TraceFilePath in Get-ChildItem $TraceFileName -ErrorAction Stop ) {
    
     76:    
    
     77:     try 
    
     78:     {
    
     79:    
    
     80:   
    
     81:      #get trace name to create table
    
     82:      $TraceFileNameTRC = ($TraceFilePath.PSChildName).trim()
    
     83:      $TraceFileNameTRC = $TraceFileNameTRC.Trim()
    
     84: 
    
     85:      [String] $TraceFilePathString = $TraceFilePath
    
     86: 
    
     87:      $TableName = "PowershellTraceTable_" + $TraceFileNameTRC.substring(0,$TraceFileNameTRC.length -4)
    
     88:      
    
     89:      $TraceFileReader = New-Object Microsoft.SqlServer.Management.Trace.TraceFile
    
     90:      $TraceFileReader.InitializeAsReader($TraceFilePathString) 
    
     91:      
    
     92:      if ($TraceFileReader.Read()-eq $true) 
    
     93:      {
    
     94:      
    
     95:       while ($TraceFileReader.Read())
    
     96:       {
    
     97:        
    
     98:       
    
     99:        $ObjectTrace = New-Object PSObject
    
    100:        
    
    101:       
    
    102:        $ObjectTrace | add-member Noteproperty LineNumber   $LineNumber   
    
    103:        $ObjectTrace | add-member Noteproperty TraceFile   $TraceFileNameTRC  
    
    104: 
    
    105:        
    
    106:        $TotalFields = ($TraceFileReader.FieldCount) -1
    
    107: 
    
    108:        for($Count = 0;$Count -le $TotalFields;$Count++)
    
    109:        {
    
    110:         $FieldName = $TraceFileReader.GetName($Count)
    
    111:         $FieldValue = $TraceFileReader.GetValue($TraceFileReader.GetOrdinal($FieldName))
    
    112:         if ($FieldValue -eq $Null){ $FieldValue = ""}
    
    113:          
    
    114:         $ObjectTrace | add-member Noteproperty  $FieldName  $FieldValue
    
    115:        }
    
    116:        
    
    117:        $FinalResult += $ObjectTrace
    
    118:        $LineNumber ++ 
    
    119:       
    
    120:       }
    
    121:       if ($FileToTable)
    
    122:       {
    
    123:       
    
    124:        try {
    
    125:         $SQLConnection = New-Object Microsoft.SqlServer.Management.Common.SqlConnectionInfo
    
    126:         $SQLConnection.ServerName = $ServerName
    
    127:         $SQLConnection.DatabaseName = $DatabaseName
    
    128:         
    
    129:         
    
    130:         $TraceFileWriter = New-Object Microsoft.SqlServer.Management.Trace.TraceTable
    
    131:         
    
    132:                
    
    133:         $TraceFileReader.InitializeAsReader($TraceFilePathString)
    
    134:         $TraceFileWriter.InitializeAsWriter($TraceFileReader,$SQLConnection,$TableName) 
    
    135:        
    
    136:         while ( $TraceFileWriter.Write()) {}
    
    137:        } 
    
    138:        Catch {
    
    139:          $msg = $error[0]
    
    140:          write-warning $msg
    
    141:        }  
    
    142:        Finally {
    
    143:         $TraceFileWriter.close()
    
    144:        } 
    
    145:        
    
    146: 
    
    147:       }
    
    148: 
    
    149:      } 
    
    150:      
    
    151:      
    
    152:     } Catch {
    
    153:         $msg = $error[0]
    
    154:         write-warning $msg  
    
    155:       } Finally {
    
    156:         $TraceFileReader.close() 
    
    157:     }
    
    158:   
    
    159:    } 
    
    160: 
    
    161:    Write-Output $FinalResult   
    
    162:    
    
    163:    
    
    164:   } Catch {
    
    165:      $msg = $error[0]
    
    166:      write-warning $msg  
    
    167:   } Finally {
    
    168:       $TraceFileReader.Dispose 
    
    169:       $TraceFileWriter.Dispose
    
    170:       $SQLConnection.Dispose
    
    171:   }
    
    172:  }  
    
    173:  
    
    174: }
    
    175: 
    
    176: 

     

    Download script : i

     

    Let´s do some tests :

    I created a function module with only this function and import it in my powershell profile. Only for our test be better !!!!

    At powershell profiler type :

    Import-Module -Name C:\temp\Get-SQLProfiler.psm1 -WarningAction SilentlyContinue  -ErrorAction Stop 

     

     

       Reading One Trace File and not Insert into SQL table.

    We have this SQL Server Profiler trace C:\Temp\ProfilerTraces\TSQL.trc

    2 copy

    This File contains the events and columns of the SQL Server Profiler template TSQL.

    Execute :

    Get-SQLProfiler "C:\TEMP\ProfilerFiles\TSQL.TRC"

    and the result :

    3

    The properties LineNumber and TraceFile will be in any resulting object of this function.

    LineNumber is the line number (increment) and TraceFile is the name of the trace.

    Remember, these properties match the columns in the trace file. Even if I'm merging files with different columns and events.

    Let´s see only the properties LineNumber, TraceFile ,EventClass and TextData, filtering the lines smaller than or equal to 5

    Get-SQLProfiler "C:\TEMP\ProfilerFiles\TSQL.TRC"  | where-object {$_.LineNumber -le 5} | select LineNumber, TraceFile ,EventClass ,TextData | format-table

     

    4

       Reading One Trace File and Insert into SQL table.

    With the previous example we have the same result with $FiletoTable parameter $true, but means now we have a SQL Server Table.

    As not informed as the server and database, a warning message was displayed that would be used default values :

    6 copy

      1: Get-SQLProfiler "C:\TEMP\ProfilerFiles\TSQL.TRC" $true | where-object {$_.LineNumber -le 5} | select LineNumber, TraceFile ,EventClass ,TextData | format-table

    And the SQL Server table  :

    7

       Reading Multiple Trace Files and Insert into SQL table.

    Let´s say we have a SQL Server Profiler trace file rollover. If you want to merge result simply enter the path that are the trace files.

      1: Get-SQLProfiler "C:\TEMP\ProfilerFiles\Rollover\*.TRC" $true |  select LineNumber, TraceFile ,EventClass ,TextData | format-table

    The figure below shows when the file changes :

    8

    Will be created one SQL table for each trace file. If you want all trace files are placed in one table, save the result of the cmdlet in XML (or txt) to import soon after the invoke-sqlcmd. Below I have one example.

       Reading Multiple Trace Files With Different Events and Columns

    We can also merge two files of traces with different columns. In the example I merge a file TSQL_SP with TSQL_Locks.

    9

    Well Laerte, but if I merge multiples files with different set up, how can I now the properties from Get-SQLProfiler ?

    Simple, put a filter to one row or linenumber = 1

    LINENUMBER and TRACEFILE Always be at Get-SQLProfiler.

      1: Get-SQLProfiler "C:\TEMP\ProfilerFiles\Merge\*.TRC" | where-object {$_.LineNumber -le 1} | format-table

    10

    Now just get the list, choose the fields and put in | select.

    Remember that for multiple files with the option  $FiletoTable true, it creates several tables, one for each file.
    Ha Laerte but I wanted to centralize everything in one. I confess that at first I wanted to do this, through parameter. But as I said, the powershell can  resolve this situation with two more lines of code and not have to "stifle" my function.

    First I Create a table with XML colum. For tests I Put at tempdb :

    USE [tempdb]
    GO

    /****** Object:  Table [dbo].[PowershellProfileTable_XML]    Script Date: 11/18/2009 02:27:39 ******/
    If  EXISTS (Select * FROM sys.objects WHERE Object_id = Object_ID(N'[dbo].[PowershellProfileTable_XML]') And type In (N'U'))
    DROP TABLE [dbo].[PowershellProfileTable_XML]
    GO

    USE [tempdb]
    GO

    /****** Object:  Table [dbo].[PowershellProfileTable_XML]    Script Date: 11/18/2009 02:27:42 ******/
    Set ANSI_NULLS On
    GO

    Set QUOTED_IDENTIFIER On
    GO

    CREATE TABLE [dbo].[PowershellProfileTable_XML](
    [XML] [xml] NULL
    ) On [PRIMARY]

    GO

     

    and let´s wait Powershell to work. We just save  to XML …and we can choose de properties too!!!

    (Get-SQLProfiler "C:\TEMP\*.TRC" | Select LIneNumber,EventClass,TextData,NTUserName,LoginName | ConvertTo-Xml -NoTypeInformation).save("c:\temp\teste.xml")
    $XML= "insert into PowershellProfileTable_XML values ('" + ((Get-Content "C:\Temp\teste.xml") -replace "'", "''")  + "')" 
    invoke-sqlcmd -ServerInstance $env:COMPUTERNAME -database "master" -query $xml

     

    And with a simple Xquery we list  all data into XML .Let’s See ?

    Select t2.Col1.value('(Property[@Name="LineNumber"]/text())[1]', 'int') LineNumber,
        t2.Col1.value('(Property[@Name="EventClass"]/text())[1]', 'nvarchar(255)') EventClass,
        t2.Col1.value('(Property[@Name="TextData"]/text())[1]', 'nvarchar(max)') TextData,
        t2.Col1.value('(Property[@Name="NTUserName"]/text())[1]', 'nvarchar(255)') NtUserName,
        t2.Col1.value('(Property[@Name="LoginName"]/text())[1]', 'nvarchar(255)') LoginName
    FROM dbo.testeXML
    CROSS APPLY xml.nodes('/Objects/Object') As t2(Col1)
    where t2.Col1.value('(Property[@Name="LoginName"]/text())[1]', 'nvarchar(255)') Like '%laerte%'

     

     

     

    11

    I do not need to put more parameters to add a table…etc. The consistency characteristic of powershell does it for me.

    I just need to pipe and save. We can Read, save to XML, filter by any property, import to SQL Table…and Sushi.

    Thanks to my friend Shay Levy as always has time to share his great knowledge. Jeffrey Hicks too, with a lot of tips to mandatory parameters in functions ,my SQL SERVER DAY fellow Felipe Ferreira in XQuery and obvius Chad Miller, the master in powershell with SQL Server

    opinions to optimize this code are welcome!

    Well  It's 2 o'clock in the morning and I hear a sound very good (tip from Thomas - doctordns) ...

    POWERSHELL ROCKS !!!!!

    “Hey, comin' out around the world be ready for a brand new beat
    Oh, summer's here and the time is right, oh, for dancing in thestreet
    Dancing in Chicago (dancing in the street)
    Down in New Orleans (dancing in the street)
    In New York City (dancing in the street)

    All we need is music, sweet music (sweet, sweet music)
    They'll be music everywhere (everywhere)
    They'll be laughing, singing, music swinging and dancing in thestreet

    It doesn't matter what you wear just as long as you are there
    They're dancing (dancing in the street) oh oh

    This is an invitation across the nation the chance for folks tomeet
    There'll be swinging, swaying, music playing and dancing in thestreet

    Philadelphia, PA now (dancing in the street)
    Baltimore and D.C. (dancing in the street)
    Can't forget them other cities (dancing in the street)”

    Dancing In The Street

    Grateful Dead

    • New blog post: http://tinyurl.com/yhbzuzd - Read, Filter,Save SQL Table, XML.. Sushi.Finally FUN SQL Server Profiler Traces in #POWERSHELL
    Follow me on Twitter


    November 14

    Check/Fix Usuários Órfãos após Restore com Powershell

    Pessoal,

    No artigo que sairá no simple-talk, fiz uma pequena alteração para contemplar usuários órfãos depois de um restore e o que coloquei aqui não tem, então segue o código.

    Meu cenário na época era o seguinte.

    Eu tinha aquele problema que alguns usuários das empresas que cuidávamos podiam alterar/Dropar, por contrato, os logins. Nunca entrei no mérito de saber porque,não era da mina conta isso. Eu tinha que fazer a coisa funcionar até se o Papa fosse o usuário principal.

    Meu problema era que o pessoal ,muito bem capacitado não posso dizer o contrário, infelizmente não se preocupava com os usuários.

    E isso era constante. Tínhamos muitos servidores deste gigante cliente. Digamos que eu fazia esta checagem todo dia.

    Resolvi centralizando um script que coletava estes usuários órfãos em todos os servidores. Após isso o User ou era dropado ou criávamos o login.

    Mas também tínhamos o caso do restore. Todo domingo restaurávamos por JOBs, bases de produção pra desenvolvimento.

    Mas acontecia que o Servidor de Produção X tinha N bases a serem restauradas pro servidor de desenvolvimento Y, O servidor H mais N bases pra desenvolvimento.

    Definimos que os usuários que não possuíam login seriam dropados após o restore e os outros mapeados.

    Uma padronização que tínhamos : Os logins criados possuíam o mesmo nome de usuários. Pelo menos !!!!

    Vamos lá. Primeira coisa é criar um TXT chamado ServersRestored.txt (ou qq outro nome..podemos passar o nome do script) que terá o nome dos servidores que terão o restore e logo a frente os bancos separados por vírgula.

    Usaremos o Powershell 2.0, pois trabalharemos agora não mais com arquivo de funções e sim com Windows Powershell Script Module , Advanced Functions e Tratamento de Erros baseados em Try Catch.

    Um Windows Powershell Script Module é um módulo de funções (Extensão .PSM1) que contém Advanced Functions e pode ser facilmente adicionado ao seu Arquivo de Profiler. As Advanced Functions são funções que possuem comandos e características avançadas, podendo assim ser colocadas num .ps1, no seu Arquivo de Profiler, ou digitadas em linha de comando mesmo.

    Quer saber mais ?

    Huddled Masses

    You can do more than breathe for free…


      A guide to Advanced Functions

     

    Voltando a nosso script, o txt será assim:

    5

    Colocamos na nossa pasta de scripts C:\PS\Servers o Script FixLoginsByrestore.ps1

      1: 
    
      2: <#	
    
      3: 
    
      4: 	$FileListName = Name of FileList that contains servers and db will be restored
    
      5: 	Server1,db2,db3
    
      6: 	Server2,db1,db2
    
      7: 	Server3\Instace1,db2,db3,db4,db5,db6
    
      8: 	
    
      9: 	$DropUserNotLogin = Flag to Drop a user withou login. default = true
    
     10: 	
    
     11: 	$PathServerList = Path that have a $FileListName
    
     12: 	
    
     13: 	$PathLogFile  = Path to log error file
    
     14: 	$PathFunctionFile = Path constains Function File
    
     15: 
    
     16: #>
    
     17: 
    
     18: 
    
     19: param 	(	[String]$FileListName,
    
     20: 			[bool]$DropUserNotLogin = $true,
    
     21: 			[string]$PathServerList = "C:\PS\servers",
    
     22: 			[string]$PathLogFile = "C:\PS\logs",
    
     23: 			[string]$PathFunctionFile = "C:\PS\PSScripts"
    
     24: 			
    
     25: 		)
    
     26: 
    
     27: 
    
     28: [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null 
    
     29: 
    
     30: 
    
     31: 
    
     32: $Error.Clear()
    
     33: 
    
     34: if ($FileListName -eq $null -or $FileListName -eq "") 
    
     35: {
    
     36: 	Write-Host "Missing Parameter Information !!!"
    
     37: 	break;
    
     38: }
    
     39: 
    
     40: [string] $VFileListName = ""
    
     41: [string] $VFunctionFile  =""
    
     42: 
    
     43: 
    
     44: $VFileListName = $PathServerList + "\" + $FileListName
    
     45: if (!(Test-Path -path $VFileListName))
    
     46: {
    
     47: 	Write-Host "Path File Server not found !!!"
    
     48: 	break;
    
     49: }	
    
     50: 
    
     51: $VFunctionFile = $PathFunctionFile + "\Functions.psm1"
    
     52: #try load functions file, if does not exists break code with message
    
     53: try {
    
     54: 	Import-Module -Name $VFunctionFile -WarningAction SilentlyContinue  -ErrorAction Stop 
    
     55: } 
    
     56: catch {
    
     57: 		Write-Host "Functions File not found !!!"
    
     58: 		break;
    
     59: }
    
     60: 
    
     61: 	
    
     62: 	
    
     63: 
    
     64: $TodayDate = get-date -format "yyyy-MM-dd hh:mm:ss" 
    
     65: $TodayDateLog = get-date -format "yyyyMMddhhmmss" 
    
     66: 
    
     67: 
    
     68: $PathLogFile = $PathLogFile + "\Log"
    
     69: 
    
     70: 
    
     71: foreach ($svr in get-content $VFileListName -ErrorAction Stop )
    
     72: {
    
     73: 	try {
    
     74: 			$ServerDBList = $svr.split(",")
    
     75: 			[Object] $SvrObject = $ServerDBList[0]
    
     76: 
    
     77: 			$TotalDB = ($ServerDBList.count) -1
    
     78: 			$Count = 1
    
     79: 			
    
     80: 			$Server= New-Object "Microsoft.SqlServer.Management.Smo.Server" "$SvrObject" -ErrorAction  stop
    
     81: 			for(;$Count -le $TotalDB;$Count++)
    
     82: 			{
    
     83: 			
    
     84: 				$Db = $Server.databases[$ServerDBList[$Count]] 
    
     85: 				$DbName = $Db.name
    
     86: 				$db.users  | Where-Object {!$_.IsSystemObject -and $_.Login -eq ""} | foreach {
    
     87: 					$ExistLogin =  Get-Login $Server $_.name
    
     88: 					if (!($ExistLogin) -and ($DropUserNotLogin))
    
     89: 					{
    
     90: 						try {
    
     91: 							$_.drop()
    
     92: 							$Msg = "User " + $User.name + " Dropped"
    
     93: 							Save-Log "OrphanedUSersRestore_MSG" "$SvrObject" "$DbName" "$msg" "$PathLogFile" "$TodayDateLog"
    
     94: 							
    
     95: 						}
    
     96: 						catch
    
     97: 						{
    
     98: 							$Err = $_.Exception.Message
    
     99: 							Save-Log "OrphanedUSersRestore_Err" "$SvrObject" "$DbName" "$Err" "$PathLogFile" "$TodayDateLog"
    
    100: 							$Error.Clear()
    
    101: 							continue;
    
    102: 						}
    
    103: 						
    
    104: 					}
    
    105: 					elseif (!$ExistLogin)
    
    106: 					{
    
    107: 						$Msg = "User Without Login : User " + $User.name
    
    108: 						Save-Log "OrphanedUSersRestore_MSG" "$SvrObject" "$DbName" "$msg" "$PathLogFile" "$TodayDateLog"
    
    109: 
    
    110: 					}
    
    111: 					elseif ($ExistLogin)
    
    112: 					{
    
    113: 						try {
    
    114: 							$LoginName = $_.name
    
    115: 							map-userlogin "$SvrObject" "$DbName" "$LoginName" 
    
    116:     						$Msg = "Success Map User " + $user
    
    117: 							Save-Log "OrphanedUsersRestore_Ok" "$Server" "$DbName" "$Msg" "$PathLogFile" "$TodayDate"
    
    118: 						}
    
    119: 						catch {
    
    120: 								$Err = $_.Exception.Message + " Can not map user " + $user
    
    121: 								Save-Log "OrphanedUSersRestore_ERR" "$SvrObject" "$DbName" "$Err" "$PathLogFile" "$TodayDateLog" 
    
    122: 								$Error.Clear()
    
    123: 								continue;
    
    124: 						}		
    
    125: 					
    
    126: 					}	
    
    127: 				}
    
    128: 			}
    
    129: 		}
    
    130: 		catch {
    
    131: 
    
    132: 				$Err = $_.Exception.Message
    
    133: 				Save-Log "OrphanedUSersRestore_ERR" "$SvrObject" "$DbName" "$Err" "$PathLogFile" "$TodayDateLog" 
    
    134: 				$Error.Clear()
    
    135: 				continue;
    
    136: 		}
    
    137: }		
    
    138: 
    
    139: 

    Como podemos ver no script, temos os parâmetros :

    [String]$FileListName,

            Nome do TXT a ser lido com a lista dos servidores e bancos que serão restaurados.

    [bool]$DropUserNotLogin = $true,

            Flag que informa se o user vai ser dropado se não tiver o Login

    [string]$PathServerList = "C:\PS\servers",

            Path que está a lista

    [string]$PathLogFile = "C:\PS\logs",

            Path que será gerado o LOG. Neste script TUDO é logado. Se mapeou, dropou o login ou mensagens de erro

    [string]$PathFunctionFile = "C:\PS\PSScripts"

            Path que está o modulo de funções (.PSM1)

    Vamos colocar o modulo de funções :

      
      1: 
    
      2: Function Save-Log () 
    
      3: <#
    
      4: ----------------------------------------------------------
    
      5: Save  log in file
    
      6: ----------------------------------------------------------
    
      7: 
    
      8: File Name     			= $NamePS1
    
      9: Server name   			= $Server 
    
     10: Message To Log		    = $Message
    
     11: Path to generate file 	= $PathFileLog 
    
     12: Date to Log				= $TodayDate
    
     13: #>
    
     14: 
    
     15: 
    
     16: {
    
     17: 
    
     18: 	[CmdletBinding()]
    
     19: 	
    
     20: 	Param (
    
     21: 		[Parameter(Mandatory = $true )][String] $NamePS1,
    
     22: 		[Parameter(Mandatory = $true )][String] $Server,
    
     23: 		[Parameter(Mandatory = $true )][String] $DatabaseName,
    
     24: 		[Parameter(Mandatory = $true )][String] $Message,
    
     25: 		[Parameter(Mandatory = $true )][String] $PathFileLog,
    
     26: 		[Parameter(Mandatory = $true )][String] $TodayDate
    
     27: 		)
    
     28: 	process 
    
     29: 	{
    
     30: 	
    
     31: 		#test if path wich will contains the error file exists. if not create 
    
     32: 	
    
     33: 	if (!(Test-Path -path $PathFileLog))
    
     34: 	{
    
     35: 		try {
    
     36: 			New-Item $PathFileLog -itemtype directory -ErrorAction  Stop
    
     37: 		}
    
     38: 		catch {
    
     39: 			Write-Host "Can not create log file path"
    
     40: 			break;
    
     41: 		}
    
     42: 	} 
    
     43: 	
    
     44: 	
    
     45: 	$NameFileFull = $PathFileLog + "\" + $NamePS1 + $TodayDate + ".log" 
    
     46: 	
    
     47: 	$TDate = $TodayDate.Substring(0,4) + "-" + $TodayDate.Substring(4,2) + "-" + $TodayDate.Substring(6,2) 
    
     48: 	
    
     49: 	"Server : " + $Server,"Database : " + $DatabaseName,"Date : " + $TDate ,"Message: " + $Message | Out-file  $NameFileFull -append 
    
     50: 	} 
    
     51: }
    
     52: 
    
     53: Function Get-Login ()	
    
     54: <#
    
     55: ----------------------------------------------------------
    
     56: Verify login exists
    
     57: ----------------------------------------------------------
    
     58: Server Object = $Server
    
     59: Login Name = $LoginName
    
     60: Returns True/False if login exists
    
     61: 
    
     62: #>
    
     63: {
    
     64: 
    
     65: 	[CmdletBinding()]
    
     66: 	
    
     67: 	PARAM ( 
    
     68: 	[Parameter(Mandatory=$true )][object] $Server,
    
     69: 	[Parameter(Mandatory=$true )][String] $LoginName
    
     70: 	)
    
     71: 	process
    
     72: 	{
    
     73: 	
    
     74: 		$Collect = $Server.logins | where-object {$_.isdisabled -eq $False -and $_.IsSystemObject -eq $False -and $_.IsLocked -eq $False -and $_.name -eq $LoginName }  
    
     75: 		return  !($Collect -eq $Null)
    
     76: 	}
    
     77: }
    
     78: 
    
     79: Function Map-UserLogin ()
    
     80: {
    
     81: <#
    
     82: ----------------------------------------------------------
    
     83: Map USer and Logins
    
     84: ----------------------------------------------------------
    
     85: Server Name			= $Server
    
     86: Database Name		= $Database
    
     87: USer Name			= $USer
    
     88: 
    
     89: #>
    
     90: 
    
     91: 	[CmdletBinding()]
    
     92: 	
    
     93: 	Param ( 
    
     94: 			[Parameter(Mandatory = $true )][string] $Server,
    
     95: 			[Parameter(Mandatory = $true )][String] $Database,
    
     96: 			[Parameter(Mandatory = $true )][String] $USer
    
     97: 			)
    
     98: 			
    
     99: 	process
    
    100: 	{
    
    101: 	
    
    102: 		$SqlConn = New-Object System.Data.SqlClient.SqlConnection
    
    103: 		$SqlCmd = New-Object System.Data.SqlClient.SqlCommand
    
    104: 		
    
    105: 		try{
    
    106: 			$SqlConn.ConnectionString = "Server=" + $Server+ ";Database=" + $Database + ";Integrated Security=True"
    
    107: 			$sqlconn.Open()
    
    108: 			$SqlCmd.Connection = $SqlConn
    
    109: 			$SqlCmd.CommandText = "ALTER USER " + $USer + " WITH LOGIN = " + $USer
    
    110: 			$SqlCmd.ExecuteNonQuery()
    
    111: 		}
    
    112: 		finally {
    
    113: 			$SqlConn.Close()
    
    114: 		}
    
    115: 	}
    
    116: 
    
    117: }

    Baixar Functions.psm1 (functions.rar)

     

    Com tudo pronto, deixávamos um Job para rodar as 6 da manhã de segunda (após todos os restores terem sido feitos) que fazia o trabalho pra gente.

     

    A chamada era simples. Num Job CMDEXEC colocávamos :

     

    Show de Bola !!!!

     

    Com a passagem do arquivo txt que quisermos pro script, damos a flexibilidade de alterar para um servidor somente ou o numero de servidores e databases que você quiser.

    Este script serve para 1 ou 1000 servidores..

     

    Um dos inúmeros recursos que temos no powershell é produtividade.

    Mas você deve estar pensando : Mas estes scripts estão um pouco maior dos que você colocava.

    Sim estão . Quando temos muitos servidores (ou até um…como eu disse no artigo o que diferenciará você dos outros é sua maneira de pensar : Grande ou Pequena) tudo tem que ser repetitivo, uniforme, consistente automatizado e PRINCIPALMENTE com tratamento de erros.

    Reparem que a maioria do código é tratamento de erros.

     

    Tente fazer este mesmo script, com os recursos que tem nele (dropar ou mapear usuário, gerar arquivo de log para cada ação executada, verificar se o login existe pro usuário..etc) em TSQL e me diga, caso consiga fazer , o número de linhas que terá. Além do que você teria que gerar este script TSQL em cada servidor e assim, não centralizando o processo.

     

    Como o som que finalizo este post, eu na minha humilde opinião tenho um pensamento sobre administração centralizada :

     

    AP/DP – Antes de Powershell e Depois de Powershell

     

    POWERSHEL ROCKS !!!

     

     

    “Living easy, livin' free
    Season ticket, on a one, way ride
    Asking nothing, leave me be
    Taking everything in my stride

    Don't need reason, don't need rhyme
    Ain't nothing I would rather do
    Going down, party time
    My friends are gonna be there too

    I'm on the highway to hell

    Picasa Content


    I'm a highway to hell
    Highway to hell
    I'm on the highway to hell”

    Highway To Hell

    AC/DC

    Follow me on Twitter


    Apresentação Powershell & SQL Server na ETEC Antonio Devisate de Marília

     

    Pessoal,

    Com bastante satisfação aceitei um convite para fazer uma apresentação de duas horas sobre Powershell & SQL Server para as três turmas  de Tecnologia da Informação da ETEC Antonio Devisate de Marília. ( e já temos uma em andamento para a ETEC de Garça)

    Acontecerá dia 24/11/2009 e novamente temos o apoio do CEA. (comunidade em ação)

    Acho que consegui passar, apesar do pouco tempo e imprevistos, a fantástica tecnologia que é o Powershell no SQL SERVER DAY e felizmente a comunidade está aderindo a este modelo de administração.

    Haaaa..Marília e Região..aguardem…teremos Grandes Novidades  no ano que vem !!!!

    Galerinha da ETEC..já veremos o Powershell 2.0 ..!!!!!!!

    POWERSHELL & CEA ROCKS !!!!!!!

    “Awake on my airplane
    Awake on my airplane
    My skin is bare
    My skin is theirs
    Awake on my airplane
    Awake on my airplane
    My skin is bare
    My skin is theirs
    I feel like a newborn
    And I feel like a newborn
    Awake on my airplane
    Awake on my airplane
    I feel so real

     

    Could you take my picture?
    'cuz I won't remember
    Could you take my picture?
    'cuz I won't remember
    Could you take my picture?
    'cuz I won't remember
    Could you take my picture?
    'cuz I won't remember
    yeah”
    Take A Picture

    Filter

    November 10

    Alterando o Collation de Colunas das Tabelas com Powershell

     

    Tarde gente..

    Vai mais um script que acredito ser útil : Alterar Collations das colunas de tabelas.

    Pra começar, aquele nosso arquivinho servers.txt com todos os servidores a serem alterados.

    No meu caso fica em C:\PS\Servers

    image 

    E também usamos o arquivo functions.ps1 que pode ser baixado aqui.
    (lembre-se de deixar o functions.ps1 no mesmo path do script principal)

    A SMO também possui as restrições que TSQL tem (PK, FK, Indice..ect) mas estes campos que não se consegui alterar serão logados.

    Vamos ao Script :

    param (      [string] $Collation)
                 [string] $path
     
    [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null
     
    # load functions file
    . C:\PS\PsScripts\Functions.ps1
     
    $TodayDateErr = get-date -format "yyyyMMddhhmmss"
     
    $Server = ""
    $table = ""
    if ($Path -eq $null)
    {
           $Path = "C:\temp"
    }     
    $Error.Clear()
      
    foreach ($svr in get-content "C:\ps\servers\servers.txt" )
    {
        $Server=New-Object "Microsoft.SqlServer.Management.Smo.Server" "$svr"
        $Server.Databases   | where-object {$_.IsSystemObject -eq $FALSE -and
        $_.IsAccessible -eq $TRUE  } | foreach {
             foreach  ($table in $Server.Databases[$_.name].tables ) {
                        $db = $Server.Databases[$_.name]
                        if (!$table.IsSystemObject)
                        {
                               $tableName = $table.name
                                
                                                       
                               $table.columns | Where-Object {$_.datatype -match "char|varchar|nvarchar|text|ntext|nchar"} | foreach {
     
                                   trap  [Exception] {
                                      $Err = "Table : " + $tablename + " | " + $_.Exception.Message
                                      Save-Log "Collation" "$svr" "$db" "$Err" "$Path" "$TodayDateErr"
                                      $Error.Clear()
                                      continue;
                                   }  
                               $_.Collation = $Collation
                               $_.Alter()
                              
                               }     
                        }
                 }     
           }     
    }

     

    Baixe ele aqui

    Bom, este script te gera um arquivo de erro (um log) com as colunas que ele não conseguiu alterar, informando o server, database, tabela, coluna e mensagem de erro. Por ali você pode pegar os caras que não funcionaram e alterar na mão.

    Este arquivo, o path dele você passa na chamada do ps1, juntamente com o collation novo.

    Digamos que eu queria trocar o collation de todas as tabelas, em todos os databases, na lista do servers.txt para Latin1_General_CS_AI

    C:\ps\psscripts\SetCollation.ps1 “Latin1_General_CS_AI” “C:\temp”

    Aonde o primeiro parâmetro é o Collation Novo e o Segundo o path do arquivo de erro.

    QQ dúvida …tumm.tum..tumtum..tum

    POWERSHELL ROCKS !!!!!

    “My eyes are open wide
    By the way I made it through the day
    I watch the world outside
    By the way I’m leaving out today

    I just saw Hayley’s comet she waved
    Said “why you always running in place?
    Even the man in the moon disappeared
    Somewhere in the stratosphere”

    Tell my mother, tell my father
    I’ve done the best I can
    To make them realize
    This is my life
    I hope they understand
    I’m not angry, I’m just saying
    Sometimes goodbye is a second chance”

    Second Chance

    Shinedown

    November 09

    Demos e PPT da apresentação de POWERSHELL & SQL Server

     

    Pessoal ,

    segue o link da apresentação

    Quem quiser baixar fique a vontade !!!!

    QQ duvida nos exemplos..já sabem..msn, email,skype, twitter, sinal de fumaça, tambor…. agente dá um jeito de compartilhar a informação

    A apresentação está em PPT, PDF…escolham a que quiserem !!!!

    Também coloquei o POWERGUI, ferramenta que uso para meus scripts POWERSHELL.

    Baixar Apresentação e Demos POWERSHELL & SQLServer

    MSN : laertejuniordba@hotmail.com
    Email : laertejuniordba@hotmail.com
    Skype : laertejuniordba
    Twitter : www.twitter.com/laertejuniordba
    Blog Simple-Talk  :www.simple-talk.com/community/blogs/laerte/
    Tambor : Tum tum tum …tumtutum..tumtumtum
    Sinal de fumaça : Só vendo

     

    “I'm just a normal boy
    That sank when I fell overboard
    My ship would leave the country
    But I'd rather swim ashore


    Without a life that's sadly stuck again
    Wish I was much more masculine
    Maybe then I could learn to swim
    Like 'fourteen miles away' “

    Into The Ocean

    Blue October

    SQL SERVER DAY …conseguimos !!!!

    Pessoal,

    Vou contar um pouquinho como foi a noite de sexta para sábado e durante o evento.
    Pra quem não sabia, eu o Fabiano e o Thiago fizemos as apresentações presencial na ETEC Antônio Devisate de Marília.
    Novamente  agradecimentos ao meu amigo de longa data Professor Arnaldo , Diretoria e coordenação.

     

    Sexta :
    6 da manhã : Após revisar pela 72346723647823 vez minha apresentação e scripts, resolvi montar mais um script.
    11 da noite  : Fui revisar novamente meus scripts. Uma chuva maravilhosa e caiu a força. Meu note estava na tomada. Tentei ligar o note, PUFFF..Nada. Pensei, vou esperar a força voltar. Alguns minutos depois voltou…..e meu note nada.,.ligava..mas não saia da tela de entrada do windows. Não pensei duas vezes, peguei meu WINDOWS ORIGINAL e comecei o trabalho. Formatar e instalar TUDO.

     

    Sabado
    4 da manhã : Eu , o professor Arnaldo e o Mateus (Grande Mateus) fomos buscar o Thiago Zavaschi que estava chegando de Curitiba
    7 da manhã : Finalizei tudo e meu note estava pronto. TEstei de novo tudo ate as 8 da manhã
    8 da manha : Fomos para ETEC
    30 minutos antes de começar  minha apresentação , fui testar meus scripts. (Mateus  ainda disse : “cara tu ja testou o dia inteiro, não se preocupe..vai dar tudo certo”..mas alguma coisa não estava certa ,seilá..!!!!)
    Minha máquina começou a rebootar sozinha. Uma vez, duas vezes…Pensei já era. Não podia usar o note do Zavaschi por conta que ele estava em apresentação.
    Bom, resolvido como ?
    Peguei o note de um aluno que estava vendo a apresentação lá. E comecei a instalar as coisas.
    Terminei 5 minutos antes do Zavaschi acabar.
    Fui me conectar …sem áudio. Pegamos o 3G do Zavaschi e conectamos. O som saiu dali e a apresentação do note do aluno.
    Imaginem meu nervoso de querer compartilhar com vocês o pouco que sei de POWERSHELL e tudo dando errado.
    Thiagão..o que você fez, eu sabia que teu 3G estava com o limite free estourado e ia começar a pagar a partir dali, mas tu não pensou duas vezes..”Cara..vai no 3G…”. O que eu posso dizer ?  TU É O CARA, seja pela seu extenso conhecimento técnico , seja pela sua humildade e companheirismo.
    Em suma…apesar de imprevistos o show tem que continuar, e se por acaso alguém não gostou me desculpem, não foi esta intenção.
    Eu tinha que mostrar pra vocês POWERSHELL, nem que fosse por sinal de fumaça.
    Acho que consegui.
    Finalizei minha apresentação e ficamos até quase as 10, mas eu estava a quase 39 horas sem dormir e não tinha mais condição alguma de continuar e a escola precisava fechar as 10 horas.
    Chegamos em casa e eu ainda tentei pegar o final…mas o cansaço não deixava !!!! O Zavaschi viu tudo e me disse depois como foi e eu fiquei muito feliz por conta que TODOS foram excepcionais em suas apresentações e principalmente o Vladimir.
    VLADIMIR…CARA VOCE É O HEROI DESSE SQL SERVER DAY. NÃO DEIXOU A PETECA CAIR A TARDE !!!
    Alexandre, eu não tenho como lhe agradecer. Você acreditou em mim desde o começo e espero que tenha pelo menos chegado perto de suas expectativas na minha apresentação.
     

    Professor Arnaldo..não é por que você é meu amigo a tantos anos,…mas você é uma pessoa única. O que você fez pela gente e principalmente pelo Thiago não se compra !!!!!

    Mateus..nosso fotógrafo, infra,mecânico..enfim tudo…MUITO OBRIGADO me sinto feliz de ter um novo amigo ..conte comigo para o que você precisar !!!!!!..Continue sempre ouvindo esse cara chamado Arnaldo…você vai longe assim garoto !!!!!

    Fabiano e Thiago. Obrigado por terem vindo. Fabiano estava trabalhando e mesmo assim veio até Marilia para fazer sua apresentação. Thiago viajou 600 KM SÓ PARA VIR APRESENTAR !!!..Esses são os tipos de pessoas que fazem parte desse
    FANTÁSTICO GRUPO do sql server day.

     

    ETEC Antonio Devisate de Marília. Muito obrigado  por todo apoio técnico. Realmente os alunos tem que se orgulhar da infra estrutura que vocês possuem !!!!

    Meus amigos e o publico de quase 100 pessoas ONLINE que estavam lá, eu não via, mas meu moderador me disse das palavras de carinho de vocês.
    MUITO OBRIGADO !!!!! Se eu consegui passar esse pouco de powershell, foi graças a vocês que também acreditaram em mim.

     

    O que eu tirei disso tudo ?

     

    SE TU TIVER FORÇA DE VONTADE, SOUBER DO SEU COMPROMISSO COM A COMUNIDADE E PRINCIPALMENTE TIVER AMIGOS COMO EU TIVE EM TODOS OS MOMENTOS…..NADA TE SEGURA !!!!!

    Novamente obrigado THIAGO…o som foi graças a teu 3G.

    Algumas fotos do que foi para gente esse SQL SERVER DAY , pelo menos pra mim…é algo que não vou esquecer…..

    Não sei se estarei nos próximos..mas NESSE EU ESTIVE !!!!

    IMG_0009 (Large) IMG_0011 (Large) IMG_0003 (Large)

     

    IMG_0008 (Large) IMG_0018 (Large) IMG_0013 (Large)

    IMG_0023 (Large) IMG_0040 (Large) IMG_0044 (Large)

    IMG_0133 (Large) IMG_0045 (Large) IMG_0046 (Large)

    IMG_9963 (Large) IMG_0042 (Large) IMG_9974 (Large)

    IMG_0133 (Large) IMG_0136 (Large) IMG_9972 (Large)

    ALMOÇO MAIS DO Q BOM !!!

    (casa do Prof Arnaldo)

    IMG_0048 (Large)  IMG_0049 (Large) IMG_0052 (Large)

    PEROLAS

    IMG_0019 (Large)IMG_0055 (Large)  IMG_0057 (Large)

     SQL SERVER DAY ROCKS !!!!

    “Girl, you'll be a woman... soon

    I love you so much, can't count all the ways
    I've died for you girl and all they can say is
    "He's not your kind"
    They never get tired of putting me down
    And I'll never know when I come around
    What I'm gonna find
    Don't let them make up your mind.
    Don't you know...

    Girl, you'll be a woman soon,
    Please, come take my hand
    Girl, you'll be a woman soon,
    Soon, you'll need a man”

    Girl, You'll Be A Woman Soon

    Urge Overkill

    November 06

    SQL SERVER DAY ……AMANHÃ !!!!

     

    sqlserverday

    Pessoal,

    Falta 1 dia pro MAIOR EVENTO de SQL SERVER que o Brasil já viu.

    CEA Sem vocês nada disso estaria acontecendo . Obrigado !!!!!!!!!!!!!!!!!!!!! (Andressa você é um anjo)

    Luciano Palma mesmo estando em outro evento, abrirá o nosso.  Obrigado !!!!!!!

    Eu queria agradecer ao Nilton Pinheiro (MCDBABRASIL), meu site de coração. Sem palavras o que você fez pela gente !!!!

    Annabel, Andrew, Chris, Brad McGehee e todo pessoal da REDGATE (Simple-Talk, SQLServerCentral) que não mediu esforços também para nos ajudar !!!

    Pessoal do forum MCITP Brasil , vocês são demais. Mais um ótimo fórum de tecnologia para ajudar a comunidade !!!!

    Miguel Reina da Consultoria Nextsys , o que posso dizer meu amigo ? OBRIGADO !!!!! Não é a toa que a Nextsys é uma das melhores consultorias que tive o prazer de trabalhar !!!

    Tiago Baeta e Rina Noronha do Imasters  . Bastou estrar em contato somente !!!!!! Obrigado !!!!!!

    Dmitry Sotnikov (PowerGUIA FERRAMENTA GRAFICA DE POWERSHELL) e Susan Roper (Manager Product Marketing), ambos da QUEST. Comentei num dia e no mesmo já tinha aprovação de apoio!!!!

    Pessoal da ETEC Antonio Devisate de Marilia, Professor Arnaldo Hidalgo Junior, Diretor João Antônio de Oliveira Barbosa, coordenação e a todos professores que estão nos apoiando com toda estrutura técnica . OBRIGADO !!!!

    AO TIME do SQL SERVER DAY (Organização, Palestrantes,e moderadores) um grande parabéns !!!!!!

    E PRINCIPALMENTE A VOCÊS GALERA !!!! MAIS DE 600 inscritos !!!!

    SQL SERVER DAY ROCKS !!!!!!!

     

    Seize the day or die regretting the time you lost
    Aproveite o dia ou morra lamentando o tempo perdido

    It's empty and cold without you here, too many people to ache over
    Está vazio e frio sem você aqui, tantas pessoas sofrendo.

    Trails in life, questions of us existing here, don't wanna die alone without you here
    Trilhas na vida, questões de nós existindo aqui, não quero morrer sozinho sem você aqui”

     

     

    Seize the Day

    Avenged Sevenfold

    November 02

    “How To Became an Exceptional DBA” usando Powershell Parte I

    Versão português !!! A ingrêis ta saindo….sabe como é ..se português já é complicado, o editor fica de cabelo em pé quando vê meu inglês…

    articlepresentation_ST

    "How to Became an Exceptional DBA"  é um daqueles handbooks que estão em minha coleção privada, ao lado no  “Inside SQL Server 2000” da Kalen Dalaney. São exemplos de livros que mudam seu jeito de pensar, trabalhar e entender as coisas.

    Para ser sincero, a primeira vez  que li pensei : “A maioria é utopia”. Mas utópico era minha organização.

    Eu não conseguia ver fora daquele “mundinho” que eu tinha criado com minhas ações profissionais que eu pensava não precisar de mais . Estava bom daquele jeito.

    Hoje eu vejo que cada palavra que Brad McGehee escreveu neste sensacional handbook é perfeitamente aplicável a qualquer organização que você trabalhe. Seja pequena ou grande o que diferenciará , depois de ler, é seu jeito de pensar : Pequeno ou grande.

    O ensinamentos deste handbook me influenciaram tanto que quando comecei a aprender o pouco que eu sei de Powershell eu pensei :

    “Vou passar todos estes checklists que são sugeridos para Powershell”

    E hoje meus amigos, eu compartilho com vocês alguns destes scripts que uso diariamente  baseado neste handbook .

    Para não ser entediante a leitura ele foi dividido, e esta é a primeira parte.

    How to Became an Exceptional DBA using Powershell Parte I
    Check/Fix Usuários órfãos

     

    O cenário

    John IDontKnow, Robert IDontknowEither e você são DBAs de um grande datacenter em 3 turnos diários. O seu é das 7:00 AM as 16:00 PM. Todos os 3 tem autonomia suficiente para tomar decisões e medidas necessárias para o funcionamento do parque de servidores SQL Server do principal cliente da companhia, que compreende uma complexa estrutura OLTP e OLAP.

    Seu gerente, um antigo DBA da companhia (sim, ele é técnico e dos bons) em uma reunião pediu para você procurar por usuários órfãos no ambiente  para implementarem uma politica de segurança adequada.

    Você responde :
    “Ok..Farei hoje isso “ 
    Mas não seria melhor responder :
    “Se você quiser a relação agora, eu a tenho. Implementamos um processo que roda toda semana e procura por usuários órfãos , logando eles numa tabela”

    Você é um “Exceptional DBA” e usa Powershell !!!

    Check/Fix Usuários órfãos

    Neste script, trabalharemos com tratamento de erros, no caso de algum servidor estar offline.
    Infelizmente este script está na versão 1.0  e o tratamento de erros nesta versão não é tão avançado quanto a 2.0.
    Os próximos artigos da série provavelmente serão na 2.0

    Nós trabalharemos com 2 funções. Uma para gerar o arquivo de log do tratamento de erros e outra para verificar se o login existe ou tem que ser criado.

    A primeira coisa a ser fazer é criar 3 folders que terão o TXT com a lista de servidores, o arquivo de log e os scripts ps1 respectivamente.

    Neste caso  :
    Lista de servidores –>  “C:\PS\Servers\Servers.txt”,
    Log estará            -->  “C:\PS\Logs\OrphanedUsers”
    Scripts ps1           -->  “C:\PS\PSScripts”
     
    O Arquivo TXT que terá a lista de servidores , deverá conter TODOS os servidores a serem monitorados e caso haja mais de uma instância , também deverá ser colocada :

     

    clip_image001

    Se você não tem o SQL Server  2008 instalado mas quer usar o provider, está é uma boa referência :

    Installing SQL Server 2008 PowerShell snap-ins for SQL Server 2005 - Tim Benninghoff

    Profile

    “Quando você adicionar aliases, funções e variáveis, você está realmente adicionando-lhes apenas para a sessão atual do Windows PowerShell. Se você sair da sessão ou encerrar o Windows PowerShell, as alterações são perdidas.

    Para manter estas mudanças, você pode criar um perfil do Windows PowerShell e adicionar os aliases, funções e variáveis para os perfis. O perfil é carregado toda vez que o Windows PowerShell é iniciado.

    Para carregar um perfil, o Windows PowerShell política de execução deve permitir que você carregue os arquivos de configuração. Se isso não acontecer, a tentativa de carregar o perfil do Windows PowerShell falhar e exibe uma mensagem de erro.”

    Windows Powershell Profiles

    Ou seja, como veremos a execução do job tipo powershell e cmdexec, precisamos adicionar os providers do
    SQL SERVER 2008 no powershell.exe. Lembre-se o host do SQL SERVER 2008 já vem, mas o shell normal não.
    Olhe no path :

    %windir%\system32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1

    Abra este arquivo, se ele não existe crie com o nome acima.

    if (!(Get-PSSnapin -registered | ?{$_.name -match 'SqlServerProviderSnapin100'}))
    {
           add-pssnapin SqlServerProviderSnapin100
           add-pssnapin SqlServerCmdletSnapin100
    }
      

    Desta maneira todos os shells e usuários estarão habilitados a usar o SQL SERVER provider.

    Com isto pronto, vamos a função que gerará o log se tivermos problema e procurará pelos logins.

    ##########################################################
    #Save  log in file
    ##########################################################
    #File Name                        = $NamePS1
    #Server name                      = $Server
    #Error Message                    = $Erro
    #Path to generate file     = $PathFileError
    Function Save-Log ([String] $NamePS1,
                      [String] $Server,
                      [String] $Erro,
                      [String] $PathFileError,
                      [String] $TodayDate
                     )
    {
        #test if path wich will contains the error file exists. if not create
      if (!(Test-Path -path $PathFileError))
      {
        New-Item $PathFileError
      }
        #Put the name of error file like  $Nameps1.log
      #$NameFileFull = $PathFileError + "\" + $NamePS1 + (get-date -format "yyyyMMddhhmmss") + ".log"
      $NameFileFull = $PathFileError + "\" + $NamePS1 + $TodayDate + ".log"
       "Server : " + $Server, "Date : " + $TodayDate ,"Error Message: " + $Erro | Out-file  $NameFileFull -append
    }
    ##########################################################
    #verify login exists
    ##########################################################
    Function Get-Login (      [object] $Server,
                              [String] $LoginName
                        )
    {  
    $Collect = $Server.logins | where-object {$_.isdisabled -eq $False -and $_.IsSystemObject -eq $False -and $_.IsLocked -eq $False -and $_.name -eq $LoginName } 
    if ($Collect -eq $Null)
           {return  $False }
    else
           {return $True}
    }     

     

    O próximo passo é salvar este script no mesmo path para todos .ps1 . C:\PS\PSScripts\Functions.ps1 

    Baixar Functions.ps1

    Pronto podemos criar a tabela no repositório.

    create table tblOrphanedUsers ([Date] smalldatetime default getdate(),
                                  ServerName varchar(50),
                                  [Database] varchar(50),
                                  Users XML)
                                   

     

    E AGORA O SCRIPT PARA CHECAGEM :

    [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | out-null
    # load fucntions file
    . c:\ps\psscripts\Functions.ps1
    $TodayDate = get-date -format "yyyy-MM-dd hh:mm:ss"
    $TodayDateErr = get-date -format "yyyyMMddhhmmss"
    ##########################################################
    #Server and Database Repository
    ##########################################################
    $ServerRepository  = "SERVER1"
    $DBRepository = "DBA"
    $Path = "C:\PS\Logs\OrphanedUsers"
    $Error.Clear()
    foreach ($svr in get-content "C:\PS\Servers\servers.txt" )
    {
                 $MyError = 0
                  trap  [Exception] {
                        $Err = $_.Exception.Message
                        Save-Log "OrphanedUSers" "$svr" "" "$Err" "$Path" "$TodayDateErr"
                        $MyError = 1
                        $Error.Clear()
                        continue;
                    }  
            $Server=New-Object "Microsoft.SqlServer.Management.Smo.Server" "$svr" -ErrorAction  stop
           # if service off, then not test
           if ($MyError -eq 0)
           {
                 $Server.Databases  | where-object {$_.IsSystemObject -eq $FALSE -and$_.IsAccessible -eq $TRUE } | foreach {
                        $Database = $_.name
                        foreach  ($user in $Server.Databases[$_.name].users ) {
                  if (!$user.IsSystemObject -and $user.Login -eq "" )
                        {
                               $Insert =  !(Get-Login $Server $user.name)
                               $ObjectXML = New-Object PSObject
                               $ObjectXML | add-member Noteproperty UserName $user.name
                               $ObjectXML | add-member Noteproperty CreateLogin $Insert
                               $ObjectXML | export-clixml C:\ps\logs\Users.xml
                               $XML= Get-Content "C:\ps\logs\Users.xml"
                               $XML = $XML -replace "'", "''"
                               $SQL = "     Insert into tblrphanedUsers ([Date],ServerName,[Database],Users)       values ('$TodayDate','$svr','$Database','$XML')"
                               Invoke-Sqlcmd -ServerInstance $ServerRepository -Database $DbRepository -Query $Sql -ErrorAction SilentlyContinue
                               if (!$?)
                               {
                                     Save-Log "OrphanedUSers" "$svr" "$Database" "$Error" "$Path" "$TodayDateErr"
                                      $Error.Clear()
                               }
                                 del C:\ps\logs\Users.xml -ErrorAction SilentlyContinue
                            }           
                        }     
                 }     
           }
    }

     

    O próximo passo é gravar este script em C:\PS\PSScripts\OrphanedUsers.ps1

    Baixar OrphanedUsers.ps1

    A função Save-Log gera um arquivo de LOG com os erros encontrados e grava na pasta C:\PS\Logs\OrphanedUsers  com o mesmo nome do .ps1 mais data e hora , que neste caso é OrphanedUsers.ps1. A figura abaixo mostra isso :

    (CLIQUE NELAS PARA AUMENTAR)

    clip_image002

    clip_image002[5]

    Agora se quisermos ver os dados que foram logados na tabela :

    clip_image002[7]

    Mas se percebermos no código em powershell eu coloquei esta linha

    Insert =  !(Get-Login $Server $user.name)

    Isso se deve ao fato que podemos ter dois tipos de usuários órfãos :

    • Login Não Existe
    • Login existe, mas não está mapeado com o usuário

    E clicando na coluna Users abrirá o XML e no nó CreateLogin eu tenho esta informação. Se preciso criar ou mapear.

    clip_image002[9]

    Agora para visualizarmos os dados com a ultima coleta, usamos :

    SELECT      [Date],
                ServerName,
                [Database],
    users.value('
    declare namespace s="http://schemas.microsoft.com/powershell/2004/04";
    (/s:Objs/s:Obj/s:MS/s:S/text())[1]', 'varchar(255)') UserName,
    users.value('
    declare namespace s="http://schemas.microsoft.com/powershell/2004/04";
    (/s:Objs/s:Obj/s:MS/s:B/text())[1]', 'varchar(255)') CreateLogin
    FROM tblOrphanedUsers
    where [Date] = (  select      MAX([date])
                                 from  tblOrphanedUsers
                   
    )

     

    clip_image002[11]

    Mapeando User com Login

    Como já temos a informação dos logins a serem criados antes de mapear pela coluna CreateLogin , vamos gerar os comandos para mapear os que não precisam ser criados ou seja, já existem. (createlogin = false)

    Podemos fazer em TSQL (Visualizar em Modo Texto)

    SELECT 'Use ' + [Database] + CHAR(13) + CHAR(10) + ' go ' + char(13) + CHAR(10)
    + ' exec sp_change_users_login ''Update_one'',''' +
    users.value('
    declare namespace s="http://schemas.microsoft.com/powershell/2004/04";
    (/s:Objs/s:Obj/s:MS/s:S/text())[1]', 'varchar(255)') + ''',''' +
    users.value('
    declare namespace s="http://schemas.microsoft.com/powershell/2004/04";
    (/s:Objs/s:Obj/s:MS/s:S/text())[1]', 'varchar(255)') + '''' + CHAR(13) + CHAR(10) + ' go ' + CHAR(13) + CHAR(10)
    FROM tblOrphanedUsers
    where [Date] = (    select MAX([date])
                        from   tblOrphanedUsers
                        )     
    and    users.value('
    declare namespace s="http://schemas.microsoft.com/powershell/2004/04";
    (/s:Objs/s:Obj/s:MS/s:B/text())[1]', 'varchar(255)') = 'False'

     

    O resultado será :

    Use DBA
    go
    exec sp_change_users_login 'Update_one','TesteUsuarioOrfao','TesteUsuarioOrfao'
    go
    Use Teste
    go
    exec sp_change_users_login 'Update_one','TesteUsuarioOrfao','TesteUsuarioOrfao'
    go

     

    Podemos usar a opção AUTO_FIX na sp_change_users_login,mas eu acredito ser melhor por questões de segurança analisar primeiro antes de criar o Login.

    Mais sobre sp_change_users_login ? (eu coloquei por questões de compatibilidade , procure por alter login)

     

    OU PODEMOS REPARAR USANDO POWERSHELL

    (não se esqueça, você é um “Exceptional DBA” e usa powershell)

    Poderíamos alterar o script powershell para que depois de inserido na tabela, já mapeasse o login.
    Mas eu particularmente prefiro ver antes. Então após analisar, vamos na tabela que está logado os users : tblOrphanedUsers

    $SqlConn1 = New-Object System.Data.SqlClient.SqlConnection
    $SqlCmd1 = New-Object System.Data.SqlClient.SqlCommand
    $SqlAdapter1 = New-Object System.Data.SqlClient.SqlDataAdapter
    $DataSet1 = New-Object System.Data.DataSet
    $sql = "SELECT    ServerName,
                    [Database],
    users.value('
    declare namespace s=""
    http://schemas.microsoft.com/powershell/2004/04"";
    (/s:Objs/s:Obj/s:MS/s:S/text())[1]', 'varchar(255)') UserName
    FROM tblOrphanedUsers
    where [Date] = (    select    MAX([date])
                        from    tblOrphanedUsers
                    )   
    and     users.value('
    declare namespace s=""
    http://schemas.microsoft.com/powershell/2004/04"";
    (/s:Objs/s:Obj/s:MS/s:B/text())[1]', 'varchar(255)') = 'False'"

    $SqlConn1.ConnectionString = "Server=<ServerRepository>;Database= DatabaseRepository>;Integrated Security=True"
    $SqlCmd1.CommandText = $sql
    $SqlCmd1.Connection = $SqlConn1
    $SqlAdapter1.SelectCommand = $SqlCmd1
    $SqlAdapter1.Fill($DataSet1)

    foreach ($result in $DataSet1.Tables[0].rows) {
        $SqlConn1.ConnectionString = "Server=" + $result[0] + ";Database=" + $result[1] + ";Integrated Security=True"
        $sqlconn1.Open()
        $SqlCmd1.Connection = $SqlConn1
        $SqlCmd1.CommandText = "sp_change_users_login 'update_one','" + $result[2]+"','" +  $result[2] + "'"
        $SqlCmd1.ExecuteNonQuery()
        $SqlConn1.Close()   
    }

     

    Baixar este script  FixUserLogin.ps1

    Na linha :
    $SqlConn1.ConnectionString = "Server=<ServerRepository>;Database= <DatabaseRepository>;Integrated Security=True"

     

    Alterar para para o nome de seu servidor e database.
    Este script eu não trato erros, pois rodo manualmente sem jobs .

     

    Schedulando a Checagem

    Se você estiver usando o SQL Server 2008 somente basta criar um job com step tipo powershell e executar o script. A figura abaixo demonstra isso :

    clip_image002[2]

    Command :

    c:\ps\psscripts\OrphanedUsers.ps1

     

    Se estiver usando versões anteriores (inclusive a 2000 depois de ter adicionado os providers e baixado o powershell), basta criar um job com  step cmdexec conforme mostra figura abaixo :

    clip_image002[4]

    Command :

    Powershell.exe ‘c:\ps\psscripts\OrphanedUsers.ps1’

     

    Depois  é só schedular conforme sua necessidade !!!!!!!

    Bom pessoal, vimos nesta primeira parte como checar e reparar usuários órfãos.

    Eu particularmente quando preciso de um processo que seja repetido várias vezes uniformemente e gerenciando múltiplos servidores (isto serve para 1 ou 1000 servidores) não consigo mais ver outra maneira sem ser com a consistência e produtividade do Powershell .

    Nos próximos artigos veremos mais checagens, fazendo de você um

    “Exceptional DBA” usando Powershell !!!!!

    Hahaaaaa  acharam que eu ia esquecer néééééé !!!!

    POWERSHELL ROCKS !!!!

    Finalizei a versão em português ouvindo Ramones……E este som merece estar inteiro :

    No one ever thought this one would survive
    Helpless child, gonna walk a drum beat behind
    Lock you in a dream, never let you go
    Never let you laugh or smile, not you.

    Well, I just want to walk right out of this world,
    'Cause everybody has a poison heart
    I just want to walk right out of this world,
    'Cause everybody has a poison heart.

    Making friends with a homeless torn up man
    He just kind of smiles, it really shakes me up.
    There's danger on every corner but I'm okay
    Walking down the street trying to forget yesterday.

    Well, I just want to walk right out of this world,
    'Cause everybody has a poison heart.
    I just want to walk right out of this world,
    'Cause everybody has a poison heart,
    a poison heart, a poison heart, a poison heart ... yeah!

    You know that life really takes its toll
    And a poet's gut reaction is to search his very soul
    So much damn confusion before my eyes,
    But nothing seems to phase me and this one still survives.

    I just want to walk right out of this world,
    'Cause everybody has a poison heart.
    I just want to walk right out of this world,
    'Cause everybody has a poison heart,
    Well, I just want to walk right out of this world,
    'Cause everybody has a poison heart.
    a poison heart, a poison heart, a poison heart.
    a poison heart, a poison heart, a poison heart, a poison heart.

    Poison Heart

    Ramones

     

    Tks a meu amigo Felipe Ferreira que me ajudou no Xquery !!!!

    October 28

    SQL SERVER DAY !!!

    REDGATE  , SIMPLE-TALK APOIAM !!!!!

     

    RG-simpletools-onwhite_320x100

    IMASTERS  e MCDBABRASIL APOIAM !!!

    curvas_v10 MCDBA

    “!I saw him dancing there by the record machine
    I knew he must have been about 17
    The beat was going strong, playing my favorite song
    And I could tell it wouldn't be long till he was with me
    Yeah with me
    And I could tell it wouldn't be long till he was with me
    Yeah with me

    Singin' I love rock and roll
    So put another dime in the jukebox baby
    I love rock and roll
    So come on take some time and dance with me

    *OWWW*”

    I Love Rock 'N Roll

    Joan Jett

    October 27

    POWERSHELL V2.0 pro nosso querido e amado XP !!!!

     

    Galera, saiu FINALMENTE o PS V2.0 pro nosso XP..

    Na verdade  é um “pacotão”  chamado Windows Management Framework, que vem com :

    • Windows PowerShell 2.0
    • WinRM 2.0
    • BITS 4.0
     
    Para baixar e maiores informações  !!!

    Windows Management Framework is here!

     

    FIX !!!!

    Fix for PowerShell v2 on XP related crashes in MSCORSVW.DLL
    http://halr9000.com/article/833

     

    “And to love, a god
    And to fear, a flame
    And to burn a crowd that has a name
    And to right or wrong
    And to meek or strong

    It is known, just scream it from the wall
    I've willed, I've walked, I've read
    I've talked, I know, I know
    I've been here before”

    Selling The Drama

    Live

    JÁ RODEI REBUILD MAS MEU ÍNDICE NÃO DESFRAGMENTA !!!!

     

    Pessoal, uma pergunta que vejo frequentemente em fóruns é :

    Já rodei rebuild, reorganize…coloquei até galinha preta na encruzilhada….e meu índice não desfragmenta. Porque ?

    Galera, tudo se baseia no número de páginas do índice.

    Rode a sys.dm_db_index_physical_stats e procure na coluna pagecount.

    select *
    from sys.dm_db_index_physical_stats(DB_ID(),OBJECT_ID('SUATABELA'),null,null,'detailed')

     
    Se estiver abaixo de 1000 páginas (ou próximo..caso seja acima), não se preocupe.
    O Engine não vai se dar ao trabalho de desfragmentar pois provavelmente o índice inteiro está em cache, e então a fragmentação passa a ser irrelevante.
    Lembre-se Page Split é operação de IO.

     

    Outra coisa, tabelas heap dificilmente tem fragmentação, pois não tem uma ordem física definida e as páginas vão pro final do arquivo.
    Quando uma uma coluna é atualizada e não tem espaço na página, cria-se ponteiros. Então cria-se uma nova página, a linha vai pra ela e é colocado uma referência a este ponteiro na nova página.
    Eu vejo bastante dizer que basta colocar o índice cluster e dropar depois pra desfragmentar, mas isso  é considerado uma prática ruim pelo Paul Randal … ele não fala porque.

     

    Mais uma, se você reorganizar precisa atualiza estatísticas. Rebuild não precisa !!!!

    Quer ler mais sobre o assunto ? Vai que esse louuuuuuco tá falando besteira né!!! (eu posso ate falar, mas o carinha ai do link não)

    http://www.sqlskills.com/blogs/paul/

     

    “Tudo bem se não deu certo
    Eu achei que nós chegamos tão perto
    Mas agora com certeza eu enxergo
    Que no fim eu amei por nós dois

    Mas você lembra!
    Você vai lembrar de mim
    Que o nosso amor valeu a pena
    Lembra é o nosso final feliz
    Você vai lembrar...
    Vai lembrar...sim...
    Você vai lembrar de mim.”

    Você Vai Lembrar De Mim

    Nenhum de Nós

    Dica Rápida !!! Um pouco de Teclado no SSMS

     

    Pessoal, que não lembra do SQL2000 o CTRL+SHIFT+C para comentar as linhas no QA.

    No 2005 e 2008 não tiraram isso não.

    Basta colocarmos o teclado em compatibilidade  SQL2000

    Vá em Tools->Options->keyboard

    teclado

    E também podemos adicionar comandos novos !!!.

    Nesta imagem quando teclo CTRL+F1 rodo o sp_helpindex , CTRL+3 é a sp_spaceused.

    Basta configurar da maneira que quiser !!!

    E essa ..olha só a imagem a baixo e me digam como consegui selecionar somente o meio das linhas !!!

    teclado1

     

    Tente com SHIFT+ALT e as setinhas….!!!!

     

    “I got to have a shot of what you got is oh so sweet.
    You got to make it hot, like a boomerang I need a repeat,
    Gimme all your lovin', all your hugs and kisses too,
    Gimme all your lovin', don't let up until we're through,”

     

    Gimme All Your Lovin'

    ZZ Top

    October 26

    Executando uma Query em Múltiplos Servidores

     

    Se eu quiser trocar a senha de SA de todos os meus servidores ?

    Posso usar o Central Management Server do SSMS ? Com certeza ….

    MAS POWERSHELL ROCKS !!!!!!

    (gostei de ficar falando isso né..esquenta não..tem dia que não tomo meu remédio ..UHAAA.UHAAA (risada macabra) !!!!)

    1 - Se eu tenho uma senha somente para todos os servidores. Crie um .txt com o nome de todos os servidores e, por exemplo, coloque na pasta C:\PS\Servers.txt.

    server1
    server2
    server3\instance1
    server3\instance2

     

    foreach ($svr in get-content "C:\PS\Servers\servers.txt"  )
    {
             trap  [Exception] {
                    $Err = $_.Exception.Message
                    Write-Host $Err  " Não posso alterar o login em "  $svr
                    $Error.Clear()
                    continue;
               }   
        $sql = "ALTER LOGIN [sa] WITH PASSWORD='NEWPASSWORD'"
        Invoke-Sqlcmd -ServerInstance $svr -Database "MASTER" -Query $Sql -ErrorAction stop
    }


     

    2 - Se eu tenho senhas diferentes para cada servidor. Coloco a senha na frente do nome separado por virgula.

    server1,PWD1
    server2,PWD2
    server3\instance1,PWD3
    server3\instance2,PWD4

    foreach ($svr in get-content "C:\PS\Servers\servers_pwd.txt"  )
    {
             trap  [Exception] {
                    $Err = $_.Exception.Message
                    Write-Host $Err  " Não posso alterar o login em "  $server[0]
                    $Error.Clear()
                    continue;
               }   
        $server = $svr.Split(",")
        $sql = "ALTER LOGIN [sa] WITH PASSWORD='" + $server[1] + "'"
        Invoke-Sqlcmd -ServerInstance $server[0] -Database "MASTER" -Query $Sql -ErrorAction stop
    }

    E mais um script ao som de :
    Every breath you take
    Every move you make
    Every bond you break
    Every step you take
    I'll be watching you”

     

    Every breath you take

    The Police

    October 25

    SQL SERVER DAY !!!!!!.

     

     

    sqlserverday

     

    RG-simpletools-onwhite_320x100 

     

    curvas_v10

    SQL Server Day ROCKS !!!!

    “Theres a lady whos sure
    All that glitters is gold
    And shes buying a stairway to heaven
    When she gets there she knows
    If the stores are all closed
    With a word she can get what she came for
    Ooh, ooh, and shes buying a stairway to heaven”

    Stairway To Heaven

    Led Zeppelin

    Finalizando PPT de Powershell !!!! E com muito ROCK !!!!!!!!

     

    6 da manhã…acordei inspirado !!!!!

    O dia promete !!! Testar 1 mol de scripts powershell pra hoje !!!

    1 Mol ? ..HAHHAHHA…QUIMICA  1 mol é um número dinossauricamente grande !!!! 6,02 x 10 a 23
    Primeiro meu cérebro teve que pegar… Formula de Error Handling Cerebral !!!

     

    Try { ACORDA_CARA !!!!!}
    -Catch {10_minutos_por_favor !!!!!!}
    -finally { JA_ERA_O_DIA PROMETE !!! }

     

    Seleção Musical de Hoje !!! 80s,70s e METAL !!!!

     

    Joan Jett
    Nena
    Ozzy Osborne
    ACDC
    Guns
    Led Zeppelin
    Yardbirs
    Peter Frampton
    Gratefuldead
    Sister of Mercy
    Echo
    Rush
    IRONNNNNNNNNNNNNN

     

    Começando com “Do you wanna touch me” Joan Jett….Pra dar um baculejo  nas idéias !!!!

     

    “Weve been here too long
    Tryin to get along
    Pretendin that youre oh so shy
    Im a natural maam
    Doin all I can
    My temperature is runnin high

    Do you wanna touch (yeah)
    Do you wanna touch (yeah)
    Do you wanna touch me there, where
    Do you wanna touch (yeah)
    Do you wanna touch (yeah)
    Do you wanna touch me there, where
    There, yeah”

    ANOTHER DAY IN PARADISE FOLKS !!!!!

    Índice Cluster+identity = 100% fillfactor e sem Page Splits ?

     

    Pessoal, vejo dizer bastante que para não gerar page splits, basta colocar o índice cluster num campo identity e pode deixar o fillfactor com 100%.

    Verdade ?….

    NÃO !!!!!!!!!!.

    A resposta correta é…Depende dos tipos de colunas que terão sua tabela e principalmente se estas terão atualizações no tamanho do seu conteúdo. Page Splits ocorrem no update também !!!!

    Vamos lá ?

    if object_id('Testfillfactor') is not null
        drop table Testfillfactor
        go

    create table Testfillfactor    (    id int identity(1,1) not null,    
                                        name1 varchar(1000),
                                        name2 varchar(1000),
                                        name3 varchar(1000),
                                        name4 varchar(1000),
                                        name5 varchar(1000),
                                        name6 varchar(1000),
                                        name7 varchar(1000),
                                        name8 varchar(1000),
                                    )
    create unique clustered index  PK_TestFill on Testfillfactor(id)

    WITH(    PAD_INDEX = OFF,
            FILLFACTOR = 100,
            STATISTICS_NORECOMPUTE = OFF,
            IGNORE_DUP_KEY = OFF,
            ALLOW_ROW_LOCKS = ON,
            ALLOW_PAGE_LOCKS = ON
        )
    ON [PRIMARY]
    go

    set nocount on
    declare @loop int
    set @loop = 1
    while @loop < 50
    begin
        insert into TestFillfactor(name1,name2,name3,name4,name5,name6,name7,name8)
        values ('Name 1 ' + convert(char(10),@loop),'Name 2 ' + convert(char(10),@loop),'Name 3 ' + convert(char(10),@loop),
        'Name 4 ' + convert(char(10),@loop),'Name 5 ' + convert(char(10),@loop),'Name 6 ' + convert(char(10),@loop),'Name 7 ' + convert(char(10),@loop),
        'Name 8 ' + convert(char(10),@loop))
        set @loop = @loop + 1
    end 
    go

     

    Criamos uma tabela com 50 linhas continuas (indentity, com CIX no campo ID). Teoricamente não teria de haver Page Splits.

    Será ?

    alter index PK_TestFill on Testfillfactor Rebuild
    go
    dbcc ind(dba, Testfillfactor, 1, 0)
    go

     

    11

    PERFEITO NÃO VEJO “PAGE SPLIIIIIIIIIIIIIIITSSSSSSSSSSSSS”

    Vamos alterar o conteúdo dos campos ?

    update Testfillfactor set    name1 = REPLICATE('X',1000),
                                name2 = REPLICATE('X',1000),
                                name3 = REPLICATE('X',1000),
                                name4 = REPLICATE('X',1000),
                                name5 = REPLICATE('X',1000),
                                name6 = REPLICATE('X',1000),
                                name7 = REPLICATE('X',1000),
                                name8 = REPLICATE('X',1000)
    go
    dbcc ind(dba, Testfillfactor, 1, 0)

     

    Vamos ver como ficou ?

    12

    Bom..Uma civilização de Page Splits !!!!

    Certeza Laerte ?…Apesar do campo NextPageId já me mostrar isso, mas vamos ver….

    Peguei a Página 7548..O próximo deveria ser a Página 7549

    create table #dbccpageresults (    ParentObject varchar(max),
                            [Object] varchar(max),
                            [Field] varchar(max),
                            [Value] varchar(max)
                          )   
    insert into #dbccpageresults exec ('dbcc page( 0, 1, 7548, 3 ) with tableresults')   

    select * from #dbccpageresults where [field] = 'id'
    go
    truncate table #dbccpageresults
    go
    insert into #dbccpageresults exec ('dbcc page( 0, 1, 7549, 3 ) with tableresults')   
    go
    select * from #dbccpageresults where [field] = 'id'
    go
    drop table #dbccpageresults

     

    13

    Errado !!!!!

    Segundo o NextPageID a Próxima Página é a 8174, que tá lá embaixo e nem aparece na imagem por não caber !!!

    create table #dbccpageresults (    ParentObject varchar(max),
                            [Object] varchar(max),
                            [Field] varchar(max),
                            [Value] varchar(max)
                          )   
    insert into #dbccpageresults exec ('dbcc page( 0, 1, 7548, 3 ) with tableresults')   

    select * from #dbccpageresults where [field] = 'id'
    go
    truncate table #dbccpageresults
    go
    insert into #dbccpageresults exec ('dbcc page( 0, 1, 8174, 3 ) with tableresults')   
    go
    select * from #dbccpageresults where [field] = 'id'
    go
    drop table #dbccpageresults

     

    18

    Agora sim!!!!!!!…. 

    Ou seja da página 7548 pulou para a página 817 para continuar a ordem do CIX (clustered index)!!!!

    CONCLUSÃO ……

    LENDA !!!!!..

     

    A colocação do identity no índice cluster e FILLFACTOR 100%:

    • sua tabela tem campos de tamanho variável (varchar,nvarchar,varbinary) e estes são altamente atualizados (seja com valores maiores ou menores)
    PAGE SPLIT NA CERTA !!!!!
     
    • sua tabela tem campos de tamanho variável (varchar,nvarchar,varbinary) e estes NÃO são atualizados
    A colocação do identity no CIX PODE ser uma boa !!!

    Não é uma regra que se eu colocar o CIX num campo identity posso deixar meu fillfactor a 100% pois não terei Page Split.

    Vimos que em alguns casos o update também pode gerar Page Splits !!!!

    A Laerte, mas no exemplo tu preencheu os campos com o valor completo deles.

    Se por acaso você tiver 1 byte disponível na pagina e der um update pra 2 bytes..Já era..Page Split tio !!! (fillfactor 100%) Este registro passará inteiro para outra página e o espaço remanescente desta página será perdido!!!!

    E Tô ouvindo AC/DC

    “Jailbreak, let me out of here
    Jailbreak, sixteen years ah
    Jailbreak, had more than I can take
    Jailbreak, yeah”

    October 24

    Alterando um valor fixo em Muitas Procedures !!!!

     

    Pessoal,

    Teve uma pergunta bem legal no ask.sqlservercentral.com (diga-se que eu e o Felipe Ferreira estamos batendo ponto lá hahahaahah)  que era assim :

    O cara precisava alterar um valor em mais de 300 procs, um valor fixo. Algo como  Raiserror(876…) trocar por Raiserror(666…)

    E que são 8 da manhã e eu estou ouvindo um Iron - The number of the beast

    "Woe to you, Oh Earth and Sea,
    for the Devil sends the beast with wrath,
    because he knows the time is short...
    Let him who hath understanding reckon
    the number of the beast for it is a human number,
    it's number is Six hundred and sixty six"

    Mas voltando ao assunto, poderia ser feito com Powershell  !!!!!!!!!!!!!!!!!!!!!!!

    Eu não costumo usar a maneira que vou mostrar, foi somente para resolver o problema. Estou usando como file system (NÃO PERCAM MINHA APRESENTAÇÃO), eu costumo usar a SMO.

    foreach ( $StoredP in Get-ChildItem SQLSERVER:\SQL\SEUSERVIDOR\default\SEUDATABASE\storedprocedures ) {
        $TextSP = ((($StoredP.textheader + $StoredP.textbody) -replace "Create","Alter") -replace "OLDVALUE","NEWVALUE")
        $file = "c:\SEUPATH\" + $StoredP.Name + ".sql"
        Out-File -inputobject $textsp -filepath $file "Default" -append
    }

     

    4 LINHAAAAAAAAAAAAAAAAAAASSSSSSSSS !!!!!!!!!!!!!!!!!!
    (e isso porque AINDA não babo colorido em powershell, porque tem uns caras aí que fazem isso numa linha só)

     

    SEUSERVIDOR = Nome do servidor
    default = Nome da instância, se não tiver deixe default
    SEUDATABASE = Nome do seu banco
    SEUPATH = Path que será gerado os .sql (scripts das procs)
    OLDVALUE = Valor Antigo
    NEWVALUE = Valor Novo

    Este script pega proc a proc, troca o create por alter e no OLDVALUE coloco o valor a procurar. No NEWVALUE o valor a ser colocado.

    Ai eu gero um .sql no caminho c:\SEUPATH de cada proc, somente para pegar uma amostra e verificar se está tudo ok.

    Estando tudo certinho :

     

    foreach ($path in Get-item "c:\SEUPATH\*.sql")
    {
    Invoke-Sqlcmd -ServerInstance NOMESEVIDOR -Database NOMEDATABASE -InputFile $path
    }

     

    Troque o NOMESEVIDOR pelo nome do seu servidor e o NOMEDATABASE pelo nome do seu database !!!

    Será alterado !!!!

     

    “Six, six, six the number of the beast.
    Hell and fire was spawned to be released.”

     

    POWERSHELL ROCKS !!!!!!

    October 22

    How to Became an Exceptional DBA using Powershell ?

     

    Do you want to became an Exceptional DBA ?

    First, read this amazing FREE ebook from Brad McGehee

    How to Became an Exceptional DBA

    AND Powershell can help you  too !!!

     

    Soon…at simple-talk

    October 18

    REGISTRO DO SQL SERVER DAY – LINKS OFICIAIS !!!!!!!

     

    Galera,

    saiu os links oficiais do SQL SERVER DAY 2009

     

    SITE OFICIAL COM OS LINKS

    WWW.SQLSERVERDAY.COM.BR

     

    Foi dividido em 3 links para melhor organização e segue :

     

    Community Webcast: SQL Server Day - Parte I 

    09:30 - 10:00 - Abertura do Evento
    10:00 - 11:00 - Resource Governor e Policy Management - Vitor Fava e Alexandre Lopes
    11:00 - 12:00 - Entenda porque o Query Optimizer é mais esperto que você - Fabiano Amorim
    12:00 - 13:00 - SQL Azure Database - Diego Nogare
    13:00 - 14:00 - Novos Recursos de Desenvolvimento do SQL Server 2008 - Higor Fernandes

    Community Webcast: SQL Server Day - Parte II

    14:00 - 15:00 - Compressão de Dados e Backup no Microsoft SQL Server 2008 - Pedro A. G. Junior
    15:00 - 16:00 - Entendendo TDE (Transparent Data Encryption) - Felipe Ferreira
    16:00 - 17:00 - Entendendo as Common Table Expressions (CTE) - Thiago Zavaschi
    17:00 - 18:00 - Powershell Coletando e Analisando os Dados -Laerte Junior e Thiago Zavaschi
    18:00 - 19:00 - Solução Avançada de Problemas com Extended Events - Vladimir Magalhães        

    Community Webcast: SQL Server Day - Parte III

    19:00 - 20:00 - Disaster Recovery - Backup, Restore e Tópicos Avançados - Gustavo Maia Aguiar
    20:00 - 21:00 - CLR - Roberto Fonseca
    21:00  - 22:00 - Analise de Desempenho utilizando as Estatísticas de Espera - Alex Rosa     

    Agora só fazer o registro !!!!!

    Quem quiser ver tudo, faz o registro nos 3 links !!!!!

     

    Abraços !!!!