WiX: installer fails in ConfigureUsers action when installing from remote computer - powershell

I have a WiX MSI installer for an ASP.NET website that runs on my_server. The package is installed via a very simple Powershell script install.ps1 that just calls msiexec with some parameters.
The problem
When I run install.ps1 directly on my_server, everything is fine. But when I want to run install.ps1 on my_server from a remote machine (e.g. build_server), the installation fails with error code 1603 and the MSI install log reveals the the following error:
Action start 14:22:30: ConfigureUsers.
ConfigureUsers: Error 0x80070005: failed to add/remove User actions
CustomAction ConfigureUsers returned actual error code 1603
Any suggestions?
Extra information
I run install.ps1 remotely with the following command:
Invoke-Command -ComputerName my_server -ScriptBlock { path\to\install.ps1 } -Authentication Negotiate
I use the same user credentials on both my_server and build_server.
In the WiX definition, the website is set up with a specific user account for the app pool, like this:
<Component Id="AppPoolCmp"
Guid="a-fine-looking-guid"
KeyPath="yes">
<util:User Id="AppPoolUser"
CreateUser="no"
RemoveOnUninstall="no"
Name="[APP_POOL_IDENTITY_NAME]"
Password="[APP_POOL_IDENTITY_PWD]"
Domain="[APP_POOL_IDENTITY_DOMAIN]">
</util:User>
<iis:WebAppPool Id="AppPool"
Name="[APP_POOL_NAME]"
ManagedPipelineMode="Classic"
ManagedRuntimeVersion="v4.0"
Identity="other"
User="AppPoolUser">
<iis:RecycleTime Value="5:00" />
</iis:WebAppPool>
</Component>

This is likely to be the double hop issue, your credentials are not valid beyond the scope of the first server.
Can you do the command with the option:
-Authentication CredSSP
Rather than Negotiate.
You will also need to specify credentials manually using the -Credentials flag as well as set up the client and server for CredSSP:
Enable-WSManCredSSP -Role Client -DelegateComputer HOSTNAME -Force
Enable-WSManCredSSP -Role Server -Force
The steps are explained in more detail here.

Related

Can't enter remote powershell 7.1 session

Been able to do it against Microsoft.PowerShell (5.1), but today I hit a known issue on 5.1 with remote Copy-Item so I installed PowerShell 7 on the remote server (checking "Enable Remoting" in the installer) and am trying to get it working.
$securePassword = ConvertTo-SecureString -AsPlainText -Force -String $Password
$credential = New-Object -TypeName system.management.automation.pscredential -ArgumentList $Username, $securePassword
$session = New-PSSession $targetMachineHostName -Credential $credential -ConfigurationName "Microsoft.PowerShell"
Enter-PSSession $session
Above works. But if I change ConfigurationName to "PowerShell.7.1.0" I get:
[myserver.com.au] Connecting to remote server myserver.com.au failed with
| the following error message : <f:WSManFault
| xmlns:f="http://schemas.microsoft.com/wbem/wsman/1/wsmanfault" Code="2689860592"
| Machine="myserver.com.au"><f:Message><f:ProviderFault provider="PowerShell.7.1.0"
| path="C:\Windows\system32\PowerShell\7.1.0\pwrshplugin.dll"></f:ProviderFault></f:Message></f:WSManFault> For more information, see the about_Remote_Troubleshooting Help topic.
On the remote server I've run enable ps remoting in a 7.1 powershell so if I run Get-PSSessionConfiguration it returns a bunch of configurations, including the following:
Name : PowerShell.7.1.0
PSVersion : 7.1
StartupScript :
RunAsUser :
Permission : NT AUTHORITY\INTERACTIVE AccessAllowed, BUILTIN\Administrators AccessAllowed, BUILTIN\Remote
Management Users AccessAllowed
The dll the error refers to exists on the machine.
The user credentials I'm using are for a Local User on the remote machine that isn't an Administrator, but belongs to the Remote Management Users group.
Also worth noting from the remote machine itself (as a different Adminstrator local account, I can start a session to localhost).
After making the user an Administrator I was able to connect, but I'd gone to great lengths earlier to make non-Adminstrator possible on 5.1.
Out of interest, I tried giving the user Full Control to C:\Windows\system32\PowerShell\7.1.0 and then I could connect...
Still would love to know what's going on though and whether I'm doing the right thing or minimum permissions required.
It seems like the minimum security permissions to the folder are:
Read & Execute
List folder contents
Read
Write
Write is bizarre, but without it I get that error. I've assigned those permissions to the "Remote Management Users" group.
Docs here touch a little bit on v5.1 vs v7, and then link to here mentioning an install script so maybe something has fallen through the cracks.
I was getting the same error. I installed PowerShell 7 from Microsoft Store and then ran Enable-PSRemoting. I got this error so I uninstalled it and reinstalled it from WinGet which uses the MSI. That didn't work either. I tried running Enable-PSRemoting again, but nothing changed.
I ran Install-PowerShellRemoting.ps1 and it gave me two errors about things already existing and did not fix the problem. However, I was able to resolve the problem by doing the following:
Delete the PowerShell 7 plugins: Remove-Item 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\PowerShell.7','HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\PowerShell.7.1.1'.
Run Install-PowerShellRemoting.ps1 again.
I'm not sure what the difference was, but deleting and allowing the script to generate it again fixed it for me.

