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

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

Thursday, October 21, 2010

Display System Error Description in Powershell

In a powershell script, I need to see description system errors and constant value

I find the solution on Ward Horsfall site
http://wiki.slothx.net/index.php?title=Powershell.


# Decode a Win32 Error Code. Example below x5A8.

$err_msg = (new-object System.ComponentModel.Win32Exception(0x5A8));
$err_msg;
Scroll bar range cannot be greater than MAXLONG



For information, you can find list of System Error Codes at
http://msdn.microsoft.com/en-us/library/ms681381(v=VS.85).aspx
and
here some informations about FormatMessage

Friday, October 15, 2010

Powershell with MySql

To do Mysql select with powershell, you first must download on MySQL site the MySQL Connector .NET

For information, on my computer, I have a "CAQuietExec Failed" error with mysql connector v6.2.5. No problem with v6.1.5 (MySQL Connector Previous Version)

To use Mysql connector, you must load assembly then use MySql connection. You can download script here


#
#
# Export MySQL Infos
#
# by F.Richard 2010-09
#

set-psdebug -strict


# Script Directory
$strCurDir = Split-Path -parent $MyInvocation.MyCommand.Path
Set-Location $strCurDir | Out-Null
#Write-Host "Current Dir: $strCurDir"

#$debug = $True
$debug = $False

# need MySQL Connector
#
# in PS2.0 Add-Type -AssemblyName
[void][System.Reflection.Assembly]::LoadWithPartialName("MySql.Data")

# ***********************************************



Function executeMYSQLQuery {
Param ([hashtable]$options)
$strServer = $(if ($options.ContainsKey("strServer")) {$options["strServer"]} else {"(localhost)"})
$strDatabase = $(if ($options.ContainsKey("strDatabase")) {$options["strDatabase"]} else {"default"})
$strCommandTimeout = $(if ($options.ContainsKey("strCommandTimeout")) {$options["strCommandTimeout"]} else {"15"})
$strPort = $(if ($options.ContainsKey("strPort")) {";Port=" + $options["strPort"]} else {""})

$strUser = $(if ($options.ContainsKey("strUser")) {";User Id=" + $options['strUser']} else {""})
$strPassword = $(if ($options.ContainsKey("strPassword")) {";Password=" + $options['strPassword']} else {""})
$strAuthentication = $(if ($strUser -and $strPassword) {"$strUser$strPassword"} else {""})
$strMisc = $(if ($options.ContainsKey("strMisc")) {";" + $options['strMisc']} else {""})

$strQuery = $(if ($options.ContainsKey("strQuery")) {$options['strQuery']} else {""})

If ($debug) {
Write-Host "DEBUG: strServer:" $strServer
Write-Host "DEBUG: strDatabase:" $strDatabase
Write-Host "DEBUG: strCommandTimeout:" $strCommandTimeout
Write-Host "DEBUG: strPort:" $strPort
Write-Host "DEBUG: strUser:" $strUser
Write-Host "DEBUG: strPassword:" $strPassword
Write-Host "DEBUG: strAuthentication:" $strAuthentication
Write-Host "DEBUG: strMisc:" $strMisc
Write-Host "DEBUG: strQuery:" $strQuery
}

# Create SqlConnection
$conn = New-Object ('MySql.Data.MySqlClient.MySqlConnection')
If (!$conn) {
Write-Host "ERROR: MySql Connection could not be created!"
Exit
}
$connString = "Server=$strServer$strAuthentication;Database=$strDatabase$strPort$strMisc"
If ($debug) {
Write-Host "DEBUG: Sql Connection String:" $connString
}

# more information http://www.connectionstrings.com/mysql
$conn.ConnectionString = $connString
$dtResult = New-Object "System.Data.DataTable"
$conn.Open()
If ($conn.State -eq 1) {
$sqlCmd = New-Object "MySql.Data.MySqlClient.MySqlCommand"
If ($sqlCmd) {
$sqlCmd.CommandTimeout = $strCommandTimeout
$sqlCmd.CommandText = $strQuery
$sqlCmd.Connection = $conn

# INSERT, UPDATE or DELETE ExecuteNonQuery()
# SELECT ExecuteReader()
$data = $sqlCmd.ExecuteReader()
$dtResult.Load($data) # fill
$data.Dispose()
$sqlCmd.Dispose() # frees all resources that were used by the object.
} Else {
Write-Host "ERROR: Cannot create SqlCommand object!";
}
} Else {
Write-Host "ERROR: Connection cannot be opened!";
}
$conn.Close()
$conn = $Null

#$dtResult | Format-Table -autosize
return $dtResult
}


# ***********************************************

Function getInfos {
$query = "SELECT * FROM YourTable"

# Here Table name is YourTable
# and fields name are Field1, Field1 and Field3

$dtResult = New-Object "System.Data.DataTable"

$hashOptions = @{ }
$hashOptions["strServer"] = "localhost"
$hashOptions["strDatabase"] = "db_name"
$hashOptions["strUser"] = "user"
$hashOptions["strPassword"] = "password"
$hashOptions["strQuery"] = $query
$dtResult = executeMYSQLQuery($hashOptions)

If ($dtResult -ne $Null) {
Foreach ($row in $dtResult){
$result = $row.Field1 + ";" + $row.Field2 + ";" + $row.Field3
Write-Host $result
}

}
$dtResult = $Null
}

# ***********************************************

getInfos

Friday, October 8, 2010

ODBC backslash problem error with MySQL

Today, I must use a software from CA names DSM reporter that permit me to export by ODBC some information to a MySQL database
All informations displayed in DSM reporter. But when I schedule this report to export datas to MySQL, it doesn't work.
Problem: I use the same ODBC , the same user than an other report that works very well. Moreover, all tables are well created, but no insertion was done.

So I use tracing. For this, click on start / Settings / Control Panel / Administrative Tools / Data Sources (ODBC). Select your System or User Data sources then click on Configure button. In details there is a Debug tab. Just enable "log queries to myodbc.sql"


