SCCM – Some Experiences with Error 0x8004005

Howdy folks and welcome back!

In addition to Service Manager, I also do a lot of work with Configuration Manager (or SCCM if you prefer).  Actually, about 90-99% of my System Center time is directed at SCCM, so I have had a fair amount of experience with it in our environment.

One of the more vexing errors you will find in SCCM during OSD is error 0x8004005 which if anything is a generic error that can be triggered by a number of things.  Instead of doing a Case 1, Case 2, etc way of going through the scenarios, these are the top things to look for when troubleshooting this issue when it pops up (again, during OSD (Operating system Deployment)).

  • Ensure the data/time of the system is correct
  • Ensure the BIOS is up to date
  • Check your network account and ensure if has security access in Software Library -> Operating Systems -> Operating System Images
    • For good measure, double-check to ensure the username/password is correct anyway
  • Ensure the hard drive is in good working order (chkdsk /r and drive diagnostics are your friends)

Lastly: IT COULD JUST BE THE TASK SEQUENCE!  We have literally solved a 0x8004005 issue in our environment by deleting the existing task sequence and recreating an exact duplicate in its place and redeploying it.  If all else fails, try it.  You might just want to bang your head on a desk if it works because that is all there is left to do.

Advertisements

DIY Service Manager Analyst Portal – Part 6 – So What Does It All Look Like?

Hey folks!

It has been a while since I posted.  OK, more than a while.

In previous parts of the Analyst Portal series I have posted the code that drives what I can see on my Analyst Portal but…what good is that if you can’t see it unless you implement the code?

This is what the default.aspx website looks like…

defaultaspx

This is what the details.aspx website looks like, using generic data…

detailsaspx

This is what the edit.aspx website looks like…

editaspx

Finally, this is what the serial.aspx website looks like, both blank and after a serial number has been typed and submitted…

serialaspx_1serialaspx_2

It looks fairly…bland…but on a mobile device (such as my S5) it is crisp and clear and, unless someone has included a link in the description field, all fits width-wise on the screen and easily scroll-able and usable.

There are vendors out there that will offer you an Analyst Portal, but my sticking point is having to pay for something that can be done in-house.  This is just a basic portal in its current incarnation but could be built upon.  Everything needed is in the SDK.

Cheers.

DIY Service Manager Analyst Portal – Part 5 – Serial Number Look Up

One of the requested additions after this went live was for technicians to easily find the serial number of a machine on site without having to go into SCCM.  This page takes advantage of our SCCM connector and if the data is correctly imported the technician is  likely to get a hit ad know what machine they are dealing with.  If you’re following a naming convention and a random hard drive fails, you can replace the drive and if it asks for the name you can provide it (as an example).

As always, it is split into HTML (serial.aspx) and C# (serial.aspx.cs) parts…

HTML:


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="serial.aspx.cs" Inherits="serial" Debug="true" %>

<html>
<body>
<form id="form1" runat="server">
<p>
Note: this serial number checker polls against the objects imported into Service Manager from Configuration Manager and shows all "active" results. The information found may not be completely up to date and there may be multiple listings.
</p>


<hr />




<div id="serialForm" runat="server">
<p>
<asp:TextBox ID="txtSerial" runat="server"></asp:TextBox>
</p>
<p>
<asp:Button ID="btnSerial" runat="server" OnClick="btnSerial_Click" Text="Search Serial Number" />
</p>
</div>

<div ID="divSerial" runat="server"></div>
</form>
</body>
</html>

C#:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Common;
using Microsoft.EnterpriseManagement.Configuration;

[Serializable()]
public class Computer : IComparable<Computer>
{
public String Name { get; set; }
public String Model { get; set; }
public String Manufacturer { get; set; }
public String SerialNumber { get; set; }

public int CompareTo(Computer other)
{
return SerialNumber.CompareTo(other.SerialNumber);
}
}

public partial class serial : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}

