How to make the website Ping ARR server and say I am going down? - wcf

I have successfully configured the ARR in Windows Azure environment, the web server instances are added to server farm.
Using Health Check option in server farm, instance that timed-out or not responding is made unhealthy.
My Question is
Instead of the ARR web farm (doing health check every 10 seconds) ping the website, is it possible or the web role itself ping back the ARR server and say I am going down ?
Is it possible to ping the ARR Server from web role and say I am going down? or this is there any best approach available.
Please suggest.

I wanted some extra notifications with our ARR setup and I put this PowerShell script together that runs once an hour and checks the health status and notify me via email when ever any hosting server was seen as unhealthy. We also use other outside resources that ping the web farm externally once an minute and alerts us when it can't be seen (Pingdom). I have a feeling you're looking for a little more than this but I hope it helps a little.
#----- First add a reference to the MWA dll ----#
$dll=[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
#----- Get the manager and config object ----#
$mgr = new-object Microsoft.Web.Administration.ServerManager
$conf = $mgr.GetApplicationHostConfiguration()
#----- Get the webFarms section ----#
$section = $conf.GetSection("webFarms")
$webFarms = $section.GetCollection()
#----- Define an array for html fragments ----#
$fragments=#()
#----- Check each webfarm ----#
foreach ($webFarm in $webFarms)
{
$Name= $webFarm.GetAttributeValue("name");
#Get the servers in the farm
$servers = $webFarm.GetCollection()
#Write-Host "Farm Name: " $Name
$fragments+= "<b>Farm Name: $Name</b>"
$fragments+="<br>"
foreach($server in $servers)
{
$ip= $server.GetAttributeValue("address")
$hostname= ([system.net.dns]::GetHostByAddress($ip)).hostname
#Get the ARR section
$arr = $server.GetChildElement("applicationRequestRouting")
$counters = $arr.GetChildElement("counters")
$isHealthy=$counters.GetAttributeValue("isHealthy")
$state= $counters.GetAttributeValue("state")
switch ($state)
{
0 {$state= "Available"}
1 {$state= "Drain"}
2 {$state= "Unavailable"}
default {$state= "Non determinato"}
}
if( $isHealthy)
{
$isHealthy="Healthy"
$fragments+="$hostname -- $ip -- $state -- $isHealthy"
$fragments+="<br>"
}
else
{
$isHealthy="Not Healthy"
$notHealthy="RED ALERT!! This is what we trained for!"
$fragments+="$hostname -- $ip -- $state -- $isHealthy"
$fragments+="<br>"
}
#Write-Host -NoNewLine $hostname " " $ip " " $state " " $isHealthy
#NEW LINE
#Write-Host
}
#NEW LINE
#Write-Host
if($notHealthy){
#write the results to HTML formated email
$smtpServer = "SMTP server"
$smtpFrom = "email address"
$smtpTo = "email address"
$messageSubject = "Unhealthy Web Server"
$message = New-Object System.Net.Mail.MailMessage $smtpfrom, $smtpto
$message.Subject = $messageSubject
$message.IsBodyHTML = $true
$message.Body = $fragments
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($message)
}
}

Related

How to automate synchronizing Windows 10 guest's time with the Linux host?

On Arch Linux I have a Windows 10 Guest on top of libvirt, kvm and virsh (still having some trouble to connect all these dots mentally together). Every time I suspend the laptop and a day is gone the Windows 10 host goes out of sync. I learned that with the following command I can force a time sync in the host:
➜ ~ virsh qemu-agent-command win10 '{"execute":"guest-set-time"}'
{"return":{}}
In order to make this work I modifed the clock XML block and added a kvm clock entry. This is how the block looks like now:
<clock offset="localtime">
<timer name="tsc" tickpolicy="delay"/>
<timer name="kvmclock"/>
<timer name="rtc" tickpolicy="delay" track="wall"/>
<timer name="pit" tickpolicy="delay"/>
<timer name="hpet" present="yes"/>
</clock>
I would like to know whether I can automate this step or trigger an update everytime I wake up the machine or log-in.
Thanks in advance
I was not able to get anywhere specifically using virsh. Here is how I fixed this issue in a Windows 11 guest on MacOS in UTM 3.6.4 and 4.1.5.
At first I tried many workarounds using w32tm - but this was always flaky.
This helped slightly:
disable "use local time for base clock" (otherwise you can't add a manual -rtc argument if using UTM)
add -rtc base=localtime,driftfix=slew
This wasn't great, because it won't recover a significant delta.
This is the solution I settled on (run in the Windows guest). It creates a scheduled task that runs every 5 minutes, gets the time from NTP, converts it to local time, measures the drift, and if the drift is >30 seconds in either direction it updates the system clock.
function Get-NtpTime
{
[OutputType([datetime])]
[CmdletBinding()]
param
(
[string]$Server = "time.nist.gov",
[int]$Port = 13
)
if (-not $PSBoundParameters.ContainsKey('ErrorAction'))
{
$ErrorActionPreference = 'Stop'
}
$Client = [Net.Sockets.TcpClient]::new($Server, $Port)
$Reader = [IO.StreamReader]::new($Client.GetStream())
try
{
$Response = $Reader.ReadToEnd()
$UtcString = $Response.Substring(7, 17)
$LocalTime = [datetime]::ParseExact(
$UtcString,
"yy-MM-dd HH:mm:ss",
[cultureinfo]::InvariantCulture,
[Globalization.DateTimeStyles]::AssumeUniversal
)
}
finally
{
$Reader.Dispose()
$Client.Dispose()
}
$LocalTime
}
function Register-TimeSync
{
[CmdletBinding()]
param
(
[Parameter()]
[timespan]$RepetitionInterval = (New-TimeSpan -Minutes 5),
[Parameter()]
[timespan]$ExecutionTimeLimit = (New-TimeSpan -Minutes 3)
)
$Invocation = {
$NtpTime = Get-NtpTime
$Delta = [datetime]::Now - $NtpTime
if ([Math]::Abs($Delta.TotalSeconds) -gt 30)
{
Set-Date $NtpTime
}
}
$PSName = if ($PSVersionTable.PSVersion.Major -le 5) {'powershell'} else {'pwsh'}
$Path = (Get-Command $PSName).Source
$Command = Get-Command Get-NtpTime
$Definition = "function Get-NtpTime`n{$($Command.Definition)}"
$Invocation = $Definition, $Invocation -join "`n"
$Bytes = [Text.Encoding]::Unicode.GetBytes($Invocation)
$Encoded = [Convert]::ToBase64String($Bytes)
$TriggerParams = #{
Once = $true
At = [datetime]::Today
RepetitionInterval = $RepetitionInterval
}
$Trigger = New-ScheduledTaskTrigger #TriggerParams
$Action = New-ScheduledTaskAction -Execute $Path -Argument "-NoProfile -EncodedCommand $Encoded"
$Settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit $ExecutionTimeLimit -MultipleInstances IgnoreNew
$Principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$RegisterParams = #{
TaskName = "Update system time from NTP"
Trigger = $Trigger
Action = $Action
Settings = $Settings
Principal = $Principal
Force = $true
}
Register-ScheduledTask #RegisterParams
}
Usage (run as admin):
Register-TimeSync

