1

I'm using Terraform with Google Cloud to create Windows Server Core 2019 hosts for use with Jenkins. I want to install some software like Git, OpenJDK, and others using Scoop, and start the Jenkins Agent JAR as a system service running under a local jenkins user.

I'm setting them up using PowerShell scripts provided via metadata keys like sysprep-specialize-script-ps1 and windows-startup-script-ps1:

https://cloud.google.com/compute/docs/startupscript#providing_a_startup_script_for_windows_instances

My problem is that I'm creating local users using Powershell like so:

New-LocalUser -Name $Username `
    -Description $Description `
    -Password $Password `
    -PasswordNeverExpires `
    -AccountNeverExpires

And I create a Jenkins Agent service using Windows Service Wrapper: https://github.com/winsw/winsw

But when I try to run it without logging into the Jenkins user first I get back:

2020-08-26 14:49:57,760 INFO  - Starting the service with id 'JenkinsAgent'
2020-08-26 14:49:57,823 FATAL - WMI Operation failure: ServiceLogonFailure
WMI.WmiException: ServiceLogonFailure
   at WMI.WmiRoot.BaseHandler.CheckError(ManagementBaseObject result)
   at WMI.WmiRoot.InstanceHandler.Invoke(Object proxy, MethodInfo method, Object[] arguments)
   at WinSW.Program.<Run>g__Start|2_2(<>c__DisplayClass2_0& )
   at WinSW.Program.Run(String[] argsArray, IWinSWConfiguration descriptor)
   at WinSW.Program.Main(String[] args)

This issue does not happen if I first log into the jenkins user using RDP, which creates the user profile on first login. I assume that's what allows the service to start correctly.

I'm trying to figure out how I can create a user and their profile without having to manually log into that user so the service can start correctly. The setup and startup PS scripts are running as SYSTEM user, which might be the reason why using something like Start-Process, Invoke-Command, or Start-Job with -Credential flag to run a command as jenkins user to let its profile be created fails.

I've had issues trying to run a command or just exit as jenkins user like so:

[localhost] The background process reported an error with the following message: .
    + CategoryInfo          : OpenError: (localhost:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : 2100,PSSessionStateBroken

What am I doing wrong?

Is there some better way of achieving what I'm trying to do?

How can I create a local user with its profile so that the service I create starts?

  • Does this answer your question? [How can I programmatically cause a new Windows user's profile to be created?](https://serverfault.com/questions/946882/how-can-i-programmatically-cause-a-new-windows-users-profile-to-be-created) – Swisstone Aug 31 '20 at 11:22
  • Were you able to solve this ? Did the @Swisstone's link helped you in any way ? – Wojtek_B Nov 26 '20 at 13:32

1 Answers1

1

Based on replies from a linked question there are three ways (that look most promising):

  1. Use CreateProfile API

  2. Use Powershell As described in this answer - you will find example on GitHub - in this case you will be able to define home directory path. Part of code which defines profile path:

    $methodName = 'UserEnvCP'
    $script:nativeMethods = @();

    Register-NativeMethod "userenv.dll" "int CreateProfile([MarshalAs(UnmanagedType.LPWStr)] string pszUserSid,`
      [MarshalAs(UnmanagedType.LPWStr)] string pszUserName,`
      [Out][MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszProfilePath, uint cchProfilePath)";

    Add-NativeMethods -typeName $MethodName;

    $localUser = New-Object System.Security.Principal.NTAccount("$UserName");
    $userSID = $localUser.Translate([System.Security.Principal.SecurityIdentifier]);
    $sb = new-object System.Text.StringBuilder(260);
    $pathLen = $sb.Capacity;
 
    Write-Verbose "Creating user profile for $Username";
    try
    {
        [UserEnvCP]::CreateProfile($userSID.Value, $Username, $sb, $pathLen) | Out-Null;
    }
    catch
    {
        Write-Error $_.Exception.Message;
        break;
    }
  1. Use psexec utility This looks like a straightforwad method but I'm not sure If it will Ansible. psexec.exe -u foobar -p Abcd123! cmd.exe /c exit Here's more info about psexec tool.
Wojtek_B
  • 931
  • 3
  • 12
  • Thanks for your answer. I have also tried using the [script you linked](https://gist.github.com/crshnbrn66/7e81bf20408c05ddb2b4fdf4498477d8#file-user-profile-psm1) and it worked fine with some adjustments, but ultimately I've given up that approach in favor of enabling OpenSSH using [this script](https://github.com/status-im/infra-tf-google-cloud/blob/master/setup.ps1) and then provisioning users [using Ansible](https://github.com/status-im/infra-role-bootstrap-windows/blob/master/tasks/users/user.yml). – Jakub Sokołowski Nov 27 '20 at 14:38
  • Thanks for confirming :) If you think my answer helped you in any way I'd appreciate if you accepted it :) – Wojtek_B Nov 30 '20 at 07:37