protected void btnSerial_Click(object sender, EventArgs e)
{
String sSerialCriteria = String.Format(@"<Criteria xmlns='http://Microsoft.EnterpriseManagement.Core.Criteria/'>" +
"<Expression>" +
"<SimpleExpression>" +
"<ValueExpressionLeft>" +
"<Property>$Context/Property[Type='Microsoft.SystemCenter.ConfigurationManager.DeployedComputer']/SerialNumber$</Property>" +
"</ValueExpressionLeft>" +
"<Operator>Equal</Operator>" +
"<ValueExpressionRight>" +
"<Value>{0}</Value>" +
"</ValueExpressionRight>" +
"</SimpleExpression>" +
"</Expression>" +
"</Criteria>", txtSerial.Text);
EnterpriseManagementConnectionSettings settings = new EnterpriseManagementConnectionSettings("SCSM SERVER");
settings.UserName = "USER NAME";
char[] pass = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' };
settings.Password = new System.Security.SecureString();
foreach (char c in pass)
settings.Password.AppendChar(c);
settings.Domain = "DOMAIN NAME";

EnterpriseManagementGroup emg = new EnterpriseManagementGroup(settings);

ManagementPack ciManagementPack = emg.GetManagementPack("Microsoft.SystemCenter.ConfigurationManager", "31bf3856ad364e35", null);

ManagementPackClass ci = emg.EntityTypes.GetClass("Microsoft.SystemCenter.ConfigurationManager.DeployedComputer", ciManagementPack);

EnterpriseManagementObjectCriteria criteria = new EnterpriseManagementObjectCriteria(sSerialCriteria, ci, ciManagementPack, emg);

IObjectReader<EnterpriseManagementObject> serialreader = emg.EntityObjects.GetObjectReader<EnterpriseManagementObject>(criteria, ObjectQueryOptions.Default);

List<Computer> compArray = new List<Computer>();

foreach (EnterpriseManagementObject emop in serialreader)
{
if (emop.Values[12].ToString() == "System.ConfigItem.ObjectStatusEnum.Active")
{
Computer newComp = new Computer();

newComp.Name = emop.Values[15].ToString();
newComp.Manufacturer = emop.Values[10].ToString();
newComp.Model = emop.Values[9].ToString();
newComp.SerialNumber = emop.Values[5].ToString();
compArray.Add(newComp);
}
}

divSerial.InnerHtml = "";

if (txtSerial.Text.Equals("") || txtSerial.Equals(null))
{
divSerial.InnerHtml = "";
}
else
{

var sortResult = compArray.OrderBy(a => a.SerialNumber);
divSerial.InnerHtml = divSerial.InnerHtml + "
";

foreach (Computer comp in sortResult)
{
divSerial.InnerHtml = divSerial.InnerHtml + "<hr />";
divSerial.InnerHtml = divSerial.InnerHtml + "
";
divSerial.InnerHtml = divSerial.InnerHtml + "<p><b>Name:</b> " + comp.Name + "</p>";
divSerial.InnerHtml = divSerial.InnerHtml + "<p><b>Manufacturer:</b> " + comp.Manufacturer + "</p>";
divSerial.InnerHtml = divSerial.InnerHtml + "<p><b>Model:</b> " + comp.Model + "</p>";
divSerial.InnerHtml = divSerial.InnerHtml + "<p><b>Serial Number:</b> " + comp.SerialNumber + "</p>";
divSerial.InnerHtml = divSerial.InnerHtml + "
";
}
}

emg.Dispose();
}
}

DIY Service Manager Analyst Portal – Part 4 – Resolving an Incident

The edit.aspx and edit.aspx.cs file is where we can go in and resolve an incident through this basic analyst portal.  Again, the HTML is fairly basic and is driven by the C# code in the background.

HTML:


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="edit.aspx.cs" Inherits="edit" %>

<html>
<body>
<form id="form1" runat="server">
<div id="editInc" runat="server">
<p>
Incident Resolution Details: <asp:TextBox ID="txtIncResDetails" runat="server" Width="100%" Height="100px" TextMode="MultiLine" ></asp:TextBox>
</p>
<p>
<asp:Button id="btnUpload" Text="Resolve!" OnClick="btnUpload_Click" runat="server" Width="105px" />
</p>
<p>
<asp:Button id="btnCancel" Text="Cancel!" OnClick="btnCancel_Click" runat="server" Width="105px" />
</p>
</div>
</form>
</body>
</html>

