Browsed by
Author: Steven

Actual Installed Application Reporting from SCCM

Actual Installed Application Reporting from SCCM

Having worked on SCCM for many years now I have lost count of how many times I have been asked, “Since you guys have an agent on all of the computers can I get you to provide me a list of ALL software that is installed on all of the computers?” after which there is a long draw out discussion explaining that when SCCM returns the information from Programs and Features it doesn’t discriminate between System install applications which are not visible in Programs and Features in which you will typically end up with double the amount of applications per computer, then what actually appears in Programs and Features. To this end I’ve had some spare time recently, so I have done some investigating, and found that with a simple update of the MOF we can typically get within +/-98% accuracy of only the applications that appear in Programs and Features appearing in the SCCM reports, which for me it a huge win.

As we know the Registry is the master of what appears in the Programs and Features list, so for example you can change the Display Name of applications in Programs and Features by changing the following registry Item:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\|DisplayName

This Key also includes such things as the Publisher, Version numbers, and Uninstallation strings. The Item’s which we are interested in for this solution are the following:
SystemComponent
ParentDisplayName

The SystemComponent item will appear as 1 if the application is to be hidden from Programs and Features, so for example the SCCM Client will have SystemComponent = 1 which appears to hide it from Programs and Features, if this item is not defined it is assumed to be a 0 (This is also used by Microsoft Office to hide each of the components from Programs and Features).

Whereas the ParentDisplayName item is used for patches to applications and Operating system, an example of can be seen in Windows XP where you could select the check box to hide updates. When not referring to the install Operating System it will refer to the DisplayName of the parent, for example “Microsoft .NET Framework 4 Client Profile” will have all of the updates that are dependent upon it.

Now we have explained what we are doing and why let’s step through the process of actually capturing the details in SCCM.

  1. Browse to \\<SCCMSERVER>\SMS_<SITECODE>\inboxes\clifiles.src\hinv
  2. Copy Configuration.mof to c:\data\mofs
  3. Open Configuration.mof with Notepad
  4. Find the Follow:
    class Win32Reg_AddRemovePrograms
    {
    [key]
    string ProdID;
    [PropertyContext(“DisplayName”)]
    string DisplayName;
    [PropertyContext(“InstallDate”)]
    string InstallDate;
    [PropertyContext(“Publisher”) ]
    string Publisher;
    [PropertyContext(“DisplayVersion”)]
    string Version;
    }
    and Replace with the following:
    class Win32Reg_AddRemovePrograms
    {
    [key]
    string ProdID;
    [PropertyContext(“DisplayName”)]
    string DisplayName;
    [PropertyContext(“InstallDate”)]
    string InstallDate;
    [PropertyContext(“Publisher”) ]
    string Publisher;
    [PropertyContext(“DisplayVersion”)]
    string Version;
    [PropertyContext(“SystemComponent”)]
    string SystemComponent;
    [PropertyContext(“ParentDisplayName”)]
    string ParentDisplayName;
    }

  5. Then find the following directly below:
    class Win32Reg_AddRemovePrograms64
    {
    [key]
    string ProdID;
    [PropertyContext(“DisplayName”)]
    string DisplayName;
    [PropertyContext(“InstallDate”)]
    string InstallDate;
    [PropertyContext(“Publisher”) ]
    string Publisher;
    [PropertyContext(“DisplayVersion”)]
    string Version;
    }
    and Replace with the following:
    class Win32Reg_AddRemovePrograms64
    {
    [key]
    string ProdID;
    [PropertyContext(“DisplayName”)]
    string DisplayName;
    [PropertyContext(“InstallDate”)]
    string InstallDate;
    [PropertyContext(“Publisher”) ]
    string Publisher;
    [PropertyContext(“DisplayVersion”)]
    string Version;
    [PropertyContext(“SystemComponent”)]
    string SystemComponent;
    [PropertyContext(“ParentDisplayName”)]
    string ParentDisplayName;
    }

  6. Close and Save Configuration.mof
  7. In an elevated command prompt run the following commands:
    1. Mofcomp c:\data\configuration.mof
      the result should look like this:
  8. Browse back to: \\<SCCMSERVER>\SMS_<SITECODE>\inboxes\clifiles.src\hinv and rename the existing file to match this naming convention:
    1. configurationYYYYMMDD.mof
  9. Copy configuration.mof from c:\data to \\<SCCMSERVER>\SMS_<SITECODE>\inboxes\clifiles.src\hinv
  10. Open SCCM 2012 Console and browse Administration à Client Settings
  11. Right click on Default Client Settings and select Properties
  12. Select Set Classes under the Hardware Inventory tab on the Default Settings Form
  13. Select Export on the Hardware Inventory Classes form
  14. Save the exported file to c:\data\export.mof
  15. Open C:\data\export.mof in notepad
  16. Find the following:
    class Win32Reg_AddRemovePrograms : SMS_Class_Template
    {
    [SMS_Report (TRUE), key ]
    string ProdID;
    [SMS_Report (TRUE) ]
    string DisplayName;
    [SMS_Report (TRUE) ]
    string InstallDate;
    [SMS_Report (TRUE) ]
    string Publisher;
    [SMS_Report (TRUE) ]
    string Version;
    };

    and replace with:
    class Win32Reg_AddRemovePrograms : SMS_Class_Template
    {
    [SMS_Report (TRUE), key ]
    string ProdID;
    [SMS_Report (TRUE) ]
    string DisplayName;
    [SMS_Report (TRUE) ]
    string InstallDate;
    [SMS_Report (TRUE) ]
    string Publisher;
    [SMS_Report (TRUE) ]
    string Version;
    [SMS_Report (TRUE) ]
    string SystemComponent;
    [SMS_Report (TRUE) ]
    string ParentDisplayName;
    };

  17. Then find the following directly below:
    class Win32Reg_AddRemovePrograms64 : SMS_Class_Template
    {
    [SMS_Report (TRUE), key ]
    string ProdID;
    [SMS_Report (TRUE) ]
    string DisplayName;
    [SMS_Report (TRUE) ]
    string InstallDate;
    [SMS_Report (TRUE) ]
    string Publisher;
    [SMS_Report (TRUE) ]
    string Version;
    };

    and replace with:
    class Win32Reg_AddRemovePrograms64 : SMS_Class_Template
    {
    [SMS_Report (TRUE), key ]
    string ProdID;
    [SMS_Report (TRUE) ]
    string DisplayName;
    [SMS_Report (TRUE) ]
    string InstallDate;
    [SMS_Report (TRUE) ]
    string Publisher;
    [SMS_Report (TRUE) ]
    string Version;
    [SMS_Report (TRUE) ]
    string SystemComponent;
    [SMS_Report (TRUE) ]
    string ParentDisplayName;
    };
  18. Close and Save c:\data\export.mof
  19. On the Hardware Inventory Classes form select Import
  20. Review the Message to ensure everything is correct, and Select Import.
  21. On the Hardware Inventory Classes form search for Win32reg_addremoveprograms and ensure that SystemComponent & ParentDisplayName are selected, then click on OK, and OK, back to the SCCM Console

