Powershell SQLCMD Mode error - sql-server

I am trying to run PowerShell Invoke-Sqlcmd but I get an error:
Invoke-Sqlcmd -MaxCharLength 100000 -ServerInstance server1\darabse -InputFile \\server\query.sql
Invoke-Sqlcmd :
At line:6 char:1
+ Invoke-Sqlcmd -MaxCharLength 1000000 -ServerInstance server\database ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ParserError: (:) [Invoke-Sqlcmd], ParserException
+ FullyQualifiedErrorId : ExecutionFailureException,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
I can run in in Management studio with SQLCMD Mode.
I have tried everything form here . Any ideas? There is no "$" within it.
I succeed to do i like this, but I am not sure this is solution?
sqlcmd -i \\server\Shared\install\file.sql
Thanks

it works like this:
cmd.exe /C sqlcmd -i \\share\Shared\install_scripts\02SQL\create.sql

Related

Getting a Cannot convert 'System.Object[]' to the type 'System.Management.Automation.ScriptBlock' calling powershell script from SQL Server

I am running this command/Script:
Exec xp_cmdshell 'powershell.exe Invoke-Command -ComputerName server01.client.local -ScriptBlock
{Get-Process myguiapp -IncludeUserName ^| Format-Table #{Expression={$_.username}}, #{Expression=
{$_.path}}, #{Expression={(((Get-Date) - $_.StartTime).ToString().Substring(0,8))}}}, #{Expression=
{$_.FileVersion.tostring()}}'
When I run it in powershell, it works fine, but when I run it in SSMS, I get this error:
Invoke-Command : Cannot convert 'System.Object[]' to the type
'System.Management.Automation.ScriptBlock' required by
parameter 'ScriptBlock'. Specified method is not supported.
At line:1 char:67
+ ... ScriptBlock {Get-Process myguiapp -IncludeUserName | Format-Table #{E ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId :
CannotConvertArgument,Microsoft.PowerShell.Commands.InvokeCommandCommand
And when I run it in SSMS without the last parameter (for FileVersion), it works fine:
Exec xp_cmdshell 'powershell.exe Invoke-Command -ComputerName zmcrds01.zmclient.local -ScriptBlock
{Get-Process zmfs.gui -IncludeUserName ^| Format-Table #{Expression={$_.username}}, #{Expression=
{$_.path}}, #{Expression={(((Get-Date) - $_.StartTime).ToString().Substring(0,8))}}}'
I'm running on SQL Server 2014 with Powershell 5.1
How can I fix this?

Outputting large XML file from SQL with Powershell

I have a Powershell script that calls a stored procedure in SQL server and outputs the resulting XML directly to a file. It works for a smaller test file but falls down with the full size (~1.5gb file).
The stored procedure works fine. I can call it within SQL server - the problem is that I have to open it in the SQL server then manually save it to a file, then edit that file to remove newlines. When I run the script it falls down when it tries to delete the intermediary files at the end. However, when I run it line by line it falls down at the invoke-sql line.
#net use S: "\\processStore\projects"
# Create variables
$SQLquery = "DECLARE #return_value int; EXEC #return_value = [XML].[XMLdata];"
$outpath = "D:\MyDocuments\XML\XML files"
$outfile = "TestOutput"
# Run the SQL command and store the object to a variable. Need to extend the timeout from the default.
$sql = invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinstance 'statdata' -QueryTimeout 100000
cd C:
# Store the SQL output as an interim text file
$sql.{XML_F52E2B61-18A1-11d1-B105-00805F49916B} | out-file -Filepath "$outpath\$outfile.txt"
# Remove Linebreaks
(Get-Content "$outpath\$outfile.txt" -Raw).Replace("`r`n","") | Set-Content "$outpath\${outfile}_del.xml" -Force
format-xml "$outpath\${outfile}_del.xml" | Set-Content "$outpath\$outfile.xml" -Force
# Delete interim text files
del "$outpath\$outfile.txt"
del "$outpath\${outfile}_del.xml"
When running lines one by one the code falls down at the invoke-sqlcmd line with the error:
invoke-sqlcmd : A transport-level error has occurred when receiving results from the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote
host.)
At line:1 char:8
+ $sql = invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinst ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Invoke-Sqlcmd], SqlPowerShellSqlExecutionException
+ FullyQualifiedErrorId : SqlError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
Change from
invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinstance 'statdata' -QueryTimeout 100000
to
invoke-sqlcmd -Database 'APP2021' -Query $SQLquery -serverinstance 'statdata' -QueryTimeout 0
Setting QueryTimeout = 0 will prevent the query from timing out

