<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Decrypt my World : VBScript</title><link>http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx</link><description>Tags: VBScript</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>How to get LastLogon property for all users in a Domain (VBScript)</title><link>http://blogs.msdn.com/alejacma/archive/2009/03/12/how-to-get-lastlogon-property-for-all-users-in-a-domain-vbscript.aspx</link><pubDate>Thu, 12 Mar 2009 13:05:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9471522</guid><dc:creator>alejacma</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9471522.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9471522</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;VBScript sample &lt;/STRONG&gt;retrieves &lt;STRONG&gt;all users in Active Directory that haven't ever logged on the domain, or haven't logged on for at least maxDays &lt;/STRONG&gt;(an argument passed to the script):&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;On Error Resume Next

' Constants
'
Const ONE_HUNDRED_NANOSECOND = .000000100
Const SECONDS_IN_DAY = 86400

' Get Max Days as an argument passed to the script
'
If Not Wscript.Arguments.Count() = 1 Then
  Wscript.Echo "Syntax error, argument required"
  Wscript.Quit
End If

maxDays = CInt(Wscript.Arguments(0))

' Create the log file
'
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objLogFile = objFSO.CreateTextFile(GetPath() &amp;amp; "log.txt", 8, true)

' Get the root of the domain
'
Set objRoot = Getobject("LDAP://RootDSE")
strRoot = objRoot.Get("defaultnamingcontext")
Set objRoot = Nothing

' Create connection
'
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"

' Create command
'
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000

' Execute command to get all DCs in the domain
'
objCommand.CommandText = "&amp;lt;LDAP://OU=Domain Controllers," &amp;amp; strRoot &amp;amp; "&amp;gt;;(objectcategory=computer);name;onelevel"
Set objRecordSet = objCommand.Execute

'LogData("INFO: There are " &amp;amp; objRecordSet.RecordCount &amp;amp; " Domain Controllers.")

' Execute command to get all users in the domain
'
objCommand.CommandText = "&amp;lt;LDAP://" &amp;amp; strRoot &amp;amp; "&amp;gt;;(&amp;amp;(objectclass=user)(objectcategory=person));adspath,distinguishedname,sAMAccountName;subtree"
Set objRecordSet2 = objCommand.Execute

'LogData("INFO: There are " &amp;amp; objRecordSet2.RecordCount &amp;amp; " users.")