To test ensure that you have completed a Policy refresh on a targeted computer, wait a few minutes then trigger a hardware inventory, you can see if the policy has updated by reviewing the InventoryAgent.log on the client computer and filter with CMTrace for Win32reg_addremoveprograms, you should see something like this:

And on the server side you can confirm the new inventory has been loaded by reviewing the DataLdr.log file on the Site server, looking for the line
“Done: Machine=(GUID:) code=0 (1473 stored procs in .MIF)”
to ensure that the data has been loaded into the SQL database.

From here we can create a report using the following example SQL query:
Count of all applications installed on all computers:

SELECT
*
FROM
(

SELECT
DISTINCT

v_GS_ADD_REMOVE_PROGRAMS_64.DisplayName0 AS “Product Name”, v_GS_ADD_REMOVE_PROGRAMS_64.Publisher0 AS “Publisher”,
count(*)
as
‘Install count’

FROM v_GS_ADD_REMOVE_PROGRAMS_64

INNER
JOIN v_R_System_Valid ON v_R_System_Valid.ResourceID = v_GS_ADD_REMOVE_PROGRAMS_64.ResourceID

JOIN v_GS_OPERATING_SYSTEM ON v_GS_ADD_REMOVE_PROGRAMS_64.ResourceID = v_GS_OPERATING_SYSTEM.ResourceID

WHERE v_GS_ADD_REMOVE_PROGRAMS_64.SystemComponent0 is
null
and v_GS_ADD_REMOVE_PROGRAMS_64.parentdisplayname0 is
null
and
not v_GS_ADD_REMOVE_PROGRAMS_64.Displayname0 is
null

group
by v_GS_ADD_REMOVE_PROGRAMS_64.DisplayName0, v_GS_ADD_REMOVE_PROGRAMS_64.Publisher0

UNION ALL

(


SELECT
DISTINCT

v_GS_ADD_REMOVE_PROGRAMS.DisplayName0 AS “Product Name”, v_GS_ADD_REMOVE_PROGRAMS.Publisher0 AS “Publisher”,count(*)
as
‘Install count’


FROM v_GS_ADD_REMOVE_PROGRAMS


INNER
JOIN v_R_System_Valid ON v_R_System_Valid.ResourceID = v_GS_ADD_REMOVE_PROGRAMS.ResourceID


JOIN v_GS_OPERATING_SYSTEM ON v_GS_ADD_REMOVE_PROGRAMS.ResourceID = v_GS_OPERATING_SYSTEM.ResourceID


WHERE v_GS_ADD_REMOVE_PROGRAMS.SystemComponent0 is
null
and v_GS_ADD_REMOVE_PROGRAMS.parentdisplayname0 is
null
and
not v_GS_ADD_REMOVE_PROGRAMS.Displayname0 is
null

    group
by v_GS_ADD_REMOVE_PROGRAMS.DisplayName0, v_GS_ADD_REMOVE_PROGRAMS.Publisher0

))
AS u

ORDER
BY “Product Name”, Publisher

Installed applications on a Single Computer:

DECLARE @compname VARCHAR(MAX) = ‘Computer Name’

SELECT
*
FROM
(

SELECT
DISTINCT

v_GS_ADD_REMOVE_PROGRAMS_64.DisplayName0 AS “Product Name”, v_GS_ADD_REMOVE_PROGRAMS_64.Publisher0 AS “Publisher”, v_GS_ADD_REMOVE_PROGRAMS_64.Version0 AS “Version”

FROM v_GS_ADD_REMOVE_PROGRAMS_64

INNER
JOIN v_R_System_Valid ON v_R_System_Valid.ResourceID = v_GS_ADD_REMOVE_PROGRAMS_64.ResourceID

JOIN v_GS_OPERATING_SYSTEM ON v_GS_ADD_REMOVE_PROGRAMS_64.ResourceID = v_GS_OPERATING_SYSTEM.ResourceID

WHERE v_GS_ADD_REMOVE_PROGRAMS_64.SystemComponent0 is
null
and v_GS_ADD_REMOVE_PROGRAMS_64.parentdisplayname0 is
null
and
not v_GS_ADD_REMOVE_PROGRAMS_64.Displayname0 is
null

and v_R_System_Valid.Netbios_Name0 = @compname

UNION ALL

(


SELECT
DISTINCT

v_GS_ADD_REMOVE_PROGRAMS.DisplayName0 AS “Product Name”, v_GS_ADD_REMOVE_PROGRAMS.Publisher0 AS “Publisher”, v_GS_ADD_REMOVE_PROGRAMS_64.Version0 AS “Version”


FROM v_GS_ADD_REMOVE_PROGRAMS


INNER
JOIN v_R_System_Valid ON v_R_System_Valid.ResourceID = v_GS_ADD_REMOVE_PROGRAMS.ResourceID


JOIN v_GS_OPERATING_SYSTEM ON v_GS_ADD_REMOVE_PROGRAMS.ResourceID = v_GS_OPERATING_SYSTEM.ResourceID


WHERE v_GS_ADD_REMOVE_PROGRAMS.SystemComponent0 is
null
and v_GS_ADD_REMOVE_PROGRAMS.parentdisplayname0 is
null
and
not v_GS_ADD_REMOVE_PROGRAMS.Displayname0 is
null

and v_R_System_Valid.Netbios_Name0 = @compname

))
AS u

ORDER
BY “Product Name”, Publisher

You will notice that we are not using the “v_add_remove_programs” view, this appears to be a derived view which doesn’t appear to be updated when new columns added to the Class, but we can get around this by using the Union function in SQL.

Good Luck

Steve

Logical steps to automate a task

Logical steps to automate a task

In this blog I’m going to detail the logic steps that I use to automate a task, I can’t say this is the best way or the most efficient way to complete the task but it is the process that I have developed over the last decade for myself to automate tasks.

First off we start with the what, when, why, and how of the task so in this example let’s detail the clean-up of a folder on a group of computers let’s call it:

