Powershell Script not getting failed in Jenkins - shell

I have downloaded SSH-Sessions by Joakim Svendsen which uses SSH.NET and installed the PowerShell module in the Jenkins Windows server
In Jenkins, I have the following PowerShell script:
Import-Module SSH-Sessions
$lastExitCode = 0
$devApp1 = "10.0.0.1"
$devApp2 = "10.0.0.2"
Write-Output "Deployment started in $devApp1......"
New-SshSession -ComputerName $devApp1 -Username test -Password test#123
$return = Invoke-SshCommand -ComputerName $devApp1 -Command "cd /NFS_DATA/autodeploy_scripts && echo test#123 | ./autodeploy.sh"
$return | Get-Member
if ($lastExitCode -ne 0)
{
Write-Output $lastExitCode
exit 1;
}
else
{
Write-Output $lastExitCode
exit 0;
}
The shell script contains:
#!/bin/bash
file="/NFS_DATA/autodeploy_scripts/test.log"
if [ -f "$file" ]
then
echo "$file found."
exit 0;
else
echo "$file not found."
exit 1;
fi
The problem is that the Jenkins job doesn't get failed when the file is not found. The Jenkins output is:
> Deployment started in 10.0.0.1...... Successfully connected to
> 10.0.0.01
> 10.0.0.01 had an error:
Finished: SUCCESS
After some suggestions I wrote the following PowerShell script using Posh-SSH. I'm also getting an error for this one, though it's different.
#Import-Module SSH-Sessions
Import-Module Posh-SSH
# Setup static variables
$devApp1="10.0.0.1"
$devApp2="10.0.0.2"
$username = "test"
$password = "test#123"
$command = "cd /NFS_DATA/autodeploy_scripts && echo Hybris#123 | ./autodeploy.sh"
Write-Output "Deployment started in $devApp1..."
# Setup PSCredentials
$secPasswd = ConvertTo-SecureString $password -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential ($username, $secPasswd)
echo $credentials
# Estalbish new SSH session automatically accepting new SSH keys
$session = New-SSHSession -Computername $devApp1 -Credential $credentials -Acceptkey:$true
# Invoke command to be run on/in the SSH session
$output = Invoke-SSHCommand -SSHSession $session -Command $command
Write-Output "Returned Output from the Command: "
Write-Output $output.Output
Write-Output "Last Exit Status: "
Write-Output $output.ExitStatus
Getting the error message as:
The same code works in my local laptop, but fails in the Jenkins server.
I think in Jenkins server, due to Windows security restrictions, will not store the $secpasswd that is retrieved from the PSCredential. This causes only the username to be supplied to POSH.
How can I either fix those issues? How should I hardcode the password?

As you've never stated where those commands are coming from, I'm going to assume you're using Posh-SSH. By looking at this article about it, the solution would probably be:
$dev_app1="10.00.00.01"
$dev_app2="10.00.00.02"
echo "Deployment started in $dev_app1......"
Import-Module SSH-Sessions
New-SshSession -ComputerName $dev_app1 -Username test -Password test#123
$result = Invoke-SshCommand -ComputerName $dev_app1 -Command "cd /NFS_DATA/autodeploy_scripts && echo test#123 | ./autodeploy.sh"
Write-Output "Returned Output from the Command: "
Write-Output $result.Output
Write-Output "Last Exit Status: "
Write-Output $result.ExitStatus
if($result.ExitStatus -ne 0){
exit $result.ExitStatus;
}
The if could be left out, it's just there for demonstration purposes. After all the exit status would be 0 otherwise.
The correct way to use Get-Member to get information about $result (in case this does not work) would be: $result | Get-Member. That will output the general attributes of whatever kind of object $result is.
As it would appear you're running this. You would need to run the following to get the objects:
$result = $SshSessions."$dev_app1".RunCommand('cd /NFS_DATA/autodeploy_scripts && echo test#123 | ./autodeploy.sh')
You'd use this instead of the Invoke-SshCommand and would need to change $result.Output to $result.Result.

