Powershell giving wrong output after scheduling with window's task scheduler - windows

I have a PowerShell script to check the password expiry date of the a system user and send a mail if it is going to expire within 10 days. Script works fine when we run it stand alone. But it show abnormal behaviour after scheduling it with windows task scheduler. Sometimes it works perfectly fine and sometimes it's not.
Output: Password will Expire in -736235 Days.
Expected output: Password will Expire in Days.
It always give -736235 days when if runs incorrectly.
Here is the configuration,
1.General tab
- Run whether user logged in or not
- Run with highest Privilege
- Configure for : Windows server 2012 R2
Action Tab
Program/script: PowerShell
-Add Argument: .\ps.ps1
Start in: D:
Setting Tab(Following Options are checked)
-Allow task to run on demand
Stop task if it running from: 3 days
-if the running task doesn't stop when requested, force stop
If the task is already running then following rule will apply: Stop the existing instance.
Please let me know if you need any other details,
Thanks,
Navdeep
Script is,
$user = Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False -and Name -eq "<user_name>" } –Properties "DisplayName", "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "Displayname",#{Name="ExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}
$DayCount = $user.ExpiryDate - (GET-DATE)
$DayAbsCount = $DayCount.Days
$message.body = "Password will Expire in $DayAbsCount Days.Please reset."
if ( $DayAbsCount -lt 10)
{
$smtp = new-object Net.Mail.SmtpClient($smtpserver)
$smtp.Send($message)
}
,
and the script is running from the same account whose pwd expiration date we needed.

Related

Preserve Active Directory trust relationships securely in AWS between VM's that start and stop