C#:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Common;
using Microsoft.EnterpriseManagement.Configuration;

public partial class edit : System.Web.UI.Page
{
String sID;
string Name;
EnterpriseManagementGroup emg;
ManagementPackClass wim;
ManagementPackRelationship wiToWi;
ManagementPackClass incidentClass;

protected void Page_Load(object sender, EventArgs e)
{
System.Security.Principal.WindowsIdentity wi = System.Security.Principal.WindowsIdentity.GetCurrent();
string[] a = Context.User.Identity.Name.Split('\\');

System.DirectoryServices.DirectoryEntry ADEntry;

ADEntry = new System.DirectoryServices.DirectoryEntry("WinNT://" + a[0] + "/" + a[1]);
Name = ADEntry.Properties["FullName"].Value.ToString();

Session["ID"] = Request.QueryString["ID"];

sID = Convert.ToString(Request.QueryString["ID"]);

EnterpriseManagementConnectionSettings settings = new EnterpriseManagementConnectionSettings("SCSM SERVER");
settings.UserName = "USER NAME";
char[] pass = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' };
settings.Password = new System.Security.SecureString();
foreach (char c in pass)
settings.Password.AppendChar(c);
settings.Domain = "DOMAIN NAME";

emg = new EnterpriseManagementGroup(settings);

ManagementPack mpSystem = emg.ManagementPacks.GetManagementPack(SystemManagementPack.System);

Version version = mpSystem.Version;
string keytoken = mpSystem.KeyToken;

ManagementPack incidentManagementMP = emg.ManagementPacks.GetManagementPack("System.WorkItem.Incident.Library", "31bf3856ad364e35", null);
incidentClass = emg.EntityTypes.GetClass("System.WorkItem.Incident", incidentManagementMP);
ManagementPack workItemManagementMP = emg.ManagementPacks.GetManagementPack("System.WorkItem.Library", "31bf3856ad364e35", null);
wim = emg.EntityTypes.GetClass("System.WorkItem.TroubleTicket.AnalystCommentLog", workItemManagementMP);
wiToWi = workItemManagementMP.GetRelationship("System.WorkItem.TroubleTicketHasAnalystComment");
}

protected void btnUpload_Click(object sender, EventArgs e)
{
foreach (EnterpriseManagementObject incident in emg.EntityObjects.GetObjectReader<EnterpriseManagementObject>(new EnterpriseManagementObjectGenericCriteria("Name='" + sID + "'"), ObjectQueryOptions.Default))
{
EnterpriseManagementObjectProjection emoAnalyst = new EnterpriseManagementObjectProjection(emg, wim);
emoAnalyst.Object[wim, "Id"].Value = Guid.NewGuid().ToString();
emoAnalyst.Object[wim, "Comment"].Value = txtIncResDetails.Text + "\n";
emoAnalyst.Object[wim, "EnteredBy"].Value = Name;
emoAnalyst.Object[wim, "EnteredDate"].Value = DateTime.Now.ToUniversalTime();
emoAnalyst.Object[wim, "DisplayName"].Value = "Record Resolved";
emoAnalyst.Object[wim, "IsPrivate"].Value = "False";
EnterpriseManagementObjectProjection emoIncident = new EnterpriseManagementObjectProjection(incident);
emoIncident.Add(emoAnalyst, wiToWi.Target);

//Set incident to resolved
string sResolvedStatusGuid = "2B8830B6-59F0-F574-9C2A-F4B4682F1681";
incident[incidentClass, "Status"].Value = new Guid(sResolvedStatusGuid);
//Set resolved classification to "Fixed my technician"
string sResolvedCategory = "C5F6ADA9-A0DF-01D6-7087-6B8500CA6C2B";
incident[incidentClass, "ResolutionCategory"].Value = new Guid(sResolvedCategory);
incident[incidentClass, "ResolvedDate"].Value = DateTime.UtcNow;
incident[incidentClass, "ResolutionDescription"].Value = txtIncResDetails.Text + "\n";

emoIncident.Commit();
emoIncident.Overwrite();
}

emg.Dispose();
Response.Redirect("default.aspx");
}

protected void btnCancel_Click(object sender, EventArgs e)
{
emg.Dispose();
Response.Redirect("default.aspx");
}
}

