PowerShell SQL Server Cannot Find Path - sql-server

I have 2x mini scripts which are fairly similar.
The first backs up our SQL Jobs and runs fine:
Import-Module "SQLPS" Get-ChildItem -Path SQLSERVER:\SQL\MYSERVERNAME\Default\JobServer\Jobs\ | %{$_.script()} | out-file -Filepath "MYFILEPATH_$(get-date -f yyyyMMdd).sql"
The second is meant to back up our SQL Stored Procedures, and does not produce results in the output file:
Import-Module "SQLPS" Get-ChildItem -Path SQLSERVER:\SQL\MYSERVERNAME\Default\Databases\MYDBNAME\StoredProcedures\ | %{$_.script()} | out-file -Filepath "MYFILEPATH_$(get-date -f yyyyMMdd).sql"
This problematic second script gives the below error:
Get-ChildItem : Cannot find path 'SQLSERVER:\SQL\MYSERVERNAME\Default\Databases\MYDBNAME\StoredProcedures\' because it does not exist.
It used to run successfully until around the time I upgraded to Windows10. Any suggestions on how to correct this second script?

Related

Can't run a Powershell command in a SQL Server Agent Job Step

I tried with "Powershell" option and commands (both don't work):
Get-Item "*.csv" | Out-File "d:\tracking\$(get-date -f yyyyMMdd-hhmmss).txt"
"Get-Item """*.csv""" | Out-File """d:\tracking\$(get-date -f yyyyMMdd-hhmmss).txt""""
And tried with "CmdExec" option and command (it doesn't work):
powershell.exe -Command "Get-Item """*.csv""" | Out-File """d:\tracking\$(get-date -f yyyyMMdd-hhmmss).txt""""
But the last command runs ok on a separate cmd.exe window
and the following also runs ok inside the powershell:
Get-Item "*.csv" | Out-File "d:\tracking\$(get-date -f yyyyMMdd-hhmmss).txt"
They create a text file eg. "20220607-112233.txt" containing the directory listing of CSV files
However I can't get this command to work from within the Job Step
The step finishes with "Unable to run. Syntax error"
Ok, I found a solution:
I created a batch (.bat file) with the code inside block 2:
powershell.exe -Command "Get-Item """*.csv""" | Out-File """d:\tracking\$(get-date -f yyyyMMdd-HHmmss).txt""""
(I only changed the hh for HH, for 24 hours based time)
Then, I configured the Job Step to run the bat file (setting the option "cmdExec")
That's all
I don't know what was going on, directory permissions were ok, the command of code block #2 above even works if I execute it with xp_cmdshell

SSIS Powershell

I'm trying to run the following Poweshell command via SSIS using the following argument..
(get-content z:\2.html) | foreach-object {$_ -replace "><", ">`r`nE<"} | set-content z:\2.html
This works in Powershell at the command line, but I cannot get this to work in SSIS.
I get the error
at "", The process exit code was "1" while the expected was "0".
In SSIS I have :
1. Created an "Execute process Task"
2. Pointed the Executable to system32\WIndowsPowershell .. etc
3. Added the argument as detailed above using a variable as the filename
Any ideas?
Seems like the syntax should have been....
(get-content z:\3.html) | foreach-object {$_ -replace '><', '>`r`nE<'} | set-content z:\3.html
it works now!

PowerShell SQL scripting USPs and Users

I have put together the below PowerShell script which scripts out all the USPs on a server.
Is there an option to split the output into individual files (instead of saving as one whole/large file)?
Get-ChildItem -Path SQLSERVER:\SQL\myserver\Default\Databases\mydb\StoredProcedures\ | %{$_.script() | out-file -Filepath "myfilelocation.sql"}
Try the following; it should append the procedure name to the file.
Get-ChildItem -Path SQLSERVER:\SQL\myserver\Default\Databases\mydb\StoredProcedures\ |
%{
#Deal with invalid chars in Procedure name i.e. [Customers\Remove]
$SProc = "$($_.name -replace '\\', '_')"
# $Sproc | Out-Host # Uncomment this to check the procedure names...
$_.script() |
out-file -Filepath "myfilelocation_$SProc.sql"
}
This should make the file name unique per database and not have the file over-written each time. That is what is currently happening with your script.

Powershell from SQL Server Agent Job doesn't recognize ConvertTo-CSV

UPDATE: Modified the script to work within the bounds of PS1 as required by SQLPS.
Changed:
IF($property.Value -match $regex){
$currentBadLine = (ConvertTo-Csv $_ -NoTypeInformation -Delimiter $delimiter);
$badLines += $currentBadLine[1,2]
};
To:
IF($property.Value -match $regex){
$badLines += $_ | Select-Object | ft -autoSize;
};
Prints a new header for each bad line, but it's not the end of the world and not worth the effort to prevent.
I have a Powershell script that pre-processes CSV files before they have a chance to screw up my data imports.
On two servers in a row now I have confirmed that the PS Major Version at least 2, and that the following code snippet runs fine in Powershell ISE. The purpose of the code is to read in each line of the CSV, and then loop through the columns looking for the regex pattern in the $regex variable. When it finds one I want it to keep track of the error before fixing it so I can write an error log later before outputting a cleaned up file ready for import.
%{
Foreach($Property in $_.PSObject.Properties){
IF($property.Value -match $regex){
$currentBadLine = (ConvertTo-Csv $_ -NoTypeInformation -Delimiter $delimiter);
$badLines += $currentBadLine[1,2]
};
$property.Value = $property.Value -replace $regex;
}
$_
}
But once I put that code into an agent job the agent complains:
'The term 'ConvertTo-Csv' 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. '
The question then is this: Is the Agents Powershell subsystem using a different version of Powershell than the rest of the system? If so, how do I find out which version the Subsystem is using and if possible upgrade it so I can fix this.
The server is running:
Windows Server 2008 R2 Enterprise
PS Major version 2, Minor 0 Build -1 revision -1
SQL Server 2008 R2 SP1 10.5.2500.0 64 bit
Thanks!
Yes, proper PowerShell support isn't really implemented until SQL Server 2012 (an even that is a bit flakey as to what cmdlets it supports)
In 2008 and R2 the agent's powershell implementation is actually a minishell, created by the now (thankfully) deprecated make-shell.exe utility, which only allows v1 cmdlets to run, and disallows the use of Add-PSSnapin so you can't add anymore cmdlets.
To get proper powershell support, you either need to shell out and call an external script, or run the job as a windows scheduled task rather than an agent job.
The following article explains a lot about why powershell support in 2008 R2 doesn't work like you think it should:
The Truth about SQLPS and PowerShell V2
One work-around: Export-CSV to a file, then Get-Content from the file.
$rows = ,(New-Object PSObject -prop #{a=7; b='stuff';});
$rows +=,(New-Object PSObject -prop #{a=77; b='more';});
#To run from SQL Job, change from this:
$csvrows = $rows | ConvertTo-CSV -NoType | % {$_.Replace('"','')};
write-output $csvrows;
#to this:
$rows | Export-CSV -NoType "C:\Temp\T.csv"
$csvrows = (Get-Content "C:\Temp\T.csv") | % {$_.Replace('"','')};
write-output $csvrows;

Powershell Script using Invoke-SQL command,needed for SQL job, the SQL Server version of Powershell is somewhat crippled, is there a workaround?

Full Question: Have Powershell Script using Invoke SQL command, using snappins, I need them to be included in a SQL job, the SQL Server version of Powershell is somewhat crippled, does anyone know a workaround?
From what I have gathered, SQL Management Studio's version of powershell is underpowered, not allowing for the use of snappins, as such it does not recognize the cmdlets that I used in the script. I have tried running it in the job as a command line prompt rather than a Powershell script, which causes the code to work somewhat, however I check the history on the job and it says that invoke-sql is still not a recognized cmdlet. I speculate that because I am running the code on a remote server, with different credentials than my standard my profile with the snappins preloaded isn't being loaded, though this is somewhat doubtful.
Also, as I am a powershell rookie, any advice on better coding practices/streamlining my code would be much appreciated!
Code is as follows:
# define parameters
param
(
$file = "\\server\folder\file.ps1"
)
"invoke-sqlcmd -query """ | out-file "\\server\folder\file.ps1"
# retrieve set of table objects
$path = invoke-sqlcmd -query "select TableName from table WITH (NoLock)" -database db -server server
[reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
$so = New-Object Microsoft.SqlServer.Management.Smo.ScriptingOptions
$so.DriPrimaryKey = $false
$so.Nocollation = $true
$so.IncludeIfNotExists = $true
$so.NoIdentities = $true
$so.AnsiPadding = $false
# script each table
foreach ($table in $path)
{
#$holder = $table
$table = get-item sqlserver:\sql\server\default\databases\database\tables\dbo.$($table.TableName)
$table.script($so) | out-file -append $file
}
(get-content "\\server\folder\file.ps1") -notmatch "ANSI_NULLS" | out-file "\\server\folder\file.ps1"
(get-content "\\server\folder\file.ps1") -notmatch " AS "| out-file "\\server\folder\file.ps1"
(get-content "\\server\folder\file.ps1") -notmatch "Quoted_" | out-file "\\server\folder\file.ps1"
(get-content "\\server\folder\file.ps1") -replace "\) ON \[PRIMARY\].*", ")" | out-file "\\server\folder\file.ps1"
(get-content "\\server\folder\file.ps1") -replace "\[text\]", "[nvarchar](max)" | out-file "\\server\folder\file.ps1"
(get-content "\\server\folder\file.ps1") -replace " SPARSE ", "" | out-file "\\server\folder\file.ps1"
(get-content "\\server\folder\file.ps1") -replace "COLUMN_SET FOR ALL_SPARSE_COLUMNS", "" | out-file "\\server\folder\file.ps1"
""" -database database -server server" | out-file "\\server\folder\file.ps1" -append
So I figured out the answer to my own question. Using this site: http://www.mssqltips.com/tip.asp?tip=1684 and
http://www.mssqltips.com/tip.asp?tip=1199
I figured out that he was able to do so using a SQL Server Agent Proxy, so I followed the yellow brick road, and basically I set up a proxy to my account and was able to use the external powershell through a feature. A note, you need to create a credential under the securities tab in object explorer prior to being able to select one when creating the proxy. Basically I ended up creating a proxy named powershell, using the powershell subsystem, and use my login info to create a credential. VOILA!
You have to add the snapins each time. In your editor you likely already have them loaded from another script/tab/session. In SQL Server you will need to add something like this to the beginning of the script:
IF ( (Get-PSSnapin -Name sqlserverprovidersnapin100 -ErrorAction SilentlyContinue) -eq $null )
{
Add-PsSnapin sqlserverprovidersnapin100
}
IF ( (Get-PSSnapin -Name sqlservercmdletsnapin100 -ErrorAction SilentlyContinue) -eq $null )
{
Add-PsSnapin sqlservercmdletsnapin100
}
I'm not sure the error you are trying to workaround - can you post that?
Have you tried this from a PowerShell prompt?
Add-PSSnapin SqlServerCmdletSnapin100

Resources