Duplicated results in Powershell - powershell

I have put together a script from various sources, but cannot understand why i am getting duplicated entries in my results..
eg..
I need to check the scheduled tasks on remote servers, and verify which ones didnt complete sucesfully, and then investigate those.
I have a schedulers.csv file, which has two comlumns IP, and Name.
I downloaded the script Get-ScheduledTask.ps1 from https://gallery.technet.microsoft.com/scriptcenter/Get-Scheduled-tasks-from-3a377294
Works great and does what i needed.
I then wanted to from a list retrieve the servers names, run the above script as a parameter, then get back the scheduled tasks in a csv file.
NextRunTime Author Trigger State UserId ComputerName Name LastRunTime LastTaskResult Description NumberOfMissedRuns Enabled Path
The headers for the above script give me Name and LastTaskResult, which is what I wanted to query further.
The LastTaskResult should be 0 if it completed sucesfully, otherwise i would investigate further.
The code i have so far is :
$servers = Import-Csv "C:\test\schedulers.csv"
foreach($server in $servers){
$ServerName = $server.Name
$ServerAddress = $server.IP
Write-Host $ServerName : $ServerAddress
$importfile = Get-ScheduledTask.ps1 -ComputerName $ServerName
|Export-Csv -Path c:\test\scheds.csv -NoTypeInformation
$Lines = Import-Csv "C:\test\scheds.csv"
ForEach($line in $lines){
$lines | %{
$TaskName = $_.name
$taskresult = $_.LastTaskResult
if ($_.LastTaskResult -ne "0")
{
Write-Host $line.LastTaskResult : $_.name : $_.Path
}else{
}
}
}
}
There should be 3 results that show, that have a value of 1 in LastTaskResult, but i get about 38 which is the total amount of tasks on the two servers that i am testing on.
the 3 entries are there also as well, plus all the rest..
please can anyone see where i have gone wrong.. Many Thanks

not tested because i don't have your Get-ScheduledTask.ps1, but here's what i might change
$servers = Import-Csv "C:\test\schedulers.csv"
foreach ($server in $servers) {
$ServerName = $server.Name
$ServerAddress = $server.IP
Write-Host $ServerName : $ServerAddress
$importfile = Get-ScheduledTask.ps1 -ComputerName $ServerName
$importfile | Export-Csv -Path c:\test\scheds.csv -NoTypeInformation
foreach ($line in $importfile) {
if ($line.LastTaskResult -ne '0') {
Write-Host $line.LastTaskResult : $line.Name : $line.Path
}
}
}

Related

Check if certain VMs are backed up

