Thursday, December 23, 2010

Generate remote registry .reg file export with powershell

Why create a .reg file with powershell when regedit /e switch or file / export on regedit work without any problem ?
Well, just for fun, but this solution can be useful if you need to do this for 3000 computers.
Some others solution exist like for example psexec with regedit (or hacked regedit for gpo security problem), but c$ must exist (that's not always the case for security reasons)

And why export .reg ?
A .reg file is more easy to analyze or compare with another registry file because it is in a string format. And you can re-use it directly without use any other tool than regedit integrated windows tool (except if you can't run regedit on your computer)

[EDIT 2011-03-23]
A new version with bug correction in multistring format


You can download this powershell script here and to test it you can use this testfr.reg file

How to use this powershell script:
.\ExportRegistyToFile.ps1 'key_to_export' 'outputfile.txt'
for example if you want to test with my registry created with testfr.reg
.\ExportRegistyToFile.ps1 'HKEY_CURRENT_USER\Software\TestFr' 'output_testfr.txt'




#
# Export registry to .reg file like regedit /e
#
# by F.Richard 2010-10
# Modified 2011-03 : bug correction in multistring format
#


# Working with Registry Entries
# http://technet.microsoft.com/en-us/library/dd315394.aspx

# [Enum]::GetNames([Microsoft.Win32.RegistryValueKind])
# -> Unknown / String / ExpandString / Binary / DWord / MultiString / QWord

# [Enum]::GetNames([Microsoft.Win32.RegistryHive])
# -> ClassesRoot / CurrentUser / LocalMachine / Users / PerformanceData / CurrentConfig / DynData

set-psdebug -strict

$debug = $True
#$debug = $False

$errorPref = "Continue" # "Continue" "Stop" "Inquire" "SilentlyContinue"
$ErrorActionPreference = $errorPref

# Script Directory
$strCurDir = Split-Path -parent $MyInvocation.MyCommand.Path
Set-Location $strCurDir | Out-Null

# ----------------------------

# DllImport using http://www.pinvoke.net
$signature = @"
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenKeyEx(HDEFKEY hKey, string subKey, int ulOptions, REGSAM samDesired, out UIntPtr hkResult);

[DllImport("advapi32.dll", SetLastError=true)]
public static extern int RegCloseKey(UIntPtr hKey);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegQueryValueExW", SetLastError = true)]
public static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out uint lpType, System.Text.StringBuilder lpData, ref uint lpcbData);

[DllImport("advapi32.dll", EntryPoint = "RegEnumKeyEx")]
public static extern int RegEnumKeyEx(UIntPtr hKey, uint index, System.Text.StringBuilder lpName, ref uint lpcbName, IntPtr reserved, IntPtr lpClass, IntPtr lpcbClass, out long lpftLastWriteTime);

public enum REGSAM : int {
KEY_ALL_ACCESS = 0xF003F,
KEY_CREATE_LINK = 0x0020,
KEY_CREATE_SUB_KEY = 0x0004,
KEY_ENUMERATE_SUB_KEYS = 0x0008,
KEY_EXECUTE = 0x20019,
KEY_NOTIFY = 0x0010,
KEY_QUERY_VALUE = 0x0001,
KEY_READ = 0x20019,
KEY_SET_VALUE = 0x0002,
KEY_WOW64_32KEY = 0x0200,
KEY_WOW64_64KEY = 0x0100,
KEY_WRITE = 0x20006
}

public enum HDEFKEY : uint {
HKEY_CLASSES_ROOT = 0x80000000,
HKEY_CURRENT_USER = 0x80000001,
HKEY_LOCAL_MACHINE = 0x80000002,
HKEY_USERS = 0x80000003,
HKEY_CURRENT_CONFIG = 0x80000005,
HKEY_DYN_DATA = 0x80000006
}


"@

# Reg Val Types Declaration
# REG_NONE = 0 / REG_SZ = 1 / REG_EXPAND = 2 / REG_BINARY = 3 / REG_DWORD = 4 / REG_DWORD_BIG_ENDIAN = 5 / REG_LINK = 6
# REG_MULTI_SZ = 7 / REG_RESSOURCE_LIST = 8 / REG_FULL_RESSOURCE_DESCRIPTOR = 9 / REG_RESOURCE_REQUIREMENTS_LIST = 10 / REG_QWORD = 11

$RegValTypes = @{"0" = "Unknown"; "1" = "String"; "2" = "ExpandString"; "3" = "Binary";
"4" = "DWord"; "5" = "DWord_Big_Endian"; "6" = "Link"; "7" = "MultiString";
"8" = "Ressource_List"; "9" = "Full_Ressource_Descriptor"; "10" = "Ressource_Equirement_list"; "11" = "QWord"
}

# ----------------------------

Function transformBinReg {
Param(
[Ref] $ref_result_property,
[Ref] $ref_line,
[Ref] $ref_values,
[Int] $nb_values,
[Ref] $ref_comma,
[Ref] $ref_nb_bin,
[String] $multi
)
$ref_comma.value = $(if ($ref_comma.value) {$ref_comma.value} else {""})
$ref_nb_bin.value = $(if ($ref_nb_bin.value) {$ref_nb_bin.value} else {0})
$multi = $(if ($multi) {$multi} else {$False})

For ($i=0; $i -lt $nb_values; $i++) {
$ref_line.value = $ref_line.value + $ref_comma.value + ([String]::Format("{0:x2}", $ref_values.value[$i]))
$ref_nb_bin.value++
$ref_comma.value = ","
if (($ref_line.value.length -gt 75) -or ($ref_nb_bin.value -eq 25)) {
if (($result_property.length - $result_property.LastIndexOfAny("`r`n")) -gt 73) {
$ref_result_property.value = $ref_result_property.value + ",\`r`n "
}
$ref_result_property.value = $ref_result_property.value + $ref_line.value
If ($i -lt ($nb_values-1)) {
$ref_result_property.value = $ref_result_property.value + ",\`r`n "
}
$ref_comma.value = ""
$ref_line.value = ""
$ref_nb_bin.value=0
}
}

If ($multi -eq $True) {
if ($ref_nb_bin.value -eq 0) {
if ($ref_result_property.value.substring($ref_result_property.value.length - 5 , 5) -eq "2a,00" ) { # 00,\
$ref_result_property.value = $ref_result_property.value.substring(0,($ref_result_property.value.length-5)) + "00,00" # replace end string - "2a" by "00"
}
} elseif ($ref_nb_bin.value -eq 1) {
if ($ref_result_property.value.substring($ref_result_property.value.length - 8, 4) -eq "2a,\" ) { # 2a,\
$ref_result_property.value = $ref_result_property.value.substring(0,($ref_result_property.value.length-8)) + "00" + ",\`r`n " # replace end string - "2a" by "00"
}
} else {
$ref_line.value = $ref_line.value.substring(0,($ref_line.value.length-5)) + "00,00" # replace end string - "2a,00" by "00,00"
}
}
}


# ----------------------------

Function transformStringReg {
Param($strReg)

$result = $strReg -replace("\\", "\\") # replace \ by \\
$result = $result -replace('"', '\"')
return $result
}

# ----------------------------

Function ExportReg {
Param(
[String] $hiveKey,
[String] $registrypath,
[String] $Computername,
[String] $outputfile
)
$computerKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hiveKey, $Computername)
$Key = $computerKey.OpenSubKey($registrypath,$false)
If(!($Key)){Return}

$result = "[" + $Key.Name + "]" + "`r`n"
If ($debug) { Write-Host $result }
$SubKeyValues = $Key.GetValueNames()
foreach($SubKeyValue in $SubKeyValues) {
$propertyname = $SubKeyValue
$propertyvalue = $Key.GetValue($SubKeyValue)
$result_property = ""
$TypeNameOfValue = ""
If ($propertyname -eq "") {
$TypeNameOfValue = "(default)"
$hKey = New-Object UIntPtr
$keyname = $key.Name
$hKeyLeft = $keyname.Substring(0, $keyname.IndexOf('\'))
$hKeyRight = $keyname.Substring( ($keyname.IndexOf('\') + 1) , ($keyname.Length - $keyname.IndexOf('\') - 1) )
$result_func = [Win32Functions.Registry]::RegOpenKeyEx($hKeyLeft, $hKeyRight, 0, "KEY_READ", [ref] $hKey)
if ($result_func -eq 0) {
$valuename = "" # (default) = ""
$lpType = New-Object uint32
$lpData = New-Object System.Text.StringBuilder
$lpcbData = New-Object uint32
# Get Type & Size
$result_func = [Win32Functions.Registry]::RegQueryValueEx($hKey, $valuename, $Null, [ref] $lpType, $lpData, [ref] $lpcbData)
# ERROR_FILE_NOT_FOUND = 2 $result_func
$TypeNameOfValue = $RegValTypes["$lpType"]
}
$result_func = [Win32Functions.Registry]::RegCloseKey($hKey)
$result_name = "@"
$property_name = ""

} else {
$ErrorActionPreference = "Continue" #"SilentlyContinue"
$TypeNameOfValue = $key.GetValueKind($propertyname) # $property.TypeNameOfValue not so precise String = ExpandString too
If ($TypeNameOfValue -eq "") { # OpenSaveMRU\* problem
$TypeNameOfValue = "TrapError"
}
$ErrorActionPreference = $errorPref
$result_name = "`"" + $(transformStringReg($propertyname)) + "`""
$property_name = $propertyname
}

Switch ($TypeNameOfValue) {
# TrapError
"TrapError" {
$result_property = ""
} # End TrapError

# String "System.String"
"String" {
$result_val = transformStringReg($propertyvalue)
$result_property = $result_name + "=`"" + $result_val + "`""
} # end String

# ExpandString "System.String"
"ExpandString" {
$result_property = ""
$tmpvalues = ($key.GetValue($property_name,"error",[Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames))
$values = [System.Text.Encoding]::UNICODE.GetBytes($tmpvalues + "*") # * = 2a
$line = $result_name + "=hex(2):"
$comma = ""
$nb_bin = 0
transformBinReg ([Ref]$result_property) ([Ref]$line) ([Ref]$values) ($values.count) ([Ref]$comma) ([Ref]$nb_bin) $True
$result_property = $result_property + $line
} # ExpandString


# MultiString "System.String[]"
"MultiString" {
$result_property = ""
$tmpvalues = $propertyvalue
$line = $result_name + "=hex(7):"

$comma = ""
$nb_bin=0
foreach ($val in $tmpvalues) {
$values = [System.Text.Encoding]::UNICODE.GetBytes($val + "*") # * = 2a
transformBinReg ([Ref]$result_property) ([Ref]$line) ([Ref]$values) ($values.count) ([Ref]$comma) ([Ref]$nb_bin) $True
}
$result_property = $result_property + $line

# Multistring
if ($result_property.substring($result_property.length - 1, 1) -eq ":") { # test if multistring has a value
$result_property = $result_property + "00,00" # End of multistring
} else {
if ( ($result_property.length - $result_property.LastIndexOfAny("`r`n")) -gt 73) {
$result_property = $result_property + ",00,\`r`n 00" # End of multistring
} else {
$result_property = $result_property + ",00,00" # End of multistring
}
}
} # MultiString

# Binary "System.Byte[]"
"Binary" {
$result_property = ""
$values = $propertyvalue
$line = $result_name + "=hex:"
$comma = ""
$nb_bin=0
transformBinReg ([Ref] $result_property) ([Ref] $line) ([Ref] $values) $values.count ([Ref] $comma) ([Ref] $nb_bin)
$result_property = $result_property + $line
} # End Binary


# DWord "System.Int32"
"DWord" {
$val = ([String]::Format("{0:x8}", $propertyvalue))
$result_property = $result_name + "=dword:$val"
} # DWord

# QWord
"QWord" {
$val = ([String]::Format("{0:x16}", $propertyvalue))
$result_property = $result_name + "=hex(b):" + $val.Substring(14,2) + "," + $val.Substring(12,2) + "," + $val.Substring(10,2) + "," + $val.Substring(8,2) + "," + $val.Substring(6,2) + "," + $val.Substring(4,2) + "," + $val.Substring(2,2) + "," + $val.Substring(0,2)
} # QWord

# Unknown
"Unknown" {
# GetValue does not support reading values of type REG_NONE or REG_LINK
# http://msdn.microsoft.com/en-us/library/kk88y0s0.aspx
$hKey = New-Object UIntPtr
$keyname = $key.Name
$hKeyLeft = $keyname.Substring(0, $keyname.IndexOf('\'))
$hKeyRight = $keyname.Substring( ($keyname.IndexOf('\') + 1) , ($keyname.Length - $keyname.IndexOf('\') - 1) )
$result_func = [Win32Functions.Registry]::RegOpenKeyEx($hKeyLeft, $hKeyRight, 0, "KEY_READ", [ref] $hKey)

$values = ""
$nb_values = 0
if ($result_func -eq 0) {
$lpType = New-Object uint32
$lpData = New-Object System.Text.StringBuilder
$lpcbData = New-Object uint32
# Get Type & Size
$result_func = [Win32Functions.Registry]::RegQueryValueEx($hKey, $property_name, $Null, [ref] $lpType, $lpData, [ref] $lpcbData)
# ERROR_MORE_DATA = 234
if ($result_func -eq 234) {
If ($lpType -eq 0) {
$lpData = New-Object System.Text.StringBuilder ([int] $lpcbData)
$result_func = [Win32Functions.Registry]::RegQueryValueEx($hKey, $property_name, $Null, [ref] $lpType, $lpData, [ref] $lpcbData)
$values = [System.Text.Encoding]::UNICODE.GetBytes($lpData) # $values.count can be different from $lpcbData
$nb_values = $lpcbData
}

}
}
$result_func = [Win32Functions.Registry]::RegCloseKey($hKey)

$result_property = ""
$line = $result_name + "=hex(0):"
$comma = ""
$nb_bin=0
transformBinReg ([Ref]$result_property) ([Ref]$line) ([Ref]$values) ($nb_values) ([Ref]$comma) ([Ref]$nb_bin)
$result_property = $result_property + $line
} # End Unknown

# Default -> error typename not defined
Default {
$result_property=";ERROR: type $TypeNameOfValue not defined " + "path:" + $key.PsPath + " Name:" + $propertyname
Write-Host $result_property
} # end Default
}
$result = $result + $result_property + "`r`n"
}
#If ($debug) { Write-Host $result }
$result | Out-File -append $outputfile
$result=""

$SubKeyNames = $Key.GetSubKeyNames()
foreach($subkeyname in $SubKeyNames) {
ExportReg $hiveKey "$registrypath\$subkeyname" $Computername $outputfile
}


}


# ----------------------------

Function TestFilePath {
Param($filename)

If ((Test-Path("$filename")) -eq $False){
If ((Test-Path("$strCurDir\$filename")) -eq $False){
Write-Host "ERROR : file $filename NOT exist"
Write-Host "ERROR : file $strCurDir\$filename NOT exist"
Exit
} Else {
$filename = "$strCurDir\$filename"
}
}

return $filename
}

# ----------------------------

#
# MAIN PROGRAM
#

# Verify Arguments Number
If($Args.Count -lt 2) {
Write-Host "Syntax:"$MyInvocation.MyCommand.Name "registry outputfilename [computername]"
Write-Host " Example:"$MyInvocation.MyCommand.Name" 'HKCM:\Software\Microsoft\Windows\CurrentVersion\Run' 'outputfile.txt' "
Write-Host " Example:"$MyInvocation.MyCommand.Name" 'HKEY_CURRENT_USER\Control Panel\Desktop' 'outputfile.txt' computername"
Write-Host
Break
}

# Registry Path
$registrypath = $Args[0]

# Output file
$outputfile = $Args[1]

# Computername
if ($Args.Count -gt 2) {
$Computername = $Args[2]
} else {
$Computername = $env:Computername
}
If ($debug) { Write-Host $Computername }


# Register registry functions
If (-not ("Win32Functions.Registry" -as [Type])) {
$type = Add-Type -MemberDefinition $signature -Name Registry -Namespace Win32Functions -Using System.Text -PassThru
} else {
If ($debug) { Write-Host "Win32Functions.Registry already Registered" }
}

# Write output file with registry informations
$Content = "Windows Registry Editor Version 5.00" + "`r`n" # "REGEDIT4"
$Content | Out-File $outputfile
$hKeyLeft = $registrypath.Substring(0, $registrypath.IndexOf('\'))
$hKeyRight = $registrypath.Substring( ($registrypath.IndexOf('\') + 1) , ($registrypath.Length - $registrypath.IndexOf('\') - 1) )
switch ($hKeyLeft) {
"HKEY_CLASSES_ROOT" { $hiveKey = "ClassesRoot"}
"HKEY_CURRENT_USER" { $hiveKey = "CurrentUser"}
"HKEY_LOCAL_MACHINE" { $hiveKey = "LocalMachine"}
"HKEY_USERS" { $hiveKey = "Users"}
"HHKEY_CURRENT_CONFIG" { $hiveKey = "CurrentConfig"}
default {
Write-Host "ERROR: you must use one of the following key: HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKCU, HKLM, HKU, HKCC"
Exit 1
}
}

ExportReg $hiveKey $hKeyRight $Computername $outputfile

# ----------------------------

Monday, November 29, 2010

How to develop your own VMWare application in C#

First, download and install "Visual Studio Express 2008" (http://www.microsoft.com/express/Downloads/)
Then download and install "VMware vSphere Web Services SDK" (http://www.vmware.com/download/sdk/)

In file Build2008.cmd (from your "VMware vSphere Web Services SDK directory\samples\DotNet" directory) if you installed your VS2008 Express in an other directory than default directory modify line
set VSINSTALLDIR="C:\Program Files\Microsoft Visual Studio 9.0"

Run a command line prompt.

Verify in command line prompt you can run
- WSDL.exe (by default at C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin)
- csc.Exe (by default at C:\WINDOWS\Microsoft.NET\Framework\v3.5)
- VCSExpress.exe (by default at C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE)

Else add path of these programs with something like this in command line before running Build2008.cmd:
Set path=%path%;C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin;C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE

In command line prompt do not forget to run this line too:
set WSDLFILE=your VMware vSphere Web Services SDK directory\wsdl

Then run Build2008.cmd
You should have all your .dll libraries created.

Run in your VMware vSphere Web Services SDK directory\samples\DotNet\cs\SimpleClient\bin\Debug this line to verify all is ok:
SimpleClient.exe https://yourvc/sdk yourvcuser yourvcpassword

Now, if you need to create your own application, just add line
using Vim25Api;
and in your project "add reference" tab browse
"Vim25Service2008.dll" and "Vim25Service2008.XmlSerializers.dll"

Use examples in your vSphere Web Services SDK\directory\samples\DotNet\cs for helping you to create your 1st C# vmware application

Tuesday, November 23, 2010

How to create multiple local account with all options and group add

A VBscript create today for technical support need. (Download it here)
For use it run
cscript createLocalUser.vbs /input:users.txt

Create a file users.txt with this format
user;password;fullname;description;options;groupstoadd

For options field, you can use these next options: (with | between each option if you need to add options)
ADS_UF_SCRIPT : The logon script is executed
ADS_UF_ACCOUNTDISABLE : The user account is disabled.
ADS_UF_HOMEDIR_REQUIRED : The home directory is required
ADS_UF_LOCKOUT : The account is currently locked out.
ADS_UF_PASSWD_NOTREQD : No password is required.
ADS_UF_PASSWD_CANT_CHANGE : The user cannot change the password
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED : The user can send an encrypted password.
ADS_UF_DONT_EXPIRE_PASSWD : When set, the password will not expire on this account
ADS_UF_SMARTCARD_REQUIRED : When set, this flag will force the user to log on using a smart card.
ADS_UF_PASSWORD_EXPIRED : The user password has expired.

USER_MUST_CHANGE_PWD :For this script only, for "User Must Change Password at Next Logon"

For group field, add | between each group if you need to add multiple groups

For example:

user;Passw0rd;fullname;description;USER_MUST_CHANGE_PWD;Administrators|Power Users
user2;Passw0rd;fullname;description;USER_MUST_CHANGE_PWD|ADS_UF_ACCOUNTDISABLE;groups



'
' Create Local User
'
' F.RICHARD
' 2010 November
'
'
Option Explicit

' OpenTextFile Const
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8


' Detect WScript or CScript
'
If InStr(LCase(WScript.FullName), "wscript")>0 Then ' ex: FullName = C:\WINNT\system32\wscript.exe
WScript.Echo "This script must be run under CScript."
WScript.Quit
End If


' Get Path
'
Dim strScriptFullName, strScriptPath, strScriptName
strScriptName = WScript.ScriptName
strScriptFullName = WScript.ScriptFullName ' ex: C:\Program Files\MyFolder\MyProg.exe
strScriptPath = Left(strScriptFullName, InStrRev(strScriptFullName, "\") - 1) ' ex: C:\Program Files\MyFolder


' Check for required arguments.
If (Wscript.Arguments.Count < 1 or WScript.Arguments.Named.Exists("?")) Then
Call Help(strScriptName)
End If

' input parameter
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")
Dim objInputFile, strInputFile
If WScript.Arguments.Named.Exists("input") Then
strInputFile = WScript.Arguments.Named("input")

If Not isFileExist(strInputFile) Then
If Not isFileExist(strScriptPath & "\" & strInputFile) Then
WScript.Echo strInputFile & " File Not Exist !"
WScript.Echo strScriptPath & "\" & strInputFile & " File Not Exist !"
WScript.Quit
End If
strInputFile = strScriptPath & "\" & strInputFile
End If
Set objInputFile = objFso.OpenTextFile(strInputFile, ForReading)
Else
WScript.Echo "You must defined an argument /input ex: /input:input.txt !"
WScript.Quit

End If

' List userFlag Values for a Local User Account
' http://gallery.technet.microsoft.com/ScriptCenter/en-us/ab4d85d6-ca38-44da-8fc2-984d70ea5f36?persist=True
Dim dicUAC
Set dicUAC = CreateObject("Scripting.Dictionary")
dicUAC.Add "ADS_UF_SCRIPT", &H0001 ' The logon script is executed
dicUAC.Add "ADS_UF_ACCOUNTDISABLE" , &H0002 ' The user account is disabled.
dicUAC.Add "ADS_UF_HOMEDIR_REQUIRED" , &H0008 ' The home directory is required
dicUAC.Add "ADS_UF_LOCKOUT" , &H0010 ' The account is currently locked out.
dicUAC.Add "ADS_UF_PASSWD_NOTREQD" , &H0020 ' No password is required.
dicUAC.Add "ADS_UF_PASSWD_CANT_CHANGE" , &H0040 ' The user cannot change the password
dicUAC.Add "ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED" , &H0080 ' The user can send an encrypted password.
dicUAC.Add "ADS_UF_DONT_EXPIRE_PASSWD" , &H10000 ' When set, the password will not expire on this account
dicUAC.Add "ADS_UF_SMARTCARD_REQUIRED" , &H40000 ' When set, this flag will force the user to log on using a smart card.
dicUAC.Add "ADS_UF_PASSWORD_EXPIRED" , &H800000 ' The user password has expired.

dicUAC.Add "USER_MUST_CHANGE_PWD" , &H0000 ' For this script only, for "User Must Change Password at Next Logon"


' Computer
Dim objWshNetwork, strComputername, objComputer
Set objWshNetwork = CreateObject("WScript.Network" )
strComputername = objWshNetwork.ComputerName
Set objComputer = GetObject("WinNT://" & strComputername)


Dim objWshShell
Set objWshShell = CreateObject("WScript.Shell")

Dim strCommandLine, strLine, arrLine, objFolder, colSubfolders, strFolderName, return
Dim strSource, objWMIServiceSrc, strComputerSrc, strPathSrc, strDestination, strLogFile
Do While objInputFile.AtEndOfStream <> True
strLine = Trim(objInputFile.Readline)
If (Len(strLine)>1) Then
return = CreateLocalUser(strLine, strComputername, objComputer, dicUAC)
End If
Loop

objInputFile.Close

'--------------------


' Help
'
' Help File
'

Sub Help(ByRef strScriptName)
WScript.Echo strScriptName & " Arguments" & vbCrLf _
& vbTab & "/input:""file name""" & vbCrLf _
& vbTab & "/? or nothing for this" & vbCrLf _
& vbCrLf & "Example:" & vbCrLf _
& "cscript " & strScriptName & " /input:""c:\input.txt"" " & vbCrLf
WScript.Quit(0)
End Sub


'--------------------

' isFileExist
'
' Test if File Exist
'
Function IsFileExist(ByRef strInputFile)
Dim iReturn
iReturn = False

Dim objFSO
On Error Resume Next
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strInputFile) Then
iReturn = True
End If
Set objFSO = Nothing
On Error Goto 0

IsFileExist = iReturn
End Function

'--------------------

' CreateLocalUser
'
' Create a local user
'
Function CreateLocalUser(ByRef strLine, ByRef strComputername, ByRef objComputer, ByRef dicUAC)
'line =
'Username;Password;FullName;Description;option1|option2|option3;group|group2
Dim arrLine, strUser, strPassword, strFullName, strDescription
Dim strGroupsToAdd, strOptions, strOption, arrOptions, funcReturn, UACFlags, errorMsg, return
funcReturn = False
arrLine = Split(strLine, ";")
If (UBound(arrLine) = 5) Then
strUser = arrLine(0) ' Username
strPassword = arrLine(1) ' Password
strFullName = arrLine(2) ' Full Name
strDescription = arrLine(3) ' Description
strOptions = arrLine(4) ' option1|option2|option3
strGroupsToAdd = arrLine(5) ' group|group2


' Create Local User
WScript.Echo "Create user:" & strUser
Dim objUser
Set objUser = objComputer.Create("user", strUser)

' Set Password
objUser.SetPassword strPassword

' Save user information
On Error Resume Next
objUser.Setinfo
If Err.Number = 0 Then ' password restrictions or any other problems
On Error Goto 0
' FullName / Description
objUser.Fullname = strFullName
objUser.Description = strDescription
objUser.Setinfo

' Get User Object
Dim strObjPath
strObjPath = "WinNT://" & strComputername & "/" & strUser
Set objUser = GetObject(strObjPath)
UACFlags = objUser.Get("UserFlags")

arrOptions = Split(strOptions, "|")
For Each strOption in arrOptions
' Enable "User Must Change Password at Next Logon"
If (UCase(Trim(strOption)) = "USER_MUST_CHANGE_PWD") Then
objUser.Put "PasswordExpired", 1
objUser.SetInfo
Else
If (dicUAC.Exists(UCase(Trim(strOption)))) Then
UACFlags = UACFlags OR dicUAC.Item(UCase(Trim(strOption)))
End If
End If
Next

objUser.Put "userFlags", UACFlags
objUser.SetInfo
funcReturn = True
Else
Select Case (Err.Number)
Case &H80070056
errorMsg = "The specified password for " & strUser & " is not correct."
Case &H800708C5
errorMsg = "The specified password does not meet policy requirements"
Case &H800708B0
errorMsg = "The user " & strUser & " already exists."
Case &H80070035
errorMsg = "Object path " & strObjPath & " not found"
Case Else
errorMsg = "Unexpected error"
End Select
WScript.Echo "ERROR creating user:" & strUser & " ERROR:" & errorMsg & " Error number:" & Err.Number & " (&H" & Hex(Err.Number) & ") Description:" & Err.Description & " Source:" & Err.Source
End If

Dim arrGroups, strGroup
arrGroups = Split(strGroupsToAdd, "|")
For Each strGroup in arrGroups
return = AddGroupToUser(strComputername, strUser, strGroup)
Next

Else
WScript.Echo "Error In line:" & strLine
End If

CreateLocalUser = funcReturn
End Function


'--------------------

' AddGroupToUser
'
' Add Group To User
'
Function AddGroupToUser(ByRef strComputername, ByRef strUser, ByRef strGroup)
' Get Group Object
Dim strObjGrpPath, objGroup, strObjUsrPath, objUser, funcReturn
Dim errorMsg
funcReturn = False

On Error Resume Next
strObjGrpPath = "WinNT://" & strComputername & "/" & strGroup & ",group"
Set objGroup = GetObject(strObjGrpPath)
If Err.Number = 0 Then ' group unknown or any other problems
strObjUsrPath = "WinNT://" & strComputername & "/" & strUser
Set objUser = GetObject(strObjUsrPath)
If Err.Number = 0 Then ' password restrictions or any other problems
objGroup.Add(objUser.ADsPath) ' Add group to user
If Err.Number = 0 Then
funcReturn = True
Else
Select Case (Err.Number)
Case &H80070562
errorMsg = "The specified account name " & strUser & " is already a member of the local group " & strGroup
Case Else
errorMsg = "Unexpected error"
End Select
WScript.Echo "ERROR (3) adding group to user:" & strUser & " ERROR:" & errorMsg & " Error number:" & Err.Number & " (&H" & Hex(Err.Number) & ") Description:" & Err.Description & " Source:" & Err.Source

End If
Else
Select Case (Err.Number)
Case Else
errorMsg = "Unexpected error"
End Select
WScript.Echo "ERROR (2) adding group to user:" & strUser & " ERROR:" & errorMsg & " Error number:" & Err.Number & " (&H" & Hex(Err.Number) & ") Description:" & Err.Description & " Source:" & Err.Source

End If

Else
Select Case (Err.Number)
Case &H800708AC
errorMsg = "The specified local group " & strGroup & " not found"
Case &H80070560
errorMsg = "The specified local group " & strGroup & " does not exist. "
Case Else
errorMsg = "Unexpected error"
End Select
WScript.Echo "ERROR (1) adding group to user:" & strUser & " ERROR:" & errorMsg & " Error number:" & Err.Number & " (&H" & Hex(Err.Number) & ") Description:" & Err.Description & " Source:" & Err.Source

End If

On Error Goto 0
AddGroupToUser = funcReturn
End Function

Wednesday, November 10, 2010

Cannot copy filename Invalid MS-DOS function error

An error "Cannot copy xxxxxx Invalid MS-DOS function" can appear when you copy big files from a server to an other. For your information, that could be because network administrators have decided to drop connection for large file, after 1gb or 2gb for example.

Cannot copy xxxxxx Invalid MS-DOS function

Wednesday, November 3, 2010

Extend Windows system volume disk easily

A great tool from Dell which permit on Windows XP, 2000 & 2003 to extend system volume:
Dell Extpart (Alternative Download)

Work on physical and virtual disk.

Friday, October 29, 2010

Christophe BLUTEAU's site

An other interesting site on powershell and exchange, but in french, is Christophe BLUTEAU's site
http://aidexchange.fr/

Tuesday, October 26, 2010

Get Windows Network configuration Remotely

Today a 1 hour script. We need to know some network informations on a lot of computers, especially DNS search order.

In powershell, that's easy done by using

$strComputername = "localhost"
$NICs = Get-WmiObject Win32_NetworkAdapterConfiguration -Computername $strComputername | Where {$_.IPEnabled -eq "TRUE"}
foreach ($nic in $nics) {
$nic.DNSServerSearchOrder
}



Unfortunately, for a lot of reason, I can't use powershell. No time to lose. So I use one of my old vbscript and adapt it using information coming from Microsoft Site(Automating TCP/IP Networking on Clients - Part 2: Scripting Basic TCP/IP Networking on Clients)

That's the result that you can download too



'
' Get All Network Configuration
'
'
' F.RICHARD
' 2010 October
'

Option Explicit
Const ForReading = 1, ForWriting = 2, ForAppending = 8


' Detect WScript or CScript
'
If InStr(LCase(WScript.FullName), "wscript")>0 Then ' ex: FullName = C:\WINNT\system32\wscript.exe
WScript.Echo "This script must be run under CScript."
WScript.Quit
End If


' Get Path
'
Dim strScriptFullName, strScriptPath, strScriptName
strScriptName = WScript.ScriptName
strScriptFullName = WScript.ScriptFullName ' ex: C:\Program Files\MyFolder\MyProg.exe
strScriptPath = Left(strScriptFullName, InStrRev(strScriptFullName, "\") - 1) ' ex: C:\Program Files\MyFolder


' Variables For File
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")


' Input parameter
'
Dim objInputFile, strInputFile
If WScript.Arguments.Named.Exists("input") Then
strInputFile = WScript.Arguments.Named("input")

If Not isFileExist(strInputFile) Then
If Not isFileExist(strScriptPath & "\" & strInputFile) Then
WScript.Echo strInputFile & " File Not Exist !"
WScript.Echo strScriptPath & "\" & strInputFile & " File Not Exist !"
WScript.Quit
End If
strInputFile = strScriptPath & "\" & strInputFile
End If
Set objInputFile = objFso.OpenTextFile(strInputFile, ForReading)
Else
WScript.Echo "You must defined an argument /input ex: /input:input.txt !"
WScript.Quit

End If


' Output parameter
Dim strOutputFile, objOutputFile
If WScript.Arguments.Named.Exists("output") Then
strOutputFile = WScript.Arguments.Named("output")
Else
WScript.Echo "You must defined an argument /output ex: /input:output.txt !"
WScript.Quit

End If
On Error Resume Next
Set objOutputFile = objFSO.CreateTextFile(strOutputFile, ForWriting, True) ' delete file
If (Err.Number <> 0) Then
WScript.Echo strOutputFile & " file - permission denied or file already opened"
On Error GoTo 0
WScript.Quit
End If
On Error GoTo 0




' Put servers in Dictionary
'
Dim objItem, objDictionary, objTextFile, strNextLine, i
Set objDictionary = CreateObject("Scripting.Dictionary")
Set objTextFile = objFSO.OpenTextFile (strInputFile, ForReading)
i = 0
Do Until objTextFile.AtEndOfStream
strNextLine = Trim(objTextFile.Readline)
If (Len(strNextLine)>1) Then
If Not Left(strNextLine, 1) = "#" Then
objDictionary.Add i, strNextLine
i = i + 1
End If
End If
Loop

Dim line
line = "Hostname;NICDescription;MACAddress;IPAddress;IPSubnet;DefaultIPGateway;DHCPEnabled;DHCPServer;DNSDomain;DNSDomainSuffixSearchOrder;WINSPrimaryServer;WINSSecondaryServer;DNSServerSearchOrder1;DNSServerSearchOrder2"
WScript.Echo line
objOutputFile.WriteLine(line)

Dim objWMIService, objWMIServiceRemote, colAdapters, objAdapter
Dim strComputerName, computers, objComputer
Dim DNSHostname, NICDescription, MACAddress, IPAddress, IPSubnet, DefaultIPGateway
Dim DHCPEnabled, DHCPServer, DNSDomain, DNSDomainSuffixSearchOrder, WINSPrimaryServer, WINSSecondaryServer
Dim DNSServerSearchOrder
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
For Each objItem in objDictionary
strComputerName = objDictionary.Item(objItem)
WScript.Echo strComputerName
Set Computers = objWMIService.ExecQuery ("Select * from Win32_PingStatus Where Address = '" & strComputerName & "'")
For Each objComputer in Computers
If objComputer.StatusCode = 0 Then
' suppress errors in case of errors
On Error Resume Next
Set objWMIServiceRemote = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputerName & "\root\cimv2")

' Only query Enabled NIC
Set colAdapters = objWMIServiceRemote.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True")
'Wscript.echo Err.Number & ";" & Err.Description

Select Case Err.number
'Case "-2147022676" :
' line = strComputerName & ";" & strGroupToCheck & " group NOT EXIST"
' WScript.Echo line
' objOutputFile.WriteLine(line)

Case "-2147024843" :
line = strComputerName & ";INVALID Network Path OR insufficient access rights"
WScript.Echo line
objOutputFile.WriteLine(line)

'Case "-2147463168" :
' line = strComputerName & ";INVALID ADSI WinNT://" & strComputerName & "/" & strGroupToCheck & ",group"
' WScript.Echo line
' objOutputFile.WriteLine(line)

Case Else :
For Each objAdapter in colAdapters
' DNS Host name
DNSHostname =""
DNSHostname = objAdapter.DNSHostName


' NIC Description
NICDescription = objAdapter.Description


' MAC Address
MACAddress = ""
MACAddress = objAdapter.MACAddress


' IP Address
IPAddress = ""
If Not IsNull(objAdapter.IPAddress) Then
For i = 0 To UBound(objAdapter.IPAddress)
If (IPAddress = "") Then
IPAddress = objAdapter.IPAddress(i)
Else
IPAddress = IPAddress & "_" & objAdapter.IPAddress(i)
End If
Next
End If


' IP Subnet
IPSubnet = ""
If Not IsNull(objAdapter.IPSubnet) Then
For i = 0 To UBound(objAdapter.IPSubnet)
If (IPSubnet = "") Then
IPSubnet = objAdapter.IPSubnet(i)
Else
IPSubnet = IPSubnet & "_" & objAdapter.IPSubnet(i)
End If
Next
End If


' Default Gateway
DefaultIPGateway = ""
If Not IsNull(objAdapter.DefaultIPGateway) Then
For i = 0 To UBound(objAdapter.DefaultIPGateway)
If (DefaultIPGateway = "") Then
DefaultIPGateway = objAdapter.DefaultIPGateway(i)
Else
DefaultIPGateway = DefaultIPGateway & "_" & objAdapter.DefaultIPGateway(i)
End If
Next
End If


' DHCP Enabled
DHCPEnabled = ""
DHCPEnabled = objAdapter.DHCPEnabled


' DHCP server
DHCPServer = ""
DHCPServer = objAdapter.DHCPServer


' DNS Domain
DNSDomain = objAdapter.DNSDomain


' DNS Domain Suffix Search Order
DNSDomainSuffixSearchOrder = ""
If Not IsNull(objAdapter.DNSDomainSuffixSearchOrder) Then
For i = 0 To UBound(objAdapter.DNSDomainSuffixSearchOrder)
If (DNSDomainSuffixSearchOrder = "") Then
DNSDomainSuffixSearchOrder = objAdapter.DNSDomainSuffixSearchOrder(i)
Else
DNSDomainSuffixSearchOrder = DNSDomainSuffixSearchOrder & "_" & objAdapter.DNSDomainSuffixSearchOrder(i)
End If
Next
End If

WINSPrimaryServer = objAdapter.WINSPrimaryServer
WINSSecondaryServer = objAdapter.WINSSecondaryServer

' DNS Search Order
DNSServerSearchOrder = ""
If Not IsNull(objAdapter.DNSServerSearchOrder) Then
For i = 0 To UBound(objAdapter.DNSServerSearchOrder)
DNSServerSearchOrder = DNSServerSearchOrder & ";" & objAdapter.DNSServerSearchOrder(i)
Next
End If


line = DNSHostname & ";" & NICDescription & ";" & MACAddress & ";" & IPAddress & ";" & IPSubnet & ";" & DefaultIPGateway & ";" & DHCPEnabled & ";" & DHCPServer & ";" & DNSDomain & ";" & DNSDomainSuffixSearchOrder & ";" & WINSPrimaryServer & ";" & WINSSecondaryServer & DNSServerSearchOrder
WScript.Echo line
objOutputFile.WriteLine(line)
Next

End Select
On Error Goto 0
Else
line = strComputerName & ";NOT available"
WScript.Echo line
objOutputFile.WriteLine(line)
End If
Next
Next


'--------------------


' Help
'
' Help File
'

Sub Help(ByRef strScriptName)
WScript.Echo strScriptName & " Arguments" & vbCrLf _
& vbTab & "/input:""filename_for_server_list""" & vbCrLf _
& vbTab & "/output:""filename_for_output""" & vbCrLf _
& vbTab & "/? or nothing for this" & vbCrLf _
& vbCrLf & "Example:" & vbCrLf _
& "cscript " & strScriptName & " /input:""servers.txt"" /input:""result.csv"" " & vbCrLf
WScript.Quit(0)
End Sub


'--------------------

' isFileExist
'
' Test if File Exist
'
Function IsFileExist(ByRef strInputFile)
Dim iReturn
iReturn = False

Dim objFSO
On Error Resume Next
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strInputFile) Then
iReturn = True
End If
Set objFSO = Nothing
On Error Goto 0

IsFileExist = iReturn
End Function


'--------------------

' pingComputer
'
' Ping Test
'
Function pingComputer(strComputerName)

Dim pingStatus, objPing, objStatus
pingStatus = false
Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}")
Set objPing = objPing.ExecQuery("select * from Win32_PingStatus where address = '" & strComputerName & "'")
For Each objStatus in objPing
If IsNull(objStatus.StatusCode) or objStatus.StatusCode<>0 Then
pingComputer = false
Else
pingComputer = true
End If
Next


End Function

'--------------------