Lets say there is an application with the name exampleService that should be running on Server1. This code works if it is running. However when it's not running, it crashes.
$application = Get-Process -ComputerName Server1 -Name "exampleService"
I get this crash if the application is not running. Is there a more graceful way of finding out if it's not running (without crashing)
Get-Process : Cannot find a process with the name "exampleService". Verify the process name and call the cmdlet again.
At line:1 char:16
+ $application = Get-Process -ComputerName Server1 -Name "exampleService"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Sampler:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Also is it possible to launch the application on the Server if it's not running?
The Server is running Windows Server 2012. The PowerShell commands are being run from a Windows 7 64-bit PC.
Look at using -ErrorAction SilentlyContinue to keep that error from displaying. You can use that in an If statement to launch the application if it isn't running.
--Updated to include launching the remote process
If (-NOT (Get-Process -Computername Server1 -name "cmd" -ErrorAction SilentlyContinue)) {
Write-Host "Launch application"
$application = "c:\windows\system32\cmd.exe"
$start = ([wmiclass]"\\Server1\Root\CIMV2:win32_process").Create($application)
}
You could set the ErrorActionto SilentlyContinue (alias for that is -ea 0):
$application = Get-Process -ComputerName Server1 -Name "exampleService" -ea 0
Now you can check $application and start the application if its null.
I only wanted my script to continue on one particular Get-Process error, i.e. process not found. (and I preferred to use a Try/Catch). But I haven't done much powershell and had trouble locating the specific error.
Once I found I could look at FullyQualifiedErrorId and added the following to a general Catch block I located what I was after.
Write-Host ('FullyQualifiedErrorId: ' + $_.FullyQualifiedErrorId);
So as a full example which works for my situation:
Try {
$application = Get-Process -Name "exampleService" -ea Stop #note the -ea Stop is so try catch will fire whatever ErrorAction is configured
} Catch [Microsoft.PowerShell.Commands.ProcessCommandException] {
If ($_.FullyQualifiedErrorId) {
If ($_.FullyQualifiedErrorId -eq "NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand"){
Write-Host "Presume not running. That is OK."; # or you could perform start action here
}
}
else {
throw #rethrow other processcommandexceptions
}
} Catch {
# Log details so we can refine catch block above if needed
Write-Host ('Exception Name:' + $_.Exception.GetType().fullname); # what to put in the catch's square brackets
If ($_.FullyQualifiedErrorId) {
Write-Host ('FullyQualifiedErrorId: ' + $_.FullyQualifiedErrorId); #what specific ID to check for
}
throw #rethrow so script stops
}
Related
First post! I apologize in advance for formatting. I'm just getting familiar with PowerShell and I'm wanting to Stop a service first, restart another service, and start the initial service. Before moving onto the next next service, I want to make sure that the service has stopped before proceeding.
I'm using this function that was mentioned here and tried to tailor it for my code.
Workflow Goal:
Stop Service A
Restart Service B
Start Service A
Code:
#Stops Service A and validates its in "Stopped" status
Get-Service 'ServiceNameA' -ComputerName 'ExampleServerA' | Stop-Service -force -PassThru
function WaitUntilServices1($searchString, $status)
{
# Get all services where DisplayName matches $searchString and loop through each of them.
foreach($service in (Get-Service -DisplayName $searchString))
{
# Wait for the service to reach the $status or a maximum of 30 seconds
$service.WaitForStatus($status, '00:00:30')
}
}
WaitUntilServices1 "ServiceDisplayNameA" "Stopped"
#Restarts Service B and validates its in "Running" status
Get-Service 'ServiceNameB' -ComputerName 'ExampleServerB' | Restart-Service -force -PassThru
function WaitUntilServices2($searchString, $status)
{
# Get all services where DisplayName matches $searchString and loop through each of them.
foreach($service in (Get-Service -DisplayName $searchString))
{
# Wait for the service to reach the $status or a maximum of 30 seconds
$service.WaitForStatus($status, '00:00:30')
}
}
WaitUntilServices2 "ServiceDisplayNameB" "Running"
#Start Service A and validates its in "Running" status
Get-Service 'ServiceA' -ComputerName 'ExampleServerA' | Start-Service -force -PassThru
Read-Host -Prompt "Press Enter to exit"
The Code I have above is giving me the following Errors for both of the functions.
Exception calling "WaitForStatus" with "2" argument(s): "Time out has expired and the operation has not been completed." At C:\PowerShell\ScriptExample\ScriptExampleFix.ps1:10 char:9
$service.WaitForStatus($status, '00:00:30')
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : TimeoutException
Then for the very last portion to start the service I'm getting 1 more error:
Start-Service : A parameter cannot be found that matches parameter name 'force'. At C:\PowerShell\ScriptExample\ScriptExampleFix.ps1:32 char:85
+ ... erName 'ServerNameExample' | Start-Service -force -PassTh ...
+ ~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Start-Service], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.StartServiceCommand
Any help would get greatly appreciated :)
In the first statement:
#Stops Service A and validates its in "Stopped" status
Get-Service 'ServiceNameA' -ComputerName 'ExampleServerA' | Stop-Service -force -PassThru
You ask PowerShell to stop ServiceNameA on a remote computer.
You then call WaitUntilServices1 which attempts to wait for a service of the same name on your local computer - which is obviously not gonna stop any time soon because you requested stopping a service on a different computer.
Change the function definition to accept a -ComputerName parameter too and pass that to Get-Service:
function Wait-ServiceStatus {
param(
[string]$Name,
[string]$ComputerName = $('.'),
[System.ServiceProcess.ServiceControllerStatus]$Status
)
foreach($service in Get-Service -Name $Name -ComputerName $ComputerName){
# If any call to WaitForStatus times out and throws, return $false
try { $service.WaitForStatus($Status, '00:00:30') } catch { return $false }
}
# No errors thrown while waiting, all is good, return $true
return $true
}
Now we can do:
# request the remote SCM stop the service
Get-Service 'ServiceNameA' -ComputerName 'ExampleServerA' | Stop-Service -Force
$success = Wait-ServiceStatus -Name 'ServiceNameA' -ComputerName 'ExampleServerA' -Status Stopped
if(-not $success){
# output an error
Write-Error "failed to complete restart cycle, 'ServiceNameA' on 'ExampleServerA' failed to stop in a timely manner"
# return from this script/function for good measure
return
}
# ... if we've reached this point the wait must have been successful, continue with the restart cycle.
Get-Service 'ServiceNameB' -ComputerName 'ExampleServerB' | Restart-Service -force -PassThru
$success = Wait-ServiceStatus -Name 'ServiceNameB' -ComputerName 'ExampleServerB' -Status Running
if(-not $success){
# ... etc.
}
I created a short PowerShell scrtipt in order to import a .reg file (an ODBC) to another server session.
I faced to this warning/issue.
The message is this (below):
The operation completed successfully.
+ CategoryInfo : NotSpecified: (The operation completed successfully.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ PSComputerName : MYSERVERNAME
NotSpecified: (:) [], RemoteException
The script, install without problem the .reg file, but constantly I get the message.
This is my code:
#PARAMETERS - Variables
$Serverlist = Get-Content C:\ServerList.txt
try
{
Foreach ($ServerName in $Serverlist)
{
$session = New-PSSession -ComputerName $servername
Write-Host -Foregroundcolor Green "Copying ODBC Driver for $servername"
$copy_cmd = "C:\MYFILE.reg"
Copy-Item $copy_cmd \\$servername\C$\ -recurse -force;
Write-Host -Foregroundcolor Green "ODBC Successfully copied on $servername"
#$session = New-PSSession -ComputerName $servername
Invoke-Command -Session $session -ScriptBlock {
#Start-Process
reg import C:\CopiedFile.reg #This line generate the message
Write-Host -Foregroundcolor Green "ODBC was installed
}
catch
{
Write-Host "ERROR" -Foregroundcolour Red
exit
}
I tried to incapsulate the Invoke-Command or reg import in to try - catch statement, but the message still appear. I used another command, instead reg import, but the nothing change.
I can use this command line, but I would like to catch the error.
Write-Host -Foregroundcolor Green "ODBC is installed " } ##-ErrorAction SilentlyContinue
There is any way to get the eventually error or handle the message.
Thanks in advance.
If the try block does not generate a terminating error, it will not move into the Catch block. This is controlled by -ErrorAction parameter. So you can set
Invoke-Command Session $session -ScriptBlock {} -ErrorAction Stop
This will cause the Invoke-Command Cmdlet to generate terminating errors(if any error occurs) allowing catch block to execute.
I'm writing a script in PowerShell that ideally would gather information from another server. If it's not able to reach that server, I want to prompt it to have the user manually enter the information. I know how to do all of these, but I'm getting hung up when the RPC Server is unavailable. I will also say that I know how to fix the error when it occurs, but I do not want to rely on my end users to have to go in and fix this.
As an example, if I run:
Get-WmiObject Win32_ComputerSystem -Computer 10.5.21.94
the result I get back is:
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:1
+ Get-WmiObject Win32_ComputerSystem -Computer 10.5.21.94
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject],
COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
I'm trying to find a way to write an if statement that will check to see if the RPC server is available or not, but I'm not sure what to check in order to create a true/false variable. And again, I'm not really looking for someone to tell me how to write the if statement, I'm just trying to figure out any query I can run to determine if I can properly connect to this server and get a result back that can tell me to continue on or not.
An easy way to get around it in an if-statement is just to ignore potential errormessages with Erroraction and use a -not statement to check whether it can reach the destination or not and then append a $false value to a variable if it can't.
See the below example.
$status = ""
if (!(Get-WmiObject Win32_ComputerSystem -ComputerName 10.5.21.94 -ErrorAction SilentlyContinue)) {
Write-Host "Server is unavailable!"
$status += $false
}
else {
Get-WmiObject Win32_ComputerSystem -ComputerName 10.5.21.94
}
if ($status -eq $false) {
$Server = Read-Host "Please enter the destionation"
Get-WmiObject Win32_ComputerSystem -ComputerName $Server
}
There was a suggestion for a Try/Catch block, but since this is not a terminating error, it didn't work initially. Then I found this:
Try/catch does not seem to have an effect
There is an answer in there about making all errors terminating:
try {
$ErrorActionPreference = "Stop"; #Make all errors terminating
get-item filethatdoesntexist; # normally non-terminating
write-host "You won't hit me";
} catch{
Write-Host "Caught the exception";
Write-Host $Error[0].Exception;
}finally{
$ErrorActionPreference = "Continue"; #Reset the error action pref to default
}
This gave me exactly what I was looking for!
Problem
This is semi-related to: PowerShell Start-Service Timeout
I am trying to run through a loop to enforce timeout of the action, but continue to run into a random validation error. The code is setup as such:
$timeout = New-TimeSpan -Seconds $SecondsToWait
$timer = [System.Diagnostics.Stopwatch]::StartNew()
$j = Start-Job -ScriptBlock { Start-Service $ServiceName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue }
$count = 0
Do {
If ($j.State -eq 'Running') {
If ($timer.Elapsed.seconds -ne $count) {
$count ++
Write-Host "Elapsed Time: $($timer.Elapsed.seconds)"
}
$j | Receive-Job
}
} While ( $timer.Elapsed -lt $timeout )
I have tried a view variations in attempts to resolve this, but I keep returning to the same root problem with the program exiting with
Cannot validate argument on parameter 'InputObject'. The Argument is null or empty.
Supply an argument that is not null or empty and then try the command again.
At C:file\path.ps1:543 char:13
$j | Receive-Job
CategoryInfo : InvalidData: (:) [Start-Service], ParameterBindingValidationException
FullyQualifiedErrorId: ParameterArgumentValidatinErrorNullNotAllowed,Microsoft.PowerShell.Commands.StartServiceCommand
I have looked through a number of solutions already on StackOverflow and a few other sites, but most are not similar enough to convert the answer to my problem. Most of the questions that I have seen pertain to the Invoke-Command feature of PowerShell or the issues is with a different command altogether. below is a small list of places I have sought out an answer:
powershell Start-Service fails
Powershell function throwing null exception
"Cannot validate argument on parameter 'Identity'" while changing the description for multiple users
Question
Has anyone run into this situation before and know how to resolve it? Also, before anyone says "oh you are not passing in anything during the Start-Service ", the Do While loop iterates randomly between 15 and 30 times before this error is encountered.
So receive-job gets the results of a thread. Then it deleted those results. The error you are getting is becuase the thread completed and the results are the error of
Start-Service $ServiceName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
which is
Cannot validate argument on parameter 'InputObject'. The argument is
null or empty. Provide an argument that is not null or empty, and then
try the command again.
+ CategoryInfo : InvalidData: (:) [Start-Service], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartServiceCommand
+ PSComputerName : localhost
Becuase you didnt specify $ServiceName...
you can verify this by doing the following using -keep tag and remove the -keep tag. The -keep tag will tell the job not to delete the results till next call.
$j = Start-Job -ScriptBlock { Start-Service $ServiceName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue }
$count = 0
Do {
$j.State
$j | Receive-Job -keep
} While ( $timer.Elapsed -lt $timeout )
the following will show running many time and then once completed will show the following
Running
Running
Running
Completed
Cannot validate argument on parameter 'InputObject'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
+ CategoryInfo : InvalidData: (:) [Start-Service], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartServiceCommand
+ PSComputerName : localhost
it will keep repeating that error over and over until loop is finished OR until it hits a Receive-Job without a -keep
Sometimes it will show
Running
{Results here}
Running
{Results here}
Complete
{Results here}
This is because Receive-job is giving you faster information then System is updating the Thread.state to Completed.
IF you dont want to see that error then just delete Receive-Job or use a try catch for the error in the scriptblock
I need to get some procs by the owner. My demo script below will first look for procs by owner locally, then it will do the same thing, but it invokes the command on the same box:
cls
write-host 'LOCAL CALL: '
$procs = #(Get-WmiObject win32_process |? {($_.getowner().user -eq 'APP_ACCOUNT') })
write-host $procs.count
$func = {
$procs = #(Get-WmiObject win32_process |? {($_.getowner().user -eq 'APP_ACCOUNT') })
write-host $procs.count
}
write-host 'REMOTE CALL: '
$session = New-PSSession -ComputerName 'SERVER'
$job = Invoke-Command -Session $session -ScriptBlock $func -AsJob
Wait-Job -Job $job
$job | Receive-Job
$job | Remove-Job
Remove-PSSession -Session $session
Most of the time when I run my script it errors with the following output:
LOCAL CALL:
38
REMOTE CALL:
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
26 Job26 RemoteJob Completed True SERVER ...
Exception calling "GetOwner" : "Not found "
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WMIMethodException
+ PSComputerName : SERVER
38
So that first 38 is the number of procs it found for the owner running locally. It finds 38 the second time as well, but errors calling getowner. I don't understand why since it worked the first time. Is it operating in some kind of "bubble" when I invoke the command? In my larger script this is causing me more severe issues as the job state goes to failed and execution halts even though it is throwing the same error. One problem at a time though.
Seems I needed to do a better job of making sure my processes still exist before filtering by owner:
$procs = #()
$allProcs = #(Get-WmiObject win32_process)
foreach($proc in $allProcs)
{
$procActive = get-process -Id $proc.processId -ErrorAction SilentlyContinue
if($procActive)
{
if($proc.getowner().user -eq 'jdholbrook')
{
$procs += $proc
}
}
}
write-host $procs.count
This is probably because the process for which you want to query the owner doesn’t exist anymore.
You can simulate this behaviour on your local PC as follows:
Start some application, like notepad.exe for example. Now run:
$w = (Get-WmiObject win32_process) # Your notepad process will now be the last in the `$w` array.
Close the notepad.exe process.
Now pipe the contents of $w to get the owners:
$w | % {$_.getowner()}
For the last object you will get:
Exception calling "GetOwner" : "Not found "
At line:1 char:20
+ $w | % {$_.getowner <<<< ()}
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WMIMethodException
To make sure this is the notepad.exe you just closed you can double-check:
$w[-1]; # last object
$w[-1].getowner(); # error
So, now you know what is causing, you can start thinking about how to handle it...