|
| 1 | +<# |
| 2 | +Copyright 2014 Cloudbase Solutions Srl |
| 3 | +
|
| 4 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +you may not use this file except in compliance with the License. |
| 6 | +You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | +Unless required by applicable law or agreed to in writing, software |
| 11 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +See the License for the specific language governing permissions and |
| 14 | +limitations under the License. |
| 15 | +#> |
| 16 | + |
| 17 | +$Source = @" |
| 18 | +using System; |
| 19 | +using System.Text; |
| 20 | +using System.Runtime.InteropServices; |
| 21 | +using System.Security.Principal; |
| 22 | +using System.ComponentModel; |
| 23 | +
|
| 24 | +namespace PSCloudbase |
| 25 | +{ |
| 26 | + public class ProcessManager |
| 27 | + { |
| 28 | + const int LOGON32_LOGON_SERVICE = 5; |
| 29 | + const int LOGON32_PROVIDER_DEFAULT = 0; |
| 30 | +
|
| 31 | + const uint GENERIC_ALL_ACCESS = 0x10000000; |
| 32 | +
|
| 33 | + const uint INFINITE = 0xFFFFFFFF; |
| 34 | +
|
| 35 | + enum SECURITY_IMPERSONATION_LEVEL |
| 36 | + { |
| 37 | + SecurityAnonymous, |
| 38 | + SecurityIdentification, |
| 39 | + SecurityImpersonation, |
| 40 | + SecurityDelegation |
| 41 | + } |
| 42 | +
|
| 43 | + enum TOKEN_TYPE |
| 44 | + { |
| 45 | + TokenPrimary = 1, |
| 46 | + TokenImpersonation |
| 47 | + } |
| 48 | +
|
| 49 | + [StructLayout(LayoutKind.Sequential)] |
| 50 | + struct SECURITY_ATTRIBUTES |
| 51 | + { |
| 52 | + public int nLength; |
| 53 | + public IntPtr lpSecurityDescriptor; |
| 54 | + public int bInheritHandle; |
| 55 | + } |
| 56 | +
|
| 57 | + [StructLayout(LayoutKind.Sequential)] |
| 58 | + struct PROCESS_INFORMATION |
| 59 | + { |
| 60 | + public IntPtr hProcess; |
| 61 | + public IntPtr hThread; |
| 62 | + public int dwProcessId; |
| 63 | + public int dwThreadId; |
| 64 | + } |
| 65 | +
|
| 66 | + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] |
| 67 | + struct STARTUPINFO |
| 68 | + { |
| 69 | + public Int32 cb; |
| 70 | + public string lpReserved; |
| 71 | + public string lpDesktop; |
| 72 | + public string lpTitle; |
| 73 | + public Int32 dwX; |
| 74 | + public Int32 dwY; |
| 75 | + public Int32 dwXSize; |
| 76 | + public Int32 dwYSize; |
| 77 | + public Int32 dwXCountChars; |
| 78 | + public Int32 dwYCountChars; |
| 79 | + public Int32 dwFillAttribute; |
| 80 | + public Int32 dwFlags; |
| 81 | + public Int16 wShowWindow; |
| 82 | + public Int16 cbReserved2; |
| 83 | + public IntPtr lpReserved2; |
| 84 | + public IntPtr hStdInput; |
| 85 | + public IntPtr hStdOutput; |
| 86 | + public IntPtr hStdError; |
| 87 | + } |
| 88 | +
|
| 89 | + [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] |
| 90 | + extern static bool DuplicateTokenEx( |
| 91 | + IntPtr hExistingToken, |
| 92 | + uint dwDesiredAccess, |
| 93 | + ref SECURITY_ATTRIBUTES lpTokenAttributes, |
| 94 | + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, |
| 95 | + TOKEN_TYPE TokenType, |
| 96 | + out IntPtr phNewToken); |
| 97 | +
|
| 98 | + [DllImport("advapi32.dll", SetLastError=true)] |
| 99 | + static extern bool LogonUser( |
| 100 | + string lpszUsername, |
| 101 | + string lpszDomain, |
| 102 | + string lpszPassword, |
| 103 | + int dwLogonType, |
| 104 | + int dwLogonProvider, |
| 105 | + out IntPtr phToken); |
| 106 | +
|
| 107 | + [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Auto)] |
| 108 | + static extern bool CreateProcessAsUser( |
| 109 | + IntPtr hToken, |
| 110 | + string lpApplicationName, |
| 111 | + string lpCommandLine, |
| 112 | + ref SECURITY_ATTRIBUTES lpProcessAttributes, |
| 113 | + ref SECURITY_ATTRIBUTES lpThreadAttributes, |
| 114 | + bool bInheritHandles, |
| 115 | + uint dwCreationFlags, |
| 116 | + IntPtr lpEnvironment, |
| 117 | + string lpCurrentDirectory, |
| 118 | + ref STARTUPINFO lpStartupInfo, |
| 119 | + out PROCESS_INFORMATION lpProcessInformation); |
| 120 | +
|
| 121 | + [DllImport("kernel32.dll", SetLastError=true)] |
| 122 | + static extern UInt32 WaitForSingleObject(IntPtr hHandle, |
| 123 | + UInt32 dwMilliseconds); |
| 124 | +
|
| 125 | + [DllImport("Kernel32.dll")] |
| 126 | + static extern int GetLastError(); |
| 127 | +
|
| 128 | + [DllImport("Kernel32.dll")] |
| 129 | + extern static int CloseHandle(IntPtr handle); |
| 130 | +
|
| 131 | + [DllImport("kernel32.dll", SetLastError = true)] |
| 132 | + [return: MarshalAs(UnmanagedType.Bool)] |
| 133 | + static extern bool GetExitCodeProcess(IntPtr hProcess, |
| 134 | + out uint lpExitCode); |
| 135 | +
|
| 136 | + public static uint RunProcess(string userName, string password, |
| 137 | + string domain, string cmd, |
| 138 | + string arguments) |
| 139 | + { |
| 140 | + bool retValue; |
| 141 | + IntPtr phToken = IntPtr.Zero; |
| 142 | + IntPtr phTokenDup = IntPtr.Zero; |
| 143 | + PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION(); |
| 144 | +
|
| 145 | + try |
| 146 | + { |
| 147 | + retValue = LogonUser(userName, domain, password, |
| 148 | + LOGON32_LOGON_SERVICE, |
| 149 | + LOGON32_PROVIDER_DEFAULT, |
| 150 | + out phToken); |
| 151 | + if(!retValue) |
| 152 | + throw new Win32Exception(GetLastError()); |
| 153 | +
|
| 154 | + var sa = new SECURITY_ATTRIBUTES(); |
| 155 | + sa.nLength = Marshal.SizeOf(sa); |
| 156 | +
|
| 157 | + retValue = DuplicateTokenEx( |
| 158 | + phToken, GENERIC_ALL_ACCESS, ref sa, |
| 159 | + SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, |
| 160 | + TOKEN_TYPE.TokenPrimary, out phTokenDup); |
| 161 | + if(!retValue) |
| 162 | + throw new Win32Exception(GetLastError()); |
| 163 | +
|
| 164 | + STARTUPINFO sInfo = new STARTUPINFO(); |
| 165 | + sInfo.lpDesktop = ""; |
| 166 | +
|
| 167 | + retValue = CreateProcessAsUser(phTokenDup, cmd, arguments, |
| 168 | + ref sa, ref sa, false, 0, |
| 169 | + IntPtr.Zero, null, |
| 170 | + ref sInfo, out pInfo); |
| 171 | + if(!retValue) |
| 172 | + throw new Win32Exception(GetLastError()); |
| 173 | +
|
| 174 | + WaitForSingleObject(pInfo.hProcess, INFINITE); |
| 175 | +
|
| 176 | + var lastErr = GetLastError(); |
| 177 | + if(lastErr != 0) |
| 178 | + throw new Win32Exception(GetLastError()); |
| 179 | +
|
| 180 | + uint exitCode; |
| 181 | + retValue = GetExitCodeProcess(pInfo.hProcess, out exitCode); |
| 182 | + if(!retValue) |
| 183 | + throw new Win32Exception(GetLastError()); |
| 184 | +
|
| 185 | + return exitCode; |
| 186 | + } |
| 187 | + finally |
| 188 | + { |
| 189 | + if(phToken != IntPtr.Zero) |
| 190 | + CloseHandle(phToken); |
| 191 | + if(phTokenDup != IntPtr.Zero) |
| 192 | + CloseHandle(phTokenDup); |
| 193 | + if(pInfo.hProcess != IntPtr.Zero) |
| 194 | + CloseHandle(pInfo.hProcess); |
| 195 | + } |
| 196 | + } |
| 197 | + } |
| 198 | +} |
| 199 | +"@ |
| 200 | + |
| 201 | +Add-Type -TypeDefinition $Source -Language CSharp |
| 202 | + |
| 203 | +function Start-ProcessAsUser |
| 204 | +{ |
| 205 | + [CmdletBinding()] |
| 206 | + param |
| 207 | + ( |
| 208 | + [parameter(Mandatory=$true, ValueFromPipeline=$true)] |
| 209 | + [string]$Command, |
| 210 | + |
| 211 | + [parameter()] |
| 212 | + [string]$Arguments, |
| 213 | + |
| 214 | + [parameter(Mandatory=$true)] |
| 215 | + [PSCredential]$Credential |
| 216 | + ) |
| 217 | + process |
| 218 | + { |
| 219 | + $nc = $Credential.GetNetworkCredential() |
| 220 | + |
| 221 | + $domain = "." |
| 222 | + if($nc.Domain) |
| 223 | + { |
| 224 | + $domain = $nc.Domain |
| 225 | + } |
| 226 | + |
| 227 | + [PSCloudbase.ProcessManager]::RunProcess($nc.UserName, $nc.Password, |
| 228 | + $domain, $Command, |
| 229 | + $Arguments) |
| 230 | + } |
| 231 | +} |
0 commit comments