I am looking for a way to check if a list of VMs has backup and what is the status.
I managed to get the status of VM backups but if the VM was not found in the $tasks I am not getting error.
I need to know if a VM is not present in the $tasks so that I know that no backup is configred for this VM.
The script so far.
Write-Host "Enter Backup Server" -ForegroundColor cyan
$h = read-host -Prompt 'Hostname'
Write-Host " "
write-host "Hostname--------Job-------------Status " -ForegroundColor Cyan
Foreach ($i in $Hostname) {
Invoke-Command -ComputerName $h -ScriptBlock {
Add-PSSnapin VeeamPSSnapin
foreach($Job in (Get-VBRJob))
{
$Session = $Job.FindLastSession()
if(!$Session){continue;}
$Tasks = $Session.GetTaskSessions()
$Tasks | ?{$_.Name -eq $using:i} | %{write-host $_.Name ":",$_.JobName,"===>"$_.Status}
}}
}
Thanks in advance!
Valeri
You are nearly there, you just need to unify your exit clause so that whether a VM has backup or not, it outputs something similar. Then when you run against a list of VMs and one or two aren't backed up, they'll appear in the output in a way that makes sense.
Foreach ($i in $Hostname) {
Invoke-Command -ComputerName $h -ScriptBlock {
Add-PSSnapin VeeamPSSnapin
foreach($Job in (Get-VBRJob))
{
$Session = $Job.FindLastSession()
if(!$Session){
[pscustomObject]#{
computerName = $_.Name;
backupStatus = "Not backed up!";
jobs = $null;
}
$Tasks = $Session.GetTaskSessions()
$jobs = $Tasks | ?{ $_.Name -eq $using:i } | Select -ExpandProperty JobName
[PSCustomObject]#{
computerName = $_.Name;
backupStatus = "Backed up";
jobs = ($jobs -join ",")
}
}
}
}
With a few small tweaks, we now emit an object back if a machine doesn't have any results for $Session, but now also return a similar object for machines that do have backups enabled.
You will likely need to tweak the code to your desired results, as I don't have Veeam available I can't quite nail down what you'd like but this should get you going.
And as a perk getting PowrShell objects back is easier to work with. You can save them in a json file or csv, or run this automatically in the off hours and review the results later, all which are much easier than using Write-Host commands.
I managed to acheave my goal by comairing all backed up VMs with the VMs from my list:
Write-host "Unprotected VMs (No backup)" -ForegroundColor RED
Write-host "---------------------------" -ForegroundColor RED
invoke-command -computername $h -ScriptBlock {
Add-PSSnapin VeeamPSSnapin
$backup=Get-VBRBackupSession | Where-Object {$_.JobType -eq "Backup" -or $_.JobType -eq "Replica" -and $_.EndTime}|foreach{$_.gettasksessions() | Where-Object {$_.Status -ne "Failed"}} |foreach{$_.Name} | Sort-Object | Get-Unique
$diff=Compare-Object $using:hostname $backup| ? { $_.SideIndicator -eq "<=" } | Select -ExpandProperty InputObject
$diff
As a result I am getting only the VMs which are missing from $backup and are present only in my list $hostnames .

Powershell output logging when using a text file to gather server names

Have a bit of an issue whereby would like to figure out the best way to handle success or failures. Have a powershell query which checks the dcom port range, if it is within the specified value output to a success file, if not a failure file. The issue is, it seems to be outputting the entire serverlist.txt for a success and need to know a way to break this down so it only appends a server (either success/failure) to it, not all at once.
Here is the powershell script contents:
powershell -executionpolicy bypass .\DCOMPortRange.ps1
Where DCOMPortRange.ps1 contains
$computername = Get-Content -Path "C:\Folderpath\serverlist.txt"
$val = (Get-ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -ExpandProperty Ports
if($val -eq "50000-50500")
{
Write-Output "$computername" | out-file C:\folderpath\Success.log -append
} Else {
Write-Output "$computername" | out-file C:\folderpath\Failure.log -append
}
The issue is the error path lets say is a success it appends the entire server list.
Please advise?
This is how I would do it. This does require that you do have PSremoting enabled on the servers
$computername = Get-Content -Path "C:\Folderpath\serverlist.txt"
ForEach ($server in $computername) {
$val = Invoke-Command -Computername $server -ScriptBlock {(Get-ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -ExpandProperty Ports}
if ($val -ge 50000 -and $val -le 50500) {
Write-Output "$server" | out-file C:\folderpath\Success.log -append
}
Else {
Write-Output "$server" | out-file C:\folderpath\Failure.log -append
}
}
Edit: A change to the if statement
/Anders
$remotecomputername = #("PC1","PC2","RealServerName")
ForEach ($computer in $remotecomputername) {
Invoke-Command -Computername $computer -ScriptBlock { $val = (Get-
ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -
ExpandProperty Ports} }
if($val -eq "50000-50500") {
write-host $computer DCOM Port in Range
} else {
write-host $computer DCOM Port not in range
}

powershell search multiple domains for computer

I need some help. I wrote a PowerShell script that grabs a text file as an input with a list of computer names. It then checks the Active Directory for the machine name. If the machine is found it writes it to one text file, and if the machine is not found, it writes it to a separate file. The idea being I get two lists... A "good" and a "bad" list. the problem is that it only queries the domain I am in and I need it to query all the domains in a forest and am stuck. can someone lend a hand? Here is my code as it stands:
Import-Module ActiveDirectory
$AdminCredentials = Get-Credential "Domain\AdminAccount"
$objForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$domains = #($objForest.Domains | Select-Object Name)
$computers = gc -Path "C:\MachinesInDifferentAds.txt"
$computer_count = $Computers.Length;
$i = 0;
foreach ($computer in $computers) {
Try
{
(Get-ADComputer $computer -Credential $AdminCredentials | FT Name)
$computer | out-file -append -filepath "C:\ComputersInAd.txt"
}
Catch
{
$computer | out-file -append -filepath "C:\ComputersNotInAd.txt"
}
$computer_progress = [int][Math]::Ceiling((($i / $computer_count) * 100))
Write-Progress "Querying the AD" -PercentComplete $computer_progress -Status "Percent Complete - $computer_progress%" -Id 1;
Sleep(1);
$i++;
}

hashtable filter / select

I was working tonight to re-write an existing server health check script to store its values in a hashtable, and that part is working fine. However, I want the results to go to a CSV file, and that file only to be populated with servers where I've tagged them as requiring action. Currently those are generating event ID 7011, or failing a ping test by Test-Connection.
Here's the code:
$CheckServer = #{}
$Servers = (Get-Content $Dir\Test.txt)
foreach ($Server in $Servers) {
$CheckServer.EventID7011 = Get-Eventlog -LogName System -ComputerName $Server -Newest 1 |
Where-Object {$_.EventId -eq 7011} | select Message
if ($CheckServer.EventID -ne $Null) {
$CheckServer.Server = "$Server"
$CheckServer.ActionReq = "Yes"
}
$CheckServer.Ping = Test-Connection -ComputerName $Server -Count 1 -Quiet
if (! $CheckServer.Ping) {
$CheckServer.Server = "$Server"
$CheckServer.ActionReq ="Yes"
$CheckServer.Ping = "Offline"
} else {
$CheckServer.Server = "$Server"
$CheckServer.ActionReq = "No"
$CheckServer.Ping = "Online"
}
New-Object -TypeName PSObject -Property $CheckServer |
Export-Csv "ScanResults.csv" -NoTypeInformation -Append
}
I need the correct code at the end, as it stands, the script works fine for collecting/storing the data in the hashtable array $CheckServer, but I'd like to only select those servers that require action. So, if I'm scanning 100 servers, and 2 of them are in a ping fail state, I want only those selected and sent to Export-Csv.
If you want only servers that don't respond to Test-Connection in the output anyway it would be much simpler to just use a Where-Object filter on the server list:
Get-Content "$Dir\Test.txt" |
Where-Object { -not (Test-Connection -Computer $_ -Count 1 -Quiet) } |
Select-Object #{n='Server';e={$_}}, #{n='ActionReq';e={'Yes'}},
#{n='Ping';e={'Offline'}} |
Export-Csv 'ScanResults.csv' -NoType -Append
You need to store the objects into a list before you can filter and export them. See the lines with comments in your code:
$CheckServer = #{}
$serverObjects = #() # create a list of server objects
$Servers = (get-content $Dir\Test.txt)
ForEach ($Server in $Servers) {
$CheckServer.EventID7011 = get-eventlog -LogName System -ComputerName
$Server -newest 1 | where-object {$_.eventID -eq 7011} |select message
If ($CheckServer.EventID -ne $Null) {
$CheckServer.Server="$Server"
$CheckServer.ActionReq = "Yes"}
$CheckServer.Ping = Test-Connection -ComputerName $Server -count 1 -quiet
if (! $CheckServer.Ping) {
$CheckServer.Server="$Server"
$CheckServer.ActionReq ="Yes"
$CheckServer.Ping= "Offline"}
Else {
$CheckServer.Server="$Server"
$CheckServer.ActionReq ="No"
$CheckServer.Ping= "Online"}
# Add the server object to the list
$serverObjects += New-Object -TypeName PSObject -Property $CheckServer
}
}
# now filter it:
$serverObjects | where ActionReq -eq "Yes" | Export-Csv -Path "...."

PowerShell hash table and output to text files

I have written a script with the help of #Ansgar. Below is the code for the script. The script checks for Ping, RDP, Remote Registry and WMI checks for a remote computer. The server names are entered in a text file servernames.txt Once the script is exeecuted, the servers that are UP are recorded in a text file named Online.txt and the servers which are DOWN are recorded in Offline.txt The format for recording is below:
ONLINE.TXT
<servername>
PING : SUCCESS
RDP : SUCCESS
Remote Registry : SUCCESS
WMI : SUCCESS
OFFLINE.TXT
<servername>
PING : SUCCESS
RDP : FAIL
Remote Registry : SUCCESS
WMI : SUCCESS
This is the script that I have till now:
#Text file to pick the server names. Path is hard coded to c:\temp\serverlist.txt
$servers = Get-Content "C:\temp\serverlist.txt"
ForEach ($server in $servers)
{
Write-Host `n
Write-Host $server
Write-Host `n
#PING
$ping = Test-Connection -ComputerName $server -Quiet -Count 1
#RDP
$rdp = Test-NetConnection -ComputerName $server -CommonTCPPort RDP -InformationLevel Quiet
#REMOTE REGISTRY
$regkey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey ([Microsoft.Win32.RegistryHive]::LocalMachine,$server)
$ref = $regkey.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall")
#WMI
$wmi = Get-WmiObject -Query "Select * from Win32_PingStatus where Address = '$server'"
$state_noun = #{
$true = 'SUCCESS'
$false = 'FAIL'
}
$state_verb = #{
$true = 'SUCCEEDED'
$false = 'FAILED'
}
$result = #"
PING : $($state_noun[$ping])
RDP : $($state_noun[$rdp])
Remote Registry : $($state_noun[[bool]$ref])
WMI : $($state_noun[[bool]$wmi])
"#
}
How can I output the servers and their results to the text files (online.txt and offline.txt)? Thank you in advance.
Use -and to calculate the overall result of your 4 checks:
$ping -and $rdp -and [bool]$ref -and [bool]$wmi
The -and operator returns true only if both operands are true, so the above statement only becomes true when all 4 checks succeeded.
Write to one or the other output file depending on the outcome of the boolean operation:
if ($ping -and $rdp -and [bool]$ref -and [bool]$wmi) {
$result | Out-File 'C:\path\to\online.txt' -Append
} else {
$result | Out-File 'C:\path\to\offline.txt' -Append
}
Or you could use the -Contains operator as previously suggested and just do something like:
If(#($state_noun[$ping],$state_noun[$rdp],$state_noun[[bool]$ref],$state_noun[[bool]$wmi]) -contains "FAIL"){
$result | Out-File 'C:\path\to\online.txt' -Append
}else{
$result | Out-File 'C:\path\to\offline.txt' -Append
}
Though I would personally use Ansgar Wiechers's solution. I just posted this as a proof of concept (I think that's the right term).