Showing posts with label vbscript. Show all posts
Showing posts with label vbscript. Show all posts

Tuesday, November 8, 2011

ESX or Linux update Automation for windows users: su root and password

Today, I improved an old post. (I recommend you to read it before this post)
These scripts work correctly but for security reasons I could not use this work. Indeed, we must log before with an user then su in root. Moreover, with these previous scripts, that was not possible to transfert any other files like binaries files. So I decided to work on this problem to avoid to manually update 150 esx.
Sure, some trick exist like "expect" (not included in esx) or cpan perl expect, but it was simpliest to me to improve my scripts.

To use my scripts, just create a file yourfile.zip containing a script yourfile.sh and all needed files
process of these scripts:
script use a computer listing file (here servers.txt file) including all your computers you need to update
Script upload on your esx or linux computers yourfile.zip to /tmp directory, then decompress yourfile.zip and run yourfile.sh file

In update_esx_v2.zip, I give you a script example which permit you to update ESX with 2 patchs
[EDIT 15 february 2012] I re-upload zip file and add some informations in this post

In update.zip, file update.sh script contains all commands to do update
#!/bin/sh
# Update
cd ESX350-201012404-BG/
esxupdate --nosig update
cd ..
cd ESX350-201012410-BG/
esxupdate --nosig update
cd ..
In update.zip, there is also all necessary files used by update.sh

update\
update\update.sh
update\ESX350-201012404-BG\
update\ESX350-201012404-BG\contents.xml
update\ESX350-201012404-BG\contents.xml.sig
update\ESX350-201012404-BG\descriptor.xml
update\ESX350-201012404-BG\VMware-esx-scripts-3.5.0-317866.i386.rpm
update\ESX350-201012404-BG\headers\
update\ESX350-201012404-BG\headers\contents.xml
update\ESX350-201012404-BG\headers\contents.xml.sig
update\ESX350-201012404-BG\headers\header.info
update\ESX350-201012404-BG\headers\VMware-esx-scripts-0-3.5.0-317866.i386.hdr
update\ESX350-201012410-BG\
update\ESX350-201012410-BG\contents.xml
update\ESX350-201012410-BG\contents.xml.sig
update\ESX350-201012410-BG\descriptor.xml
update\ESX350-201012410-BG\vmware-keying-data-1-20100930.noarch.rpm
update\ESX350-201012410-BG\headers\
update\ESX350-201012410-BG\headers\contents.xml
update\ESX350-201012410-BG\headers\contents.xml.sig
update\ESX350-201012410-BG\headers\header.info
update\ESX350-201012410-BG\headers\vmware-keying-data-0-1-20100930.noarch.hdr



Now, you can run "run_update.cmd" which run your updates with user esxadmin
(only if this user can do all that you want - if user to connect your esx is not esxadmin change line with set usern=esxadmin)
@echo off
set usern=esxadmin
set zipfile=update.zip
set computerfile=servers.txt

if "%1"=="" goto :nopass
set password=%1

cscript //nologo update_esx.vbs %computerfile% %zipfile% %usern% %password%
goto :eof

:nopass
echo you need a password for user %usern%
goto :eof

To run your update with user esxadmin then su root
@echo off
set usern=esxadmin
set userroot=root
set zipfile=update.zip
set computerfile=servers.txt

if "%1"=="" goto :nopass
if "%2"=="" goto :nopass2
set password=%1
set pwdroot=%2

cscript //nologo update_esx.vbs %computerfile% %zipfile% %usern% %password% %userroot% %pwdroot%
goto :eof

:nopass
echo you need a password for user %usern%
goto :eof

:nopass2
echo you need a password for user %userroot% 
goto :eof

all computers to update are in file servers.txt below
computer1
computer2
computer3

Main script update_esx.vbs that permit to transfert and decompress "yourfile.zip" and execute "yourfile.sh" on your linux or esx
'
' update_esx.vbs
'
' by F.RICHARD
'
' v1.00 2007 Nov - Initial release
' v1.01 2008 Jan - Display Standard output
' v2.00 2011 Nov - Modify script to use and send ZIP file
'
Option Explicit