Run your MySQL ODBC export again (for me,here, with DSM Reporter export / ODBC Database Table on a result). Now just to analyse C:\myodbc.sql file.
Finally, I found my problem come from \ (backslash) which is considered in MySQL like an Escape character. So I resolve problem as indicated in http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html, using NO_BACKSLASH_ESCAPES mode.

You can see your current sql mode by

SELECT @@SESSION.sql_mode;

or globally by

SELECT @@GLOBAL.sql_mode;


Now, to change sql mode in your current connection:

SET sql_mode='NO_BACKSLASH_ESCAPES';

To set this mode globally any connections:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES'


And if you don't want any sql mode options in your current connection:

SET sql_mode='';

Anf globally for all connections:

SET GLOBAL sql_mode=''

Wednesday, October 6, 2010

Get prod or dev environment by IP address

I have some DMZ with same computer name (...). These computers use one of my schedule script to retrieve some computers informations and put them by ssh on a secure ftp server. As these computers don't have same IP address, I can differentiate computer environnement (Production or Dev) using a list I get before using the same secure ftp server.

So here, script part to get prod or dev environment by IP address (Download it)

You need at least psftp from http://www.chiark.greenend.org.uk/~sgtatham/putty/ (Alternative Download). Put these files in the same directory than you will put GetEnvByIP.ps1 file.



#
# Get Env By IP Address
#
# by F.Richard 2010-10
#

set-psdebug -strict

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


# Computername
$Computername = Get-Content env:COMPUTERNAME


# get IP file by FTP
# Ip File format
# ip,csv
$ftp_cmdline = "
get ip.csv
quit
"
$ftp_cmdline | out-file -encoding OEM ".\ftp-get.txt"
$cmdline = $strCurDir + "\psftp yourftpserver -l user -pw password -b `"" + $strCurDir + "\ftp-get.txt`""
cmd /c $cmdline


# Get IP/env into Hash
$hashIP = @{ }
$content = import-csv "$strCurDir\ip.csv"
foreach ($line in $content) {
$IPAddress = $line.ip.Trim()
If ($IPAddress.length -gt 0) {
$env = $line.env.Trim()
$hashIP["$IPAddress"] = "$env"
}
}

# Detect IPs and display env
$StringToAdd="unknown"
$NetworkAdapterConfigurations = Get-WMIObject -Class Win32_NetworkAdapterConfiguration -computername $Computername
foreach ($NetworkAdapterConfiguration in $NetworkAdapterConfigurations) {
$IPAddress = $NetworkAdapterConfiguration.IPAddress
If ($hashIP.ContainsKey("$IPAddress")) {
$StringToAdd = $hashIP["$IPAddress"]
}
}
Write-Host "This computer is in $StringToAdd environment"



Ip.csv file should be like this

ip,csv
192.168.1.10,dev
192.168.1.20,prod


Do not forget to change variables yourftpserver user and password by your ftp, your user and your password. And put an ip.csv file on your ftp server.

This script use psftp for secure ftp but if you don't need secure ftp, you can use windows ftp by replacing psftp part by these lines


# get IP file by FTP
# Ip File format
# ip,csv
$ftp_cmdline = "
open yourftpserver
ftpuser
ftppassword
prompt
get ip.csv
quit
"
$ftp_cmdline | out-file -encoding OEM ".\ftp-get.txt"
$cmdline = "ftp -i -s:`"" + $strCurDir + "\ftp-get.txt`""
cmd /c $cmdline

Thursday, September 23, 2010

Reset Administrator password from HP Virtual Connect and Onbord Administrator

If you have some guys which makes fun to change password on a virtual connect there is a procedure to reset administrator password to it original setting.

This procedure comes from c00865618.pdf file page 28 HP Virtual Connect for c-Class BladeSystem User Guide

Resetting the Administrator password and DNS settings
-----------------------------------------------------
If the system maintenance switch 1 is in the ON position on a VC-Enet module, the firmware restores the Administrator account password and DNS settings to the original factory defaults as found on the module label (without disturbing any other local user accounts), and also displays the password on the VC-Enet module management console. For information on accessing the VC-Enet module management console, see the OA user guide. The default password is no longer displayed after switch 1 is in the OFF position.

Password restoration is done during each power-up sequence while switch 1 is in the ON position (and reserved switches are in the OFF position) and does not allow changes until the switch is placed back into the OFF position. For switch locations, see the appropriate system maintenance switch ("HP 1/10Gb VCEnet Module system maintenance switch" on page 15, "HP 1/10Gb-F VC-Enet Module system maintenance switch" on page 18, "HP Virtual Connect Flex-10 10Gb Ethernet Module system maintenance switch" on page 22).
After switch 1 is returned to the OFF position, users with appropriate privileges can then change the Administrator password.
Only reset the password on the module running the Virtual Connect Manager (and/or its backup), and not other modules in the domain.



The recommended password recovery procedure is as follows:

1. Remove the Virtual Connect Ethernet module from interconnect bay 1.

2. Remove the access panel from the Virtual Connect Ethernet module.

3. Set switch 1 to the ON position. Ensure that all other switches remain in the OFF position.

4. Install the access panel.

5. Insert the Virtual Connect Ethernet module into bay 1 and allow the module to power up and reach a fully booted and operational state (approximately 1 minute).

6. Remove the Virtual Connect Ethernet module from interconnect bay 2.
This causes interconnect bay 1 to become the module running the active VC Manager. Because switch 1 is set, the Administrator password remains at the factory default for interconnect bay 1 (not overwritten by the change of state because of the failover).

7. Wait to ensure that the VC Manager has had time to become active on interconnect bay 1. Log into the VC Manager to confirm it is up and functional on interconnect bay 1.

8. Insert the Virtual Connect Ethernet module into interconnect bay 2 and allow the module to power on and reach a fully booted and operational state (approximately 1 minute).