c:\users\<username>\appdata\roaming\Apple computer (you know the folder that roams with the backup of your iPhone)

So we have the What which is empty the apple computer folder

The When well you would want to complete this task before the roaming profiles starts to copy the files up to your file server.

The Why is a simple one where we want to stop the replication of a stupid amount of data when you log on and off the computer.

And the How in this circumstance we are going to use an SCCM compliance settings.

These all group together to provide us a purpose as to why we are making this change. The next step is to start stepping out the process, I personally prefer to do this with a pencil and paper with a rubber, as it allows you to remove the computer element from your planning. In saying that Visio does the task just as well if not better as you don’t have to keep rubbing things out if you keep missing steps. My process flowcharts look something like this:

remediate

So we have a simple process mapped out now which gives us a high level break down of the steps required to complete the task.

From here I like to put fragments of code that I’m going to use next to each process step, this give me the ability to capture where I use the same process repeatedly where it might suit a sub routine or function.

In this example I will use VBscript as it might need to run on machines that don’t have PowerShell I’m looking at you XP.

remediatewithscript

So from here we can create a script that looks something like this:

 


strComputer = "."
dim OS
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery _
("SELECT * FROM Win32_OperatingSystem")
For Each objOperatingSystem in colOperatingSystems
OS = objOperatingSystem.Caption
Next
 
if instr(os, "XP") or instr(os, "2003") then
                userpath = "c:\documents and settings"
else
                userpath = "c:\users"
end if
 
set FSO = createobject("Scripting.FileSystemObject")
userfolder = fso.getfolder(userpath)
 
for each subfolder in userfolder
                if FSO.folderexists(subfolder.path & "\appdata\roaming\Apple computer") then
                                FSO.deletefolder(subfolder.path & "\appdata\roaming\Apple computer")
                end if
next

 

This will remediate the issue on all of the targeted computers. Now we need to make it so we can detect if the folder actually exists on the computer to use the SCCM Compliance Settings.

The process is very much the same for the Detection method but rather than deleting the folder if we find it we will return back that we have found the folder and it would look something like this:

Discovery

Obviously we can use the same process to create the script to detect the folder, and reuse a good part of our previous script, on the process diagram it would look like this:

Discoverywithscript

Which results in a script that looks like this:

 


strComputer = "."
dim OS
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery _
("SELECT * FROM Win32_OperatingSystem")
For Each objOperatingSystem in colOperatingSystems
OS = objOperatingSystem.Caption
Next
 
if instr(os, "XP") or instr(os, "2003") then
                userpath = "c:\documents and settings"
else
                userpath = "c:\users"
end if
 
set FSO = createobject("Scripting.FileSystemObject")
userfolder = fso.getfolder(userpath)
 
noncompliant = 0
for each subfolder in userfolder
                if FSO.folderexists(subfolder.path & "\appdata\roaming\Apple computer") then
                                noncompliant = noncompliant + 1
                end if
next
 
if noncompliant > 0 then
                wscript.echo "Non-Compliant"
else
                wscript.echo "Compliant"
end if

From here we can create a script based configuration item and apply it to a configuration baseline in SCCM with remediation.

We now have everything required to create our new Configuration Item in SCCM 2012 to create this we need to open the SCCM 2012 Console and navigate to Assets and Compliance, Compliance Settings, Configuration Items.

From here we can select the Create Configuration Item task from the Ribbon

createconfigitem

On the Create Configuration Item Wizard form enter a descriptive name something like U – Cleanup Apple Backups which provides a quick view of what the task is, I would also strongly encourage the use of the Description box to save you needing to try to pull apart your Configuration Item 6 months down the track when you have to fix it.

On the next page we can define the Platform we are wanting to support, as we handle this in the script we can just leave it with the default of select all.

Now we can create a new Settings object and fill it out to look something like this:

createsetting

You will see the Red error mark next to the Add Script for Discovery Script, let’s go ahead and add the script we create earlier making sure to change the script language to vbscript

discoscript

Complete the same steps to add the Remediation script, and select OK to close out of the Create Setting form.

On the Compliance Rules stop in the Create Configuration Item Wizard we are now going to define on what condition we will declare noncompliance needing remediation, which looks something like this:

compliacerule

Note the field for “the following values” is where we handle the command we echo in the script.

From here we can complete the wizard and apply the new Configuration Item to a baseline and your systems and clean up the Apple backup folder before it clogs up your roaming profiles.

I hope this has provided an insight in to a process that you can use to create automated processes.

Good Luck

Steve

Troubleshooting like a Boss (not a real Boss tho)

Troubleshooting like a Boss (not a real Boss tho)

Recently I have been doing some informal training sessions with some junior staff members and realised that there is quite a few things we do in the this industry that can be very hard to pick up without prompting from the guys that have been around for a while. As such I figured I would take a few hours and detail some of the processes I use to troubleshoot issues.

From a troubleshooting point of view, let’s review a scenario that recently I have been involved in resolving.

Scenario:

When logging on to a computer post ADMT on a few computers we were receiving the follow error message when attempting to log onto the computer with an account that hadn’t previously logged onto the computer:

User Profile Service Service Failed the logon. User Profile cannot be loaded

When this came to me there had already been 2 tech’s looking into this error, and were blaming it on the Domain migration, we could log onto the machine as Local administrator and I could connect remotely to it via the SCCM 2012 Remote tools.

Trouble Shooting Steps:

The first steps to investigate this issue would be to start in the event log, I know it sounds daunting to look in the event log it’s huge and there is so much information in there, which is exactly why this is perfect for the task at hand.

We looked in the Security event log and there was no issues with the computer or the user authenticating, right away at a high level we can start ruling out the ADMT component of the changes to the system, as there would be authentication issues between the machine and the domain if there was.

We then moved to the Application event log and right away we started seeing warning events like this every time a new user attempts to logon:

Windows cannot copy file C:\Users\Default\AppData\Local\Microsoft\Windows Live\SqmApi\SqmData720896_00.sqm to location C:\Users\Guest\AppData\Local\Microsoft\Windows Live\SqmApi\SqmData720896_00.sqm. This error may be caused by network problems or insufficient security rights.

DETAIL – Access is denied.

And:

Windows cannot find the local profile and is logging you on with a temporary profile. Changes you make to this profile will be lost when you log off

And:

Windows cannot copy file C:\Users\Default\AppData\Local\Microsoft\Windows Live\SqmApi\SqmData720896_00.sqm to location C:\Users\TEMP\AppData\Local\Microsoft\Windows Live\SqmApi\SqmData720896_00.sqm. This error may be caused by network problems or insufficient security rights.