Related

Running a powershell from rundeck(linux) display different result

I'm trying to run a powershell script from rundeck(linux), If I run the script locally[Deletes some files from multiple terminal servers](Windows server) it is working as expected however if I call it from rundeck server(winrm configured) it seems that the script cant access the remote folders I'm trying to access.
I tried running the script using the same user but still shows different result.
Script bellow:
$userAD = "someuser"
$servers = Get-Content C:\TSList.csv
$Folder = "c$\Users\$userAD\"
$TSFolderShare = "\\sharepath"
Write-Output "#####Start of script#####"
Write-output `n
Write-output "Checking if $userAD user profile exist in Terminal servers..."
sleep -seconds 1
foreach ($server in $servers) {
Test-Path "\\$server\$Folder" -PathType Any
Get-ChildItem "\\$server\$Folder"
if (Test-Path "\\$server\$Folder" -PathType Any) {
Write-output "Resetting user profile in $server.."
Get-ChildItem "\\$server\$Folder" -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
sleep -seconds 1
Write-output "Done."
if( (Get-ChildItem "\\$server\$Folder" | Measure-Object).Count -eq 0)
{
Write-output "Done."
}
}
else
{
Write-output "Resetting user profile in $server.."
sleep -seconds 1
Write-output "User profile does not exist in $server."
#Write-output "\\$server\$Folder does not exist in $server!" -ForegroundColor Red
}
}
EDIT: It seems my problem is when running my script from another script with RunAS.
Below I'm trying to access a folder from another server using ps script, but since I want to integrate this to Rundeck I need to call my ps script from my linux server using python. I did a test running the ps script directly and calling the test path script using another script with RunUs using the same user I used to run the script manually
Scenario 1
Running PS script via separate PS script with RunAS(my_account)
$username = "my_account"
$password = "my_password"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
Invoke-Command -FilePath "C:\testpath.ps1" -Credential $cred -Computer localhost
(C:\testpath.ps1) Content below:
Test-Path "\\server\c$\Users\myaccount\"
result:
Access is denied
+ CategoryInfo : PermissionDenied: (\server\c$\Users\myaccount:String) [Test-Path], UnauthorizedAccessException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.TestPathCommand
+ PSComputerName : localhost
False
Scenario 2
Running C:\testpath.ps1 directly as my_account
Test-Path "\\server\c$\Users\myaccount\"
result:
True
I used session configuration in powershell to solve the issue. This way allows you to tie a credential to a PowerShell session configuration and reuse this configuration for all future connections.
https://4sysops.com/archives/solve-the-powershell-multi-hop-problem-without-using-credssp/
Thanks a lot!
You're facing a double-hop issue with Rundeck and Powershell, here the explanation. That's asked before, take a look a this, and here a good workaround. Also this to solve it.

Running command on freeSSHD server with WinSCP fails with "Your shell is probably incompatible with the application (BASH is recommended)"

I am using below script to Verify checksum of a remote file against a local file. The server I installed on my machine is freeSSHd.
When I tried to execute the below script using PowerShell ISE I get an error message saying:
Your shell is probably incompatible with the application (BASH is recommended)
I've granted shell access in the FreeSSHd Server User properties:
Script:
param (
# Use Generate URL function to obtain a value for -sessionUrl parameter.
$sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx#example.com/",
[Parameter(Mandatory = $True)]
$localPath,
[Parameter(Mandatory = $True)]
$remotePath,
[Switch]
$pause = $False
)
try
{
Write-Host $localPath -foregroundcolor Gray
# Calculate local file checksum
$localChecksum = ((CertUtil -hashfile $localPath SHA1)[1] -replace " ","")
# Write-Host "Local Checksum:"
Write-Host $localChecksum
# Load WinSCP .NET assembly
#Add-Type -Path (Join-Path $PSScriptRoot "WinSCPnet.dll")
[Reflection.Assembly]::LoadFrom("\\c:\Program Files (x86)\WinSCP\WinSCPnet.dll") | Out-Null
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.ParseUrl($sessionUrl)
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
Write-Host $remotePath -foregroundcolor Gray
# Calculate remote file checksum
$sha1Command = "bash sha1sum -b $remotePath | awk '{print `$1}'"
$result = $session.ExecuteCommand($sha1Command)
$result.Check()
$remoteChecksum = $result.Output;
#$remoteChecksum =
[System.BitConverter]::ToString($session.CalculateFileChecksum("sha-1", $remotePath))
# Write-Host "Remote Checksum:"
Write-Host $remoteChecksum
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
# Compare cheksums
if ($localChecksum -eq $remoteChecksum)
{
Write-Host
Write-Host "Match" -foregroundcolor "green"
$result = 0
}
else
{
Write-Host
Write-Host "Does NOT match" -foregroundcolor "red"
$result = 1
}
}
catch [Exception]
{
Write-Host $_.Exception.Message
$result = 1
}
# Pause if -pause switch was used
if ($pause)
{
Write-Host "Press any key to exit..."
[System.Console]::ReadKey() | Out-Null
}
exit $result
FreeSSHd server does not support any "bash". Its "shell" is Windows cmd.exe.
Your code cannot work. Windows cmd.exe is not compatible with WinSCP.
Moreover FreeSSHd is pretty buggy, do not use it.
You should use another Windows SSH server.
You can use Windows build of OpenSSH. It would allow you to execute a PowerShell script on the server to calculate the checksum.
If you install Windows Subsystem for Linux, you may even get the sha1sum (but I'm not sure).
You can use Cygwin, if you need to simulate *nix environment on Windows.
You can use Bitvise SSH Server for personal use for free. Its SFTP server supports checksum calculation on its own, so you would be able to use WinSCP Session.CalculateFileChecksum method directly.
There are lot of other options.

'Run a program' option in windows service pannel for failure recovery

I am trying to run a perl script whenever there is a service crash. The perl script intends to restart the service and send a mail to all the developers.
I have used windows recovery options for that, where it has an option to run a program . I have filled the required details in the command line option but the script doesn't seem to get executed. Can you please help me by sharing your knowledge on this?
Recovery tab configuration
I have tried with Restart service option and that is working fine but the run a program isn't executing the script. Am I missing something?
Any comment on this will be helpful.
I recently implemented a recovery option to run a powershell script that attempts to restart the service a defined number of times and sends an email notification at the conclusion, it also attaches a txt file with recent relevant logs.
After several attempts (and despite all the other things I have seen) The configuration of fields on the recovery tab in services is as follows:
Program: Powershell.exe
**Not C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe
Command line parameters: -command "& {SomePath\YourScript.ps1 '$args[0]' '$args[1]' '$args[n]'}"
eg: -command "& {C:\PowershellScripts\ServicesRecovery.ps1 'Service Name'}"
**The $args are parameters that will be passed to your script. These are not required.
here is the powershell script:
cd $PSScriptRoot
$n = $args[0]
function CreateLogFile {
$events = Get-EventLog -LogName Application -Source SomeSource -Newest 40
if (!(Test-Path "c:\temp")) {
New-Item -Path "c:\temp" -Type directory}
if (!(Test-Path "c:\temp\ServicesLogs.txt")) {
New-Item -Path "c:\temp" -Type File -Name "ServicesLogs.txt"}
$events | Out-File -width 600 c:\temp\ServicesLogs.txt
}
function SendEmail {
$EmailServer = "SMTP Server"
$ToAddress = "Name#domain.com"
$FromAddress = "Name#domain.com"
CreateLogFile
$Retrycount = $Retrycount + 1
send-mailmessage -SmtpServer $EmailServer -Priority High -To $ToAddress -From $FromAddress -Subject "$n Service failure" `
-Body "The $n service on server $env:COMPUTERNAME has stopped and was unable to be restarted after $Retrycount attempts." -Attachments c:\temp\ServicesLogs.txt
Remove-Item "c:\temp\ServicesLogs.txt"
}
function SendEmailFail {
$EmailServer = "SMTP Server"
$ToAddress = "Name#domain.com"
$FromAddress = "Name#domain.com"
CreateLogFile
$Retrycount = $Retrycount + 1
send-mailmessage -SmtpServer $EmailServer -Priority High -To $ToAddress -From $FromAddress -Subject "$n Service Restarted" `
-Body "The $n service on server $env:COMPUTERNAME stopped and was successfully restarted after $Retrycount attempts. The relevant system logs are attached." -Attachments c:\temp\ServicesLogs.txt
Remove-Item "c:\temp\ServicesLogs.txt"
}
function StartService {
$Stoploop = $false
do {
if ($Retrycount -gt 3){
$Stoploop = $true
SendEmail
Break
}
$i = Get-WmiObject win32_service | ?{$_.Name -imatch $n} | select Name, State, StartMode
if ($i.State -ne "Running" -and $i.StartMode -ne "Disabled") {
sc.exe start $n
Start-Sleep -Seconds 35
$i = Get-WmiObject win32_service | ?{$_.Name -imatch $n} | select State
if ($i.state -eq "Running"){
$Stoploop = $true
SendEmailFail}
else {$Retrycount = $Retrycount + 1}
}
}
While ($Stoploop -eq $false)
}
[int]$Retrycount = "0"
StartService

failed to join domain with automated powershell script -- "unable to update password"

I'm trying to add a host to the domain with a Powershell script. The script fails with the error below when it's called via CloudFormation or Ansible. It's succeed when I run it manually on the host.
I suspect I'm doing something wrong with users (I run as admin manually) so I've tried to force it to run as admin all the time. Unfortunately that didn't work either.
Has anyone seen this issue before?
Error:
> [DEBUG] Command 4-add-to-domain output: Add-Computer : Computer
> 'WIN-xxxxx' failed to join domain
>
> 'aws.cloud.bp.com' from its current workgroup 'WORKGROUP' with
> following error
>
> message: Unable to update the password. The value provided as the
> current
>
> password is incorrect.
>
> At line:1 char:1
>
> + Add-Computer -DomainName $domain -Credential $credential -OUPath $ouPath
>
> -Restar ...
>
> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ~~~
>
> + CategoryInfo : OperationStopped: (WIN-K9DU7TO9331:String) [Add-
>
> Computer], InvalidOperationException
>
> + FullyQualifiedErrorId : FailToJoinDomainFromWorkgroup,Microsoft.PowerShe
>
> ll.Commands.AddComputerCommand
PS1:
if ((gwmi win32_computersystem).partofdomain -eq $true)
{
write-host "already in domain"
}
else
{
$domain = $domainname
$password = $password | ConvertTo-SecureString -asPlainText -Force
$username = $uid
$credential = New-Object System.Management.Automation.PSCredential($username,$password)
$ouPath = $oupath
$cmd = 'Add-Computer -DomainName $domain -Credential $credential -OUPath $ouPath -Restart'
$runas = [Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$log = "not running as admin"
$log | out-file -Filepath $logger -append
} else {
$log = "running as admin, about to run $cmd"
$log | out-file -Filepath $logger -append
Invoke-Expression -Command $cmd
}
}
The answer was simpler than I thought: when the script's running via the automation tool (either CloudFormation or Ansible) it was running as local admin. However, manually it's running as domain\admin. therefore what I needed to do is call it with username $username = "mydomain\my-domain-user" rather than simply "my-domain-user".
Hope this will help for people hitting the same problem...
Taken from: http://www.gi-architects.co.uk/2017/01/powershell-add-computer-error-when-executed-remotely/
The root of the problem is (given that your password is correct) when running things interactively the domain is pre-appended and as such you only need to provide the user. But in a non-interactive environment, the domain is not known as such it’s a very simple fix, make sure you either include the short domain names like “contoso\DMAdmin” or the full FQDN “DMAdmin#contoso.com.
Have you tried the password without the ConvertTo-SecureString? Just to test it? I had some issues with that when I was trying to remotely change local admin passwords on my domain. From what I could gather, when you convert it to a secure string and then assign it as a variable, the actual password seems to get lost. Now, I'm a real newbie with powershell, but I could only get ConvertTo-SecureString to work when it was called directly, not as a variable though.
I'm not sure why it wold work when you run it manually, but that's what I would try first to try and isolate the issue. If I'm way off feel free to correct me.

PowerShell Closing open sessions

I'm working on a large script where I run a Foreach loop, define variables in that loop and afterwards check if the $Server variable is pingable and if it is remotely accessible.
For this I use the following functions coming from the PowerShell help:
# Function to check if $Server is online
Function CanPing ($Server) {
$error.clear()
$tmp = Test-Connection $Server -ErrorAction SilentlyContinue
if ($?) {
Write-Host "Ping succeeded: $Server"; Return $true
}
else {
Write-Host "Ping failed: $Server."; Return $false
}
}
# Function to check if $Server is remotely accessible
Function CanRemote ($Server) {
$s = New-PSSession $Server -Authentication Credssp -Credential $Credentials -Name "Test" -ErrorAction SilentlyContinue
if ($s -is [System.Management.Automation.Runspaces.PSSession]) {
Enter-PSSession -Session $s
Exit-PSSession
Write-Host "Remote test succeeded: $Server."; Return $true
}
else {
Write-Host "Remote test failed: $Server."; Return $false
}
}
# Execute functions to check $Server
if ($Server -ne "UNC") {
if (CanPing $Server) {
if (-Not (CanRemote $Server)) {
Write-Host "Exit loop REMOTE" -ForegroundColor Yellow
continue
}
}
else {
Write-Host "Exit loop PING" -ForegroundColor Yellow
continue # 'continue' to the next object and don't execute the rest of the code, 'break' exits the foreach loop completely
}
}
Every time when I run this code, there is a process created on the remote server called wsmprovhost.exe. This process represents the PowerShell session, if the info I found on the web is correct. However, when doing Get-PSSession $Server there are no open sessions displayed in the PowerShell ISE, even though the processes are visible on the remote server and can only be killed with the Task Manager.
When I run this code often the limit of open sessions is reached because every time a new process wsmprovhost.exe is added to the $Server and the command errors out. I've tried to solve this by adding Exit-PSSessionto the code, but it doesn't close the session.
Any help or ideas are more than welcome.
The problem is that Enter-PSSession. Enter-PSSession can only be used interactively, you can't use it in a script. I'd suggest something more like this:
# Function to check if $Server is remotely accessible
Function CanRemote ($Server) {
Try {
$s = New-PSSession $Server -Authentication Credssp -Credential $Credentials -Name "Test" -ErrorAction Stop
Write-Host "Remote test succeeded: $Server."
$true
Remove-PSSession $s
}
Catch {
"Remote test failed: $Server."
$false
}
}
If I have understood correctly, Your remote ps-session are not getting closed.
To my understaning, Get-PSSession will show the session till your local session
is alive (I mean the session you created the remote ps-session) but once your local session
ends Get-PSSession will not show them cause they are no more live on your computer
rather on the remote system (or) they are no more in local session scope.
You can get the session using the command
Get-PSSession -ComputerName server_name
If you want to remove them you can do like
Get-PSSession -ComputerName server_name | Remove-PSSession
Even After executing the below command also, if you are not able to create session
Get-PSSession -ComputerName server_name | Remove-PSSession
Please, Restart the service Windows Remote Management (WS-Management) in the target machine.

Resources