9. Remove the Virtual Connect Ethernet module from interconnect bay 1.

10. Remove the access panel from the Virtual Connect Ethernet module.

11. Set switch 1 to the OFF position. Ensure that all other switches remain in the OFF position.

12. Install the access panel.

13. Insert the Virtual Connect Ethernet module into interconnect bay 1 and allow the module to power up and reach a fully booted and operation state (approximately 1 minute).

14. Log into the VC Manager using the factory default user name and password to log in to the module (regardless of whether it is running on the module







[EDIT MARCH 12 2012] FOR ONBOARD ADMINISTRATOR

FOR OA this link http://h30499.www3.hp.com/t5/HP-BladeSystem-Management/Resetting-the-Onboard-Administrator-password/td-p/2304569 explain how to do on OA
I re-copy it for everyone:


Brian had an Onboard Administrator question:
**********************
I have two chassis were the customer has lost the passwords. They are not set to the default. Does anyone have password recovery procedures. Downtime and configuration is not any concern as this is a new install.
**********************
Bill had the process down:
********************
From the OA 3.10 user Guide, page 19...

Recovering the administrator password

If the administrator password has been lost, you can reset the administrator password to the factory default that shipped on the tag with the Onboard Administrator module. The Onboard Administrator resets a lost password to Lost Password/Flash Disaster Recovery (LP/FDR) mode. To recover the password and reset the administrator password to the factory default:

1. Connect a computer to the serial port of the Active Onboard Administrator using a null-modem cable.

2. With a null-modem cable (9600 N, 8, 1, VT100, locally connect to the Onboard Administrator).

3. Open HyperTerminal (in Microsoft(r) Windows(r)) or a suitable terminal window (in Linux), and then connect to the Active Onboard Administrator.

4. Press and hold in the Onboard Administrator reset button for 5 seconds.

5. To boot the system into Lost Password modem Press L. The password appears as the system reboots.

************************
from Ken:

*********************

I prefer to use a script on a thumb drive to recover lost OA passwords. I’ve attached 2 scripts. ResetPW resets the “Administrator” account password to “password”. The OA-Add-admin script adds use “admin” password “hpinvent” to the OA, and all ILOs in the enclosure.

To run the scripts:

Copy the scripts to a thumb drive
Place the thumb drive in the active OA
Run the script from the Insight Display

o USB Menu
o Restore Configuration
o usb://d1/script-name.cfg

Script 1:
ADD USER admin hpinvent
SET USER ACCESS admin ADMINISTRATOR
ASSIGN SERVER ALL admin
ASSIGN INTERCONNECT ALL admin
ASSIGN OA admin
ENABLE USER admin
HPONCFG all << end_marker
<RIBCL VERSION="2.0">
<LOGIN USER_LOGIN="adminname" PASSWORD="password">
<USER_INFO MODE="write">
<ADD_USER
USER_NAME="admin"
USER_LOGIN="admin"
PASSWORD="hpinvent">
<ADMIN_PRIV value ="Yes"/>
<REMOTE_CONS_PRIV value ="Yes"/>
<RESET_SERVER_PRIV value ="Yes"/>
<VIRTUAL_MEDIA_PRIV value ="Yes"/>
<CONFIG_ILO_PRIV value="Yes"/>
</ADD_USER>
</USER_INFO>
</LOGIN>
</RIBCL>
end_marker

Script 2:
SET USER PASSWORD "Administrator" "password"

Tuesday, September 21, 2010

Export SCCM informations to CSV and send it by FTP

A script that export by FTP some SCCM informations to re-use in a personal intranet.
(Download it). That script retrieve cpu, memory, OS, interfaces, disks informations using SQL server queries. To use it, modify next lines by yours.
$hashOptions["strServerInstance"] = "DBserver\DBInstance"
$hashOptions["strDatabase"] = "SMS_XXX"



#
#
# Export SCCM Infos
#
# by F.Richard 2010-09
#

set-psdebug -strict


# Script Directory
$strCurDir = Split-Path -parent $MyInvocation.MyCommand.Path
Set-Location $strCurDir | Out-Null
#Write-Host "Current Dir: $strCurDir"

#$debug = $True
$debug = $False


# ***********************************************



Function executeSQLQuery {
Param ([hashtable]$options)
$strServerInstance = $(if ($options.ContainsKey("strServerInstance")) {$options["strServerInstance"]} else {"(local)"}) # ex: srv\inst
$strConnectionName = $(if ($options.ContainsKey("strConnectionName")) {$options["strConnectionName"]} else {"connectionname"})
$strDatabase = $(if ($options.ContainsKey("strDatabase")) {$options["strDatabase"]} else {"default"})
$strCommandTimeout = $(if ($options.ContainsKey("strCommandTimeout")) {$options["strCommandTimeout"]} else {"15"})

$strUser = $(if ($options.ContainsKey("strUser")) {"User Id=" + $options['strUser'] + ";"} else {""})
$strPassword = $(if ($options.ContainsKey("strPassword")) {"Password=" + $options['strPassword'] + ";"} else {""})
$strAuthentication = $(if ($strUser -and $strPassword) {"$strUser$strPassword"} else {"Integrated Security=SSPI"})

$strQuery = $(if ($options.ContainsKey("strQuery")) {$options['strQuery']} else {""})


If ($debug) {
Write-Host "DEBUG: strServerInstance:" $strServerInstance
Write-Host "DEBUG: strConnectionName:" $strConnectionName
Write-Host "DEBUG: strDatabase:" $strDatabase
Write-Host "DEBUG: strCommandTimeout:" $strCommandTimeout
Write-Host "DEBUG: strUser:" $strUser
Write-Host "DEBUG: strPassword:" $strPassword
Write-Host "DEBUG: strAuthentication:" $strAuthentication
Write-Host "DEBUG: strQuery:" $strQuery
}

# Create SqlConnection
$conn = New-Object ('System.Data.SqlClient.SqlConnection')
If (!$conn) {
Write-Host "ERROR: Sql Connection could not be created!"
Exit
}

# http://www.connectionstrings.com/ for more details
# "Integrated Security=SSPI" = "Trusted_Connection=true" ->is telling SQL Server to use windows authentication -> User Id & Password not used
$connString = "Server=$strServerInstance;$strAuthentication;Database=$strDatabase;Application Name=$strConnectionName"
If ($debug) {
Write-Host "DEBUG: Sql Connection String:" $connString
}
$conn.ConnectionString = $connString
$dtResult = New-Object "System.Data.DataTable"
$conn.Open()
If ($conn.State -eq 1) {
$sqlCmd = New-Object "System.Data.SqlClient.SqlCommand"
If ($sqlCmd) {
$sqlCmd.CommandTimeout = $strCommandTimeout
$sqlCmd.CommandText = $strQuery
$sqlCmd.Connection = $conn

# INSERT, UPDATE or DELETE ExecuteNonQuery()
# SELECT ExecuteReader()
$data = $sqlCmd.ExecuteReader()
$dtResult.Load($data) # fill
$data.Dispose()
$sqlCmd.Dispose() # frees all resources that were used by the object.
} Else {
Write-Host "ERROR: Cannot create SqlCommand object!";
}
} Else {
Write-Host "ERROR: Connection cannot be opened!";
}
$conn.Close()
$conn = $Null

#$dtResult | Format-Table -autosize
return $dtResult
}


# ***********************************************

Function getServersList {

$yesterday = Get-Date((Get-Date).AddDays(-1)) -uformat "%d/%m/%Y"
If ($debug) { Write-Host "yesterday:" $yesterday }

$query = "SELECT DISTINCT system.[Name0] AS name_machine
,comp.[Model0] AS model
,system.SystemRole0 AS name_model
,comp.[Manufacturer0] AS constructor
,comp.[Domain0] AS domain
,MAX(system2.User_Name0) AS lastLoggedInUser
FROM [v_GS_SYSTEM] system
JOIN [v_R_System] system2 ON system2.ResourceID = system.ResourceID
JOIN [v_GS_COMPUTER_SYSTEM] comp ON comp.ResourceID = system.ResourceID
JOIN [v_Gs_Workstation_Status] WStatus ON WStatus.ResourceID = comp.ResourceID
WHERE 1=1
AND convert(VarChar(11), WStatus.LastHwScan, 103) = '$yesterday' -- 103 = dd/mm/yy but here = dd/mm/yyyy
GROUP BY system.[Name0], comp.[Model0], system.SystemRole0, comp.[Manufacturer0], comp.[Domain0]
ORDER BY name_machine"

$dtResult = New-Object "System.Data.DataTable"

$hashOptions = @{ }
$hashOptions["strServerInstance"] = "DBserver\DBInstance"
$hashOptions["strDatabase"] = "SMS_XXX"
#$hashOptions["strUser"] = "user"
#$hashOptions["strPassword"] = "password"
$hashOptions["strQuery"] = $query
$dtResult = executeSQLQuery($hashOptions)

If ($dtResult -ne $Null) {
New-Item ".\SCCM_Hardware.csv" -type file -force | out-null
Foreach ($row in $dtResult){
$query = "SELECT [SerialNumber0]
FROM V_GS_PC_BIOS bios
LEFT OUTER JOIN v_GS_SYSTEM system
ON bios.ResourceID = system.ResourceID
WHERE UPPER(system.Name0)='" + $row.name_machine.ToUpper() + "'"
$hashOptions["strQuery"] = $query
$dtResult2 = executeSQLQuery($hashOptions)
If ($dtResult2 -ne $Null) {
Foreach ($row2 in $dtResult2){
$result = $row.name_machine + ";" + $row.name_model + ";" + $row.constructor + ";" + $row.model + ";" + $row.domain + ";" + $row.lastLoggedInUser + ";" + $row2.SerialNumber0
$result | out-file -encoding OEM ".\SCCM_Hardware.csv" -append
}
}
}


# Memory
New-Item ".\SCCM_Memory.csv" -type file -force | out-null
Foreach ($row in $dtResult){
$query = "SELECT mem.[TotalPhysicalMemory0] AS totalphysicalmem -- 3407160
FROM v_GS_X86_PC_MEMORY mem
LEFT OUTER JOIN v_GS_SYSTEM system ON system.ResourceID = mem.ResourceID
WHERE UPPER(system.Name0)='" + $row.name_machine.ToUpper() + "'
AND mem.RevisionID = (
SELECT MAX(mem2.RevisionID) FROM v_GS_X86_PC_MEMORY mem2
LEFT OUTER JOIN v_GS_SYSTEM system2 ON system2.ResourceID = mem2.ResourceID
WHERE UPPER(system2.Name0)='" + $row.name_machine.ToUpper() + "')"
$hashOptions["strQuery"] = $query
$dtResult2 = executeSQLQuery($hashOptions)
If ($dtResult2 -ne $Null) {
Foreach ($row2 in $dtResult2){
$result = $row.name_machine + ";" + $row2.totalphysicalmem
$result | out-file -encoding OEM ".\SCCM_Memory.csv" -append
}
}
}


# CPU
New-Item ".\SCCM_CPU.csv" -type file -force | out-null
Foreach ($row in $dtResult){
$query = "SELECT process.nb_socket
,COUNT(DISTINCT processor.DeviceID0) AS number_core
,processor.[MaxClockSpeed0] AS frequency
,RTRIM(LTRIM(processor.Name0)) AS type_cpu
FROM [v_GS_PROCESSOR] processor

LEFT OUTER JOIN v_GS_SYSTEM system
ON processor.ResourceID = system.ResourceID

LEFT OUTER JOIN (SELECT p.ResourceID, COUNT(DISTINCT p.[SocketDesignation0]) AS nb_socket FROM [v_GS_PROCESSOR] p GROUP BY p.ResourceID)
process ON process.ResourceID = system.ResourceID

WHERE UPPER(system.Name0) = '" + $row.name_machine.ToUpper() + "'" + "
GROUP BY process.nb_socket
,processor.[MaxClockSpeed0]
,processor.Name0"

$hashOptions["strQuery"] = $query
$dtResult2 = executeSQLQuery($hashOptions)
If ($dtResult2 -ne $Null) {
Foreach ($row2 in $dtResult2){
$result = $row.name_machine + ";" + $row2.nb_socket + ";" + $row2.number_core + ";" + $row2.frequency + ";" + $row2.type_cpu
$result | out-file -encoding OEM ".\SCCM_CPU.csv" -append
}
}
}

# Interfaces
New-Item ".\SCCM_Interfaces.csv" -type file -force | out-null
Foreach ($row in $dtResult){
$query = "SELECT netadapt.[DefaultIPGateway0] AS gateway
,netadapt.[DHCPServer0] AS dhcp
,netadapt.[IPAddress0] AS ip
,netadapt.[IPSubnet0] AS mask
,netadapt.[MACAddress0] mac_interface
FROM v_GS_SYSTEM system
LEFT OUTER JOIN v_GS_NETWORK_ADAPTER_CONFIGUR netadapt ON
netadapt.ResourceID = system.ResourceID
WHERE UPPER(system.Name0)= '" + $row.name_machine.ToUpper() + "' AND
DefaultIPGateway0 IS NOT NULL"
$hashOptions["strQuery"] = $query
$dtResult2 = executeSQLQuery($hashOptions)
If ($dtResult2 -ne $Null) {
Foreach ($row2 in $dtResult2){
$result = $row.name_machine + ";" + $row2.gateway + ";" + $row2.dhcp + ";" + $row2.ip + ";" + $row2.mask + ";" + $row2.mac_interface
$result | out-file -encoding OEM ".\SCCM_Interfaces.csv" -append
}
}
}

# Os
New-Item ".\SCCM_OS.csv" -type file -force | out-null
Foreach ($row in $dtResult){
$query = "SELECT [Caption0] AS capsystem
,[CSDVersion0] AS patch
,[InstallDate0] AS date_install
,[LastBootUpTime0] AS lastbootuptime
,[Version0] AS version_os
FROM v_GS_OPERATING_SYSTEM os
LEFT OUTER JOIN v_GS_SYSTEM system ON system.ResourceID = os.ResourceID
WHERE UPPER(system.Name0) = '" + $row.name_machine.ToUpper() + "'"
$hashOptions["strQuery"] = $query
$dtResult2 = executeSQLQuery($hashOptions)
If ($dtResult2 -ne $Null) {
Foreach ($row2 in $dtResult2){
$result = $row.name_machine + ";" + $row2.capsystem + ";" + $row2.patch + ";" + $row2.date_install + ";" + $row2.lastbootuptime + ";" + $row2.version_os
$result | out-file -encoding OEM ".\SCCM_OS.csv" -append
}
}
}

# Disk
New-Item ".\SCCM_Disk.csv" -type file -force | out-null
Foreach ($row in $dtResult){
$query = "SELECT LTRIM(RTRIM([Description0])) AS id_type_disk -- local Fixed Disk or CD-ROM Disc
,[DeviceID0] AS letter -- D: or Z:
,[FileSystem0] AS id_file_system -- NTFS, FAT32, etc.
,[FreeSpace0] AS free_space
,system.[Name0] AS id_machine
,[Size0] AS size
,[VolumeName0] AS volume_name
,[VolumeSerialNumber0] AS volume_serial_number
FROM [v_GS_LOGICAL_DISK] logdisk
LEFT OUTER JOIN [v_GS_SYSTEM] system ON system.ResourceID = logdisk.ResourceID
WHERE UPPER(system.Name0) = '" + $row.name_machine.ToUpper() + "' AND [FileSystem0] IS NOT NULL"
$hashOptions["strQuery"] = $query
$dtResult2 = executeSQLQuery($hashOptions)
If ($dtResult2 -ne $Null) {
Foreach ($row2 in $dtResult2){
$result = $row.name_machine + ";" + $row2.id_type_disk + ";" + $row2.letter + ";" + $row2.id_file_system + ";" + $row2.free_space + ";" + $row2.id_machine + ";" + $row2.size + ";" + $row2.volume_name + ";" + $row2.volume_serial_number
$result | out-file -encoding OEM ".\SCCM_Disk.csv" -append
}
}
}
}

$dtResult = $Null

# FTP all .CSV
$today = Get-Date -uformat "%Y-%m-%d" # 2010-03-01
If (!(Test-Path "$strCurDir\log")) {
New-Item -Path "$strCurDir\log" -type directory | Out-Null
}
$ftp = "
open yourftpserver
ftpuser
ftppassword
mput `"$strCurDir\*.csv`"
quit
"
$ftp | out-file -encoding OEM ".\ftp-send.txt"

$cmdline = "ftp -i -s:`"" + $strCurDir + "\ftp-send.txt`" > `"" + $strCurDir + "\log\ftp_$today.txt`""
If ($debug) { Write-Host $cmdline }
cmd /c $cmdline
}

# ***********************************************

getServersList

Wednesday, September 1, 2010

Some tools interesting in Gilles Laurent's site

Gilles Laurent's site (http://glsft.free.fr/) is French site (sorry for english people), but some script or tools are interesting as these ones:

EmbedFileInVBScript
http://glsft.free.fr/index.php?option=com_content&task=view&id=38&Itemid=33
A vbscript which permit to transform binary to text (for exemple, can be used for RDP to export binary to a computer by clipboard, when you do not have rights to copy files directly)

DynSetEnv
http://glsft.free.fr/index.php?option=com_content&task=view&id=67&Itemid=28
A tool to create environment variable like SET in cmd but with parent process propogation

RunAsLoggedOnUser
http://glsft.free.fr/index.php?option=com_content&task=view&id=31&Itemid=28
A tool to execute a process with user right connected on computer

DynaWrap
http://glsft.free.fr/index.php?option=com_content&task=view&id=47&Itemid=33
An improved version of WSHDDynacall http://ourworld.compuserve.com/homepages/Guenter_born/WSHBazaar/WSHDynaCall.htm
permitting to call API in vbscript, perl...

Delete some local users and do a report

Today, support team need help to delete a lot of same local users on multiple servers which are in a workgroup (do not ask me why they do not use AD and domain....). And all these deletions must be report.
Like today I do not have really a lot of time to help them (too much projects to finish and manage today) I decided to do a 5 min batch script.

Here it is DeleteLocalUsers.cmd

set inputfile=users.txt
set result=result.txt
echo. >%result%
for /F %%i IN (%inputfile%) Do echo %%i >> %result% 2>>&1 & net user %%i /delete >> %result% 2>>&1


This batch use an input file named users.txt that containing users to delete like this:

aaaaaaa
bbbbbbb


No you just to run batch script to delete users (report file named result.txt)
Here user aaaaaa whas created before and bbbbbb does not exist

aaaaaa
The command completed successfully.

bbbbbb
The user name could not be found.

More help is available by typing NET HELPMSG 2221.


For better report, you can improve batch by testing if it's a successfull deletion by testing "successfully" with findstr command and errorlevel
If you need to execute this batch remotely on multiple computers, use psexec in for loop with a computers.txt file
(for example see in my blog in HP Onboard administrator and Citrix backup posts)

To download it

Monday, August 30, 2010

Format a volume larger than 32 GB in FAT32

Windows XP doesn't permit you to format FAT32 drive more than 32 gb
(see KB Q314463 Limitations of the FAT32 File System in Windows XP)

You can do this by command line using /FS switch but that doesn't work everytime

format /FS:FAT32 yourletter:




So you can use some tools

Fat32Format
http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm or
version with GUI (Alternate download location) or commandline (Alternate download location)

or

Fat32Formatter
http://tokiwa.qee.jp/EN/Fat32Formatter/ (Alternate download location)

Friday, August 13, 2010

Powershell get encoding file type

Like I need to know file encoding type programmatically, I first search and found on internet a script which permit to do it. I just modified it to add some encoding type

On this page http://poshcode.org/2059 original code I also copied below (Sorry, I don't know original author for greetings)


<# .SYNOPSIS Gets file encoding. .DESCRIPTION The Get-FileEncoding function determines encoding by looking at Byte Order Mark (BOM). Based on port of C# code from http://www.west-wind.com/Weblog/posts/197245.aspx .EXAMPLE Get-ChildItem *.ps1 select FullName, @{n='Encoding';e={Get-FileEncoding $_.FullName}} where {$_.Encoding -ne 'ASCII'} This command gets ps1 files in current directory where encoding is not ASCII .EXAMPLE Get-ChildItem *.ps1 select FullName, @{n='Encoding';e={Get-FileEncoding $_.FullName}} where {$_.Encoding -ne 'ASCII'} foreach {(get-content $_.FullName) set-content $_.FullName -Encoding ASCII} Same as previous example but fixes encoding using set-content #>
function Get-FileEncoding
{
[CmdletBinding()] Param (
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [string]$Path
)

[byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path

if ( $byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf )
{ Write-Output 'UTF8' }
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff)
{ Write-Output 'Unicode' }
elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff)
{ Write-Output 'UTF32' }
elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76)
{ Write-Output 'UTF7'}
else
{ Write-Output 'ASCII' }
}


