I recently had a look at an issue with the Configuration Manager PXE Service Point running on a test environment of mine. I couldn't get any of my operating system images to deploy - in fact I couldn't get the PXE boot to complete successfully. In the smspxe.log file I was getting the following messages:
No Boot Action for Device (38) found ProcessDatabaseReply: No Advertisement found in Db for device
No Boot Action for Device (38) found
ProcessDatabaseReply: No Advertisement found in Db for device
I found this a little odd, as the machine definitely had a task sequence advertised against it, and my custom WinPE image had been made available for PXE.
Digging in the event log, I was getting error messages when WDS started up, saying:
Source: WDSIMGSRV Category: WdsImgSrv Event ID: 258 Description: An error occurred while trying to initialize the Windows Deployment Services image server. Error information 0xC1030104
Source: WDSIMGSRV
Category: WdsImgSrv
Event ID: 258
Description: An error occurred while trying to initialize the Windows Deployment Services image server. Error information 0xC1030104
A little cryptic, and not exactly obvious what it meant. Having a dig around, it appears that 0xC1030104 actually means that the WDSServer is not configured. Strange, I thought the Configuration Manager PXE Service Point setup did that? I checked all the appropriate logs (pxesetup.log, pxemsi.log) and everything seemed in order. I decided to try and initialise the server at the command line to see if that made a different. I ran:
wdsutil /initialize-server /REMINST:"D:\remoteinstall"
where D:\remoteinstall was the directory that Configuration Manager had configured WDS to use. Sure enough, as soon as I did that, PXE started working perfectly.
One of the things I've recently been working on is a question asked by a partner - how do I get extra information about my machines into Operations Manager? If you're not familiar with extending Operations Manager and using Classes & Discovery, it can be quite intimidating, but it's relatively simple. I figure if I can work out, most people probably can. This post will walk through extending the Windows Computer class with an extra attribute populated by an AD query.
First, download and install the Operations Manager Authoring Console: http://www.microsoft.com/downloads/details.aspx?FamilyID=6c8911c3-c495-4a03-96df-9731c37aa6d7&DisplayLang=en
It's also handy to have the Operations Manager Authoring Guide: http://www.microsoft.com/downloads/details.aspx?FamilyID=d826b836-59e5-4628-939e-2b852ed79859&DisplayLang=en. The Authoring Guide covers all the concepts involved, and is especially useful to know about classes and inheritance.
Start the Authoring Console & create a new Management Pack (File...New or click the icon). Create an Empty Management Pack. The best practice for the identity (see the Authoring Guide - Management Packs & Namespaces) is to use Vendor.ProductName.Version - in this case I'm going to use stufox.windowsserver with no version as this will be generic across all Windows server versions, and it's for demo purposes.
Name & description is up to you, this is what will show up in the Operations Manager console when you import the management pack.
Now you have a new blank Management Pack. The first thing to do is to create our new class, so go to Classes and click New Custom Class. You then need to provide a unique identifier for the Class, I'm going to create a class called stufox.windowsserver.ExtendedComputer which will be used to store the Description information from the Active Directory.
Once you click OK you will see the class creation screen. You need to set a few fields in here:
Base Class: Microsoft.Windows.Computer - this is the class that we're extending to create our new attribute.
Name: StuFox Extended Computer (this will appear in the Operations Manager console as the name of the attribute)
Description: Up to you
Change to the Properties tab, and right click in the left hand pane, and choose Add Property. Our property in this case is going to be ADDescription. The defaults are fine, although you can set a Display Name & Description if you want to.
Click OK to create the class.
Now that the class is created you need to create a discovery to populate the class. I'm going to use a VBscript to do this, there is a lot of information on MSDN about this:
How to create Discovery Data by using a script
How to use Runtime Scripts for Discovery
Change to the Health Model section & click Discoveries. Click New & choose Script.
In the screen that opens, set the following values:
Element ID: stufox.windowsserver.DiscoverAdDescription
Display Name: Discover AD Description
Target: Microsoft.Windows.Computer (important: the default will not be set to this, if you don't target it correctly you won't get any data)
Click Next and you will get to set the schedule for the discovery. This discovery doesn't really need to run very frequently - once every 24 hours is fine.
Click Next and you will get the script screen. This allows you to paste in a script written in VBScript or Jscript.
Set the filename to DiscoverDescription.vbs, and paste in the discovery script below (Caveat: This script isn't 100% production ready, I've just used it as an example to show how to get the information in there. There isn't much error handling, and there isn't any allowance for machines that aren't domain members. Use at your own risk!) . I've highlighted (bold, italic) two places you need to modify the script to set the class name to whatever your class name is set to. Set the timeout to 10 minutes.
Click the parameters button, and enter the following three parameters.
$mpelement$ $Target/Id$ $Target/Property[Type="Windows!Microsoft.Computer"]/PrincipalName$
Click OK to create the discovery. Once this has been created, highlight the discovery and choose Properties. Change to the Discovered Types tab and click Add. Highlight your custom class in the list, and choose OK. Right click the newly added class and choose the ADDescription property.
Save the management pack to your hard disk somewhere and it is ready to import into Operations Manager. It will just be a standard XML file that you can open with an XML editor (or notepad) if you like to see what's in there.
So, now that it's imported how do you tell that it's there? The discovery will be available to view in the Operations Manager Console. Go to the Authoring view, and then choose Object Discoveries. You may have to change the scope of the console to see the discovery - include your new management pack. You can also change the schedule of the discovery to force it to run at a time of your choosing if you like - in fact, because the management pack is unsealed you can edit the discovery script directly if you want to. This can be quite handy if like me you haven't necessarily ironed out all the bugs in your script. :)
Once the discovery is run, to see the if the data is in the database you can look at the Ops Mgr database - the data will be stored in a table named MT_<Class Name> - in this case it's MT_ExtendedComputer (Extended_Computer being the name of our new class).
You can troubleshoot by looking at the Operations Manager event logs on the Ops Mgr server. If you need to see if the script has made it down to the machines to actually run, you can go to a command prompt and change to the "Health Service State" directory where the Operations Manager agent is installed (by default C:\Program Files\System Center Operations Manager 2007) and then running dir /s discoverdescription.vbs. It will be in one of the "Monitoring Host Temporary Files x" directories.
I assume there will be some clever people out there who will show me better ways to write my script, feel free, I'm always open to good advice. One of the things I've thought about adding to it is the ability to determine if a machine is in a domain or not, and if not use the description from the local computer instead.
'DiscoverDescription.vbs ' ' Script discovers the Description field from AD given the DNS name of the computer ' Option Explicit 'On Error Resume Next Const ADS_SCOPE_SUBTREE = 2 Dim oAPI, oArgs, strDescription Dim SourceID, ManagedEntityId, TargetComputer, objRootDSE, strDomain Dim wshnetwork, strCompName Dim objConnection, objCommand, objRecordSet, objComputer, strComputerAccount Dim oDiscoveryData, oInst Set oAPI = CreateObject("MOM.ScriptAPI") ' Arguments: ' 0 - SourceID ' 1 - ManagedEntityID ' 2 - ComputerIdentity Set oArgs = WScript.Arguments if oArgs.Count < 3 Then call oAPI.LogScriptEvent("DiscoverDescription.vbs",9999,2,"Script was called with fewer than 3 arguments and was not executed") Wscript.quit -1 End If SourceID = oArgs(0) ManagedEntityId = oArgs(1) TargetComputer = oArgs(2) call oAPI.LogScriptEvent("DiscoverDescription.vbs",9999,1,"Source ID: " & SourceID & "ManagedEntityID: " & ManagedEntityID) Set objRootDSE = GetObject("LDAP://RootDSE") strDomain = objRootDSE.Get("DefaultNamingContext") set wshnetwork=wscript.createobject("Wscript.Network") strCompName=wshnetwork.computername if err.number <> 0 Then call oAPI.LogScriptEvent("DiscoverDescription.vbs",9997,2,"Error creating objects") Wscript.quit -1 End If set objConnection = CreateObject("ADODB.Connection") set objCommand = CreateObject("ADODB.Command") objConnection.Provider = "ADsDSOObject" objConnection.Open "Active Directory Provider" set objCommand.ActiveConnection = objConnection if err.number <> 0 Then call oAPI.LogScriptEvent("DiscoverDescription.vbs",9996,2,"Error creating ADO objects") Wscript.quit -1 End If objCommand.Properties("Page Size") = 1000 objCommand.Properties("SearchScope") = ADS_SCOPE_SUBTREE objCommand.CommandText = "SELECT ADsPath FROM 'LDAP://"&strDomain&"' WHERE objectCategory='computer' AND name='"&strCompName&"'" Set objRecordSet = objCommand.Execute strDescription = "" objRecordSet.MoveFirst if NOT objRecordSet.EOF Then Do until objRecordSet.EOF strComputerAccount=objRecordSet.Fields("ADsPath").value set objComputer = GetObject(strComputerAccount) strDescription = left(objComputer.Description,255) objRecordSet.MoveNext Loop Else call oAPI.LogScriptEvent("DiscoverDescription.vbs",9998,2,"Active Directory Object could not be found") End If Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceID, ManagedEntityID) set oInst = oDiscoveryData.CreateClassInstance("$MPElement[Name='stufox.windowsserver.ExtendedComputer ']$") call oInst.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", TargetComputer) call oInst.AddProperty("$MPElement[Name='stufox.windowsserver. ExtendedComputer']/ADDescription$",strDescription) call oDiscoveryData.AddInstance(oInst) call oAPI.Return(oDiscoveryData)
'DiscoverDescription.vbs
'
' Script discovers the Description field from AD given the DNS name of the computer
Option Explicit
'On Error Resume Next
Const ADS_SCOPE_SUBTREE = 2
Dim oAPI, oArgs, strDescription
Dim SourceID, ManagedEntityId, TargetComputer, objRootDSE, strDomain
Dim wshnetwork, strCompName
Dim objConnection, objCommand, objRecordSet, objComputer, strComputerAccount
Dim oDiscoveryData, oInst
Set oAPI = CreateObject("MOM.ScriptAPI")
' Arguments:
' 0 - SourceID
' 1 - ManagedEntityID
' 2 - ComputerIdentity
Set oArgs = WScript.Arguments
if oArgs.Count < 3 Then
call oAPI.LogScriptEvent("DiscoverDescription.vbs",9999,2,"Script was called with fewer than 3 arguments and was not executed")
Wscript.quit -1
End If
SourceID = oArgs(0)
ManagedEntityId = oArgs(1)
TargetComputer = oArgs(2)
call oAPI.LogScriptEvent("DiscoverDescription.vbs",9999,1,"Source ID: " & SourceID & "ManagedEntityID: " & ManagedEntityID)
Set objRootDSE = GetObject("LDAP://RootDSE")
strDomain = objRootDSE.Get("DefaultNamingContext")
set wshnetwork=wscript.createobject("Wscript.Network")
strCompName=wshnetwork.computername
if err.number <> 0 Then
call oAPI.LogScriptEvent("DiscoverDescription.vbs",9997,2,"Error creating objects")
set objConnection = CreateObject("ADODB.Connection")
set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
set objCommand.ActiveConnection = objConnection
call oAPI.LogScriptEvent("DiscoverDescription.vbs",9996,2,"Error creating ADO objects")
objCommand.Properties("Page Size") = 1000
objCommand.Properties("SearchScope") = ADS_SCOPE_SUBTREE
objCommand.CommandText = "SELECT ADsPath FROM 'LDAP://"&strDomain&"' WHERE objectCategory='computer' AND name='"&strCompName&"'"
Set objRecordSet = objCommand.Execute
strDescription = ""
objRecordSet.MoveFirst
if NOT objRecordSet.EOF Then
Do until objRecordSet.EOF
strComputerAccount=objRecordSet.Fields("ADsPath").value
set objComputer = GetObject(strComputerAccount)
strDescription = left(objComputer.Description,255)
objRecordSet.MoveNext
Loop
Else
call oAPI.LogScriptEvent("DiscoverDescription.vbs",9998,2,"Active Directory Object could not be found")
Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceID, ManagedEntityID)
set oInst = oDiscoveryData.CreateClassInstance("$MPElement[Name='stufox.windowsserver.ExtendedComputer ']$")
call oInst.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", TargetComputer)
call oInst.AddProperty("$MPElement[Name='stufox.windowsserver. ExtendedComputer']/ADDescription$",strDescription)
call oDiscoveryData.AddInstance(oInst)
call oAPI.Return(oDiscoveryData)