Developing Active Directory for a scalable and hackable student environment and I cannot manage to preserve the Domain Trust Relationship after the VM's restart. On first launch everything works, but after stopping/starting the AD Set, the trust relationship is broken.
Configuration Basics.
Three machines built and running in AWS (Windows Server 2012)
Domain Controller (Pre-Built Forest, Domains, Users, Computers, GPO's, etc)
Two "Targets" with varying permissions.
AMIs are built and domian joined before imaging.
Prior to imaging, Target Boxes are REMOVED from the domain, leaving a single DC and two un-joined Windows Server 2012 boxes.
Boxes are stopped without SysPrep to preserve SIDs and other variables like admin passwords, and an image is taken. User data is enabled
At this point, I can relaunch these boxes from AMI, re-join the domain, and I have no issues after restarting.
Here are the next steps.
The AMI's are run through a code pipeline that applies user data to the boxes to Domain Join and set the DNS to the IP of the DC.
Code exists to prevent the targets from crating until the DC is listening so they can join the domain.
On creation, things work flawlessly again.
After stopping and restarting, however, I start getting "NO_LOGON_SERVER" errors with tools, and cannot login with a domain user.
There are obvious solutions, but nearly all of them manual, and this must be automated. Furthermore, I must configure this in a way that no passwords are exposed on the box or retained as tickets or hashes in lsass that could ruin the exploint path.
If it helps, here is the User-Data that domain joins the targets.
<powershell>
# Checking for response from DC
do {
Start-Sleep 30
} until(Test-NetConnection -InformationLevel Quiet '{DC_IP_ADDR}')
# "true" if Domain Joined
$dCheck = (Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain
# Join domain if not already, skip if joined.
if ($dCheck -eq 'True') {
echo "I was domain joined after restarting." >> C:\Windows\Temp\log.txt
}
else {
# Allows 'rdesktop' by disabling NLA as a requirement
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name "fDenyTSConnections" -Value 0
# Set DNS to DC IP address via custom variable
$adapterIndex = Get-NetAdapter | % { Process { If ( $_.Status -eq "up" ) { $_.ifIndex } }}
Set-DNSClientServerAddress –interfaceIndex $adapterIndex –ServerAddresses ('{DC_IP_ADDR}','8.8.8.8')
#Set DA Credential object and join domain
$username = 'MYDOMAIN\ADMINISTRATOR'; $password = ConvertTo-SecureString -AsPlainText 'NotTheActualPasswordButReallySecure' -Force; $Credentials = New-Object System.Management.Automation.PSCredential $Username,$Password
Add-Computer -Domain 'MYDOMAIN.LOCAL' -Credential $Credentials -Force -Restart
}
</powershell>
<persist>true</persist>
And here is the Domain Controller. It is scheduled to change it's DA Password after 4 minutes so that the password exposed in the user data above is no longer valid
<powershell>
# Enable Network Discovery
netsh advfirewall firewall set rule group="Network Discovery" new enable=Yes
# Allows 'rdesktop' by disabling NLA as a requirement
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name "fDenyTSConnections" -Value 0
Start-Sleep -Seconds 240
# Recycle DA Password
powershell.exe -C "C:\Windows\Temp\recycle.ps1"
echo "Done" > "C:\Users\Administrator\Desktop\done.txt"
</powershell>

Powershell, check that the service is running and if it is not, start it

I have created a powershell script that detects if X service is active or not, if not, it starts it. I also wanted to add a parameter in the while to avoid that the script gets stuck and after several attempts (2) it closes the script.
The script works, it starts the service, but it tries to do the or even though the first statement was true. And not the reason why it does not work:
$ServiceName = 'MSIREGISTER_MR'
$arrService = Get-Service -Name $ServiceName
$conteo = 0
while (($arrService.Status -ne 'Running') -or ($conteo -ne '2'))
{
Start-Service $ServiceName
write-host $arrService.status
write-host 'Arrancando el servicio...'
$conteo = $conteo +1
Start-Sleep -seconds 5
$arrService.Refresh()
if ($arrService.Status -eq 'Running')
{
Write-Host 'El servicio esta arrancado'
}
else
{
Write-Host 'Fallo al arrancar el servicio'
}
}
Why this is happening
In your script today, you check for the status of the service only once, at the top of the script:
$arrService = Get-Service -Name $ServiceName
As you can see here, if I try the same using the Xbox Live Game Save Service which is currently stopped on my PC...
$service = get-service XblGameSave
Status Name DisplayName
------ ---- -----------
Stopped XblGameSave Xbox Live Game Save
C:\git\core> $service.Start()
C:\git\core> $service
Status Name DisplayName
------ ---- -----------
Stopped XblGameSave Xbox Live Game Save
I made a variable, I checked it, then I started the service.
When I check, the Xbox Live Game save service, is actually started, but my variable doesn't know about it.
However, when I refresh the variable, I can now see the new status.
PS> $service.Refresh()
Status Name DisplayName
------ ---- -----------
Running XblGameSave Xbox Live Game Save
Refreshing the variable with .Refresh() is a VERY weird thing that basically nothing else in PowerShell does other than services.
What you need to do
You need to update your code to check within the loop every time, to see if the service is now running or not.
Also, your condition on the loop seems incorrect.
while (($arrService.Status -ne 'Running') -or ($conteo -ne '2'))
This should run until the service is either running, or $conteo is greater than 2 (from your description). Here's how that should to do that in code.
while (($arrService.Status -ne 'Running') -or ($conteo -gt '2'))
There's a logic flaw in your conditional; change it to:
while ($arrService.Status -ne 'Running' -and $conteo -lt 2) { ...
That way, you exit the loop either once the service was started successfully or if $conteo reaches value 2, i.e. after the 2nd unsuccessful start attempt.

Setting counter on Windows Event log for Email notification

I am having below script:
$pattern = 'Unable to authenticate user!'
$events = Get-WinEvent -ea SilentlyContinue `
-ProviderName "Windows DB Controller - Task Manager Service"|
Where-Object { $_.TimeCreated -gt [datetime]::today -and $_.Message -match $pattern }
$events >> D:\Error.txt
if ($events) {
Send-MailMessage -SmtpServer smtp.domain.com -From No-reply#domain.com -To sunny#domain.com -Subject 'Error found in log' -Body $events
}
I had scheduled it to run on every 10 mins and purposely ,I wanted to achieve following point using above script:
Search the specified error message in the event viewer log only for current-date and as soon as the error message encountered send a email notification to me but didn't want to receive email notification for the error message which appreared today and for which I had already been notified (I mean , wanted to receive error-notification only once for a specific time of current day).
But problem I am facing here is: Getting multiple notifications for same error message for which already being notified.
I hope I am clear enough to put my exact problem.
Could you please help me out, how to resolve this problem ?
If you are running the script every 10 minutes, I would change the condition on the Where-Object so instead of getting all of the events that are "today"; I would change it to get only the events that happened in the last 10 minutes. i.e. the code becomes:
Where-Object { $_.TimeCreated -gt [datetime]::now.AddMinutes(-10) -and $_.Message -match $pattern }
Have a look at this thread:
Powershell - Tail Windows Event Log? Is it possible?
It's on tailing an event log, but the same method should work for what you're tyring to do. Just save the last index number to a file between runs.
How about the following approach:
Register-WmiEvent -Query "select * from __InstanceCreationEvent where TargetInstance ISA 'Win32_NTLogEvent' and TargetInstance.SourceName = 'Windows DB Controller - Task Manager Service' and TargetInstance.Message LIKE '%Unable to authenticate user!%'" -SourceIdentifier "MyEventListener" -Action {
#Your actions
write-host "$($eventargs.NewEvent.TargetInstance.RecordNumber) at $($eventargs.NewEvent.TargetInstance.TimeGenerated)"
}
It uses WMI to subscribe to the event that occurs when an eventlog entry is generated with your criterias. The action itself will only return the new object(so no more duplicates). I've included a sample action to help you understand how to access the object. This method will give you live monitoring.
Inside the action, $eventargs.NewEvent.TargetInstance will give you the object which is an instance of win32_ntlogevent. To see properties of this class, check out TechNet or run the following command:
([wmiclass]'win32_ntlogevent').Properties | ft Name
To make the script run forever, just call your script with powershell -file script.ps1 -noexit or include a while($true) loop at the end of your script. (I'm not sure how the while-loop will affect resource usage longterm, you'd have to test).

Getting Stop-NlbClusterNode : A parameter cannot be found that matches parameter name 'Credential'. error while stopping node

I am using the following script to stop the node on a machine. But getting Getting Stop-NlbClusterNode : A parameter cannot be found that matches parameter name 'Credential'. error while stopping node using power-shell script and windows 2012. Also how can I pass a password in this script. Please guide.
#This script monitors stopped application pools along with websites on the current host
$RemoteHostName = "testserver"
#set hostname
#import NLB module. In PS v3 these lines should be redundant and can be removed.
import-module NetworkLoadBalancingClusters
"Networking Load Balancing Clusters Module imported"
# requests the user's credentials and assigns the credentials to an object
$Credential = Get-Credential "domain\testuser"
"Get credentials for test user done"
#uses the nlb cmdlets to check the state of the current cluster
$clusterstatus = get-nlbclusternode -nodename $RemoteHostName
[string]$status = $clusterstatus | select -expand state
"Got the status of cluster $clusterstatus"
#if the node has already been stopped dont do anything
if ($status -eq "Stopped")
{
#donothing
"Node alrerady stopped"
}
#if the node hasnt been stopped, stop the node and then send an email out
else
{
"Starting to drain stop the node"
stop-NlbClusterNode -HostName $RemoteHostName -Credential $Credential -Drain
}
start-sleep -s 30

Best Way to Trigger an Event When a Specific Error is Thrown in Windows 2003 Server?

I have a Windows 2003 Server that uses IIS to host a legacy ASP.NET web service that connects to a database on a remote Oracle database server that I have no control over. The problem is that the database server goes down every week or two, but then comes back up after about 5 minutes. I have to then restart IIS to remove any corrupt connections before my web service works again.
What is the best way to trigger an event (i.e. email myself and/or reset IIS) when a specific error code occurs (in this case it will be an ORA- type error, but I can get the Windows error code)?
IIS Setting?
Task Scheduler? (limited to scheduled tasks only I believe on Windows 2003 server, eg. per day/week/month etc)
Powershell Script?
Other options?
I know in Windows 2008 Server that you can configure the Task Scheduler to trigger an event when the server experiences certain error codes in its Error Log... but I can't find anything like this in the Task Scheduler of Windows 2003 Server.
Thanks.
I wrote a powershell shell script to monitor the sql server errorlog and report on specific errors. I stored where I last stop reading and then continued on from that point the next time I ran the script. This is the part that actually reads the log. Then you just need to store the position in some temp file and run this as a scheduled task. And send an email if the error occurs or even restart some service.
$path = $logs.file
Write-Host $path
if($currentLog.lastpos -ne $null){$pos = $currentLog.lastpos}
else{$pos = 0}
if($logs.enc -eq $null){$br = New-Object System.IO.BinaryReader([System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite))}
else{
$encoding = $logs.enc.toUpper().Replace('-','')
if($encoding -eq 'UTF16'){$encoding = 'Unicode'}
$br = New-Object System.IO.BinaryReader([System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite), [System.Text.Encoding]::$encoding)
}
$required = $br.BaseStream.Length - $pos
if($required -lt 0){
$pos = 0
$required = $br.BaseStream.Length
}
if($required -eq 0){$br.close(); return $null}
$br.BaseStream.Seek($pos, [System.IO.SeekOrigin]::Begin)|Out-Null
$bytes = $br.ReadBytes($required)
$result = [System.Text.Encoding]::Unicode.GetString($bytes)
$split = $result.Split("`n")
foreach($s in $split)
{
if($s.contains(" Error:"))
{
#Filter events here
}
}
$currentLog.lastpos = $br.BaseStream.Position
$br.close()

Resources