Below my little changes to detect more encoding format refering http://en.wikipedia.org/wiki/Byte_order_mark



<#
.SYNOPSIS
Gets file encoding.
.DESCRIPTION
The Get-FileEncoding function determines encoding by looking at Byte Order Mark (BOM).
Based on port of C# code from http://www.west-wind.com/Weblog/posts/197245.aspx
.EXAMPLE
Get-ChildItem *.ps1 | select FullName, @{n='Encoding';e={Get-FileEncoding $_.FullName}} | where {$_.Encoding -ne 'ASCII'}
This command gets ps1 files in current directory where encoding is not ASCII
.EXAMPLE
Get-ChildItem *.ps1 | select FullName, @{n='Encoding';e={Get-FileEncoding $_.FullName}} | where {$_.Encoding -ne 'ASCII'} | foreach {(get-content $_.FullName) | set-content $_.FullName -Encoding ASCII}
Same as previous example but fixes encoding using set-content


# Modified by F.RICHARD August 2010
# add comment + more BOM
# http://unicode.org/faq/utf_bom.html
# http://en.wikipedia.org/wiki/Byte_order_mark
#
# Do this next line before or add function in Profile.ps1
# Import-Module .\Get-FileEncoding.ps1
#>
function Get-FileEncoding
{
[CmdletBinding()]
Param (
[Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)]
[string]$Path
)