Const ForReading = 1
Const ForWriting = 2

'
' 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 Command Line Args
'
Dim Args
Set Args = Wscript.Arguments
If Args.Count < 4 Then
 Wscript.Echo "Syntax : " & WScript.ScriptName & " input_computer_list_file zip_file_to_send_uncompress_and_execute user password"
 Wscript.Echo "Syntax : " & WScript.ScriptName & " input_computer_list_file zip_file_to_send_uncompress_and_execute user password [root] [root password]"
 Wscript.Echo "         Example : cscript " & WScript.ScriptName & " servers.txt myfile.zip user password"
 Wscript.Echo "         Example : cscript " & WScript.ScriptName & " servers.txt myfile.zip user password root rootpass"
 Wscript.Echo ""
 Wscript.Echo "computer_list_file: line begin by # or ; indicate start of a comment, everything after is ignored"
 Wscript.Echo ""
 Wscript.Quit
End If


' Args(0) = computer list
Dim strInputList
strInputList = Trim(args(0))

' Args(1) = zip file to send and execute
Dim strScriptToExecute, strCompressFile, strDirectory, strCompressFileExt
strCompressFile = Trim(args(1))
strCompressFileExt = Right(strCompressFile, Len(strCompressFile)-InStr(1, strCompressFile, ".") )
If (StrComp(strCompressFileExt, "zip", vbTextCompare) <> 0) Then
 WScript.Echo "File to send: '" & strCompressFile & "'is not a .zip file"
 WScript.Quit
End If
strDirectory = Left(strCompressFile, InStr(1, strCompressFile, ".")-1)
strScriptToExecute = strDirectory & ".sh"

' Args(2) = user
Dim strUser
strUser = Trim(args(2))

' Args(3) = password
Dim strPassword
strPassword = Trim(args(3))

' Args(4) = root name
' Args(5) = root password
Dim strRootPassword, strRootName
If Args.Count > 5 Then
 strRootName = Trim(args(4))
 strRootPassword = Trim(args(5))
End If


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

Dim objFso
Set objFso = CreateObject("Scripting.FileSystemObject")


'
' Test If all Files Exist
'
If Not isFileExist(strInputList) Then
 strInputList = strScriptPath & "\" & strInputList
 If Not isFileExist(strInputList) Then
  WScript.Echo "Computer list:" & strInputList & " File Not Exist !"
  WScript.Quit
 End If   
End If   
WScript.Echo "Computer list:" & strInputList & " File Exist"

