Quantcast
Channel: CodeSection,代码区,SQL Server(mssql)数据库 技术分享 - CodeSec
Viewing all articles
Browse latest Browse all 3160

Increase PowerShell available commands in a SQL Server Agent Job step

$
0
0

By: Pablo Echeverria || Related Tips:More >SQL Server Agent

Problem

It is often required to perform advanced operations within a SQL Server Agent Job step, like interact with the operating system or import custom modules. For this, you’re able to create a PowerShell type step, but the problem is that the Powershell version varies when it runs inside a job step, so many people recommend ( link link link ) creating a .ps1 file and specify an “Operating system (CmdExec)” type step.

But what if you need to implement this job as a Multi-Server job? It will be a nightmare when you need to update the script in all your servers, keeping up to date the existing servers and copy this script to the new ones, not to mention that the path may not always be the same. So, what other option do you have?

Solution

Here’s the thing: when you run a “PowerShell” type step, it runs as SQLPS.exe which is a sub-set of PowerShell, so not all commands are available. Here is a comparison of the first commands available in each of them:

SQLPS.exe PowerShell.exe Add-Computer Add-Content Add-Content Add-History Add-History Add-Member Add-Member Add-PSSnapin Add-Type Checkpoint-Computer Clear-Content Clear-Content Clear-EventLog Clear-History Clear-Item Clear-Item Clear-ItemProperty Clear-ItemProperty Clear-Variable Clear-Variable Compare-Object Compare-Object Complete-Transaction Connect-WSMan ConvertFrom-Csv ConvertFrom-SecureString ConvertFrom-SecureString ConvertFrom-StringData Convert-Path Convert-Path ConvertTo-Csv

As you can see, there are a lot few commands in SQLPS.exe than when it runs from PowerShell.exe.

Let’s start by looking at a command to get the perf counters of the local machine, and what is the output in the different PowerShell options.

From PowerShell.exe:

PS C:\Users\PE> $result = Get-Counter | select -ExpandProperty CounterSamples
PS C:\Users\PE> $result[0]
Path InstanceName CookedValue
---- ------------ -----------
\\server01\network interface(... core 122376.167085421
PS C:\Users\PE>

From SQLPS.exe:

PS C:\Users\PE> $result = Get-Counter | select -ExpandProperty CounterSamples
The term 'Get-Counter' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:22
+ $result = Get-Counter <<<< | select -ExpandProperty CounterSamples
+ CategoryInfo : ObjectNotFound: (Get-Counter:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\Users\PE>

From a PowerShell type step:

A job step received an error at line 1 in a PowerShell script. The corresponding line is '$result = Get-Counter | select -ExpandProperty CounterSamples'. Correct the script and reschedule the job. The error information returned by PowerShell is: 'The term 'Get-Counter' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. '. Process Exit Code -1. The step failed.

But this doesn’t mean we can’t use all the available PowerShell commands and functions, because you can invoke PowerShell.exe passing the command to execute, just like you would do from a CmdExec type step. If we modify the script, we’re able to get the results.

Script:

$result = powershell.exe -command "Get-Counter | select -ExpandProperty CounterSamples"
$result[1]
$result[2]
$result[3]

Output:

Path InstanceName CookedValue
---- ------------ -----------
\\server01\network interface(... core 109935.744974759

As you may have already noticed, the result is an array of strings with the output from PowerShell.exe, so if you need the object with its properties and methods, you must think about serialize/deserialize .

However, if you can deal with this string output (as in my case), here are a few things you must consider:

Problem Solution Need to run multiple commands in a single line Separate the commands with semicolon [ ; ] Need to run multiple commands in multiple lines Declare a here-string as follows:
$var = @” … “@
Note that if you declare a variable, you need to escape the $ [ $var ] And if you need to use double quotes, you need to escape the “ [ \” ] Note that there are different escape sequences, and some may not work in every case, so it’s trial and error, but here are some links to help you with that: link link link . Need to pass a variable to the command being executed You just leave the variable without escaping the $:
Get-Counter -Counter @($availCounters) Where $availCounters in my case is a string variable, which holds valid perf counters in the form:
‘\\server01\counter1’, ‘\\server01\counter2’, etc. Output strings get trimmed Append the following commands at the end of your script: link
| Format-Table -Property * -AutoSize | Out-String -Width 100 Replace 100 with a size big enough to hold all your content. Output stri

Viewing all articles
Browse latest Browse all 3160

Trending Articles