DIY Service Manager Analyst Portal – Part 3 – Viewing Details

The details.aspx and details.aspx.cs file is where we really get into the “fun” of working with the Service Manager SDK.  I should mention that we have extended the Incident class and forms to include extra fields that our organization needs (location, alternate schedule, room location, etc) that you will see in the code.  There is also a method to translate the Enumeration values (list of locations) stored by SCSM into friendly text.

HTML:


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="details.aspx.cs" Inherits="test2" %>

<html>
<body>
<form id="form1" runat="server">
<div ID="lblActive" runat="server"></div>
<div id="activeDetails" runat="server"></div>

<div ID="lblPending" runat="server"></div>
<div id="pendingDetails" runat="server"></div>
</form>
</body>
</html>

C#:


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Common;
using Microsoft.EnterpriseManagement.Configuration;

.[Serializable()]
public class Incident : IComparable<Incident>
{
public String ID { get; set; }
public String Title { get; set; }
public String Description { get; set; }
public String AltContact { get; set; }
public String Location { get; set; }
public String Room { get; set; }
public String AltSchedule { get; set; }
public DateTime CreatedDate { get; set; }
public String AffectedUser { get; set; }
public String FileAttachment { get; set; }

public int CompareTo(Incident other)
{
return Location.CompareTo(other.Location);
}
}

public partial class test2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
int cActive = 0;
int cPending = 0;

Session["tech"] = Request.QueryString["tech"];

String sUsername = Convert.ToString(Request.QueryString["tech"]);

String sActiveCriteria;
String sPendingCriteria;