If Not isFileExist(strCompressFile) Then
 strCompressFile = strScriptPath & "\" & strCompressFile
 If Not isFileExist(strCompressFile) Then
  WScript.Echo "Compress file:" & strCompressFile & """" & " File Not Exist !"
  WScript.Quit
 End If   
End If   
WScript.Echo "Script to uncompress:" & strCompressFile & " File Exist"

Dim strPlink
strPlink= strScriptPath & "\" & "plink.exe"
If Not isFileExist(strPlink) Then
 WScript.Echo "PuTTY Link:" & strPlink & " File Not Exist !"
 WScript.Quit
End If     
WScript.Echo "PuTTY Link:" & strPlink & " File Exist"

Dim strPscp
strPscp= strScriptPath & "\" & "pscp.exe"
If Not isFileExist(strPscp) Then
 WScript.Echo "PuTTY Secure Copy client:" & strPscp & " File Not Exist !"
 WScript.Quit
End If     
WScript.Echo "PuTTY Secure Copy client:" & strPscp & " File Exist"


Dim objShell, ComSpec
Set objShell = CreateObject( "WScript.Shell" )
ComSpec=objShell.ExpandEnvironmentStrings("%ComSpec%")

'
' Read computer list file into dictionary
'
Dim objDictionary, return
return = ReadFileToDict(strInputList, objDictionary)
If return = 0 Then
 WScript.Echo "Error during computer list file read"
 WScript.Quit
End If


'
' Generate .sh file to execute
'
Dim strContent, strScriptToDecFile
strScriptToDecFile = "decfile.sh"
strContent = "#!/bin/sh" & vbLf & _
 "# Unzip " & strCompressFile & " then enter in " & strDirectory & " directory and execute " & strScriptToExecute & " file" & vbLf & _
 "cd /tmp" & vbLf & _
 "unzip -o " & strCompressFile & vbLf
return = WriteStrToFile(strScriptToDecFile, strContent)


' Display file
Dim objItem, strServer, objCmd, strCmdline, continue, strGenerateKey
For Each objItem in objDictionary
 strServer = objDictionary.Item(objItem)
 Wscript.Echo ""
 WScript.Echo "Server:" & strServer
 
 ' Test Connection
 strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " " & strUser & "@" & strServer & " pwd "
 strGenerateKey = ComSpec & " /c echo y | """ & strPlink & """ " & strServer & " -pw " & strPassword & " " & strUser

 WScript.Echo "Test Connection on server " & strServer
 return = DoConnection(strCmdline, strGenerateKey, strServer, True)

 If (return > 0) Then
  strGenerateKey=""
  Do
   WScript.Echo "Re-verify Connection on server " & strServer
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)
  Loop While (return > 0 and return < 255)
  If (return > 0) Then
   WScript.Echo "Transfer " & strScriptToDecFile & " script on server " & strServer
   strCmdline = ComSpec & " /c """ & strPscp & """ -batch -C -pw " & strPassword & " " & strScriptToDecFile & " " & strUser & "@" & strServer & ":/tmp"
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)

   WScript.Echo "Transfer " & strCompressFile & " script on server " & strServer
   strCmdline = ComSpec & " /c """ & strPscp & """ -batch -C -pw " & strPassword & " " & strCompressFile & " " & strUser & "@" & strServer & ":/tmp"
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)

   WScript.Echo "Execute " & strScriptToDecFile & " script on server " & strServer
   strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " " & strUser & "@" & strServer & " " & "cd /tmp; sh " & strScriptToDecFile
   return = DoConnection(strCmdline, strGenerateKey, strServer, True)

   ' if root / or not root
   If Args.Count > 5 Then

    objShell.Run "putty.exe -ssh " & strUser & "@" & strServer
    WScript.Sleep 5000
    objShell.AppActivate strServer & " - PuTTY"
    WScript.Sleep 5000
    objShell.SendKeys "" &  strPassword & "{ENTER}"
    WScript.Sleep 5000     
    objShell.SendKeys "su - " & strRootName & "{ENTER}"
    WScript.Sleep 5000     
    objShell.SendKeys "" & strRootPassword & "{ENTER}"
    WScript.Sleep 5000     
    objShell.SendKeys "cd /tmp/" & strDirectory & "; sh " & strScriptToExecute & "{ENTER}"
    WScript.Sleep 5000     
   Else
    WScript.Echo "Execute " & strScriptToExecute & " script on server " & strServer
    strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " " & strUser & "@" & strServer & " " & "cd /tmp/" & strDirectory & "; sh " & strScriptToExecute
    return = DoConnection(strCmdline, strGenerateKey, strServer, True)
   End If
  End If
 End If

Next



'
' Quit
'
WScript.Sleep 1000
WScript.Quit

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

' DoConnection
'
' 
'
Function DoConnection(strCmdline, strGenerateKey, strServer, displayLogfile)
 Dim objCmd, return, Continue

 'WScript.Echo "cmdline->" & strCmdline
 Set objCmd = objShell.Exec(strCmdline)
 Do While objCmd.Status = 0
  return = objCmd.stdErr.ReadAll
  WScript.Sleep 100
 Loop
 If (displayLogfile) Then
  Dim strStdOut
  strStdOut = objCmd.StdOut.ReadAll()
  If (len(strStdOut) > 0) Then
   Wscript.Echo strStdOut
  End If
 End If

 continue = 0
 If Instr(return, "Access denied" ) > 0 Then ' Access denied
  WScript.Echo "ERROR on server " & strServer & vbCrLf & return
  continue = 0

 Elseif Instr(return, "Unable to open connection" ) > 0 Then ' Unable to open connection
  WScript.Echo "ERROR on server " & strServer & vbCrLf & return
  continue = 0

 Elseif Instr(return, "ERROR" ) > 0 Then ' FATAL ERROR: Network error: Connection timed out
  WScript.Echo "ERROR on server " & strServer & vbCrLf & return
  continue = 0

 Elseif Instr(return, "fingerprint" ) > 0 Then
  If (len(strGenerateKey) > 2) Then
   WScript.Echo "GENERATE key fingerprint on server " & strServer
   'WScript.Echo "generatekey->" & strGenerateKey
   objShell.Exec(strGenerateKey)
   continue = 1
  Else
   WScript.Echo "NOT GENERATE key fingerprint " & strServer
   continue = 2
  End If
 Else
  continue = 255
  'WScript.Echo "Logged on " & strServer & " - " & return
 End if

 DoConnection = continue
End Function



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

' isFileExist
'
' Test if File Exist
'
Function IsFileExist(strInputFile)
 Dim objFSO
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 If Not objFSO.FileExists(strInputFile) Then
  Wscript.echo strInputFile & " file not exist !"
  IsFileExist = False
 Else
  IsFileExist = True
 End If
End Function


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

' ReadFileToDict
'
' Read each line -> put in Dictionary
' strInputfile = file to read
' objDictionary = dictionary for results
'
Function ReadFileToDict(strInputFile, ByRef objDictionary)
 Dim objFSO, objTextFile, strNextLine, i
 Set objDictionary = CreateObject("Scripting.Dictionary")
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 If isFileExist(strInputFile) Then
  Set objTextFile = objFSO.OpenTextFile(strInputFile, ForReading)
  i = 0
  Do Until objTextFile.AtEndOfStream
   strNextLine = Trim(objTextFile.Readline)
   If ( (Not Left(strNextLine, 1) = "#") _
    and (Not Left(strNextLine, 1) = ";") _
    and (Len(strNextLine)>1) _
    ) Then
    objDictionary.Add i, strNextLine
    i = i + 1
   End If
  Loop
  objTextFile.Close
  ReadFileToDict = True
 Else
  ReadFileToDict = False
 End If
End Function


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

' WriteStrToFile
'
' Write string to file
' strOutputFile = file to write
' strContent = string to write
'
Function WriteStrToFile(strOutputFile, ByRef strContent)
 Dim objFSO, objTextFile
 Set objFSO = CreateObject("Scripting.FileSystemObject")
 Set objTextFile = objFSO.CreateTextFile(strOutputFile, True)  ' delete file
 objTextFile.Write(strContent)
 objTextFile.Close
End Function


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

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

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, April 10, 2008

How to update or configure automatically vmware esx or linux servers when you are a windows user ?

Problem when you have 32 esx 3.01 to upgrade is that takes long time. And ask to windows prod team to realize these - not interesting - tasks needs a really big documentation to avoid errors. So I decided to create something to automatize this process.
So, today I give you a script which permit you to update or configure any linux/vmware redhat/unix server with simple vbscript file. First, you need at least plink.exe and pscp.exe from http://www.chiark.greenend.org.uk/~sgtatham/putty/ (Alternative Download). Put these files in the same directory than you will put update_esx.vbs file.

But why this script is magic? Because plink and pscp could do it for you really easily, no ? In fact, problem with plink.exe is when you need to automatize your process. Each time you will try to log on a new server, plink will ask you to create ssh host keys. (for security)
With this script you do no need to create plink ssh host keys before running script on your servers. This script do it for you.
Now, you need to create servers.txt file containing all servers you need to update or configure. (1 line = 1 server). For example:

esxserver001
esxserver002


You need also a .sh file which will be executed on esx - linux server (don't forget to use a unix text file with only line feed, and not Windows text file with line feed and carriage return ASCII characters. So do not use notepad to modify files. Use Textpad or other tools that recognize file encoding. )

Below an example to send to your esx. This file ls.sh

#!/bin/sh
# Configure ESX Server
ls


Last thing: root password should be the same on each esx - linux server (else modify my vbscript using a second column in servers.txt like server;rootpassword)
You must also permit root user to log on your esx.

How to use it: run in you windows command line something like


cscript //nologo update_esx.vbs servers.txt file_to_execute.sh your_esx_root_password


If you need to write log, redirect standard output to a file like this:


cscript //nologo update_esx.vbs servers.txt file_to_execute.sh your_esx_root_password > mylog.txt


And now the last but not least, the main tool, update_esx.vbs

'
' update_esx.vbs
'
' by F.RICHARD
'
' v1.00 2007 Nov - Initial release
' v1.01 2008 Jan - Display Standard output
'
Option Explicit

Const ForReading = 1

'
' 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 Command Line Args
'
Dim Args
Set Args = Wscript.Arguments
If Args.Count < 3 Then
Wscript.Echo "Syntax : " & WScript.ScriptName & " input_computer_list_file script_to_execute root_password"
Wscript.Echo " Example : cscript " & WScript.ScriptName & " servers.txt update.sh password"
Wscript.Echo ""
Wscript.Echo "computer_list_file: line begin by # or ; indicate start of a comment, everything after is ignored"
Wscript.Echo ""
Wscript.Quit
End If


' Arg(0) = computer list
Dim strInputList
strInputList = Trim(args(0))

' Arg(1) = script to execute
Dim strScriptToExecute
strScriptToExecute = Trim(args(1))


' Arg(2) = root password
Dim strPassword
strPassword = Trim(args(2))


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

Dim objFso
Set objFso = CreateObject("Scripting.FileSystemObject")


'
' Test If all Files Exist
'
If Not isFileExist(strInputList) Then
strInputList = strScriptPath & "\" & strInputList
If Not isFileExist(strInputList) Then
WScript.Echo "Computer list:" & strInputList & " File Not Exist !"
WScript.Quit
End If
End If
WScript.Echo "Computer list:" & strInputList & " File Exist"

If Not isFileExist(strScriptToExecute) Then
strScriptToExecute = strScriptPath & "\" & strScriptToExecute
If Not isFileExist(strScriptToExecute) Then
WScript.Echo "Script to execute:" & strScriptToExecute & """" & " File Not Exist !"
WScript.Quit
End If
End If
WScript.Echo "Script to execute:" & strScriptToExecute & " File Exist"

