LastExitCode of invoke-command does not match condition - powershell

I am running script through jenkins and the Invoke command should fail as the file already exits and should reach exit code 1 and error out and show a fail in jenkins but instead it still is exiting 0 as green
I have tried using Try catch and using $? but still cannot get this to show as red when failure
$Time = $args[1]
$Server = $args[2]
$username = $args[3]
$password = $args[4]
$pass="$password"|ConvertTo-SecureString -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PsCredential("ad\$username",$pass)
$session = New-PSSession -ComputerName $Server -Credential $Cred -ErrorAction Stop
Invoke-Command -Session $session -ScriptBlock {netsh trace start capture=yes tracefile=C:\Traces\netsh.etl}
If ($LastExitCode -eq 1)
{
exit 1
}
write-host "hello world"
start-sleep -Seconds $Time
Invoke-command -Session $session -ScriptBlock {netsh trace stop}
If ($LastExitCode -eq 1)
{
exit 1
}
exit 0
The file already exists which should be expected but not reaching the exit 1 inside either if statements when it should.

The $LastExistCode you are testing is on the local system, but you are running the command on a remote system. Try returning the $LastExistCode at the end of your scriptblock and test the result of the Invoke-Command
For example:
$result = Invoke-command -Session $session -ScriptBlock {netsh trace stop; $LastExitCode}
If ($result -eq 1)
{
exit 1
}
This assumes that netsh itself doesn't return anything (I didn't test it). If it does, you can typically supress the output by piping it to Out-Null:
Invoke-command -Session $session -ScriptBlock {netsh trace stop | Out-Null; $LastExitCode}

Related

Powershell | get a value from 2 nested invoke commands

i want to transfer the values from the invoke commands to local. I have problems to get the values from the second invoke command. I want $computers and $tasks in the textbox. Any Ideas? I have tried with return but then i can only get the values from first invoke command.
EDITED:
$session = New-PSSession -ComputerName $remote -Credential $cred
Invoke-Command -Session $session -ScriptBlock {
### get all computers in Domain ###
$computers = dsquery computer "DC=kanzlei,DC=local" -o rdn
Write-Host ("In dieser Domäne gibt es die folgenden Server:")
write-host $computers
#configure all computers
foreach($computer in $computers) {
$session3 = New-PSSession -ComputerName $remote -Credential $cred_session
Invoke-Command -Session $session3 -ScriptBlock {
write-host "Tasks for $env:computername gonna be activated"
#### acitivate tasks ####
$tasks = Get-ScheduledTask -TaskPath "\RA-MICRO_Update_Routine\" | Enable-ScheduledTask | FL Taskname,State }
write-host "$tasks"
}
}
}
##### I want vriable $Computers and $Tasks here on Local ####
do anything with $tasks
do anything with $computers

PowerShell Exit out of the whole script not Just the Invoke-Command

I have a script that is currently monitoring a couple of windows services on different VMs. If the service is stopped, it will attempt to start the service.
I have added a $LoopCounter to stop the script it it loops to many time as to not fall into an infinite loop if the service cannot be started for what ever reason.
This is all inside a Invoke-Command that runs some code on the remote VMs. I have used Exit to stop the script running but it does not seem to be in the right scope of things and it stops the Invoke-Command but not the whole script.
Script:
Invoke-Command -ComputerName VM1, VM2, VM3 -Credential $Cred -ArgumentList $ServiceList -ScriptBlock {
Foreach ($Service in $Using:ServiceList) {
$C = [System.Net.Dns]::GetHostName()
$S = Get-Service -Name $Service
while ($S.Status -ne 'Running') {
# Code...
$LoopCounter++
If($LoopCounter -gt 2) {
Exit
}
}
}
}
You could have the scriptblock return a value and check for that.
The example below has the returned value 1 if the script should exit as a whole:
$result = Invoke-Command -ComputerName VM1, VM2, VM3 -Credential $Cred -ArgumentList $ServiceList -ScriptBlock {
Foreach ($Service in $Using:ServiceList) {
$C = [System.Net.Dns]::GetHostName()
$S = Get-Service -Name $Service
while ($S.Status -ne 'Running') {
# Code...
$LoopCounter++
If($LoopCounter -gt 2) {
return 1 # return a value other than 0 to the calling script
Exit # exit the scriptblock
}
}
}
}
# check the returned value from Invoke-Command
# if it is not 0 (in this example), exit the whole script
if ($result) { exit }
Hope that helps