TeamCity Remote Powershell Access Denied Suddenly

Disclaimer: I am not a DevOps guy so please forgive any ignorance. I'm learning this stuff to expand my understanding.
I've enabled remote Powershell on a Windows Server 2019 instance in order to stop/start scheduled tasks during deployment of files from my build server (also Windows Server 2019).
I followed the below steps in an Administrator Powershell as the Adminstrator user on the remote server:
1. Enable RSRemoting.
2. Remove existing listener.
3. Create self-signed certificate and export to crt file.
$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "<subdomain.domain.com>"
Create listener.
Create firewall rules to allow secure PSRemoting and disable unsecure connections.
Copy certificate to build server.
Import certificate on build server.
From the build server, I've tested the configuration using the following commands in Powershell:
$username = 'Administrator'
$pass = ConvertTo-SecureString -string '<password here>' -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $pass
Invoke-Command -ComputerName <subdomain.domain.com> -UseSSL -ScriptBlock {whoami} -Credential $cred
Which responds nicely with win-<some stuff>\administrator. However, when I execute a remote Powersehll command from within a TeamCity build step, I get a big ugly Connecting to remote server <subdomain.domain.com> failed with the following error message : Access is denied..
The weird part is, this worked two days ago and I have several builds that were able to complete all remote operations. From this morning, it's just stopped working - poof!
If I fudge the credentials, I do get an incorrect username/password error so it is definitely reaching the server.
Another interesting find is that if I run
[bool](Test-WSMan)
on the remote server, I get True returned, but if I run the same command with -ComputerName <subdomain.domain.com> on the build server, I get
WinRM cannot complete the operation. Verify that the specified computer name is
valid, that the computer is accessible over the network, and that a firewall exception for the WinRM service is enabled and allows access from this computer. By default, the WinRM firewall exception for public profiles limits
access to remote computers within the same local subnet. returned.
Both the remote host and build server are logged on as the default Administrator.
Any ideas?
After more research and calling in a few favours, I was advised to tweak the TeamCity Build Agent and TeamCity Server services. These need to Log On As a User and not Local System. I can't explain how my previous settings worked. The Access is denied error I experienced has nothing to do with the Remote Powershell configuration mentioned above.

Powershell remoting - cannot execute an exe as another user

