While I was working on some samples for another blog post on the PowerShell cmdlets that ships with web deploy 3 I discovered something that I think might be worth knowing about.
This blog post will first describe the problem and then present a solution for the problem.
The image above is meant to illustrate the infrastructure that I’m using and what I aim to accomplish which is:
- I’m developing ‘www.example.com’ on my laptop, pushing changes to some sort of VCS (git in my example but not important at all really).
- The build server (which is TeamCity but also not at all important) picks up the changes and as part of the build process uses a web deploy PowerShell cmdlet, Restore-WDPackage, to update the test site test.example.com with the latest bits.
- my laptop and the build server reside on the company network
- the test site reside on the hosting provider network (thus remote and not aware of our network domain/AD wise)
- I’ve set all this up locally with hyper-v on my windows 8 machine but the idea is the same as if it where for real (different domains etc.)
To set it up, the build process scenario, I started on my laptop followed the documentation from iis.net which states that you should start with creating a publish settings file.
To create such a file you’d use the New-WDPublishSettings cmdlet:
The really great thing about using the PowerShell cmdlets compared to the msdeploy.exe command-line is that you can encrypt the password in a better way, as shown on line 5.
The result is a file that contains this:
Next up I’m putting the script together using the Restore-WDPackage cmdlet that uses the publish settings file that I created I the previous step.
I tested it on my laptop and it worked just fine.
Restore-WDPackage on TeamCity
Since it worked just fine locally I was confident and committed the .ps1- and .publishsettings files to the git repository and pushed the changes so TeamCity could see them.
Bang!! And the following error appears in the logs:
Restore-WDPackage : Connected to the remote computer (“virjole-wfe1”) using the Web Management Service, but could not authorize. Make sure that you are using the correct user name and password, that the site you are connecting to exists, and that the credentials represent a user who has permissions to access the site. Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_USER_UNAUTHORIZED
I also verified the error by logging into the build server, via remote desktop, and executed the same command locally on that computer. The same error occurred.
What went wrong…it all worked just fine on my laptop?
I logged on to the build server and executed a simple/standard web deploy command, using dump on ‘Default Web Site’ using iisApp provider, via msdeploy.exe:
That worked fine so there’s nothing wrong with the connection between the two servers it appears.
The difference between the PowerShell and the msdeploy.exe way is of course the .publishsettings file and the encrypted password specifically.
Dissecting the EncryptPassword switch
I decided to look into how the password is encrypted by the PowerShell cmdlet:
From the image above (taken from the decompiled code of the cmdlet) you can see that the password is encrypted using DataProtectionScope.CurrentUser.
The protected data is associated with the current user. Only threads running under the current user context can unprotect the data.
OK, so that means that the only account that can decrypt the password is the account that created it. Since I created it on my laptop I used my own account but TeamCity’s PowerShell runner executes using the account that runs the TC agent service.
Make it work then
Since my TeamCity build agent runs under a local account on the build server I then have to re-generate the .publishfile using that account and commit that file (or the content of it) to my VCS.
My TC agent runs under the svc_TCAgent account. Run a PowerShell prompt using that account and again execute the code to generate the file which is:
…copy the output, commit, push and:
So it seemed that the old “works on my box” thingy came back to bite me once again. Lesson…never rely on your own box.