Run Remote Command via Powershell

I'm trying to invoke discrete CLI commands on a series of remote systems via a script, and I can't get any PowerShell commands to accept them. Rather than try to explain the specifics of the issue, I'll provide some pseudocode of what I'm trying to do below.
Please note that this is just a simple example. Using the stop-service command is not an option. These are explicit commands used via CLI with via the Splunk program that I need to run in this order.
In short, I just can not figure out how to tell PowerShell to run a CLI command verbatim on a remote machine.
foreach ($server in $list)
cd C:\Program Files\SplunkUniversalForwarder\bin
splunk stop
splunk clone-prep-clear-config
splunk start
Bunch of ways you can do this. Using WMI c/o Powershell:
Starting,Stopping and Restarting Remote Services with PowerShell
You can also use Windows remoting, but I'd start here.
You could try...
Foreach($server in $list)
{
Invoke-command -computername $server -scripblock {
$splunkpath = 'c:\program files\splunkuniversalforwarder\bin\splunk.exe'
Start-process -filepath $splunkpath -argumentlist 'stop' -wait -nonewwindow
Start-process -filepath $splunkpath -argumentlist 'clone-prep-clear-config' -wait -nonewwindow
Start-process -filepath $splunkpath -argumentlist 'start' -wait -nonewwindow
}
}
Note: you may need to remove the -wait and/or -nonewwindow from the commands depending on how your process behaves.
There are also output redirection parameters checkout the docs below for more.
Invoke-command
Start-process
I literally just did this this morning. This is the main part I came up with.
foreach($server in $servers){
Write-Host "From " -nonewline; Write-Host "$server" -ForegroundColor Yellow
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe stop } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe clone-prep-clear-config } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe start } -Credential $cred
}
my full code is below:
#Author: Christopher Boillot
#Clear config of Splunk Forwarder
[CmdletBinding()]
Param ([Parameter(Mandatory=$False,Position=0)]
[String[]]$servers = (Get-Content C:\ClearConfig.txt))
Set-Location $PSScriptRoot
#User login
$User = "user.txt"
$FileExists = Test-Path $User
If ($FileExists -eq $False) {
Write-Host "Enter your user name. This will be saved as $User"
read-host | out-file $User
}
$Pass = "securepass.txt"
$FileExists = Test-Path $Pass
If ($FileExists -eq $False) {
Write-Host "Enter your password. This will be saved as an encrypted sting as $Pass"
read-host -assecurestring | convertfrom-securestring | out-file $Pass
}
$username = cat $User
$password = cat $Pass | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $username, $password
#go through each server in list
foreach($server in $servers){
Write-Host "From " -nonewline; Write-Host "$server" -ForegroundColor Yellow
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe stop } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe clone-prep-clear-config } -Credential $cred
Invoke-Command -ComputerName $server -ScriptBlock { C:\SplunkUniversalForwarder\bin\splunk.exe start } -Credential $cred
}

PowerShell Invoke-Command -AsJob

