{"id":3685,"date":"2013-05-06T00:01:00","date_gmt":"2013-05-06T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/05\/06\/10-tips-for-the-sql-server-powershell-scripter\/"},"modified":"2013-05-06T00:01:00","modified_gmt":"2013-05-06T00:01:00","slug":"10-tips-for-the-sql-server-powershell-scripter","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/10-tips-for-the-sql-server-powershell-scripter\/","title":{"rendered":"10 Tips for the SQL Server PowerShell Scripter"},"content":{"rendered":"<p><strong style=\"font-size: 12px\">Summary<\/strong><span style=\"font-size: 12px\">: Microsoft PowerShell MVP, Chad Miller shares his top ten tips for the SQL Server Windows PowerShell scripter.<\/span><\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Today&rsquo;s blog is a bit unique. I was throwing around ideas with Chad Miller, and somehow we came up with the idea that he would share some tips for the SQL Server Windows PowerShell scripter. You can read more about Chad and see his other blog posts on the <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/tags\/chad+miller\/\" target=\"_blank\">Hey, Scripting Guy! Blog site<\/a>.<\/p>\n<p>And now, Chad&hellip;<\/p>\n<h3>1. Use here-strings<\/h3>\n<p>Here-strings are great for working with strings that span multiple lines or contain characters you would normally need to escape, such as embedded quotes. Like regular strings, when using here-strings, you still get variables replaced by their values.<\/p>\n<p style=\"padding-left: 30px\">$group = &#8220;PRD&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: 12px\">#Don&#8217;t do this:<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: 12px\">$query = &#8220;SELECT DISTINCT&#8221;<\/span><\/p>\n<p style=\"padding-left: 30px\">$query +=&#8221;`n s.server_name&#8221;<\/p>\n<p style=\"padding-left: 30px\">$query += &#8220;`n FROM&nbsp;&nbsp;&nbsp; msdb.dbo.sysmanagement_shared_registered_servers s&#8221;<\/p>\n<p style=\"padding-left: 30px\">$query +=&#8221;`n JOIN msdb.dbo.sysmanagement_shared_server_groups g ON s.server_group_id = g.server_group_id&#8221;<\/p>\n<p style=\"padding-left: 30px\">$query += &#8220;`n WHERE&nbsp;&nbsp; g.name = &#8216;$group'&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">#Instead use a here-string:<\/p>\n<p style=\"padding-left: 30px\">$query = @&#8221;<\/p>\n<p style=\"padding-left: 30px\">SELECT DISTINCT<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s.server_name<\/p>\n<p style=\"padding-left: 30px\">FROM&nbsp;&nbsp;&nbsp; msdb.dbo.sysmanagement_shared_registered_servers s<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JOIN msdb.dbo.sysmanagement_shared_server_groups g ON s.server_group_id = g.server_group_id<\/p>\n<p style=\"padding-left: 30px\">WHERE &nbsp;&nbsp;g.name = &#8216;$group&#8217;<\/p>\n<p style=\"padding-left: 30px\">&#8220;@<\/p>\n<p>Not only is the here-string example more readable, but you can also copy and paste it right into SQL Server Management Studio. You test your queries before running them in Windows Powershell, right? for For more information about here-strings, see <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/hh847740.aspx\" target=\"_blank\">about_Quoting_Rules<\/a>.<\/p>\n<h3>2. Leverage Central Management Server<\/h3>\n<p>Some administrators may store their list of servers in text files or Active Directory organizational units, but you have a SQL Server Central Management Server (CMS). Use your CMS to pull lists of servers and SQL Server instances for input into Windows PowerShell scripts.<\/p>\n<p style=\"padding-left: 30px\">$serverInstances = sqlcmd -S myCMServerInstance -d msdb -Q $query -h -1 -W<\/p>\n<p style=\"padding-left: 30px\">$serverInstances | foreach {new-object Microsoft.SqlServer.Management.Smo.Server($($_.server_name)) } |<\/p>\n<p style=\"padding-left: 30px\">Select Name, PhysicalMemory, @{n=&#8217;MaxServerMemory&#8217;; e={$_.Configuration.MaxServerMemory.RunValue}}<\/p>\n<p>&nbsp;<\/p>\n<p style=\"padding-left: 30px\">#Get server names by removing instance name i.e. Z001\\SQL1 becomes Z001<\/p>\n<p style=\"padding-left: 30px\">$servers = sqlcmd -S myCMServerInstance -d msdb -Q $query -h -1 -W | foreach { $_ -replace &#8220;\\\\.*|,.*&#8221; }<\/p>\n<p style=\"padding-left: 30px\">invoke-command -ComputerName $servers -ScriptBlock {get-psdrive -PSProvider FileSystem}<\/p>\n<p>For more information, see <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb895144.aspx\" target=\"_blank\">Administer Multiple Servers Using Central Management Servers<\/a>.<\/p>\n<h3>3. Load SMO assemblies<\/h3>\n<p>SQL Server Management Objects (SMO) is the API you&#8217;ll use to script against SQL Server. To use SMO, you must first load the SMO assemblies. If you have SQL Server&nbsp;2012, all you need to do to load assemblies is call <strong>Import-Module sqlps<\/strong>. This will load the SMO assemblies with the sqlps module. If you&#8217;re not using 2012 or would prefer to load the assemblies without the sqlps module, you&#8217;ll need to use <strong>Add-Type<\/strong> with the fully qualified name:<\/p>\n<p style=\"padding-left: 30px\">#For SQL Server 2008 R2 and&nbsp;SQL Server 2008<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.ConnectionInfo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.Smo, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.SMOExtended, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.SqlEnum, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.Management.Sdk.Sfc, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">#For SQL Server 2012<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.ConnectionInfo, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.Smo, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.SMOExtended, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.SqlEnum, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">add-type -AssemblyName &#8220;Microsoft.SqlServer.Management.Sdk.Sfc, Version=11.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91&#8221; -ErrorAction Stop<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">#See loaded SMO assemblies<\/p>\n<p style=\"padding-left: 30px\">[appdomain]::CurrentDomain.GetAssemblies() | where {$_.FullName -like &#8220;*sqlserver*&#8221;}<\/p>\n<p>Like SQL Server Management Studio, SMO is backwards compatible so you can script against 2000 and 2005 SQL Server using either the 2008 or 2012 version of SMO.<\/p>\n<h3>4. Exercise Invoke-Sqlcmd with caution<\/h3>\n<p>One of the cmdlets that is included with SQL Server&nbsp;2012, SQL Server&nbsp;2008&nbsp;R2, and SQL Server&nbsp;2008 is <strong>Invoke-Sqlcmd<\/strong>. As the name implies, the cmdlet tries to be a Windows PowerShell version of the venerable sqlcmd utility introduced in SQL Server 2005 and enhanced with each SQL Server release. The <strong>Invoke-Sqlcmd<\/strong> cmdlet has <a href=\"https:\/\/connect.microsoft.com\/SQLServer\/SearchResults.aspx?SearchQuery=invoke-sqlcmd\" target=\"_blank\">several bugs and workarounds that you should be aware of<\/a>.<\/p>\n<p>One issue is with the <strong>QueryTimeout<\/strong> setting. At the time of this writing, the documentation incorrectly states the following about <strong>QueryTimeout<\/strong> parameter:<\/p>\n<p style=\"padding-left: 30px\">help Invoke-Sqlcmd -Parameter QueryTimeout<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">QueryTimeout<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; Specifies the number of seconds before the queries time out. If a timeout value is not specified, the queries do not time out. The timeout must be an integer between 1 and 65535.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; Required?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; Position?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; named<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; Default value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; Accept pipeline input?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; Accept wildcard characters?&nbsp; false<\/p>\n<p>This isn&#8217;t true, which can be easily proven by running this simple test:<\/p>\n<p style=\"padding-left: 30px\">invoke-sqlcmd &#8220;waitfor delay &#8217;00:00:31&#8242;&#8221; -Database master -ServerInstance $env:computername<\/p>\n<p style=\"padding-left: 30px\">Invoke-Sqlcmd : Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.<\/p>\n<p>So, you&#8217;ll need to specify a query timeout. In SQL Server&nbsp;2012, the bug was partially fixed and you can specify 0, which means no<strong> QueryTimeout<\/strong>:<\/p>\n<p style=\"padding-left: 30px\">invoke-sqlcmd &#8220;waitfor delay &#8217;00:00:31&#8242;&#8221; -Database master -ServerInstance $env:computername\\sql1 -querytimeout 0<\/p>\n<p>When you use the SQL Server&nbsp;2008&nbsp;R2 or SQL Server&nbsp;2008 versions of <strong>Invoke-Sqlcmd<\/strong>, specifying 0 doesn&#8217;t work. Instead, you&#8217;ll need to provide a value greater than 1. Here&#8217;s a trick that works:<\/p>\n<p style=\"padding-left: 30px\">invoke-sqlcmd &#8220;waitfor delay &#8217;00:00:31&#8242;&#8221; -Database master -ServerInstance $env:computername\\sql1 -querytimeout ([int]::MaxValue)<\/p>\n<p>One other issue that isn&#8217;t a bug, but something to be aware of&hellip;<\/p>\n<p>If you&#8217;re querying data with columns larger than 4,000 characters for XML or char data types, or 1,024 bytes for binary data types, you&#8217;ll want to override the default settings for <strong>MaxCharLength<\/strong> or <strong>MaxBinaryLength<\/strong> parameters:<\/p>\n<p style=\"padding-left: 30px\">#By default character data larger than 4,000 is truncated<\/p>\n<p style=\"padding-left: 30px\">invoke-sqlcmd &#8220;select REPLICATE(&#8216;x&#8217;, 4001)&#8221; -Database master -ServerInstance $env:computername\\sql1 | foreach {($_.Column1).length}<\/p>\n<p style=\"padding-left: 30px\">4000<\/p>\n<p style=\"padding-left: 30px\">#This is fixed by specifying a value for the maxcharlength parameter<\/p>\n<p style=\"padding-left: 30px\">invoke-sqlcmd &#8220;select REPLICATE(&#8216;x&#8217;, 4001)&#8221; -Database master -ServerInstance $env:computername\\sql1&nbsp; -maxcharlength ([int]::MaxValue) | foreach {($_.Column1).length}<\/p>\n<p style=\"padding-left: 30px\">4001<\/p>\n<p>&nbsp;<\/p>\n<p style=\"padding-left: 30px\">#See help for more information on max length parameters<\/p>\n<p style=\"padding-left: 30px\">help invoke-sqlcmd -Parameter max*<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">-MaxCharLength<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Specifies the maximum number of characters returned for columns with character or Unicode data types, such as<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; char, nchar, varchar, and nvarchar. The default is 4,000 characters.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Required?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Position?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; named<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Default value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Accept pipeline input?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Accept wildcard characters?&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">-MaxBinaryLength<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Specifies the maximum number of bytes returned for columns with binary string data types, such as binary and<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; varbinary. The default is 1,024 bytes.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Required?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Position?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; named<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Default value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp; &nbsp;Accept pipeline input?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Accept wildcard characters?&nbsp; false<\/p>\n<p>One serious issue with <strong>Invoke-Sqlcmd<\/strong> is around error handling. As an example, the following command does not produce an error in <strong>Invoke-Sqlcmd<\/strong> at the time of this writing:<\/p>\n<p style=\"padding-left: 30px\">invoke-sqlcmd -ServerInstance $env:computername\\sql1 -Database tempdb -Query &#8220;select 1\/0&#8221; -OutputSqlErrors $true -AbortOnError -SeverityLevel 0 -ErrorLevel 0<\/p>\n<p style=\"padding-left: 30px\">Sqlcmd.exe and SQL Server Management Studio return an error:<\/p>\n<p style=\"padding-left: 30px\">sqlcmd.exe -S &#8220;%COMPUTERNAME%&#8221; -d tempdb -Q &#8220;select 1\/0&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">Msg 8134, Level 16, State 1, Server YourServer, Line 1 Divide by zero error encountered.<\/p>\n<p>Unfortunately, there aren&#8217;t any good workarounds for the error handling issue other than don&#8217;t use <strong>Invoke-Sqlcmd<\/strong> if you need error handling. There are other issues with <strong>Invoke-Sqlcmd<\/strong>, which the command-line utility, sqlcmd.exe, doesn&#8217;t have.<\/p>\n<p>In any case it&#8217;s trivial to write your own <strong>Invoke-Sqlcmd<\/strong> replacement. For more information, see <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/7985b7ef-ed89-4dfd-b02a-433cc4e30894\">Invoke-Sqlcmd2<\/a> in the Script Center Repository.<\/p>\n<p>You may want to continue to use sqlcmd.exe for scripted data loading.<\/p>\n<h3>5. Don&#8217;t forget SQL Server command-line utilities<\/h3>\n<p>One of tenets of Windows PowerShell is to not needlessly write scripts. What I mean by this is instead of writing a script to perform an action, first see if there&#8217;s a cmdlet that accomplishes the task. Think of a cmdlet as a script that you don&#8217;t have to write.<\/p>\n<p>And if there isn&#8217;t a cmdlet available? Here&#8217;s where Windows PowerShell (being a shell) comes in handy. You can still use the native Windows console applications. You might even find that if there is Windows PowerShell cmdlet, the console application simply works better. At the top of my list of SQL Server command-line utilities that are still very useful: <strong>sqlcmd<\/strong>, <strong>dtutil<\/strong>, and <strong>dtexec<\/strong>, and Red Gate <strong>sqlcompare<\/strong>.<\/p>\n<h3>6. Read the SMO documentation<\/h3>\n<p>If you&#8217;re going to write scripts that use SMO, you&#8217;ll probably want to spend some time looking at the SMO documentation. Rather than hunt through the documentation, I find it easier to search the web for the SMO documentation on a particular class. Add the term &#8220;SMO class&#8221; to your web search, for example, &#8220;smo server class.&#8221; The first item in your search results will usually be the MSDN documentation.<\/p>\n<h3>7. Don&#8217;t use Windows PowerShell for everything<\/h3>\n<p>If you know T-SQL or SQL Server Reporting Services, the solutions you build can leverage the best tool for the job. What&#8217;s really cool is using Windows PowerShell as only one part of the solution. One of my favorite patterns is to use Windows PowerShell to collect information, load the data into a SQL Server table, and then present the data as a web-based report in SQL Server Reporting Services.<\/p>\n<p>Check out my previous post, <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2010\/11\/01\/use-powershell-to-collect-server-data-and-write-to-sql.aspx\" target=\"_blank\">Use PowerShell to Collect Server Data and Write to SQL<\/a> for more information. Let&#8217;s face it, sometimes using Windows PowerShell is more complex than what&#8217;s needed. Do you need to interactively run query across multiple SQL Servers? It doesn&#8217;t get much simpler than multiserver queries in SQL Server Management Studio.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5367.hsg-5-6-13-1.jpg\"><img decoding=\"async\" title=\"Image of menu\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5367.hsg-5-6-13-1.jpg\" alt=\"Image of menu\" \/><\/a><\/p>\n<h3>8. Load data with Out-GridView<\/h3>\n<p>Although you could mess with scripts to export data directly into Excel or convert CSV files, a quick and dirty way to get data into Excel is to simply copy and paste from <strong>Out-GridView<\/strong>. This also works on small tables you open in SQL Server Management Studio Object Explorer: right-click <strong>Table<\/strong> and select <strong>Edit Top 200 Rows<\/strong>.<\/p>\n<p>You&#8217;ll then be able to paste <strong>Out-GridView<\/strong> output rows into a SQL Server table. This is especially useful when you need to run a Windows PowerShell command one-time and insert the data into Excel. Here&#8217;s an example script called <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Get-SqlSpn-17d5c0d7\" target=\"_blank\">Get-SqlSpn<\/a>, which grabs all the SPNs in a domain related to SQL Server. I&#8217;ll then use <strong>Out-GridView<\/strong> with CTRL+A and CTRL+C to copy, and then CTRL+V to paste into Excel.<\/p>\n<p style=\"padding-left: 30px\">&nbsp;. .\/get-sqlspn.ps1<\/p>\n<p style=\"padding-left: 30px\">&nbsp;$spns = Get-SqlSpn<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">#4. Get Column Headers<\/p>\n<p style=\"padding-left: 30px\">$object = $spns | select -first 1<\/p>\n<p style=\"padding-left: 30px\">$ht = @{}<\/p>\n<p style=\"padding-left: 30px\">foreach($property in $object.PsObject.get_properties()) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp; $ht.add($property.Name.ToString(),$property.Name.ToString())<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">new-object psobject -Property $ht | out-gridview<\/p>\n<p style=\"padding-left: 30px\">#Copy\/Paste heading row to Excel (Ctrl-A, Ctrl-C)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">$spns | out-gridview<\/p>\n<p style=\"padding-left: 30px\">#Copy\/Paste spns to Excel (Ctrl-A, Ctrl-C)<\/p>\n<p>This image shows an example of where I copy from:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8284.hsg-5-6-13-2.jpg\"><img decoding=\"async\" title=\"Image of menu\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8284.hsg-5-6-13-2.jpg\" alt=\"Image of menu\" width=\"400\" height=\"132\" \/><\/a><\/p>\n<p>And here is my paste into Excel:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4555.hsg-5-6-13-3.jpg\"><img decoding=\"async\" title=\"Image of menu\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4555.hsg-5-6-13-3.jpg\" alt=\"Image of menu\" \/><\/a><\/p>\n<h3>9. Adjust SMO StatementTimeout<\/h3>\n<p>The default statement time setting for SMO is 10 minutes. Of course, some operations (such as a backup or restore) can take longer than the default timeout of 600 seconds (10 minutes). Set the <strong>StatementTimeout<\/strong> setting to no timeout by specifying 0:<\/p>\n<p style=\"padding-left: 30px\">$server = new-object (&#8220;Microsoft.SqlServer.Management.Smo.Server&#8221;) &#8220;Z001\\SQL&#8221;<\/p>\n<p style=\"padding-left: 30px\">$server.ConnectionContext.StatementTimeout = 0<\/p>\n<h3>10. Handle Windows Powershell errors in SQL Server Agent jobs<\/h3>\n<p>By default the <strong>ErrorActionPreference<\/strong> is set to Continue, and this has implications on how errors bubble up to the SQL Server Job Server. If you run a Windows PowerShell command as a SQL Server Agent job and there are no syntax errors yet, the command produces an error (for example, attempting to get operating system information from an unavailable server). The SQL Server Agent job will report success. If you want an error condition to halt execution of a SQL Server Agent job or to produce an error, you&#8217;ll need to add some error handling. You can set up a SQL Server Agent job with Windows PowerShell Job Step as follows:<\/p>\n<p style=\"padding-left: 30px\">get-wmiobject Win32_OperatingSystem -ComputerName &#8216;nothere&#8217;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3441.hsg-5-6-13-4.jpg\"><img decoding=\"async\" title=\"Image of menu\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3441.hsg-5-6-13-4.jpg\" alt=\"Image of menu\" \/><\/a><\/p>\n<p>The job will run successfully, but if you run it directly in Windows PowerShell, you&#8217;ll see:<\/p>\n<p style=\"padding-left: 30px\">get-wmiobject Win32_OperatingSystem -ComputerName &#8216;nothere&#8217;<\/p>\n<p style=\"padding-left: 30px\">get-wmiobject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)<\/p>\n<p style=\"padding-left: 30px\">At line:1 char:1<\/p>\n<p style=\"padding-left: 30px\">+ get-wmiobject Win32_OperatingSystem -ComputerName &#8216;nothere&#8217;<\/p>\n<p>To bubble up Windows PowerShell errors to SQL Server Agent, you&#8217;ll need to do one of the following:<\/p>\n<p><strong>A. Set your $ErrorActionPreference = &#8220;Stop&#8221;<\/strong><\/p>\n<p style=\"padding-left: 30px\">$erroractionpreference = &#8220;Stop&#8221;<\/p>\n<p style=\"padding-left: 30px\">get-wmiobject Win32_OperatingSystem -ComputerName &#8216;nothere&#8217;<\/p>\n<p><strong>B. Set ErrorAction at the cmdlet-level (more granular)<\/strong><\/p>\n<p style=\"padding-left: 30px\">get-wmiobject Win32_OperatingSystem -ComputerName &#8216;nothere&#8217;&nbsp; -ErrorAction &#8216;Stop&#8217;<\/p>\n<p><strong>C. Use Try\/Catch with ErrorActionPreference or ErrorAction <\/strong><\/p>\n<p style=\"padding-left: 30px\">try {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; get-wmiobject Win32_OperatingSystem -ComputerName &#8216;nothere&#8217; -ErrorAction &#8216;Stop&#8217;<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">catch {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; throw &#8220;Something went wrong&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; #or rethrow error<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; #throw $_<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; #or throw an error no message<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; #throw<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p><strong>D. Continue, and fail the SQL Server Agent job<\/strong><\/p>\n<p>Let&#8217;s say you have a collection of computers and you want to continue on the error, but you also want to fail the job. In this case you can make use of the <strong>ErrorVariable<\/strong>:<\/p>\n<p style=\"padding-left: 30px\">#Note the -ErrorVariable parameter takes a variable name without the $ prefix.<\/p>\n<p style=\"padding-left: 30px\">get-wmiobject Win32_OperatingSystem -ComputerName &#8216;localhost&#8217;,&#8217;nothere&#8217;,&#8217;Win7boot&#8217; -ErrorVariable myError<\/p>\n<p style=\"padding-left: 30px\">if ($myError)<\/p>\n<p style=\"padding-left: 30px\">{ throw (&#8220;$myError&#8221;) }<\/p>\n<p>~Chad<\/p>\n<p>Thank you, Chad, for some extremely practical information. Well done! Join me tomorrow for the exciting conclusion to our SQL Server Week as we have a guest blog written by SQL Server MVP, Kendal Van ***.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft PowerShell MVP, Chad Miller shares his top ten tips for the SQL Server Windows PowerShell scripter. Microsoft Scripting Guy, Ed Wilson, is here. Today&rsquo;s blog is a bit unique. I was throwing around ideas with Chad Miller, and somehow we came up with the idea that he would share some tips for the [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[195,146,56,3,176,45],"class_list":["post-3685","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-chad-miller","tag-databases","tag-guest-blogger","tag-scripting-guy","tag-sql-server","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft PowerShell MVP, Chad Miller shares his top ten tips for the SQL Server Windows PowerShell scripter. Microsoft Scripting Guy, Ed Wilson, is here. Today&rsquo;s blog is a bit unique. I was throwing around ideas with Chad Miller, and somehow we came up with the idea that he would share some tips for the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3685","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=3685"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3685\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=3685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=3685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=3685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}