Tuesday, May 27, 2008

Powershell WMI one-liners

The PowerShell WMI capability is quite advanced and provides a vast scope for processing a returned recordset easily and effectively.

Here are just three types of Powershell WMI calls using different namespaces.

Return details about a service
get-wmiobject win32_service -filter "name='alerter'"

Return a users first name from Active Directory
(Get-WmiObject -namespace "root\directory\ldap" -class ds_user -filter "ds_Cn='[UserID]'").DS_givenname

Return details about a specified SMS package
Get-WmiObject -computer [SMSServer] -namespace root\sms\site_[SiteCode] -Query "SELECT * FROM SMS_Package WHERE PackageID='[PackageID]'"

Installing device drivers without the device being present

Having completed a number of SOE unattended installations, I have had reason to be able to install device drivers without the device being present. Attempts to install drivers without the device present using well known driver installation tools such as devcon.exe and dpinst.exe, failed to load the device drivers.

During investigation of the process I reviewed the device installation log file, %SystemRoot%\setupapi.log. In hindsight, the log file is quite aptly named in that functions within the setupapi.dll are called to install devices during windows setup and driver installation programs. This was shown by log entries from the devcon and dpinst programs.

Searches for setupapi.dll eventually showed that the SetupCopyOEMInf function is used to install the devices. Which in turn led to Pyron's SetupCopyOEMInf.exe utility. Whilst the utility is fantastic and performs device installation flawlessly, I was after something that could be manipulated if required.

Enter Powershell!

Utilising managed API calls, I was able to write a powershell script that calls the SetupCopyOEMInf function whilst maintaining the flexibility that scripting offers. Whilst by no means the right solution for everyone, this approach further demonstrates the capabilities of powershell.

In summary, the script installs the device drivers without the device being present.

During a standard user session, the device can be plugged in and the device drivers are loaded without prompting for Administrator credentials.

[string] $DriverDir = $(throw "Please specify a directory of drivers to process")

$Scripts = Split-Path $Myinvocation.Mycommand.Path
# Copy a Driver to the OEM path (Install driver without the device being present)
# References
# http://monadblog.blogspot.com/2005/12/calling-win32-api-functions-through.html
# http://www.pinvoke.net/default.aspx/setupapi.SetupCopyOEMInf
# Set Error Handling
$ErrorActionPreference = "SilentlyContinue"
$Me = "SetupCopyOEMInf"
$provider = new-object Microsoft.VisualBasic.VBCodeProvider

$params = new-object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
# Find all the .inf files in the specified directory

