<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dwarfsoft [GPA] &#187; Hack</title>
	<atom:link href="http://www.dwarfsoft.com/blog/tag/hack/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dwarfsoft.com/blog</link>
	<description>Great Programming Artistry</description>
	<lastBuildDate>Tue, 06 Sep 2011 11:18:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>SYSTEM Account Permissions</title>
		<link>http://www.dwarfsoft.com/blog/2010/05/25/system-account-permissions/</link>
		<comments>http://www.dwarfsoft.com/blog/2010/05/25/system-account-permissions/#comments</comments>
		<pubDate>Tue, 25 May 2010 01:08:45 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Novell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Tweet]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[eDirectory]]></category>
		<category><![CDATA[Hack]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[User Accounts]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=305</guid>
		<description><![CDATA[Recently I have been working on some rather complicated projects preparing our SOE to move from Novell eDirectory to an Active Directory environment. One of the packages I built was required to run periodically and so I set up a Scheduled Task to accomplish this. Rather than introduce a security risk by creating a new [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I have been working on some rather complicated projects preparing our SOE to move from Novell eDirectory to an Active Directory environment. One of the packages I built was required to run periodically and so I set up a Scheduled Task to accomplish this. Rather than introduce a security risk by creating a new Administrator Account I just created the scheduled task to run as the local SYSTEM account. It turns out that the SYSTEM account does not have as much access as I required, especially when managing user registry hives.</p>
<p>After quite some time looking in to how to achieve my goal I came up with a rather simple, yet ultimately hacky, solution. Give the SYSTEM Account Administrative Privileges.</p>
<p><span id="more-305"></span></p>
<p>It turns out that the SYSTEM Account, despite not having Administrator level permissions, does have permission to modify group memberships. As such I came up with two functions to manage these permissions for itself:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #008000;">'*****************************************************************
</span><span style="color: #008000;">' Elevates the System Account to a Member of the Administrators Group
</span><span style="color: #E56717; font-weight: bold;">Function</span> ElevateSystem
  strSystemUser = <span style="color: #800000;">&quot;WinNT://NT AUTHORITY/SYSTEM&quot;</span>
  <span style="color: #151B8D; font-weight: bold;">Set</span> objGroup = <span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;WinNT://./Administrators,group&quot;</span>)
  <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> objGroup.isMember(strSystemUser) <span style="color: #8D38C9; font-weight: bold;">Then</span>
    objGroup.Add (strSystemUser)
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span>
&nbsp;
<span style="color: #008000;">'*****************************************************************
</span><span style="color: #008000;">' Removes the System Account from the Administrators Group
</span><span style="color: #E56717; font-weight: bold;">Function</span> RelegateSystem
  strSystemUser = <span style="color: #800000;">&quot;WinNT://NT AUTHORITY/SYSTEM&quot;</span>
  <span style="color: #151B8D; font-weight: bold;">Set</span> objGroup = <span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;WinNT://./Administrators,group&quot;</span>)
  <span style="color: #8D38C9; font-weight: bold;">If</span> objGroup.isMember(strSystemUser) <span style="color: #8D38C9; font-weight: bold;">Then</span>
    objGroup.Remove (strSystemUser)
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>I just run ElevateSystem at the start of the script and then RelegateSystem at the end of the script and I have no issue with permissions anymore.</p>
<p>Elegant, yet hacky. Hope somebody found this useful, because it sure beats creating (and then managing) a new Administrator User on thousands of Workstations. </p>
<p>N.B. I should also point out that if you are installing a script onto Workstations that you will be using this kind of workaround on, make sure you set the permissions on it. The last thing you need is somebody hijacking your script to do whatever they want with Administrative Privileges.</p>
<p>Cheers, Chris.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2010/05/25/system-account-permissions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Shared User Profiles &#8211; Staging Scripts</title>
		<link>http://www.dwarfsoft.com/blog/2010/03/15/shared-user-profiles-staging-scripts/</link>
		<comments>http://www.dwarfsoft.com/blog/2010/03/15/shared-user-profiles-staging-scripts/#comments</comments>
		<pubDate>Mon, 15 Mar 2010 05:19:40 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Novell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Tweet]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[eDirectory]]></category>
		<category><![CDATA[Hack]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Profile]]></category>
		<category><![CDATA[Script]]></category>
		<category><![CDATA[User Accounts]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=291</guid>
		<description><![CDATA[As promised, here are the scripts required for the Pre-staging of Domain User Profiles on the local machine. The first thing we need to do is Enumerate all the Local User Accounts. Function StageAllUsers(DomainFQDN, strDomain) ' Enumerate all users that are Local and not built in accounts. strComputer = &#34;.&#34; Set objWMIService = GetObject(&#34;winmgmts:\\&#34; &#38; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.dwarfsoft.com/blog/2010/03/12/shared-user-profiles-alternative-to-migration/">As promised</a>, here are the scripts required for the Pre-staging of Domain User Profiles on the local machine. The first thing we need to do is Enumerate all the Local User Accounts.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> StageAllUsers(DomainFQDN, strDomain)
   <span style="color: #008000;">' Enumerate all users that are Local and not built in accounts.
</span>   strComputer = <span style="color: #800000;">&quot;.&quot;</span>
   <span style="color: #151B8D; font-weight: bold;">Set</span> objWMIService = <span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;winmgmts:\\&quot;</span> &amp; strComputer &amp; <span style="color: #800000;">&quot;\root\cimv2&quot;</span>)
   <span style="color: #008000;">'Enumerate users where the User Domain is the Local Machine
</span>   <span style="color: #151B8D; font-weight: bold;">Set</span> colItems = objWMIService.ExecQuery _
                  (<span style="color: #800000;">&quot;Select * from Win32_UserAccount &quot;</span> &amp; _
                   <span style="color: #800000;">&quot;Where Domain = '&quot;</span> &amp; GetComputerName &amp; <span style="color: #800000;">&quot;' &quot;</span> &amp; _
                   <span style="color: #800000;">&quot;And Disabled = FALSE And Name &lt;&gt; 'Administrator'&quot;</span>)
   <span style="color: #008000;">' Stage each user
</span>   <span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> objItem <span style="color: #8D38C9; font-weight: bold;">In</span> colItems
      <span style="color: #008000;">' Ensure the account actually has a profile (otherwise we can ignore it)
</span>      <span style="color: #8D38C9; font-weight: bold;">If</span> GetLocalUserProfile(objItem.Name) &lt;&gt; <span style="color: #800000;">&quot;&quot;</span> <span style="color: #8D38C9; font-weight: bold;">Then</span>
         ret = StageUser(objItem.Name, DomainFQDN, strDomain)
      <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
   <span style="color: #8D38C9; font-weight: bold;">Next</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>The functions called here are GetComputerName, which returns the name of the local machine, and the other important ones are GetLocalUserProfile and Stage User. The first we can check is GetLocalUserProfile.<span id="more-291"></span></p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #008000;">'Gets the Profile Path for the User passed in UserName.
</span><span style="color: #008000;">' This requires the profile to exist on the local machine
</span><span style="color: #008000;">' Returns an empty string on error
</span><span style="color: #E56717; font-weight: bold;">Function</span> GetLocalUserProfile(UserName)
   <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #151B8D; font-weight: bold;">Resume</span> <span style="color: #8D38C9; font-weight: bold;">Next</span>
   GetLocalUserProfile = <span style="color: #800000;">&quot;&quot;</span>
   SDDL = GetLocalUserSDDL(UserName)
   <span style="color: #8D38C9; font-weight: bold;">If</span> SDDL = <span style="color: #800000;">&quot;&quot;</span> <span style="color: #8D38C9; font-weight: bold;">Then</span>
      <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
   <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
   <span style="color: #151B8D; font-weight: bold;">Set</span> objShell = <span style="color: #E56717; font-weight: bold;">CreateObject</span>(<span style="color: #800000;">&quot;WScript.Shell&quot;</span>)
   GetLocalUserProfile = objShell.ExpandEnvironmentStrings( _
                            objShell.RegRead( _
                               <span style="color: #800000;">&quot;HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\&quot;</span> &amp; _
                               SDDL &amp; _
                               <span style="color: #800000;">&quot;\ProfileImagePath&quot;</span>))
  <span style="color: #151B8D; font-weight: bold;">On</span> <span style="color: #151B8D; font-weight: bold;">Error</span> <span style="color: #8D38C9; font-weight: bold;">Goto</span> 0
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>The registry path (including the SDDL, covered next) returns the profile path for the user. This relies on a function called GetLocalUserSDDL which goes as follows:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> GetLocalUserSDDL(UserName)
   strComputer = <span style="color: #800000;">&quot;.&quot;</span>
   <span style="color: #151B8D; font-weight: bold;">Set</span> objWMIService = <span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;winmgmts:\\&quot;</span> &amp; strComputer &amp; <span style="color: #800000;">&quot;\root\cimv2&quot;</span>)
   <span style="color: #008000;">'Enumerate users where the User Domain is the Local Machine
</span>   <span style="color: #008000;">'and the username matches the Supplied Name
</span>   <span style="color: #151B8D; font-weight: bold;">Set</span> colItems = objWMIService.ExecQuery _
                     (<span style="color: #800000;">&quot;Select * from Win32_UserAccount  &quot;</span> &amp; _
                      <span style="color: #800000;">&quot;Where Domain = '&quot;</span> &amp; GetComputerName &amp; <span style="color: #800000;">&quot;' &quot;</span> &amp; _
                      <span style="color: #800000;">&quot;And Name = '&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;'&quot;</span>)
   GetLocalUserSDDL = <span style="color: #800000;">&quot;&quot;</span>
   <span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> objItem <span style="color: #8D38C9; font-weight: bold;">In</span> colItems
      <span style="color: #008000;">'Get the first returned SID/SDDL then exit
</span>      GetLocalUserSDDL = objItem.SID
      <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
   <span style="color: #8D38C9; font-weight: bold;">Next</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>This reads the SDDL (eg S-1-5-21-791012361-4073638415-1907800938-1006 or otherwise known as the String SID) for the User on the local machine. The next major function is Stage User:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> StageUser(UserName, DomainFQDN, strDomain)
   <span style="color: #151B8D; font-weight: bold;">Set</span> objShell = <span style="color: #E56717; font-weight: bold;">CreateObject</span>(<span style="color: #800000;">&quot;WScript.Shell&quot;</span>)
   <span style="color: #008000;">' Not Assuming &quot;C:\Documents and Settings\&quot; &amp; UserName:
</span>   <span style="color: #008000;">'   Get SDDL of user via WMI interrogation of UserAccount
</span>   <span style="color: #008000;">'   Get Profile Location of user (from HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\&quot; &amp; SDDL &amp; &quot;ProfileImagePath&quot;
</span>   strProfile = GetLocalUserProfile(UserName)
&nbsp;
   <span style="color: #008000;">' Set ACLs on ProfileLocation
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;subinacl /subdirectories &quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; strProfile &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot; /grant=&quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;@&quot;</span> &amp; DomainFQDN &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;=F&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
&nbsp;
   <span style="color: #008000;">' Set ACLs on D:\UserData\%username%
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;subinacl /subdirectories &quot;</span><span style="color: #800000;">&quot;D:\UserData\&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot; /grant=&quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;@&quot;</span> &amp; DomainFQDN &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;=F&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
&nbsp;
   <span style="color: #008000;">' Reg load ProfileLocation\NTUSER.DAT into HKU\%username%
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;reg load &quot;</span><span style="color: #800000;">&quot;HKU\&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot; &quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; strProfile &amp; <span style="color: #800000;">&quot;\NTUSER.DAT&quot;</span><span style="color: #800000;">&quot;&quot;</span> ,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
   <span style="color: #008000;">' Reg load ProfileLocation\Local Settings\Application Data\Microsoft\Windows\UsrClass.DAT into HKU\%username%_Classes
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;reg load &quot;</span><span style="color: #800000;">&quot;HKU\&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;_Classes&quot;</span><span style="color: #800000;">&quot; &quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; strProfile &amp; <span style="color: #800000;">&quot;\Local Settings\Application Data\Microsoft\Windows\UsrClass.DAT&quot;</span><span style="color: #800000;">&quot;&quot;</span> ,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
&nbsp;
   <span style="color: #008000;">'Try both of the following. One should fail, the other should pass.
</span>   <span style="color: #008000;">' Set ACLs on HKU\%username%
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;subinacl /subkeyreg &quot;</span><span style="color: #800000;">&quot;HKEY_USERS\&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot; /grant=&quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;@&quot;</span> &amp; DomainFQDN &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;=F&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
   <span style="color: #008000;">' If User is already logged in then the registry will be open at HKU\SDDL
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;subinacl /subkeyreg &quot;</span><span style="color: #800000;">&quot;HKEY_USERS\&quot;</span> &amp; GetLocalUserSDDL(UserName) &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot; /grant=&quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;@&quot;</span> &amp; DomainFQDN &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;=F&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
&nbsp;
   <span style="color: #008000;">'Try both of the following. One should fail, the other should pass.
</span>   <span style="color: #008000;">' Set ACLs on HKU\%username%
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;subinacl /subkeyreg &quot;</span><span style="color: #800000;">&quot;HKEY_USERS\&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;_Classes&quot;</span><span style="color: #800000;">&quot; /grant=&quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;@&quot;</span> &amp; DomainFQDN &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;=F&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
   <span style="color: #008000;">' If User is already logged in then the registry will be open at HKU\SDDL
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;subinacl /subkeyreg &quot;</span><span style="color: #800000;">&quot;HKEY_USERS\&quot;</span> &amp; GetLocalUserSDDL(UserName) &amp; <span style="color: #800000;">&quot;_Classes&quot;</span><span style="color: #800000;">&quot; /grant=&quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;@&quot;</span> &amp; DomainFQDN &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;=F&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
&nbsp;
   <span style="color: #008000;">' Reg unload HKU\%username%
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;reg unload &quot;</span><span style="color: #800000;">&quot;HKU\&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
   <span style="color: #008000;">' Reg unload HKU\%username%_Classes
</span>   ret = objShell.Run(<span style="color: #800000;">&quot;reg unload &quot;</span><span style="color: #800000;">&quot;HKU\&quot;</span> &amp; UserName &amp; <span style="color: #800000;">&quot;_Classes&quot;</span><span style="color: #800000;">&quot;&quot;</span>,0,<span style="color: #00C2FF; font-weight: bold;">True</span>)
&nbsp;
   <span style="color: #008000;">' Get Domain User SID from ProfileLocation ACL
</span>   arrSID = GetDomainUserSidFromFolderACL(strProfile, UserName, strDomain)
&nbsp;
   <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(arrSID) &gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span>
      <span style="color: #008000;">' Convert Domain User SID to SDDL
</span>      WScript.Echo <span style="color: #800000;">&quot;Getting Sid for &quot;</span> &amp; UserName
      SDDL = ArraySidToStrSid(arrSID)
&nbsp;
      <span style="color: #008000;">' Stage Domain User Profile into Registry under HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\%DomainUserSDDL%
</span>      ret = CreateAndLinkProfile(SDDL, arrSID, strProfile)
   <span style="color: #8D38C9; font-weight: bold;">Else</span>
      <span style="color: #008000;">'Account didn't exist in the domain or ACL failed to set on Folder
</span>   <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>For the most part this function behaves by running external commands to mount registry hives, and set ACLs on folders and registry, all up until we call GetDomainUserSidFromFolderACL. This is where we retrieve the SID of the Domain User that we are pre-staging via the ACL we set earlier on the Local User Profile folder. This subverts the need to query Active Directory for the SID through other means.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> GetDomainUserSidFromFolderACL(strFolder, strUserName, strUserDomain)
   <span style="color: #151B8D; font-weight: bold;">Dim</span> arrSID(0)
   GetDomainUserSidFromFolderACL = arrSID
&nbsp;
   <span style="color: #151B8D; font-weight: bold;">Set</span> objFSO = <span style="color: #E56717; font-weight: bold;">CreateObject</span>(<span style="color: #800000;">&quot;Scripting.FileSystemObject&quot;</span>)
   <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> objFSO.FolderExists(strFolder) <span style="color: #8D38C9; font-weight: bold;">Then</span>
      <span style="color: #151B8D; font-weight: bold;">Set</span> objFSO = <span style="color: #00C2FF; font-weight: bold;">Nothing</span>
      <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
   <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
&nbsp;
   <span style="color: #008000;">' Ensure that strFolder is of the form C:\\Documents and Settings\\UserName
</span>    strFolderName = Replace(strFolder, <span style="color: #800000;">&quot;\\&quot;</span>,<span style="color: #800000;">&quot;\&quot;</span>)
    strFolderName = Replace(strFolderName, <span style="color: #800000;">&quot;\&quot;</span>,<span style="color: #800000;">&quot;\\&quot;</span>)
&nbsp;
   <span style="color: #151B8D; font-weight: bold;">Set</span> wmiFileSecSetting = <span style="color: #E56717; font-weight: bold;">GetObject</span>( _
      <span style="color: #800000;">&quot;winmgmts:Win32_LogicalFileSecuritySetting.path='&quot;</span> &amp; strFolderName &amp; <span style="color: #800000;">&quot;'&quot;</span>)
&nbsp;
   RetVal = wmiFileSecSetting. _
       GetSecurityDescriptor(wmiSecurityDescriptor)
   <span style="color: #8D38C9; font-weight: bold;">If</span> Err &lt;&gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span>
       <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
   <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
&nbsp;
   <span style="color: #008000;">' Retrieve the DACL array of Win32_ACE objects.
</span>   DACL = wmiSecurityDescriptor.DACL
&nbsp;
   <span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">each</span> wmiAce <span style="color: #8D38C9; font-weight: bold;">in</span> DACL
   <span style="color: #008000;">' Get Win32_Trustee object from ACE 
</span>      <span style="color: #151B8D; font-weight: bold;">Set</span> Trustee = wmiAce.Trustee
      <span style="color: #8D38C9; font-weight: bold;">If</span> (StrComp(Trustee.Name, strUserName, vbTextCompare) = 0) <span style="color: #8D38C9; font-weight: bold;">And</span> _
         (StrComp(Trustee.Domain, strUserDomain, vbTextCompare) = 0) <span style="color: #8D38C9; font-weight: bold;">Then</span>
         GetDomainUserSidFromFolderACL = Trustee.SID
         <span style="color: #E56717; font-weight: bold;">Exit</span> <span style="color: #E56717; font-weight: bold;">Function</span>
      <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
   <span style="color: #8D38C9; font-weight: bold;">Next</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>Although this subverts the need to Query Active Directory, this does also mean that we receive the SID in a format that is unexpected. Normally, via querying Active Directory we would have received a SID in an Octet String format. Querying the SID from WMI returned it in SDDL or String SID format. The format that we receive the SID from the ACL is in an Array of Integers. In order to Pre-stage an account we need the SDDL/String SID, and the only way to get this in VBScript is to manually convert it using some functions developed by Richard Mueller and Wilfred Wong in <a href="http://groups.google.com.au/group/microsoft.public.windows.server.active_directory/browse_thread/thread/5e26b20bba486280/95eb5a589be4cf11">this newsgroup posting</a>.</p>
<p>Instead of using only the code listed, we need to alter it for dealing with the SID array we received back from the ACL.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> ArraySidToStrSid(arrSid)
   <span style="color: #008000;">' Function to convert OctetString (byte array) to Decimal string (SDDL) Sid.
</span>   <span style="color: #151B8D; font-weight: bold;">Dim</span> strHex, strDec
&nbsp;
   strHex = ArraySidToHexStr(arrSid)
   strDec = HexStrToDecStr(strHex)
   ArraySidToStrSid = strDec
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span>
&nbsp;
<span style="color: #E56717; font-weight: bold;">Function</span> ArraySidToHexStr(arrSid)
   ArraySidToHexStr = <span style="color: #800000;">&quot;&quot;</span>
   <span style="color: #8D38C9; font-weight: bold;">For</span> <span style="color: #8D38C9; font-weight: bold;">Each</span> x <span style="color: #8D38C9; font-weight: bold;">In</span> arrSid
      ArraySidToHexStr = ArraySidToHexStr &amp; _
         Right(<span style="color: #800000;">&quot;0&quot;</span> &amp; Hex(x), 2)
   <span style="color: #8D38C9; font-weight: bold;">Next</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>The HexStrToDecStr function is the same as it was from the <a href="http://groups.google.com.au/group/microsoft.public.windows.server.active_directory/browse_thread/thread/5e26b20bba486280/95eb5a589be4cf11">Richard Mueller posting</a> listed above.</p>
<p>Finally we just need to run through the actual staging of the account:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> CreateAndLinkProfile(strNewSDDL, strNewSID, strProfilePath)
   WScript.Echo <span style="color: #800000;">&quot;Creating Profile for &quot;</span> &amp; strNewSDDL &amp; <span style="color: #800000;">&quot;: &quot;</span> &amp; strProfilePath
   <span style="color: #008000;">'Write Sid to registry
</span>   ret = WriteRegBinaryToRegistry(HKEY_LOCAL_MACHINE,<span style="color: #800000;">&quot;SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\&quot;</span> &amp; strNewSDDL,<span style="color: #800000;">&quot;Sid&quot;</span>,strNewSID)
   ret = WriteRegStringToRegistry(HKEY_LOCAL_MACHINE,<span style="color: #800000;">&quot;SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\&quot;</span> &amp; strNewSDDL,<span style="color: #800000;">&quot;ProfileImagePath&quot;</span>,strProfilePath)
   ret = WriteRegStringToRegistry(HKEY_LOCAL_MACHINE,<span style="color: #800000;">&quot;SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\&quot;</span> &amp; strNewSDDL,<span style="color: #800000;">&quot;CentralProfile&quot;</span>,<span style="color: #800000;">&quot;&quot;</span>)
   ret = WriteRegDwordToRegistry(HKEY_LOCAL_MACHINE,<span style="color: #800000;">&quot;SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\&quot;</span> &amp; strNewSDDL,<span style="color: #800000;">&quot;Flags&quot;</span>,1)
   ret = WriteRegDwordToRegistry(HKEY_LOCAL_MACHINE,<span style="color: #800000;">&quot;SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\&quot;</span> &amp; strNewSDDL,<span style="color: #800000;">&quot;State&quot;</span>,0)
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>At this point if the Domain User logs in they get redirected to the existing local users profile. Then if rollback is initiated they log on with the Local User account with the same profile. This is seamless to end users, both forward and backward. </p>
<p>On a side note the functions for writing to the registry are through WMI due to needing to write Binary values to the Registry</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> WriteRegBinaryToRegistry(Hive, strKeyPath, strValueName, ArrValues)
   strComputer = <span style="color: #800000;">&quot;.&quot;</span>
   <span style="color: #151B8D; font-weight: bold;">Set</span> oReg = <span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;winmgmts:{impersonationLevel=impersonate}!\\&quot;</span> &amp; _
               strComputer &amp; <span style="color: #800000;">&quot;\root\default:StdRegProv&quot;</span>)
   oReg.CreateKey Hive,strKeyPath
&nbsp;
   oReg.SetBinaryValue Hive, strKeyPath, strValueName,ArrValues
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span>
&nbsp;
<span style="color: #E56717; font-weight: bold;">Function</span> WriteRegDwordToRegistry(Hive, strKeyPath, strValueName, Value)
   strComputer = <span style="color: #800000;">&quot;.&quot;</span>
   <span style="color: #151B8D; font-weight: bold;">Set</span> oReg = <span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;winmgmts:{impersonationLevel=impersonate}!\\&quot;</span> &amp; _
               strComputer &amp; <span style="color: #800000;">&quot;\root\default:StdRegProv&quot;</span>)
   oReg.CreateKey Hive,strKeyPath