Dim strPlink
strPlink= strScriptPath & "\" & "plink.exe"
If Not isFileExist(strPlink) Then
WScript.Echo "PuTTY Link:" & strPlink & " File Not Exist !"
WScript.Quit
End If
WScript.Echo "PuTTY Link:" & strPlink & " File Exist"

Dim strPscp
strPscp= strScriptPath & "\" & "pscp.exe"
If Not isFileExist(strPscp) Then
WScript.Echo "PuTTY Secure Copy client:" & strPscp & " File Not Exist !"
WScript.Quit
End If
WScript.Echo "PuTTY Secure Copy client:" & strPscp & " File Exist"


Dim objShell, ComSpec
Set objShell = CreateObject( "WScript.Shell" )
ComSpec=objShell.ExpandEnvironmentStrings("%ComSpec%")

'
' Read computer list file into dictionary
'
Dim objDictionary, return
return = ReadFileToDict(strInputList, objDictionary)
If return = 0 Then
WScript.Echo "Error during computer list file read"
WScript.Quit
End If

' Display file
Dim objItem, strServer, objCmd, strCmdline, continue, strGenerateKey
For Each objItem in objDictionary
strServer = objDictionary.Item(objItem)
Wscript.Echo ""
WScript.Echo "Server:" & strServer