DETAIL – Access is denied.

And:

Windows cannot log you on because your profile cannot be loaded. Check that you are connected to the network, and that your network is functioning correctly.

DETAIL – Only part of a ReadProcessMemory or WriteProcessMemory request was completed.

So we browse to “C:\Users\Default\AppData\Local\Microsoft\Windows Live\SqmApi” and sure enough when we looked at the permissions on SqmData720896_00.sqm we found that the user’s security group didn’t have access to the file thus it was causing the User Profile Service to fail as it couldn’t copy this file into the new user profile nor the Temp profile. Once the permissions we replicated from the parent folder the issue was resolved. I know it sounds simple when you see it like this, but this whole troubleshooting took around 20-30 minutes, with much searching around the internet and discussion with the techs on site to find out the extent of the issue and alike, and keeping them informed throughout the trouble shooting phase.

Wrap up:

The biggest piece of advice I can provide anybody just starting out and wanting to impress around there troubleshooting ability, is to use the KISS method,

K eep

I t

S imple

S tupid

Always think that the simplest answer is the correct one, this methodology can be used for creating the fix for the issue, if it’s for the issue above where it was impacting lest than 5 users it doesn’t make sense to script or even automate the issue, this is something that you hand the solution back to the support teams with the comment if you see this issue check this event message and confirm it is the exact issue then run the remediation steps. If this issue was impacting a large percentage of my fleet I would look at creating a fix to remediate it proactively, be it with a simple Group Policy as this one could be covered with, or a compliance setting from SCCM it can be automated if need be.

In the heat of an issue it can be very hard to keep calm especially when you need to be able to quickly and confidently rule out idea even if everybody else working on the issue keeps pointing at that being the issue, I recommend setting your IM to Busy or Do Not Disturb so only the people you can control the flow of information coming in, let’s face it being told for the 10th time that there are users unable to logon to their computers gets a bit grating when you are trying to focus on how you are going to resolve the issue, in saying that being able to bounce ideas of co-workers is just as invaluable as they might have made a change to the system or alike that you are not aware of.

The next thing to start looking at is the log files be it the event log or application specific logs, now days most good applications log almost everything, this is where you will find out more information about the goings on of your system then randomly clicking around the OS to try to just resolve the issue like a lot of admins now days do so often, with the goal of, I just have to fix the issue and if I try this it might fix the problem. In some cases you can resolve or at least Band-Aid a solution by doing this, but it normally takes a lot longer to come to the root cause and in most cases you don’t know the root cause as you have just found the fix and moved on to the next fire. I can’t say that logs will provide the answer for everything problem but it is a fantastic place to start.

Another simple thing you can do if the machine is blue screen is to get the Debug tool kit from Microsoft for you OS and run the dump check application over the memory.dmp/mini.dmp file which typically will return the offending component of the OS just confirm dates before you do it as it might have been from a blue screen 2 weeks/months/years earlier.

I know a lot of what I’m saying is common sense to most of us but the number of people I deal with now days that gloss over these troubleshooting steps it staggering, the other thing that makes a great troubleshooter is somebody who has the confidence to sit there and state their case and back it up, there is no point working out the problem, then raising the ticket to a senior resource without a hand over because you are not quite sure about the answer. The senior resources have typically made it to those roles because they have back themselves and ask the right questions to build trust with the management teams.

Good Luck and Happy trouble shooting,

Steve

Why could SCCM Compliance Settings replace Group Policy?

Why could SCCM Compliance Settings replace Group Policy?

My hope with this post is to plant an idea in your mind on what could be done with SCCM Compliance Settings over using Group Policy. Let’s start off with an over view of the 2 options we will be discussing today.

Group Policy (GPO)

You can trace Group Policy all the way back to the first version of Active Directory in Windows Server 2000, the use of ADM files can be traced back even further into NT4, and windows 95/98 using the System Policy Editor which was part of the NT 4.0 Resource Kit which you can download here for those of you still using NT as your domain. Don’t get me wrong along the way Microsoft has added more features into Group Policy, for example Group Policy Preferences which was part of the acquisitions of Desktop Standard in 2006 originally called PolicyMaker. This alone has made group policy quite a powerful tool since Server 2008, the centralisation of the task like Printer and Drive Mapping which previously the easiest way to deploy these settings was Logon Script. The addition of the Advance Group Policy Management tool in the MDOP was great for those large companies which had SA and then also know about it, and admins didn’t know a password for a domain admin account, but a step in a very good direction none the less. Let’s face it most vendors that are doing large-scale deployments provide ADM/x files to configure the application as it still is a very easy way to empower the admins.

One of my biggest gripes with Group Policy was very noticeable in Windows XP, and less so in the new Windows Versions is that it is a set and hope solution, what I mean by this is that if I define a policy to my whole fleet without completing a process which is not out of the box I have to hope that the settings have applied, and typically I find out a month later when somebody raises the issue that was meant to be resolved.

Compliance Settings

Much like Group Policy you can trace Compliance Settings back a few generations of SCCM/SMS, to SMS 2003 to be precise. I have to on good authority it was originally created to confirm that exchanges servers in a large company had the same settings as each other. In 2003 the feature was called Desired Configuration Monitoring it was very much a passive process of collecting information, from which you could pull a report from. In SCCM 2007 this feature was renamed to Desired Configuration Management, and improved slightly it was included as a component that ran under ccmexec, it was converted to XML files stored on the client computer rather than WMI Classes which were returned with Hardware Inventory. Again it was very much a passive reporting feature which required manual steps to remediate the problems, and in large environments it gave you some where to start. Then Microsoft moved to SCCM 2012 and like a good deal of the product this component was given a comprehensive overhaul, along with the Compliance Settings moniker. As part of the overhaul a few new options were added, such as Remediation, a larger range of detection types (AD, Registry Keys, Scripts, SQL/WQL queries to name a few), and the ability to create a Collection from each deployment dependent on the status message.

Until SCCM 2012 I didn’t see a huge use for DCM as I was managing sites of around the 5000 seat mark, which is just on the cusp of needing to have everything repeatable. But with SCCM 2012 I can see great potential for Compliance Settings to replace large parts of Group Policy Objects which will not only allow for the reporting of settings, but ideally reduce the logon/startup time for our computers. In addition to this it has the ability for staff to run the evaluation independent of the schedule & create a local report without using the commandline. One of the downsides is this is equivalent to a local group policy setting, which is trumped by the Domain Group Policy, so it is one or the other for each of the defined settings.

Demo

