Norman Bauer

… just technical stuff!

Home » Windows Internals » Archive by category "Active Directory"

“No such object” when configuring TPM on Windows Server 2012 or Windows 8

Turn on the TPM security hardware failed 0x80072030

Scenario: You have a Windows Server 2012 or Windows 8 computer with TPM and you store your Bitlocker recovery and TPM owner information in Active Directory.
When trying to configure the TPM hardware by using tpm.msc you get this error:

Turn on the TPM security hardware failed 0x80072030

Turn on the TPM security hardware

This computer may require you to change the state of the Trusted Platform Module (TPM) manually. To perform this action, try turning on the TPM through the BIOS or performing a firmware update. Consult the computer manufacture’s documentation for instructions.

There is no such object on the server.

Error code: 0×80072030

This error is a bit misleading as it asserts that there is something wrong with your hardware. But never mind. There is no such object on the server and error code 0×80072030 are Active Directory related. This simply means the wizard could not find an object in AD.

The way Windows Server 2012 and Windows 8 store their TPM owner information changed from previous versions. With Active Directory schema version 48 some TPM objects have been introduced (like msTPM-InformationObject) that store this information in the future. You can have look at these changes, just open the support\adprep\sch48.ldf file from your Windows Server 2012 DVD.

If you want to use AD to store your TPM information the same way you did with Windows Server 2008 R2 or Windows 7 you’ll need to update your schema first to version 56 (Windows Server 2012). This will bring all the necessary changes to your environment. If you cannot update your schema you’ll just have one possibility left: Move your computer object to another ou where the group policy object containing your TMP/Bitlocker settings is not applied. Configure TPM “offline” and store the information in a secure place – you won’t have the owner information in AD for this computer. Then move the object back to its previous ou.

Check objectVersion on all Domain Controllers after schema update with PowerShell

AD Schema objectVersion on all Domain Controllers

Just copy and paste into PowerShell (Active Directory Module for Windows PowerShell) to get the version of AD schema on all domain controllers in current domain:

$schemaContext = Get-ADRootDSE | %{$_.schemaNamingContext}

Foreach ($dc in ([System.DirectoryServices.ActiveDirectory.DomainController]::findall(
   (new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$env:USERDNSDOMAIN)))) | 
   %{$_.name})
{
	$path = 'LDAP://' + $dc + '/' + $schemaContext
	$Object = [adsi]$path
	$dc + '  ' + $Object.objectversion
}

AD Schema objectVersion on all Domain Controllers

Restore deleted computer object including BitLocker recovery information

Recovery of Active Directory objects became much easier with the introduction of AD recycle bin feature in Windows Server 2008 R2. Simply use the restore-adobject PowerShell cmdlet and you’re done. But what if you are using BitLocker with its keys stored in AD? You can still restore the computer object once it got deleted. But the attached msFVE-RecoveryInformation objects will not get restored automatically.

This small PowerShell cmdlet will do the work for you:

import-module ActiveDirectory

function RestoreComputer($computername)
{
  If ($computername.substring($computername.length - 1, 1) -ne '$')
  {
    $computername += '$'
  }

  $existing = Get-ADObject -Filter {sAMAccountName -eq $computername}
  If (!$existing)
  {
    "No existing computer object found, searching for deleted objects."
    $deleted = Get-ADObject -IncludeDeletedObjects -Filter {sAMAccountName -eq $computername -and Deleted -eq $True}
    If ($deleted)
    {
      "Deleted object found, trying to restore..."
      $deleted | Restore-ADObject
      Start-Sleep -s 5
      $restoredobject = Get-ADObject -Filter {sAMAccountName -eq $computername}
      If ($restoredobject)
      {
        "Computer object successfully restored. Trying to find recovery information..."
        $recoveryinfos = Get-ADObject -IncludeDeletedObjects -Filter {lastKnownParent -eq $restoredobject.DistinguishedName -and Deleted -eq $True -and objectClass -eq 'msFVE-RecoveryInformation'}
        ForEach($recoveryinfo in $recoveryinfos)  
        {
          If ($recoveryinfo)
          {
            "Recovery information found, trying to restore..."
            $recoveryinfo | Restore-ADObject
            Start-Sleep -s 5
            $restoredinfo = Get-ADObject -Filter {ObjectGUID -eq $recoveryinfo.ObjectGUID}
            If ($restoredinfo)
            {
              "Recovery information successfully restored."
            }
            Else
            {
              "Could not restore recovery information, aborting script."
              return $false
            }
          }
          Else
          {
            "No recovery information found for computer object, aborting script."
            return $true
          }
        }
      }
      Else
      {
        "Something went wrong. Could not find restored object, aborting script."
        return $false
      }
    }
    Else
    {
      "No deleted computer found, aborting script"
      return $false;
    }
  }
  Else
  {
    "Computer already existing, aborting script"
    return $false
  }
  "Restore of computer object succeeded."
  "Finished."
  return $true
}

