How Can I handle Errors in PS [duplicate] - powershell

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.

Related

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

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
}

New-PSSession - WinRM cannot process the request

I am trying to list all the websites in IIS on a remote server using PowerShell scripting. Below is how I am trying to connect to the server:
$s = New-PSSession -ComputerName $Server
But when I run the script I am getting the following error:
New-PSSession : [Server] Connecting to remote server Server failed with the
following error message : WinRM cannot process the request. The following error
occurred while using Kerberos authentication: Cannot find the computer Server.
Verify that the computer exists on the network and that the name provided is
spelled correctly. For more information, see the about_Remote_Troubleshooting
Help topic.
At C:\AppServers\Application.ps1:8 char:8
+ $s = New-PSSession -ComputerName Server
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : NetworkPathNotFound,PSSessionOpenFailed
The server is already enabled to receive remote requests.
Update:
Below is the full function that i am trying to run:
function audit-servers {
if (Test-path "ApplicationsOnTheServer.txt") {Remove-Item "ApplicationsOnTheServer.txt"}
if (Test-Path "ServersList.txt") {
foreach ($server in Get-Content .\ServersList.txt) {
"Application Server : $server`n" | out-file -FilePath "ApplicationsOnTheServer.txt" -Append
"Applications list:" | out-file -FilePath "ApplicationsOnTheServer.txt" -Append
$s = New-PSSession -ComputerName $server -Credential domainabc\myname
Invoke-Command -Session $s -ScriptBlock {Import-Module WebAdministration;Get-iissite} | out-file -FilePath "ApplicationsOnTheServer.txt" -Append
}
} else {
"ServersList.txt file is missing"
break;
}
"`nAll Done!`n"}
The ServersList.txt has atstappvmabc.tsteag.com
The error message clearly states that you wanted to connect to the server named Server not to the server which name is stored in $Server variable (text in bold is actually the name of the server you try to connect to):
New-PSSession : [Server] Connecting to remote server Server failed
If you tried to connect to the server named for example MyServer01.example.com you'd receive the error like below (truncated):
PS C:\> New-PSSession -ComputerName "MyServer01.example.com"
New-PSSession : [MyServer01.example.com] Connecting to remote server MyServer01.example.com failed (...)
Even though you state that you try to execute
$s = New-PSSession -ComputerName $Server
You actually execute (notice missing dollar sign)
$s = New-PSSession -ComputerName Server
The above was also taken from the error message you pasted. I'd suggest to first skip the variable and try to enter server path in the command itself to verify it's working:
$s = New-PSSession -ComputerName "MyServer01.example.com"
And then, if it works, put the path in variable and test again.
The error you're receiving FullyQualifiedErrorId : NetworkPathNotFound generally means that the name you're passing to the -ComputerName parameter can't be resolved.
Perhaps try running Test-Connection $Server to troubleshoot what's happening there.
Your variable $Server contains wrong value. You have to assign valid computer name to $Server.

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
}

Catch result of PowerShell's Restart-Service cmdlet

When running a script with:
Restart-Service ServiceName
How do I capture the result? For example, if the service doesn't exist, I'll get a message like:
Restart-Service : Cannot find any service with service name 'ServiceName'.
I've tried try and catch using if ($error) but no luck.
You could check out the ErrorAction parameter. If you just don't want an error you could try the following (check $? to see if it was successful).
Restart-Service ServiceName -ErrorAction SilentlyContinue
try catch does not catch all errors you see, only terminating errors. If you want to turn the error in a terminating error you could try the following.
try
{
Restart-Service ServiceName -ErrorAction Stop
}
catch
{
'Catched'
}
To get the last error:
$error[0]