Group Policy

So let’s for example say you work for a company which wants to annoy your staff by defining a standard wallpaper for all staff.

So in Group Policy we would create a new Group Policy Object, and define the following setting:

To point to in this example c:\windows\demo.jpg and defined to be centered.

We then assign it to the desired OU and it’s deployed.

Then you get the staff that have managed to convince the people of power, that to complete their work they must have local admin access to the work computer, you know the type that install “freeware” software for Business purposes and deny it when you approach them for a licence key. These guys are super smart and work out that they can change the wallpaper by making a regkey change, or replacing a file. As stated above there is no way out of the box to report on this, so you get questions from your managers as to why these guys have different wallpapers and the inevitable how can I change theirs for them.

dcm1

SCCM Compliance Settings

So with SCCM to define this we first need to get the RegKey that is being defined as part of the Group Policy Setting, for something like Desktop Wallpaper you can google Bing it and some bright spark will have published it, like this: HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System Wallpaper – REG_SZ WallpaperStyle – REG_SZ

For the more complicated settings if they are default Windows polices you can download excel files which detail each policy and the regkey that is set from here and for Office products you can find the link here.

We now have the registry key for our new Configuration Item in SCCM 2012 to create this we need to open the SCCM 2012 Console and navigate to Assets and Compliance, Compliance Settings, Configuration Items.

From here we can select the Create Configuration Item task from the Ribbon

dcm2

On the Create Configuration Item Wizard form enter a descriptive name something like

U – Desktop Wallpaper which represents that we are defining a user setting for the desktop wallpaper, in addition to this I would recommend put a brief blurb in the Description box as you will be wondering why you created the item 6 months later.

The other part you need to make sure is that if you are defining a registry key that the settings applies to the operating systems which you are targeting on the Supported Platform page.

When we get to the point of creating a new Setting this is where we can define multiple settings that must be met, for example a scripted item to confirm the wallpaper file hasn’t been changed, and a registry value to ensure that the registry key hasn’t been changed.

Something like this for the registry key item:

dcm3

We can then create compliance rules around the setting, which is where we can set it to report on if a certain value exists, and that it meets a defined task. In this example we want Wallpaper to equal “C:\windows\demo.jpg” in addition to reporting on if the systems are compliant, we can also remediate the setting where desired, in this case we do want to remediate the setting as shown below:

dcm4

We have now created the Compliance Item which we can deploy to our users/computers with a configuration baseline. Again use a descriptive name, so for this demo we will use U – Desktop Wallpaper and add the Configuration Item that we created earlier.

dcm5

We then deploy this to our desired collections, and this is where we can create multiple deployments one which will remediate the setting, and the other to only report on it, along with how often we want the evaluation to run on the computers.

dcm6

On the client side your users will see the following tab in the Configuration Manager Client in the control panel.

dcm7

As you can see you have ability to evaluate each of the Assigned baselines, along with providing a local report of the compliance of the baseline.

Good Luck

Steve

Reporting on Shares with SCCM 2012

Reporting on Shares with SCCM 2012

To follow in the same vain as my last post for reporting on usage of logon scripts, we now need to find which shares have been removed since the last time the logon script was updated. To do this is reasonably easy to complete by connecting to each share and checking to see if they still exist, until you have a list of over 200 shares to check. So let’s take a look at what we can do with SCCM to handle this.

First task would be to identify if we can utilise an existing WMI class to query, thankfully there is the Win32_Share class which will return the information back to SCCM. In addition to this we can enable this class via selecting it in the Hardware Inventory for the client settings.

RSpic1

Once this has been enabled and some of the computers have reported back you can use the below query to your database. To present the data back in a usable form I have joined the share path.

RSpic2

 

Now we have the server names tied to the share paths, from this we can grab the shares from the logon script and do a query like this

 

select ‘\\’ + rsys.name0 + ‘\’ + sha.name0
from v_GS_SHARE as sha
Join v_r_system as rsys on sha.resourceID = rsys.resourceID
where ‘\\’ + rsys.name0 + ‘\’ + sha.name0 in (‘\\cm7\admin4’,
‘\\or7\c$’)

This will bring back a nice list we can then copy into excel and do a simple countif on the 2 columns of share paths.

The problem we have is when it comes to Clustered shares, as since Server 2000 Microsoft hasn’t represented the shares for Clusters with the Win32_Share class. But from Server 2008 R2 we have be able to query the Win32_Clustershare. The process to add this class to the hardware inventory in SCCM is a little bit different as you need to add the class to the list,

To do this open the “default client settings” policy and browse the hardware inventory, then select Classes to inventory. once this appears select Add and then on the screen that appears hit the connect button. Which will bring a prompt like this. (Yes Microsoft forgot to select the password field as hidden). Make sure you select Recursive otherwise most classes wont appear.

RSpic3

Once you select connect, search the win32_clustershare class and enable it.

RSpic4

Then we can select the Fields that we want to inventory either in the Default policy to apply to all computers in the environment, or apply to a new/existing client settings policy.

RSpic5

Once we have deployed the Client Settings to the cluster we can return the data with the below query, as you can see the default fields are structured a little bit differently to the win32_share class. The class has both the server name and the Share Path which saves creating a constructed string.

RSpic6

Much like the Win32_Share class we can do a where in query which would look something like this:

select ServerName0,
Path0,
Name0
from v_GS_CLUSTER_SHARE
where name0 in (‘\\svr354\ab’,
‘\\svr354\acc’)

From here you have a couple of options on how to move forward, for example you can create both of these queries as data sources in an Excel Workbook with the 3rd sheet containing a list of all your shares from your logon script, from which you can derive the exists of each of the shares from either the win32_share or the Win32_clustershare data sources.

Cheers

Steve

UPDATED: missing image.

Reporting on logon scripts with SCCM 2012

Reporting on logon scripts with SCCM 2012

I had a use case to be able to report on the Current logon scripts in our environment, along with the status of the user accounts. This report is to be used to plan the consolidate all of our many logon scripts into a single script.

So by default we all look to running a powershell script or alike to return the logon script details from Active Directory and use that to plan the consolidation, as we all know this is a static list which we need to obtain on a regular bases to ensure that we keep track of the changes.

So I had the idea of what if we can capture this information in a SQL database and make it work for us, thankfully Microsoft has a really easy tool to handle this out of the box, it’s called System Center Configuration Manager (both 2007 & 2012 Supports this method.).

To enable the inventory of addition Active Directory fields into the SCCM database it’s a simple as updating the Active Directory User Discovery method to include the scriptpath attribute.