if (sUsername == "unassigned")
{
sActiveCriteria = String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">
<Expression>
<And>
<Expression>
<UnaryExpression>
<ValueExpression>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAssignedToUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/LastName$</Property>
</ValueExpression>
<Operator>IsNull</Operator>
</UnaryExpression>
</Expression>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='CoreIncident!System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>Equal</Operator>
<ValueExpressionRight>
<Value>5e2d3932-ca6d-1515-7310-6f58584df73e</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</And>
</Expression>
</Criteria>");

sPendingCriteria = String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">
<Expression>
<And>
<Expression>
<UnaryExpression>
<ValueExpression>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAssignedToUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/LastName$</Property>
</ValueExpression>
<Operator>IsNull</Operator>
</UnaryExpression>
</Expression>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='CoreIncident!System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>Equal</Operator>
<ValueExpressionRight>
<Value>b6679968-e84e-96fa-1fec-8cd4ab39c3de</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</And>
</Expression>
</Criteria>");
}
else
{
sActiveCriteria = String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">
<Expression>
<And>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAssignedToUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/LastName$</Property>
</ValueExpressionLeft>
<Operator>Equal</Operator>
<ValueExpressionRight>
<Value>{0}</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='CoreIncident!System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>Equal</Operator>
<ValueExpressionRight>
<Value>5e2d3932-ca6d-1515-7310-6f58584df73e</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</And>
</Expression>
</Criteria>", sUsername);

sPendingCriteria = String.Format(@"<Criteria xmlns=""http://Microsoft.EnterpriseManagement.Core.Criteria/"">
<Expression>
<And>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Path[Relationship='WorkItem!System.WorkItemAssignedToUser' TypeConstraint='System!System.Domain.User']/Property[Type='System!System.Domain.User']/LastName$</Property>
</ValueExpressionLeft>
<Operator>Equal</Operator>
<ValueExpressionRight>
<Value>{0}</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
<Expression>
<SimpleExpression>
<ValueExpressionLeft>
<Property>$Context/Property[Type='CoreIncident!System.WorkItem.Incident']/Status$</Property>
</ValueExpressionLeft>
<Operator>Equal</Operator>
<ValueExpressionRight>
<Value>b6679968-e84e-96fa-1fec-8cd4ab39c3de</Value>
</ValueExpressionRight>
</SimpleExpression>
</Expression>
</And>
</Expression>
</Criteria>", sUsername);
}

EnterpriseManagementConnectionSettings settings = new EnterpriseManagementConnectionSettings("SCSM SERVER");
settings.UserName = "USER NAME";
char[] pass = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd'};
settings.Password = new System.Security.SecureString();
foreach (char c in pass)
settings.Password.AppendChar(c);
settings.Domain = "DOMAIN NAME";

EnterpriseManagementGroup emg = new EnterpriseManagementGroup(settings);

//Note - this projection isn't that great for performance but is provided in SCSM without the need to create your own
ManagementPackTypeProjection activemptp = emg.EntityTypes.GetTypeProjection(new Guid("285cb0a2-f276-bccb-563e-bb721df7cdec"));
ObjectProjectionCriteria activeopc = new ObjectProjectionCriteria(sActiveCriteria, activemptp, activemptp.GetManagementPack(), emg);
IObjectProjectionReader<EnterpriseManagementObject> activereader = emg.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(activeopc, ObjectQueryOptions.Default);
ManagementPackTypeProjection pendingmptp = emg.EntityTypes.GetTypeProjection(new Guid("285cb0a2-f276-bccb-563e-bb721df7cdec"));
ObjectProjectionCriteria pendingopc = new ObjectProjectionCriteria(sPendingCriteria, pendingmptp, pendingmptp.GetManagementPack(), emg);
IObjectProjectionReader<EnterpriseManagementObject> pendingreader = emg.EntityObjects.GetObjectProjectionReader<EnterpriseManagementObject>(pendingopc, ObjectQueryOptions.Default);

ManagementPackRelationship relIncidentAffectedUser = emg.EntityTypes.GetRelationshipClass(new Guid("DFF9BE66-38B0-B6D6-6144-A412A3EBD4CE"));

ManagementPackRelationship relIncidentFileAttachment = emg.EntityTypes.GetRelationshipClass(new Guid("aa8c26dc-3a12-5f88-d9c7-753e5a8a55b4"));

int n = 1;

cActive = activereader.Count();
cPending = pendingreader.Count();

List<Incident> incActiveArray = new List<Incident>();
List<Incident> incPendingArray = new List<Incident>();

String red = "#FF0000";
String green = "#00CC00";

foreach (EnterpriseManagementObjectProjection emop in activereader)
{
String date = emop.Object.Values[23].ToString();
DateTime created = Convert.ToDateTime(date);
created = created.ToLocalTime();

Incident newInc = new Incident();

newInc.ID = emop.Object.Name;
newInc.Title = emop.Object.Values[20].ToString();
newInc.Description = emop.Object.Values[21].ToString();
newInc.AltContact = emop.Object.Values[22].ToString();
newInc.Location = translate(emop.Object.Values[13].ToString());
newInc.Room = emop.Object.Values[11].ToString();
newInc.AltSchedule = emop.Object.Values[12].ToString();
newInc.CreatedDate = created;

if (emop[relIncidentAffectedUser.Target].Count > 0)
{
foreach (IComposableProjection icpAffectedUser in emop[relIncidentAffectedUser.Target])
{
String s = icpAffectedUser.Object.Name;
s = s.Replace(".", "\\");
newInc.AffectedUser = icpAffectedUser.Object.DisplayName + " (" + s + ")";
}
}
else
{
newInc.AffectedUser = "No user assigned";
}

if (emop[relIncidentFileAttachment.Target].Count > 0)
{
newInc.FileAttachment = "File attachment exists, please view in the SCSM console";
}
else
{
newInc.FileAttachment = "No file attachment";
}

incActiveArray.Add(newInc);
}

var sortResult = incActiveArray.OrderBy(a => a.Location).ThenBy(a => a.ID);

foreach (Incident inc in sortResult)
{
int days = (DateTime.Now.Date - inc.CreatedDate.Date).Days;

if (days < 7)
{
activeDetails.InnerHtml = activeDetails.InnerHtml + "<div style=\"color:" + green + "\"><h1>" + inc.ID + " (" + n + " of " + cActive + ")</h1></div>";
}
else
{
activeDetails.InnerHtml = activeDetails.InnerHtml + "<div style=\"color:" + red + "\"><h1>" + inc.ID + " (" + n + " of " + cActive + ")</h1></div>";
}

activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Title:</b> " + inc.Title + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Description:</b> " + inc.Description + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Alternate Contact Method:</b> " + inc.AltContact + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Location:</b> " + inc.Location + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Room:</b> " + inc.Room + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Alt Schedule:</b> " + inc.AltSchedule + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Created Date:</b> " + inc.CreatedDate + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>Affected User:</b> " + inc.AffectedUser + "</p>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><b>File Attachment:</b> " + inc.FileAttachment + "</p>";

activeDetails.InnerHtml = activeDetails.InnerHtml + "<p><a href=\"edit.aspx?ID=" + inc.ID + "\">Resolve Incident</a></p>";

activeDetails.InnerHtml = activeDetails.InnerHtml + "</div>";
activeDetails.InnerHtml = activeDetails.InnerHtml + "
";
activeDetails.InnerHtml = activeDetails.InnerHtml + "<hr />";
activeDetails.InnerHtml = activeDetails.InnerHtml + "
";

n++;
}

lblActive.InnerHtml = "<h1>Active Incidents: " + cActive + "</h1>";
lblActive.InnerHtml = lblActive.InnerHtml + "<hr />";
lblActive.InnerHtml = lblActive.InnerHtml + "<hr />";

n = 1;
foreach (EnterpriseManagementObjectProjection emop in pendingreader)
{
String date = emop.Object.Values[23].ToString();
DateTime created = Convert.ToDateTime(date);
created = created.ToLocalTime();

Incident newInc = new Incident();

newInc.ID = emop.Object.Name;
newInc.Title = emop.Object.Values[20].ToString();
newInc.Description = emop.Object.Values[21].ToString();
newInc.AltContact = emop.Object.Values[22].ToString();
newInc.Location = translate(emop.Object.Values[13].ToString());
newInc.Room = emop.Object.Values[11].ToString();
newInc.AltSchedule = emop.Object.Values[12].ToString();
newInc.CreatedDate = created;

if (emop[relIncidentAffectedUser.Target].Count > 0)
{
foreach (IComposableProjection icpAffectedUser in emop[relIncidentAffectedUser.Target])
{
String s = icpAffectedUser.Object.Name;
s = s.Replace(".", "\\");
newInc.AffectedUser = icpAffectedUser.Object.DisplayName + " (" + s + ")";
}
}
else
{
newInc.AffectedUser = "No user assigned";
}

if (emop[relIncidentFileAttachment.Target].Count > 0)
{
newInc.FileAttachment = "File attachment exists, please view in the SCSM console";
}
else
{
newInc.FileAttachment = "No file attachment";
}

incPendingArray.Add(newInc);
}

var sortPendingResult = incPendingArray.OrderBy(a => a.Location).ThenBy(a => a.ID);

foreach (Incident inc in sortPendingResult)
{
int days = (DateTime.Now.Date - inc.CreatedDate.Date).Days;

if (days < 7)
{
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<div style=\"color:" + green + "\"><h1>" + inc.ID + " (" + n + " of " + cPending + ")</h1></div>";
}
else
{
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<div style=\"color:" + red + "\"><h1>" + inc.ID + " (" + n + " of " + cPending + ")</h1></div>";
}

pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Title:</b> " + inc.Title + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Description:</b> " + inc.Description + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Alternate Contact Method:</b> " + inc.AltContact + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Location:</b> " + inc.Location + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Room:</b> " + inc.Room + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Alt Schedule:</b> " + inc.AltSchedule + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Created Date:</b> " + inc.CreatedDate + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>Affected User:</b> " + inc.AffectedUser + "</p>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><b>File Attachment:</b> " + inc.FileAttachment + "</p>";

pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<p><a href=\"edit.aspx?ID=" + inc.ID + "\">Resolve Incident</a></p>";

pendingDetails.InnerHtml = pendingDetails.InnerHtml + "</div>";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "
";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "<hr />";
pendingDetails.InnerHtml = pendingDetails.InnerHtml + "
";

n++;
}

lblPending.InnerHtml = "<h1>Pending Incidents: " + cPending + "</h1>";
lblPending.InnerHtml = lblPending.InnerHtml + "<hr />";
lblPending.InnerHtml = lblPending.InnerHtml + "<hr />";

emg.Dispose();

}