Powershell Applying SQL Patches Multiple Servers

I need to apply SQL Server Patches in more than 300 Servers, so, I've created code below and saved it as Apply_SQL_Patch.ps1.
I'm reading a txt file with all servers names and I'd like to connect to them, extract and apply Patch.
The issue is when I execute it, it connect to server, but it's not changing directory to D:\Software\Patch, resulting in an error on next lines:
$output = foreach ($cluster in GC "D:\Software\Patch\Servers_List.txt")
{
Enter-PSSession -ComputerName $cluster
cd D:\Software\Patch\
.\SQLServer2014-KB4037356-x64.exe /X:D:\Software\Patch
.\setup.exe /action=patch /instancename=SQL2014 /quiet /IAcceptSQLServerLicenseTerms
}
$output | Out-File -Append D:\Software\Patch\Patch_Result.txt
Error below:
.\SQLServer2014-KB4037356-x64.exe : The term
'.\SQLServer2014-KB4037356-x64.exe' 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 D:\software\patch\Apply_SQL_Patch.ps1:5
char:2
+ .\SQLServer2014-KB4037356-x64.exe /X:D:\Software\Patch
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (.\SQLServer2014-KB4037356-x64.exe:String) [],
CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
.\setup.exe : The term '.\setup.exe' 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 D:\software\patch\Apply_SQL_Patch.ps1:7
char:2
+ .\setup.exe /action=patch /instancename=SQL2014 /quiet /IAcceptSQLServerLicense ...
+ ~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (.\setup.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Thanks for your help!
Enter-PSSession -ComputerName $cluster
cd D:\Software\Patch\
.\SQLServer2014-KB4037356-x64.exe /X:D:\Software\Patch
.\setup.exe /action=patch /instancename=SQL2014 /quiet /IAcceptSQLServerLicenseTerms
I don't think this is going to work like you think. You're creating a session and then executing three commands locally.
Try:
Invoke-Command -ComputerName $cluster -ScriptBlock {
cd D:\Software\Patch\
Start-Process -PSPath '.\SQLServer2014-KB4037356-x64.exe' -ArgumentList '/X:D:\Software\Patch' -Wait
.\setup.exe /action=patch /instancename=SQL2014 /quiet /IAcceptSQLServerLicenseTerms
}
I've replaced the patch extraction command with the one above because the command returns control to PowerShell immediately. You may need to do the same thing with setup.exe. I don't have an SQL 2014 instance to test on.

Powershell Value of argument path is NULL

I've developed a PS1 file which will be responsible to apply SQL Server Patches, based on a Server List. So, it'll read a text file with all servers I need to patch and apply Patch.
I've decided using PARAM for "Source Folder" ( where I'll get Server List and record output ); "Destination Folder" ( where I'll be able to run patch ), "File" ( name of patch ), "Instance" ( SQL Server Instance which I'll be running Patch update ).
When I start to run commands below, it's able to read Servers List ( so, 1st PARAM is ok ), but, it returns the error below aborting process.
What is missing or what am I doing wrong on code below?
PS.: I also would like to use Try...Catch to record a message on the output file. Did I write it correctly?
Thanks in advance!
[CmdletBinding()]
Param (
[Parameter(Mandatory=$True,Position=0)]
[string]$foldersource,
[Parameter(Position=1)]
[string]$folderdest,
[Parameter(Position=2)]
[string]$file,
[Parameter(Position=3)]
[string]$instance
)
foreach ($cluster in GC "$foldersource\Servers_List.txt")
{
$output = "Server: $cluster Patch Installation on: $(Get-Date -format 'u')"
try{
Invoke-Command -ComputerName $cluster -ScriptBlock
{
cd $folderdest
.\$file /X:$folderdest
Start-Sleep -s 10
.\SETUP.exe /action=patch /instancename=$instance /quiet /IAcceptSQLServerLicenseTerms
}
-ErrorAction Stop;
$output += " SUCCESS"
}
catch
{
$output += "Failed - $($_.exception.message)"
}
$output | Out-File -Append $foldersource\Patch_Result_Non_SP.txt
}
How I'm running command above: .\SQL_Server_install_non-Service_Pack_V2.ps1 "D:\Software\Patch" "D:\Software" "SQLServer2008R2-KB3045316-x64.exe" "MSSQLSERVER"
ERROR:
Cannot process argument because the value of argument "path" is null. Change the value of argument "path" to a non-null value.
+ CategoryInfo : InvalidArgument: (:) [Set-Location], PSArgumentNullException
+ FullyQualifiedErrorId : ArgumentNull,Microsoft.PowerShell.Commands.SetLocationCommand
+ PSComputerName :
The term '.\$file' 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.
+ CategoryInfo : ObjectNotFound: (.\$file:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName :
The term '.\SETUP.exe' 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.
+ CategoryInfo : ObjectNotFound: (.\SETUP.exe:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
+ PSComputerName :
You've to pass your arguments either via -ArgumentList or via $using convention to the Invoke-Command cmdlet. Since you are not doing it that way $folderdest, $file will be null in the scope of the Invoke-Command scriptblock -> the scriptblock defines a seperate scope!
From Microsoft:
-ArgumentList
Supplies the values of local variables in the command. The variables in the command are replaced by these values before the command is run on the remote computer. Enter the values in a comma-separated list. Values are associated with variables in the order that they are listed. The alias for ArgumentList is Args.
Also checkout the exmamples of the Invoke-Commandcmdlet via Get-Help Invoke-Command -Examples.
If you don't like the ArgumentList solution you can also use remote variables.
Additionally you should also define an absolute path to your Setup.exe!
So your code should look like:
....
Invoke-Command -ComputerName $cluster -ArgumentList $file, $folderdest, $instance -ScriptBlock
{
Param(
[string] $rFile,
[string] $rfileDest,
[string] $rInstance
)
# Remove Write-Host after the script block works fine -> Write-Host is only a quick and dirty way to dump the variables content
Write-Host $rFile
Write-Host $rfileDest
Write-Host $rInstance
cd $rfileDest
$someArgs = "/X:{0}" -f $rfileDest
Start-Process -FilePath $rFile -ArgumentList $someArgs -Wait -PassThru
Start-Sleep -s 10
$setupArgs = "action=patch /instancename={0} /quiet /IAcceptSQLServerLicenseTerms" -f $rInstance
Start-Process -FilePath ".\Setup.exe" -ArgumentList $setupArgs -Wait -PassThru
}
....
Hope that helps.

Remote execute sql script for one server to another

I have a "test.sql" in Server1, and I would like to run this script on server2 and server3. I utilized the code below:
$InstanceNm = "server2\inst2,1433"
$CommandExecute_SP = "D:\testscript\test.sql" --located in Server1
invoke-expression "SQLCMD -E -S $InstanceNm -d 'master' -i $CommandExecute_SP -b"
I run the all the codes from server1 and I target server2, but I am getting this error:
SQLCMD : Sqlcmd: 'server2\inst2,1433': Unexpected argument. Enter '-?' for help.
Then when i type -?
It gives this:
At line:1 char:2
+ -?
+ ~
Missing expression after unary operator '-'.
At line:1 char:2
+ -?
+ ~
Unexpected token '?' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
I was wondering what the correct way is to run a .sql file which creates objects on another server from a separate server? I know how to run short sql statements via using System.Data.SQLClient.SQLConnection but I would like to avoid that since this .sql file has over 1000 lines of code.
You could create remote sessions and run the command via Invoke-Command-cmdlet.
$sessions = New-PSSession -computername server1, server2, server3
invoke-command -session $sessions -scriptblock {
invoke-expression "SQLCMD -E -S $InstanceNm -d 'master' -i $CommandExecute_SP -b"
}
If you've Win2012 R2 (or higher version) PS-remoting is activated by default. Otherwise take a look at remoting.
Hope that helps
I ran through myscript again and found out that the error was caused by the ' character in the 'master', I omitted this and it is working now.

Resources