{"id":83677,"date":"2019-03-25T15:15:37","date_gmt":"2019-03-25T15:15:37","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=83677"},"modified":"2019-08-15T13:43:59","modified_gmt":"2019-08-15T13:43:59","slug":"scripting-out-a-sql-server-instance-agent-jobs-xevents-triggers-and-the-like","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/scripting-out-a-sql-server-instance-agent-jobs-xevents-triggers-and-the-like\/","title":{"rendered":"Scripting Out a SQL Server instance (Agent jobs, XEvents, Triggers and the like)"},"content":{"rendered":"<p>In order for a database system to work, you often need to provide programmable server objects. I&#8217;ve written very few databases that didn&#8217;t include agent jobs and triggers, or that didn&#8217;t require XEvents for diagnostics.\u00a0 These need to be scripted out in just the same way as database objects. . It can be done via SSMS, of course, but a script provides a safety-net even then. For a DBA, it is useful to script server objects.\u00a0<\/p>\n<p>You may be wanting to save just the server objects that are associated with one or more databases. It is always a problem with server scripts that it isn&#8217;t always easy to associate agent job steps with a particular database. I don&#8217;t have an answer for this. I think the best approach is to filter jobs by name if you have a\u00a0 job that has a one-to-one relationship with a database.<\/p>\n<p>Here is an example of how to script out the main server programmable objects with the sqlserver module. I&#8217;ve included the empty databases in this script, since these are server objects, but you can experiment with the list according to your specific requirements. I&#8217;ve chosen to script out the server objects that aren&#8217;t system objects. You will get more informationabout settings and configurations if you remove that filter.<\/p>\n<pre class=\"theme:ssms2012-simple-talk font:consolas font-size:14 line-height:16 marking:false ranges:false nums-toggle:false wrap:true wrap-toggle:false lang:ps decode:true  \">$Filepath = 'MyFilePath' # local directory to save build-scripts to\r\n$ServerInstance  = 'MyServer' # server name and instance\r\n$SQLUserName = 'MyLogin' #leave blank if Windows auth\r\n\r\n$BadChars = '[\\\\\\\/\\:\\.]' #characters that we don't want in filenames\r\n\r\n\r\nset-psdebug -strict # to catch subtle errors\r\n$ErrorActionPreference = \"stop\" # you can opt to stagger on, bleeding, if an error occurs\r\n# Load sqlserver module\r\n$popVerbosity = $VerbosePreference #remember current verbosity setting\r\n$VerbosePreference = \"Silentlycontinue\"\r\n# the import process is very noisy if you are in verbose mode\r\nImport-Module sqlserver -DisableNameChecking #load the SQLPS functionality\r\nif ([System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.Management.XEvent\") -eq $null)\r\n{\r\n  throw \"Could not load library for Extended Events.\"\r\n}\r\n$VerbosePreference = $popVerbosity\r\n#Does the directory specified actually exist? If not create it.\r\nif (-not (Test-Path -PathType Container $Filepath))\r\n{\r\n  # we create the  directory if it doesn't already exist\r\n  $null = New-Item -ItemType Directory -Force -Path $Filepath;\r\n}\r\n\r\n# get credentials if necessary\r\nif ($SQLUserName -ne '') #then it is using SQL Server Credentials\r\n{\r\n  $SqlEncryptedPasswordFile = `\r\n  \"$env:USERPROFILE\\$($SqlUserName)-$($SQLInstance).txt\"\r\n  # test to see if we know about the password in a secure string stored in the user area\r\n  if (Test-Path -path $SqlEncryptedPasswordFile -PathType leaf)\r\n  {\r\n    #has already got this set for this login so fetch it\r\n    $Sqlencrypted = Get-Content $SqlEncryptedPasswordFile | ConvertTo-SecureString\r\n    $SqlCredentials = `\r\n    New-Object System.Management.Automation.PsCredential($SqlUserName, $Sqlencrypted)\r\n  }\r\n  else #then we have to ask the user for it\r\n  {\r\n    #hasn't got this set for this login\r\n    $SqlCredentials = get-credential -Credential $SqlUserName\r\n    $SqlCredentials.Password | ConvertFrom-SecureString |\r\n    Set-Content $SqlEncryptedPasswordFile\r\n  }\r\n}\r\n\r\n$ms = 'Microsoft.SqlServer'\r\n$My = \"$ms.Management.Smo\" #\r\nif ($SQLUserName -eq '') #dead simple if using windows security\r\n{ $s = new-object (\"$My.Server\") $ServerInstance  }\r\nelse # if using sql server security we do it via a connection object\r\n{\r\n  $ServerConnection = new-object \"$ms.Management.Common.ServerConnection\" (\r\n    $ServerInstance , $SQLUsername, $SqlCredentials.Password)\r\n  $s = new-object (\"$My.Server\") $ServerConnection\r\n}\r\n\r\n$ScriptOptions = new-object (\"$My.ScriptingOptions\")\r\n$MyPreferences = @{\r\n  #create the scripting options just the once\r\n  'ExtendedProperties' = $true; #we want extended properties scripted\r\n  'DRIAll' = $true; #Yes, all the constraints\r\n  'ScriptDrops' = $false;\r\n  'Indexes' = $true; # Yup, these would be nice\r\n  'Triggers' = $true; # This should be included when scripting a database\r\n  'ScriptBatchTerminator' = $true; # this only goes to the file\r\n  'IncludeHeaders' = $true; # of course\r\n  'ToFileOnly' = $true; #no need of string output as well\r\n  'IncludeIfNotExists' = $true; # not necessary but the script can be more versatile\r\n  'IncludeDatabaseContext' = $true;\r\n  'Encoding' = [System.Text.Encoding]::UTF8;\r\n}\r\n$MyPreferences.GetEnumerator() |\r\nForeach{ $Name = $_.name; $ScriptOptions.$name = $_.Value }\r\n\r\n#\r\nif ($s.Version -eq $null) { Throw \"Can't find the instance $ServerInstance \" }\r\n$Scriptdirectory = \"$FilePath\\$($s.DomainInstanceName -replace $BadChars, '-')\"\r\n&lt;# and we can now establish the filename based on the server and maybe create the directories #&gt;\r\nif (-not (Test-Path -PathType Container $Scriptdirectory))\r\n{\r\n  # we create the  directory if it doesn't already exist\r\n  $null = New-Item -ItemType Directory -Force -Path $Scriptdirectory;\r\n}\r\n\r\n$ScriptOptions.Filename = \"$Scriptdirectory\\Agent.sql\";\r\n$s.jobserver.script($ScriptOptions) #script out the agent creation (its properties, in fact!)\r\n#properties, roles,\r\n@('Databases', 'audits', 'AvailabilityGroups', 'CryptographicProviders', 'Endpoints', 'Settings',\r\n  'Triggers', 'BackupDevices', 'LinkedServers', 'Logins', 'UserDefinedMessages') |\r\nforeach { $s.\"$_\" } | # we can get a description of each type from the URN and write each object out\r\n  foreach {\r\n    $currentCollection = $_.urn.Type;\r\n    if ($_.IsSystemObject -eq 0)\r\n    {\r\n      $ScriptOptions.Filename = \"$Scriptdirectory`\\$currentCollection-$($_.Name -replace $BadChars, '-').sql\";\r\n      $ScriptOptions.ScriptDrops = $true; $ScriptOptions.AppendToFile = $false;\r\n      try { $_.Script($ScriptOptions) }\r\n      catch { write-warning \"$currentCollection : $($_)\" } #delete server object if it is there\r\n      $ScriptOptions.ScriptDrops = $false; $ScriptOptions.AppendToFile = $true;\r\n      try { $_.Script($ScriptOptions) }\r\n     catch { write-warning \"$currentCollection : $($_)\" } #create server object if not there \r\n    }\r\n  }\r\n#iterate over the collections we want to script out...  \r\n@('Alerts', 'Jobs', 'Operators',\r\n  'SharedSchedules', 'ProxyAccounts', 'TargetServers') |\r\nforeach { $s.JobServer.\"$_\" } | # all the Agent objects we want to script out\r\n  foreach {\r\n  $currentJobserverCollection = $_.urn.Type;\r\n  $ScriptOptions.Filename = \"$Scriptdirectory`\\$currentJobserverCollection-$($_.Name -replace $BadChars, '-').sql\";\r\n  $ScriptOptions.ScriptDrops = $true; $ScriptOptions.AppendToFile = $false;\r\n  try { $_.Script($ScriptOptions) }\r\n  catch { write-warning \"$currentJobServerCollection : $($_)\" } #script delete agent object if it is there\r\n  $ScriptOptions.ScriptDrops = $false; $ScriptOptions.AppendToFile = $true;\r\n  try { $_.Script($ScriptOptions) }\r\n  catch { write-warning \"$currentJobserverCollection : $($_)\" } #create agent object \r\n}\r\n#Now we script out the Extended events (xEvents)\r\n#first we get our connection\r\n$SqlConn = $s.ConnectionContext.SqlConnectionObject\r\n#we use this to instantiate our Xtended Events store\r\n$store = New-Object  Microsoft.SqlServer.Management.XEvent.XEStore $SqlConn\r\n#we script out all the sessions.\r\n$store.Sessions | foreach{\r\n  $_.ScriptCreate().ToString() &gt; \"$Scriptdirectory`\\Events-$($_.Name -replace $BadChars, '-').sql\";\r\n}\r\n\r\n<\/pre>\n<p>This should end up providing you with a directory with all your programmable server objects scripted out, each in its own file.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In order for a database system to work, you often need to provide programmable server objects. I&#8217;ve written very few databases that didn&#8217;t include agent jobs and triggers, or that didn&#8217;t require XEvents for diagnostics.\u00a0 These need to be scripted out in just the same way as database objects. . It can be done via&#8230;&hellip;<\/p>\n","protected":false},"author":154613,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[],"coauthors":[6813],"class_list":["post-83677","post","type-post","status-publish","format-standard","hentry","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/83677","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/154613"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=83677"}],"version-history":[{"count":3,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/83677\/revisions"}],"predecessor-version":[{"id":83680,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/83677\/revisions\/83680"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=83677"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=83677"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=83677"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=83677"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}