[byte[]]$byte = get-content -Encoding byte -ReadCount 4 -TotalCount 4 -Path $Path
#Write-Host Bytes: $byte[0] $byte[1] $byte[2] $byte[3]

# EF BB BF (UTF8)
if ( $byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf )
{ Write-Output 'UTF8' }

# FE FF (UTF-16 Big-Endian)
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff)
{ Write-Output 'Unicode UTF-16 Big-Endian' }

# FF FE (UTF-16 Little-Endian)
elseif ($byte[0] -eq 0xff -and $byte[1] -eq 0xfe)
{ Write-Output 'Unicode UTF-16 Little-Endian' }

# 00 00 FE FF (UTF32 Big-Endian)
elseif ($byte[0] -eq 0 -and $byte[1] -eq 0 -and $byte[2] -eq 0xfe -and $byte[3] -eq 0xff)
{ Write-Output 'UTF32 Big-Endian' }

# FE FF 00 00 (UTF32 Little-Endian)
elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff -and $byte[2] -eq 0 -and $byte[3] -eq 0)
{ Write-Output 'UTF32 Little-Endian' }

# 2B 2F 76 (38 | 38 | 2B | 2F)
elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76 -and ($byte[3] -eq 0x38 -or $byte[3] -eq 0x39 -or $byte[3] -eq 0x2b -or $byte[3] -eq 0x2f) )
{ Write-Output 'UTF7'}

