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

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'"
}

Related

Getting MSSQL Instance Version in Powershell

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

Issue with my powershell syntax to do an clean up

I am using below PowerShell code to delete the logs in database server path
powershell.exe -command & {
get-childitem -path "$(ESCAPE_SQUOTE(D:\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Log\))" -filter *_*_*_*.txt |
Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | remove-item -verbose
}
Its erroring out as in below
At line:1 char:25
+ powershell.exe -command & {get-childitem -path "$(ESCAPE_SQUOTE(D:\Microsoft SQL ...
+ ~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
quotation marks ("&") to pass it as part of a string.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : AmpersandNotAllowed
I am new to PowerShell and thought adding "" to "&" would suffice but its erroring again
powershell.exe : ScriptBlock should only be specified as a value of the Command parameter.
At line:1 char:1
+ powershell.exe -command "&" {get-childitem -path "$(ESCAPE_SQUOTE(D:\Microsoft S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], ParameterBindingException
+ FullyQualifiedErrorId : IncorrectValueForCommandParameter
Added "" to the path but it doesn't help
powershell.exe -command & {get-childitem -path "$(ESCAPE_SQUOTE("D:\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Log\"))" -filter *_*_*_*.txt | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | remove-item -verbose}
I need to call it from an SQL agent job under operating system command exec
Can any one help me with the syntax
Regards and Wishes
Eben
When passing commands to the PowerShell CLI's -Command / -c parameter:
If you're calling from outside PowerShell, omit & { ... } altogether, just specify ... - & { ... } is never needed and only creates overhead.
Additionally, if you're calling from cmd.exe (you're not), it's safest to double-quote ... ("..."), and to escape embedded double quotes as \" (sic).
From inside PowerShell, omit & (you do need { ... } to robustly pass the commands, but this approach only works when calling from inside PowerShell):
Your error message suggest that powershell.exe was indeed called from a PowerShell session.
However, the question is why you're calling another PowerShell instance - as a child process - given that you're already in a PowerShell session - you could just execute the statements inside { ... } directly.
Given your symptom, I'm wondering whether the exec command in your case actually already uses PowerShell rather than cmd.exe as the shell, in which case passing just the text inside { ... } from your question would be sufficient.

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?

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.

Resources