$cn = Read-Host "Computername to restore?"

RestoreComputer($cn)

The script will first search for any existing computer objects with the same name. If there are none, it will try to restore a deleted object. Be careful if you have multiple deleted objects with the same name, you may need to change some parts of the script for this scenario.
After that it searches for BitLocker recovery information and tries to restore this as well – no matter how many objects the computer object contained.

How to manage GPOs with vbScript?

gporeport

You can do really really cool stuff with gpos in vbScript. I will show you how to export reports and give you some examples what else can be done going the vbScript way…
The Group Policy Management console in Windows offers you the possibility to export reports about group policy object’s settings to html files – this, for example, is an excerpt of my default domain controllers policy:

You can do this (and much more) by script too. Here is how you can do it… You can choose to save this report in a variable to do further processing in your script or you can save it to a file, just like the console does.

Function getGPOHTMLReport(strDomain, strGPOCN)
  Set objGPM = CreateObject("GPMgmt.GPM")
  Set objGPMConstants = objGPM.GetConstants()
  Set objGPMDomain = objGPM.GetDomain(strDomain, "", objGPMConstants.UseAnyDC)
  Set objGPO = objGPMDomain.GetGPO(strGPOCN)
  Set objGPMReport = objGPO.GenerateReport(objGPMConstants.ReportHTML)
  getGPOHTMLReport = objGPMReport.result
End Function

Wscript.echo getGPOHTMLReport("normanbauer.com", "{6AC1786C-016F-11D2-945F-00C04fB984F9}") 'Default Domain Controllers Policy
Sub exportGPOHTMLReport(strDomain, strGPOCN, strOutFilename)
  Set objGPM = CreateObject("GPMgmt.GPM")
  set objGPMConstants = objGPM.GetConstants()
  set objGPMDomain = objGPM.GetDomain(strDomain, "", objGPMConstants.UseAnyDC)

  Set objGPO = objGPMDomain.GetGPO(strGPOCN)
  objGPO.GenerateReportToFile objGPMConstants.ReportHTML, strOutFilename
End Sub

exportGPOHTMLReport "normanbauer.com", "{6AC1786C-016F-11D2-945F-00C04fB984F9}", "C:\temp\export.html" 'Default Domain Controllers Policy

Functions used in the scripts above:

The function above generates the report of the specified gpo (you can find the cn of the gpo ["Unique ID"] in the Group Policy Management console on the details tab of a gpo, or in the System\Policies Container in Active Directory) and returns the html formatted result. The sub does almost the same but does not return the result but saves it to a file specified in strOutFilename.

You can do much more with the GPMgmt.GPM object – almost everything what the console can do, like creating, deleting and copying gpos, get and set wmi filters and set the gpo to be enabled or disabled on computer and/or user accounts.

How to display user pictures in Outlook, Sharepoint & Co. using Active Directory?

Newer versions of Sharepoint, Outlook or Office Communicator support showing small user pictures in new mails, contact information or websites using data stored in a user’s object in Active Directory. Even Windows can show your user picture for example on the lock screen or in the start menu. But you need to make some preparations for this feature to work.
First at all you need the pictures for your user objects in the directory. You can use ADSI Edit, Powershell or 3rd party software to put pictures in AD. My blog post “How to save a user picture in Active Directory with vbScript?” will do this for you using vbScript.
The second step (only required if you have multiple domains) requires extend permissions on your forest. You’ll need at least the Schema Admin rights to edit the thumbnailPhoto attribute in the Active Directory Schema. View the attribute section in the Active Directory Schema snapin, open the properties of the thumbnailPhoto attribute and enable the option “Replicate this attribute to the Global Catalog”.
That’s all…
Note: This will work for Outlook, OCS, Sharepoint & Co. Windows will not use the data stored in the thumbnailPhoto attribute automatically. But there is a way to show the user picture in the start menu or on the lock screen. Please read my blog post “How to display Active Directory stored user account pictures in Windows?” for further information.

How to display Active Directory stored user account pictures in Windows?

This topic is little more complex and we’ll need different steps to accomplish this feature.
First at all you need the pictures for your user objects in the directory. You can use ADSI Edit, Powershell or 3rd party software to put pictures in AD. My blog post “How to save a user picture in Active Directory with vbScript?” will do this for you using vbScript.
Second you’ll need a small application that sets a picture on your harddrive as the user account picture. I tested this only with Windows 7 – so there is no guarantee that this works with other versions too. Why an application? Because there is no documented way of setting an individual user account picture programmatically in vbScript – neither via registry nor via file system.
My blog post “How to set the Windows 7 user account picture programmatically?” covers that small application.
Now that we have the pictures in Active Directory and developed a small application that sets an image file as user account picture we just need one more step between both. We need a vbScript that runs at logon, loads the picture from AD, puts it on the disk and calls our application. Here we go:

