Step 1: Install RacADM
$computerlist=@'
SERVER1
SERVER2
'@
$computernames=@($computerlist -split "`n")|%{$_.Trim()}
$fileURL="https://dl.dell.com/FOLDER08543783M/1/DellEMC-iDRACTools-Web-WINX64-10.3.0.0-4945.exe"
$expectedExecutable='racadm.exe'
$expectedInstallPath='C:\Program Files\Dell\SysMgt\iDRACTools\racadm'
$stageFolder='C:\Temp\'
function installProgramFromExeZipArchive{
param(
$computernames=$env:computername,
$fileURL="https://dl.dell.com/FOLDER07549599M/1/DellEMC-iDRACTools-Web-WINX64-10.2.0.0-4583_A00.exe",
$expectedExecutable='racadm.exe',
$expectedInstallPath='C:\program files\Dell\SysMgt\iDRACTools\racadm',
$stageFolder='C:\Temp\'
)
$results=[hashtable]@{}
function addEnvironmentalPath($pathToAdd){
$registryEnvironment='Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment'
$pathToAdd=if($pathToAdd -match '\\$'){$pathToAdd -replace '.$'}else{$pathToAdd}
try{
$originalPaths=(Get-ItemProperty -Path $registryEnvironment -Name PATH).path
$pathsArray=$originalPaths -split ';'|?{$_.trim() -ne ''}|%{if($_ -match '\\$'){$_ -replace '.$'}else{$_}}|Sort-Object -Unique
# dotNet method: [Environment]::SetEnvironmentVariable('Foo', 'Bar', 'Machine')
# legacy method: setx /M PATH "%PATH%;C:\Something\bin"
if($pathToAdd -in $pathsArray){
write-host "$pathToAdd is already included in the environmental paths: '$originalPaths'"
return $true
}else{
$newPathsArray=$pathsArray+$pathToAdd
$newPaths=$newPathsArray -join ';'
Set-ItemProperty -Path $registryEnvironment -Name PATH -Value $newPaths
$newRegistryEnvironment=(Get-ItemProperty -Path $registryEnvironment -Name PATH).Path
write-host "Environmental paths have been changed:`r`nFrom: $originalPaths`r`nTo: $newPaths"
return $true
}
# non-persistent environmental reload
# $Env:Path=[System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
}catch{
write-warning $_
return $false
}
}
foreach($computerName in $computernames){
$alreadyInstalled=invoke-command -computername $computername -scriptblock{
param($expectedExecutable,$addEnvironmentalPath,$expectedInstallPath)
$validCommand=try{
get-command $expectedExecutable -EA Ignore
}catch{
$false
}
if($validCommand){
return $validCommand
}else{
if(test-path "$expectedInstallPath\$expectedExecutable" -EA Ignore){
[scriptblock]::create($addEnvironmentalPath).invoke($expectedInstallPath)
$env:Path=[System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
return $(get-command $expectedExecutable -EA Ignore)
}else{
return $false
}
}
} -Args $expectedExecutable,${function:addEnvironmentalPath},$expectedInstallPath
if($alreadyInstalled){
write-host "$computername has already installed $expectedExecutable"
$results+=[hashtable]@{$computername=$true}
}else{
# Autogen variables
$fileName=[regex]::match($fileURL,'[^/\\&\?]+\.\w{3,4}(?=([\?&].*$|$))').value
$translatedVolume=[regex]::match($stageFolder,'^(\w)\:').captures.groups[1].value+'$'
$translatedFoldername=[regex]::match($stageFolder,'\:(.*)$').captures.groups[1].value
$remoteSmbPath=join-path $('\\'+$computerName+"\$translatedVolume") $translatedFoldername
try{
# Download the file directly onto target server's staging folder
Import-Module BitsTransfer
if(!(test-path $remoteSmbPath)){$null=mkdir $remoteSmbPath}
# Start-BitsTransfer -Source $fileURL -Destination $output
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Start-BitsTransfer -Source $fileURL -Destination $remoteSmbPath
$psSession=new-pssession $computerName
if($psSession.State -eq 'Opened'){
write-host "Now attempting to install $expectedExecutable on $computername..."
$result=invoke-command -Session $psSession -ScriptBlock{
param($stageFolder,$filename,$expectedExecutable,$expectedInstallPath,$addEnvironmentalPath)
# write-host "$env:computername : $stageFolder,$filename,$expectedExecutable,$expectedInstallPath"
# pause
$commandAvailable=try{get-command $expectedExecutable -EA Ignore}catch{$false}
if(!$commandAvailable -and $(test-path "$expectedInstallPath\$expectedExecutable" -EA Ignore)){
# if(!($env:path -like "*$expectedInstallPath*")){$env:path+=";$expectedInstallPath"}
# $null=RefreshEnv
$null=[scriptblock]::create($addEnvironmentalPath).invoke($expectedInstallPath)
$env:Path=[System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
$commandAvailable=try{get-command $expectedExecutable -EA Ignore}catch{$false}
}
if (!$commandAvailable){
write-host "Installing $expectedExecutable on $env:computername ..."
# $exeExists=try{ls $expectedInstallPath -EA Ignore|?{$_.Name -like $expectedExecutable}}catch{$false}
if($(test-path "$expectedInstallPath\$expectedExecutable" -EA Ignore)){
$null=[scriptblock]::create($addEnvironmentalPath).invoke($expectedInstallPath)
$env:Path=[System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
# $null=RefreshEnv
$commandNowAvailable=try{get-command $expectedExecutable -EA Ignore}catch{$false}
if($commandNowAvailable){
return $true
}else{
return $false
}
}else{
$expectedFileLocation=join-path $stageFolder $filename
$zipFilename=$([System.IO.Path]::GetFileNameWithoutExtension($expectedFileLocation))+'.zip'
$newZipFile=join-path $stageFolder $zipFilename
#[System.IO.Path]::GetExtension($expectedFileLocation)
Rename-Item -Path $expectedFileLocation -NewName $newZipFile -EA Ignore
# $null=Expand-Archive -Path $newZipFile -DestinationPath $stageFolder
# alternative method: backward compatible to older systems
Add-Type -AssemblyName System.IO.Compression.FileSystem
$null=[System.IO.Compression.ZipFile]::ExtractToDirectory($newZipFile, $stageFolder)
$msiFile=(ls $stageFolder|?{$_.FullName -match '\.msi$'}|sort -property LastWriteTime|select -first 1).FullName
Start-Process $msiFile -ArgumentList "/quiet" -wait
# this command doesn't work: msiexec /i $msiFile /quiet /qn /norestart
# $environmentalPathExists=$env:path -like "*$expectedInstallPath*"
$commandAvailable=try{get-command $expectedExecutable -EA Ignore}catch{$false}
if(!$commandAvailable -and $(test-path $expectedInstallPath -EA Ignore)){
$null=[scriptblock]::create($addEnvironmentalPath).invoke($expectedInstallPath)
$env:Path=[System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
#$env:path+=";C:\Program Files\Dell\SysMgt\iDRACTools\racadm"
#$null=RefreshEnv
}
$commandNowAvailable=try{get-command $expectedExecutable -EA Ignore}catch{$false}
if($commandNowAvailable){return $true}else{return $false}
}
}else{
write-host "Command $expectedExecutable is available on $env:computername"
return $true
}
} -Args $stageFolder,$fileName,$expectedExecutable,$expectedInstallPath,${function:addEnvironmentalPath}
Remove-PSSession $psSession
write-host "$computername result: $result"
$results+=[hashtable]@{$computername=$result}
}else{
write-warning "Unable to connect to $computername via WinRM"
$results+=[hashtable]@{$computername=$null}
}
}catch{
write-warning $_
$results+=[hashtable]@{$computername=$null}
}
}
if($computername -like "$env:computername*"){
$env:Path=[System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
}
}
return $results
}
installProgramFromExeZipArchive $computernames $fileURL $expectedExecutable $expectedInstallPath $stageFolder
Step 2: Invoke-Command toward a list of Remote Computers
$computerlist=@'
SERVER1
SERVER2
'@
$computernames=@($computerList -split "`n")|%{$_.Trim()}
$adminUid=2
$preferredAdminUsername='sysadmin'
$preferredPassword='PASSWORD1'
$admin2Username='backupadmin'
$admin2Password='PASSWORD2'
$admin2Uid=3
$alertEmailAddress='[email protected]'
$results=@()
foreach ($computername in $computernames){
$commands=@(
'racadm set iDRAC.EmailAlert.Enable.1 0', # disable email alerts prior to running commands
"racadm set system.lcd.LCDUserString $computername",
"racadm set iDRAC.NIC.DNSRacName $computername",
'racadm set iDRAC.Webserver.HostHeaderCheck 0', # Pre-empt SSL cert issues
'racadm set iDRAC.NIC.DNSRegister 0',
'racadm set iDRAC.IPv4.DHCPEnable 1',
'racadm set iDRAC.IPv4.DNSFromDHCP 1',
'racadm set iDRAC.NIC.DNSDomainFromDHCP 1',
'racadm set iDRAC.NIC.VLanEnable 0',
"racadm set iDRAC.Users.$adminUid.UserName $preferredAdminUsername",
"racadm set iDRAC.Users.$adminUid.Password $preferredPassword",
"racadm set iDRAC.Users.$admin2Uid.UserName $admin2Username",
"racadm set iDRAC.Users.$admin2Uid.Password $admin2Password",
"racadm set iDRAC.Users.$admin2Uid.Enable 1",
"racadm set iDRAC.Users.$admin2Uid.Privilege 0x1ff", # hex code for admin privilege
"racadm set iDRAC.EmailAlert.Address.1 $alertEmailAddress",
'racadm set iDRAC.EmailAlert.Enable.1 1'
)
# $commands=@(
# 'racadm set iDRAC.EmailAlert.Enable.1 0', # disable email alerts prior to running commands
# 'racadm set iDRAC.EmailAlert.Enable.1 1'
# )
# invokeRacAdmCommands $computername $command
$computername=[regex]::match($computername,'([a-zA-Z0-9-]{1,15})\.{0,1}').captures.groups[1].value # sanitize: remove ltd suffexes
$result=invoke-command -computername $computername {
param($commands)
write-host "Processing $env:computername..."
if(!(get-command racadm -EA Ignore)){
try{
$Env:Path=[System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
$null=get-command racadm
}catch{
write-warning $_
return "$env:computername commands overall: Failed (racadm.exe not available)"
}
}
$successes=@()
foreach($command in $commands){
write-host $command -nonewline
$success=invoke-expression $command
$passed=if($success|Select-String 'successfully'){
write-host ': success' -foregroundcolor Green
'success'
}else{
write-host ': failed' -foregroundcolor Red
'failed'
}
$successes+="$command`: $passed"
}
if('failed' -notin $successes){
$comment="$env:computername commands overall: Passed"
write-host $comment -foregroundcolor Green
}else{
$comment="$env:computername commands overall: Failed"
write-host $comment -foregroundcolor Red
}
$successes=,$comment+$successes
return $($successes|out-string)
} -Args (,$commands)
$results+=$result
# pause
}
Alternatively, use RacAdm API from a Central ‘Jump Host’
$iDracInterfaces=@'
server1.drac.kimconnect.com
server2.drac.kimconnect.com
'@
$iDracInterfaces=@($iDracInterfaces -split "`n")|%{$_.Trim()}
$possibleCredentials=@(
@{username='sysadmin';password='PASSWORD'},
@{username='root';password='calvin'}
)
$adminUid=2
$preferredAdminUsername='sysadmin'
$preferredPassword='PASSWORD'
$admin2Username='backupadmin'
$admin2Password='PASSWORD2'
$admin2Uid=3
$alertEmailAddress='[email protected]'
$commands=@(
"set system.lcd.LCDUserString $env:computername",
"set iDRAC.NIC.DNSRacName $env:computername",
'set iDRAC.NIC.DNSRegister 0',
'set iDRAC.IPv4.DHCPEnable 1',
'set iDRAC.IPv4.DNSFromDHCP 1',
'set iDRAC.NIC.DNSDomainFromDHCP 1',
'set iDRAC.NIC.VLanEnable 0',
"set iDRAC.Users.$admin2Uid.UserName $admin2Username",
"set iDRAC.Users.$admin2Uid.Password $admin2Password",
"set iDRAC.Users.$admin2Uid.Enable 1",
"set iDRAC.Users.$admin2Uid.Privilege 0x1ff", # code for admin privilege
'set iDRAC.EmailAlert.Enable.1 1',
"set iDRAC.EmailAlert.Address.1 $alertEmailAddress"
)
# make a comment to edge case where usernames collide
function remoteRacAdmCommands{
param(
$iDracInterfaces,
$possibleCredentials,
$commands,
$preferredAdminUsername='root',
$preferredPassword='calvin',
$adminUid=2
)
$ErrorActionPreference = 'stop'
$results=[hashtable]@{}
function invokeRacCommand($command){
write-host $command -nonewline
$success=invoke-expression $command
if($success|Select-String 'successfully'){
write-host ': success' -foregroundcolor Green
return $true
}else{
write-host ': failed' -foregroundcolor Red
return $false
}
}
foreach($computername in $iDracInterfaces){
$validIp=try{test-connection $computername -Count 1 -EA Ignore}catch{$false}
if($validIp){
$ipAddress=$validIp.IPV4Address.IPAddressToString
$goodCredentials=.{
write-host "Attempting to connect to $computername via $ipAddress"
foreach ($credentials in $possibleCredentials){
$testUsername=$credentials.username
$testPassword=$credentials.password
$test=racadm -r $ipAddress -u $testUsername -p $testPassword getractime
if($null -ne $test -and $test -match '\d{2}\:\d{2}\:\d{2}'){
write-host "Valid credentials on $ipAddress`: $testUsername/$testPassword"
return $credentials
}else{
write-warning "Test of username $testUsername with password $testPassword has failed."
$null=ping 127.0.0.1
}
}
return $null
}
if($goodCredentials){
$username=$goodCredentials.username
$password=$goodCredentials.password
$successes=@()
foreach($command in $commands){
$remoteCommand="racadm -r $ipAddress -u $username -p $password $command"
$success=invokeRacCommand $remoteCommand
$successes+=$success
}
$result=if($null -eq $($successes|?{$_ -eq $false})){'Passed'}else{'Failed'}
}else{
write-warning "Unable to login due to incorrect passwords"
$result='incorrect passwords'
}
}else{
write-warning "$computername is NOT pingable. Hence it's being skipped"
$result='NOT pingable'
}
$results+=[hashtable]@{$computername=$result}
}
return $results
}
remoteRacAdmCommands $iDracInterfaces $possibleCredentials $commands $preferredAdminUsername $preferredPassword $adminUid
OLD Notes…
Configure iDrac Settings
# Download and install RacAdm 10.2 :
$url='https://dl.dell.com/FOLDER07549599M/1/DellEMC-iDRACTools-Web-WINX64-10.2.0.0-4583_A00.exe'
$tempDir='C:\Temp'
mkdir $tempDir; cd $tempDir
wget $url
write-host "Please install RacAdm from $temp or search for a script with function named installProgramFromExeZipArchive to automate this process"
# Run this command after RacAdm is installed
$env:path += ";C:\Program Files\Dell\SysMgt\iDRACTools\racadm"; refreshenv
# Setup iDrac with standardized default settings
$adminUid=2
$adminPassword='insertPasswordHere'
racadm set iDRAC.Users.$adminUid.UserName admin
racadm set iDRAC.Users.$adminUid.Password $adminPassword
racadm set iDRAC.NIC.DNSRacName ($env:computername).tolower()
racadm set iDRAC.NIC.DNSRegister 0
racadm set iDRAC.IPv4.DHCPEnable 1
racadm set iDRAC.IPv4.DNSFromDHCP 1
racadm set iDRAC.NIC.DNSDomainFromDHCP 1
racadm set iDRAC.NIC.VLanEnable
How to execute racadm toward remote targets
# General syntax
racadm -r <racIpAddr> -u <username> -p <password> get <devicename>.<groupname>.[<index>].[<objectname>]
racadm -r <racIpAddr> -u <username> -p <password> set <devicename>.<groupname>.[<index>].<objectname> <value>
# Script example: how to set an alerting email address
$remoteNodes=@'
idracIP1
idracIP2
'@
$adminUsername='root'
$adminPassword='somepasswordhere'
$emailAddress='[email protected]'
$remoteNodes=@($remoteNodes -split "`n")|%{$_.Trim()}
foreach ($idracInterface in $remoteNodes){
try{
$commandsCount=2
$command1="racadm -r $idracInterface -u $adminUsername -p `$adminPassword set iDRAC.EmailAlert.Enable.1 1"
$command2="racadm -r $idracInterface -u $adminUsername -p `$adminPassword set iDRAC.EmailAlert.Address.1 $emailAddress"
write-host $command1
$result=racadm -r $idracInterface -u $adminUsername -p $adminPassword set iDRAC.EmailAlert.Enable.1 1
write-host $command2
$result+=racadm -r $idracInterface -u $adminUsername -p $adminPassword set iDRAC.EmailAlert.Address.1 $emailAddress
# racadm -r $idracInterface -u $adminUsername -p $adminPassword get iDRAC.EmailAlert.Enable.1
# racadm -r $idracInterface -u $adminUsername -p $adminPassword get iDRAC.EmailAlert.Address.1
$successes=($result|Select-String 'successfully').count
if($successes -ge $commandsCount){
write-host "$idracInterface commands successful: $successes" -foregroundcolor Green
}else{
write-warning "$idracInterface commands $successes of $commandsCount successful"
}
}catch{
write-warning $_
}
}