How to check Time synchronization for domain controllers? - windows

I am trying to write a PowerShell script to alert me if one of the domain controllers goes out of sync via an email, I tried to run the script, but I had a problem with sending the email, here is the code. Could you please help me and tell me what is missing in my code? I did not receive any email, so how can I send the script results to my email?
function Get-Time {
<#
.SYNOPSIS
Gets the time of a windows server
.DESCRIPTION
Uses WMI to get the time of a remote server
.PARAMETER ServerName
The Server to get the date and time from
.EXAMPLE
PS C:\> Get-Time localhost
.EXAMPLE
PS C:\> Get-Time server01.domain.local -Credential (Get-Credential)
#>
[CmdletBinding()]
Param(
[Parameter(Position=0, Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[System.String]
$ServerName,
$Credential
)
try {
if ($Credential) {
$DT = Get-WmiObject -Class Win32_LocalTime -ComputerName $servername -Credential $Credential
} else {
$DT = Get-WmiObject -Class Win32_LocalTime -ComputerName $servername
}
} catch {
throw
}
$w32tm = Invoke-Command -Computer $Servers -ArgumentList $Servers -Scriptblock {
Param ($Servers)
foreach ($Server in $Servers) {
$Check = w32tm /monitor /computers:$Server /nowarn
$ICMP = (($Check | Select-String "ICMP")-Replace "ICMP: " , "").Trim()
$ICMPVal = [int]($ICMP -split "ms")[0]
$Source = w32tm /query /source
$Name = Hostname
switch ($ICMPVal) {
{$ICMPVal -le 0} {$Status = "Optimal time synchronisation"}
#you probably need another value here since you'll get no status if it is between 0 and 2m
{$ICMPVal -lt 100000} {$Status = "0-2 Minute time difference"}
{$ICMPVal -ge 100000} {$Status = "Warning, 2 minutes time difference"}
{$ICMPVal -ge 300000} {$Status = "Critical. Over 5 minutes time difference!"}
}
$String = $Name + " - $Status " + "- $ICMP " + " - Source: $Source"
Write-Output $String
}
}
$Servers = "localhost","DC001"
$Servers | Foreach {
Get-Time $_
$results = foreach ($Server in $Servers) {
Get-Time $Server
}
$Servers = "localhost","DC001"
$From = "abc#company.com"
$To = "abc#company.com"
$Cc = ""
$Subject = "Time Skew Results"
$Body = $Servers | ConvertTo-Html | Out-String
$SMTPServer = "imail.company.com"
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -BodyAsHTML
}
}

I wrote the code again and it works now, here is the code:
$w32tm = Invoke-Command -Computer $Servers -ArgumentList $Servers -Scriptblock {
Param ($Servers)
Foreach ($Server in $Servers)
{
$Check = w32tm /monitor /computers:$Server /nowarn
$ICMP = (($Check | Select-String "ICMP")-Replace "ICMP: " , "").Trim()
$ICMPVal = [int]($ICMP -split "ms")[0]
$Source = w32tm /query /source
$Name = Hostname
Switch ($ICMPVal)
{
#{$ICMPVal -le 0} {$Status = "Optimal time synchronisation"}
#{$ICMPVal -lt 100000} {$Status = "0-2 Minute time difference"}
{$ICMPVal -ge 100000} {$Status = "Warning, 2 minutes time difference"}
{$ICMPVal -ge 300000} {$Status = "Critical. Over 5 minutes time difference!"}
}
if ($ICMPVal -gt 100000)
{
$String = "The Domain Controller: " + $Name + " has " + " - $Status " + " - $ICMP " + " - Source: $Source"
$From = "abc#company.com"
$To = "abc#company.com"
$Cc = ""
$Subject = "Time Synchronization Alert "
$Body = Write-Output $String
$SMTPServer = "imail.company.com"
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -BodyAsHTML
}
}
}
$w32tm

Related

How to collect system monitor information remotly using powershell?

I have code to collect system information remotely and create a csv file ,below,
Param(
[Parameter(Mandatory=$true, position=0)][string]$infile,
[Parameter(Mandatory=$true, position=1)][string]$outfile
)
#Column header in input CSV file that contains the host name
$ColumnHeader = "ComputerName"
$HostList = import-csv $infile | select-object $ColumnHeader
$out = #()
foreach($object in $HostList) {
$os = Get-WmiObject -computername $object.("ComputerName") -class win32_operatingsystem
$vol = Get-WmiObject -computername $object.("ComputerName") -class Win32_Volume
$net = Get-WmiObject -computername $object.("ComputerName") -class Win32_NetworkAdapterConfiguration | where-object { $_.IPAddress -ne $null }
$DeviceInfo= #{}
$DeviceInfo.add("Operating System", $os.name.split("|")[0])
$DeviceInfo.add("Version", $os.Version)
$DeviceInfo.add("Architecture", $os.OSArchitecture)
$DeviceInfo.add("Serial Number", $os.SerialNumber)
$DeviceInfo.add("Organization", $os.Organization)
$DeviceInfo.add("Disk Capacity", "$([math]::floor($vol.Capacity/ (1024 * 1024 * 1024 )) )" + " GB" )
$DeviceInfo.add("Free Capacity", "$([math]::floor($vol.FreeSpace/ (1024 * 1024 * 1024 )))" + " GB" )
$DeviceInfo.add("System Name", $vol.SystemName)
$DeviceInfo.add("File System", $vol.FileSystem)
$DeviceInfo.add("IP Address", ($net.IPAddress -join (", ")))
$DeviceInfo.add("Subnet", ($net.IPSubnet -join (", ")))
$DeviceInfo.add("MAC Address", $net.MACAddress )
$out += New-Object PSObject -Property $DeviceInfo | Select-Object `
"System Name", "Organization", "Serial Number","Operating System", `
"Version","Architecture","File System","Disk Capacity", `
"Free Capacity","MAC Address","IP Address","Subnet"
Write-Verbose ($out | Out-String) -Verbose
$out | Export-CSV $outfile -NoTypeInformation
}
and i have a script to get monitor information
function Decode {
If ($args[0] -is [System.Array]) {
[System.Text.Encoding]::ASCII.GetString($args[0])
}
Else {
"Not Found"
}
}
ForEach ($Monitor in Get-WmiObject WmiMonitorID -Namespace root\wmi) {
$Manufacturer = Decode $Monitor.ManufacturerName -notmatch 0
$Name = Decode $Monitor.UserFriendlyName -notmatch 0
$Serial = Decode $Monitor.SerialNumberID -notmatch 0
$ManufactureWeek = (Get-WmiObject WmiMonitorID -Namespace root\wmi).WeekofManufacture
$ManufactureYear = (Get-WmiObject WmiMonitorID -Namespace root\wmi).YearOfManufacture
echo "Manufacturer: $Manufacturer`nName: $Name`nSerial Number: $Serial"
echo "Week of Manufacture: $ManufactureWeek"
echo "Year of Manufacture: $ManufactureYear"
}
how can i combine these codes to get monitor information remotly,
how can i get monitor information remotely???????????
You may also update your monitor script. With more than one monitor, it will not work correctly.
function Decode {
If ($args[0] -is [System.Array]) {
[System.Text.Encoding]::ASCII.GetString($args[0])
}
Else {
"Not Found"
}
}
ForEach ($Monitor in Get-WmiObject WmiMonitorID -Namespace root\wmi) {
$Manufacturer = Decode $Monitor.ManufacturerName -notmatch 0
$Name = Decode $Monitor.UserFriendlyName -notmatch 0
$Serial = Decode $Monitor.SerialNumberID -notmatch 0
$ManufactureWeek = $Monitor.WeekofManufacture
$ManufactureYear = $Monitor.YearOfManufacture
echo "Manufacturer: $Manufacturer`nName: $Name`nSerial Number: $Serial"
echo "Week of Manufacture: $ManufactureWeek"
echo "Year of Manufacture: $ManufactureYear"
}

Powershell, send email for each user that has been disabled to their managers

So after a-lot of help, there is a script that will search users that were disabled for the past 14 days + show their managers name + email and date when they were disabled:
$ou = "my-ou"
$date = (Get-Date).AddDays(-14)
$todaydate = Get-Date -DisplayHint Date
$disabledAccounts = Get-aduser -filter {Enabled -eq $false -and Modified -ge $date } -SearchBase $ou -Properties Modified,manager | select samaccountname,Modified,manager
#$ManagerName = ''
$Body = ”
<html>
<body>
<p>Dear $ManagerName,<br>
The user $userName has been disabled on $todaydate .<br
</body>
</html>”
ForEach($disabledAccount in $disabledAccounts){
$manager = get-aduser -property emailaddress,DisplayName $disabledAccount.manager
$ManagerName= $manager.Displayname
$userName = $disabledAccount.samaccountname
Send-MailMessage -To $manager.UserPrincipalName -From ‘test#email.com’ -Subject ‘Disabled account’ -Body $Body -SmtpServer ‘mysmtp’ -BodyAsHtml -Priority High
}
The problem for now that this script only sent email for 1 user when in my test i have 2 disabled users in this period of time.
And the first command with "Get-Aduser" i see both of the users, and in the second one "Get-aduser" i see only 1.
$ou = "my ou direction"
$date = (Get-Date).AddDays(-14)
$diabledAccounts = Get-ADUser -Filter {Enabled -eq $false -and Modified -ge $date } -SearchBase $ou -Properties Modified,manager | select samaccountname,Modified,#{n='Manager';e={(Get-ADUser $.manager).name}},#{n='ManagerEmail';e={(Get-ADUser $.manager -properties mail).mail}}
ForEach($diabledAccount in $diabledAccounts){
Send-MailMessage -To $diabledAccount.ManagerEmail -Subject 'Disabled account' -Body "Account $diabledAccount.samaccountname has been disabled in the last 14 days" -SmtpServer ''
}
I answered something like this on Spice works
$ou = “my_ou”
$date = (Get-Date).AddDays(-14)
$disabledAccounts = Get-aduser -filter {Enabled -eq $false -and Modified -ge $date } -SearchBase $ou -Properties Modified,manager | select samaccountname,Modified,manager
$ManagerName = ''
$Body = ”
<html>
<body>
<p>Dear $ManagerName,<br>
The user $userName has been disabled on .<br
</body>
</html>”
ForEach($disabledAccount in $disabledAccounts){
$manager = get-aduser -property emailaddress,DisplayName $disabledAccount.manager
$ManagerName= $manager.Displayname
$userName = $disabledAccount.samaccountname
Send-MailMessage -To $manager.ManagerEmail -From ‘myemail#’ -Subject ‘Disabled account’ -Body $Body -SmtpServer ‘mysmtp server’ -BodyAsHtml -Priority High
}

Powershell Get-Service report wrong information

I've created a powershell script to list all domain controllers under current trusted forest, and than check each individual server for specific services if it's running or not and send an email with report.
I found 2 issues so far.
Get-Service -name "MyService" -ComputerName $myComputer "will say no service is found with that name, but if I list all the services : Get-Service -ComputerName $myComputer it will say "This operation might require other privileges." This is a problem because I'm reporting that the service doesn't exist but it is actually there.
For some reason if I just run the powershell script from command line manually it lists way more servers and most of the info is correct. But I schedule the powershell script from windows task manager with that same account the information is all wrong and it reports way less servers.
Script:
#$domain = [system.directoryservices.activedirectory.domain]::GetCurrentDomain().Name
#$numerOfDomainControlers= nslookup $domain
Clear-Content .\log.txt
$startTime = Get-Date
$allDCs = ((Get-ADForest).Domains | %{ Get-ADDomainController -Filter * -Server $_ } | Where-Object { $_.hostname -notlike '*root*' }).hostname
foreach( $allDC in $allDCs){
$testConnection = Test-Connection $allDC -Quiet -Count 1 -ErrorAction SilentlyContinue
Write-Host
if($testConnection -like "true") {
$SyncStatus = Get-Service -name "MyServicesName" -ComputerName $allDC -ErrorAction SilentlyContinue
if($SyncStatus.length -eq 0) {
Write-Host "MyServicesName doesn't exists on:"$allDC
$SyncStatus = "MyServicesName doesn't exists on:" + $allDC
$logs = $SyncStatus |Out-File .\log.txt -Append
}
else{
write-host "MyServicesName on "$allDC "is: " $SyncStatus.status
$SyncStatus = "MyServicesName on " + $allDC + "is: " + $SyncStatus.status
$logs = $SyncStatus |Out-File .\log.txt -Append
}
}
else
{
Write-Host "Test Connection to Server failed:"$allDC
$SyncStatus = "Test Connection to Server failed:" + $allDC
$logs = $SyncStatus |Out-File .\log.txt -Append
}
}
$endTime = Get-Date
$totalTime = New-TimeSpan -start $startTime -end $endTime
Write-Host $totalTime
$logs = "Total Time in Seconds:" + $totalTime |Out-File .\log.txt -Append
#send Email
$logs = Get-Content .\log.txt
$serverName = $env:computername
$LogTime = Get-Date -Format "MM/dd/yyyy hh:mm:ss"
$FromAddress = "email.com"
$ToAddress = "email.com"
foreach($log in $logs)
{
$Messagebody = $messagebody + $log + "`r`n" |Out-String
}
[string] $MessageSubject ="Status Report runing on " + $serverName +" " + $endTime
$SendingServer = "server"
Send-MailMessage -to $ToAddress -from $FromAddress -subject $MessageSubject -smtpServer $SendingServer -body $Messagebody -Attachments .\log.txt

send mail after successfull powershell script execution

So I created the script below:
$target = "c:\$(get-date -F 'yyyy-MM')"
if (!(Test-Path $target)) {md $target}
gci 'c:\test\' -Filter *.xml -recurse | ?{!$_.PSIsContainer -and $_.CreationTime -ge (get-date "01.$((get-date).Month)")} | copy-item -Destination $target -Force
Could somebody point me to the right direction of how to send a email to a specific address after this script was successfully executed ?
As arco444 noted in his comment, send-mailmessage will allow you to send email from any machine running Powershell v2 or higher, as long as you have an accessible SMTP server.
you can try below solution in PowerShell
$EmailFrom = "someone1#company.com"
$EmailTo = "someone2#company.com"
$ccUsers="someone3#company.com"
$SMTPServer = "smtp.office365.com"
$port=587
$smtp = New-Object Net.Mail.SmtpClient($SMTPServer,$port)
$smtp.EnableSsl = "true"
$smtp.Credentials =New-Object System.Net.NetworkCredential($userName, $password);
$msg = New-Object Net.Mail.MailMessage
$msg.From = $EmailFrom
$msg.To.Add($EmailTo)
$msg.CC.Add($ccUsers)
$msg.IsBodyHTML = $true
$msg.Subject = "Test Subject";
#if you want to send some html in your email
$html = "<html><body><table width='100%'><tr bgcolor='#CCCCCC'><td height='25' align='center'> <font face='tahoma' color='#003399' size='4'><strong>Test Email from PowerShell</strong></font></td> </tr> </table></body></html>" $msg.Body = $html; $smtp.Send($msg);
If your using outlook, here is a example
[system.reflection.assembly]::loadwithpartialname("Microsoft.office.interop.outlook")
$OL=New-Object -ComObject OUTLOOK.APPLICATION
$ns =$OL.GETNAMESPACE("MAPI")
$mail =$ol.createitem(0)
$mail.recipients.add("something#live.nl")
$mail.CC=("something#ziggo.nl")
$MAIL.Subject= "$shortname"
#gets a signature
$mail.htmlbody= get-content $env:appdata\Microsoft\Signatures\*.txt
#for attachments..
$mail.Attachments.Add($file.FullName)
$lines=get-content $filename
$lines+=get-content $env:appdata\Microsoft\Signatures\*.txt
clear-variable text
foreach ($line in $lines)
{
$text += $line + "`r`n"
}
$mail.body= $text
$mail.display()

Clearing temp items stored by Powershell

We use this script to try and get information from some of our servers. Issue that I have is the script somehow "saves" the last server IP, so when the next server in the list is unreachable we still get a "success" response from the previous IP. I have tried using the Clear-Item variable: command after every test but it doesn't seem to release the value.
$enddate = (Get-Date).tostring("yyyyMMdd")
$filename_SRM = 'C:\Scripts\' + $enddate + '_SRM_Scan.csv'
$compArray = get-content C:\Scripts\Servers.txt
foreach($strComputer in $compArray)
{
$ErrorActionPreference = “SilentlyContinue”
$ping = new-object system.net.networkinformation.ping
$ping.send(“$strComputer”) | Where-Object{$_.Name -eq 'Address'}
$pingreturns = $ping.send(“$strComputer”).Status
$socket = new-object Net.Sockets.TcpClient
$port = 135 #445
$socket.Connect($strComputer, $port)
$Network = Get-WMIObject -class Win32_NetworkAdapterConfiguration -Computername $strComputer | `
Where-Object {$_.IPEnabled -match "True"} | `
Select-Object -property DNSHostName,#{N="DNSServerSearchOrder";
E={"$($_.DNSServerSearchOrder)"}},
#{N='IPAddress';E={$_.IPAddress}}
$IP = [System.Net.Dns]::GetHostAddresses(“$strComputer”)
if ($socket.Connected)
{
$Netlogon = Get-WMIObject Win32_Service -ComputerName $strComputer | Where-Object{$_.Name -eq 'Netlogon'}
if ($Netlogon) {
$OS = Get-WmiObject -class Win32_OperatingSystem -computername $strComputer
$services = Get-WMIObject -class Win32_Service -ComputerName $strComputer
"$strComputer ; $pingreturns ; connected ; $($OS.CSName) ; $($Network.IPAddress) "
}else{
"$strComputer ; $pingreturns ; WMI Unavailable ; ; $IP"
}
}
if (!$socket.Connected)
{
echo "$strComputer ; $pingreturns ; Unable to connect ; ; $IP"
}
$socket.Close()
}
Instead of Clear-Item <variable name>, try Remove-Variable <variable name> or alternatively you could use the syntax $variable = $null. Either should work fine.

Resources