Impersonate.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<#
#>

Function Invoke-ImpersonateUser
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingUsernameAndPasswordParams', '')]
    [CmdletBinding()]
    param(
        [Parameter(mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]$Username,

        [Parameter(mandatory=$true)]
        [ValidateNotNull()]
        [AllowEmptyString()]
        [string]$PasswordInPlaintext
    )

    process
    {

Add-Type @'
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;

namespace CustomProcess
{
    [StructLayout(LayoutKind.Sequential)]
    public struct PROFILEINFO {
        public int dwSize;
        public int dwFlags;
        [MarshalAs(UnmanagedType.LPTStr)]
        public String lpUserName;
        [MarshalAs(UnmanagedType.LPTStr)]
        public String lpProfilePath;
        [MarshalAs(UnmanagedType.LPTStr)]
        public String lpDefaultPath;
        [MarshalAs(UnmanagedType.LPTStr)]
        public String lpServerName;
        [MarshalAs(UnmanagedType.LPTStr)]
        public String lpPolicyPath;
        public IntPtr hProfile;
    }

    public static class ProcessInvoker
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
            int dwLogonType, int dwLogonProvider, out IntPtr phToken);

        [DllImport("userenv.dll", SetLastError=true, CharSet=CharSet.Auto)]
        public static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo);

        public static string Impersonate(string username, string domain, string password)
        {

            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int LOGON32_LOGON_INTERACTIVE = 2;
            IntPtr token = IntPtr.Zero;

            bool returnValue = LogonUser(username, domain, password,
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                out token);

            if (false == returnValue)
            {
                int ret = Marshal.GetLastWin32Error();
                Console.WriteLine("LogonUser failed with error code : {0}", ret);
                //throw new System.ComponentModel.Win32Exception(ret);
                return ("LogonUser Error: " + ret);
            }

            var profileInfo = new PROFILEINFO();
            profileInfo.lpUserName = username;
            profileInfo.dwSize = Marshal.SizeOf(profileInfo);

            returnValue = LoadUserProfile(token, ref profileInfo);

            if (returnValue == false)
            {
                int ret = Marshal.GetLastWin32Error();
                Console.WriteLine("LogonUser failed with error code : {0}", ret);
                //throw new System.ComponentModel.Win32Exception(ret);
                return ("LoadUserProfile Error: " + ret);
            }

            var identity = new WindowsIdentity(token);

            var context = identity.Impersonate();

            return String.Empty;
        }
    }
}
'@


        $domain = $null
        $user = $Username
        if ($Username.Contains("\"))
        {
            $split = $Username.Split("\")
            if (($split | Measure-Object).Count -ne 2)
            {
                Write-Error "Username contains invalid number of '\' characters."
            }

            $domain = $split[0]
            $user = $split[1]
        }

        [CustomProcess.ProcessInvoker]::Impersonate($user, $domain, $PasswordInPlaintext)
    }
}