I've a commandline program (c#) that encrypts config files based on machine key.
A powershell script copies the build to a Target Server, modifies configs accordingly and installs windows services.
All the windows services run as local system account (standard user, non-admin) - let's call this account "locuser".
The Target Server is a Win 2012 R2 Server. All of the above is achieved by PS remoting from the Build Server to this Target server.
Now, I need to run the encrypt commandline program as "locuser", so that the program can use the account specific key to do the encryption.
I know that this can be easily achieved by calling Start-Process cmdlet with -Credentials parameter. Well, here's the catch, the above works fine, if I remote in (RDP) to the Target Server and then run the Start-Process .... -Credential $cred from a Powershell Console.
However, I need this to be working while I remote-in (using my scripts) to the TargetServer whilst deploying. When I remote-in to the TargetServer I use credentials that has Admin privileges.
I've tried the following
I've granted "locuser" both "Full Control" and "Invoke (Execute)" permissions by using the Set-PSSessionConfiguration -Name Microsoft.PowerShell -ShowSecurityDescriptorUI command. I've run this command for both Microsoft.Powershell and Microsoft.Powershell32 - Still get Access Denied
I've edited the "Local Security Policy"->"Local Policies"->"User Rights Assignment"->Impersonate a client after authentication - and added both the Admin account (that I login with) and the "locuser" account - Still get Access Denied
I've also granted locuser admin rights - Still get Access Denied
I'm pretty sure, there is some configuration on the PS Remoting Side of things that I'm missing out but can't figure out what - because all Powershell throws me is a Access Denied error (see screenshot) with little to no useful information to troubleshoot further.
Also, checked Event logs for any traces but to no avail.
You've fallen prey to the dreaded Double Hop. Basically you're authenticating from computer A to computer B, then trying to authenticate again from computer B to computer C (which also happens to be B in this case).
If at all possible, you would be better off ending the session and starting a new one with the locuser credentials, then just calling Start-Process. Another, more messy approach is to use schtasks.
I can tell you how to do it in the same session but it's a bit messy and very complicated, and should only be a last resort:
On the originating server (Build Server):
Run the command Enable-WSManCredSSP -Role Client -Delegate [name] where [name] is an IP or DNS address / range including any target servers (eg "192.168.1.*")
Open GPEdit.msc, navigate to Computer Configuration\Administrative Templates\System\Credentials Delegation and check that the rules Allow delegating fresh credentials and Allow delegating fresh credentials with NTLM... are enabled and include [name]
On the Target Server:
Run the command Enable-WSManCredSSP -Role Server
Running the command:
Invoke-Command [targetserver] [-Credential $cred] -Scriptblock {
## do stuff
Invoke-Command . -Credential $locusercred -Authentication Credssp -ScriptBlock {
Start-Process -FilePath $sc #etc
}
}
Some things to be aware of:
Firstly I used this setup to create a local session, then remote from there (so A-A-B instead of A-B-B) so the Group Policy stuff might be in the wrong place but pretty sure it's right.
Secondly I found that credentials are a pain to get working in sessions (in this case $locusercred). I did get it going natively but weirdly it suddenly couldn't decrypt the securestring. I ended up saving a securestring with a defined key to the registry so it can always be decrypted from any account, you may need to come up with your own solution there.
All this stuff is explained in the free eBook "The Secrets of PowerShell Remoting", if you go for the double-hop approach I recommend giving it a read.

Cannot find service when attempting to remotely stop via Powershell / MSBuild

