$arecord='intranet'
$domain='contoso.com'
$serverIp='555.555.555.555'
$groupTag='# Accounting Servers'
$serversToEdit='Accounting1','Accounting2','Watermelon'
$commentOut=$false
function updateHostFiles{
param(
$appLocalIp, $orgName, $domain, $searchString, $servers,$commentOut=$false
)
# placing this supporting function for easy copy/paste
function confirmation($content,$testValue="I confirm",$maxAttempts=3){
$confirmed=$false;
$attempts=0;
$content|write-host
write-host "Please review this content for accuracy.`r`n"
while ($attempts -le $maxAttempts){
if($attempts++ -ge $maxAttempts){
write-host "A maximum number of attempts have reached. No confirmations received!`r`n"
break;
}
$userInput = Read-Host -Prompt "Please type in this value => $testValue <= to confirm";
if ($userInput.ToLower() -ne $testValue.ToLower()){
cls;
$content|write-host
write-host "Attempt number $attempts of $maxAttempts`: $userInput does not match $testValue. Try again..`r`n"
}else{
$confirmed=$true;
write-host "Confirmed!`r`n";
break;
}
}
return $confirmed;
}
function generateARecord{
param(
$newARecord,
$domain,
$ip
)
$url=$newARecord+'.'+$domain;
$recordString="$ip`t$url";
return $recordString;
}
function updateHostRecord{
param(
$record,
$insertAfter,
$servers,
$remove=$false
)
$hostFiles=$($servers|%{"\\$_\C$\windows\system32\drivers\etc\hosts"})
$results=@{}
#replaceLine -textContent $fileContent -match $url -updateLineContent $record -remove $remove
function replaceLine($textContent,$match,$updateLineContent,$remove=$false){
write-host "Search string: $match"
$lineMatch = $textContent | Select-String "$match"
$lineNumber = $lineMatch.LineNumber
$lineContent = $lineMatch.Line
$replaceWith=if($remove){if($lineContent[0] -eq '#'){$lineContent}else{"#$lineContent #record disabled $(get-date) by $(whoami)"}}
else{$updateLineContent}
write-host "Replacing`t: $lineMatch`r`nWith`t: $replaceWith"
$textContent[$lineNumber-1]=$replaceWith
return $textContent
}
function updateLocalHostRecord{
param(
$record,
$hostfile="c:\windows\system32\drivers\etc\hosts",
$searchString=$false,
$remove=$false
)
function insertAfterMatchString{
param(
$content,
$searchString,
$insert,
$remove=$false
)
if($remove){$insert='#'+$insert}
[int]$matchedIndex=.{$lines=[array]$content
for ($i=0;$i -lt $lines.Count;$i++) {if($lines[$i] -like "$searchString*"){return $i}}
}
if($matchedIndex){
$nextAvailableSpaceIndex=.{for($i=$matchedIndex;$i -lt $content.Length;$i++){
$isEmpty=$content[$i] -match "^\s*$"
#$isEmpty=$content[$i].Trim().isEmpty()
if ($isEmpty){return $i}
}
}
$content=$content[0..$($nextAvailableSpaceIndex-1)]+$insert+$content[$($nextAvailableSpaceIndex)..$($content.length-1)]
write-host "$insert will be inserted after $($content[$nextAvailableSpaceIndex-1])`r`n-----------------------`r`n"
}else{
$content+=$insert
write-host "$searchString has not matched anything.";
}
return $content
}
$validPath=[System.IO.File]::Exists($hostfile) # Slightly faster than Test-Path for true positives but not true negatives
if($validPath){
$fileContent=Get-Content -Path $hostfile
$url=.{[void]($record -match "([0-9A-Za-z_\.\-]*)$");$matches[1]}
$entryExists=$fileContent|?{$_ -match "$url"}|select -First 1
write-host "Entry exists: $entryExists"
if(!$entryExists){
write-host "Search string: '$searchString'"
pause
if($searchString){
$fileContent=insertAfterMatchString -content $fileContent -searchString $searchString -insert $record $remove
}else{
$fileContent+=$(if($remove){'#'})+$record
}
$confirmed=confirmation -content $fileContent
if ($confirmed){
$backupFile=$hostFile+"_backup"
try{
Rename-Item -Path $hostfile -NewName $backupFile -ErrorAction Stop
}
catch{
write-host "Unable to rename. Now trying to delete previous backup and retry"
Remove-item $backupFile -Force
Rename-Item -Path $hostfile -NewName $backupFile
}
# The try-catch method overcomes this error
#Rename-Item : Cannot create a file when that file already exists.
#At line:1 char:1
#+ Rename-Item -Path $hostfile -NewName $($hostFile+"_backup") -Force
#+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# + CategoryInfo : WriteError: (C:\windows\system32\drivers\etc\hosts:String) [Rename-Item], IOException
# + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand
$fileContent|set-Content $hostfile
$message="$hostfile updated successfully."
write-host $message -ForegroundColor Green
return $message
}else{
$message="$hostfile update cancelled."
write-host $message -ForegroundColor Red
return $message;
}
}
else{
$fileContent=replaceLine -textContent $fileContent -match $url -updateLineContent $record -remove $remove
$confirmed=confirmation -content $fileContent
if ($confirmed){
$backupFile=$hostFile+"_backup"
try{
Rename-Item -Path $hostfile -NewName $backupFile -ErrorAction Stop
}
catch{
write-host "Unable to rename. Now trying to delete previous backup and retry"
Remove-item $backupFile -Force
Rename-Item -Path $hostfile -NewName $backupFile
}
# The try-catch method overcomes this error
#Rename-Item : Cannot create a file when that file already exists.
#At line:1 char:1
#+ Rename-Item -Path $hostfile -NewName $($hostFile+"_backup") -Force
#+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# + CategoryInfo : WriteError: (C:\windows\system32\drivers\etc\hosts:String) [Rename-Item], IOException
# + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand
$fileContent|set-Content $hostfile
$message="$hostfile updated successfully."
write-host $message -ForegroundColor Green
return $message
}else{
$message="$hostfile update cancelled."
write-host $message -ForegroundColor Red
return $message;
}
}
}else{
$message="Unable to access $hostfile. Action aborted.";
write-warning $message
return $message;
}
}
for ($i=0;$i -lt $hostFiles.count; $i++){
$hostfile=$hostFiles[$i]
write-host "Processing $hostfile..."
$result=updateLocalHostRecord -record $record -hostfile $hostFile -searchString $insertAfter -remove $remove
$results.Add($servers[$i],$result)
}
return $results
}
function updateHostRecordOnServers{
param(
$appLocalIp,
$orgName,
$domain,
$searchString,
$servers,
$remove=$false
)
$regexIP = [regex] "\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"
if ($appLocalIp -match $regexIP){
$newRecord=generateARecord -newARecord $orgName -domain $domain -ip $appLocalIp
$result=updateHostRecord -record $newRecord -insertAfter $searchString -servers $servers -remove $remove
}else{
$result="Unable to retrieve the app server private IP. Cannot update host records without that information."
write-warning $result
}
return $result
}
return updateHostRecordOnServers $appLocalIp $orgName $domain $searchString $servers $commentOut
#$regexIP = [regex] "\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"
#$newRecord=generateARecord -newARecord $orgName -domain $domain -ip $appLocalIp
#foreach ($server in $servers){
# if ($appLocalIp -match $regexIP){
# #updateHostRecord -record $newRecord -insertAfter $searchString -servers $server -remove $remove
# invoke-command -ComputerName $server -credential $adminCredential -scriptblock {
# param ($updateHostRecord,$newRecord, $searchString, $server, $remove)
# [ScriptBlock]::Create($updateHostRecord).invoke($newRecord, $searchString, $server, $remove)
# } -Args ${function:updateHostRecord},$newRecord, $searchString, $server, $remove
# }
# else{
# write-host "Unable to retrieve the app server private IP. Cannot update host records without that information."
# }
#}
}
# updateHostFiles $appLocalIp $orgName $domain $searchString $sourceServers $commentOut
function invokeUpdateHostFiles{
param(
$adminCredential,$serverLocalIp,$orgName, $domain, $searchString,$targetHosts,$remove=$false
)
$jobResults=start-job -credential $adminCredential -scriptblock {
param ($updateHostFiles,$serverLocalIp, $orgName, $domain, $searchString, $targetHosts,$remove)
[ScriptBlock]::Create($updateHostFiles).invoke($serverLocalIp, $orgName, $domain, $searchString, $targetHosts,$remove)
} -Args ${function:updateHostFiles},$serverLocalIp, $orgName, $domain, $searchString, $targetHosts,$remove|Receive-Job -Wait
return $jobResults
}
invokeUpdateHostFiles $adminCredential $serverIp $aRecord $domain $groupTag $serversToEdit $commentOut
Categories: