<?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; Novell</title>
	<atom:link href="http://www.dwarfsoft.com/blog/tag/novell/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>Group Policy Editing &#8211; Findings</title>
		<link>http://www.dwarfsoft.com/blog/2010/06/15/group-policy-editing-findings/</link>
		<comments>http://www.dwarfsoft.com/blog/2010/06/15/group-policy-editing-findings/#comments</comments>
		<pubDate>Tue, 15 Jun 2010 03:16:01 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Novell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Tweet]]></category>
		<category><![CDATA[Domain]]></category>
		<category><![CDATA[eDirectory]]></category>
		<category><![CDATA[Group Policy]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[Profile]]></category>
		<category><![CDATA[Script]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=309</guid>
		<description><![CDATA[I had started another post on Group Policy editing, and how the Policy files are structured, and how to use and improve on the existing Group Policy Editor tool. The post has been found to be far too epic, so I have decided to cover a smaller subset of recent finds. As everybody is probably [...]]]></description>
			<content:encoded><![CDATA[<p>I had started another post on Group Policy editing, and how the Policy files are structured, and how to use and improve on the existing Group Policy Editor tool. The post has been found to be far too epic, so I have decided to cover a smaller subset of recent finds. </p>
<p>As everybody is probably already aware, we use Novell ConsoleOne and Zenworks where I work. ConsoleOne has some interesting features that require that whenever a Group Policy is being edited it takes over as the policy on the machine that is editing it. Rather than have a useful tool like Microsofts Group Policy Management Console, Novell likes to replace the local Group Policy and then just run gpedit.msc. Which is where my first gripe about gpedit.msc comes in:</p>
<p>GPEdit.msc requires line by line entry of things like, for example, port exceptions and program exceptions for the Windows Firewall. This is usually not an issue except that, as I have discussed in previous posts, we have been moving towards a Windows Domain environment. Firewall Exception rules are configured within two places in Group Policy: Domain Profile and Standard Profile. I have found that there is a need to move our current Standard Profile settings across to the Domain Profile settings. After a bit of registry searching I found a neat trick for doing exactly that.</p>
<p><span id="more-309"></span></p>
<p>In Novell, when a GPO is opened in gpedit.msc the Group Policy Contents are loaded into the normal registry locations (as per a normal GPO being applied to user and machine) and the contents are also loaded under a specific pair of registry keys. The <strong>HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects</strong> Key is created on loading gpedit.msc, and underneath a pair of Keys are created like <strong>{449E44B0-A4DC-4665-AE8F-68710E1BC1EC}Machine</strong> and <strong>{449E44B0-A4DC-4665-AE8F-68710E1BC1EC}User</strong>, where the GUID is randomly generated  (or at least seems to be random) each time gpedit.msc is run. Under these keys are the branch on which the Group Policy Settings are configured.</p>
<p>So therefore in order to duplicate StandardProfile Settings I need to duplicate all keys and values underneath <strong>HKCU\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\<em>{GUID}</em>Machine\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\</strong>, where {GUID} is the randomly generated GUID for editing a Group Policy Object. So far from my research I have never seen more than one GUID appear underneath the <strong>Group Policy Objects</strong> key, though your mileage may vary. So the first step is to get the User and Machine keys from under the Group Policy Objects key.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;">Const HKEY_CURRENT_USER = &amp;H80000001
Const HKEY_LOCAL_MACHINE = &amp;H80000002
&nbsp;
Const REG_SZ = 1
Const REG_EXPAND_SZ = 2
Const REG_BINARY = 3
Const REG_DWORD = 4
Const REG_MULTI_SZ = 7
&nbsp;
strComputer = <span style="color: #800000;">&quot;.&quot;</span>
&nbsp;
<span style="color: #151B8D; font-weight: bold;">Set</span> objReg=<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>)
&nbsp;
strKeyPath = <span style="color: #800000;">&quot;Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\&quot;</span>
strStandardPath = <span style="color: #800000;">&quot;\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\&quot;</span>
strDomainPath = <span style="color: #800000;">&quot;\Software\Policies\Microsoft\WindowsFirewall\DomainProfile\&quot;</span>
&nbsp;
<span style="color: #8D38C9; font-weight: bold;">If</span> keyExists(HKEY_CURRENT_USER,strKeyPath) <span style="color: #8D38C9; font-weight: bold;">Then</span>
  subkeys = GetSubkeys(HKEY_CURRENT_USER,strKeyPath)
  <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> IsEmpty(subkeys) <span style="color: #8D38C9; font-weight: bold;">Then</span>
    GPOMachine = subkeys(<span style="color: #151B8D; font-weight: bold;">LBound</span>(subkeys)) 
    GPOUser    = subkeys(<span style="color: #151B8D; font-weight: bold;">UBound</span>(subkeys))
&nbsp;
    RegCopyTree HKEY_CURRENT_USER, strKeyPath &amp; GPOMachine &amp; strStandardPath, strKeyPath &amp; GPOMachine &amp; strDomainPath, <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">Else</span>
    WScript.Echo <span style="color: #800000;">&quot;Policy not found, please try editing the policy manually&quot;</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;">Else</span>
  WScript.Echo <span style="color: #800000;">&quot;Please start editing the Group Policy before running this script&quot;</span>
<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span></pre></div></div>

<p>The code here is the shell of the script. We need to flesh out the functions keyExists, GetSubkeys, RegCopyTree, and valueExists (which we can&#8217;t see just yet). So first we will have a look at keyExists:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> keyExists(Hive, Key)
  <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>
  Err.Clear
&nbsp;
  ret = objReg.EnumValues(Hive,Key,arrValues,arrValueTypes)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">If</span> ret &lt;&gt; 0 <span style="color: #8D38C9; font-weight: bold;">Then</span>
    keyExists = <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">Else</span>
    keyExists = <span style="color: #00C2FF; font-weight: bold;">True</span>
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
  Err.Clear
  <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>Fairly straightforward, we try and enumerate the values of a key. If we succeed then the key does exist, otherwise it doesn&#8217;t. We will use the same principle for checking if a Value Exists.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> valueExists(Hive, Key, ValueName)
  <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>
  Err.Clear
&nbsp;
  valueExists = <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> keyExists(Hive, Key) <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;
  ret = objReg.EnumValues(Hive,Key,arrValues,arrValueTypes)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">If</span> IsNull(arrValues) <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: #8D38C9; font-weight: bold;">For</span> i = <span style="color: #151B8D; font-weight: bold;">LBound</span>(arrValues) <span style="color: #8D38C9; font-weight: bold;">to</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(arrValues)
    <span style="color: #8D38C9; font-weight: bold;">If</span> LCase(CStr(arrValues(i))) = LCase(CStr(ValueName)) <span style="color: #8D38C9; font-weight: bold;">Then</span>
	  valueExists = <span style="color: #00C2FF; font-weight: bold;">True</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: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
  valueExists = <span style="color: #00C2FF; font-weight: bold;">False</span>
&nbsp;
  Err.Clear
  <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>Here, we take the Enumeration of the Keys Values a step further and actually step through them looking for a match with ValueName. I have opted for a Case Insensitive search due to registry being case insensitive with value names.</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> GetSubkeys(Hive, Key)
  <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>
  Err.Clear
&nbsp;
  ret = objReg.EnumKey(Hive,Key,arrSubkeys)
&nbsp;
  GetSubkeys = arrSubkeys
&nbsp;
  Err.Clear
  <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>Possibly the simplest of the functions, GetSubkeys just returns an array of Keys underneath the current Key. The most indepth function we require is the RegCopyTree:</p>

<div class="wp_syntax"><div class="code"><pre class="vb" style="font-family:monospace;"><span style="color: #E56717; font-weight: bold;">Function</span> RegCopyTree(Hive, SrcKey, DestKey, Force)
  <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>
  Err.Clear
  strComputer = <span style="color: #800000;">&quot;.&quot;</span>
  <span style="color: #151B8D; font-weight: bold;">Set</span> StdOut = WScript.StdOut
  strValue = <span style="color: #800000;">&quot;&quot;</span>
  <span style="color: #8D38C9; font-weight: bold;">If</span> Force &lt;&gt; <span style="color: #00C2FF; font-weight: bold;">True</span> <span style="color: #8D38C9; font-weight: bold;">Then</span>
    Force = <span style="color: #00C2FF; font-weight: bold;">False</span>
  <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">if</span> Right(SrcKey,1) &lt;&gt; <span style="color: #800000;">&quot;\&quot;</span> <span style="color: #8D38C9; font-weight: bold;">Then</span> SrcKey = SrcKey &amp; <span style="color: #800000;">&quot;\&quot;</span>
  <span style="color: #8D38C9; font-weight: bold;">if</span> Right(DestKey,1) &lt;&gt; <span style="color: #800000;">&quot;\&quot;</span> <span style="color: #8D38C9; font-weight: bold;">Then</span> DestKey = DestKey &amp; <span style="color: #800000;">&quot;\&quot;</span>
&nbsp;
  ret = objReg.EnumValues(Hive,SrcKey,arrValueNames,arrValueTypes)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">For</span> i= <span style="color: #151B8D; font-weight: bold;">LBound</span>(arrValueNames) <span style="color: #8D38C9; font-weight: bold;">To</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(arrValueNames)
    <span style="color: #008000;">'StdOut.WriteLine &quot;Value Name: &quot; &amp; arrValueNames(i) 
</span>	StdOut.WriteLine <span style="color: #800000;">&quot;Copying from: &quot;</span> &amp; SrcKey &amp; arrValueNames(i)
	StdOut.WriteLine <span style="color: #800000;">&quot;To          : &quot;</span> &amp; DestKey &amp; arrValueNames(i)
    StdOut.Write     <span style="color: #800000;">&quot;       Value: &quot;</span>
&nbsp;
	<span style="color: #8D38C9; font-weight: bold;">If</span> (<span style="color: #8D38C9; font-weight: bold;">Not</span> valueExists(Hive, DestKey, arrValueNames(i))) <span style="color: #8D38C9; font-weight: bold;">Or</span> Force <span style="color: #8D38C9; font-weight: bold;">Then</span>
	  <span style="color: #8D38C9; font-weight: bold;">Select</span> <span style="color: #8D38C9; font-weight: bold;">Case</span> arrValueTypes(i)
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_SZ
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: String&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetStringValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetStringValue Hive, DestKey, arrValueNames(i), strValue
				StdOut.Write strValue
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_EXPAND_SZ
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: Expanded String&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetExpandedStringValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetExpandedStringValue Hive, DestKey, arrValueNames(i), strValue
				StdOut.Write strValue
&nbsp;
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_BINARY
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: Binary&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetBinaryValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetBinaryValue Hive, DestKey, arrValueNames(i), strValue
				<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> strValue
		          StdOut.Write Hex(x) &amp; <span style="color: #800000;">&quot; &quot;</span>
		        <span style="color: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_DWORD
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: DWORD&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetDWORDValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetDWordValue Hive, DestKey, arrValueNames(i), strValue
&nbsp;
				StdOut.Write Hex(strValue)
			<span style="color: #8D38C9; font-weight: bold;">Case</span> REG_MULTI_SZ
				<span style="color: #008000;">'StdOut.WriteLine &quot;Data Type: Multi String&quot;
</span>				<span style="color: #008000;">'StdOut.WriteBlankLines(1)
</span>				
				objReg.GetMultiStringValue Hive, SrcKey, arrValueNames(i), strValue
				objReg.SetMultiStringValue Hive, DestKey, arrValueNames(i), strValue
				<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> strValue
		          StdOut.Write x
		        <span style="color: #8D38C9; font-weight: bold;">Next</span>
		<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">Select</span> 
&nbsp;
		StdOut.WriteLine <span style="color: #800000;">&quot;&quot;</span>
    <span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #008000;">'' Force
</span>  <span style="color: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
  ret = objReg.EnumKey(Hive,SrcKey,arrSubkeys)
&nbsp;
  <span style="color: #8D38C9; font-weight: bold;">For</span> i = <span style="color: #151B8D; font-weight: bold;">LBound</span>(arrSubkeys) <span style="color: #8D38C9; font-weight: bold;">to</span> <span style="color: #151B8D; font-weight: bold;">UBound</span>(arrSubkeys)
    <span style="color: #8D38C9; font-weight: bold;">If</span> <span style="color: #8D38C9; font-weight: bold;">Not</span> keyExists(Hive,DestKey &amp; arrSubkeys(i)) <span style="color: #8D38C9; font-weight: bold;">Then</span>
	  objReg.CreateKey Hive,DestKey &amp; arrSubkeys(i)
	<span style="color: #8D38C9; font-weight: bold;">End</span> <span style="color: #8D38C9; font-weight: bold;">If</span>
	RegCopyTree Hive, SrcKey &amp; arrSubkeys(i), DestKey &amp; arrSubkeys(i), Force
  <span style="color: #8D38C9; font-weight: bold;">Next</span>
&nbsp;
  <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>This function takes the Hive, Source Key, Destination Key, and a Boolean Value to determine whether to Force overwriting existing values. It first creates the Destination key if it doesn&#8217;t already exist, then enumerates all values in the Source path, and writes them to the Destination path, creating new values or overwriting only if Force is set. This function has a lot of StdOut.Write calls to show the progress of the duplication. Running the script via CScript gives the following results:</p>
<pre>Copying from: Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\EnableFirewall
To          : Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\DomainProfile\EnableFirewall
       Value: 1
Copying from: Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\StandardProfile\AuthorizedApplications\Enabled
To          : Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{678C8897-54AA-4FB9-AA72-6C227C287D12}Machine\Software\Policies\Microsoft\WindowsFirewall\DomainProfile\AuthorizedApplications\Enabled
       Value: 1
...</pre>
<p>This should simplify the time taken for duplicating from Standard to Domain profile. For future reference this has also made it far easier to import/export port/program exceptions from policies I am editing. In future I may incorporate this into my Group Policy Firewall Exceptions Excel Spreadsheet in VBA to allow writing updated policies to the Policy.</p>
<p>After running this the settings will be seen to have changed in the Group Policy Editor Window immediately. I have tested this and checked that the Logging file is not replaced by &#8220;&#8230;\standard.log&#8221; where it should be &#8220;&#8230;\domain.log&#8221;.</p>
<p>Cheers, Chris.</p>
<p>Attached: <a href='http://www.dwarfsoft.com/blog/wp-content/uploads/2010/06/RegFirewallProfileDuplication.vbs_.txt'>RegFirewallProfileDuplication.vbs</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2010/06/15/group-policy-editing-findings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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>
		<item>
		<title>Back Behind the Keyboard</title>
		<link>http://www.dwarfsoft.com/blog/2009/07/20/back-behind-the-keyboard/</link>
		<comments>http://www.dwarfsoft.com/blog/2009/07/20/back-behind-the-keyboard/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 04:31:21 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Home]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Study]]></category>
		<category><![CDATA[Uni]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Application]]></category>
		<category><![CDATA[Book]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Certification]]></category>
		<category><![CDATA[Daugher]]></category>
		<category><![CDATA[Exam]]></category>
		<category><![CDATA[Graduation]]></category>
		<category><![CDATA[GTD]]></category>
		<category><![CDATA[Novell]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[PyTA]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[TED]]></category>
		<category><![CDATA[VBScript]]></category>
		<category><![CDATA[XNA]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=252</guid>
		<description><![CDATA[It has again been some time since my last update. I have been quite busy getting used to balancing my new life with my daughter now nearly 3 months old. Fatherhood has obviously taken a lot of my time that I previously used for development, and learning. The past few months have also seen my [...]]]></description>
			<content:encoded><![CDATA[<p>It has again been some time since my last update. I have been quite busy getting used to balancing my new life with my daughter now nearly 3 months old. Fatherhood has obviously taken a lot of my time that I previously used for development, and learning.</p>
<p>The past few months have also seen my University Graduation 3 days after my Daughters Birth, Family Visits, Job Applications, Job Interviews, and finally Permanency in my Servers Position.</p>
<p>Aside from that I have been working with some friends on converting the old TA Server to the C# .Net/Python version (PyTA). I have also been busy in mapping out my development goals and objectives for the coming months and years.</p>
<p><span id="more-252"></span></p>
<div class="wp-caption alignright" style="width: 84px"><a href="http://www.amazon.com/dp/0142000280?tag=dwgp-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=0142000280&amp;adid=0VNZXPFS9EAVTH6R7JM5&amp;"><img title="David Allens Getting Things Done" src="http://rcm-images.amazon.com/images/I/4104N6ME70L._SL110_.jpg" alt="David Allens Getting Things Done" width="74" height="110" /></a><p class="wp-caption-text">David Allens Getting Things Done</p></div>
<p>In order to better manage my time and my priorities I have been implementing and reviewing <a href="http://www.davidco.com/">David Allen&#8217;s</a> &#8220;Getting Things Done&#8221;, and have been operating my own install of GTD-PHP. I have been using this to manage all aspects of my life, from professional to personal projects. This has allowed me a lot greater control of my personal and professional life and allowed me to manage my time far more effectively than ever before. Currently in this system I am managing 100 Active Projects, 44 Someday/Maybe Projects, and within those I have currently 147 Actions within those. I am still in the process of determining Next actions for some of these projects, but at least having visibility of all these things I need to do has given me greater control of managing the most important of these. Most of the projects without next actions are someday/maybe projects, and the others that are not could be put in someday/maybe until such time as I have time to process their next actions. I definitely encourage anybody to try this method of organisation, time management, prioritisation because it has helped me to lower my stress and be able to switch off from work when I get home. Just note that it does tend to increase the likelihood of adding more projects to your list than you started out doing <img src='http://www.dwarfsoft.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p>Aside from this I have been attempting to build an Application Audit script at work that will pull the NAL objects from our system through LDAP. I have started coding this type of script now as a class which is in a .vbs file and then for implementing its use I have started using .wsf files to include and execute the required code. This adds to the usability of my existing code and makes my code far more acccessible for reuse in other applications. I had already started writing these types of classes before for my Ini File Handler, but previously I had been including the VBScript files internally using a manual Include function:</p>

<div class="wp_syntax"><div class="code"><pre class="vbnet" style="font-family:monospace;"><span style="color: #0600FF;">Function</span> Include<span style="color: #000000;">&#40;</span>vbsFile<span style="color: #000000;">&#41;</span>
   <span style="color: #FF8000;">Set</span> fso <span style="color: #008000;">=</span> <span style="color: #0600FF;">CreateObject</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">&quot;Scripting.FileSystemObject&quot;</span><span style="color: #000000;">&#41;</span>
   <span style="color: #0600FF;">If</span> fso.<span style="color: #0000FF;">FileExists</span><span style="color: #000000;">&#40;</span>vbsFile<span style="color: #000000;">&#41;</span> <span style="color: #FF8000;">Then</span>
      <span style="color: #FF8000;">Set</span> f <span style="color: #008000;">=</span> fso.<span style="color: #0000FF;">OpenTextFile</span><span style="color: #000000;">&#40;</span>vbsFile<span style="color: #000000;">&#41;</span>
      s <span style="color: #008000;">=</span> f.<span style="color: #0000FF;">ReadAll</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
      f.<span style="color: #0600FF;">Close</span>
      ExecuteGlobal s
   <span style="color: #0600FF;">End</span> <span style="color: #0600FF;">If</span>
<span style="color: #0600FF;">End</span> <span style="color: #0600FF;">Function</span></pre></div></div>

<p>The .wsf include method is so much cleaner:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;script</span> <span style="color: #000066;">language</span>=<span style="color: #ff0000;">&quot;VBScript&quot;</span> <span style="color: #000066;">src</span>=<span style="color: #ff0000;">&quot;Applications.vbs&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>When I have managed to get my projects and actions further under control I will have to provide updates. I have some plans for the XNA in a Day series which I started with breakout, but that is some way off. I am also planning on overhauling some of my previous projects and actually actioning them. </p>
<p>Cheers, Chris.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2009/07/20/back-behind-the-keyboard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Manipulating CSV Files &#8211; Part 1</title>
		<link>http://www.dwarfsoft.com/blog/2008/09/09/manipulating-csv-files-part-1/</link>
		<comments>http://www.dwarfsoft.com/blog/2008/09/09/manipulating-csv-files-part-1/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 04:44:46 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Certification]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[Novell]]></category>
		<category><![CDATA[Politics]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Study]]></category>
		<category><![CDATA[Training]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Batch]]></category>
		<category><![CDATA[MCSA]]></category>
		<category><![CDATA[MCSA Messaging]]></category>
		<category><![CDATA[MCSE]]></category>
		<category><![CDATA[VBScript]]></category>
		<category><![CDATA[Workstation]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=67</guid>
		<description><![CDATA[Before I jump in to the fun that is the Scripting that I have been wading through this past week, I thought I&#8217;d let all of those who may care that I finally have some kind of certification. I passed Microsoft exams 70-291 and 70-284. So I am now the proud holder of a Microsoft [...]]]></description>
			<content:encoded><![CDATA[<p>Before I jump in to the fun that is the Scripting that I have been wading through this past week, I thought I&#8217;d let all of those who may care that I finally have some kind of certification. I passed Microsoft exams 70-291 and 70-284. So I am now the proud holder of a Microsoft Certified Systems Administrator Messaging Specialist certification (MCSA Messaging). Now I am concentrating on the final three exams so that I can get my MCSE.</p>
<p>After a rather hectic week of scripting a solution and then distributing it under an excessively short deadline, I have been asked to provide stats on the result of forcing this solution out to clients. The solution that I had to develop keeps tabs on a System Volume Image of PCs, and ensures that this Image never gets out of date too far. Currently I am not forcing a Store every restart, as the planned solution was to do, but I do inform the client that their current Image is out of date and ask them if they want to do a Store now. If they click on Yes then their PC is rebooted and the Store is done (providing that one of many flaws in the current Store process do not interrupt the process).<span id="more-67"></span></p>
<p>Because of some of the issues that we have had, as well as Managements want to view the impact of what we have done in a statistical format, I was required to provide a secondary application, which is just an updated version of an AutoIT Script that logs the Image Date into a log file during login. Because this file was preexisting it has been used in this way to gather stats for some time.</p>
<p>The issue is that the log file includes EVERY instance of a login for a PC, and I want only the most recent with the timestamp of the image, not all the other instances, or the log values that are too old (I was unable to clear the logs due to current procedure). Therefore I was required to learn some new things in the VBScript world. This solution is surprisingly fast considering how much data it is required to crunch in order to produce the output CSV file.</p>
<pre>Const ForReading = 1
Const ForWriting = 2

Dim arrLines()
i = 0

Set objDictionary = CreateObject("Scripting.Dictionary")
Set objFSO = CreateObject("Scripting.FileSystemObject")

objStartFolder = WScript.ScriptFullNameobjStartFolder = Replace  (objStartFolder, WScript.ScriptName, "") 

Set objFolder = objFSO.GetFolder(objStartFolder &amp; "Logs")

Set colFiles = objFolder.Files
For Each objFile in colFiles
    Set textFile = objFSO.OpenTextFile(objFile.Path, ForReading)

    Do Until textFile.AtEndOfStream
        Redim Preserve arrLines(i)
        arrLines(i) = textFile.ReadLine
        i = i + 1
    Loop

    For i = Ubound(arrLines) to LBound(arrLines) Step -1
        splt = Split (arrLines(i),",")

        If (UBound(splt) &lt; 19) Then
            i = LBound(arrLines)
        Else
            If Splt(19) &lt;&gt; "" Then
               If Not objDictionary.Exists(splt(1)) Then
                  objDictionary.Add splt(1),splt(19)
               End If
            End If
        End If
    Next

    ReDim arrLines(0)
    i = 0
    textFile.Close
Next

Set writeFile = objFSO.CreateTextFile(objStartFolder &amp; "Stores.csv")
For Each strKey in objDictionary.Keys
   writeFile.WriteLine strKey &amp; "," &amp; objDictionary.Item(strKey)
Next
writeFile.Close</pre>
<p>In this particular script the splt Array has 20 columns (or 19 for those items that were prior to me updating the script). Column 2 (or splt(1)) is the PC Name, and Column 20 (or splt(19)) is the Timestamp of the Image. This script reads through every file in the Logs folder (in the same path as the script) and reads the file in reverse until it comes across the entries with only 19 columns. For every unique PC Name that it finds it adds this into a Dictionary object with the Timestamp as the value. The Dictionary is then written to the new CSV file one at a time.</p>
<p>In order to get the stats on how effective this has been, I paste a couple of Excel Macros:</p>
<pre>=COUNTIF(B:B,"&gt;22/08/2008")
=COUNT(B:B)</pre>
<p>The magic date here is the 22nd of August 2008. This was chosen purely because it was a recent date, and it was newer than most of the Images for the PCs within the IT Department, who already had the AutoStore scripts working on their machines. Which provided for a controlled Environment for testing some of the modifications I was forced to make last minute.</p>
<p>One thing that I could do to improve the accuracy of this script is to pull out all the Workstation Names from Novell using LDAP and get a total overall status of where the Store dates are across all PCs, but that would pollute the pool with a large number of machines that have been decommissioned (they still appear as a Workstation in Novell until they have not been logged on to for 3 months, then they fall off the system).</p>
<p>On a side note, I have to pull in the Logs into the Logs directory in some way, which is achieved for me by running a Batch file which I have written as follows:</p>
<pre>@ECHO OFF
ECHO Pulling Logs %DATE% - %TIME%&gt;&gt;Log.txt
ECHO.&gt;&gt;Log.txt
%~d0
cd %~dp0
FOR /F "tokens=*" %%A IN (Sources.txt) DO (
  FOR /F "tokens=1 delims=" %%Z IN ("%%A") DO (
     COPY "%%AlogsLogIn.csv" "%~dp0Logs%%Z.csv" /A /D /Y /Z &gt;&gt;Log.txt
  )
)
ECHO.&gt;&gt;Log.txt
ECHO Current Stores being Rebuilt at %DATE - %TIME%&gt;&gt;Log.txt
WScript Stores.vbs
Start Excel Stores.csv
ECHO Log Pull Finished at %DATE% - %TIME%&gt;&gt;Log.txt</pre>
<p>This script uses a file called &#8220;Sources.txt&#8221; which is a list of paths on newlines which point to where each of the Logs are stored. Each line consists of something like \ServerNameSYSPUBLIC. The line FOR /F &#8220;tokens=1 delims=&#8221; %%Z IN (&#8220;%%A&#8221;) allows me to pull out the servername from each line in the file, so that when I copy the file from the server, I can rename it so that its source can be identified.</p>
<p>I think this will conclude todays lesson in VBScript and Batch, and I&#8217;d best get back to studying.</p>
<p>Cheers, Chris.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2008/09/09/manipulating-csv-files-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MCSA Study</title>
		<link>http://www.dwarfsoft.com/blog/2008/08/17/mcsa-study/</link>
		<comments>http://www.dwarfsoft.com/blog/2008/08/17/mcsa-study/#comments</comments>
		<pubDate>Sun, 17 Aug 2008 13:46:48 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Certification]]></category>
		<category><![CDATA[Study]]></category>
		<category><![CDATA[Training]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[70-284]]></category>
		<category><![CDATA[70-290]]></category>
		<category><![CDATA[70-291]]></category>
		<category><![CDATA[CCNA]]></category>
		<category><![CDATA[Cisco]]></category>
		<category><![CDATA[CNA]]></category>
		<category><![CDATA[Cram]]></category>
		<category><![CDATA[Exam]]></category>
		<category><![CDATA[Exchange]]></category>
		<category><![CDATA[MCSA]]></category>
		<category><![CDATA[MCSE]]></category>
		<category><![CDATA[Novell]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=51</guid>
		<description><![CDATA[I haven&#8217;t updated you all for a while, but in that time I have completed Microsoft exam 70-290. This ended up being quite a lot simpler than I had originally anticipated. I am currently studying for two more exams. 70-291, which is Microsoft Windows 2003 Networking, and 70-284, which is Microsoft Exchange Server 2003 configuration. [...]]]></description>
			<content:encoded><![CDATA[<p>I haven&#8217;t updated you all for a while, but in that time I have completed Microsoft exam 70-290. This ended up being quite a lot simpler than I had originally anticipated. I am currently studying for two more exams. 70-291, which is Microsoft Windows 2003 Networking, and 70-284, which is Microsoft Exchange Server 2003 configuration. I have been attempting the practice exams and reading the MSPress books, and am relatively confident.</p>
<p>I have scheduled both of these exams for the same day, which will make the day a very long one. If I manage to pass both then that will give me MCSA: Messaging Specialist status. I can then focus on the remaining 3 exams to get my full MCSE certification.</p>
<p><span id="more-51"></span></p>
<p>I hope to get around to completing my Novell CNA exam at some point soon as well. Or once I have the MCSE I might concentrate on the Cisco CCNA. This will give me the required certification level in order to work overseas.</p>
<p>There are still 2 weeks until the exams, so time to start cramming as much study as I can in.</p>
<p>Cheers, Chris.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2008/08/17/mcsa-study/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Changing Roles</title>
		<link>http://www.dwarfsoft.com/blog/2008/06/30/changing-roles/</link>
		<comments>http://www.dwarfsoft.com/blog/2008/06/30/changing-roles/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 12:38:50 +0000</pubDate>
		<dc:creator>dwarfsoft</dc:creator>
				<category><![CDATA[Novell]]></category>
		<category><![CDATA[Politics]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Application]]></category>
		<category><![CDATA[Concept]]></category>
		<category><![CDATA[Container]]></category>
		<category><![CDATA[Distribution]]></category>
		<category><![CDATA[Initiative]]></category>
		<category><![CDATA[NAL]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[TED]]></category>
		<category><![CDATA[Theory]]></category>
		<category><![CDATA[UNC]]></category>
		<category><![CDATA[ZfS]]></category>

		<guid isPermaLink="false">http://www.dwarfsoft.com/blog/?p=30</guid>
		<description><![CDATA[Interesting moves happening at work. Today I moved into a Networks role. Originally it was intended that I be doing 80% Servers and 20% Networks due to the solid input I have provided within the Server team to date. This has now been changed to 80% Networks and 20% Servers. The guy who I am [...]]]></description>
			<content:encoded><![CDATA[<p>Interesting moves happening at work. Today I moved into a Networks role. Originally it was intended that I be doing 80% Servers and 20% Networks due to the solid input I have provided within the Server team to date. This has now been changed to 80% Networks and 20% Servers. The guy who I am filling in for didn&#8217;t like the idea of his role being technically abandonned, and I agree with him. There will definitely be some Server Action from my end anyway, because I have a keen interest in running with a few ideas.</p>
<p>Trav and I have approached the Server team with an idea on distributing apps more effectively, relying mainly on network addresses of the PCs to correctly locate an application server. This brings up a few logistical hurdles.<span id="more-30"></span></p>
<ol>
<li>The restructuring of our Applications such that we can point to a mapped network drive instead of relying on UNC paths.</li>
<li>The fact that some applications are released with site specific information. As we currently have to modify every new release of these apps to include that information, we should approach the issue from a more managable perspective.</li>
<li>The Implementation of Login Scripts to Base Drive Mapping on current Network Location instead of the Current Login or Workstation Context or Group (as this then provides a benefit of decreased WAN traffic for Mobile Computers and Distributed Applications).</li>
<li>The Politics of testing and gaining approval for implementing a new process into something that is seen as a working system. This is possibly the greatest hurdle to overcome in regards to the push for initiative.</li>
</ol>
<p>At least with respect to point Number 4, Trav and I raised this with one of our counterparts in the Server Team, and although we were given some good reasons why some of the ideas we initially had could not go any further than the drawing board, he did provide some additional ideas on how to proceed to at least implement some positive change so that we can all manage our site specific apps (Point number 2) more effectively.</p>
<p>The thing we need to concentrate on first is going to be appropriating some hardware and then building an environment in which we can test some of our theories that are not being implemented. In the mean time I will start testing some of the ideas that the team has approved at this point.</p>
<p>Hopefully we can implement a ZfS Server that creates NALs under the District Container (as opposed to our site containers) which uses %DEST-APPS1% as X:\ instead of a UNC path, and use a Cluster Wide Login Script to appropriately map X:\.</p>
<p>One parting thought on another issue this could have on us, that the X:\ drive is not consistent around the state. From ZfS&#8217;s perspective, everything is all well, however there are a lot more things stored on the X:\ drive that are used constantly from a Technical perspective. This will possibly require some more training, or at least another drive mapping&#8230;</p>
<p>Until I start looking into DFS at least <img src='http://www.dwarfsoft.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>In three weeks time we shall see what position I am in though, before too many things are set in stone.</p>
<p>Cheers, Chris.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.dwarfsoft.com/blog/2008/06/30/changing-roles/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