# F7 64 4C (UTF-1)
elseif ( $byte[0] -eq 0xf7 -and $byte[1] -eq 0x64 -and $byte[2] -eq 0x4c )
{ Write-Output 'UTF-1' }

# DD 73 66 73 (UTF-EBCDIC)
elseif ($byte[0] -eq 0xdd -and $byte[1] -eq 0x73 -and $byte[2] -eq 0x66 -and $byte[3] -eq 0x73)
{ Write-Output 'UTF-EBCDIC' }

# 0E FE FF (SCSU)
elseif ( $byte[0] -eq 0x0e -and $byte[1] -eq 0xfe -and $byte[2] -eq 0xff )
{ Write-Output 'SCSU' }

# FB EE 28 (BOCU-1)
elseif ( $byte[0] -eq 0xfb -and $byte[1] -eq 0xee -and $byte[2] -eq 0x28 )
{ Write-Output 'BOCU-1' }

# 84 31 95 33 (GB-18030)
elseif ($byte[0] -eq 0x84 -and $byte[1] -eq 0x31 -and $byte[2] -eq 0x95 -and $byte[3] -eq 0x33)
{ Write-Output 'GB-18030' }

else
{ Write-Output 'ASCII' }
}


To use this function paste it to your profile.ps1 file or copy file on a folder and use this next line before use the function