The script I wrote is pretty long but works fine except for one problem. When I have more jobs for the same $Server it's only submitting one job and doesn't execute the second or third job for the same $Server.
The input comes from a CSV-file in this format:
\\domain\SHARE\Target3, 0
BELSFBRUS0131, E:\DEPARTMENTS\CBR\SHARE\Target2, 0
BELSFBRUS0131, E:\DEPARTMENTS\CBR\SHARE\Target4, 0
In the example above the script only starts 2 jobs, one for the UNC-path Target3 and one for Target2 on BELSFBRUS0131, these are executed fine. But there's no job launched for Target4to the same server... Is this maybe a restriction of Invoke-Command to only launch once to each server?
Thank you for your help guys.
Here is the important part of the script (due to max. 30.000 lines, I limited it):
Foreach ($_ in $File) {
# Starting jobs
if (($Server -eq "UNC") -or ($Server -eq "$env:COMPUTERNAME")) {
Write-Host "$(Get-TimeStamp) $env:COMPUTERNAME > Start job: local > $Server, $Target, $OlderThanDays, $LogFolder, $CleanFolders" -ForegroundColor Gray
$arrayAllJobs += Start-Job -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server, $LogFolder, $CleanFolders) -Name DelFiles
}
else {
Write-Host "$(Get-TimeStamp) $env:COMPUTERNAME > Start job: Remote > $Server, $Target, $OlderThanDays, $LogFolder, $CleanFolders" -ForegroundColor Gray
$arrayAllJobs += Invoke-Command -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server, $LogFolder, $CleanFolders) -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -AsJob -JobName DelFiles
}
}
#__________________________________________________________________________________________________________________________________
# Checking jobs
Write-Host "`n$(Get-TimeStamp) $env:COMPUTERNAME > Waiting for all jobs to finish.." -ForegroundColor Cyan; Wait-Job -Job $arrayAllJobs
Write-Host "`n$(Get-TimeStamp) $env:COMPUTERNAME > The targets were:" -ForegroundColor Cyan; $arrayAllPaths | Format-List
foreach ($Job in $arrayAllJobs) {
if ($job.State -ne 'Completed') {
# Write-Host ($Job.ChildJobs[0].JobStateInfo.Reason.Message) -ForegroundColor Red
$arrayJobError += $Job.ChildJobs[0].JobStateInfo.Reason.Message
$HTMLarrayJobError += $Job.ChildJobs[0].JobStateInfo.Reason.Message +"<br>"
}
#<# Reported success:
else {
Write-Host (Receive-Job $Job) -ForegroundColor Green
} #>
}
I suspect it related to the fact that all of your jobs are being created with the same JobName:
Invoke-Command -ScriptBlock $JobCall -ArgumentList ($Target, $OlderThanDays, $Server, $LogFolder, $CleanFolders) -ComputerName "$Server.grouphc.net" -Authentication Credssp -Credential $Credentials -AsJob -JobName DelFiles
so you're trying to create two jobs with the same name, on the same server.
I made a previous error in my script, that was the reason why the seconde server didn't arrive in the loop. I'm sorry everyone, my bad.

Stop remote service using PowerShell

I've a script that stops remote services through WMI:
(get-service -ComputerName $server_ip -Name $service).Stop()
I want to force a service after five tries. I have build a counter, but what is the command to force a stop?
If you have winRM enabled you can use the following:
Invoke-Command -ComputerName server1 -ScriptBlock {
Stop-Service $args[0] -Force } -ArgumentList $service
If by "force a stop" you mean you want to forcibly terminate (i.e. kill) the service process you could try killing the process via its PID:
$server = '1.2.3.4'
$service = 'name'
Invoke-Command -Computer $server -ScriptBlock {
param($svc)
$Error.Clear()
1..5 | % {
Stop-Service -Name $svc
if ($?) { break } # exit from loop if previous command succeeded
}
if ($Error.Count -eq 5) {
$pid = (Get-WmiObject Win32_Service -Filter "Name='$svc'").ProcessId
(Get-Process -Id $pid).Kill()
}
} -ArgumentList $service
Running the code via Invoke-Command is to avoid multiple remote connections.
This should work even for services that have the NOT_STOPPABLE flag set.