&nbsp;
   oReg.SetDwordValue Hive, strKeyPath, strValueName,Value
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span>
&nbsp;
<span style="color: #E56717; font-weight: bold;">Function</span> WriteRegStringToRegistry(Hive, strKeyPath, strValueName, Value)
   strComputer = <span style="color: #800000;">&quot;.&quot;</span>
   <span style="color: #151B8D; font-weight: bold;">Set</span> oReg = <span style="color: #E56717; font-weight: bold;">GetObject</span>(<span style="color: #800000;">&quot;winmgmts:{impersonationLevel=impersonate}!\\&quot;</span> &amp; _
               strComputer &amp; <span style="color: #800000;">&quot;\root\default:StdRegProv&quot;</span>)
   oReg.CreateKey Hive,strKeyPath
&nbsp;
   oReg.SetStringValue Hive, strKeyPath, strValueName,Value
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #E56717; font-weight: bold;">Function</span></pre></div></div>

<p>Cheers, Chris.</p>
<p>Edit: <a href='http://www.dwarfsoft.com/blog/wp-content/uploads/2010/03/DomainAccountProfileStaging.vbs_.txt'>DomainAccountProfileStaging.vbs</a> has been uploaded as a complete file.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2010/03/15/shared-user-profiles-staging-scripts/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Shared User Profiles &#8211; Alternative to Migration</title>
		<link>http://www.dwarfsoft.com/blog/2010/03/12/shared-user-profiles-alternative-to-migration/</link>
		<comments>http://www.dwarfsoft.com/blog/2010/03/12/shared-user-profiles-alternative-to-migration/#comments</comments>
		<pubDate>Fri, 12 Mar 2010 10:01:16 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Novell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Tweet]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[eDirectory]]></category>
		<category><![CDATA[Hack]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Profile]]></category>
		<category><![CDATA[User Accounts]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=287</guid>
		<description><![CDATA[Well, I have been very slack in that I haven&#8217;t updated with my Group Policy investigations or the eDirectory VBScript classes I was working on, but what I have been involved in recently is working on Migrating Workstations from Novell eDirectory to Active Directory. In this process I have come across an array of options [...]]]></description>
			<content:encoded><![CDATA[<p>Well, I have been very slack in that I haven&#8217;t updated with my Group Policy investigations or the eDirectory VBScript classes I was working on, but what I have been involved in recently is working on Migrating Workstations from Novell eDirectory to Active Directory.</p>
<p>In this process I have come across an array of options in migrating accounts from a Local User account to Domain User account and transferring the profiles across to keep the user &#8220;look and feel&#8221; that they are accustomed to.</p>
<p>One problem: In this scenario it makes for a very manual rollback strategy, no matter how much scripting and automation is involved in the migration process. This boils down to Novells implementation of &#8220;Dynamic Local User&#8221; which effectively creates a Local User Account that is not really bound to a User Account in eDirectory for Authentication or mapping purposes (which you can see if you look at the account SIDs).</p>
<p><span id="more-287"></span></p>
<p>So, how can you Migrate a local profile to a Domain User account while still maintaining a seamless rollback option (without using Roaming Profiles&#8230; This is out of the question)? The solution I have worked on is what I am terming &#8220;pre-staging&#8221; or &#8220;seeding&#8221; the Domain User Profile.</p>
<ol>
<li>Enumerate all Local Enabled Users (except for &#8220;Administrator&#8221;)</li>
<li>Get the SID for that User (and the SDDL/String SID)</li>
<li>Read the Profile Path for that User from Registry</li>
<li>Set an ACL on that folder for &lt;Domain>\&lt;UserName> (we have the UserName being replicated between eDirectory and Active Directory</li>
<li>Mount the existing users NTUser.dat into HKU\&lt;UserName></li>
<li>Set ACL on HKU\&lt;UserName> and all subkeys for &lt;Domain>\&lt;UserName></li>
<li>Set ACL on HKU\&lt;LocalUserSID> and all subkeys  for &lt;Domain>\&lt;UserName> (just in case the user is actually logged in)</li>
<li>Dismount HKU\&lt;UserName></li>
<li>Mount the User Class hive (UsrClass.dat) into HKU\&lt;UserName>_Classes</li>
<li>Set ACL on HKU\&lt;UserName>_Classes and all subkeys for &lt;Domain>\&lt;UserName></li>
<li>Set ACL on HKU\&lt;LocalUserSID>_Classes and all subkeys  for &lt;Domain>\&lt;UserName> (just in case the user is actually logged in)</li>
<li>Dismount HKU\&lt;UserName>_Classes</li>
<li>Read the ACL on the Profile Folder (set Earlier) for &lt;Domain>\&lt;UserName> to get the Domain User SID</li>
<li>Convert the Domain User SID to an SDDL/String SID</li>
<li>Pre-stage/Seed the Domain User Profile by creating a new Registry key in HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\&lt;DomainUserSDDL></li>
<li>Write in a few choice keys, the two most important being ProfileImagePath (String) and Sid (Binary). (The others I seeded were the DWords State and Flags, which were set to 0, and CentralProfile, which was an empty string).</li>
</ol>
<p>Once the eDirectory user is no longer a member of a DLU enabled User Profile Package, they will be forced to log on through the Active Directory Domain (yes, we are still logging on through the Novell Client). The Profile used for the Domain User will be the same as that used by the Local user. The added benefit is that our rollback strategy becomes &#8220;Add user to a DLU enabled User Policy Package&#8221; and gets them to log back into their original profile. To safely secure a situation where there is a catastrophic failure of the profile (loss) a backup of the profile can also be done at the seeding stage (just check %userdomain% for equality with %computername% to see if they are logging on with a Local account or a Domain Account).</p>
<p>This has had only minor testing at this stage, but as no paths have changed and there appears to be no problem with the Domain User using the existing Profile I believe this is a reasonably comprehensive solution. This, I must stress, is not a recommended way to deal with migrating users, but it is a tricky little feature that can be abused as I have just demonstrated.</p>
<p>Code (or VBScript) will follow soon</p>
<p>Cheers, Chris.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2010/03/12/shared-user-profiles-alternative-to-migration/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

