{"id":69673,"date":"2005-06-03T11:12:00","date_gmt":"2005-06-03T11:12:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2005\/06\/03\/hey-scripting-guy-how-can-i-list-all-the-user-profiles-on-a-computer\/"},"modified":"2018-12-19T11:20:24","modified_gmt":"2018-12-19T18:20:24","slug":"hey-scripting-guy-how-can-i-list-all-the-user-profiles-on-a-computer","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-list-all-the-user-profiles-on-a-computer\/","title":{"rendered":"Hey, Scripting Guy! How Can I List All the User Profiles on a Computer?"},"content":{"rendered":"<p><img decoding=\"async\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2005\/08\/q-for-powertip.jpg\" alt=\"question\" width=\"34\" height=\"34\" class=\"alignleft size-full wp-image-83488\" \/>\nHey, Scripting Guy! How can I list all the user profiles on a computer?     &#8212; GN\n<img decoding=\"async\" src=\"http:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2005\/08\/a-for-powertip.jpg\" alt=\"answer\" width=\"34\" height=\"34\" class=\"alignleft size-full wp-image-83489\" \/><\/p>\n<p>Hey, GN. You want to know a secret? We hate questions about user profiles. It\u2019s not that we have anything against user profiles. The problem is that user profiles represent an important part of a system administrator\u2019s duties, and because of that everyone assumes that there must be all sorts of really cool scripting technologies that make it easy to manage user profiles. In turn, that means everyone ends up disappointed when we Scripting Guys have to break the bad news: there aren\u2019t <i>any<\/i> really cool scripting technologies that make it easy to manage user profiles.<\/p>\n<p>Hey, no need to be embarrassed: we cried the first time we heard the news, too. But listen, all is not lost. There might not be a really cool scripting technology dedicated to user profiles, but there are workarounds that enable us to accomplish some of the more common management tasks related to user profiles. And one of those workarounds allows us to list all the user profiles found on a computer.<\/p>\n<p>As it turns out, you can find a list of all the user profiles in the HKEY_LOCAL_MACHINE portion of the registry; more specifically, you can find them listed under this registry key:<\/p>\n<pre class=\"codeSample\">HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\r\n<\/pre>\n<p>That\u2019s the good news. The bad news is that you don\u2019t get a nice, neat list of user profiles; instead, you see a series of separate registry subkeys, each one named after a user\u2019s SID (Security Identifier). To determine the actual user profiles found on a computer we need to iterate through each of those individual subkeys and read the value of <b>ProfileImagePath<\/b>; as shown in the following screenshot, ProfileImagePath gives us the path to the profile and, by extension, the name of the user that the profile belongs to:<\/p>\n<p>For a larger, easier-to-read version of this graphic click <a href=\"http:\/\/null\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/profiles-big.jpg\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>So how do we iterate through all these subkeys and read the value of ProfileImagePath? Well, as we almost always do any time we\u2019re faced with a scripting issue that involves the registry, we turn to WMI:<\/p>\n<pre class=\"codeSample\">On Error Resume Next<\/pre>\n<p>Const HKEY_LOCAL_MACHINE = &amp;H80000002<\/p>\n<p>strComputer = &#8220;.&#8221;<\/p>\n<p>Set objRegistry=GetObject(&#8220;winmgmts:\\\\&#8221; &amp; _\nstrComputer &amp; &#8220;\\root\\default:StdRegProv&#8221;)<\/p>\n<p>strKeyPath = &#8220;SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList&#8221;\nobjRegistry.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubkeys<\/p>\n<p>For Each objSubkey In arrSubkeys\nstrValueName = &#8220;ProfileImagePath&#8221;\nstrSubPath = strKeyPath &amp; &#8220;\\&#8221; &amp; objSubkey\nobjRegistry.GetExpandedStringValue HKEY_LOCAL_MACHINE,strSubPath,strValueName,strValue\nWscript.Echo strValue\nNext<\/p>\n<p>Don\u2019t worry: we\u2019ll explain how this all works. We begin by defining a constant named HKEY_LOCAL_MACHINE and assigning it the value &amp;H80000002; we\u2019ll use this constant later on to indicate the part of the registry we want to work with. We then connect to the WMI service, specifying the path to the <b>StdRegProv<\/b> class (note that this is found in the <b>root\\default<\/b> namespace).<\/p>\n<p>After that we store the registry path (SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList) in the variable strKeyPath, then use the <b>EnumKey<\/b> method to return a collection of all the subkeys found under ProfileList (as we\u2019ve already determined, these subkeys &#8211; each one named after a user SID &#8211; represent all the user profiles found on the computer). Note that the EnumKey method takes three parameters:<\/p>\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"listBullet\" valign=\"top\">\u2022<\/td>\n<td class=\"listItem\"><i>HKEY_LOCAL_MACHINE<\/i>, the constant that tells the script which portion of the registry to work with.<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" valign=\"top\">\u2022<\/td>\n<td class=\"listItem\"><i>strKeyPath<\/i>, the variable containing the path to the ProfieList registry value.<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" valign=\"top\">\u2022<\/td>\n<td class=\"listItem\"><i>arrSubkeys<\/i>, an \u201cout\u201d parameter that will hold the results returned by EnumKey. When we call EnumKey, the collection of registry subkeys found under ProfileList will be stored in arrSubkeys.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If we wanted to we could list all the subkey names by using code similar to this:<\/p>\n<pre class=\"codeSample\">For Each objSubkey In arrSubkeys\r\n     Wscript.Echo objSubkey\r\nNext\r\n<\/pre>\n<p>So why don\u2019t we do that? Well, remember, these subkeys are named after user SIDs; simply listing the subkey names will return data similar to this:<\/p>\n<pre class=\"codeSample\">S-1-5-18\r\nS-1-5-19\r\nS-1-5-20\r\nS-1-5-21-1229272821-920026266-1060284298-1003\r\nS-1-5-21-1229272821-920026266-1060284298-1005\r\nS-1-5-21-1229272821-920026266-1060284298-1009\r\nS-1-5-21-1454471165-1004336348-1606980848-8183\r\n<\/pre>\n<p>Interesting, but not very informative. (Unless, of course, you usually call people by their SID rather than by their name.)<\/p>\n<p>Instead, what we need to do is connect to each of these registry subkeys and read the value of ProfileImagePath; that\u2019s what we do with these lines of code:<\/p>\n<pre class=\"codeSample\">For Each objSubkey In arrSubkeys\r\n    strValueName = \"ProfileImagePath\"\r\n    strSubPath = strKeyPath &amp; \"\\\" &amp; objSubkey\r\n    objRegistry.GetExpandedStringValue HKEY_LOCAL_MACHINE,strSubPath,strValueName,strValue\r\n    Wscript.Echo strValue\r\nNext\r\n<\/pre>\n<p>No, it\u2019s <i>not<\/i> too hard. We start off by defining a variable named strValueName and assigning it the value ProfileImagePath; this is the name of the individual registry value we want to read. We then take our original registry path (SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList) and tack on a \\ and the name of the first subkey in our collection (for example, S-1-5-18). That will give us a path to that first subkey, something similar to this:<\/p>\n<pre class=\"codeSample\">SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\S-1-5-18\r\n<\/pre>\n<p>Now that we know the path to the registry value we can use the <b>GetExpandedStringValue<\/b> method to read the value of ProfileImagPath. Why GetExpandedStringValue? Well, ProfileImagePath happens to be an expanded string value; it contains information similar to this:<\/p>\n<pre class=\"codeSample\">%SystemDrive%\\Documents and Settings\\TestUser\r\n<\/pre>\n<p>The GetExpandedStringValue method will automatically replace a variable like <i>%SystemDrive%<\/i> with the actual value (e.g., C:). Thus we end up with output similar to this:<\/p>\n<pre class=\"codeSample\">C:\\Documents and Settings\\TestUser\r\n<\/pre>\n<p>As long as we\u2019re on the subject, note that GetExpandedStringValue requires four parameters:<\/p>\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"listBullet\" valign=\"top\">\u2022<\/td>\n<td class=\"listItem\"><i>HKEY_LOCAL_MACHINE<\/i>, the constant that &#8211; again &#8211; represents the HKLM portion of the registry.<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" valign=\"top\">\u2022<\/td>\n<td class=\"listItem\"><i>strSubPath<\/i>, the path to the first user profile subkey (for example, SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\S-1-5-18).<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" valign=\"top\">\u2022<\/td>\n<td class=\"listItem\"><i>strValueName<\/i>, a variable representing the registry value (ProfileImagePath) we want to read.<\/td>\n<\/tr>\n<tr>\n<td class=\"listBullet\" valign=\"top\">\u2022<\/td>\n<td class=\"listItem\"><i>strValue<\/i>, another out parameter, this one containing the value of ProfileImagePath. The last thing we do in our For Each loop is echo the value of this out parameter, which will coincide quite nicely with the path to the user profile.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>When we run the script we\u2019ll get back data similar to this:<\/p>\n<pre class=\"codeSample\">C:\\WINDOWS\\system32\\config\\systemprofile\r\nC:\\Documents and Settings\\LocalService\r\nC:\\Documents and Settings\\NetworkService\r\nC:\\Documents and Settings\\kenmyer\r\nC:\\Documents and Settings\\TestUser\r\nC:\\Documents and Settings\\packerman\r\n<\/pre>\n<p>Much better.<\/p>\n<p>Incidentally, if all we wanted was the user name (for example, kenmyer) we could get fancy and use the VBScript <b>Split<\/b> function to separate the user name (the last item in the path) from the rest of the output. But that\u2019s something we\u2019ll leave for you to try on your own. (But if you need a hint for how to work with the Split function take a peek at this <a href=\"http:\/\/null\/technet\/scriptcenter\/resources\/qanda\/may05\/hey0526.mspx\"><b>Hey, Scripting Guy!<\/b><\/a> column.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I list all the user profiles on a computer? &#8212; GN Hey, GN. You want to know a secret? We hate questions about user profiles. It\u2019s not that we have anything against user profiles. The problem is that user profiles represent an important part of a system administrator\u2019s duties, and [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[16,31,26,3,5],"class_list":["post-69673","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-desktop-management","tag-operating-system","tag-registry","tag-scripting-guy","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I list all the user profiles on a computer? &#8212; GN Hey, GN. You want to know a secret? We hate questions about user profiles. It\u2019s not that we have anything against user profiles. The problem is that user profiles represent an important part of a system administrator\u2019s duties, and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/69673","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=69673"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/69673\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=69673"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=69673"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=69673"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}