Function LoadPictureFromAD(szADsPath, szSaveFileName)
	Dim objUser, bytesRead, adoStreamWrite
	Const adTypeBinary = 1, adSaveCreateOverWrite = 2
 
	Set objUser = GetObject(szADsPath)
	bytesRead = objUser.Get("thumbnailPhoto")
	
	Set adoStreamWrite = CreateObject("ADODB.Stream")
	adoStreamWrite.Type = adTypeBinary
	adoStreamWrite.Open
	adoStreamWrite.Write(bytesRead)
	adoStreamWrite.SaveToFile szSaveFileName, adSaveCreateOverWrite
	adoStreamWrite.Close
End Function

Set wshShell = CreateObject("WScript.Shell")
Set fso = CreateObject("Scripting.FileSystemObject")

workingdir = Replace(wscript.scriptfullname, Wscript.scriptname, "")

Set wshNetwork = WScript.CreateObject("WScript.Network")
username = wshNetwork.UserDomain  & "\" & wshNetwork.UserName
Set objSysInfo = CreateObject("ADSystemInfo")
strUserName = objSysInfo.UserName
dn = "LDAP://" & strUserName

path = wshShell.ExpandEnvironmentStrings("%temp%") & "\"
filename = path & "uap.jpg"

LoadPictureFromAD dn, filename
wshshell.run workingdir & "useraccountpicture.exe " & username & " " & filename, 0, true

This script contains the function LoadPictureFromAD which expects the user’s distinguished name and a filename where the resulting picture will be saved to. Inside the function we connect to AD, get the user’s object, read the attribute thumbnailPhoto, copy it to a previously created stream object and save it in a file identified by szSaveFileName.
The script itself assumes that the useraccountpicture.exe application resists in the same location as the script. So we set the working directory to the scripts location. After that we need the user’s name, it’s domain and it’s distinguished name. Then we create the filename for the image, this is simply the temp folder with “uap.jpg” as filename. With the distinguished name and the filename we can call the LoadPictureFromAD function and finally we run the useraccountpicture application with the username and the filename as parameters.

Save the script as .vbs – run it – have a look at the start menu – that’s all…

Now you can use this script as a logon script within group policies and all your users can find their photos in the start menu and on the lock screen.

How to save a user picture in Active Directory with vbScript?

Active Directory offers the possibility to save pictures in a user’s object. These pictures can then be used in Outlook, Sharepoint or even self-written applications. Here is how you can do it:

Function SavePictureToAdFromUrl(szADsPath, szUrl)
	Dim objUser, bytesRead, adoStreamRead
	Const adTypeBinary = 1
	
	Set xml = CreateObject("Microsoft.XMLHTTP")
	xml.Open "GET", szUrl, False
	xml.Send
	
	If xml.status = 200 Then
		Set adoStreamRead = CreateObject("ADODB.Stream")
		adoStreamRead.Type = adTypeBinary
		adoStreamRead.Open
		adoStreamRead.Write xml.responseBody
		adoStreamRead.Position = 0
		bytesRead = adoStreamRead.Read()
		adoStreamRead.Close
	 
		Set objUser = GetObject(szADsPath)
		objUser.Put "thumbnailPhoto", bytesRead
		objUser.SetInfo
	End If
End Function

This function will read a picture resource from a url (szUrl) and append it to the thumbnailPhoto attribute in the user object identified by szADsPath.
First we open the url and see if we’ll get a status 200 (OK). If so a binary stream object is created and the picture data from the url is written into it. After that we transfer the data from the stream object into a variable, then we create an object from the given szADsPath and finally put the content of the bytesRead variable into the thumbnailPhoto attribute of the user object.
If you do not have a website providing the picture you can do this also with files on a file system.

Function SavePictureToAD(szADsPath, szLoadFileName)
	Dim objUser, bytesRead, adoStreamRead
	Const adTypeBinary = 1
 
	Set adoStreamRead = CreateObject("ADODB.Stream")
	adoStreamRead.Type = adTypeBinary
	adoStreamRead.Open
	adoStreamRead.LoadFromFile szLoadFileName
	bytesRead = adoStreamRead.Read()
	adoStreamRead.Close
 
	Set objUser = GetObject(szADsPath)
	objUser.Put "thumbnailPhoto", bytesRead
	objUser.SetInfo
End Function

This one is almost the same function, but it does not expect an url as parameter but a filename – the rest of the function stays the same.

When using one of these functions please make sure that the resource identified by either url or filename is a valid picture file like jpeg or png. Neither Active Directory nor my functions will validate the files!
Please also note that the attribute thumbnailPhoto is for thumbnails – therefor you should use small pictures. Recommended are jpeg pictures with dimensions of 128×128 pixels an a size not exceeding 10KB. The limit of the thumbnailPhoto attribute is 100KB.