' Get the LastLogon for each user in each DC
'
Do Until objRecordSet2.EOF

  ' Get the LastLogon for one user in each DC, and get the maximum
  '
  objRecordSet.MoveFirst
  maxDate = 0
  Do Until objRecordSet.EOF

    ' Execute command to get LastLogon for the user in one DC
    '
    LdapPath = "LDAP://" &amp;amp; objRecordSet.Fields("name").Value &amp;amp; "/" &amp;amp; Replace(objRecordSet2.Fields("distinguishedname").Value, "/", "\/")
    set objUser = GetObject(LdapPath)

    ' Check for errors executing the command
    '
    if Err.Number &amp;lt;&amp;gt; 0 Then
      ' Error
      '
      LogData("INFO: LDAP Path = " &amp;amp; LdapPath)
      Select Case Err.Number
        Case &amp;amp;H8007203A
          Err.Description = """The server is not operational"""
        Case &amp;amp;H80005000
          Err.Description = """An invalid ADSI pathname was passed"""
        Case Else
          Err.Description = ""
      End Select 
      LogData("ERROR: " &amp;amp; Err.Number &amp;amp; " " &amp;amp; Err.Description)
    Else
      ' No error
      '
      ' Get the LastLogon
      '
      set objLastLogon = objUser.LastLogon
      myDate = 0
      If Not(IsNull(objLastLogon) Or IsEmpty(objLastLogon)) Then
        myDate = MakeDate(objLastLogon)
      End If

      ' See if it's the maximum
      '
      If myDate &amp;gt; maxDate Then
        maxDate = myDate
      End If

    End If

    ' Move on to the next DC
    '
    Err.Clear
    set objUser = nothing
    set objLastLogon = nothing
    objRecordSet.MoveNext

  Loop

  ' Show the maximum LastLogon for the user
  '
  If maxDate = 0 Then
    LogData("INFO: User """ &amp;amp; objRecordSet2.Fields("sAMAccountName").Value &amp;amp; """ never logged on.")
  ElseIf (Date() - maxDate) &amp;gt; maxDays Then 
    LogData("INFO: User """ &amp;amp; objRecordSet2.Fields("sAMAccountName").Value &amp;amp; """ logged on " &amp;amp; maxDate)
  End If

  ' Move on to the next user
  '
  objRecordSet2.MoveNext

Loop


' Close everything
'
objRecordSet.Close
Set objRecordSet = Nothing
objRecordSet2.Close
Set objRecordSet2 = Nothing
Set objCommand = Nothing
objConnection.Close
Set objConnection = Nothing

' We are done!
'
Wscript.Echo "All Done!"


'================================================================
' HELPER FUNCTIONS
'================================================================

' Get script's path
'
Function GetPath()

  Dim path
  path = WScript.ScriptFullName
  GetPath = Left(path, InStrRev(path, "\"))

End Function


' Write data to log file
'
Sub LogData(data)

  objLogFile.writeline Now() &amp;amp; ", " &amp;amp; data

End Sub


' Convert long integer to a date
'
Function MakeDate(oLInt)

  Set objShell = CreateObject("Wscript.Shell")

  lngBiasKey = objShell.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias")

  If UCase(TypeName(lngBiasKey)) = "LONG" Then
    glngBias = lngBiasKey

  ElseIf UCase(TypeName(lngBiasKey)) = "VARIANT()" Then
    glngBias = 0

    For k = 0 To UBound(lngBiasKey)
      glngBias = lngBias + (lngBiasKey(k) * 256^k)
    Next
  End If 

  dtmDate = #1/1/1601# + (((oLInt.HighPart * (2 ^ 32)) + oLInt.LowPart) / 600000000 - glngBias) / 1440

  MakeDate = dtmDate

End Function
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9471522" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/ADSI/default.aspx">ADSI</category></item><item><title>How to sign EXE files with an Authenticode certificate (part 2)</title><link>http://blogs.msdn.com/alejacma/archive/2008/12/11/how-to-sign-exe-files-with-an-authenticode-certificate-part-2.aspx</link><pubDate>Thu, 11 Dec 2008 12:59:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9196078</guid><dc:creator>alejacma</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9196078.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9196078</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;The other day a customer of mine was having an &lt;STRONG&gt;issue&lt;/STRONG&gt; with &lt;STRONG&gt;SignTool.exe&lt;/STRONG&gt; when &lt;STRONG&gt;signing&lt;/STRONG&gt; an &lt;STRONG&gt;EXE&lt;/STRONG&gt; file. The EXE file was getting &lt;STRONG&gt;corrupted&lt;/STRONG&gt;/unusable after signing it.&lt;/P&gt;
&lt;P&gt;When troubleshooting this issue, I had the chance to play a bit more&amp;nbsp;with SignTool and check what it does behind the scenes. &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Note: I already talked a bit about signing EXEs in post &lt;/EM&gt;&lt;A class="" href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx" mce_href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx"&gt;&lt;EM&gt;How to sign EXE files with an Authenticode certificate (VB.NET)&lt;/EM&gt;&lt;/A&gt;&lt;EM&gt;. This new post will add more details and samples.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;SignTool.exe&lt;/STRONG&gt; uses &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa387712(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa387712(VS.85).aspx"&gt;CAPICOM.SignedCode&lt;/A&gt; class and its &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa387717(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa387717(VS.85).aspx"&gt;Sign&lt;/A&gt; method to do the signing.&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;VBScript&lt;/STRONG&gt; shows how we may use &lt;STRONG&gt;CAPICOM&lt;/STRONG&gt; to do the signing programmatically:&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;Option Explicit

Dim szCertName, szExeToSign
szCertName = "My cert Subject"
szExeToSign = "MyApplication.exe"

Const CAPICOM_CURRENT_USER_STORE = 2
Const CAPICOM_STORE_OPEN_READ_ONLY = 0
Const CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1
Const CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION = 2

' Get certificate for signing
'
Dim objStore
Set objStore = WScript.CreateObject("&lt;STRONG&gt;CAPICOM.Store&lt;/STRONG&gt;")
objStore.Open CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY
Dim objSigningCert
Set objSigningCert = objStore.&lt;STRONG&gt;Certificates.Find&lt;/STRONG&gt;(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, szCertName).Item(1)

' Create a signer for the code
'
Dim objSigner
Set objSigner = WScript.CreateObject("&lt;STRONG&gt;CAPICOM.Signer&lt;/STRONG&gt;")
objSigner.&lt;STRONG&gt;Certificate&lt;/STRONG&gt; = objSigningCert

' Sign the file
'
Dim objSignedCode
Set objSignedCode = WScript.CreateObject("&lt;STRONG&gt;CAPICOM.SignedCode&lt;/STRONG&gt;")
objSignedCode.&lt;STRONG&gt;FileName&lt;/STRONG&gt; = szExeToSign
objSignedCode.&lt;STRONG&gt;Sign&lt;/STRONG&gt; objSigner
objSignedCode.&lt;STRONG&gt;TimeStamp&lt;/STRONG&gt; "http://timestamp.globalsign.com/scripts/timstamp.dll"

WScript.Echo "Done!"
&lt;/PRE&gt;
&lt;P&gt;Note that&amp;nbsp;this sample also shows how to &lt;STRONG&gt;time stamp a signature&lt;/STRONG&gt; programmatically.&lt;/P&gt;
&lt;P&gt;This sample was also reproducing my customer's issue. So&amp;nbsp;I checked what CAPICOM does behind the scenes to further troubleshoot the issue.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;CAPICOM.SignedCode.Sign&lt;/STRONG&gt; uses &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa380292(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa380292(VS.85).aspx"&gt;CryptUIWizDigitalSign&lt;/A&gt; API to do the signing. &lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;VB.NET &lt;/STRONG&gt;sample uses &lt;STRONG&gt;CryptUIWizDigitalSign &lt;/STRONG&gt;through &lt;STRONG&gt;P/Invoke&lt;/STRONG&gt; to do the signing programmatically:&lt;/P&gt;&lt;PRE&gt;&amp;lt;SAMPLE file="Crypto.vb"&amp;gt;

Imports System.Runtime.InteropServices
Imports System.Security.Cryptography
Imports System.ComponentModel
Imports System.Windows.Forms

Public Class Crypto

    ' #define CRYPTUI_WIZ_NO_UI     1
    Public Const &lt;STRONG&gt;CRYPTUI_WIZ_NO_UI&lt;/STRONG&gt; As Int32 = 1

    ' #define CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE     0x01
    Public Const &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE&lt;/STRONG&gt; As Int32 = 1

    ' #define CRYPTUI_WIZ_DIGITAL_SIGN_CERT                    0x01
    Public Const &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_CERT&lt;/STRONG&gt; As Int32 = 1

    ' typedef struct _CRYPTUI_WIZ_DIGITAL_SIGN_INFO {  
    '   DWORD dwSize;  
    '   DWORD dwSubjectChoice;  
    '   union {    
    '       LPCWSTR pwszFileName;    
    '       PCCRYPTUI_WIZ_DIGITAL_SIGN_BLOB_INFO pSignBlobInfo;  
    '   };  
    '   DWORD dwSigningCertChoice;  
    '   union {    
    '       PCCERT_CONTEXT pSigningCertContext;    
    '       PCCRYPTUI_WIZ_DIGITAL_SIGN_STORE_INFO pSigningCertStore;    
    '       PCCRYPTUI_WIZ_DIGITAL_SIGN_CERT_PVK_INFO pSigningCertPvkInfo;  
    '   };  
    '   LPCWSTR pwszTimestampURL;  
    '   DWORD dwAdditionalCertChoice;  
    '   PCCRYPTUI_WIZ_DIGITAL_SIGN_EXTENDED_INFO pSignExtInfo;
    ' } CRYPTUI_WIZ_DIGITAL_SIGN_INFO;
    &amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
    Public Structure &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_INFO&lt;/STRONG&gt;
        Public dwSize As Int32
        Public dwSubjectChoice As Int32
        &amp;lt;MarshalAs(UnmanagedType.LPWStr)&amp;gt; Public pwszFileName As String
        Public dwSigningCertChoice As Int32
        Public pSigningCertContext As IntPtr
        Public pwszTimestampURL As String
        Public dwAdditionalCertChoice As Int32
        Public pSignExtInfo As IntPtr
    End Structure

    ' typedef struct _CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT {  
    '      DWORD dwSize;  
    '      DWORD cbBlob;  
    '      BYTE* pbBlob;
    ' } CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT;
    &amp;lt;StructLayout(LayoutKind.Sequential)&amp;gt; _
    Public Structure &lt;STRONG&gt;CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT&lt;/STRONG&gt;
        Public dwSize As Int32
        Public cbBlob As Int32
        Public pbBlob As IntPtr
    End Structure

    ' BOOL WINAPI CryptUIWizDigitalSign(
    '      DWORD dwFlags,
    '      HWND hwndParent,
    '      LPCWSTR pwszWizardTitle,
    '      PCCRYPTUI_WIZ_DIGITAL_SIGN_INFO pDigitalSignInfo,
    '      PCCRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT* ppSignContext
    ' );
    &amp;lt;DllImport("Cryptui.dll", CharSet:=CharSet.Unicode, SetLastError:=True)&amp;gt; _
    Public Shared Function &lt;STRONG&gt;CryptUIWizDigitalSign&lt;/STRONG&gt;( _
        ByVal dwFlags As Int32, _
        ByVal hwndParent As IntPtr, _
        ByVal pwszWizardTitle As String, _
        ByRef pDigitalSignInfo As CRYPTUI_WIZ_DIGITAL_SIGN_INFO, _
        ByRef ppSignContext As IntPtr _
    ) As Boolean
    End Function

    ' BOOL WINAPI CryptUIWizFreeDigitalSignContext(
    '   PCCRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT pSignContext
    ' );
    &amp;lt;DllImport("Cryptui.dll", CharSet:=CharSet.Auto, SetLastError:=True)&amp;gt; _
    Public Shared Function &lt;STRONG&gt;CryptUIWizFreeDigitalSignContext&lt;/STRONG&gt;( _
        ByVal pSignContext As IntPtr _
    ) As Boolean
    End Function

End Class

&amp;lt;/SAMPLE&amp;gt;

&amp;lt;SAMPLE file="Module1.vb"&amp;gt;

Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports SignExe.Crypto
Imports System.Security.Cryptography.X509Certificates
Imports System.IO

Module Module1

    Sub Main()

        ' Parameters
        Dim certPath As String = "MyCert.pfx"
        Dim exePath As String = "MyApplication.exe"
        Dim sigPath As String = "signature.sig"

        ' Variables
        '
        Dim cert As X509Certificate2
        Dim digitalSignInfo As CRYPTUI_WIZ_DIGITAL_SIGN_INFO
        Dim pSignContext As IntPtr
        Dim pSigningCertContext As IntPtr
        Dim signContext As CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT
        Dim fileOut As FileStream
        Dim binWriter As BinaryWriter
        Dim blob() As Byte

        Try
            ' Get certificate context
            '
            cert = New &lt;STRONG&gt;X509Certificate2&lt;/STRONG&gt;(certPath, "")
            pSigningCertContext = cert.Handle

            ' Prepare signing info: exe and cert
            '
            digitalSignInfo = New CRYPTUI_WIZ_DIGITAL_SIGN_INFO
            digitalSignInfo.dwSize = Marshal.SizeOf(digitalSignInfo)
            digitalSignInfo.dwSubjectChoice = CRYPTUI_WIZ_DIGITAL_SIGN_SUBJECT_FILE
            digitalSignInfo.pwszFileName = exePath
            digitalSignInfo.dwSigningCertChoice = CRYPTUI_WIZ_DIGITAL_SIGN_CERT
            digitalSignInfo.pSigningCertContext = pSigningCertContext
            digitalSignInfo.pwszTimestampURL = vbNullString
            digitalSignInfo.dwAdditionalCertChoice = 0
            digitalSignInfo.pSignExtInfo = IntPtr.Zero

            ' Sign exe
            '
            If (Not &lt;STRONG&gt;CryptUIWizDigitalSign&lt;/STRONG&gt;( _
                CRYPTUI_WIZ_NO_UI, _
                IntPtr.Zero, _
                vbNullString, _
                digitalSignInfo, _
                pSignContext _
            )) Then
                Throw New Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizDigitalSign")
            End If

            ' Get the blob with the signature
            '
            signContext = Marshal.PtrToStructure(pSignContext, GetType(CRYPTUI_WIZ_DIGITAL_SIGN_CONTEXT))
            blob = New Byte(signContext.cbBlob) {}
            Marshal.Copy(signContext.pbBlob, blob, 0, signContext.cbBlob)

            ' Store the signature in a new file
            '
            fileOut = File.Open(sigPath, FileMode.Create)
            binWriter = New BinaryWriter(fileOut)
            binWriter.Write(blob)
            binWriter.Close()
            fileOut.Close()

            ' Free blob
            '
            If (Not &lt;STRONG&gt;CryptUIWizFreeDigitalSignContext&lt;/STRONG&gt;(pSignContext)) Then
                Throw New Win32Exception(Marshal.GetLastWin32Error(), "CryptUIWizFreeDigitalSignContext")
            End If

            ' We are done
            Console.WriteLine("Done!!!")

        Catch ex As Win32Exception
            ' Any expected errors?
            '
            Console.WriteLine(ex.Message + " error#" + ex.NativeErrorCode.ToString)
        Catch ex As Exception
            ' Any unexpected errors?
            '
            Console.WriteLine(ex.Message)
        End Try

        ' We are done
        '
        Console.WriteLine("&amp;lt;&amp;lt; Press any key to continue &amp;gt;&amp;gt;")
        Console.ReadKey()

    End Sub

End Module

&amp;lt;/SAMPLE&amp;gt;&lt;/PRE&gt;
&lt;P&gt;This sample was also reproducing the issue. So I checked what CryptUIWizDigitalSign does behind the scenes.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;CryptUIWizDigitalSign&lt;/STRONG&gt; API uses &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa387734(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa387734(VS.85).aspx"&gt;SignerSignEx&lt;/A&gt; API to do the signing.&lt;/P&gt;
&lt;P mce_keep="true"&gt;The following &lt;STRONG&gt;VC++&lt;/STRONG&gt; sample uses &lt;STRONG&gt;SignerSignEx&lt;/STRONG&gt; API to do the signing programmatically:&lt;/P&gt;&lt;PRE&gt;#include "windows.h"
#include "Wincrypt.h"
#include "stdio.h"
#include "conio.h"


// STRUCTS

typedef &lt;STRONG&gt;struct _SIGNER_FILE_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	LPCWSTR pwszFileName;  
	HANDLE hFile;
} SIGNER_FILE_INFO,  *PSIGNER_FILE_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_BLOB_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	GUID *pGuidSubject;  
	DWORD cbBlob;  
	BYTE *pbBlob;  
	LPCWSTR pwszDisplayName;
} SIGNER_BLOB_INFO,  *PSIGNER_BLOB_INFO;

typedef&lt;STRONG&gt; struct _SIGNER_SUBJECT_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	DWORD *pdwIndex;  
	DWORD dwSubjectChoice;  
	union {    
		SIGNER_FILE_INFO *pSignerFileInfo;    
		SIGNER_BLOB_INFO *pSignerBlobInfo;  
	} ;
} SIGNER_SUBJECT_INFO,  *PSIGNER_SUBJECT_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_CERT_STORE_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	PCCERT_CONTEXT pSigningCert;  
	DWORD dwCertPolicy;  
	HCERTSTORE hCertStore;
} SIGNER_CERT_STORE_INFO,  *PSIGNER_CERT_STORE_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_SPC_CHAIN_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	LPCWSTR pwszSpcFile;  
	DWORD dwCertPolicy;  
	HCERTSTORE hCertStore;
} SIGNER_SPC_CHAIN_INFO,  *PSIGNER_SPC_CHAIN_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_CERT&lt;/STRONG&gt; {  
	DWORD cbSize;  
	DWORD dwCertChoice;  
	union {    
		LPCWSTR pwszSpcFile;    
		SIGNER_CERT_STORE_INFO *pCertStoreInfo;    
		SIGNER_SPC_CHAIN_INFO *pSpcChainInfo;  
	} ;  
	HWND hwnd;
} SIGNER_CERT,  *PSIGNER_CERT;

typedef&lt;STRONG&gt; struct _SIGNER_ATTR_AUTHCODE&lt;/STRONG&gt; {  
	DWORD cbSize;  
	BOOL fCommercial;  
	BOOL fIndividual;  
	LPCWSTR pwszName;  
	LPCWSTR pwszInfo;
} SIGNER_ATTR_AUTHCODE,  *PSIGNER_ATTR_AUTHCODE;

typedef &lt;STRONG&gt;struct _SIGNER_SIGNATURE_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	ALG_ID algidHash;  
	DWORD dwAttrChoice;  
	union {    
		SIGNER_ATTR_AUTHCODE *pAttrAuthcode;  
	} ;  
	PCRYPT_ATTRIBUTES psAuthenticated;  
	PCRYPT_ATTRIBUTES psUnauthenticated;
} SIGNER_SIGNATURE_INFO,  *PSIGNER_SIGNATURE_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_PROVIDER_INFO&lt;/STRONG&gt; {  
	DWORD cbSize;  
	LPCWSTR pwszProviderName;  
	DWORD dwProviderType;  
	DWORD dwKeySpec;  
	DWORD dwPvkChoice;  
	union {    
		LPWSTR pwszPvkFileName;    
		LPWSTR pwszKeyContainer;  
	} ;
} SIGNER_PROVIDER_INFO,  *PSIGNER_PROVIDER_INFO;

typedef &lt;STRONG&gt;struct _SIGNER_CONTEXT&lt;/STRONG&gt; {  
	DWORD cbSize;  
	DWORD cbBlob;  
	BYTE *pbBlob;
} SIGNER_CONTEXT,  *PSIGNER_CONTEXT;


// EXPORTS 

typedef HRESULT (WINAPI* &lt;STRONG&gt;SignerFreeSignerContextType&lt;/STRONG&gt;)(
  __in  SIGNER_CONTEXT *pSignerContext
);

typedef HRESULT (WINAPI *&lt;STRONG&gt;SignerSignExType&lt;/STRONG&gt;)(
  __in      DWORD dwFlags,
  __in      SIGNER_SUBJECT_INFO *pSubjectInfo,
  __in      SIGNER_CERT *pSignerCert,
  __in      SIGNER_SIGNATURE_INFO *pSignatureInfo,
  __in_opt  SIGNER_PROVIDER_INFO *pProviderInfo,
  __in_opt  LPCWSTR pwszHttpTimeStamp,
  __in_opt  PCRYPT_ATTRIBUTES psRequest,
  __in_opt  LPVOID pSipData,
  __out     SIGNER_CONTEXT **ppSignerContext
);


// MAIN

void main()
{
	// PARAMETERS

	// File to sign
	LPCWSTR pwszFileName = L"C:\\TEST\\MyApplication.exe";

	// Signing Cert Subject
	LPCWSTR pwszCertSubject = L"My cert Subject";

	// VARIABLES
	HRESULT hResult = S_OK;
	BOOL bResult = TRUE;
	HMODULE hMssign32 = NULL;
	SignerSignExType pfSignerSignEx = NULL;
	SignerFreeSignerContextType pfSignerFreeSignerContext = NULL;
	HANDLE hFile = NULL;
	HCERTSTORE hCertStore = NULL; 
	PCCERT_CONTEXT pCertContext = NULL;
	DWORD dwIndex = 0;
	SIGNER_FILE_INFO signerFileInfo;
	SIGNER_SUBJECT_INFO signerSubjectInfo;
	SIGNER_CERT_STORE_INFO signerCertStoreInfo;
	SIGNER_CERT signerCert;
	SIGNER_SIGNATURE_INFO signerSignatureInfo;
	SIGNER_CONTEXT * pSignerContext = NULL;

	// MAIN

	// Attach a debugger now!
	printf("&amp;lt;&amp;lt; Press any key to continue&amp;gt;&amp;gt;\n");
	_getch();

	// Load library containing SignerSignEx and SignerFreeSignerContext
	printf("LoadLibrary...");
	hMssign32 = &lt;STRONG&gt;LoadLibrary&lt;/STRONG&gt;(L"&lt;STRONG&gt;Mssign32.dll&lt;/STRONG&gt;");
	if (!hMssign32)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Get SignerSignEx function
	printf("GetProcAddress(SignerSignEx)...");
	pfSignerSignEx = (SignerSignExType) &lt;STRONG&gt;GetProcAddress&lt;/STRONG&gt;(hMssign32, "&lt;STRONG&gt;SignerSignEx&lt;/STRONG&gt;");
	if (!pfSignerSignEx)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Get SignerFreeSignerContext function
	printf("GetProcAddress(SignerFreeSignerContext)...");
	pfSignerFreeSignerContext = (SignerFreeSignerContextType) &lt;STRONG&gt;GetProcAddress&lt;/STRONG&gt;(hMssign32, "&lt;STRONG&gt;SignerFreeSignerContext&lt;/STRONG&gt;");
	if (!pfSignerFreeSignerContext)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Open file to sign
	printf("CreateFile...");
	hFile = &lt;STRONG&gt;CreateFile&lt;/STRONG&gt;(
		pwszFileName,
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);
	if (!hFile)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Open MY cert store
	printf("CertOpenStore...");
	hCertStore = &lt;STRONG&gt;CertOpenStore&lt;/STRONG&gt;(
		CERT_STORE_PROV_SYSTEM, 
		0,
		NULL,
		CERT_SYSTEM_STORE_CURRENT_USER,
		L"MY"
	);                 
	if (!hCertStore)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Find signing cert in MY cert store
	printf("CertFindCertificateInStore...");
	pCertContext = &lt;STRONG&gt;CertFindCertificateInStore&lt;/STRONG&gt;(
		hCertStore,
		X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
		0,
		CERT_FIND_SUBJECT_STR,
		(void *)pwszCertSubject,
		NULL
	);
	if (!pCertContext)
	{
		printf("Error #%d\n", GetLastError()); goto cleanup;
	}
	printf("Done!\n");

	// Prepare SIGNER_FILE_INFO struct
	signerFileInfo.cbSize = sizeof(SIGNER_FILE_INFO);
	signerFileInfo.pwszFileName = pwszFileName;
	signerFileInfo.hFile = hFile;

	// Prepare SIGNER_SUBJECT_INFO struct
	signerSubjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO);
	dwIndex = 0;
	signerSubjectInfo.pdwIndex = &amp;amp;dwIndex;
	signerSubjectInfo.dwSubjectChoice = 1; // SIGNER_SUBJECT_FILE
	signerSubjectInfo.pSignerFileInfo = &amp;amp;signerFileInfo;

	// Prepare SIGNER_CERT_STORE_INFO struct
	signerCertStoreInfo.cbSize = sizeof(SIGNER_CERT_STORE_INFO);
	signerCertStoreInfo.pSigningCert = pCertContext;
	signerCertStoreInfo.dwCertPolicy = 2; // SIGNER_CERT_POLICY_CHAIN
	signerCertStoreInfo.hCertStore = NULL;

	// Prepare SIGNER_CERT struct
	signerCert.cbSize = sizeof(SIGNER_CERT);
	signerCert.dwCertChoice = 2; // SIGNER_CERT_STORE
	signerCert.pCertStoreInfo = &amp;amp;signerCertStoreInfo;
	signerCert.hwnd = NULL;

	// Prepare SIGNER_SIGNATURE_INFO struct
	signerSignatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO);
	signerSignatureInfo.algidHash = CALG_SHA1;
	signerSignatureInfo.dwAttrChoice = 0; // SIGNER_NO_ATTR
	signerSignatureInfo.pAttrAuthcode = NULL;
	signerSignatureInfo.psAuthenticated = NULL;
	signerSignatureInfo.psUnauthenticated = NULL;

	// Sign file with cert
	printf("SignerSignEx...");
	hResult = pf&lt;STRONG&gt;SignerSignEx&lt;/STRONG&gt;(
		0,
		&amp;amp;signerSubjectInfo,
		&amp;amp;signerCert,
		&amp;amp;signerSignatureInfo,
		NULL,
		NULL,
		NULL,
		NULL,
		&amp;amp;pSignerContext
	);
	if (S_OK != hResult)
	{
		printf("Error #%d\n", hResult); goto cleanup;
	}
	printf("Done!\n");

	printf("\nSUCCESS!!!\n");

	// Clean up
cleanup:

	if (pSignerContext)
	{
		hResult = pf&lt;STRONG&gt;SignerFreeSignerContext&lt;/STRONG&gt;(pSignerContext);
	}

	if (pCertContext)
	{
		bResult = &lt;STRONG&gt;CertFreeCertificateContext&lt;/STRONG&gt;(pCertContext);
	}

	if (hCertStore)
	{
		bResult = &lt;STRONG&gt;CertCloseStore&lt;/STRONG&gt;(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
	}

	if (hFile)
	{
		bResult = &lt;STRONG&gt;CloseHandle&lt;/STRONG&gt;(hFile);
	}

	if (hMssign32)
	{
		bResult = &lt;STRONG&gt;FreeLibrary&lt;/STRONG&gt;(hMssign32);
	}

	// Exit
	printf("&amp;lt;&amp;lt; Press any key to exit &amp;gt;&amp;gt;\n");
	_getch();
	return;
}
&lt;/PRE&gt;
&lt;P&gt;This sample was also reproducing the issue.&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Finally we saw that the &lt;STRONG&gt;issue&lt;/STRONG&gt; was not in SignTool.exe / CAPICOM.SignCode.Sign / CryptUIWizDigitalSign / SignerSignEx, but in the &lt;STRONG&gt;EXE itself&lt;/STRONG&gt;!&lt;/P&gt;
&lt;P&gt;I run Visual Studio's &lt;A class="" href="http://support.microsoft.com/kb/177429/en-us" mce_href="http://support.microsoft.com/kb/177429/en-us"&gt;Dumpbin.exe&lt;/A&gt; with its &lt;STRONG&gt;"/HEADER"&lt;/STRONG&gt; parameter to list the problematic EXE's &lt;STRONG&gt;PE&lt;/STRONG&gt; &lt;STRONG&gt;header&lt;/STRONG&gt; information before and after signing it (the &lt;A class="" href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx" mce_href="http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx"&gt;Microsoft Portable Executable and Common Object File Format Specification &lt;/A&gt;gives detailed information about PE header information).&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Before signing&lt;/STRONG&gt;, I could see the following &lt;STRONG&gt;Optional Header Value&lt;/STRONG&gt;:&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;1400&lt;/STRONG&gt; [ &lt;STRONG&gt;C40&lt;/STRONG&gt;] RVA [size] of &lt;STRONG&gt;Certificates Directory&lt;/STRONG&gt;&lt;BR&gt;&lt;/EM&gt;&lt;BR&gt;&lt;STRONG&gt;After signing&lt;/STRONG&gt;, I could see the following value:&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;1400&lt;/STRONG&gt; [ &lt;STRONG&gt;1650&lt;/STRONG&gt;] RVA [size] of &lt;STRONG&gt;Certificates Directory&lt;/STRONG&gt;&lt;BR&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Certificates Directory &lt;/STRONG&gt;points to the &lt;STRONG&gt;location of the code signing signature in the binary&lt;/STRONG&gt;. So an &lt;STRONG&gt;EXE which has not been signed&lt;/STRONG&gt; should contain the following values:&lt;BR&gt;&lt;BR&gt;&lt;EM&gt;&lt;STRONG&gt;0&lt;/STRONG&gt; [ &lt;STRONG&gt;0&lt;/STRONG&gt;] RVA [size] of &lt;STRONG&gt;Certificates Directory&lt;/STRONG&gt;&lt;/EM&gt;&lt;BR&gt;&lt;BR&gt;Which was not our case. So SignerSignEx was not corrupting the EXE when signing it. It was already corrupted before that, even if it was successfully running before signing!&lt;/P&gt;
&lt;P&gt;Just for testing, I opened the problematic EXE with a &lt;STRONG&gt;binary editor&lt;/STRONG&gt; before signing it. I looked for "00 14 00 00 04 0c 00 00" bytes (correspondent to "1400 [ C40] RVA [size] of Certificates Directory" values), changed them to "00 00 00 00 00 00 00 00" and signed the EXE. It worked! Now the EXE is not corrupted and I can see the Digital Signature in Explorer, the certificate I used to sign, launch the EXE and run it as expected.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Manually modifying the PE header is not supported by Microsoft.&lt;/STRONG&gt; If you face a similar issue, you should work with the team that developed the EXE and focus on why the EXE got generated with an invalid PE header in the first place. &lt;/P&gt;
&lt;P&gt;I looked on the Internet and found that there are some &lt;STRONG&gt;third-party tools&lt;/STRONG&gt; which may help us to &lt;STRONG&gt;see&lt;/STRONG&gt; &lt;STRONG&gt;and modify the PE header&lt;/STRONG&gt; if needed for testing purposes, for example &lt;A class="" href="http://www.pazera-software.com/products/peinfo/" mce_href="http://www.pazera-software.com/products/peinfo/"&gt;PEInfo 0.9 BETA&lt;/A&gt; which I haven't tried so I can't neither recommend nor discourage its use.&lt;/P&gt;
&lt;P&gt;I&amp;nbsp;hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;A href="http://blogs.msdn.com/alejacma/archive/2008/02/20/how-to-sign-exe-files-with-an-authenticode-certificate-vb-net.aspx"&gt;&lt;/A&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9196078" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/CAPICOM/default.aspx">CAPICOM</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/CryptoAPI/default.aspx">CryptoAPI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/P_2F00_Invoke/default.aspx">P/Invoke</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category></item><item><title>How to change Windows Theme programmatically in XP</title><link>http://blogs.msdn.com/alejacma/archive/2008/11/26/how-to-change-windows-theme-programmatically-in-xp.aspx</link><pubDate>Wed, 26 Nov 2008 18:30:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9144706</guid><dc:creator>alejacma</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/9144706.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=9144706</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;You may know already that there is no i.e. COM object or .NET class we can use to &lt;STRONG&gt;change&lt;/STRONG&gt; the &lt;STRONG&gt;Windows Theme&lt;/STRONG&gt; programmatically on &lt;STRONG&gt;Windows XP&lt;/STRONG&gt;. You may also know the following &lt;STRONG&gt;VBScript&lt;/STRONG&gt; which can be used to do this change without user intervention:&lt;/P&gt;&lt;PRE&gt;Set OSHApp = CreateObject("&lt;STRONG&gt;Shell.Application&lt;/STRONG&gt;")
Set oShell = CreateObject("Wscript.Shell")

' Set the Path to the Theme file
'
Theme = "\\SERVER\SHAREDFOLDER\FILE.THEME"
Theme = """" + Theme + """"
' Open the Theme in Display Properties
'
oSHApp.&lt;STRONG&gt;ControlPanelItem&lt;/STRONG&gt; cstr("&lt;STRONG&gt;desk.cpl desk,@Themes /Action:OpenTheme /file:&lt;/STRONG&gt;" &amp;amp; Theme)

' Loop and wait until Display Properties is loaded.
'
While OShell.AppActivate ("Display Properties") = FALSE
Wscript.Sleep 1000
Wend

' Loop and send the Enter key to Display Properties until Theme is applied 
'
While OShell.AppActivate ("Display Properties") = TRUE
    oShell.AppActivate "Display Properties"
    Wscript.Sleep 200
    oShell.sendkeys "{ENTER}"
Wend
&lt;/PRE&gt;
&lt;P&gt;If you try this script,&amp;nbsp;it will sometimes fail. In some situations, the Display Properties dialog won't be closed automatically. You may "play" with the Sleep times and solve the issue in several machines, but it won't necessarily work in all of them.&lt;/P&gt;
&lt;P&gt;The issue here is that "oShell.sendkeys "{ENTER}"" is not getting to the right window and there is any guarantee that it will do it.&lt;/P&gt;
&lt;P&gt;Fortunately there is an &lt;STRONG&gt;alternate solution&lt;/STRONG&gt; to this script and its SendKeys: &lt;STRONG&gt;send a&lt;/STRONG&gt; &lt;STRONG&gt;BM_CLICK&lt;/STRONG&gt; &lt;STRONG&gt;window message&lt;/STRONG&gt; to the button we need to press in the required &lt;STRONG&gt;Theme window&lt;/STRONG&gt;. This way we can warrantee that we close the right window by pressing the right button.&lt;/P&gt;
&lt;P&gt;You will find a&lt;STRONG&gt; VB.NET&lt;/STRONG&gt; sample below which gets &lt;STRONG&gt;all windows in the desktop&lt;/STRONG&gt; (visible and invisible), the way &lt;STRONG&gt;Spy++&lt;/STRONG&gt; does it, in a tree. Then the sample also shows how if we select one of those windows in the tree manually (i.e. the print dialog of notepad), we can&amp;nbsp;interact with it programmatically&amp;nbsp;(i.e. changing the editbox with the number of copies to print and pressing the Print button). &lt;/P&gt;
&lt;P&gt;It should be easy to adapt this sample to our needs so it first launches the Theme console to change the theme the way the script above does it (i.e. &lt;A class="" href="http://www.codeguru.com/vb/gen/vb_system/win32/print.php/c13963" mce_href="http://www.codeguru.com/vb/gen/vb_system/win32/print.php/c13963"&gt;Running Windows XP Control Panel Applets from Visual Basic.NET 2005&lt;/A&gt;), and then it looks for the window we need to close, locates its OK button and sends a BM_CLICK message to it in order to close the window.&lt;/P&gt;
&lt;P&gt;Here is the sample:&lt;/P&gt;&lt;PRE&gt;Imports System.Runtime.InteropServices

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

        ' Get all windows and show them in the tree
        '
        GetWindows()
        TreeView1.Nodes.Item(0).Expand()
    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents Button2 As System.Windows.Forms.Button
    &lt;SYSTEM.DIAGNOSTICS.DEBUGGERSTEPTHROUGH()&gt; Private Sub InitializeComponent()
        Me.TreeView1 = New System.Windows.Forms.TreeView
        Me.Button1 = New System.Windows.Forms.Button
        Me.Button2 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'TreeView1
        '
        Me.TreeView1.HideSelection = False
        Me.TreeView1.ImageIndex = -1
        Me.TreeView1.Location = New System.Drawing.Point(8, 48)
        Me.TreeView1.Name = "TreeView1"
        Me.TreeView1.SelectedImageIndex = -1
        Me.TreeView1.Size = New System.Drawing.Size(640, 504)
        Me.TreeView1.TabIndex = 0
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(8, 8)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(160, 32)
        Me.Button1.TabIndex = 1
        Me.Button1.Text = "Refresh"
        '
        'Button2
        '
        Me.Button2.Location = New System.Drawing.Point(176, 8)
        Me.Button2.Name = "Button2"
        Me.Button2.Size = New System.Drawing.Size(472, 32)
        Me.Button2.TabIndex = 2
        Me.Button2.Text = "Set ""Number of copies"" and click ""Print"" in selected notepad's Print dialog"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(656, 558)
        Me.Controls.Add(Me.Button2)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.TreeView1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

#Region "AlejaCMa"

    ' Constants
    '
    Private Const GW_CHILD = 5
    Private Const GW_HWNDNEXT = 2

    Private Const WM_SETTEXT = &amp;amp;HC
    Private Const BM_CLICK = &amp;amp;HF5

    ' API declarations
    '
    Private Declare Function GetDesktopWindow Lib "user32" () As IntPtr

    Private Declare Function GetWindow Lib "user32" ( _
        ByVal hWnd As IntPtr, _
        ByVal uCmd As Int32) _
    As IntPtr

    Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" ( _
        ByVal hWnd As IntPtr, _
        ByVal lpString As String, _
        ByVal nMaxCount As Int32) _
    As Int32

    Public Declare Function GetWindowThreadProcessId Lib "user32" Alias "GetWindowThreadProcessId" ( _
        ByVal hwnd As IntPtr, _
        ByRef lpdwProcessId As Int32) _
    As Int32

    Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" ( _
        ByVal hWnd As IntPtr, _
        ByVal lpClassName As String, _
        ByVal nMaxCount As Int32) _
    As Int32

    Private Declare Function IsWindowVisible Lib "user32" ( _
        ByVal hWnd As IntPtr) _
    As Int32

    Public Declare Auto Function SendMessage Lib "user32" Alias "SendMessageA" ( _
        ByVal hWnd As IntPtr, _
        ByVal wMsg As Int32, _
        ByVal wParam As Int32, _
        &lt;MARSHALAS(UNMANAGEDTYPE.ANSIBSTR)&gt; ByVal lParam As String) _
    As Int32

    ' Get windows, and show them in the tree
    '
    Private Sub GetWindows()
        ' Variables
        '
        Dim hWnd As IntPtr
        Dim node As TreeNode
        Dim windowText As String
        Dim className As String
        Dim c As Int32
        Dim nodeText As String

        ' Get desktop window
        '
        hWnd = GetDesktopWindow()

        ' Get window text and class name
        '
        windowText = Space(255)
        c = GetWindowText(hWnd, windowText, 255)
        windowText = Microsoft.VisualBasic.Left(windowText, c)

        className = Space(255)
        c = GetClassName(hWnd, className, 255)
        className = Microsoft.VisualBasic.Left(className, c)

        ' Add window to the tree
        '
        nodeText = String.Format("{0:X8} ""{1}"" {2} (Desktop)", hWnd.ToInt32, windowText, className)
        node = TreeView1.Nodes.Add(nodeText)
        node.ForeColor = Color.Black

        ' Search children by recursion
        '
        GetWindows(hWnd, node)
    End Sub

    Private Sub GetWindows(ByVal hParentWnd As IntPtr, ByVal parentNode As TreeNode)
        ' Variables
        '
        Dim hWnd As IntPtr
        Dim node As TreeNode
        Dim windowText As String
        Dim className As String
        Dim c As Int32
        Dim nodeText As String

        ' Get first child window
        '
        hWnd = GetWindow(hParentWnd, GW_CHILD)

        Do Until hWnd.Equals(IntPtr.Zero)
            ' Get the window text and class name
            '
            windowText = Space(255)
            c = GetWindowText(hWnd, windowText, 255)
            windowText = Microsoft.VisualBasic.Left(windowText, c)

            className = Space(255)
            c = GetClassName(hWnd, className, 255)
            className = Microsoft.VisualBasic.Left(className, c)

            ' Add window to the tree
            '
            nodeText = String.Format("{0:X8} ""{1}"" {2}", hWnd.ToInt32, windowText, className)
            node = parentNode.Nodes.Add(nodeText)
            If (IsWindowVisible(hWnd)) Then
                ' Visible windows are shown in black
                '
                node.ForeColor = Color.Black
            Else
                ' Invisible windows are shown in red
                '
                node.ForeColor = Color.Red
            End If

            ' Search children by recursion
            '
            GetWindows(hWnd, node)

            ' Get next child window
            '
            hWnd = GetWindow(hWnd, GW_HWNDNEXT)
        Loop
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ' Get all windows and show them in the tree
        '
        TreeView1.Nodes.Clear()
        GetWindows()
        TreeView1.Nodes.Item(0).Expand()
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        ' Variables
        '
        Dim node As TreeNode
        Dim windowInfo As String
        Dim hWnd As IntPtr
        Dim pid As Int32
        Dim processName As String

        ' Get the selected window in the tree
        '
        node = TreeView1.SelectedNode

        ' Get PID (Process ID) for the selected window
        '
        hWnd = New IntPtr(CInt("&amp;amp;H" + Microsoft.VisualBasic.Left(node.Text, 8)))
        GetWindowThreadProcessId(hWnd, pid)

        ' Get process name from PID
        '
        processName = Process.GetProcessById(pid).ProcessName

        ' Check if the selected window in the tree is notepad's Print dialog:
        '   Window Handle = xxxxxxxx (variable)
        '   Window Text   = Print
        '   Class Name    = #32770
        '   Process Name  = "notepad"
        '
        windowInfo = Microsoft.VisualBasic.Right(node.Text, node.Text.Length - 9)
        If (windowInfo = """Print"" #32770" And processName = "notepad") Then
            ' The selected window is notepad's Print dialog

            ' Change the number of copies in "Number of &amp;amp;copies" edit box 
            '
            ' xxxxxxxx "Print" #32770       &amp;lt;-- Selected node
            '   - xxxxxxxx "General" #32770
            '       - xxxxxxxx "" #32770
            '            xxxxxxxx "" Edit   &amp;lt;-- We have to write here
            '
            hWnd = New IntPtr(CInt("&amp;amp;H" + Microsoft.VisualBasic.Left(node.Nodes(0).Nodes(13).Nodes(10).Text, 8)))
            SendMessage(hWnd, WM_SETTEXT, 0, "2")

            ' Press the print button
            '
            ' xxxxxxxx "Print" #32770       &amp;lt;-- Selected node
            '    xxxxxxxx "&amp;amp;Print" Button   &amp;lt;-- We have to press here
            '
            hWnd = New IntPtr(CInt("&amp;amp;H" + Microsoft.VisualBasic.Left(node.Nodes(1).Text, 8)))
            SendMessage(hWnd, BM_CLICK, 0, Nothing)
        Else
            ' The selected window is not notepad's Print dialog
            '
            MessageBox.Show("The selected window is not a notepad's Print dialog")
        End If
    End Sub
#End Region

End Class

&lt;/PRE&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9144706" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/P_2F00_Invoke/default.aspx">P/Invoke</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/Windows+XP/default.aspx">Windows XP</category></item><item><title>How to get more than 1000 group members including foreign SAMs (VBScript)</title><link>http://blogs.msdn.com/alejacma/archive/2008/08/05/how-to-get-more-than-1000-group-members-including-foreign-sams-vbscript.aspx</link><pubDate>Tue, 05 Aug 2008 10:21:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8833391</guid><dc:creator>alejacma</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8833391.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8833391</wfw:commentRss><description>&lt;P&gt;Hi all,&lt;/P&gt;
&lt;P&gt;We may have a &lt;STRONG&gt;group &lt;/STRONG&gt;in our &lt;STRONG&gt;Active Directory&lt;/STRONG&gt; with &lt;STRONG&gt;members&lt;/STRONG&gt; from a &lt;STRONG&gt;foreign domain&lt;/STRONG&gt;. We may try to retrieve all those members with &lt;STRONG&gt;ADSI&lt;/STRONG&gt; and a code like this: &lt;A class="" href="http://msdn.microsoft.com/en-us/library/aa746518.aspx" mce_href="http://msdn.microsoft.com/en-us/library/aa746518.aspx"&gt;Using IADs::GetInfoEx for Range Retrieval&lt;/A&gt;. The issue with this code is that we will only be able to see the &lt;STRONG&gt;SID&lt;/STRONG&gt; of &lt;STRONG&gt;foreign principals&lt;/STRONG&gt; (i.e. CN=S-1-5-21-1234567890...-123,CN=ForeignSecurityPrincipals,DC=domain,DC=com), which may not be very useful for us.&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;sample&lt;/STRONG&gt; (based on above &lt;STRONG&gt;Range Retrieval&lt;/STRONG&gt; sample) will retrieve &lt;STRONG&gt;all members in a group&lt;/STRONG&gt; (&lt;STRONG&gt;including foreign principals&lt;/STRONG&gt;) and show their &lt;STRONG&gt;sAMAccountName&lt;/STRONG&gt;:&lt;/P&gt;&lt;PRE&gt;' PARAMETERS.
'
strFileName = "c:\List.txt"
strGroupDN = "CN=groupName,CN=Users,DC=domainName,DC=com"

' Bind to the group with the current credentials.
'
Set oGroup = GetObject("LDAP://" &amp;amp; strGroupDN)

' Create file for results.
'
Set fs = CreateObject("Scripting.FileSystemObject")
Set usersFile = fs.CreateTextFile(strFileName, True)

' For compatibility with all operating systems, the number of objects
' retrieved by each query should not exceed 999. The number of objects
' to retrieve should be as close as possible to 999 to reduce the number
' of round trips to the server necessary to retrieve the objects.
rangeStep = 999
lowRange = 0
highRange = lowRange + rangeStep

Do
  ' Use the "member;range=&amp;lt;lowRange&amp;gt;-&amp;lt;highRange&amp;gt;" syntax.
  '
  strCommandText = "member;range=" &amp;amp; lowRange &amp;amp; "-" &amp;amp; highRange
  usersFile.WriteLine(vbCrLf &amp;amp; "Current search command: " &amp;amp; _
  strCommandText &amp;amp; vbCrLf)

  ' Load the specified range of members into the local cache. This 
  ' will throw an error if the range exceeds the properties contained 
  ' in the object. The "On Error GoTo quit" error handler will cause 
  ' the loop to terminate when this happens.
  '
  On Error Resume Next
  oGroup.GetInfoEx Array(strCommandText), 0
  If Err.Number = &amp;amp;H80072020 Then
    Exit Do
  End If
  On Error Goto 0

  ' Enumerate the retrieved members.
  '
  oMembers = oGroup.Get("member")
  If vbArray And VarType(oMembers) Then
    For Each oMember In oMembers
      ' Add the member.
      '            
      Set oUser = GetObject("LDAP://" &amp;amp; oMember)            
      If (oUser.Class = "foreignSecurityPrincipal") Then

        usersFile.WriteLine(GetForeignSAM(oUser))
      Else
        usersFile.WriteLine(oUser.sAMAccountName)
      End If 
      nRetrieved = nRetrieved + 1
    Next
  Else
    ' oGroup.Get returned only one member, so add it to the list.
    '
    Set oUser = GetObject("LDAP://" &amp;amp; oMembers)            
    If (oUser.Class = "foreignSecurityPrincipal") Then

      usersFile.WriteLine(&lt;STRONG&gt;GetForeignSAM&lt;/STRONG&gt;(oUser))
    Else
      usersFile.WriteLine(oUser.sAMAccountName)
    End If 

    nRetrieved = nRetrieved + 1
  End If

  ' Increment the high and low ranges to query for the next block of 
  ' objects.
  '
  lowRange = highRange + 1
  highRange = lowRange + rangeStep
Loop While True

MsgBox "File """ &amp;amp; strFileName &amp;amp;  """ created"


'-----------------------------------------------------------------------
' HELPER FUNCTIONS
'-----------------------------------------------------------------------
&lt;STRONG&gt;function GetForeignSAM&lt;/STRONG&gt; (oUser)
  ' CONSTANTS.
  '
  ADS_SID_RAW = 0
  ADS_SID_HEXSTRING = ADS_SID_RAW + 1
  ADS_SID_SAM = ADS_SID_HEXSTRING + 1
  ADS_SID_UPN = ADS_SID_SAM + 1
  ADS_SID_SDDL = ADS_SID_UPN + 1
  ADS_SID_WINNT_PATH = ADS_SID_SDDL + 1

  ' Get the SID
  '

  ' Now, resolve the SID into its sAMAcountName.
  '
  set oADsSID = CreateObject("&lt;STRONG&gt;ADsSID&lt;/STRONG&gt;")
  oADsSID.&lt;STRONG&gt;SetAs ADS_SID_RAW&lt;/STRONG&gt;, oUser.Get("objectSid")

  ' Requesting the Sam Account Name
  '
  GetForeignSAM = oADsSID.&lt;STRONG&gt;GetAs(ADS_SID_SAM)&lt;/STRONG&gt;	

end function
&lt;/PRE&gt;
&lt;P&gt;Note: &lt;STRONG&gt;ADsSID&lt;/STRONG&gt; object is implemented in &lt;STRONG&gt;ADsSecurity.dll&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8833391" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/ADSI/default.aspx">ADSI</category></item><item><title>How to get Antivirus information with WMI (VBScript)</title><link>http://blogs.msdn.com/alejacma/archive/2008/05/12/how-to-get-antivirus-information-with-wmi-vbscript.aspx</link><pubDate>Mon, 12 May 2008 12:23:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8492893</guid><dc:creator>alejacma</dc:creator><slash:comments>15</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8492893.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8492893</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;As we read in &lt;A class="" href="http://www.microsoft.com/windowsxp/sp2/wscoverview.mspx" mce_href="http://www.microsoft.com/windowsxp/sp2/wscoverview.mspx"&gt;Windows Security Center – Managing the State of Security&lt;/A&gt;, the vast majority of &lt;STRONG&gt;antivirus&lt;/STRONG&gt; Independent Software Vendors (ISVs) support &lt;STRONG&gt;WMI&lt;/STRONG&gt; integration. Windows Security Center uses it to detect antivirus and firewall solutions.&lt;/P&gt;
&lt;P&gt;The following &lt;STRONG&gt;script&lt;/STRONG&gt; shows how to get some information from those solutions:&lt;BR&gt;&lt;BR&gt;&amp;nbsp; &lt;/P&gt;&lt;PRE&gt;strComputer = "."
    
Set oWMI = GetObject( _
  "winmgmts:{impersonationLevel=impersonate}!\\" &amp;amp; strComputer &amp;amp; "\root\SecurityCenter")
  
Set colItems = oWMI.ExecQuery("Select * from AntiVirusProduct")

For Each objItem in colItems
  With objItem
    WScript.Echo .companyName
    WScript.Echo .displayName
    WScript.Echo .instanceGuid
    WScript.Echo .onAccessScanningEnabled
    WScript.Echo .pathToSignedProductExe
    WScript.Echo .productHasNotifiedUser
    WScript.Echo .productState
    WScript.Echo .productUptoDate
    WScript.Echo .productWantsWscNotifications
    WScript.Echo .versionNumber  
  End With
Next

&lt;/PRE&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8492893" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/WMI/default.aspx">WMI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category></item><item><title>How to get a list of all users in an OU (VBScript)</title><link>http://blogs.msdn.com/alejacma/archive/2008/04/23/how-to-get-a-list-of-all-users-in-an-ou-vbscript.aspx</link><pubDate>Wed, 23 Apr 2008 18:44:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8419309</guid><dc:creator>alejacma</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8419309.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8419309</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;Today I'll post a very straight forward sample which gets a list of all &lt;STRONG&gt;users&lt;/STRONG&gt; in an &lt;STRONG&gt;Organizational Unit&lt;/STRONG&gt; (&lt;STRONG&gt;OU&lt;/STRONG&gt;) in &lt;STRONG&gt;Active Directory&lt;/STRONG&gt; (&lt;STRONG&gt;AD&lt;/STRONG&gt;) using &lt;STRONG&gt;VBScript&lt;/STRONG&gt;:&lt;/P&gt;&lt;PRE&gt;' Get OU
'
strOU = "OU=Users,DC=domain,DC=com"

' Create connection to AD
'
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Open "Provider=ADsDSOObject;"

' Create command
'
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection = objConnection
objCommand.Properties("Page Size") = 1000

' Execute command to get all users in OU
'
objCommand.CommandText = _
  "&amp;lt;LDAP://" &amp;amp; strOU &amp;amp; "&amp;gt;;" &amp;amp; _
  "(&amp;amp;(objectclass=user)(objectcategory=person));" &amp;amp; _
  "adspath,distinguishedname,sAMAccountName;subtree"
Set objRecordSet = objCommand.Execute

' Show info for each user in OU
'
Do Until objRecordSet.EOF

  ' Show required info for a user
  '  
  WScript.Echo objRecordSet.Fields("adspath").Value
  WScript.Echo objRecordSet.Fields("distinguishedname").Value
  WScript.Echo objRecordSet.Fields("sAMAccountName").Value

  ' Move to the next user
  '
  objRecordSet.MoveNext

Loop

' Clean up
'
objRecordSet.Close
Set objRecordSet = Nothing
Set objCommand = Nothing
objConnection.Close
Set objConnection = Nothing
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Regards,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8419309" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/ADSI/default.aspx">ADSI</category></item><item><title>How to read a registry key and its values (VBScript)</title><link>http://blogs.msdn.com/alejacma/archive/2008/04/11/how-to-read-a-registry-key-and-its-values.aspx</link><pubDate>Fri, 11 Apr 2008 09:27:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8378781</guid><dc:creator>alejacma</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8378781.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8378781</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back, &lt;/P&gt;
&lt;P&gt;Today I'll share with you a couple of &lt;STRONG&gt;VBScript&lt;/STRONG&gt; samples I developed the other day. They use &lt;STRONG&gt;WMI&lt;/STRONG&gt; and its &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/aa393664(VS.85).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa393664(VS.85).aspx"&gt;StdRegProv class&lt;/A&gt; to read the &lt;STRONG&gt;Windows registry&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;This sample will take a &lt;STRONG&gt;registry key&lt;/STRONG&gt; and show its &lt;STRONG&gt;subkeys&lt;/STRONG&gt; and the &lt;STRONG&gt;values&lt;/STRONG&gt; within those subkeys:&lt;/P&gt;&lt;PRE&gt;' Constants (taken from WinReg.h)
'
Const HKEY_CLASSES_ROOT   = &amp;amp;H80000000
Const HKEY_CURRENT_USER   = &amp;amp;H80000001
Const HKEY_LOCAL_MACHINE  = &amp;amp;H80000002
Const HKEY_USERS          = &amp;amp;H80000003

Const REG_SZ        = 1
Const REG_EXPAND_SZ = 2
Const REG_BINARY    = 3
Const REG_DWORD     = 4
Const REG_MULTI_SZ  = 7

' Chose computer name, registry tree and key path
'
strComputer = "." ' Use . for current machine
hDefKey = HKEY_LOCAL_MACHINE
strKeyPath = "SOFTWARE\Microsoft\Cryptography\Defaults\Provider"

' Connect to registry provider on target machine with current user
'
Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &amp;amp; strComputer &amp;amp; "\root\default:StdRegProv")

' Enum the subkeys of the key path we've chosen
'
oReg.EnumKey hDefKey, strKeyPath, arrSubKeys

For Each strSubkey In arrSubKeys

  ' Show the subkey
  '
  wscript.echo strSubkey

  ' Show its value names and types
  '
  strSubKeyPath = strKeyPath &amp;amp; "\" &amp;amp; strSubkey
  oReg.EnumValues hDefKey, strSubKeyPath, arrValueNames, arrTypes

  For i = LBound(arrValueNames) To UBound(arrValueNames)
    strValueName = arrValueNames(i)
    Select Case arrTypes(i)

      ' Show a REG_SZ value
      '
      Case REG_SZ          
        oReg.GetStringValue hDefKey, strSubKeyPath, strValueName, strValue
        wscript.echo "  " &amp;amp; strValueName &amp;amp; " (REG_SZ) = " &amp;amp; strValue

      ' Show a REG_EXPAND_SZ value
      '
      Case REG_EXPAND_SZ
        oReg.GetExpandedStringValue hDefKey, strSubKeyPath, strValueName, strValue
        wscript.echo "  " &amp;amp; strValueName &amp;amp; " (REG_EXPAND_SZ) = " &amp;amp; strValue

      ' Show a REG_BINARY value
      '          
      Case REG_BINARY
        oReg.GetBinaryValue hDefKey, strSubKeyPath, strValueName, arrBytes
        strBytes = ""
        For Each uByte in arrBytes
          strBytes = strBytes &amp;amp; Hex(uByte) &amp;amp; " "
        Next
        wscript.echo "  " &amp;amp; strValueName &amp;amp; " (REG_BINARY) = " &amp;amp; strBytes

      ' Show a REG_DWORD value
      '
      Case REG_DWORD
        oReg.GetDWORDValue hDefKey, strSubKeyPath, strValueName, uValue
        wscript.echo "  " &amp;amp; strValueName &amp;amp; " (REG_DWORD) = " &amp;amp; CStr(uValue)				  

      ' Show a REG_MULTI_SZ value
      '
      Case REG_MULTI_SZ
        oReg.GetMultiStringValue hDefKey, strSubKeyPath, strValueName, arrValues				  				
        wscript.echo "  " &amp;amp; strValueName &amp;amp; " (REG_MULTI_SZ) ="
        For Each strValue in arrValues
          wscript.echo "    " &amp;amp; strValue 
        Next

    End Select
  Next

Next&lt;/PRE&gt;
&lt;P&gt;But what if we only need to know if a registry key exists? We could just do the following:&lt;/P&gt;&lt;PRE&gt;' Constants (taken from WinReg.h)
'
Const HKEY_CLASSES_ROOT   = &amp;amp;H80000000
Const HKEY_CURRENT_USER   = &amp;amp;H80000001
Const HKEY_LOCAL_MACHINE  = &amp;amp;H80000002
Const HKEY_USERS          = &amp;amp;H80000003

' Chose computer name, registry tree and key path
'
strComputer = "." ' Use . for current machine
hDefKey = HKEY_LOCAL_MACHINE
strKeyPath = "SOFTWARE\Microsoft\Cryptography\Defaults\Provider"

' Connect to registry provider on target machine with current user
'
Set oReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &amp;amp; strComputer &amp;amp; "\root\default:StdRegProv")

' Try to enum the subkeys of the key path we've chosen. We can't if the key doesn't exist
'
If oReg.EnumKey(hDefKey, strKeyPath, arrSubKeys) = 0 Then
  wscript.echo "Key exists!"
Else
  wscript.echo "Key does not exists!"
End If
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8378781" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category></item><item><title>How to change the Security Descriptor of WMI objects</title><link>http://blogs.msdn.com/alejacma/archive/2008/03/14/how-to-change-the-security-descriptor-of-wmi-objects.aspx</link><pubDate>Fri, 14 Mar 2008 05:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8172662</guid><dc:creator>alejacma</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8172662.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8172662</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;You may want to give users or groups &lt;STRONG&gt;access&lt;/STRONG&gt; to perform read/modify &lt;STRONG&gt;WMI operations&lt;/STRONG&gt; on &lt;STRONG&gt;WMI objects&lt;/STRONG&gt;, and for that you need to change the &lt;STRONG&gt;Security Descriptor&lt;/STRONG&gt; (&lt;STRONG&gt;SD&lt;/STRONG&gt;) for WMI objects. There are several ways to achieve this:&lt;/P&gt;
&lt;P&gt;1) &lt;STRONG&gt;Manually&lt;/STRONG&gt; with wmimgmt.msc: &lt;A class="" href="http://support.microsoft.com/default.aspx?scid=kb;EN-US;325353" mce_href="http://support.microsoft.com/default.aspx?scid=kb;EN-US;325353"&gt;325353&amp;nbsp;HOW TO: Set WMI Namespace Security in Windows Server 2003&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;2) Using &lt;STRONG&gt;third-party tools&lt;/STRONG&gt; like &lt;A class="" href="http://www.codeproject.com/cs/system/WmiSecurity.asp" mce_href="http://www.codeproject.com/cs/system/WmiSecurity.asp"&gt;WMI Namespace Security&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;3) &lt;STRONG&gt;Programmatically, the easy way&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;We could manually set the SD on one box, then save it to a text file with &lt;A class="" href="http://msdn2.microsoft.com/en-gb/library/aa394680(VS.85).aspx" mce_href="http://msdn2.microsoft.com/en-gb/library/aa394680(VS.85).aspx"&gt;GetSD method of the __SystemSecurity class&lt;/A&gt;, read the SD from the text file and reapply it to new boxes with &lt;A class="" href="http://msdn2.microsoft.com/en-gb/library/aa394682(VS.85).aspx" mce_href="http://msdn2.microsoft.com/en-gb/library/aa394682(VS.85).aspx"&gt;SetSD&lt;/A&gt; method.&lt;/P&gt;
&lt;P&gt;The following VBScript shows how to use GetSD to obtain the current SD for the Root\Cimv2 namespace and change it to the byte array shown in strDisplaySD.&lt;/P&gt;&lt;PRE&gt;' Connect to WMI and the root namespace.
'
Set objWMI = GetObject("winmgmts:root\cimv2")

' Get the single __SystemSecurity object in this namespace.
'
Set objSecurity = objWMI.Get("__SystemSecurity=@")

' Get the namespace security.
'
nReturn = objSecurity.GetSD(arrSD)
If Err &amp;lt;&amp;gt; 0 Then
    WScript.Echo "Return value =  " &amp;amp; nReturn
Else
    ' Show it
    '
    strDisplaySD = "SD = {"
    For I = Lbound(arrSD) To Ubound(arrSD)
        strDisplaySD = strDisplaySD &amp;amp; arrSD(I)
        If I &amp;lt;&amp;gt; Ubound(arrSD) Then    
            strDisplaySD = DisplaySD &amp;amp; ","
        End If
    Next
    strDisplaySD = strDisplaySD &amp;amp; "}"
    WScript.Echo strDisplaySD
End If
&lt;/PRE&gt;
&lt;P&gt;The following script shows how to use SetSD to set the namespace SD for the root namespace and change it to the byte array shown in arrSD.&lt;/P&gt;&lt;PRE&gt;' Hard-coded security descriptor
'
arrSD = array( 1, 0, 4,129,72, 0, 0, 0, _ 
    88, 0, 0, 0, 0, 0, 0, 0, _
    20, 0, 0, 0, 2, 0,52, 0, _
    2, 0, 0, 0, 0, 2,24, 0, _
    63, 0, 6, 0, 1, 2, 0, 0, _
    0, 0, 0, 5,32, 0, 0, 0, _
    32, 2, 0, 0, 0, 2,20, 0, _
    63, 0, 6, 0, 1, 1, 0, 0, _
    0, 0, 0, 1, 0, 0, 0, 0, _
    1, 2, 0, 0, 0, 0, 0, 5, _
    32, 0, 0, 0,32, 2, 0, 0, _
    1, 2, 0, 0, 0, 0, 0, 5, _
    32, 0, 0, 0,32, 2, 0, 0)

' Connect to WMI and the root namespace.
'
Set objWMI = GetObject("winmgmts:root\cimv2")

' Get the single __SystemSecurity object in this namespace.
'
Set objSecurity = objWMI.Get("__SystemSecurity=@")

' Change the namespace security.
'
nReturn = objSecurity.SetSD(arrSD)
WScript.Echo "Return value = " &amp;amp; nReturn
&lt;/PRE&gt;
&lt;P&gt;4) &lt;STRONG&gt;Programmatically, the hard way&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;We can write our own WMI script using the following sample found at &lt;A href="http://www.lissware.net/"&gt;http://www.lissware.net/&lt;/A&gt;: &lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://www.lissware.net/wmibooks/Volume_2_ScriptKits.zip" mce_href="http://www.lissware.net/wmibooks/Volume_2_ScriptKits.zip"&gt;vol 2, Sample 4.02 to 4.13 - WMIManageSD.Wsf&lt;/A&gt;, using a series of subfunctions:&lt;BR&gt;&amp;nbsp;&lt;BR&gt;Sample 4.02 to 4.13 - WMIManageSD.Wsf&lt;BR&gt;Sample 4.14 to 4.24 - GetSDFunction.vbs&lt;BR&gt;Sample 4.25 - CreateDefaultSDFunction.vbs&lt;BR&gt;Sample 4.26 to 4.27 - ADSIHelper.exp&lt;BR&gt;Sample 4.28 - DecipherWMISDFunction.vbs&lt;BR&gt;Sample 4.29 - DecipherADSISDFunction.vbs&lt;BR&gt;Sample 4.30 - DecipherSDControlFlagsFunction.vbs&lt;BR&gt;Sample 4.31 - CalculateSDControlFlagsFunction.vbs&lt;BR&gt;Sample 4.32 to 4.40 - ActiveDirectory.CMD&lt;BR&gt;Sample 4.41 - SetSDOwnerFunction.vbs&lt;BR&gt;Sample 4.42 - CreateTrusteeFunction.vbs&lt;BR&gt;Sample 4.43 - SetSDGroupFunction.vbs&lt;BR&gt;Sample 4.44 - SetSDControlFlagsFunction.vbs&lt;BR&gt;Sample 4.45 to 4.46 - AddACEFunction.vbs&lt;BR&gt;Sample 4.47 to 4.48 - DelACEFunction.vbs&lt;BR&gt;Sample 4.49 to 4.50 - ReOrderACEFunction.vbs&lt;BR&gt;Sample 4.51 to 4.61 - SetSDFunction.vbs&lt;BR&gt;&amp;nbsp;&lt;BR&gt;The script actually reads the binary SD with __SystemSecurity class and converts it with Sample 4.14 to 4.24 - GetSDFunction.vbs at line 283.&lt;BR&gt;The object used to convert the SD is defined at line 189 in Sample 4.02 to 4.13 - WMIManageSD.Wsf.&lt;BR&gt;Under XP and 2003, it uses the IADsSecurityUtility::ConvertSecurityDescriptor.&lt;BR&gt;Before XP, it uses a COM component especially written for the purpose of the bin array conversion to an ADSI SD representation (located in the resources folder coming with the ZIP that must be REGSVR32).&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;The sample given there manages the security not only on WMI namespaces, but also on Files, Folders, Shares, AD objects, Exchange Mailboxes and Registry keys.&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;Everything is explained in greater details in the book related to this sample as&amp;nbsp;the full coverage of the details for the management of all SD supported above required 220 pages of texts and tables.&lt;BR&gt;This is not a trivial task even if it is fairly achievable.&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8172662" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/WMI/default.aspx">WMI</category><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category></item><item><title>How to change Registry Permissions with RegIni.exe (VBScript)</title><link>http://blogs.msdn.com/alejacma/archive/2008/03/11/how-to-change-registry-permissions-with-regini-exe-vbscript.aspx</link><pubDate>Tue, 11 Mar 2008 10:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8146408</guid><dc:creator>alejacma</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8146408.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8146408</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;Today I'll show how we can set the following &lt;STRONG&gt;permissions&lt;/STRONG&gt; on a &lt;STRONG&gt;registry key&lt;/STRONG&gt; with &lt;STRONG&gt;RegIni.exe&lt;/STRONG&gt; and a &lt;STRONG&gt;VBScript&lt;/STRONG&gt;:&lt;/P&gt;
&lt;P&gt;- Creator Owner Full Control &lt;BR&gt;- Users Full Control &lt;BR&gt;- Power Users Full Control &lt;BR&gt;- Administrators Full Control &lt;BR&gt;- System Full Control&lt;/P&gt;
&lt;P&gt;I will set the permissions here for testing purposes:&lt;/P&gt;
&lt;P&gt;- HKEY_CLASSES_ROOT\AlejaCMaTypelib&lt;BR&gt;- HKEY_LOCAL_MACHINE\Software\AlejaCMaCo\AlejaCMaApp&lt;BR&gt;&lt;BR&gt;And for that I will need to create a special &lt;STRONG&gt;regini.exe script&lt;/STRONG&gt; which will have the following contents:&lt;/P&gt;&lt;PRE&gt; 
HKEY_LOCAL_MACHINE\Software\Classes\AlejaCMaTypelib [1 5 7 11 17]
HKEY_LOCAL_MACHINE\Software\AlejaCMaCo\AlejaCMaApp [1 5 7 11 17]
&lt;/PRE&gt;
&lt;P&gt;&lt;BR&gt;Notes:&lt;BR&gt;- With regini.exe I won't be able to set Users Full Control, but Everyone Full Control.&lt;BR&gt;- HKEY_CLASSES_ROOT = HKEY_LOCAL_MACHINE\Software\Classes&lt;BR&gt;&lt;BR&gt;See the following articles for details on the values used in the regini script:&lt;BR&gt;- &lt;A class="" href="http://support.microsoft.com/?kbid=237607" mce_href="http://support.microsoft.com/?kbid=237607"&gt;How to Use Regini.exe to Set Permissions on Registry Keys&lt;/A&gt;&lt;BR&gt;- &lt;A class="" href="http://support.microsoft.com/Default.aspx?kbid=245031" mce_href="http://support.microsoft.com/Default.aspx?kbid=245031"&gt;How to: Use a Script to Change Registry Permissions from the Command Line&lt;/A&gt;&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;And here you have the VBScript that will use regini.exe and its script:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;' Create temp file with the script that regini.exe will use
'
set oFSO = CreateObject("Scripting.FileSystemObject")
strFileName = oFSO.GetTempName
set oFile = oFSO.CreateTextFile(strFileName)
oFile.WriteLine "HKEY_LOCAL_MACHINE\Software\Classes\AlejaCMaTypelib [1 5 7 11 17]"
oFile.WriteLine "HKEY_LOCAL_MACHINE\Software\AlejaCMaCo\AlejaCMaApp [1 5 7 11 17]"
oFile.Close

' Change registry permissions with regini.exe
'
set oShell = CreateObject("WScript.Shell")
oShell.Run "regini " &amp;amp; strFileName, 8, true

' Delete temp file
'
oFSO.DeleteFile strFileName

WScript.Echo "Done!"
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope it helps.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8146408" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category></item><item><title>How to get the user running a VBScript</title><link>http://blogs.msdn.com/alejacma/archive/2008/03/11/how-to-get-the-user-running-a-vbscript.aspx</link><pubDate>Tue, 11 Mar 2008 10:07:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8146187</guid><dc:creator>alejacma</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/alejacma/comments/8146187.aspx</comments><wfw:commentRss>http://blogs.msdn.com/alejacma/commentrss.aspx?PostID=8146187</wfw:commentRss><description>&lt;P&gt;Hi all, welcome back,&lt;/P&gt;
&lt;P&gt;It's very easy to find out the &lt;STRONG&gt;user name&lt;/STRONG&gt; and&amp;nbsp;the &lt;STRONG&gt;domain name&lt;/STRONG&gt; of the user running a VBScript, and the &lt;STRONG&gt;computer&amp;nbsp;name &lt;/STRONG&gt;where it's running:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;Set objNet = CreateObject("WScript.NetWork") 

strInfo = "User Name is     " &amp;amp; objNet.UserName &amp;amp; vbCRLF &amp;amp; _
          "Computer Name is " &amp;amp; objNet.ComputerName &amp;amp; vbCRLF &amp;amp; _
          "Domain Name is   " &amp;amp; objNet.UserDomain

MsgBox strInfo
&lt;/PRE&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I hope this helps.&lt;/P&gt;
&lt;P&gt;Cheers,&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Alex (Alejandro Campos Magencio)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8146187" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/alejacma/archive/tags/VBScript/default.aspx">VBScript</category></item></channel></rss>