$TaskDesc = "Locate INF Files"
$TempDir = Get-ChildItem $DriverDir -filter '*.inf' -recurse
If ($? -eq $False) {
Write-Host "Invalid directory $($DriverDir)"
Exit 1

$txtCode = @'
Class CopyOEMInf
Private Declare Function SetupCopyOEMInf Lib "setupapi.dll" Alias "SetupCopyOEMInfA" (ByVal SourceInfFileName As String, ByVal OEMSourceMediaLocation As String, ByVal OEMSourceMediaType As Long, ByVal CopyStyle As Long, ByVal DestinationInfFileName As String, ByVal DestinationInfFileNameSize As Long, ByRef RequiredSize As Long, ByVal DestinationInfFileNameComponent As String) As Long

Public Function Main(ByVal sInf As String, ByVal sDir As String) As Long
Const SP_COPY_NEWER As Integer = &H4
Dim lngResult As Long

Dim ret2 As String
Dim ret3 As String

' Install the driver'
lngResult = SetupCopyOEMInf(sInf, sDir, 1, SP_COPY_NEWER, ret2, 255, 255, ret3)
End Function
end class


$cr = $provider.CompileAssemblyFromSource($params, $txtCode)
if ($cr.Errors.Count) {
$codeLines = $txtCode.Split("`n");

foreach ($ce in $cr.Errors) {
Write-Host "Code compilation error, line $($ce.Line - 1)"
write-host "Error: $($codeLines[$($ce.Line - 1)])"
write-host $ce
Throw "INVALID DATA: Errors encountered while compiling code"

$mAssembly = $cr.CompiledAssembly

$i = $mAssembly.CreateInstance("CopyOEMInf")
# Process each inf file found

$TempDir ¦ foreach {
Write-Host "Installing Driver $($_.Get_FullName().ToString())"

$r = $i.Main($_.Get_FullName().ToString(), $_.Get_Directory().ToString())

Troubleshooting Device Installation with the SetupAPI Log File
Pyron setupcopyoeminf

Thanks goes to Wayne for introducing the concept and code snippets for compiling managed code from unmanaged scripts.

Friday, May 23, 2008

Effective permissions may be reported incorrectly


Using a Domain member computer, the "Advanced / Effective Permissions"
tab is used to evaluate permissions for specific user on a folder.

In this example,
\\[Server]\[Share]\[Folder] and the user specified is a member of the local Administrators group on the Domain Member computer. The "effective permissions"
tab reports that the user holds Full Control for the folder.

Member computers of a domain are only able to perform group expansion for Built-in groups locally. Thus when the account context is evaluated the Built-In\Administrators membership is returned.

Universally, the SID for Builtin\Administrators is S-1-5-32-544, which cannot be distinguished between the local computer group membership and local server group membership by the "Effective Permissions" tab.

More Information
Permissions for user accounts that are not members of the local computer Administrators group are not affected by this issue.

This issue does not occur if the computer used to evaluate permissions is a domain controller or the server hosting the resource.

Access control lists may report incorrect information in Windows Server

MDT 2008 Storage Drivers - 0x0000007B error

I have been testing the MDT 2008 capability to automatically insert mass storage drivers into the unattend.txt and sysprep.inf, and have found that the implementation of the feature does not appear to be working as expected.

The two scripts ZTIStorageDrivers.wsf and ZTIStorageDriversSysprep.wsf seem to enumerate the driver database correctly and make modifications to the appropriate unttend build file (unattend.txt / sysprep.inf), but upon reboot the workstation fails with the 0x0000007B error.

After a number of attempts to get the feature to work it was evident that something was fundamentally wrong with the process. A google search for ZTIStorageDrivers.wsf uncovered a blog post by Michael Niehaus, who is reportedly involved with the MS deployment team.

After following the tip for including the HDC class into the ZTIStorageDriversSysprep.wsf script, the script failed with the same error (32811) as the blog respondent received.

It would seem that until Microsoft release a fix for the bug, we should continue with the practice of hand-crafting the txtsetup.oem / sysprep.inf files.

Once a working hot fix is released I see great benefit in adopting the mechanism to reduce the turnaround time in delivering support for new hardware with new mass storage drivers.


Monday, May 19, 2008

NVIDIA Screen resolution resets


Each time a user without administrative privileges logs on to a workstation the screen resolution is set to the maximum capable resolution.


The NVIDIA Display Driver Service (NVSvc) inserts the "NvCplDaemon" run key in the machine startup Run key.


The key executes the command "RUNDLL32.EXE C:\\WINDOWS\\system32\\NvCpl.dll,NvStartup",
which is responsible for setting the screen resolution to the highest capable resolution.


Disable the NVIDIA Display Driver service and remove the run key.
This may be achieved from the command line with the following commands;

\\[ComputerName] config NVSvc startup= disabled
Reg delete \\[ComputerName]\HKLM\Software\Microsoft\Windows\CurrentVersion\Run /v NvCplDaemon

Thursday, May 15, 2008

Mandatory ZTI advertisement does not run

When a workstation is built using OSD, the SMS Package and Program are flagged as being executed on the SMS client. This prevents any future mandatory ZTI advertisements from executing. Thus when an automated Computer refresh is undertaken, the refresh may not run.

This workaround specifically relates to ZTI deployments, however, the principals would apply to an SMS Advertisement that requires re-running without modification of the client Execution History.

The SMS Client flags the Package and Program has having been previously executed and checks the following registry location when a request to run the Package is received.

HKEY_LOCAL_MACHINE\Software\Microsoft\SMS\Mobile Client\Software Distribution\Execution History\System\[PackageID]\[ExecutionGUID]

If an entry exists for the Package and Program, a message is logged in the ExecMgr.log file, stating that the program cannot be run as it is prevented by policy.

Microsoft reports this as behaviour by design.


Add a second Mandatory Assignment for the actual desired deployment time. This triggers the client to execute the SMS recurring advertisement code and re-runs the advertisement.

To automate a ZTI deployment, I created a new advertisement, added a dummy mandatory assignment time, then a second mandatory assignment for the desired deployment time.


With regards to what I have referred to as the ExecutionGUID, I have been unable to find a definitive description of what this part of the registry key entails. So I put forth my description of the entry.

It appears to be a dynamically generated GUID for a unique representation of this execution of the Package/Program on an individual client. This is contrary to Microsoft's description in KB829853 which suggests it is related to the program.

My investigations and testing this showed that the GUID was indeed different for the same Package / Program on different clients.

Checks of the program GUID using the SMS Console "Node Information" tab, with the /sms:nodeinfo=1 switch enabled, showed the Program to have a different GUID to the one listed in the aforementioned registry location.

SMS: Client Does Not Run New Advertisement of the Same Package and Program

Advertisements are run again if you upgrade a Systems Management Server 2.0 client to a Systems Management Server 2003 advanced client

Wednesday, May 14, 2008

You receive message "Please wait while the domain list is created" when changing the "Log on to" field

You receive message "Please wait while the domain list is created" when changing the "Log on to" field.

This message can occur when Sysprep is run on a machine, and a new name is entered for the machine.

The registry contains the DefaultDomainName and AltDefaultDomainName registry keys with the AltDefaultDomainName field containing the value of the old machine name.

When the "Log on to" field is modified Windows attempts to verify the domain as listed in the AltDefaultDomainName field.

A machine is built with the name "Workstation1"

During the Sysprep mini-setup wizard a different name is entered for the workstation, "Workstation2".

The value of HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon /v AltDefaultDomainName is still set to the original workstation, "Workstation1".

Enter CTL+ALT+DEL again to remove the message and enter your credentials and logon to the workstation or domain.
This sets the AltDefaultDomainName to the logged on domain.

Wednesday, May 7, 2008

Decrypt / Encrypt string in ROT-13

' Converts a string from ROT13
Const Alpha_Upper = "abcdefghijklm" ' First 13 letters

Const Alpha_Lower = "nopqrstuvwxyz" ' Second 13 letters
Dim aAlpha, aStringDim iDim sROT13, sFullROT13

aAlpha = Split(Alpha, ",")
sString = Wscript.Arguments(0)

For i = 1 to Len(sString)
  iPos = InStr(Alpha_Upper, LCase(Mid(sString, i, 1)))
  If iPos > 0 Then ' Found in upper so return corresponding lower character
    sROT13 = Mid(Alpha_Lower, iPos, 1)
    iPos = InStr(Alpha_Lower, LCase(Mid(sString, i, 1)))
    If iPos > 0 Then
      sROT13 = Mid(Alpha_Upper, iPos, 1)
      sROT13 = Mid(sString, i, 1) ' Not an alphabetic character, so just return the supplied character
    End If
  End If

  sFullRot13 = sFullRot13 & sROT13

Wscript.Echo sFullROT13

Understanding the Most Frequently Used (MFU) registry key

Have you ever wondered what the gibberish in the MFU key is? These are the items that get populated dynamically in the start menu when you click on an item.

Analysing the key shows some not so obvious items. They are in fact filepath / filename pairs to the files initiated from the start menu.

For some reason Microsoft felt the need to encrypt the entries, presumably from prying eyes. The question I am unable to answer is why?

Anyway the encryption MS chose is a rather simple key substition named ROT-13. Simply, if the alphabet is number 1-26 with A =1, take a character and add 13 to it. For letters toward the end of the alphabet add up to 26, then start at 1.

With scripting this I used an alternate method that was easier to code, see my reference at the bottom of this post for the decrypt rot-13 script.


HRZR_EHAPCY REG_BINARY 0100000006000000A04C12589864C801
HRZR_EHACNGU REG_BINARY 010000001300000020E6A157DE66C801
HRZR_EHACVQY REG_BINARY 010000000D00000080DE7657DE66C801
HRZR_EHACNGU:P:\JVAQBJF\flfgrz32\gbhefgneg.rkr REG_BINARY
HRZR_EHACNGU:P:\Cebtenz Svyrf\Jvaqbjf Zrqvn Cynlre\jzcynlre.rkr
REG_BINARY 01000000000000000000000000000000
HRZR_EHACNGU:P:\Cebtenz Svyrf\Vagrearg Rkcybere\vrkcyber.rkr
REG_BINARY 010000000A00000000B43246DE66C801
HRZR_EHACVQY:::{2559N1S4-21Q7-11Q4-OQNS-00P04S60O9S0} REG_BINARY
HRZR_EHACVQY:%pfvqy2%\Vagrearg Rkcybere.yax REG_BINARY
HRZR_EHACVQY:%pfvqy2%\Nqbor Ernqre 8.yax REG_BINARY
HRZR_EHACNGU:P:\Cebtenz Svyrf\Nqbor\Ernqre 8.0\Ernqre\NpebEq32.rkr
REG_BINARY 010000000600000020E6A157DE66C801
HRZR_EHACNGU:{NP76ON86-7NQ7-1033-7O44-N81000000003} REG_BINARY


ueme_runcpl ert_ovanel
ueme_runpath:c:\program files\windows media player\wmplayer.exe ueme_runpath:c:\windows\explorer.exe
ueme_runpath:c:\program files\internet explorer\iexplore.exe

ueme_runpidl:%csidl2%\internet explorer.lnk ueme_runpidl:%csidl2%\adobe reader 8.lnk ueme_runpath:c:\program files\adobe\reader 8.0\reader\acrord32.exe


Decrypt / Encrypt string using ROT-13 Encryption

Friday, May 2, 2008

Windows XP reboots during setup

During an unattended setup of Windows XP, the system reboots at T-30 when configuring the network.

One cause of this issue is that a duplicate name exists on the network.

Remove the name conflict by either shutting down the existing computer or renaming the computer you are performing an unattended build on.