1

This is accessible on the last tab of the “Active Directory User Discovery Properties” (2012 has the nice search function to ensure correct spelling 🙂 )

2

Run a full discovery on the Active Directory Users. Once the scan has completed you can check in the adusrdis.log file to confirm the agent has completed, we can now run the SQL query of (make sure you change the domain name to match your domain), go ahead I’ll wait:

SELECT user_name0,

user_Account_control0,

CASE user_Account_control0

WHEN ‘512’ THEN ‘Active Account’

WHEN ‘514’ THEN ‘Account Disabled’

WHEN ‘66048’ THEN ‘Password Does Not Expire’

WHEN ‘544’ THEN ‘does not require Password’

WHEN ‘590336’ THEN ‘Trusted for Delegation and Password does not expire’

WHEN ‘66050’ THEN ‘account disabled and does not require password’

WHEN ‘66080’ THEN’Password does not expire and password not required’

ELSE CAST(user_account_control0 as VARCHAR(20)) end as ‘Account Status’,  scriptPath0

FROM v_r_user

WHERE Windows_NT_Domain0=’domain7′

AND NOT user_account_control0 in (

‘66176’/* don’t expire password, emailed, encrypted text password allowed*/,

‘546’/* disabled, Password not required*/,

‘2080’/* Interdomain trust account, Password not required*/,

‘4260352’/* don’t require preauth, don’t expired password, enabled */)

ORDER BY [Account Status]

 Which returns something like this:

3

So we can capture a good amount of information by querying the database directly. The next step is to present it in a fashion that is useful for other staff, so let’s step through the process of putting this into a report.

Browse to your reporting site and if you don’t already have a folder for internal reports create one (keeps it neat and tidy) browse to the folder and select report builder. Once report builder opens select new report, table or matrix

4

And we are wanting to create a dataset

5

Browse for the system generate Data Source Connector, this is located under the configmgr_ folder on the SSRS server.

6

Enter your username & password that has access to the SQL database.

7

Select the edit as text option and paste the above query

8

We can now select how we present the information, if we want to put in a simple table it is a matter of adding all of the options into the values box like this:

9

Which will return a result something like below, which will give us a decent amount of information:

10

But we want to create a report that will allow for a glance to provide a count so we can select the options like this:

11

Which presents a result like this:

12

Which give us a place to start on how to clean up the logon scripts.

One thing to note is with SCCM 2012 the Active Directory User Discovery ignores disabled user objects, whereas SCCM 2007 would bring this information into the database to allow you to report on the information.

Obviously you can replace the scriptpath with almost any active directory user attribute to bring into the SCCM database, the common ones that I bring through include the phone numbers, address fields, title, and manager.

I hope this helps.

Good luck

Steve

SCCM 2012 Report Builder Certificate chain error

SCCM 2012 Report Builder Certificate chain error

So you have just installed SCCM 2012 R2 and found the awesome power of SQL Server Reporting Services, and you have given your managers access to the web site to allow them to access the information that they keep asking you about.

After a while you get complaints that not all of the information that they need is available via the website and they want the ability to be able to create their own reports on the website. So you delegate them access to create reports from the console and you go there desk to explain how SQL report builder works and then you get the following error: “The Certificate chain was issued by an authority that is not trusted” or looks like this.

1

You probably received the same error on your computer but you lived with it because we can just make the change on the server and it works.

So the course of this issue is this little option inside the saved connection

2

Ok cool we have identified the why, can’t we just change the TrustServerCertificate to equal true, this does work, for about 5-10 minutes before the SCCM system checks run and revert the setting back.

So to resolve this we just need to export the “ConfigMgr SQL Server Identification Certificate” from the SCCM server and import it onto each of the computers that you plan to have access to update/modify reports.

To do this first we need to export the Certificate from the SCCM server which is a matter of running the MMC console on the SCCM server

3

And adding the local computer certificate snapin

4

And browsing to the Personal Certificate Store

5

And exporting the highlighted certificate as DER

6

Now on the report builder machine we need to import the certificate to the Current User

7

Into the Trusted Root Certificate Authorities

8

Hit yes on the Security Warning

9

And go back to Report Builder and everything will be fixed.

10

Now you can create reports to you hearts content.

Good luck

Steve

Firefox Non-Admin install clean up

Firefox Non-Admin install clean up

So when we were rolling out our managed Windows 7 platform which we had spent a considerable amount of time planning and diligently removed local admin rights from all staff other than IT Staff (you know the guys cause the most issues with local admin, but I digress), I noticed one of our more IT savvy staff members installing the latest version of Firefox onto his computer. On prompting him that he was breeching our policy of installing software he laughed me off and said don’t worry about it, because if you hit no when the UAC prompt comes up you can still install it. To say I was a bit miffed would be an understatement, so I went and did some digging. It appears that Mozilla when they created the installation package they set it so if the user account being used to install doesn’t have access to Program Files it will install it into the user’s profile (c:\%username%\appdata\local\mozilla firefox\) to be precise, so short of black listing the installer every time there is a release there was little we could do.

Fast forward 18 months, 2 Building relocations and 2/3 of the fleet replaced with shiny new laptops to match the activity based working layout. We are finally getting time to sit down and do all of the feature adds that have been deemed nice to have, but not must haves. You know like the upgrade to SCCM 2012, along with a plan to deal with the browser sprawl that has occurred, since we rolled out Windows 7. Let face it the easiest way to combat this would be set up a Baseline in SCCM to detect when a browser other than the supported version of IE has been installed and remediate. But being well almost 2014 and embracing the whole empowerment of the users and all of that fun stuff, how can we set this up for self service, while cleaning up the legacy installs, the update process doesn’t handle the admin rights like the installer so we still have installs all the way back to version 9.

So I saw Sherry Kissinger’s post here which details how to disable the update process for Admin installs of Firefox, which is great and works really well. But it doesn’t handle our use case of per user installs of Firefox. So I had a quick look into the scripts that Sherry was using, and found that by adding in a looping function to step through the sub folders in c:\users looking for the Mozilla Firefox folder, and just created the files to disable the update process so the users don’t get prompted for updates that they can’t complete.

Disable updates of Per User install of Firefox Compliance Baseline

This got me thinking, can we use compliance settings to remediate the per user installs of Firefox, the short answer is yes, but it’s a little bit more complicated than using the remediation task in the compliance settings as we need to be able to install the latest version of Firefox. We can handle this by creating a device Collection using the following Query:

