Start-Service cmdlet: get underlying error in case of failure - powershell

Say that I want to start MSSSQLSERVER service. this is done in PowerShell via the Start-Service cmdlet.
Sometimes services fail to start due to an error like in the example below.
What I'm interested in is the root cause of the failure, while start-service seems to be returning the powershell exception, a generic wrapper that does not contain error-specific information.
PS C:\Users\Administrator> start-service MSSQLSERVER
start-service : Failed to start service 'SQL Server (MSSQLSERVER) (MSSQLSERVER)'.
At line:1 char:1
+ Start-Service MSSQLSERVER
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service],
ServiceCommandException
+ FullyQualifiedErrorId : StartServiceFailed,Microsoft.PowerShell.Commands.StartServiceCommand
To get the root cause of the problem, we have to resort to net start command, that brings us back to the old-days that should be forgotten with PowerShell.
C:\Users\Administrator>NET START MSSQLSERVER
The SQL Server (MSSQLSERVER) service is starting.
The SQL Server (MSSQLSERVER) service could not be started.
A service specific error occurred: 17051.
More help is available by typing NET HELPMSG 3547.
Is there a way to see the underlying error thrown by the service?

As I.T Delinquent stated, the error can be found in the exception, however in this case it will be stored in the inner exception(s):
$ErrorActionPreference = "Stop"
try
{
Start-Service -Name "MSSQLSERVER"
}
catch
{
$msg = #()
$err = $_.Exception
do {
$msg += $err.Message
$err = $err.InnerException
} while ($err)
Write-Verbose "Failed to start service: $($msg -join ' - ')"
}

I think it would be good for you to check out this link
But basically, you can use a Try/Catch statement and output the message from the error, something like this:
try{
Start-Service MSSQLSERVER -ErrorAction Stop
}catch{
$PSItem.Exception.Message
}

Related

How Can I handle Errors in PS [duplicate]

This question already has an answer here:
How to handle failed variable assignments in powershell? [duplicate]
(1 answer)
Closed 2 years ago.
I'm trying to catch the error from service restart using function. The issue Im having that catch is not doing anything through the script.
Function Service_Restart ($Servers, $Service){
try {
Write-Host "$CurrentDateTime - Restarting Service $Service on Servers $Servers"
ForEach($Serv in $Servers){
Get-Service -ComputerName $Serv -Name $Service | Restart-Service
}
} catch [System.ServiceProcess.ServiceController] {
$error[0].Exception
}
Service_Restart Server1 ServiceName
I'm expecting to see an one line error not the full stack, however I see the entire error.
What I like to see as an example
Restart-Service : Service 'Adobe Acrobat Update Service (AdobeARMservice)' cannot be stopped due to the following error: Cannot open AdobeARMservice service on computer 'Localhost'.
However I'm seeing
Restart-Service : Service 'Adobe Acrobat Update Service (AdobeARMservice)' cannot be stopped due to the following error: Cannot open AdobeARMservice service on computer 'Localhost'.
At C:\user\UTILS_Version3.ps1:48 char:62
+ ... Get-Service -ComputerName $Serv -Name $Service | Restart-Service
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (System.ServiceProcess.ServiceController:ServiceController) [Restart-Service], ServiceCommandException
+ FullyQualifiedErrorId : CouldNotStopService,Microsoft.PowerShell.Commands.RestartServiceCommand
If I run $error[0].Exception manually I get the result I'm looking for but not through the function.
PS C:\Users\> $error[0].Exception
Service 'Adobe Acrobat Update Service (AdobeARMservice)' cannot be stopped due to the following error: Cannot open AdobeARMservice service on computer '127.0.0.1'.
PS C:\Users\>
When using try and catch, you must be working with terminating errors. Since some errors are non-terminating, you can force them to be terminating. To ensure your commands generate terminating errors, you can use the common parameter -ErrorAction Stop. Alternatively, you can set $ErrorActionPreference = 'Stop' and all commands within the session will implicitly apply -ErrorAction Stop.
In a catch block, $_ or $PSItem is the caught ErrorRecord object. When handling a specific error, it is best to use the error type's full name. You can retrieve that with $_.Exception.GetType().Fullname in the catch block or $error[0].Exception.GetType().Fullname outside of try {} catch {}.
Putting this all together, you can do the following:
try {
Get-Service -ComputerName $Serv -Name $Service -ErrorAction Stop |
Restart-Service -ErrorAction Stop
} catch [Microsoft.PowerShell.Commands.ServiceCommandException] {
$_.Exception
}
See About Try Catch Finally for more information.

powershell remote script execution errors

I notice an error " Connecting to remote server usa-chicago failed with the following error message : Access is denied. For more information, see the
about_Remote_Troubleshooting Help topic
CategoryInfo : OpenError: (usa-chicago:String) [], PSRemotingTransportException
FullyQualifiedErrorId : AccessDenied,PSSessionStateBroken
". Below is the snippet used. Any suggestions?
All the machines are inside a workgroup.
$computers = gc "C:\servers.txt"
$source = "\\usa-chicago\c$\temp\one.jar"
$destination = "c$\july1\folder1\"
foreach ($computer in $computers) {
Invoke-Command -Computername $computer -ScriptBlock { & Copy-Item $using:source -Destination \\$using:computer\$using:destination -Force }
}
Does your user account have access both to the computer and also the share you try to copy something to? It could be that you hit the dreaded 'second hop' problem with PowerShell Remoting: https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/ps-remoting-second-hop?view=powershell-7
If this is the problem, there are some workarounds for that. What i like to do is:
In the Invoke Command, create a Scheduled Task with the commands you'd like to execute and pass the credentials into it, execute it, and delete it after.

MSBTS_HostSetting is Not Found

Upon building a script to automate the deletion of Host and Host Instances, I run the script below in PowerShell.
PS
C:\WINDOWS\system32>
[System.Management.ManagementObject]$objHostSetting =
([WmiClass]"root/MicrosoftBizTalkServer:MSBTS_HostSetting").Delete()
However, after running the script, it seems that the MSBTS_HostSetting is gone because I was receiving the error below every time I am running it.
PS
C:\WINDOWS\system32>
[System.Management.ManagementObject]$objHostSetting
=[WmiClass]"root/MicrosoftBizTalkServer:MSBTS_HostSetting" Cannot convert value "root/MicrosoftBizTalkServer:MSBTS_HostSetting" to type
"System.Management.ManagementClass". Error: "Not found " At line:1
char:2
+ [System.Management.ManagementObject]$objHostSetting =[WmiClass]"root/MicrosoftB ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastToWMIClass
I am trying to load the BizTalkOMExplorer but the MSBTS_HostSetting has not returned. Any suggestions or knowledge how can I bring it back.
Just fixed my issue! Below are what I've done.
Open CMD and register the BTSWMIProvider.dll
Example:
Regsvr32.exe “C:\Program Files (x86)\Microsoft BizTalk Server 2013 R2\Bins32\BTSWMIProvider.dll“
Run the following in CMD as well.
mofcomp.exe BTSWMISchema.mof
mofcomp.exe BTSWMISchema.mfl
Restart WMI in services.
This would do the trick! :)
With PowerShell, you can get your HostInstances as:
$hostInstances = Get-WmiObject MSBTS_HostInstance -namespace root\MicrosoftBizTalkServer -ErrorAction Stop
And then you can find which one you want to delete and invoke Delete method:
$hostInstances[0].Delete()
The same with Hosts:
$hosts = Get-WmiObject MSBTS_Host -Namespace root\MicrosoftBizTalkServer -ErrorAction Stop
$hostToDelete = $hosts | where {$_.Name -eq 'HostNameToDelete'}
$hostToDelete.Delete()