How to test authentication to remote IP address

I have one powershell script that invokes another powershell script.
The first script is invoked with an ip address, which gets passed to the second script. The second script is supposed to return the userId in form Domain\User
The first script uses ProcessStartInfo and Process to get elevated credentials to call the second script
# part of first script
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
$startInfo.Arguments = "C:\script\second_script.ps1 "
$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $false
$startInfo.Username = Service_Account
$startInfo.Domain = Domain
$startInfo.Password = password
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start() | Out-Null
$standardOut = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
The second script has many try-catch blocks, such as checking whether we can ping the machine, checking whether we can access WMI
# part of second
# Can we ping the machine?
try{
Test-Connection $Sender_IP -count 1 -ErrorAction Stop | out-null
}
catch [Exception]
{
$userId = "Unknown/CannotPing "
return $output = "userId=" + $userId
}
try
{
<#Gather information on the computer corresponding to $Sender_IP#>
$Win32OS = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $Sender_IP -ErrorAction Stop
}
catch [Exception]
{
$userId = "Unknown/CannotDetectOS "
return $output = "userId=" + $userId
}
The script was unable to access WMI of many IP addresses. And when I was trying to troubleshoot by manually remoting into the IP address with the service account, I was unable to.
Now, I am trying to figure out a way for the script to check whether it can authenticate to the IP address. If the script is unable to authenticate to the IP address, it should throw and exception and not even check whether it can access WMI.
What cmdlets can help with this?

LDAP bind with Win Server 2008 R2 Standard AD fails