select SMS_R_SYSTEM.ResourceID, SMS_R_SYSTEM.ResourceType, SMS_R_SYSTEM.Name, SMS_R_SYSTEM.SMSUniqueIdentifier, SMS_R_SYSTEM.ResourceDomainORWorkgroup, SMS_R_SYSTEM.Client from SMS_R_System inner join SMS_G_System_CI_ComplianceState on SMS_G_System_CI_ComplianceState.ResourceId = SMS_R_System.ResourceId where SMS_G_System_CI_ComplianceState.LocalizedDisplayName = “FireFox Per User install” and SMS_G_System_CI_ComplianceState.ComplianceStateName = “Non-Compliant”

Of course this is after you have deployed the “FireFox Per User Install” configuration baseline to all of your computers. Then the remediation is as simple as creating an application to deploy to collection to run the attached script which will cycle through all of user profiles, and run the per user uninstall string of “c:\users\%username%\appdata\local\mozilla firefox\uninstall\helper.exe /s” and then clean up the Firefox shortcut for each of the user profiles. Once this is complete we can then execute an admin install of Firefox for the computer and disable the auto update process.

Identify Per user installs of Firefox Configuration Baseline

Good Luck

Steve

Extended Active Directory Attributes from Orchestrator

Extended Active Directory Attributes from Orchestrator

ADExtPublic OIP download

So we have just implemented a new VoIP Phone system and we found that on occasion we would get errors where disabled users object would still have the ipPhone attribute populated with a number that had been reassigned. To report back on this is pretty simple by using the SCCM user object discovery, but to how do we automate a solution to do something with the details. We ended up settling on using System Centre Orchestrator, as it allows us to be a little bit more flexible then a script.

So I got to work creating an OIP, and in the end I created 3 custom Activities, which are “”, “” and “” detailed below.

Obtain Custom Properties:

This one is quite simple in its use, you define the String Attibute for the user object that you want returned and it will return it.
Inputs:

Distinguished Name:  This is the Distinguished Name of the user.
Property Name: This is the name of the Attribute that you want returned.

Outputs:

Property result: This is the Value of the Attribute for the desired user.

Obtain ipPhone:

The result of this activity is the same as the Obtain Custom Properties activity, just hard set to the ipPhone attribute.

Inputs:

Distinguished Name:  This is the Distinguished Name of the user.

Outputs:

ipPhone: This is the Value of the ipPhone attribute for the desired user.

Remove ipPhone:

This Activity is a little more destructive, it will actually clear the ipPhone attribute for the defined user object.

Inputs:

Distinguished Name:  This is the Distinguished Name of the user.

Outputs:

IPPhone removal result: Result of “Success” or “did not exist”

As you can see below the scripts for this OIP is pretty simple.

ADUserExtended.cs

using Microsoft.SystemCenter.Orchestrator.Integration;namespace ADUserExtended
{
[Activity(“Obtain Custom Properties”)]
public class ADExtendedCustProp
{
private string usercust;
[ActivityInput(“Distingished Name”)]
public string Usercust
{
set { usercust = value; }
}
private string propname;
[ActivityInput(“Property Name”)]
public string Propname
{
set { propname = value; }
}
[ActivityOutput(“Property result”)]
public string PropResult
{
get { return defineProp.getcustprop(usercust, propname); }
}
}
[Activity(“Obtain ipPhone”)]
public class ADExtendedipPhone
{
private string userip;
[ActivityInput(“Distingished Name”)]
public string Userip
{
set
{
userip = value;
}
}
[ActivityOutput(“ipPhone”)]
public string IPPhone
{
get { return checkphone.GetIPphone(userip); }
}
}
[Activity(“Remove ipPhone”)]
public class ADExtendedremove
{
private string userrem;
[ActivityInput(“Distingished Name”)]
public string Userrem
{
set
{
userrem = value;
}
}
[ActivityOutput(“IPPhone removal result”)]
public string IPPhonerem
{
get { return removeipPhone.remIPphone(userrem); }
}
}
}

 DefineProps.cs