use import-module .\Get-FileEncoding.ps1

Then use it by something like

Get-Item *.log | select FullName, @{n='Encoding';e={Get-FileEncoding $_.FullName}}


You can download this file here

Wednesday, August 4, 2010

Get alias cname hostname DNS using powershell

Well, just a way in powershell to know real hostname alias (CNAME)


$computername = [System.Net.Dns]::GetHostByName("youralias")
Write-Host $computername.HostName.substring(0,$computername.HostName.IndexOf("."))

Friday, July 30, 2010

Powershell to display Storage Model for each VMWare VM

Script below permit to display which storage model is used for each VM of you Virtual Center
Download it


#
# Storage Model by VM
#
# by Franck RICHARD
# 2010 July
#

# Connect VC
$VC = "localhost"
Connect-VIServer -Server $VC | Out-Null

# Get all Datastores
$datastores = Get-Datastore
# Get All VMs
$ArrVM = Get-VM
foreach ($VM in $arrVM) {
# Get VMHost View
$VMHostView = Get-VMHost -VM $VM | Get-View

# Get all HardDisks
$HardDisks = $VM | Get-HardDisk
foreach ($HardDisk in $HardDisks) {
# Filename = "[VMFS-PROD] COMPUTER01/COMPUTER01.vmdk" for example
$DatastoreVM = $HardDisk.Filename.Split("[]")[1]
$DatastoreVMView = $datastores | where {$_.name -eq $DatastoreVM} | Get-View

# Diskname = "vmhba2:0:20" for example
$VMFSextents = $DatastoreVMView.info.vmfs.extent
foreach ($VMFSextent in $VMFSextents) {
$Diskname = $vmfsextent.Diskname
#Write-Host "Diskname:"$Diskname
}

$ScsiLuns = $VMHostView.Config.StorageDevice.ScsiLun
$bDiskFound = $False
foreach ($ScsiLun in $ScsiLuns) {
if ($ScsiLun.CanonicalName -eq $Diskname) {
#For Example
# CanonicalName = "vmhba2:0:0"
# Vendor = "EMC"
# Model = "SYMMETRIX"
$bDiskFound = $True
break
}
}

if ($bDiskFound) {
Write-Host "Name:" $VM.Name $HardDisk.Name $ScsiLun.CanonicalName "Vendor:"$ScsiLun.Vendor "Model:"$ScsiLun.Model
} else {
Write-Host "Name:" $VM.Name $diskname "not found"
}
# break # if all HardDisks are on the SAN
} # Foreach $HardDisk
} # Foreach $VM

Saturday, July 10, 2010

Site WWoIT - Wayne's World of IT

Site WWoIT - Wayne's World of IT
http://waynes-world-it.blogspot.com/
Some very interesting information about vmware and windows infrastructure

Tuesday, June 29, 2010

Filter all lines of a text file with multiple strings list

To display only lines containing a string in a text file, easiest way is to use findstr commandline. For example, if we want to display lines containing "ok" (with /i switch for no case sensitivity) in a file file.txt we just to run at command line something like

type file.txt | findstr /i ok


With findstr you can also display lines NOT containing a particular string. For example you want all lines except line with string "not good" with this command

type file.txt | findstr /i /v /c:"not good"


Today my problem is that I need to report all administrators users of all computers except some users in a list.(yes, there is not SCCM or another tool which permit to do it here). I could do it like this:

type file.txt findstr /i /v /c:"administrator1" findstr /i /v /c:"administrator2" findstr /i /v /c:"administrator3"


But that's not really simple to maintain if you need to do some changes. Moreover, why do not do something which could be used for others problems of the same type?
So to do better than excel :) I created this batch file filter.cmd

@echo off
REM
REM Line Filter
REM By F.RICHARD
REM
REM created 2010 July
REM modified 2010 september for %1
REM

SET CURDIR=%~d0%~p0
cd /d %CURDIR%