I have a task to deploy two Windows services created using Topshelf to a test server as part of our continuous integration build process.
My MSBuild target file is as follows:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Condition="'$(ConfigurationName)'=='Release'" Name="StopService">
<Exec Command="powershell.exe -NonInteractive -executionpolicy Unrestricted -command "& { &&apos;.\ServiceStop.ps1&apos; } "" ContinueOnError="true" />
</Target>
</Project>
This executes a Powershell script (well, a couple of lines) situated within the same folder within the project called ServiceStop.ps:
$service = get-service -ComputerName MyServerName -Name 'MyServiceName'
stop-service -InputObject $service -Verbose
The problem
When I queue a new build from within TFS, the script does successfully execute; however, the get-service command fails to find the service in question - despite the fact that it is definitely there and running. The specific error from the build log is as follows:
Get-Service : Cannot find any service with service name 'MyServiceName' (TaskId:198)
When the script is run locally from my machine, the service on the remote machine is found and stopped successfully, making me think it is some sort of permissions issue.
What I've tried
I have very limited experience with Powershell. I read that credentials could be stored within a Powershell object like so:
$pw = Read-Host -AsSecureString "Enter password"
$pw | ConvertFrom-SecureString | Out-File -Path .\storedPassword.txt
$password = get-content .\storedPassword.txt | convertto-securestring
$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist "myAdminAccountName",$password
However, it would appear that get-service does not have any method to pass credentials to it.
I also experimented with using PSExec to remotely start and stop the service, but ran into similar issues.
Some questions I reviewed
Using PowerShell credentials without being prompted for a password
Powershell stop-service error: cannot find any service with service name
Powershell Get-WmiObject Access is denied
Saving credentials for reuse by powershell and error ConvertTo-SecureString : Key not valid for use in specified state
I have spent more time on this issue than I can really afford, so would appreciate any help / guidance / comments that may help.
Thank you!
UPDATE
I was able to confirm that the Powershell script was receiving information from the MSBuild task, as the log showed Powershell output.
However, I ran out of time to find a solution and instead worked around the issue by dropping the updated services binaries onto the target server and wrote a Powershell script that installed them from there.
Thanks a lot to those that commented on the issue.
It appears that nothing is being passed from the MSBuild target file to the powershell script. You are defining the name of the service involved via ' marks, so its taking that rather than what the MSBuild target file is doing.
I would suggest you find out how to pass this variable, otherwise the script won't be able to pick this up correctly.
I'm making a complete stab in the dark, but your service name needs the TopShelf instance name including when you call get-service.
For example your service might be called "MyWindowsService" but what you need to programmatically look for is "MyWindowsService$default"

Orchestrator won't run PowerShell Cloud Exchange task

I'm having a problem getting a PowerShell script which queries objects in a cloud-based Exchange resource to work in an Orchestrator runbook.
The PowerShell script (which works correctly from my desktop computer's command line and when stepping through it in ISE) sets up a remote management session to the cloud and looks like this:
try
{
$user = "username#domain.com"
$pword = convert-toSecureString -string "password" -asplaintext -force
$creds = new-object -typename system.management.automation.pscredential -argumentlist $user, $pword
$o365 = new-pssession -configurationname Microsoft.Exchange -connectionuri https://ps.outlook.com -credential $creds -authentication basic - allowredirection
import-pssession $o365 -allowclobber -prefix o365
get-o365Mailbox 'Doe, John'
}
catch
{
throw $_.exception
}
As I mentioned, it runs fine when I step through it in the editor on my desktop but when executed inside the Orchestrator runbook it fails on the "import-pssession" command (because the $o365 is never set).
I've taken the PowerShell script and run it manually on the actual runbook server and it works there as well as it does on my own desktop -- it's only when run inside of an Orchestrator runbook that it won't function. I only have a few weeks experience with Orchestrator and didn't know I'd run into a problem like this so quickly -- I am trying to run the script in a "Run .Net Script" activity with the language set to "Powershell," which I believe is the recommended method.
I've tried saving the script as a file on the runbook server and then used the "Run Program" activity to run PowerShell with this file (recommended by someone during my searching) and that doesn't work either.
Is the Orchestrator service account that's running the script a member of the Exchange RBAC role groups? If not, it won't be allowed to connect to those Exchange management sessions.
The problem turned out to be related to the client's firewall and proxy settings for the service account they set up to be used by Orchestrator. They (the clients) would not grant the service account Internet access as a matter of policy.
A couple of different solutions came up: One was installing the PowerShell integration pack from CodePlex and using that -- the CodePlex PowerShell activity allowed me to explicitly set the security context of the activity, which let me get around their firewall issue by running the activity under an account which did have Internet access.
The second solution was installing the Exchange Admin integration pack and configuring a connection to the cloud host. Using the "Run Exchange PowerShell Command" activity rather than the more generic "Run .NET script" activity also allowed the code to work as expected.
Orchestrator is still x86 and the commands in your script will only run in x64.
Test this in your x86 ISE and see the same failure.
My workaround is to call the script using the "Run Program" activity within the System activities list.:
Program execution
Computer = I always start with initialize activity and then subscribe to the computer here
Program path: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Parameters: full path to the .ps1 of your script
Working folder: c:\temp