PowerShell Remote script exiting, but not exiting parent script - powershell

Below is a script we are using in TeamCity. We are sporadically getting a hung build during this step and some others similarly written. From what I've been able to find out is that the error is occurring between the two servers.
The script creates a remote session and executes on the remote machine. The remote script completes successfully, but never causes this script to exit which leads to a build step hanging.
$username = '%SvcAcct%'
$password = '%SvcAcctPwd%'
$credentials = New-Object System.Management.Automation.PSCredential `
-ArgumentList #($username,(ConvertTo-SecureString -String $password -AsPlainText -Force))
$remoteSession = New-PSSession -ComputerName %RemoteServer% -Authentication Credssp -Credential $credentials
Invoke-Command -FilePath %teamcity.build.checkoutDir%\NovoDeploy\Powershell\InstallNovo.ps1 `
-ArgumentList "C:\NovoDeploy\Installers","C:\NovoDeploy\%InstallSettingsConfigFileName%","%SvcAcctPwd%" -Session $remoteSession
#Get the exit code from the remote session so
#we can pass it through to TeamCity and fail the build.
$remoteSessionExitCode = Invoke-Command { $lastexitcode } -Session $remoteSession
exit $remoteSessionExitCode

Try using remove-pssession -$remoteSession at the end of your script.
Remove-PSSessioncloses one or more Windows PowerShell sessions (PSSessions). I'm thinking maybe your exit command is just exiting the remote powershell session you use to run the remote command and then continuing as a local powershell session after your exit. If you add remove-pssession after you assign the exitcode variable, then maybe your exitcommand will exit the local terminal as needed.
Just a theory but it's worth testing out.

Related

Executing CMD or EXE file using PSSession (remote powershell) caused Error 1603 access denied

