github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/cloudconfig/powershell_helpers.go (about)

     1  // Copyright 2014, 2015 Canonical Ltd.
     2  // Copyright 2014, 2015 Cloudbase Solutions
     3  // Copyright 2012 Aaron Jensen
     4  //
     5  // Licensed under the AGPLv3, see LICENCE file for details.
     6  //
     7  // This file borrowed some code from https://bitbucket.org/splatteredbits/carbon
     8  // (see Source/Security/Privilege.cs). This external source is licensed under
     9  // Apache-2.0 license which is compatible with AGPLv3 license. Because it's
    10  // compatible we can and have licensed this derived work under AGPLv3. The original
    11  // Apache-2.0 license for the external source can be found inside Apache-License.txt.
    12  // Copyright statement of the external source: Copyright 2012 Aaron Jensen
    13  
    14  package cloudconfig
    15  
    16  var winPowershellHelperFunctions = `
    17  
    18  $ErrorActionPreference = "Stop"
    19  
    20  function ExecRetry($command, $maxRetryCount = 10, $retryInterval=2)
    21  {
    22      $currErrorActionPreference = $ErrorActionPreference
    23      $ErrorActionPreference = "Continue"
    24  
    25      $retryCount = 0
    26      while ($true)
    27      {
    28          try
    29          {
    30              & $command
    31              break
    32          }
    33          catch [System.Exception]
    34          {
    35              $retryCount++
    36              if ($retryCount -ge $maxRetryCount)
    37              {
    38                  $ErrorActionPreference = $currErrorActionPreference
    39                  throw
    40              }
    41              else
    42              {
    43                  Write-Error $_.Exception
    44                  Start-Sleep $retryInterval
    45              }
    46          }
    47      }
    48  
    49      $ErrorActionPreference = $currErrorActionPreference
    50  }
    51  
    52  function create-account ([string]$accountName, [string]$accountDescription, [string]$password) {
    53  	$hostname = hostname
    54  	$comp = [adsi]"WinNT://$hostname"
    55  	$user = $comp.Create("User", $accountName)
    56  	$user.SetPassword($password)
    57  	$user.SetInfo()
    58  	$user.description = $accountDescription
    59  	$user.SetInfo()
    60  	$User.UserFlags[0] = $User.UserFlags[0] -bor 0x10000
    61  	$user.SetInfo()
    62  
    63  	$objOU = [ADSI]"WinNT://$hostname/Administrators,group"
    64  	$objOU.add("WinNT://$hostname/$accountName")
    65  }
    66  
    67  $Source = @"
    68  using System;
    69  using System.Text;
    70  using System.Runtime.InteropServices;
    71  
    72  namespace PSCloudbase
    73  {
    74      public sealed class Win32CryptApi
    75      {
    76          public static long CRYPT_SILENT                     = 0x00000040;
    77          public static long CRYPT_VERIFYCONTEXT              = 0xF0000000;
    78          public static int PROV_RSA_FULL                     = 1;
    79  
    80          [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    81          [return : MarshalAs(UnmanagedType.Bool)]
    82          public static extern bool CryptAcquireContext(ref IntPtr hProv,
    83                                                        StringBuilder pszContainer, // Don't use string, as Powershell replaces $null with an empty string
    84                                                        StringBuilder pszProvider, // Don't use string, as Powershell replaces $null with an empty string
    85                                                        uint dwProvType,
    86                                                        uint dwFlags);
    87  
    88          [DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)]
    89          public static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags);
    90  
    91          [DllImport("advapi32.dll", SetLastError=true)]
    92          public static extern bool CryptGenRandom(IntPtr hProv, uint dwLen, byte[] pbBuffer);
    93  
    94          [DllImport("Kernel32.dll")]
    95          public static extern uint GetLastError();
    96      }
    97  }
    98  "@
    99  
   100  Add-Type -TypeDefinition $Source -Language CSharp
   101  
   102  function Get-RandomPassword
   103  {
   104      [CmdletBinding()]
   105      param
   106      (
   107          [parameter(Mandatory=$true)]
   108          [int]$Length
   109      )
   110      process
   111      {
   112          $hProvider = 0
   113          try
   114          {
   115              if(![PSCloudbase.Win32CryptApi]::CryptAcquireContext([ref]$hProvider, $null, $null,
   116                                                                   [PSCloudbase.Win32CryptApi]::PROV_RSA_FULL,
   117                                                                   ([PSCloudbase.Win32CryptApi]::CRYPT_VERIFYCONTEXT -bor
   118                                                                    [PSCloudbase.Win32CryptApi]::CRYPT_SILENT)))
   119              {
   120                  throw "CryptAcquireContext failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError()
   121              }
   122  
   123              $buffer = New-Object byte[] $Length
   124              if(![PSCloudbase.Win32CryptApi]::CryptGenRandom($hProvider, $Length, $buffer))
   125              {
   126                  throw "CryptGenRandom failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError()
   127              }
   128  
   129              $buffer | ForEach-Object { $password += "{0:X0}" -f $_ }
   130              return $password
   131          }
   132          finally
   133          {
   134              if($hProvider)
   135              {
   136                  $retVal = [PSCloudbase.Win32CryptApi]::CryptReleaseContext($hProvider, 0)
   137              }
   138          }
   139      }
   140  }
   141  
   142  $SourcePolicy = @"
   143  /*
   144  Original sources available at: https://bitbucket.org/splatteredbits/carbon
   145  */
   146  
   147  using System;
   148  using System.Collections.Generic;
   149  using System.ComponentModel;
   150  using System.Runtime.InteropServices;
   151  using System.Security.Principal;
   152  using System.Text;
   153  
   154  namespace PSCarbon
   155  {
   156      public sealed class Lsa
   157      {
   158          // ReSharper disable InconsistentNaming
   159          [StructLayout(LayoutKind.Sequential)]
   160          internal struct LSA_UNICODE_STRING
   161          {
   162              internal LSA_UNICODE_STRING(string inputString)
   163              {
   164                  if (inputString == null)
   165                  {
   166                      Buffer = IntPtr.Zero;
   167                      Length = 0;
   168                      MaximumLength = 0;
   169                  }
   170                  else
   171                  {
   172                      Buffer = Marshal.StringToHGlobalAuto(inputString);
   173                      Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize);
   174                      MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize);
   175                  }
   176              }
   177  
   178              internal ushort Length;
   179              internal ushort MaximumLength;
   180              internal IntPtr Buffer;
   181          }
   182  
   183          [StructLayout(LayoutKind.Sequential)]
   184          internal struct LSA_OBJECT_ATTRIBUTES
   185          {
   186              internal uint Length;
   187              internal IntPtr RootDirectory;
   188              internal LSA_UNICODE_STRING ObjectName;
   189              internal uint Attributes;
   190              internal IntPtr SecurityDescriptor;
   191              internal IntPtr SecurityQualityOfService;
   192          }
   193  
   194          [StructLayout(LayoutKind.Sequential)]
   195          public struct LUID
   196          {
   197              public uint LowPart;
   198              public int HighPart;
   199          }
   200  
   201          // ReSharper disable UnusedMember.Local
   202          private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001;
   203          private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002;
   204          private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004;
   205          private const uint POLICY_TRUST_ADMIN = 0x00000008;
   206          private const uint POLICY_CREATE_ACCOUNT = 0x00000010;
   207          private const uint POLICY_CREATE_SECRET = 0x00000014;
   208          private const uint POLICY_CREATE_PRIVILEGE = 0x00000040;
   209          private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080;
   210          private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100;
   211          private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200;
   212          private const uint POLICY_SERVER_ADMIN = 0x00000400;
   213          private const uint POLICY_LOOKUP_NAMES = 0x00000800;
   214          private const uint POLICY_NOTIFICATION = 0x00001000;
   215          // ReSharper restore UnusedMember.Local
   216  
   217          [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
   218          public static extern bool LookupPrivilegeValue(
   219              [MarshalAs(UnmanagedType.LPTStr)] string lpSystemName,
   220              [MarshalAs(UnmanagedType.LPTStr)] string lpName,
   221              out LUID lpLuid);
   222  
   223          [DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
   224          private static extern uint LsaAddAccountRights(
   225              IntPtr PolicyHandle,
   226              IntPtr AccountSid,
   227              LSA_UNICODE_STRING[] UserRights,
   228              uint CountOfRights);
   229  
   230          [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)]
   231          private static extern uint LsaClose(IntPtr ObjectHandle);
   232  
   233          [DllImport("advapi32.dll", SetLastError = true)]
   234          private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle,
   235              IntPtr AccountSid,
   236              out IntPtr UserRights,
   237              out uint CountOfRights
   238              );
   239  
   240          [DllImport("advapi32.dll", SetLastError = true)]
   241          private static extern uint LsaFreeMemory(IntPtr pBuffer);
   242  
   243          [DllImport("advapi32.dll")]
   244          private static extern int LsaNtStatusToWinError(long status);
   245  
   246          [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
   247          private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle );
   248  
   249          [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
   250          static extern uint LsaRemoveAccountRights(
   251              IntPtr PolicyHandle,
   252              IntPtr AccountSid,
   253              [MarshalAs(UnmanagedType.U1)]
   254              bool AllRights,
   255              LSA_UNICODE_STRING[] UserRights,
   256              uint CountOfRights);
   257          // ReSharper restore InconsistentNaming
   258  
   259          private static IntPtr GetIdentitySid(string identity)
   260          {
   261              var sid =
   262                  new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier;
   263              if (sid == null)
   264              {
   265                  throw new ArgumentException(string.Format("Account {0} not found.", identity));
   266              }
   267              var sidBytes = new byte[sid.BinaryLength];
   268              sid.GetBinaryForm(sidBytes, 0);
   269              var sidPtr = Marshal.AllocHGlobal(sidBytes.Length);
   270              Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length);
   271              return sidPtr;
   272          }
   273  
   274          private static IntPtr GetLsaPolicyHandle()
   275          {
   276              var computerName = Environment.MachineName;
   277              IntPtr hPolicy;
   278              var objectAttributes = new LSA_OBJECT_ATTRIBUTES
   279              {
   280                  Length = 0,
   281                  RootDirectory = IntPtr.Zero,
   282                  Attributes = 0,
   283                  SecurityDescriptor = IntPtr.Zero,
   284                  SecurityQualityOfService = IntPtr.Zero
   285              };
   286  
   287              const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION;
   288              var machineNameLsa = new LSA_UNICODE_STRING(computerName);
   289              var result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy);
   290              HandleLsaResult(result);
   291              return hPolicy;
   292          }
   293  
   294          public static string[] GetPrivileges(string identity)
   295          {
   296              var sidPtr = GetIdentitySid(identity);
   297              var hPolicy = GetLsaPolicyHandle();
   298              var rightsPtr = IntPtr.Zero;
   299  
   300              try
   301              {
   302  
   303                  var privileges = new List<string>();
   304  
   305                  uint rightsCount;
   306                  var result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount);
   307                  var win32ErrorCode = LsaNtStatusToWinError(result);
   308                  // the user has no privileges
   309                  if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND )
   310                  {
   311                      return new string[0];
   312                  }
   313                  HandleLsaResult(result);
   314  
   315                  var myLsaus = new LSA_UNICODE_STRING();
   316                  for (ulong i = 0; i < rightsCount; i++)
   317                  {
   318                      var itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus)));
   319                      myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType());
   320                      var cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize];
   321                      Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize);
   322                      var thisRight = new string(cvt);
   323                      privileges.Add(thisRight);
   324                  }
   325                  return privileges.ToArray();
   326              }
   327              finally
   328              {
   329                  Marshal.FreeHGlobal(sidPtr);
   330                  var result = LsaClose(hPolicy);
   331                  HandleLsaResult(result);
   332                  result = LsaFreeMemory(rightsPtr);
   333                  HandleLsaResult(result);
   334              }
   335          }
   336  
   337          public static void GrantPrivileges(string identity, string[] privileges)
   338          {
   339              var sidPtr = GetIdentitySid(identity);
   340              var hPolicy = GetLsaPolicyHandle();
   341  
   342              try
   343              {
   344                  var lsaPrivileges = StringsToLsaStrings(privileges);
   345                  var result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length);
   346                  HandleLsaResult(result);
   347              }
   348              finally
   349              {
   350                  Marshal.FreeHGlobal(sidPtr);
   351                  var result = LsaClose(hPolicy);
   352                  HandleLsaResult(result);
   353              }
   354          }
   355  
   356          const int STATUS_SUCCESS = 0x0;
   357          const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002;
   358          const int STATUS_ACCESS_DENIED = 0x00000005;
   359          const int STATUS_INVALID_HANDLE = 0x00000006;
   360          const int STATUS_UNSUCCESSFUL = 0x0000001F;
   361          const int STATUS_INVALID_PARAMETER = 0x00000057;
   362          const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521;
   363          const int STATUS_INVALID_SERVER_STATE = 0x00000548;
   364          const int STATUS_INTERNAL_DB_ERROR = 0x00000567;
   365          const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA;
   366  
   367          private static readonly Dictionary<int, string> ErrorMessages = new Dictionary<int, string>
   368                                      {
   369                                          {STATUS_OBJECT_NAME_NOT_FOUND, "Object name not found. An object in the LSA policy database was not found. The object may have been specified either by SID or by name, depending on its type."},
   370                                          {STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation."},
   371                                          {STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used."},
   372                                          {STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure."},
   373                                          {STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid."},
   374                                          {STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist."},
   375                                          {STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled."},
   376                                          {STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency."},
   377                                          {STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call."}
   378                                      };
   379  
   380          private static void HandleLsaResult(uint returnCode)
   381          {
   382              var win32ErrorCode = LsaNtStatusToWinError(returnCode);
   383  
   384              if( win32ErrorCode == STATUS_SUCCESS)
   385                  return;
   386  
   387              if( ErrorMessages.ContainsKey(win32ErrorCode) )
   388              {
   389                  throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]);
   390              }
   391  
   392              throw new Win32Exception(win32ErrorCode);
   393          }
   394  
   395          public static void RevokePrivileges(string identity, string[] privileges)
   396          {
   397              var sidPtr = GetIdentitySid(identity);
   398              var hPolicy = GetLsaPolicyHandle();
   399  
   400              try
   401              {
   402                  var currentPrivileges = GetPrivileges(identity);
   403                  if (currentPrivileges.Length == 0)
   404                  {
   405                      return;
   406                  }
   407                  var lsaPrivileges = StringsToLsaStrings(privileges);
   408                  var result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length);
   409                  HandleLsaResult(result);
   410              }
   411              finally
   412              {
   413                  Marshal.FreeHGlobal(sidPtr);
   414                  var result = LsaClose(hPolicy);
   415                  HandleLsaResult(result);
   416              }
   417  
   418          }
   419  
   420          private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges)
   421          {
   422              var lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length];
   423              for (var idx = 0; idx < privileges.Length; ++idx)
   424              {
   425                  lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]);
   426              }
   427              return lsaPrivileges;
   428          }
   429      }
   430  }
   431  "@
   432  
   433  Add-Type -TypeDefinition $SourcePolicy -Language CSharp
   434  
   435  $ServiceChangeErrors = @{}
   436  $ServiceChangeErrors.Add(1, "Not Supported")
   437  $ServiceChangeErrors.Add(2, "Access Denied")
   438  $ServiceChangeErrors.Add(3, "Dependent Services Running")
   439  $ServiceChangeErrors.Add(4, "Invalid Service Control")
   440  $ServiceChangeErrors.Add(5, "Service Cannot Accept Control")
   441  $ServiceChangeErrors.Add(6, "Service Not Active")
   442  $ServiceChangeErrors.Add(7, "Service Request Timeout")
   443  $ServiceChangeErrors.Add(8, "Unknown Failure")
   444  $ServiceChangeErrors.Add(9, "Path Not Found")
   445  $ServiceChangeErrors.Add(10, "Service Already Running")
   446  $ServiceChangeErrors.Add(11, "Service Database Locked")
   447  $ServiceChangeErrors.Add(12, "Service Dependency Deleted")
   448  $ServiceChangeErrors.Add(13, "Service Dependency Failure")
   449  $ServiceChangeErrors.Add(14, "Service Disabled")
   450  $ServiceChangeErrors.Add(15, "Service Logon Failure")
   451  $ServiceChangeErrors.Add(16, "Service Marked For Deletion")
   452  $ServiceChangeErrors.Add(17, "Service No Thread")
   453  $ServiceChangeErrors.Add(18, "Status Circular Dependency")
   454  $ServiceChangeErrors.Add(19, "Status Duplicate Name")
   455  $ServiceChangeErrors.Add(20, "Status Invalid Name")
   456  $ServiceChangeErrors.Add(21, "Status Invalid Parameter")
   457  $ServiceChangeErrors.Add(22, "Status Invalid Service Account")
   458  $ServiceChangeErrors.Add(23, "Status Service Exists")
   459  $ServiceChangeErrors.Add(24, "Service Already Paused")
   460  
   461  
   462  function SetAssignPrimaryTokenPrivilege($UserName)
   463  {
   464      $privilege = "SeAssignPrimaryTokenPrivilege"
   465      if (![PSCarbon.Lsa]::GetPrivileges($UserName).Contains($privilege))
   466      {
   467          [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege)
   468      }
   469  }
   470  
   471  function SetUserLogonAsServiceRights($UserName)
   472  {
   473      $privilege = "SeServiceLogonRight"
   474      if (![PSCarbon.Lsa]::GetPrivileges($UserName).Contains($privilege))
   475      {
   476          [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege)
   477      }
   478  }
   479  
   480  $Source = @"
   481  using System;
   482  using System.Text;
   483  using System.Runtime.InteropServices;
   484  using System.Security.Principal;
   485  using System.ComponentModel;
   486  
   487  namespace PSCloudbase
   488  {
   489      public class ProcessManager
   490      {
   491          const int LOGON32_LOGON_SERVICE = 5;
   492          const int LOGON32_PROVIDER_DEFAULT = 0;
   493          const int TOKEN_ALL_ACCESS = 0x000f01ff;
   494          const uint GENERIC_ALL_ACCESS = 0x10000000;
   495          const uint INFINITE = 0xFFFFFFFF;
   496          const uint PI_NOUI = 0x00000001;
   497          const uint WAIT_FAILED = 0xFFFFFFFF;
   498  
   499          enum SECURITY_IMPERSONATION_LEVEL
   500          {
   501              SecurityAnonymous,
   502              SecurityIdentification,
   503              SecurityImpersonation,
   504              SecurityDelegation
   505          }
   506  
   507          enum TOKEN_TYPE
   508          {
   509              TokenPrimary = 1,
   510              TokenImpersonation
   511          }
   512  
   513          [StructLayout(LayoutKind.Sequential)]
   514          struct SECURITY_ATTRIBUTES
   515          {
   516              public int nLength;
   517              public IntPtr lpSecurityDescriptor;
   518              public int bInheritHandle;
   519          }
   520  
   521          [StructLayout(LayoutKind.Sequential)]
   522          struct PROCESS_INFORMATION
   523          {
   524              public IntPtr hProcess;
   525              public IntPtr hThread;
   526              public int dwProcessId;
   527              public int dwThreadId;
   528          }
   529  
   530          [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
   531          struct STARTUPINFO
   532          {
   533              public Int32 cb;
   534              public string lpReserved;
   535              public string lpDesktop;
   536              public string lpTitle;
   537              public Int32 dwX;
   538              public Int32 dwY;
   539              public Int32 dwXSize;
   540              public Int32 dwYSize;
   541              public Int32 dwXCountChars;
   542              public Int32 dwYCountChars;
   543              public Int32 dwFillAttribute;
   544              public Int32 dwFlags;
   545              public Int16 wShowWindow;
   546              public Int16 cbReserved2;
   547              public IntPtr lpReserved2;
   548              public IntPtr hStdInput;
   549              public IntPtr hStdOutput;
   550              public IntPtr hStdError;
   551          }
   552  
   553          [StructLayout(LayoutKind.Sequential)]
   554          struct PROFILEINFO {
   555              public int dwSize;
   556              public uint dwFlags;
   557              [MarshalAs(UnmanagedType.LPTStr)]
   558              public String lpUserName;
   559              [MarshalAs(UnmanagedType.LPTStr)]
   560              public String lpProfilePath;
   561              [MarshalAs(UnmanagedType.LPTStr)]
   562              public String lpDefaultPath;
   563              [MarshalAs(UnmanagedType.LPTStr)]
   564              public String lpServerName;
   565              [MarshalAs(UnmanagedType.LPTStr)]
   566              public String lpPolicyPath;
   567              public IntPtr hProfile;
   568          }
   569  
   570          [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
   571          public struct USER_INFO_4
   572          {
   573              public string name;
   574              public string password;
   575              public int password_age;
   576              public uint priv;
   577              public string home_dir;
   578              public string comment;
   579              public uint flags;
   580              public string script_path;
   581              public uint auth_flags;
   582              public string full_name;
   583              public string usr_comment;
   584              public string parms;
   585              public string workstations;
   586              public int last_logon;
   587              public int last_logoff;
   588              public int acct_expires;
   589              public int max_storage;
   590              public int units_per_week;
   591              public IntPtr logon_hours;    // This is a PBYTE
   592              public int bad_pw_count;
   593              public int num_logons;
   594              public string logon_server;
   595              public int country_code;
   596              public int code_page;
   597              public IntPtr user_sid;     // This is a PSID
   598              public int primary_group_id;
   599              public string profile;
   600              public string home_dir_drive;
   601              public int password_expired;
   602          }
   603  
   604          [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
   605          extern static bool DuplicateTokenEx(
   606              IntPtr hExistingToken,
   607              uint dwDesiredAccess,
   608              ref SECURITY_ATTRIBUTES lpTokenAttributes,
   609              SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
   610              TOKEN_TYPE TokenType,
   611              out IntPtr phNewToken);
   612  
   613          [DllImport("advapi32.dll", SetLastError=true)]
   614          static extern bool LogonUser(
   615              string lpszUsername,
   616              string lpszDomain,
   617              string lpszPassword,
   618              int dwLogonType,
   619              int dwLogonProvider,
   620              out IntPtr phToken);
   621  
   622          [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Auto)]
   623          static extern bool CreateProcessAsUser(
   624              IntPtr hToken,
   625              string lpApplicationName,
   626              string lpCommandLine,
   627              ref SECURITY_ATTRIBUTES lpProcessAttributes,
   628              ref SECURITY_ATTRIBUTES lpThreadAttributes,
   629              bool bInheritHandles,
   630              uint dwCreationFlags,
   631              IntPtr lpEnvironment,
   632              string lpCurrentDirectory,
   633              ref STARTUPINFO lpStartupInfo,
   634              out PROCESS_INFORMATION lpProcessInformation);
   635  
   636          [DllImport("kernel32.dll", SetLastError=true)]
   637          static extern UInt32 WaitForSingleObject(IntPtr hHandle,
   638                                                   UInt32 dwMilliseconds);
   639  
   640          [DllImport("Kernel32.dll")]
   641          static extern int GetLastError();
   642  
   643          [DllImport("Kernel32.dll")]
   644          extern static int CloseHandle(IntPtr handle);
   645  
   646          [DllImport("kernel32.dll", SetLastError = true)]
   647          [return: MarshalAs(UnmanagedType.Bool)]
   648          static extern bool GetExitCodeProcess(IntPtr hProcess,
   649                                                out uint lpExitCode);
   650  
   651          [DllImport("userenv.dll", SetLastError=true, CharSet=CharSet.Auto)]
   652          [return: MarshalAs(UnmanagedType.Bool)]
   653          static extern bool LoadUserProfile(IntPtr hToken,
   654                                             ref PROFILEINFO lpProfileInfo);
   655  
   656          [DllImport("userenv.dll", SetLastError=true, CharSet=CharSet.Auto)]
   657          [return: MarshalAs(UnmanagedType.Bool)]
   658          static extern bool UnloadUserProfile(IntPtr hToken, IntPtr hProfile);
   659  
   660           [DllImport("Netapi32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
   661          extern static int NetUserGetInfo(
   662              [MarshalAs(UnmanagedType.LPWStr)] string ServerName,
   663              [MarshalAs(UnmanagedType.LPWStr)] string UserName,
   664              int level, out IntPtr BufPtr);
   665  
   666          public static uint RunProcess(string userName, string password,
   667                                        string domain, string cmd,
   668                                        string arguments,
   669                                        bool loadUserProfile = true)
   670          {
   671              bool retValue;
   672              IntPtr phToken = IntPtr.Zero;
   673              IntPtr phTokenDup = IntPtr.Zero;
   674              PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
   675              PROFILEINFO pi = new PROFILEINFO();
   676  
   677              try
   678              {
   679                  retValue = LogonUser(userName, domain, password,
   680                                       LOGON32_LOGON_SERVICE,
   681                                       LOGON32_PROVIDER_DEFAULT,
   682                                       out phToken);
   683                  if(!retValue)
   684                      throw new Win32Exception(GetLastError());
   685  
   686                  var sa = new SECURITY_ATTRIBUTES();
   687                  sa.nLength = Marshal.SizeOf(sa);
   688  
   689                  retValue = DuplicateTokenEx(
   690                      phToken, GENERIC_ALL_ACCESS, ref sa,
   691                      SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
   692                      TOKEN_TYPE.TokenPrimary, out phTokenDup);
   693                  if(!retValue)
   694                      throw new Win32Exception(GetLastError());
   695  
   696                  STARTUPINFO sInfo = new STARTUPINFO();
   697                  sInfo.lpDesktop = "";
   698  
   699                  if(loadUserProfile)
   700                  {
   701                      IntPtr userInfoPtr = IntPtr.Zero;
   702                      int retValueNetUser = NetUserGetInfo(null, userName, 4,
   703                                                           out userInfoPtr);
   704                      if(retValueNetUser != 0)
   705                          throw new Win32Exception(retValueNetUser);
   706  
   707                      USER_INFO_4 userInfo = (USER_INFO_4)Marshal.PtrToStructure(
   708                          userInfoPtr, typeof(USER_INFO_4));
   709  
   710                      pi.dwSize = Marshal.SizeOf(pi);
   711                      pi.dwFlags = PI_NOUI;
   712                      pi.lpUserName = userName;
   713                      pi.lpProfilePath = userInfo.profile;
   714  
   715                      retValue = LoadUserProfile(phTokenDup, ref pi);
   716                      if(!retValue)
   717                          throw new Win32Exception(GetLastError());
   718                  }
   719  
   720                  retValue = CreateProcessAsUser(phTokenDup, cmd, arguments,
   721                                                 ref sa, ref sa, false, 0,
   722                                                 IntPtr.Zero, null,
   723                                                 ref sInfo, out pInfo);
   724                  if(!retValue)
   725                      throw new Win32Exception(GetLastError());
   726  
   727                  if(WaitForSingleObject(pInfo.hProcess, INFINITE) == WAIT_FAILED)
   728                      throw new Win32Exception(GetLastError());
   729  
   730                  uint exitCode;
   731                  retValue = GetExitCodeProcess(pInfo.hProcess, out exitCode);
   732                  if(!retValue)
   733                      throw new Win32Exception(GetLastError());
   734  
   735                  return exitCode;
   736              }
   737              finally
   738              {
   739                  if(pi.hProfile != IntPtr.Zero)
   740                      UnloadUserProfile(phTokenDup, pi.hProfile);
   741                  if(phToken != IntPtr.Zero)
   742                      CloseHandle(phToken);
   743                  if(phTokenDup != IntPtr.Zero)
   744                      CloseHandle(phTokenDup);
   745                  if(pInfo.hProcess != IntPtr.Zero)
   746                      CloseHandle(pInfo.hProcess);
   747              }
   748          }
   749      }
   750  }
   751  "@
   752  
   753  Add-Type -TypeDefinition $Source -Language CSharp
   754  
   755  function Start-ProcessAsUser
   756  {
   757      [CmdletBinding()]
   758      param
   759      (
   760          [parameter(Mandatory=$true, ValueFromPipeline=$true)]
   761          [string]$Command,
   762  
   763          [parameter()]
   764          [string]$Arguments,
   765  
   766          [parameter(Mandatory=$true)]
   767          [PSCredential]$Credential,
   768  
   769          [parameter()]
   770          [bool]$LoadUserProfile = $true
   771      )
   772      process
   773      {
   774          $nc = $Credential.GetNetworkCredential()
   775  
   776          $domain = "."
   777          if($nc.Domain)
   778          {
   779              $domain = $nc.Domain
   780          }
   781  
   782          [PSCloudbase.ProcessManager]::RunProcess($nc.UserName, $nc.Password,
   783                                                   $domain, $Command,
   784                                                   $Arguments, $LoadUserProfile)
   785      }
   786  }
   787  
   788  $powershell = "$ENV:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe"
   789  $cmdExe = "$ENV:SystemRoot\System32\cmd.exe"
   790  
   791  $juju_passwd = Get-RandomPassword 20
   792  $juju_passwd += "^"
   793  create-account jujud "Juju Admin user" $juju_passwd
   794  $hostname = hostname
   795  $juju_user = "$hostname\jujud"
   796  
   797  SetUserLogonAsServiceRights $juju_user
   798  SetAssignPrimaryTokenPrivilege $juju_user
   799  
   800  New-ItemProperty "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" -Name "jujud" -Value 0 -PropertyType "DWord"
   801  
   802  $secpasswd = ConvertTo-SecureString $juju_passwd -AsPlainText -Force
   803  $jujuCreds = New-Object System.Management.Automation.PSCredential ($juju_user, $secpasswd)
   804  
   805  `
   806  
   807  var winSetPasswdScript = `
   808  
   809  Set-Content "C:\juju\bin\save_pass.ps1" @"
   810  Param (
   811  	[Parameter(Mandatory=` + "`$true" + `)]
   812  	[string]` + "`$pass" + `
   813  )
   814  
   815  ` + "`$secpasswd" + ` = ConvertTo-SecureString ` + "`$pass" + ` -AsPlainText -Force
   816  ` + "`$secpasswd" + ` | convertfrom-securestring | Add-Content C:\Juju\Jujud.pass
   817  "@
   818  
   819  `