Powershell Workflow to reboot computers

Code:
workflow Test-RemoteReboot{
param ([string[]]$serverNames)
foreach -parallel($server in $serverNames){
Restart-Computer -PSComputerName $server -Wait -Force
}
}
Test-RemoteReboot SP,SP2
Issue:
this is a small excerpt from a pretty long workflow I built in powershell. By all accounts, this should work but I get the following error (even when running this script in isolation):
Microsoft.PowerShell.Utility\Write-Error : The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: The computer SP2 is
skipped. Fail to retrieve its LastBootUpTime via the WMI service with the following error message: The RPC server is unavailable. (Exception from HRESULT: 0x800706BA).
At line:433 char:25
+ ... Receive-Job -Job $job -Wait -Verbose -Debug -ErrorAction ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], ActionPreferenceStopException
+ FullyQualifiedErrorId : System.Management.Automation.ActionPreferenceStopException,Microsoft.PowerShell.Commands.WriteErrorCommand
+ PSComputerName : [localhost]
I looked into the RPC server unavailable issue. Firewall is down, RPC Service is running, Servers are on domain, Workflow running from domain member computer, as domain admin. I can successfully PSRemote into the machines and do whatever. I can even do this:
workflow Test-LocalRebootRemotely{
param ([string[]]$serverNames)
foreach -parallel($server in $serverNames){
InlineScript { Restart-Computer -Force } -PSComputerName $server
}
}
Test-LocalRebootRemotely SP,SP2
The problem is, is that I need a return value to determine if I need to reboot and handle other logic outside of the remote computer. I do notice that there is an abnormal pause just before it errors. So maybe it is a timeout? anyone have a similar issue?
You can try the Restart-Computer cmdlet with the -Protocol WSMan parameter instead of the default DCOM over RPC protocol (-Protocol DCOM).
This would confirm that your RPC network packets are blocked somewhere.

Set-Service: Cannot stop service because it is dependent on other services

When I run the following command:
Set-Service -ComputerName appserver -Name MyService -Status Stopped
I get an error message:
Set-Service : Cannot stop service 'My Service (MyService)' because it is
dependent on other services.
At line:1 char:12
+ Set-Service <<<< -ComputerName appserver -Name MyService -Status Stopped
+ CategoryInfo : InvalidOperation: (System.ServiceProcess.ServiceController:ServiceController) [Set-Service], ServiceCommandException
+ FullyQualifiedErrorId : ServiceIsDependentOnNoForce,Microsoft.PowerShell.Commands.SetServiceCommand
I can stop the service from the services.msc GUI, and I can start the service with Set-Service, but I can't stop it again.
It is true that the service depends on some other services, but I don't understand why that would prevent me from stopping it—nothing else depends on it.
The Set-Service cmdlet is for changing the configuration of a service. That you can use it to stop a service by changing its status is just coincidental. Use the Stop-Service cmdlet for stopping services. It allows you to stop dependent services as well via the parameter -Force. You'll need to retrieve the service object with Get-Service first, though, since Stop-Service doesn't have a parameter -ComputerName.
Get-Service -Computer appserver -Name MyService | Stop-Service -Force
I eventually resolved this problem with the following code, which calls sc to stop the service and then waits for it to finish stopping. This achieves the same result as expected from Set-Service -Status Stopped; that is, when it returns the service has been stopped. (sc on its own starts to stop the service, but does not wait until it has finished stopping.)
Start-Process "$env:WINDIR\system32\sc.exe" \\APPSERVER,stop,MyService -NoNewWindow -Wait
while ((Get-Service -ComputerName APPSERVER -Name MyService |
Select -ExpandProperty Status) -ne 'Stopped') {
Write-Host "Waiting for service to stop..."
Start-Sleep -Seconds 10
}