' Test Connection
strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " root" & "@" & strServer & " pwd "
strGenerateKey = ComSpec & " /c echo y | """ & strPlink & """ " & strServer & " -pw " & strPassword & " root"

WScript.Echo "Test Connection on server " & strServer
return = DoConnection(strCmdline, strGenerateKey, strServer, True)

If (return > 0) Then
strGenerateKey=""
Do
WScript.Echo "Re-verify Connection on server " & strServer
return = DoConnection(strCmdline, strGenerateKey, strServer, True)
Loop While (return > 0 and return < 255)
If (return > 0) Then
WScript.Echo "Transfer " & strScriptToExecute & " script on server " & strServer
strCmdline = ComSpec & " /c """ & strPscp & """ -batch -C -pw " & strPassword & " " & strScriptToExecute & " root" & "@" & strServer & ":/tmp"
return = DoConnection(strCmdline, strGenerateKey, strServer, True)

WScript.Echo "Execute " & strScriptToExecute & " script on server " & strServer
strCmdline = ComSpec & " /c """ & strPlink & """ -batch -C -pw " & strPassword & " root" & "@" & strServer & ":/tmp" & " sh /tmp/" & strScriptToExecute
return = DoConnection(strCmdline, strGenerateKey, strServer, True)
End If
End If

Next


'
' Quit
'
WScript.Sleep 1000
WScript.Quit



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

' DoConnection
'
'
'
Function DoConnection(strCmdline, strGenerateKey, strServer, displayLogfile)
Dim objCmd, return, Continue

'WScript.Echo "cmdline->" & strCmdline
Set objCmd = objShell.Exec(strCmdline)
Do While objCmd.Status = 0
return = objCmd.stdErr.ReadAll
WScript.Sleep 100
Loop
If (displayLogfile) Then
Dim strStdOut
strStdOut = objCmd.StdOut.ReadAll()
If (len(strStdOut) > 0) Then
Wscript.Echo strStdOut
End If
End If

continue = 0
If Instr(return, "Access denied" ) > 0 Then ' Access denied
WScript.Echo "ERROR on server " & strServer & vbCrLf & return
continue = 0

Elseif Instr(return, "Unable to open connection" ) > 0 Then ' Unable to open connection
WScript.Echo "ERROR on server " & strServer & vbCrLf & return
continue = 0

Elseif Instr(return, "ERROR" ) > 0 Then ' FATAL ERROR: Network error: Connection timed out
WScript.Echo "ERROR on server " & strServer & vbCrLf & return
continue = 0

Elseif Instr(return, "fingerprint" ) > 0 Then
If (len(strGenerateKey) > 2) Then
WScript.Echo "GENERATE key fingerprint on server " & strServer
'WScript.Echo "generatekey->" & strGenerateKey
objShell.Exec(strGenerateKey)
continue = 1
Else
WScript.Echo "NOT GENERATE key fingerprint " & strServer
continue = 2
End If
Else
continue = 255
'WScript.Echo "Logged on " & strServer & " - " & return
End if

DoConnection = continue
End Function



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

' isFileExist
'
' Test if File Exist
'
Function IsFileExist(strInputFile)
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not objFSO.FileExists(strInputFile) Then
Wscript.echo strInputFile & " file not exist !"
IsFileExist = False
Else
IsFileExist = True
End If
End Function


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

' ReadFileToDict
'
' Read each line -> put in Dictionary
' strInputfile = file to read
' objDictionary = dictionary for results
'
Function ReadFileToDict(strInputFile, ByRef objDictionary)
Dim objFSO, objTextFile, strNextLine, i
Set objDictionary = CreateObject("Scripting.Dictionary")
Set objFSO = CreateObject("Scripting.FileSystemObject")
If isFileExist(strInputFile) Then
Set objTextFile = objFSO.OpenTextFile(strInputFile, ForReading)
i = 0
Do Until objTextFile.AtEndOfStream
strNextLine = Trim(objTextFile.Readline)
If ( (Not Left(strNextLine, 1) = "#") _
and (Not Left(strNextLine, 1) = ";") _
and (Len(strNextLine)>1) _
) Then
objDictionary.Add i, strNextLine
i = i + 1
End If
Loop
objTextFile.Close
ReadFileToDict = True
Else
ReadFileToDict = False
End If
End Function


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



You can download a .zip file here including an example with change_ntp.sh

Next step, if I had some time, a graphical interface with a description of each script and variables for each script.