public string translate(String strLocation)
{
switch (strLocation)
{
case "":
return "No location specified";
case "Enum.14cc8a0e69924da290753329d6568e41":
return "No location specified";
case "(null)":
return "No location specified";
case "Enum.0444226300e947f9bf173e72ff6dab16":
return "Location 1";
case "Enum.742fdc5e91194c08b48af5c7891af15d":
return "Location 2";
case "Enum.420e59a8160b4a9a9ae48a3039b9cfda":
return "Location 3";
}
return strLocation;
}
}

There is a lot going on in the code, but what it will give you is two lists of Incidents (in our case, sorted by location and created date so techs can see oldest to newest alphabetically by building location), first active incidents then pending.  Incidents older than a certain number of calendar days will be in red to indicate an aging call that needs to be dealt with and green for anything else.

The list will also tell if someone posted an attachment and if so direct them to the SCSM console to view it.  It may be possible to access it via the webpage but if that is true I haven’t figured it out yet.

DIY Service Manager Analyst Portal – Part 2 – default.aspx

Welcome to part 2 of the DIY Analyst Portal for Service Manager.  This post is dedicated to the most basic page on the site, the default.aspx home page.  It is purely HTML and anyone could create it in seconds but I’ve included it anyway.  The code has been generalized and only the pertinent code required to run the site has been included.