The environment is a single server running Win Server 2008 R2 Standard with SP1 with Apache 2.2 and PHP 5.3.19.
I have a PHP script that attempts to do an LDAP bind to the Win Server 2008 R2 Active Directory and fails no matter what variations I try. I put in a lot of echos to see the results at each step, and I've discovered that ldap_connect ALWAYS connects. I can put total garbage in the URL and it never fails. The latest iteration of my PHP script does an anonymous bind, then does an ldap_search, which fails.
Here's the script (actual domain, user & pswd changed):
<?php
define(LDAP_OPT_DIAGNOSTIC_MESSAGE, 0x0032);
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
echo "<br>LDAP set debug level: " . ldap_errno($ad) . ' ' . ldap_error($ad);
$LDAPhost = 'ldap://myDomain.com';
$LDAPport = '3268';
$ad = ldap_connect($LDAPhost, $LDAPport);
echo "<br>LDAP connect to $LDAPhost: " . ldap_errno($ad) . ' ' . ldap_error($ad);
if ($ad) {
ldap_set_option($ad, LDAP_OPT_PROTOCOL_VERSION, 3);
echo "<br>LDAP set protocol to version 3: " . ldap_errno($ad) . ' ' . ldap_error($ad);
ldap_set_option($ad, LDAP_OPT_REFERRALS, 0);
echo "<br>LDAP set referrals to 0: " . ldap_errno($ad) . ' ' . ldap_error($ad);
$bind = ldap_bind($ad);
echo "<br>LDAP bind: " . ldap_errno($ad) . ' ' . ldap_error($ad);
$baseDN = 'CN=Users,DC=myDomain,DC=com';
$filter = '(objectClass=*)';
$search = ldap_search($ad, $baseDN, $filter);
echo "<br>LDAP search $baseDN $filter: " . ldap_errno($ad) . ' ' . ldap_error($ad);
if ($rec = ldap_get_entries($ad, $search)) {
echo "<br>LDAP get entries: " . ldap_errno($ad) . ' ' . ldap_error($ad);
for ($i = 0; $i < $rec["count"]; $i++) {
echo "<br>$rec[0]['uid'][0]";
echo "<br>$rec[0]['givenname'][0]";
}
} else {
echo '<br>Record not found.';
}
ldap_close($ad);
} else {
echo '<br><br>Could not connect.';
}
?>
The displayed results are:
LDAP set debug level:
LDAP connect to ldap://myDomain.com: 0 Success
LDAP set protocol to version 3: 0 Success
LDAP set referrals to 0: 0 Success
LDAP bind: 0 Success
LDAP search CN=Users,DC=myDomain,DC=com (objectClass=*): 1 Operations error
Record not found.
Using the Windows LDP.exe utility, I am able to bind with the same user/pswd credentials used in the test.
I would love to know exactly what to put as the base DN, i.e. what is ldap_bind comparing these values to? Something in Active Directory? Something in the registry? Something else?
Searching for this stuff turns up lots of examples, but none that work for me. Any ideas?
The Base DN you need is a valid DN in your AD. How do you find a base DN? Well you need to look at the rootDSE, to see what the namingContexts attribute says.
If you have a Unix box with ldapsearch, you can do an
ldapsearch -x -h mydomain.com -p3268 | less to see what namingContexts values are.
AD usually has 4 namingContexts values as I recall by default. (Don't have an AD box to do a quick test against). Many GUI LDAP tools can let you connect and look at the rootDSE or else have a GUI way to see it.
One thing to note is if the base DN doesn't seem to work and you are sure of everything, try using the 2003 format for the username: user#domain instead of the DN. There seems to be an issue where a domain that was migrated from a 2003 controller to a 2008 controller might have issues binding using PHP LDAP functions. I don't have the full details as I'm still exploring it but the 2003 format works on a 2008 R2 domain controller. Below is a sample basic function used in testing.
# $ldapconn = a valid connection
# $username = a username in the format 'username#domain'
# #password = the password for the above user
function ad_auth($ldapconn,$username,$password){
ldap_set_option ($ldapconn, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
try {
$ldap_bind = ldap_bind($ldapconn, $username, $password);
} catch (Exception $e){
# Your error code
}
return $ldap_bind;
}
Usage: $rs = ad_auth($ldapconn,$username,$password);
If I figure out the cause I'll post it.

Optimise mail sending process of phpmailer

I am trying to send mails using phpmailer and code is working fine. However when I see the CPU usage history in task manager I could see it is fluctuating rapidly between 0% to 100%. And RAM usage is constant around 4.65GB of 6GB.
I was able to send 500 emails in 15 minutes or so and I feel its bit slow because my CPU usage is fluctuating a lot, may be I am wrong in my assumption.
Can anyone help me in optimizing max usage of my system and fasten the process?
Also I have created a column in table email_sent to check how many mails have been sent and avoid any duplication but the code is not updating the database and giving up! (so it is commented out below).
<?php
//this code sends mails in HTML format using emailids from database. It also sends attachment if needed.
error_reporting(E_ALL);
//error_reporting(E_STRICT);
ini_set("display_errors", "on");
ini_set('max_execution_time', 30000000); //300 seconds = 5 minutes
ini_set('memory_limit', '6500M'); //Maximum amount of memory a script may consume (128MB by default)
date_default_timezone_set('UTC');
require_once('../class.phpmailer.php');
//include("class.smtp.php"); // optional, gets called from within class.phpmailer.php if not already loaded
$mail = new PHPMailer();
$body = file_get_contents("contents.html");
//$body = preg_replace('/[\]/','',$body);
$body = preg_replace('/IDontKnowWTFThisFunctionIsdoing/','',$body);
$mail->IsSMTP(); // telling the class to use SMTP
$mail->Host = "ssl://smtp.gmail.com";
$mail->SMTPAuth = true; // enable SMTP authentication
$mail->SMTPKeepAlive = true; // SMTP connection will not close after each email sent
$mail->Host = "ssl://smtp.gmail.com"; // sets the SMTP server
$mail->Port = 465; // set the SMTP port for the GMAIL server
$mail->Username = "myemail#gmail.com"; // SMTP account username
$mail->Password = "password"; // SMTP account password
//$mail->SetFrom ('myemail#gmail.com', 'me');
$mail-> From = "myemail#gmail.com";
$mail->FromName = "me";
$mail->AddReplyTo ('myemail#gmail.com', 'me');
$mail->Subject = "Subject";
#MYSQL_CONNECT("localhost","root","");
#mysql_select_db("database");
$startnum1 = 501;
$endnum1 = 5000;
//$query = "SELECT emailid FROM test WHERE email_sent = 0 Limit $startnum1,$endnum1";
$query = "SELECT emailid FROM test Limit $startnum1,$endnum1";
$result = #MYSQL_QUERY($query);
echo "message sending in process";
while ($row = mysql_fetch_array ($result)) {
$mail->body = $body;
$mail->AltBody = "To view the message, please use an HTML compatible email viewer!"; // optional, comment out and test
$mail->IsHTML(true);
$mail->MsgHTML($body);
$mail->AddAddress($row["emailid"], $row["emailid"]);
//$mail->AddStringAttachment($row["emailid"], "contents.html");
if(!$mail->Send()) {
echo "Mailer Error (" . str_replace("#", "#", $row["emailid"]) . ') ' . $mail->ErrorInfo . '<br />';
} else {
//$query1 = "UPDATE test SET Email_Sent= 1 WHERE EmailID= emailid Limit $startnum1,$endnum1";
//$result1 = #MYSQL_QUERY($query1);
echo "Message sent to :" . $row["emailid"] . ' (' . str_replace("#", "#", $row["emailid"]) . ')<br />';
}
// Clear all addresses and attachments for next loop
$mail->ClearAddresses();
//$mail->ClearAttachments();
}
[CPU history] (http://s3.postimg.org/v99ucpq6p/Capture.jpg)
[System information] (http://s3.postimg.org/3n72s16tt/Capture1.jpg)
?>

How can you add a Certificate to WebClient in Powershell

I wan't to examine a Webpage which requires Client Side Certificate Authentication.
How can i provide my Cert from the Certstore to the Webrequest:
Is there a way to specify this in Credentials odr within the Proxy?
$webclient = New-Object Net.WebClient
# The next 5 lines are required if your network has a proxy server
$webclient.Credentials = [System.Net.CredentialCache]::DefaultCredentials
if($webclient.Proxy -ne $null) {
$webclient.Proxy.Credentials = `
[System.Net.CredentialCache]::DefaultNetworkCredentials
}
# This is the main call
$output = $webclient.DownloadString("$URL")
PS: Maybe this helps: How can you add a Certificate to WebClient (C#)? But i don't get it.. ;-)
Using the new Add-Type functionality in PowerShell v2, you can craft a custom class that you can then use to make your typical WebRequest. I have included a method on the custom class to allow you to add certificates that can be used for authentication.
PS C:\> $def = #"
public class ClientCertWebClient : System.Net.WebClient
{
System.Net.HttpWebRequest request = null;
System.Security.Cryptography.X509Certificates.X509CertificateCollection certificates = null;
protected override System.Net.WebRequest GetWebRequest(System.Uri address)
{
request = (System.Net.HttpWebRequest)base.GetWebRequest(address);
if (certificates != null)
{
request.ClientCertificates.AddRange(certificates);
}
return request;
}
public void AddCerts(System.Security.Cryptography.X509Certificates.X509Certificate[] certs)
{
if (certificates == null)
{
certificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
}
if (request != null)
{
request.ClientCertificates.AddRange(certs);
}
certificates.AddRange(certs);
}
}
"#
PS C:\> Add-Type -TypeDefinition $def
You would perhaps want to limit the certificates being added to just the one (or ones) you would want to use rather than just use every available certificate in the Current User store, but here is an example that just loads all of them:
PS C:\> $wc = New-Object ClientCertWebClient
PS C:\> $certs = dir cert:\CurrentUser\My
PS C:\> $wc.AddCerts($certs)
PS C:\> $wc.DownloadString("http://stackoverflow.com")