ptg 514 CHAPTER 17 Administering SQL Server 2008 with PowerShell Where {$_.EntryType -eq “Error”} PS>Get-EventLog Application -New 10| ` Where {$_.EntryType -eq “Error”}|Select-Object TimeWritten The preceding example demonstrates another useful feature of the PowerShell pipeline where you can join several commands together to get specific results. First, only the 10 newest entries are retrieved; then a pipe is used to get only the entries classified as an error, and finally, only the TimeWritten property is displayed. We mentioned WMI earlier in this chapter as a method for remote control and adminis- tration of servers. WMI is packed full of features that are useful for system administration. A few examples of using PowerShell’s built-in WMI features are shown here. . Getting a listing of all the fixed local logical drives: PS>Get-WmiObject -query “select * from Win32_LogicalDisk where DriveType=’3’” . Getting a listing of all the fixed remote logical drives: PS>Get-WmiObject -computerName server -query “select * from Win32_LogicalDisk where DriveType=’3’” . Getting a listing of all the local patches/hotfixes installed (the –computerName para- meter could be used with a value to retrieve this information from a remote system): PS>Get-WmiObject Win32_QuickFixEngineering NOTE Remote WMI connections may require that appropriate firewall rules be open in the network and also with a client firewall on the remote system. In addition, remote WMI queries must also be authenticated. By default, WMI queries use the current user’s authentication credentials. In some scenarios WMI authentication can be more complicated. The preceding examples show only the beginning of all the things WMI can provide quick access to. Another common task is trying to find files or folders. You can use the Get- ChildItem cmdlet to recursively search through a directory structure. The following example shows how to search for the location of the powershell.exe executable: PS>Get-ChildItem c:\ -recurse powershell.exe SQL Server–Specific Tasks Before jumping into more hardcore SQL Server PowerShell features, let’s briefly look at the SQL Server event log. Fortunately, the log simply contains text-based files, which PowerShell can read. You could use the Get-Content cmdlet to view the entire log, but Download from www.wowebook.com ptg 515 Step-By-Step Examples 17 instead you can use the Select-String cmdlet to look for a specific string or pattern in the error log file. First, you change the current location to the SQL Server log directory: PS>Set-Location “C:\Program Files\Microsoft SQL Server” PS>Set-Location (join-path $pwd “MSSQL10_50.MSSQLSERVER\MSSQL\Log”) PS>Select-String “error” ERRORLOG The PowerShell prompt in the preceding example is simply a generic one because the preceding commands would work both in the default PowerShell console and in the SQL Server PowerShell minishell. An example of taking this further would be to retrieve all the errors in the ERRORLOG file. When you use Get-Member and Format-List to look at the object output by Select- String, the date is hidden inside a string in the Line property: PS > Select-String “error” ERRORLOG|foreach{$_.line}|where{$_ -match “^20*”}| foreach{$date,$time=$_.split()[0],$_.split()[1];[datetime]$($date+” “+$time) } PS > The preceding example demonstrates how to look for the string ”error” in the current SQL Server ERRORLOG file. For all the lines that match, the Line property is passed along the pipeline. Next, based on some testing, it appears that you want to search only lines that start with ”20*-”. From that object, two values are retrieved: $_.split()[0] and $_.split[1]. These values are placed in the $date and $time variables, respectively. From there, they are recombined, and a type accelerator is used to indicate that this is a date/time object, so any calculations against this value will be simplified. What is finally output is the time stamp showing when the error occurred. Using the Provider Using the SQL Server provider can be very handy in navigating the system. Starting PowerShell from SSMS, DBAs can easily find their way through different objects as if working with files and directories. When the SSMS is used to start PowerShell at the server level, the databases are down one level, and from there tables and users, for example, can also be easily accessed. In the session shown in Figure 17.8, we navigated to a particular database and entered a dir Tables command. The output from the last command would scroll beyond the current screen, so only the first part of the output is displayed. Creating a Database Table Creating a database and a table are common tasks that a DBA may undertake. You can use T-SQL with the Invoke-SqlCmd cmdlet to do this, but a demonstration on how to do this with the SQL Server PowerShell minishell using SMO is presented here to help you better understand the new functionality that is available: Download from www.wowebook.com ptg 516 CHAPTER 17 Administering SQL Server 2008 with PowerShell FIGURE 17.8 Navigating the SQL Server provider. cd databases $my_db=New-Object Microsoft.SqlServer.Management.Smo.Database $my_db.Name=”my_database” $my_db.Parent=(Get-Item ) $my_db.Create() cd my_database cd tables $my_tbl=New-Object Microsoft.SqlServer.Management.Smo.Table $my_tbl.Name=”my_table” $my_tbl.Parent=(Get-Item ) $my_col=New-Object Microsoft.SqlServer.Management.Smo.Column $my_col.Name=”my_column” $my_col.Parent=$my_tbl $my_col.DataType= ([Microsoft.SqlServer.Management.Smo.DataType]::Int) $my_tbl.Columns.Add($my_col) $my_tbl.Create() In the preceding example, some new objects are created, some of their properties are set, and some methods are called. You can search for the particular SMO classes used in this example to gain further information. In the future, there may be something like New-Database and New-Table cmdlets that help to create a database and table, which would likely reduce the preceding code to fewer than five lines. Performing a Database Backup Another example that may be useful is performing a database backup using SMO. Using the AdventureWorks2008R2 database, you can back up the database using just a few lines: $server=New-Object Microsoft.SqlServer.Management.Smo.Server Download from www.wowebook.com ptg 517 Step-By-Step Examples 17 $backup=new-object Microsoft.SqlServer.Management.Smo.Backup $file=new-object Microsoft.SqlServer.Management.Smo.BackupDeviceItem $file.Name=”C:\backup\AW_DB.bak” $backup.Devices.Add($file) $backup.Database=”AdventureWorks2008R2” $backup.SqlBackup($server) The preceding code could be copied into a .ps1 file (for this example, assume it’s copied to c:\temp\backup.ps1), and it could be changed to accept two arguments. The preceding code could be modified to the following code snippet so that it accepts parameters from the command line: param([string]$device=$(throw Write-Host “Device required”), [string] $database=$(throw Write-Host “Database required”)) Write-Host “backup of $database to $device starting ” $server=New-Object Microsoft.SqlServer.Management.Smo.Server $backup=new-object Microsoft.SqlServer.Management.Smo.Backup $file=new-object Microsoft.SqlServer.Management.Smo.BackupDeviceItem $file.Name=$device $backup.Devices.Add($file) $backup.Database=$database $backup.SqlBackup($server) Write-Host “backup complete” Get-Item $device The changes in the preceding example introduce a new keyword, throw. Without it, error messages would be thrown to the console, but this might not help the end user to under- stand why it failed. For the purpose of printing feedback to the console, the Write-Host and Get-Item cmdlets were also added to provide a limited amount of feedback and to finally provide the details of the final backup file. Then to invoke the script, as shown in the following example, you simply need to pass two parameters to the script: the names of the file to back up to and the database to actu- ally back up. PS>$backup_to=”C:\backup\AdventureWorks2008R2.bak” PS>$db=”AdventureWorks2008R2” PS> c:\temp\backup.ps1 $backup_to $db As an example of using a conditional statement in the preceding script, perhaps a check could be done to see whether a backup has already been completed within the past seven days. To accomplish this, you would add this particular section of code just before the line Write-Host “backup of $database to $device starting ”: If((Test-Path $device) -and (Get-Item $device).LastWriteTime ` -gt (Get-Date).AddDays(-7)){ “Backup has been performed in last 7 days” Break } Download from www.wowebook.com ptg 518 CHAPTER 17 Administering SQL Server 2008 with PowerShell In the preceding code, a conditional statement is added to accomplish the check. The AddDays() method is passed a negative number which subtracts days from the current date NOTE When you use the param keyword, this section of code must be on the first noncom- mented line in all scripts. Otherwise, the PowerShell parser returns an error. Again, using SMO isn’t necessarily for beginners, but the good thing is that scripts can easily be created and passed around. The preceding example shows the bare minimum required to do a database backup; several other options are available, and the preceding code would actually overwrite the backup each time it is run. There also isn’t any error checking of any sort, which isn’t the best way to develop scripts. Along with the New-Database and New-Table cmdlets that may come in the future, maybe a Start-DbBackup will be another good cmdlet to have available. Checking Server Settings From the SSMS, by right-clicking on the SQL Server node and then starting a SQL Server PowerShell session, you can open a console directly in the root of the default SQL Server in the example. From here, you can easily obtain information on the SQL Server. First, the location is set to the instance that is to be queried, and then an object representing the SQL Server is saved to a variable (this demonstrates the advanced features mentioned earlier where objects can be saved to variables). The properties of that variable can then be accessed as follows: PS>Set-Location SQLSERVER:\SQL\<servername>\<instance_name> PS>$sql_server=get-item . PS>$sql_server.Information.VersionString Using the Get-Member cmdlet discussed earlier, you can easily discover other members of the object contained in $sql_server, but this is left as an exercise for you to perform on your own. NOTE This example demonstrates an important feature of the SQL Server provider: context sensitivity. In the preceding example, the current location was in the root of the SQL Server provider or database, and the command Get-Item. was used. The dot in this command basically indicates that you want an object that represents the current loca- tion in the provider. If the dot were moved to a different location, this command would no longer work the same way. Download from www.wowebook.com ptg 519 Step-By-Step Examples 17 Checking the Database Usage Using the object retrieved in the $sql_server variable, you can create a quick report of database usage using the databases property of that object, as shown here: PS SQLSERVER:\SQL\<servername>\<instancename>> $sql_server.databases| Format-Table -autosize Name,@{ Label= “% Used” Expression={[math]::round((($_.spaceavailable/1kb)/$_.size),2)} }Name % Used AdventureWorks2008R2 0.02 AdventureWorksDW2008R2 0 AdventureWorksLT2008R2 0.02 bigpubs2008 0.18 Customer 0.74 master 0.24 model 0.39 msdb 0.02 my_database 0.38 tempdb 0.8 Using the Format-Table cmdlet, you can easily and quickly create all kinds of reports. Some capabilities we haven’t discussed yet were used to create this report: . Calculated properties—The values displayed by Format-Table can be calculated using scriptblocks. That allows the logic to be highly customized. These scriptblocks are laid out as follows: @{Label=”some text value” Expression={the scriptblock to evaluate here} } . Direct access to the .NET Framework—The following line is directly from the .NET Framework: ”[math]::round(value,decimal)” .NET functionality is being used to round out the numbers to the second decimal point. PowerShell has special meaning for 1kb, 1mb, 1gb and 1tb, which all present the value of the counterpart in number of bytes—for example, 1kb=1024. The values can also be uppercase. Download from www.wowebook.com ptg 520 CHAPTER 17 Administering SQL Server 2008 with PowerShell Getting Table Properties Another common task is to get a row count of the tables in a particular database: PS SQLSERVER:\SQL\<servername>\<instancename>\Databases\ AdventureWorks2008R2\Tables> Get-ChildItem .| Sort-Object -descending|Select- Object -First 10| Format-Table -autosize Name,RowCountNote NOTE An easy-to-remember alias for Get-ChildItem is basically dir. In the preceding example using the AdventureWorks2008R2 database, the top 10 tables with the highest row count value are returned. NOTE The preceding example shows how many features are packaged within PowerShell, which applies not only to SQL tables, but also to all .NET objects. Simply using Get- Item on a particular table returns only the default properties of Schema, Name, and Created. Piping something like Get-Item [table_name] to either Format-Table * or Get-Member exposes all the properties available for a particular object. Cmdlet Example: Invoke-SqlCmd The Invoke-SqlCmd cmdlet was mentioned earlier. It will likely be the most commonly used cmdlet currently provided. Here is a simple example using this cmdlet: Invoke-sqlcmd -query “exec sp_help” Using Invoke-SqlCmd, you can simply pass any T-SQL–based query as a value to the cmdlet. The preceding basic example is provided by running a basic built-in stored proce- dure: sp_help. This example demonstrates several important issues, especially how powerful the provider can be. Based on the location in the SQL provider, some of the values passed to the cmdlet are automatically provided to the cmdlet by the provider itself: the server and database to query aren’t required in the command line. Let’s consider this example a bit further and do a few extra things with it. First, this cmdlet can accept input from the pipeline: ”exec sp_help”|ForEach-Object{Invoke-SqlCmd $_} The preceding line demonstrates a few more issues that have already been discussed: the ForEach-Object cmdlet, the special variable $_, and also the way parameters can automat- Download from www.wowebook.com ptg 521 Step-By-Step Examples 17 ically match values to parameters even when the parameter name isn’t explicitly added to the command entered. The sp_help stored procedure provides a lot of information. What if only the extended stored procedures were required? When Get-Member is used, the members from this particular query are inspected, and it is determined that the Object_type property is the value that indicates what kind of stored procedure is being dealt with. The query to get only extended stored procedures is now the following: ”exec sp_help”|ForEach-Object{Invoke-SqlCmd $_}| ` Where{$_.Object_type -eq “extended stored proc”}|Select Name Finally, the output consists only of extended stored procedures. Cmdlet Example: Invoke-PolicyEvaluation Another one of the provided cmdlets is Invoke-PolicyEvaluation. This cmdlet is used to specify a SQL Server Policy-Based Management policy (or policies) that will be evaluated against the target server. You can easily cycle through all the available policies and evalu- ate each one, or simply provide a list of policies to evaluate separated by a comma. Consider this example: sl “C:\Program Files\Microsoft SQL Server\100\Tools\Policies\DatabaseEngine\1033” Invoke-PolicyEvaluation -Policy “Database Auto Shrink.xml” -TargetServerName “MSSQLSERVER” The preceding command returns the output to the console of the result of the policy eval- uation. By default, the particular policy passed to the cmdlet is only checked. In other words, by default, properties are actually changed so that they are now compliant with the policy. Joining Columns Quite often, databases provide a table for users. Frequently, these users have their last name and first name in separate columns. Because these are typically simple strings, a feature, already discussed, allows two strings to be easily joined together. The following code snippet shows how two columns from the AdventureWorks2008R2 database are easily joined together from within the SQL minishell: PS SQLSERVER:\SQL\D830\DEFAULT\databases\adventureworks2008r2> Invoke-SqlCmd “Select * from Person.Person”| ` >> Select-Object -First 10|ForEach-Object{$_.LastName + “, “ + $_.FirstName} Sánchez, Ken Duffy, Terri Tamburello, Roberto Walters, Rob Download from www.wowebook.com ptg 522 CHAPTER 17 Administering SQL Server 2008 with PowerShell Erickson, Gail Goldberg, Jossef Miller, Dylan Margheim, Diane Matthew, Gigi Raheem, Michael Here, the first 10 records are selected, and then the LastName and FirstName values are combined together. Retrieving an Entry On occasion, you might need to get a particular entry from a table. When the following code snippet is run, an array is automatically returned: PS SQLSERVER:\SQL\D830\DEFAULT\databases\adventureworks2008r2> Invoke-SqlCmd “Select * from Person.Person” PowerShell provides a simple way to look at particular elements within an array. In the following example, entry 100 is returned and then entries 95 to 105: PS SQLSERVER:\SQL\D830\DEFAULT\databases\adventureworks2008r2> (Invoke-SqlCmd “Select * from Person.Person”)[100] PS SQLSERVER:\SQL\D830\DEFAULT\databases\adventureworks2008r2> (Invoke-SqlCmd “Select * from Person.Person”)[95 105] NOTE The first element of an array is the element zero; therefore, the first record in an array is retrieved by referencing the element id [0]. Summary This chapter provides an overview of PowerShell and how it has been specifically imple- mented in SQL Server 2008. Microsoft is putting a lot of effort into integrating PowerShell into all its server-based products, including SQL Server. Support for PowerShell in SQL Server 2008 still has a way to go before it could ever be considered the main scripting language, but the functionality available now is worth looking at. The next chapter delves into high availability and the options available in SQL Server 2008. Download from www.wowebook.com ptg CHAPTER 18 SQL Server High Availability IN THIS CHAPTER . What’s New in High Availability144 . What Is High Availability?145 . The Fundamentals of HA147 . Building Solutions with One or More HA Options150 . Other HA Techniques That Yield Great Results159 . High Availability from the Windows Server Family Side162 With SQL Server 2008, Microsoft continues to push the high availability (HA) bar higher and higher. Extensive high-availability options, coupled with a variety of Windows server family enhancements, provide almost everyone with a chance at achieving the mythical “five- nines” (that is, 99.999% uptime). Understanding your high-availability requirements is only the first step in implementing a successful high-availability application. Knowing what technical options exist is equally as important. Then, by following a few basic design guidelines, you can match your requirements to the best high-availability technical solution. This chapter introduces a variety of fundamental HA options—such as redundant hardware configurations, RAID, and MSCS clustering—as well as more high-level options— such as SQL clustering, data replication, and database mirroring—that should lead you to a solid high-availability foundation. Microsoft has slowly been moving in the direc- tion of trying to make SQL Server (and the Windows oper- ating systems) as continuously available as possible for as many of its options as possible. Remember that Microsoft is competing with the UNIX/Linux-based worlds that have offered (and achieved) much higher uptime levels for years. The SQL Server RDBMS engine itself and the surrounding services, such as Analysis Services, Integration Services, Notification Services, and Reporting Services, have all taken big steps toward higher availability. Download from www.wowebook.com . 105: PS SQLSERVER: SQL D830DEFAULTdatabasesadventureworks200 8r2& gt; (Invoke-SqlCmd “Select * from Person.Person”)[100] PS SQLSERVER: SQL D830DEFAULTdatabasesadventureworks200 8r2& gt; (Invoke-SqlCmd. $device starting ” $server= New-Object Microsoft. SqlServer.Management.Smo .Server $backup=new-object Microsoft. SqlServer.Management.Smo.Backup $file=new-object Microsoft. SqlServer.Management.Smo.BackupDeviceItem. imple- mented in SQL Server 2008. Microsoft is putting a lot of effort into integrating PowerShell into all its server- based products, including SQL Server. Support for PowerShell in SQL Server 2008 still