IF {%1}=={} GOTO :ERRFILEINPUT
SET INPUTFILE=%1
echo Input file:%INPUTFILE%
If NOT EXIST %INPUTFILE% GOTO :ERRNEINPFILE
IF {%2}=={} GOTO :ERRFILEFILTER
SET FILTERFILE=%2
echo Filter file:%FILTERFILE%
If NOT EXIST %FILTERFILE% GOTO :ERRNEFILFILE
IF {%3}=={} GOTO :ERRFILERESULT
SET RESULTFILE=%3
echo Result file:%RESULTFILE%

setlocal EnableDelayedExpansion
set /a nbstr=0

Echo Begin filter
type %INPUTFILE% > tempfile!nbstr!.txt
for /F "tokens=*" %%i IN (%FILTERFILE%) Do (
set tmpfileread=tempfile!nbstr!.txt
set /a nbstr=!nbstr!+1
set tmpfileresult=tempfile!nbstr!.txt
type !tmpfileread! | findstr /v /i /c:%%i > !tmpfileresult!
del /f /q !tmpfileread!
)
move /Y !tmpfileresult! %RESULTFILE%
Echo End filter
goto :EOF

:ERRFILEINPUT
Echo.
Echo ERROR: you need an input filename
goto :Syntax

:ERRFILEFILTER
Echo.
Echo ERROR: you need a filter file
goto :Syntax

:ERRFILERESULT
Echo.
Echo ERROR: you need a result filename
goto :Syntax

:ERRNEINPFILE
Echo.
Echo ERROR: input file - %INPUTFILE% - does not exist in %CURDIR% directory
goto :EOF

:ERRNEFILFILE
Echo.
Echo ERROR: filter file - %FILTERFILE% - does not exist in %CURDIR% directory
goto :EOF

:Syntax
Echo.
Echo Syntax:
Echo %~nx0 inputfile filterfile resultfile
Echo.
goto :EOF


use it with something like

stringfilter.cmd input.txt filter.txt result.txt


With a input file like this input.txt

aaaaaaa
do not want to see it
bbbbbbb
not this one
ccccccc


This batch use a filter file like this filter.txt

"not this"
bbbbbbb
"not want"


and result file was like this result.txt

aaaaaaa
ccccccc


Et voilà

You can download this script
here

Saturday, June 26, 2010

Get all OU's computers in a AD

If you need to have all computers of a specific OU, just run




@dsquery computer "OU=YourOU,DC=Domain,DC=Net" -limit 0 -o rdn > Computers_YourOu_domain_net.txt


Result will be savec in a file Computers_YourOu_domain_net.txt that will be like this:

"computer1"
"computer2"
"computer3"


Now you can use it to run a script on each OU's computers :-)

Friday, June 18, 2010

Append/Consolidate a lot of files to 1 file

Again a need I have regurlarly. You have a lot of files you want to append in only one text. For example a lot of .csv files that you want to consolidate in 1 .csv file

Here it's a powershell script that consolidate all file in a folder to a file "_allFilesInOne.txt". Just put this file GetAllFilesInOne_ps1.txt in a folder and run it (renamed it .ps1 before)


#
# Get All Files In One File
#
# F.Richard
# 2010 June
#
$appendfile = "_allFilesInOne.txt"
$files = Get-ChildItem * -exclude $appendfile,$MyInvocation.MyCommand.Name -include *
$Content = ""
$Content | Out-File $appendfile
ForEach ($filename in $files) {
Write-Host $filename
$Content = Get-Content $filename
$Content | Out-File -append $appendfile
}


You can improve this script easily.
For example, you can exclude .log files by changing
-exclude $appendfile,$MyInvocation.MyCommand.Name
by
-exclude $appendfile,$MyInvocation.MyCommand.Name,*.log

You can can also change inclusion of all files to only .txt files by changing
-include *
by
-include *.txt

Get user SID and vice versa

For a Citrix problem, support team had to know correspondance between user or computer name and SID. If you don't know what is SID, it's something like S-1-5-21-1009609029-4169793705-2371228398 and correspond to an unique identifier of a user, computer or group (see definition in Technet Glossary at http://technet.microsoft.com/en-us/library/cc776189(WS.10).aspx#s)

Well In my toolbox I have 2 very old vbs scripts from Shane Boudreaux that permit to convert SID to username and vice versa

Convert Username to SID
http://www.thescriptlibrary.com/Default.asp?Action=Display&Level=Category3&ScriptLanguage=VBScript&Category1=Security&Category2=Other&Title=Convert%20Username%20to%20SID (Alternate Download)

Convert SID to Username
http://www.thescriptlibrary.com/Default.asp?Action=Display&Level=Category3&ScriptLanguage=VBScript&Category1=Security&Category2=Other&Title=Convert%20SID%20to%20Username (Alternate Download)

But now Microsoft sysinternals have a tool PsGetSid (http://technet.microsoft.com/en-us/sysinternals/bb897417.aspx) (Alternate Download) that do the same

If you need to know how sysinternals do, you can check source code sid2user.cpp and user2sid.cpp from Evgenii B. Rudnyi http://evgenii.rudnyi.ru/soft/sid/ (Alternate Download user2sid.cpp and sid2user.cpp)

If you are a powershell geek, go directly to Powershell Guy blog http://thepowershellguy.com/blogs/posh/archive/2007/01/23/powershell-converting-accountname-to-sid-and-vice-versa.aspx (Alternate Download)

Thursday, June 17, 2010

Blog Syntax Highlighting

For my blog, I search something to code Syntax Highlighter (see http://en.wikipedia.org/wiki/Syntax_highlighting if you don't know what that means). Finally, I think there is 2 good choices:

- the simplest:
Use http://www.thecomplex.plus.com/highlighter.html or http://tohtml.com/ to translate your code in your language. Just HTML copy code to you blog .
If you prefer, you can also install a free software: "highlight" from http://www.andre-simon.de/
(Alternate Download)

- the most complete (because it permit to add "copy clipboard" and "view plain" ):
Use http://alexgorbatchev.com/wiki/SyntaxHighlighter (with integration example in http://alexgorbatchev.com/SyntaxHighlighter/integration.html)