using System.DirectoryServices;namespace ADUserExtended
{
class defineProp
{
public static string getcustprop(string userId, string Propname)
{
using (var userEntry = new DirectoryEntry(@”LDAP://” + userId))
{
if (userEntry.Properties.Contains(Propname))
{
return userEntry.Properties[Propname][0].ToString();
}
else
{
return “did not exist”;
}
}
}
}
}

CheckPhones.cs

using System.DirectoryServices;namespace ADUserExtended
{
public class checkphone
{
public static string GetIPphone(string userId)
{
using (var userEntry = new DirectoryEntry(@”LDAP://” + userId))
{
if (userEntry.Properties.Contains(“ipPhone”))
{
return userEntry.Properties[“ipPhone”][0].ToString();
}
else
{
return string.Empty;
}
}
}
}
}

RemoveipPhone.cs

using System.DirectoryServices;namespace ADUserExtended
{
class removeipPhone
{
public static string remIPphone(string userId)
{
using (var userEntry = new DirectoryEntry(@”LDAP://” + userId))
{
if (userEntry.Properties.Contains(“ipPhone”))
{
userEntry.Properties[“ipPhone”].Clear();
userEntry.CommitChanges();
userEntry.Close();
return “success”;
}
else
{
return “did not exist”;
}
}
}
}
}

Good Luck

Steve

How to update BIOS on laptops that have Bitlocker Encrypted drives.

How to update BIOS on laptops that have Bitlocker Encrypted drives.

Download Script from here(updateBios)

Completing an unattended update of computers BIOS was something I never thought I would be championing but with hardware vendors now releasing updates every other month which include performance and stability fixes we have been forced into investigating how to complete this.

So my initial plan was to finally get SCUP up and running and then utilise the BIOS updates that are included in the HP pack. This was great for our desktops and laptops that a.) didn’t have a BIOS password, and b.) didn’t have BitLocker enabled.

So from here we needed to come up with a different route, that could handle bother the BIOS password and BitLocker, what also needed to be taking into consideration is to check to make sure the laptop has AC power connected, as most vendors have put safe guards in place to stop BIOS installing if not connected. Along with the re-enablement of BitLocker encryption after the BIOS has been updated.

So lets get into the code, for simplicity it is all written in vbs, and has been tested on Windows 7 & 8. Below is a break down of the Sub Routines & Functions.

Application Execution

sn = wscript.scriptname ' gets the script name
fn = wscript.scriptfullname 'gets the scripts full UNC Path
fp = replace(fn, "\" & sn, "") 'provides the path of all of the files.
Set objShell = WScript.CreateObject("WScript.Shell")
opt = WScript.Arguments.Item(0) 'returns the Argument that has been entered in at script calling.

if opt = "flash" then 'is the option to Flash turned on
 if power then 'is Power Attached?
  manageBDE ("disable") 'Suspend BitLocker Drive Encryption
  install (fp & "\hpqflash.exe -s -p" & fp & _
   "\pwfile.bin") 'Call the HP Flash applicaiton - Change this to match your Vendor
  writekey "SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" _
  , "ReenableBDE", fn & " encrypt" 'Create regkey to unsuspend BDE after reboot
  install ("c:\windows\system32\shutdown.exe -r -f -t" _ 
  " 600") 'Restart the computer change the timeout to match you need
 end if
elseif opt = "encrypt" then 'is the option to encrypt?
 manageBDE ("enable") 'unsuspend BDE
elseif opt = "/?" then
 wscript.echo "Usage of script, to kick off Flashing" _ 
 " call script with the argument "& chr(34) & "Flash" & chr(34)
end if

This is the code that is used to call the Sub-Routines & Functions detailed below.

Checking the AC:

'#################################################
' Function Name: power
' Outputs:
' power (boolen) = TRUE means power is plugged in,
'             FALSE means power it not plugged in
'#################################################
function power
 Set objWMIService = GetObject("winmgmts:\\.\root\wmi")
 Set colItems = objWMIService.ExecQuery("Select *" _
 " From BatteryStatus Where Voltage > 0")
 For Each objItem in colItems
  if objItem.Discharging = FALSE then
   'wscript.echo "AC plugged in"
   power = true

  else
   'wscript.echo "AC NOT plugged in"
   power = false
  end if
 Next
end function

The reason why we use Discharging rather then Charging is that we found if the Laptop was fully charged it would return that it wasn’t charging, but if the AC was plugged in, the laptop isn’t discharging (have a think about it and it makes sense).

Manage BDE (BitLocker Drive Encryption)

'#################################################
' Routine Name: manageBDE
' Inputs:
' switch (String) = options are "Enable" or "Disable"
' checks to see if BitLocker is enabled and if it is it will 
' Suspend if required. it will also report the various 
' states with different exit codes as listed in the script.
'#################################################
sub manageBDE(switch)
 dim nProtStatus, intRC
 strConnectionStr2 = "winmgmts:{impersonationLevel=impersonate," _
    "authenticationLevel=pktPrivacy}!root\cimv2\Security\" _
    "MicrosoftVolumeEncryption"
 Set objWMIBDE = GetObject(strConnectionStr2)
 Set colEnVol = objWMIBDE.ExecQuery("Select * from" _
    " Win32_EncryptableVolume")
 if colEnVol.count > 0 then
  For Each objEnVol in colEnVol
   if objEnVol.DriveLetter = "C:"  then
    intRC = objEnVol.GetConversionStatus(nProtStatus)
    if switch = "disable" then
     select case nProtStatus
     case 0 'fully decrypted
      wscript.quit 663
     case 1 'fully encrypted
      objShell.Run ("c:\windows\system32\manage-bde.exe" _
      " -protectors -disable C:")
     case 2 'Encryption in Progress
      wscript.quit 665
     case 3 'Decryption in progress
      wscript.quit 666
     case 4 'Encryption Paused

     case 5 'Decryption Paused
      wscript.quit 664
     end select

    elseif switch = "enable" then
     select case nProtStatus
     case 0 'fully decrypted
      wscript.quit 663
     case 1 'fully encrypted
      objShell.Run ("c:\windows\system32\manage-bde.exe" _
      " -protectors -disable C:")
      objShell.Run ("c:\windows\system32\manage-bde.exe" _
      " -protectors -enable C:")
     case 2 'Encryption in Progress
      wscript.quit 665
     case 3 'Decryption in progress
      wscript.quit 666
     case 4 'Encryption Paused
      objShell.Run ("c:\windows\system32\manage-bde.exe" _
      " -protectors -enable C:")
     case 5 'Decryption Paused
      wscript.quit 664
     end select
    end if
   end if
  next
 end if
end sub

We ended up using the GetProvisionStatus rather then the GetEncryptionStatus option for this solution to be able to handle if the hard drive is currently in the process of being encrypted, for example when a system is recently been built. When using GetEncryptionStatus WMI reported correctly that BDE was enabled, it just didn’t report that it was currently being encrypted.

Install Sub Routine

'#################################################
' Routine Name: install
' Inputs:
' exestring (string) = command you want to call.
' this Routine will start an application and wait
' until the application has stopped before moveing
' on to the next task in the script. useful for 
'applications that close automaticly with exit code 0
'#################################################
sub install(exestring)
 running = 1
 strComputer = "."
 strCommand = exestring
 Set objWMIService = GetObject("winmgmts:" _ 
 "{impersonationLevel=impersonate}!\\" & strComputer _
 & "\root\cimv2")
 Set objProcess = objWMIService.Get("Win32_Process")
 errReturn = objProcess.Create(strCommand, null, null, _
 intProcessID)
 If errReturn = 0 Then
  'wscript.echo exestring & " : " & intprocessid
  do while running = 1
   Set objProcess = objWMIService.execquery("select *" _
   " from Win32_Process")
   for each objproc in objprocess
    if objproc.processid = intprocessid then
     running = 1
     exit for
    else
     running = 0
    end if
   next
  loop
 Else
 End If
end sub

This routine is something I wrote a few years back to deal with those awesome applications that report exit code 0 immediately on execution for the application. (contact me if you need a routine to handle an executable inside an executable….)

Write RegKey

'#################################################
' Routine Name: WriteKey
' Inputs:
' key (string) = this is the path to the key to update
' vn (string) = this is the new Value name
' v (string) = this is the new Value
' Creates a DWORD value at the KEY path.
'#################################################
sub writekey(key,vn,v) 
 const HKEY_LOCAL_MACHINE = &H80000002
 Set oReg=GetObject("winmgmts:" _
 "{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
 oReg.SetStringValue HKEY_LOCAL_MACHINE,key,vn,v
end sub

This writes a DWORD into the registry in this script we use it to handle the re-enablement of BDE after a restart.

One thing to note is that to complete the HP Bios update from the command line you are required to create a pwfile.bin file by using this application http://ftp.hp.com/pub/caps-softpaq/cmit/softpaq/sp62065.exe when installing the application it displays as HP ElitePad 900 from my experience this file will work for all HP Laptops that utilise the HPQFlash application

I think that pretty much covers it off, we have successfully tried this on multiple HP laptop models to great success.

Good Luck

Steve