I have the following script powershell command but it returns access denied. I assume the Error 1603 is caused by remote accessing the server. However, the $username has admin rights in the computer01 server.
To recheck if my hunch was right, I tried to test with the following and I got access denied:
Start-Process cmd -Credential $Cred
Update
The error was due to the $Cred . Removing the -Credential argument works fine.
End of Update
The commands have no problems executing directly in the computer01 machine using the cmd.exe.
I want to use cmd /c in this case as I need to get the real exit code from the SETUP.EXE installer.
See full script below:
$script = {
#Param(
# [String]$username,
# [String]$password
#)
# $Cred = New-Object System.Management.Automation.PSCredential ($username, $password)
$respfile = "$env:TEMP\test.resp"
echo 'key=value' > $respfile
$username = "$env:USERDOMAIN\$env:USERNAME"
Write-Host Hello $username
$Creds = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME" )
Start-Process cmd -Credential $Creds
#This command cannot be run due to the error: Access is denied.
# + CategoryInfo : InvalidOperation: (:) [Start-Process], #InvalidOperationException
# + FullyQualifiedErrorId : #InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand
# + PSComputerName : computer01
# cmd /c "$path\SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'"
runas /user:$Username "SETUP.EXE" /INSTALL -s /RESPFILE:"$respfile"
echo $LASTEXITCODE
# Error 1603
}
#$username = 'domain/user'
#$password = 'password'
$server = 'computer01'
$Creds = New-Object System.Management.Automation.PSCredential
$session = New-PSSession -ComputerName $server
#Invoke-Command -Session $session -Scriptblock $script -Argumentlist $username, $password
Invoke-Command -Session $session -Scriptblock $script -Credential $Creds #updated based on #postanote advise
Remove-PSSession -ComputerName $server
I have found the following similar link install-remotely but do not want to use the ENTER-PSSession command. I do not want to exit the current PSSession and remotely join again in server just to install then exit.
Any suggestions how to use only PSSession and successfully executing installers in the remote server?
As one mentioned in the comments, you don't need cmd.exe. You can use the call/invocation operator - & - to specify that the next token on the line is a command:
& "$path\SETUP.EXE" /INSTALL -s /RESPFILE:$respfile
Of course, for this to work, the parameters to SETUP.EXE need to be correct (I don't know whether that's the case or not).
Never pass plain text passwords in scripts. It exposes you to uneeded risks.
Use proper secured credentials models.
• Working with Passwords, Secure Strings and Credentials in Windows PowerShell
• quickly-and-securely-storing-your-credentials-powershell
PowerShell remoting requires the use of an implicit (New-PSSession) or explicit (Enter-PSSession) session.
• About Remote Requirements
There are only a handful of cmdlets you can use as non-Admin ir run without PSRemoting enabled.
• Tip: Work Remotely with Windows PowerShell without using Remoting or WinRM
As noted in the Powershell Help file | MS Docs link above, with PSRemoting, you must be using an account that is an admin on the remote host.
In Windows OS proper, to install software, you must be an admin and running that in an admin session.
PowerShell runs in the context of the user who started it.
If you are trying to run in another user context, that is a Windows Security boundary, and you cannot do that without PowerShell natively, you'd need other tools like MS Sysinternals PSExec. See also:
Find-Module -Name '*Invoke*' | Format-Table -AutoSize
# Results
<#
Version Name Repository Description
------- ---- ---------- -----------
...
3.1.6 Invoke-CommandAs PSGallery Invoke Command as System/User on Local/Remote computer using ScheduleTask.
...
#>
Try this refactored option...
$script = {
$Creds = (Get-Credential -Credential "$env:USERDOMAIN\$env:USERNAME" )
$respfile = 'whatever this is'
& "SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'"
Write-Output $LASTEXITCODE
}
$server = 'computer01'
$session = New-PSSession -ComputerName $server
Invoke-Command -Session $session -Scriptblock $script -Credential $Creds
Remove-PSSession -ComputerName $server
Details
# Get specifics for a module, cmdlet, or function
(Get-Command -Name Invoke-Command).Parameters
(Get-Command -Name Invoke-Command).Parameters.Keys
Get-help -Name Invoke-Command -Examples
# Results
<#
Invoke-Command -ComputerName server01 -Credential domain01\user01 -ScriptBlock {Get-Culture}
$s = New-PSSession -ComputerName Server02 -Credential Domain01\User01
$LiveCred = Get-Credential
Invoke-Command -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.exchangelabs.com/PowerShell -Credential $LiveCred -Authentication Basic
Invoke-Command -Session $s -ScriptBlock { Get-HotFix } -SessionOption $so -Credential server01\user01
Enable-WSManCredSSP -Delegate Server02
Set-Item WSMan:\Server02*\Service\Auth\CredSSP -Value $True
Invoke-Command -Session $s -ScriptBlock {Get-Item \\Net03\Scripts\LogFiles.ps1} -Authentication CredSSP -Credential Domain01\Admin01
#>
Get-help -Name Invoke-Command -Full
Get-help -Name Invoke-Command -Online
So, I was able to solve my problem.
1603 is the error thrown by the setup.exe.
Just to be sure, I manually executed first the following directly in the server using CMD and it was working!
$path\SETUP.EXE /INSTALL -s /RESPFILE:'$respfile'
I did a lot of testings. Researched and as mentioned from comments above, I did different ways to execute programs using powershell. I even used ACL to change ownership of installer directory/ files, switching to different user accounts (with different priviledges) but still getting access denied (including the Admin account).
It took days before I realized the difference in output file size of manual run in machine and the remote. The cause was the $respfile. It really is worth checking every possible reason/ scenario why there's access denied. Plus I cannot extract the setup.exe and its contents to troubleshoot.
The $respfile was created via powershell. I noticed the size created by powershell is doubled compared to a CMD size that was needed. With that, I assumed that the setup.exe reads file in UTF-8 format. I only know that it's working when triggered via CMD and not via powershell.
I suddenly bumped on this links differrent Powershell and CMD sizes and convert file content to CMD readable file - utf8. After converting the $respfile to UTF-8 format, I was able to run the exe successfully.
Hopefully, this can help others too!

PowerShell Script fails to execute batch file on Remote server

