Graeme Bray

Real World Automation and Deployment

PowerShell should change your documentation method

leave a comment »

I’ve been doing a lot of documentation lately for some new infrastructure type of deployments. I’ve been documenting how to install and configure different Microsoft services to save for our internal documentation. (If you’re not doing this…get with the program). I’m still taking screen shots of how to do everything with text blurbs. It takes forever to do this. I’ve been putting at the end my powershell commands on how to do it.

For example…

I am working on building a DFS Cluster with File Shares. My steps were documented almost entirely via PowerShell. Yes, we still take screenshots and document what the command does so people can learn, its better than the GUI.

Install-WindowsFeature Failover-Clustering -IncludeManagementTools
Install-WindowsFeature -Name FS-DFS-Replication -IncludeManagementTools
Install-WindowsFeature -Name FS-Resource-Manager -IncludeManagementTools
New-Cluster -Name DFSCLUSTER -StaticAddress 192.168.1.20 -Node DFS01a.graemebray.com -NoStorage -Verbose
Get-Cluster -Name DFSCLUSTER | Add-ClusterNode -Name DFS01b.graemebray.com
Get-ClusterAvailableDisk
Get-ClusterAvailableDisk | Add-ClusterDisk -Verbose
Set-ClusterQuorum -NodeAndDiskMajority 'Cluster Disk 1' -Verbose
get-adcomputer -identity DFSCLUSTER | Set-ADObject -ProtectedFromAccidentalDeletion:$false

I just built a 2 node cluster (granted I have no error checking) in about 5 minutes. Server is online and ready to have an application installed, assuming that you have no issues with Firewalls or Virtualization.

The second step of a HA DFS Cluster is to create the File Server Role. This is a single Powershell command. I didn’t *bother* to create documentation for this in the GUI.

Add-ClusterFileServerRole -Name DFSSVR -Storage 'Cluster Disk 2' -StaticAddress 192.168.1.21 -Verbose

Finally, I am also working on creating documentation for how to create a new Share on this Server 2012 R2 cluster. I’ve got a 24 step process on how to create a share properly via the GUI.

I also have a 4 line Powershell command (names obviously obfuscated)

If (!(Test-Path 'D:\Graeme')) {
    New-Item 'D:\Graeme' -ItemType Directory
}

New-SmbShare -Name 'Graeme' -Path 'D:\Graeme' -ContinuouslyAvailable:$true -FullAccess 'Everyone' -CachingMode None -ScopeName DFSSVR -EncryptData:$false -FolderEnumerationMode AccessBased

I haven’t figured out how to perform the NTFS permissioning (So please feel free to assist. The Get-ACL and Set-ACL commands seem to require some investigation and playing with).

If you haven’t started documented and building everything in Powershell, you’re late to the party.

Written by Graeme Bray

September 15, 2014 at 3:17 AM

Capitalize MDT Computer Name (no matter how it was entered)

leave a comment »

In an enterprise environment, the most important thing is a consistent environment, whether it be something with multiple components such as IIS, or something as simple as a Computer Name case. Without any type of consistency, how can you support any environment? I think I’ve eluded to this on a couple of my other posts. Consistency is a big thing in our environment.

We were recently approached by our monitoring team stating that Server systems were being built with either a lowercase name (ex: testserver01) or uppercase name (ex: TESTSERVER02). They were trying to get the inconsistency fixed, which is completely understandable.

