Getting MSSQL Instance Version in Powershell - sql-server

From running the following I can see that there are 4 MSSQL instances running on this machine:
$Hostname = (Get-WmiObject Win32_OperatingSystem).CSName
$GetSQLInstance = Get-Service -ComputerName $Hostname | Where-Object { ($_.Name -eq 'mssqlserver' -or $_.Name -like 'mssql$*') -and $_.DisplayName -like 'SQL Server*'}
$GetSQLInstance
Status Name DisplayName
------ ---- -----------
Running MSSQL$INSTANCE01 SQL Server (INSTANCE01)
Running MSSQL$INSTANCE02 SQL Server (INSTANCE02)
Running MSSQL$INSTANCE03 SQL Server (INSTANCE03)
Running MSSQL$INSTANCE04 SQL Server (INSTANCE04)
I am trying to ascertain the MSSQL version of these instances, what would be the best way to do so? I thought to use Get-SqlInstance, but it doesn't seem to be installed on this machine:
Get-SqlInstance
Get-SqlInstance : The term 'Get-SqlInstance' 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:1
+ Get-SqlInstance
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Get-SqlInstance:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

I use a modified version of this solution here. This is nice since you can run this remotely from your machine and it writes the info to a CSV.
Invoke-Command -ComputerName (Get-Content 'C:\Powershell\machines.txt') -ScriptBlock {
$SQLInstance = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server').InstalledInstances
foreach ($Install in $SQLInstance)
{
$Path = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL').$Install
return (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$Path\Setup")
}
} | Select-Object -Property PSComputerName,Edition,PatchLevel | Export-CSV -Path 'C:\Powershell\output.csv' -NoTypeInformation

Related

PowerShell runtime execption in remote call

I intend to install remotely a sql-instance. I have a share with sql-binaries and a config-file.
My script is:
import-module sqlserver -DisableNameChecking
$setupDrive = "\\sqlshare\sql_source\ISO\Setup\SW_DVD9_NTRL_SQL_Svr_Ent_Core_2019Dec2019_64Bit_English_OEM_VL_X22-22120"
$fileExe = "$setupDrive", "setup.exe" -join("\")
$configurationFile = "\\sqlshare\sql_source\ISO\ConfigurationFileMSSQLSERVER.ini"
$session = New-PSSession -ComputerName "xxxx_yyyy"
Invoke-Command -ScriptBlock{& $args[0] /CONFIGURATIONFILE=$args[1]} -Session $session
-ArgumentList $fileExe, $configurationFile
I'm still getting an error and don't know how to interpret it:
An error occurred while creating the pipeline.
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
+ PSComputerName : xxxx_yyyy
I have a PS-script on the server A:(C:\temp\script.ps1) with this content:
import-module sqlserver -DisableNameChecking
& ("\\server1-ssp1102.my.domain\sql_source\Setup\setup.exe
/CONFIGURATIONFILE=\\server1-ssp1102.my.domain\sql_source\SQLUnattended\ConfigurationFileMSSQLSERVER.ini")
I want to execute this script on the server B (installs a sql server).
This doesn't work:
invoke-command -computer ServerB -FilePath C:\C:\temp\script.ps1 -credentials (get-credential)
Update once again:
The complete call looks like following:
# A sample target computer.
$computer = 'myComputer'
# Obtain the credentials for the remote session and store them in a
variable.
$cred = Get-Credential my\user
Invoke-Command -ComputerName $computer -Credential $cred {
$setup = '\\myShare-xxxx.my.domain\sql_source\Setup\setup.exe'
$config = '\\myShare-yyy- xxx.my.domain\sql_source\SQLUnattendedInstallation\ConfigurationFileMSSQLSERVER.ini'
$cu = '\\my-domain-xxxx.my.domain\sql_source\SQLUnattendedInstallation2019\CU'
$null = New-PSDrive -Credential $using:cred -Name cu -Root $cu -PSProvider FileSystem
$null = New-PSDrive -Credential $using:cred -Name setup -Root (Split-Path -Parent $setup) -PSProvider FileSystem
$null = New-PSDrive -Credential $using:cred -Name config -Root (Split-Path -Parent $config) -PSProvider FileSystem
& $using:setup /CONFIGURATIONFILE=$using:config
}
Update:2
I've created a file (test5.ps1) with this content:
import-module sqlserver -DisableNameChecking
$setup = '\\xxx-xxx-xxx.xxx.xxx\sql_source\Setup\setup.exe'
$config = '\\xxx-xxx- xxx.xxx.xxx\sql_source\SQLUnattendedInstallation2019\ConfigurationFileMSSQLSERVER.ini'
$cu = '\\xxx-xxx-xxx.xxx.xxx\sql_source\SQLUnattendedInstallation2019\CU\SQLServer2019-KB5014353-x64.exe'
$null = New-PSDrive -Credential $using:cred -Name cu -Root (Split-
Path $cu) -PSProvider FileSystem
$null = New-PSDrive -Credential $using:cred -Name setup -Root
(Split-Path -Parent $setup) -PSProvider FileSystem
$null = New-PSDrive -Credential $using:cred -Name config -Root
(Split-Path -Parent $config) -PSProvider FileSystem
& $setup /CONFIGURATIONFILE=$config
and then I'm calling this script like this:
Invoke-Command -ComputerName xxx-sql-yyy -FilePath
C:\Users\xxx\Documents\test\test5.ps1 -Credential (Get-Credential
my\user)
then the script begins to install the sql server on the remote machine, but still I get an error (in the summary.txt from the sql server installation on the remote machine):
Access is denied.
Error result: -2061762559
Result facility code: 1308
Result error code: 1
meaning: still a problem with the credentials.
Update 3:
The script (test5.ps1) stays untouched
on the caller-site:
$cred = get-credential
Invoke-Command -ComputerName xxx-sql-yyy -FilePath
C:\Users\xxx\Documents\test\test5.ps1 -Credential $cred
Unfortunately the same error: Access denied etc.
the tricky problem was inside of the configuration.ini file for unattended sql server installation, namely:
;SQLSVCACCOUNT="myDomain\theServiceAccount$" # originally
SQLSVCACCOUNT="NT Service\MSSQLServer" # changed
;AGTSVCACCOUNT="myDomain\theAgentAccount$" # originally
AGTSVCACCOUNT="NT Service\SQLServerAgent" # changed
The error-message "Access denied" was all about those accounts.
After the installation I have to change the service accounts for the sql- and agent services and that's all.

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?

Get-WmiObject can't be executed on PowerShell (x86) but on PowerShell

Why can I execute the following code on PowerShell but not on PowerShell (x86) on the same computer?
Get-WmiObject -Namespace "root\Microsoft\SqlServer\ComputerManagement13" -Class ServerSettingsGeneralFlag -Filter "FlagName='ForceEncryption'"
Exception:
At line:1 char:1
+ Get-WmiObject -Namespace "root\Microsoft\SqlServer\ComputerManagement ...
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], FileNotFoundException
+ FullyQualifiedErrorId : System.IO.FileNotFoundException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
As #AnsgarWiechers said, it likely doesn't exist. As for why, maybe you've installed 64 bit SQL Server and not 32 bit?
One way you might be able to work around this is with PowerShell remoting. If PowerShell remoting is enabled and configured, you can remote into your own machine from the 32 bit process, and you'll be connected to a 64 bit instance. So you can run this code to get your result from the 64 bit session.
$result64 = Invoke-Command -ComputerName . -ScriptBlock {
Get-WmiObject -Namespace "root\Microsoft\SqlServer\ComputerManagement13" -Class ServerSettingsGeneralFlag -Filter "FlagName='ForceEncryption'"
}

Run multiple *.sql query files log to file

My goal is to have a PowerShell script run several Sqlquery.sql files against a specific SQL server and then log the output to a log file.
I can't get the logging to work and I don't know what I'm missing. My log file is always empty and I'm at a loss for that I am missing.
Contents of C:\Temp:
Build1.SQL
Build2.SQL
Build3.sql
Build4.sql
Build5.SQL
Build6.SQL
$PatchPostConvSQLScripts = Get-ChildItem -Path C::\Temp -Filter *.sql -Name
$Queries = $PatchPostConvSQLScripts
foreach ($query in $Queries){
Write-Host "Starting: $query"
Invoke-Sqlcmd -ServerInstance $DBServer -InputFile $query |
Out-File "C:\TEMP\scriptResults.log"
Write-Host "Completed: $query"
}
Once I get it logging to a file, I'll need to get a newline each time with a `n`r, but baby steps right now.
Is there a better way to do this that I just don't know?
The main reason you got nothing in log file is that Output-File rewrite whole data in it on each run. Try to use -Verbose as mentioned in answer by TechSpud to collect print/server statements, or write output to temp file and Add-Content to main log file:
$DBServer = "MYPC\SQLEXPRESS"
$sqlPath = "C:\TEMP\"
$log = "scriptResults.log"
$tempOut = "temp.log"
$files = Get-ChildItem -Path $sqlPath -Filter *.sql -Name
foreach ($file in $files){
Write-Host "Starting: $file"
Invoke-SQLcmd -ServerInstance $DBServer -InputFile $sqlPath$file | Out-File $sqlPath$tempOut
Get-Content $sqlPath$tempOut | Add-Content $sqlPath$log
Write-Host "Completed: $file"
}
Firstly, as #Ben Thul has mentioned in his comment, check that your SQL files actually output something (a resultset, or messages), by running them in Management Studio.
Then, you'll need to use the -Verbose flag, as this command will tell you.
Get-Help Invoke-Sqlcmd -Full
Invoke-Sqlcmd does not return SQL Server message output, such as the
output of PRINT statements, unless you use the PowerShell -Verbose parameter.
$Queries = Get-ChildItem -Path C::\Temp -Filter *.sql -Name
Clear-Content -Path "C:\TEMP\scriptResults.log" -Force
foreach ($query in $Queries){
Write-Host "Starting: $query"
Invoke-Sqlcmd -ServerInstance $DBServer -InputFile $query -Verbose |
Add-Content -Path "C:\TEMP\scriptResults.log"
Write-Host "Completed: $query"
}

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