<html>
<body>
<form>
<div>
<p><a href="details.aspx?tech=unassigned">Unassigned</a></p>


<p><a href="details.aspx?tech=tech1">Tech 1</a></p>


<p><a href="details.aspx?tech=tech2">Tech 2</a></p>


<p><a href="details.aspx?tech=tech3">Tech 3</a></p>


<hr />


<p><a href="serial.aspx">Check Serial Number</a></p>
</div>
</form>
</body>
</html>

KB2520155 and the Mysteriously Disappearing DNS Record

Our organization has an interesting bug with some of our servers – if they don’t “cleanly” shut down and are down for 15+ minutes, the DNS record is deleted when they come back up causing all sorts of issues.  The servers that were encountering this issue were all Windows 2008 R2.

While attending a recent local user group of IT professionals, Microsoft KB 2520155 (link here) happened to be mentioned during a presentation on a members journey of updating a SBS2003/Exchange 2003 server to Windows Server 2012 R2 and Exchange 2013.  As the article hasn’t been modified since 2012 who knows if the 2012 or 2012 R2 versions of Windows Server are prone to the issue or not.

What is interesting is we have had tickets open with Microsoft before regarding our issue and have had them check our systems with no mention of this particular article or the hotfix.

So if you have a randomly disappearing DNS record, whether client or server, check this out!

–NB

DIY Service Manager Analyst Portal – Part 1

One of the shortcomings of the Service Manager product is the lack of an analyst portal for remote technicians to easily view and resolve tickets without having to remote into a machine and use the SCSM console.

This short series of blog posts will show my way of getting around this limitation and after this prelude I will start to add more posts in the near future.  Using the SDK for SCSM I was able to build my own analyst portal which performs beautifully on both a desktop browser and mobile device.

This is a straightforward HTML website driven by C# in the background – no fancy HTML5 or anything here (so far)!  I will generalize the code as I post it as some menu items are hard-coded, such as technician names to link to their tickets.  Also the current implementation only looks at IR (Incident Request) tickets that have been submitted.  In my organisation we do not use Service Requests or Change Requests but if you do you can try modifying the code.

This code is offered freely for you to investigate and carries with it no warranty or anything like that.

hello, world

Hello and welcome to my new blog.  Over the coming weeks, months, and years I hope offer what advice, tips, or tricks I have discovered in my time as an IT professional.  I’ll also share some of my custom-built work in the hopes that it helps others.