I have a PowerShell script which works fine on windows server 2016 azure VM but fails to execute the same script from my build agent which is also window server 2016 OS azure VM.
No errors get logged in PowerShell due to which i am not able to figure out what is the reasons?
Is there any Prerequisites that i need to validate or install on the server for executing this script?
Below is the script which execute batch file present on another another VM.
$Username = 'ABC'
$Password = 'XYZ'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
try {
Invoke-Command -ComputerName "ServerName" -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'C:\CI\Demo_CI.bat'"
Write-Host "done"
}
} catch {
Write-Host "error"
}
I believe what you are facing here is a Credential delegation issue, You can try enabling CredSSP in your build agent and the target "ServerName". To know more about credssp , see here, therwise you will have to use psexec in CI.

Powershell - Running remote session on intended server

So I have a server set up for remoting called "Server01" so I can use the PS2 configuration.
Problem is I want to run the ISE as PS2 on the same machine.
So I am trying:
$username = "Domain\User"
$password = "Password"
$cred = new-object -typename System.Management.Automation.PSCredential -ArgumentList $username, $password
$s=new-PSsession "Server01" -authentication Credssp -credential $cred -ConfigurationName PS2
Invoke-Command -Session $s -ScriptBlock {
}
Remove-PSSession $s
while on "Server01" and I am getting an access denied error. I have made sure "Allow Delegating Fresh Credentials" is enabled and configured properly.
I am trying to avoid running this through the Management Shell because I would like to have a scheduled task kick off this script automatically.
Any suggestions/ideas?
You don't have to use session configurations to invoke PowerShell with version 2.0 in a scheduled task.
Just use:
powershell.exe -Version 2.0
In your task definition. This is way easier and safer than trying to remote into the local machine with CredSSP.

Executing an Exe file inside Invoke-Command causes Access Denied

Using Powershell, I'm trying to connect to a remote machine and install an exe file on that system. Unfortunately I'm getting an Access is denied error when running the file. What's truly odd about this error, is that other exe's located on the same path run fine, so I'm wondering if something more cryptic could be involved?
I'm currently using this command to connect to the remote machine, upon which I'm a local admin.
$InstallFile = "\\networkshare\folder\folder\setup.exe"
$InstallParameters = "SampleParameter1 = 5"
$Server = SERVERNAME.DOMAINNAME.COM
$cred = Get-Credential
invoke-command -Computername $Server -authentication credssp -credential $cred -ScriptBlock {
$CurrentProcess = Start-Process -FilePath $InstallFile -ArgumentList $InstallParameters -Wait -PassThru
$CurrentProcess | Wait-Process
}
I'm using CredSSP which seems to be working well since it fixed this issue for other files, but this one simply refuses. Any other thoughts? I ran into a similar issue with .NET 4 and was unable to resolve that install either.
I've noticed you are using Start-Process to run your executable. According to this:
http://technet.microsoft.com/en-us/library/dd347667.aspx
there's also -Credential parameter that can be passed to it. It very well might be the case that Start-Process is not executed by the user that called Invoke-Command. Try passing Credential to your Start-Process:
invoke-command -Computername $Server -authentication credssp -credential $cred -ScriptBlock {
$CurrentProcess = Start-Process -FilePath $InstallFile - Credential $cred -ArgumentList $InstallParameters -Wait -PassThru
$CurrentProcess | Wait-Process }

Enter-PSSession is not working in my Powershell script

When I run the lines below from a script the file ends up being created on my local machine.
$cred = Get-Credential domain\DanTest
Enter-PSSession -computerName xsappb01 -credential $cred
New-Item -type file c:\temp\blahxsappk02.txt
exit-pssession
When I run each line individually from the powershell console the remote session is created correctly and the file is created on the remote machine. Any thoughts on why? Is it a timing issue is the script perhaps?
Not sure if it is a timing issue. I suspect it's more like Enter-PSSession is invoking something like a nested prompt and your subsequent commands are not executing within it. Anyway, I believe Enter/Exit-PSSession is meant for interactive use - not scripting use. For scripts use New-PSSession and pass that session instance into Invoke-Command e.g.:
$cred = Get-Credential domain\DanTest
$s = New-PSSession -computerName xsappb01 -credential $cred
Invoke-Command -Session $s -Scriptblock {New-Item -type file c:\temp\blah.txt}
Remove-PSSession $s