I was tasked with finding a solution to the problem. I thought, this should be pretty simple. There is a Task Sequence variable called OSDComputerName that I should be able to use the built-in functions to perform a UCase on via VBScript. I created a script (which I lost, due to some automated copy methods I have in place. Oops.

I tried to use the script in my Preinstall phase of my test Task Sequence (GEB_test in this case). I put it after the Configure step. I was able to get the OSDComputerName to show that it was properly being capitalized, but when I went into the OS, it showed a lowercase name still. I gave up for a few days, knowing that when you keep looking into a problem, a solution never presents itself. I came back to my issue today after setting my tasks of things to do, which included this issue.

After getting frustrated that my initial solution, and subsequent re-tries never worked, sent a message to Mikael Nystrom and Johan Arwidmark. I got a couple responses, including one from Tim Mintner, Mikael asked that I follow up via e-mail, which I was working on before the end of the day. I had a quarter of the e-mail typed up, but realized that I lost my ZTIComputerName.wsf script. Crap. I clicked .

I got home and re-wrote my script. It took about 15 minutes in total, as I borrowed some other template code I had and removed 95% of it, which, if you aren’t doing, you’re doing it wrong. Andrew Barnes has a great template (or you can edit and re-use some of Johan’s or Mikaels, if you’ve bought their books.)

After having time to have thought about my issue, I found the simplest solution after some simple thinking.
I was changing the computer name too *late* in the Task Sequence.

First, I created my script, as seen below

<job id="ZTIComputerName">
<script language="VBScript" src="ZTIUtility.vbs"/>
<script language="VBScript">

'//—————————————————————————-
'// Solution: Capitalize Computer Name
'//
'// Usage: cscript ZTIComputerName.wsf[/debug:true]
'// Version: 1.0 – 05-Aug-2014 - Graeme Bray
'//
'// This script is provided "AS IS" with no warranties, confers no rights and 
'// is not supported by the authors
'//
'//—————————————————————————-

'//—————————————————————————-
'// Global constant and variable declarations
'//—————————————————————————-

Option Explicit

Dim iRetVal

'//—————————————————————————-
'// End declarations
'//—————————————————————————-

'//—————————————————————————-
'// Main routine
'//—————————————————————————-

'On Error Resume Next
iRetVal = ZTIProcess
ProcessResults iRetVal
On Error Goto 0

'//—————————————————————————
'//
'// Function: ZTIProcess()
'//
'// Input: None
'// 
'// Return: Success – 0
'// Failure – non-zero
'//
'// Purpose: Perform main ZTI processing
'// 
'//—————————————————————————
Function ZTIProcess()

    Dim strComputerName
    iRetVal = Success 
    ZTIProcess = iRetval
    
    strComputerName = oEnvironment.Item("OSDComputerName")
    
    oLogging.CreateEntry "———————————————-", LogTypeInfo
    oLogging.CreateEntry "Config-ComputerName   ", LogTypeInfo
    oLogging.CreateEntry "Config-ComputerName – Current name is:       " & strComputerName, LogTypeInfo
    
	oLogging.CreateEntry "Config-ComputerName - Changing computer name to uppercase", LogTypeInfo
	strComputerName = UCase(oEnvironment.Item("OSDComputerName"))

	oEnvironment.Item("OSDComputerName") = UCase(strComputerName)
	
    oLogging.CreateEntry "Config-ComputerName - New Name - " & strComputerName, LogTypeInfo
	oLogging.CreateEntry "Config-ComputerName - Computer Name Change Complete", LogTypeInfo
	oLogging.CreateEntry "———————————————-", LogTypeInfo

End Function 
</script>
</job>

This script was saved to the D:\DeploymentShare\Scripts\ folder.

I then added it to my Task Sequence *above* the Gather local only step in my Preinstall phase.
Task Sequence

To test my script, I launched a simple 2012 R2 Task Sequence (the OS deploys in about 5 minutes and with no State Restore options, its complete in about 8 minutes. My test computer name had some upper and some lower case in it.
Computer Name - Upper/Lower Case

I hit ‘Go’ and the build completed. I checked properties of ‘My PC’ and….
Computer Name - Final

This worked out great and will soon be implemented in our environment, adding to even more consistency, even between different Engineers.

Until next time (which hopefully won’t be months in between)

Written by Graeme Bray

August 6, 2014 at 2:35 AM

Posted in MDT

Tagged with

MDT Wizard Panes – Watch your Case

leave a comment »

Just a quick post..

I am in the process of setting up my home lab on some servers that I have here.
– 1 PowerEdge 860
– 1 PowerEdge 2950

Both support 2012 R2. Hyper-V 2012 R2 is running on the 2950.

I set up a MDT Deployment Share on the 860. I tried to use the Hydration Kit for SC2012 that Johan has provided, but I wanted some specific customizations (and no viamonstra). I also wasn’t sure how to set it up to point at a different Hyper-V Host.

I went with what I know. I added a new Wizard Pane to my MDT (DeployWiz_AppProfile.xml) and I set it up so that I could have one task sequence to run each different type of Build that I wanted.

<Wizard>
	<Global>
	</Global>
	<Pane id="ServerRole" title="Server Role">
	<Body><![CDATA[<H1>Select an application profile for this server</H1>
		<div id="myMenu" Class="TreeList">
		
		<table style="width:100%;">
			<tr>
				<td colspan="2">
					<p style="color:DarkBlue; font-size:16px; font-weight:bold; font-family:Veranda, Arial, Helvetica, sans-serif;">
						<img src="MinusIcon1.png" /> <img src="FolderIcon.png" />Generic Builds
					</p>
				</td>
			</tr>
			<tr>
				<td style="width:15;">
				</td>
				<td style="width:500;">
					<input type="radio" name="GEBConfig" value="GEBBase" checked>Base Server <br />
					<input type="radio" name="GEBConfig" value="GEBWeb">Web Server <br />
				</td>
			</tr>
			<tr>
				<td colspan="2">
					<p style="color:DarkBlue; font-size:16px; font-weight:bold; font-family:Veranda, Arial, Helvetica, sans-serif;">
						<img src="MinusIcon1.png" /> <img src="FolderIcon.png" />Infrastructure Servers
					</p>
				</td>
			</tr>
			<tr>
				<td style="width:15;">
				</td>
				<td style="width:500;">
					<input type="radio" name="GEBConfig" value="GEBDC">Domain Controller <br />
					<input type="radio" name="GEBConfig" value="GEBWSUS">WSUS Server <br />
					<input type="radio" name="GEBConfig" value="GEBMDT">MDT Server <br />
				</td>
			</tr>
		</table>]]>
	</Body>
	<Condition><![CDATA[UCase(Property("SkipGEBSettings"))<>"YES" and Property("DeploymentType")<>"REPLACE" and Property("DeploymentType")<>"UPGRADE"]]></Condition>
	</Pane>
</Wizard>

I thought I was done. It looked good. I booted my DC01 VM. I got a strange script error after I entered my credentials in MDT.

Script Error

I looked at the Wizard.hta pane in Notepad++. I saw these lines of code:

		For each refItem in oReference.SelectSingleNode("//Wizard/Pane").ChildNodes
			item.AppendChild refItem.CloneNode(true)
		Next

Odd. I hit F8 to open the CMD window.

I navigated to the logs
cd\
cd MININT\SMSOSD\OSDLogs
Wizard.log

Command Prompt - WinPE

At the bottom of the log, it referenced my closing tag did not match my starting tag.

Error Line
(FYI, I am using CMTrace that does this highlighting. If you don’t have it, I highly recommend it – CM Trace)

I opened my DeployWiz_AppProfile.xml file. I checked my Body tags.

  • Line 5
    <Body>
  • Line 41 –
    </body>

Moral of the story – be sure to verify that your tags are at the proper case.

Written by Graeme Bray

June 1, 2014 at 10:14 PM

Posted in MDT

Tagged with ,

Why you should revisit your code

leave a comment »

I recently had a script sent to me. This script was originally written at the end of 2011, edited in early 2012. Per the comment block at the top the script, it was version 5. It was a good script. It did what was needed for the end users.

It’s now 2014. We’ve upgraded the domain to Forest and Domain Functional Levels of 2008 R2. We’ve upgraded all of the DC’s to 2008 R2 or greater. We don’t need to use the Quest AD CMDlets anymore. They’re deprecated (in my eyes).

Here is the majority of the code snippet (I’ve edited out company information).

#Checks to see if the Quest Add on is installed.  If not installed, Installs it.
$snap_ins = Get-PSSnapin -Name Quest.ActiveRoles.ADManagement

if (!$snap_ins)
{
	Add-PSSnapin Quest.ActiveRoles.ADManagement       
}
#Loads the variable with the data from the Active Directory
$serviceaccounts = Get-QADUser -SizeLimit 0 -SearchRoot 'mydomain.local/MyOU/Accounts/Users'

#Recursively loops through every entry in $serviceaccounts variable
foreach ($account in $serviceaccounts)
{
    $contains = 0
    
    #Stores all the information about the memberships of the service account into the $memberdetails variable
    $memberdetails = Get-QADmemberof $account

    #Recursively loops through each membership per service account
    foreach ($group in $memberdetails)
    {
        #If there exists a membership that starts with "SEC", sets the flag to 1
    	if (($group.Name.StartsWith("SEC")))
    	{	            
    		$Contains = 1                	
    	}      
    }
        #If User has/hasn't a Membership starting with "SEC" then output the correct message
        if ($contains -eq 1)
        {
            write-host $account.name "has the group"
            $yes = $account.name | Out-File -Append $containspath
            $contains = 0
        }
        else
        {
            Write-Host $account.name "Does not have the group" 
            $no = $account.name | Out-File -Append $nocontainspath
        }
    #Resets the variable
    $contains = 0       
}

This was good, in 2011. We didn’t have the ability to run the AD cmdlets. We didn’t have Powershell 3.0, or 4.0, or even 5.0 (Preview – Don’t run in production, duh).

There are approximately 2000 users in this OU location that we were needing to check to see if they had any of a specific group type.

I was asked a question (at this point, I don’t remember what), but I was told that the script “works.” I looked at it and said, I’m going to re-write this. For fun, I took what was said at TechEd, to heart. I wanted to remove the Write-Host, I wanted to improve the run speed, and I wanted to make this script so it could be customized a little easier.

First, I ran Measure-Command on the entire script. Here are the results:
Old Script - Run Time
Yikes. Almost 15 minutes. That’s running sequentially, writing output to the screen. Ick.

I decided, lets re-write the script. I didn’t do it *all* on my own, but I did realize that you cannot do a -like, or -match, or -anything with a wildcard for the MemberOf property of a Get-ADUser.

<#
.SYNOPSIS
   This script will output two sets of data - one providing users in a group, the other providing users *not* in a group.
.DESCRIPTION
   This script provides the ability to take 3 parameters (Domain, GroupName) and will search in
   the specified Domain for that group.  If a SearchBase is specified, it will use that as a modifier and significantly
   speed up the script as you are searching a specific OU.

   This script will output to two different files, each appended with a specific date.

   This script can be modified to suit your specific needs.
.EXAMPLE
   Get-GroupInformation
.EXAMPLE
   Get-GroupInformation -Domain mydomain.local -GroupName SEC-*
.OUTPUTS
   Script will output 2 files to:
    "C:\Admin\Scripts\Audit_$GroupName_Security_Group\
#>
function Get-GroupInformation
{
    [CmdletBinding(DefaultParameterSetName='Parameter Set 1', 
                  SupportsShouldProcess=$true, 
                  PositionalBinding=$false,
                  HelpUri = 'http://www.microsoft.com/',
                  ConfirmImpact='Medium')]
    [OutputType([String])]
    Param
    (
        # Domain - ex: mydomain.local
        [Parameter(ParameterSetName='Domain name')]
        [string]
        $Domain = 'mydomain.local',

        # GroupName - ex: GRP-*
        [Parameter(ParameterSetName='Group name')]
        [string]
        $GroupName = 'SEC-*'
    )

    Begin
    {
        Write-Verbose 'Defining/creating variables'
        $SearchBase = 'OU=Users,OU=Accounts,OU=MyOu,DC=MyDomain,DC=Local'
        $varUserArray = @()

    }
    Process
    {
        Write-Verbose 'Getting list of Users from Active Directory'
        try
        {
            $ADQuery = Get-ADUser -Server $Domain -Properties memberof -Filter * -SearchBase $SearchBase
        }
        catch [System.Net.WebException],[System.Exception]
        {
            Write-Error 'AD Query returned no users.'
        }
        
        Write-Verbose 'Looking through users, creating array with UserName and Groups'
        foreach ($User in $ADQuery) {
            $Groups = $User.memberof -join ';'
            $varUserArray += New-Object psObject -Property @{'User'=$User.name;'Groups'= $Groups}
        } #End ForEach User
    }
    End
    {
        Write-Verbose 'Sorting users and outputting to appropriate Output File'
        $Member = $varUserArray | Where-Object {($_.groups -match $GroupName) } | Select-Object User | Out-File D:\Workspace\Graeme\Output\Member.txt -Force
        $NonMember = $varUserArray| Where-Object {!($_.groups -match $GroupName) } | Select-Object User | Out-File D:\Workspace\Graeme\Output\NonMember.txt -Force
    }
}

Get-GroupInformation

This provided the exact same results. Bingo. This script took….
New Script - Run Time

4 Seconds!

Wow. Plus, with the new script you get some of the standard cmdlet options (Verbose for one), and it’s more easily edited.

*Note* – It is very possible that the script may not work correctly. I haven’t fully tested, but I was so blown away by the time results, that it had to be said…and posted.

Written by Graeme Bray

May 30, 2014 at 4:59 AM

Posted in PowerShell

Tagged with

MDT – Server 2012 R2 Pre-Capture Disk Cleanup

leave a comment »

As a result of going to TechEd, I learned a few disk cleaning techniques from Mikael Nystrom.  One of these was to run the following command during the Build & Capture Task Sequence.  This adds about 15 minutes on to the build time, but it can save (in my case) 700MB of space.  It may not end up being much, but in the server world, it can mean a lot.  (Disclosure, I have only tested on Server 2012 R2 U1)

Command: (Run Elevated) DISM.exe /online /cleanup-image /StartComponentCleanup /ResetBase

Used Space Before:

Image

 

Used Space After:

Image

 

I will shamelessly admit that I have taken one script from Mikael and edited them for use in my environment.  After all, why re-create something when there are already working examples?  I do leave all of the credit at the top of the script, so no issues there.

<job id=”Config-Server2012DiskCleanup”>
<script language=”VBScript” src=”..\..\scripts\ZTIUtility.vbs”/>
<script language=”VBScript”>
‘//—————————————————————————-
‘// Purpose: Used to Configure and reset the Base for Windows Server 2012 R2
‘// Usage: cscript Config-Server2012DiskCleanup.wsf [/debug:true]
‘// Version: 1.0 – 7 Sep 2011 – Mikael Nystrom
‘//
‘// This script is provided “AS IS” with no warranties, confers no rights and 
‘// is not supported by the authors or Deployment Artist. 
‘//
‘//—————————————————————————-
‘//—————————————————————————-
‘// Global constant and variable declarations
‘//—————————————————————————-
Option Explicit
Dim iRetVal
‘//—————————————————————————-
‘// End declarations
‘//—————————————————————————-
‘//—————————————————————————-
‘// Main routine
‘//—————————————————————————-
On Error Resume Next
iRetVal = ZTIProcess
ProcessResults iRetVal
On Error Goto 0
‘//—————————————————————————
‘//
‘// Function: ZTIProcess()
‘//
‘// Input: None
‘// 
‘// Return: Success – 0
‘// Failure – non-zero
‘//
‘// Purpose: Perform main ZTI processing
‘// 
‘//—————————————————————————
Function ZTIProcess()
Dim sCommand
Dim sConfigname
sConfigName = “Config-Server 2012 Disk Cleanup”
oLogging.CreateEntry sConfigName & “: Starting ” & sConfigName, LogTypeInfo

‘//Run a command
sCommand = “dism.exe /online /cleanup-image /startcomponentcleanup /resetbase”
oLogging.CreateEntry sConfigName & “: Running ” & sCommand, LogTypeInfo
iRetVal = oUtility.RunwithHeartbeat(sCommand)
oLogging.CreateEntry sConfigName & “: Return code from command = ” & iRetVal, LogTypeInfo

oLogging.CreateEntry sConfigName & “: Finished ” & sConfigName, LogTypeInfo
End Function

</script>
</job>

I will find a place to post the .wsf file online, but in the mean time, there it is

Written by Graeme Bray

May 20, 2014 at 8:01 PM

Posted in Uncategorized

Tagged with

MDT – State Restore for Multiple Task Sequences

leave a comment »

As a Windows Engineer, one of the most difficult things about maintaining my deployments is consistency.  I maintain our legacy builds (Server 2003 – Std/Ent, x86/x64) as well as our current builds (2008 R2 Std/Ent, 2012 R2 Std).  My biggest problem is ensuring that our builds are the same no matter the OS (from 2008 through 2012 – who really cares about 2003 at this point).  One thing that Microsoft has done with MDT and Windows Server in general is make the OS Roles/Features and compatibility similar.

Task sequences are the lifeblood of the MDT Build Process. Consistency between the MDT Builds for each OS version (for example, 2008 R2 Std/Ent, or 2012 R2 Std) should be paramount in the Windows Server world. The average Windows Admin should strive to have an OS that looks identical each time it is deployed, no matter if it is Development, Production, or QA. This can be accomplished by building a State Restore phase of the that can be copied from a main task sequence to each subsequent one. Building this so that you can copy the entire State Restore phase will greatly reduce the time you spend configuring your task sequences.

To do this, each different OS you build will need to have a group created for the step you would like to perform (for example, a Role installation). You would then create a subgroup with the specific label of the OS (Ex: Server 2008 R2, Server 2012 R2) with a WQL Query.

Here’s an example of my Web (IIS) group:

Image

And here is my WQL (WMI) query for Server 2008 R2:

Image

The two queries that I use are:

SELECT * FROM Win32_OperatingSystem WHERE Name LIKE “%Windows Server 2008 R2%”

SELECT * FROM Win32_OperatingSystem WHERE Name LIKE “%Windows Server 2012%”

If you want to get more specific than just all 2012, then you can specify “%Windows Server 2012 R2%”.  Personally, my company never plans to deploy Server 2012 (And why would you at this point?  Its like Windows 8, why not skip right to 8.1?

Once I’ve got my folder templates created, I copy them to whatever place I need them, whether its my Role installs or specific applications that are only needed on 2008 or 2012.  This works very well to group items so you can see at first glance what is being installed for each OS.

Once this is complete, I select the “State Restore” phase grouping and right click to “Copy”.  I’ll open each of my other two task sequences (after testing the first of course) and remove my old State Restore and Paste the new one.

Voila, I never have to compare Task Sequences, nor make my updates more than once.

Work smarter, not harder, especially to maintain consistency.

Written by Graeme Bray

April 25, 2014 at 1:11 AM

Posted in MDT

Tagged with

Unable to mount the WIM/DISM was unable to set the system root

leave a comment »

My company has recently started to deploy Server 2012 R2.  Before we could do this, the security team had to develop the policies to apply to the systems before we were allowed to do so.  Naturally, this leads to some times where we have to troubleshoot issues due to restrictive policies.  I started the process to deploy a new MDT server to replace one of my 2008 MDT systems that hosts WDS to attempt to get past the issue documented here.

I built my MDT Server, with 2013, ADK, and copied my old Deployment Share over to get the process started.  I updated my bootstrap.ini file to show the proper server name and tried to build a new boot image.  *BAM!*  I was hit with an error as soon as it started.

Unable to mount the wim, so the update process cannot continue.

Image

 

I looked and searched high and low for the cause.  I removed policies, thinking I knew what the issue was.  I *couldn’t* find it.  I took a break and came back to it by adding policies one at a time to see what broken my process.

I was able to get past this issue by changing the following setting:

Computer Configuration/Policies/Windows Settings/Security Settings/Local Policies/User Rights Assignments

  • Backup Files and Directories – Add Administrators back in
  • Restore Files and Directories – Add Administrators back in

These two policy settings had only Backup Operators as to provide for the least rights possible.

This should alleviate the first issue.


 

Once I fixed this issue, I (re-applied group policy, logged out/in) attempted to re-build my WIM file.  I was hit by the next errors.

  • DISM Imaging Servicing Utility has stopped working
  • DISM was unable to set the system root (target path) for the Windows PE image, so the update process cannot continue.
    • Exit Code = -1073741819
    • DISM /Set-TargetPath failed, rc = -1073741819

Image

Image

 

Well…crap.  Back to looking.  I had an idea what the issue may be by looking at my event logs.  In my (fast scrolling, due to advanced auditing) security logs, I was able to see some Task Category entries for Process Creation.  I can’t claim to know what all of this means, but I did see that it was attempting to get a new Token for WIM build.

Process Information:
New Process ID: 0x1010
New Process Name: C:\Windows\System32\cmd.exe
Token Elevation Type: TokenElevationTypeFull (2)
Creator Process ID: 0x918
Process Command Line:

Token Elevation Type indicates the type of token that was assigned to the new process in accordance with User Account Control policy.

Type 1 is a full token with no privileges removed or groups disabled. A full token is only used if User Account Control is disabled or if the user is the built-in Administrator account or a service account.

Type 2 is an elevated token with no privileges removed or groups disabled. An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator. An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group.

Type 3 is a limited token with administrative privileges removed and administrative groups disabled. The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.

Tokens Eh?  I remember seeing a policy for that!

Computer Configuration/Policies/Windows Settings/Security Settings/Local Policies/User Rights Assignments

  • Create Token Object

I added Administrators, applied policy, logged out/in.  No dice.  I read a little more.

 

Computer Configuration/Policies/Windows Settings/Security Settings/Local Policies/User Rights Assignments

  • Create global objects – Add Administrators.

Bingo! Our setting was LOCAL SERVICE, NETWORK SERVICE only.  I adjusted this setting, I was able to build my WIM’s successfully.

I hope this blog post is useful for someone else!

 

 

Written by Graeme Bray

March 26, 2014 at 2:21 PM

Posted in MDT

Tagged with

Follow

Get every new post delivered to your Inbox.