Reboot check is showing all reboots not just last - powershell

I have a reboot check script that is run post MW, I need it to pull just the last reboot to verify the servers have been rebooted, currently they pull all reboot history. Below is my script:
$DHCP = (Get-Content -Path "\\termserv\d$\SERVER1\SERVER2\Scripts\morescripts\DHCPServers.txt")
foreach ($Server in $DHCP) {
Get-Service -ComputerName $Server -DisplayName "DHCP Server" |
ConvertTo-Html -Title "PScomputername" -Body "<H3> SERVER2 Uptime Report </H3> " -Property PSComputername >> \\termserv\d$\SERVER1\SERVER2\Server3\SERVER2.html
Get-Service -ComputerName $Server -DisplayName "DHCP Server" |
ConvertTo-Html -Property MachineName,Status,ServiceName |
foreach {
if ($_ -like "*<td>Running</td>*") {
$_ -replace "<tr>", "<tr bgcolor=green>"
} elseif ($_ -like "*<td>Stopped</td>*") {
$_ -replace "<tr>", "<tr bgcolor=red>"
} else {
$_
}
} >> \\termserv\d$\SERVER1\SERVER2\Server3\SERVER2.html
Get-WmiObject win32_operatingsystem -ComputerName $Server |
Select PSComputername, #{n='BootTime';e={$_.ConvertToDateTime($_.LastBootupTime)}} |
ConvertTo-Html -Property PSComputerName,BootTime >> \\termserv\d$\SERVER1\SERVER2\Server3\SERVER2.html
ConvertTo-Html -Property PSComputerName,Installedon,Description,caption >> \\termserv\d$\SERVER1\SERVER2\Server3\SERVER2.html
}
$Print = (Get-Content -Path "\\termserv\d$\SERVER1\SERVER2\Scripts\morescripts\PrintServers.txt")
foreach ($Server in $Print) {
Get-Service -ComputerName $Server -DisplayName "Print Spooler" |
ConvertTo-Html -Property MachineName,Status,ServiceName |
foreach {
if ($_ -like "*<td>Running</td>*") {
$_ -replace "<tr>", "<tr bgcolor=green>"
} elseif ($_ -like "*<td>Stopped</td>*") {
$_ -replace "<tr>", "<tr bgcolor=red>"
} else {
$_
}
} >> \\termserv\d$\SERVER1\SERVER2\Server3\SERVER2.html
Get-WmiObject win32_operatingsystem -ComputerName $Server |
Select PSComputername, #{n='BootTime';e={$_.ConvertToDateTime($_.LastBootupTime)}} |
ConvertTo-Html -Property PSComputerName,BootTime >> \\termserv\d$\SERVER1\SERVER2\Server3\SERVER2.html
ConvertTo-Html -Property PSComputerName,Installedon,Description,caption >> \\termserv\d$\SERVER1\SERVER2\Server3\SERVER2.html
}

You just need to Sort-Object with a calculated property and then tell Select-Object to pick the first item:
Get-WmiObject -ClassName Win32_OperatingSystem -ComputerName $Server |
Sort-Object -Property #{e={$_.ConvertToDateTime($_.LastBootupTime)}} -Descending |
Select-Object -First 1 -Property [...] |
ConvertTo-Html [...]
It should be noted that the final ConvertTo-Html call in each main foreach loop doesn't have anything to convert as far as I can tell. They're going to create an empty HTML document with an empty table and append that to your file.
Also, you're appending multiple HTML documents to the server2.html file. If they're going to be in the same document, you should start the entire file with <html><head><title /></head><body>, then use the -Fragment parameter on all of your ConvertTo-Html calls, and finally close the document with </body></html>. Your current method may work, but you're generating an explicitly invalid HTML document. A browser that renders correctly should only display the first table.

Related

Selection of only one user from list

I have this script that I need to use to retrieve the data of a particular user "ADTuser" from a list of servers the script works well, but the output file with my user add also other users' detail that is not needed for my final output how can I filter it to only the user that I need.
get-content C:\servers.txt | foreach-object {
$Comp = $_
if (test-connection -computername $Comp -count 1 -quiet) {
([ADSI]"WinNT://$comp").Children | ?{$_.SchemaClassName -eq 'user' } | %{
$groups = $_.Groups() | %{$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
$_ | Select #{n='Computername';e={$comp}},
#{n='UserName';e={$_.Name}},
#{n='Memberof';e={$groups -join ';'}},
#{n='status'; e={if($groups -like "*Administrators*"){$true} else{$false}}}
}
} Else {Write-Warning "Server '$Comp' is Unreachable hence Could not fetch data"}
} | Out-File -FilePath C:\users.txt
This should be an easier way of doing what you're looking for, Get-CimInstance and Get-CimAssociatedInstance have been around since PowerShell 3:
Get-Content C:\servers.txt | ForEach-Object {
$computer = $_
try {
$query = Get-CimInstance Win32_UserAccount -Filter "Name='ADTuser'" -ComputerName $_ -ErrorAction Stop
foreach($object in $query) {
$membership = Get-CimAssociatedInstance -InputObject $object -ResultClassName Win32_Group -ComputerName $_
[pscustomobject]#{
Computername = $_
UserName = $object.Name
Memberof = $membership.Name -join ';'
Status = $membership.Name -contains 'Administrators'
}
}
}
catch {
Write-Warning "Server '$computer' is Unreachable hence Could not fetch data"
}
} | Export-Csv C:\users.csv -NoTypeInformation
If that doesn't work for you, your code would require a simple modification on your first filtering statement:
Where-Object { $_.SchemaClassName -eq 'user' -and $_.Name.Value -eq 'ADTuser' }
It's important to note that Test-Connection -ComputerName $_ -Count 1 -Quiet is not a relevant test for this script, this command is testing for ICMP response and adsi over WinNT requires RPC connectivity as well SMB.
Putting it all together with minor improvements the script would look like this:
Get-Content C:\servers.txt | ForEach-Object {
if (-not (Test-Connection -ComputerName $_ -Count 1 -Quiet)) {
Write-Warning "Server '$_' is Unreachable hence Could not fetch data"
return
}
$computer = $_
([adsi]"WinNT://$_").Children.ForEach{
if($_.SchemaClassName -ne 'user' -and $_.Name.Value -ne 'ADTuser') {
return
}
$groups = $_.Groups().ForEach([adsi]).Name
[pscustomobject]#{
Computername = $computer
UserName = $_.Name.Value
Memberof = $groups -join ';'
Status = $groups -contains 'Administrators'
}
}
} | Export-Csv C:\users.csv -NoTypeInformation

How to edit my script to combine its outputs in one table per server from serverlist?

Could you please inform me how can I make my script to format its output in a single table for all "services" per "server"?
Please find my current PowerShell script below:
$serverList = gc computer.txt
$serviceList = gc service.txt
if ((Test-Path OUTPUT.txt) -eq $true) {
Write-Host "Deleting existing OUTPUT file"
Remove-Item OUTPUT.txt
}
ForEach ($server in $serverList)
{
$style = #{Expression={$server};Label="Server Name";width=30}, `
#{Expression={$_.Name};Label="Service Name";width=20}, `
#{Expression={$_.StartMode};Label="StartMode";width=10}, `
#{Expression={$_.State};Label="State";width=10}, `
#{Expression={$_.ProcessId};Label="ProcessId";width=10}
Write-Host "Starting Service Check on $server"
ForEach ($service in $serviceList)
{
Get-WmiObject -Class Win32_Service -ComputerName $server -Filter "Name='$service'" | Select-Object -Property Name, StartMode, State, ProcessId | Format-Table $style | Out-File OUTPUT.txt -Append
}
Write-Host "Service Check Completed on $server"
}
WMI appends the property PSComputername. You can just append it in your select-object-command like so:
Get-WmiObject -Class Win32_Service -ComputerName $server -Filter "Name='$service'" | Select-Object -Property PScomputername, Name, StartMode, State, ProcessId | Format-Table $style | Out-File OUTPUT.txt -Append

Powershell: Pipe variable $_ in if statement?

I have the following short script to grab serial numbers of computers and monitors in an OU, which works fine:
Import-Module ActiveDirectory
$searchbase = "OU=some,OU=organisational,OU=units,DC=somedomain,DC=local"
Write-Host ""
Write-Host "Serial Numbers for Computers and Monitors in" $searchbase
Write-Host "--"
Get-ADComputer -SearchBase $searchbase -Filter '*' | `
Select-Object -Expand Name | %{Write-Host ""; echo $_ ; Get-WMIObject -Class Win32_BIOS -ComputerName $_ | Select-Object -Expand SerialNumber; `
$monitor = gwmi WmiMonitorID -Namespace root\wmi -computername $_; ($monitor.SerialNumberID | foreach {[char]$_}) -join ""};
This script doesn't check to see if the computer is online before attempting to fetch the WMIObject, so if a computer is offline it takes ages before the RPC call times out.
I tried to modify the script to use the Test-Connection cmdlet before trying to get the WMIObject:
Import-Module ActiveDirectory
$searchbase = "OU=some,OU=organisational,OU=units,DC=somedomain,DC=local"
Write-Host ""
Write-Host "Serial Numbers for Computers and Monitors in" $searchbase
Write-Host "--"
Get-ADComputer -SearchBase $searchbase -Filter '*' | `
Select-Object -Expand Name | `
if (Test-Connection -ComputerName $_ -Quiet) {
%{Write-Host ""; echo $_ ; Get-WMIObject -Class Win32_BIOS -ComputerName $_ | Select-Object -Expand SerialNumber; `
$monitor = gwmi WmiMonitorID -Namespace root\wmi -computername $_; ($monitor.SerialNumberID | foreach {[char]$_}) -join ""};}
}
else {
Write-Host ""; Write-Host $_ "is offline";
}
I'm sure I'm doing something syntactically stupid. Can someone point me in the right direction?
You can't pipe directly to an if statement, only to cmdlets.
Put the if statement inside the ForEach-Object block (% is an alias for ForEach-Object):
... | Select-Object -Expand Name | `
%{
if (Test-Connection -ComputerName $_ -Quiet) {
# Get-WmiObject in here
}
else {
Write-Host ""; Write-Host $_ "is offline";
}
}
If you don't care about writing each machine's status to the host, you could also filter out offline computers with Where-Object(alias ?):
... | Select-Object -Expand Name | ?{
Test-Connection $_ -Quiet
} | % {
Get-WmiObject -ComputerName $_
}
In addition to the answer from #Mathias R. Jessen, you can get rid of the backticks for line continuation.
They are not needed if the end of the line infers there is another block of code required for the statement. Like | or { or (.
"foo", "bar" |
% {$_}
works just fine...

Powershell looping through message queues

I'm trying to return tables with message queues from three different environments. I could copy and paste the existing code for all three, but I want to make it cleaner and more reusable.
Is there a way to loop through each message queue and return them in separate tables (i.e.: Dev, Dev2, Dev3 queues)?
[object]$dev3Queues = gwmi -class Win32_PerfFormattedData_msmq_MSMQQueue -computerName myServer | Where{$_.Name -like "*dev3*" } | select Name,MessagesInQueue #| Out-File "C:\test.txt"
[object]$dev2Queues = gwmi -class Win32_PerfFormattedData_msmq_MSMQQueue -computerName myServer | Where{$_.Name -like "*dev2*" } | select Name,MessagesInQueue #| Out-File "C:\test2.txt"
[object]$devQueues = gwmi -class Win32_PerfFormattedData_msmq_MSMQQueue -computerName myServer |
Where{$_.Name -notlike "*dev2*" -AND $_.Name -notlike "*dev3*" -AND $_.Name -notlike "*private*" -AND $_.Name -notlike "*Computer Queues*" -AND $_.Name -notlike "*uat*"} | select Name,MessagesInQueue #| Out-File "C:\test3.txt"
$Html = "<html><head>Whoo Queues</head><body><table border=1>"
foreach($element in $devQueues)
{
$Html += "<tr><td>" + $element.Name + "</td><td>"+ $element.MessagesInQueue + "</td> </tr>"
}
$Html += "</table></body></html>"
$Html | out-file C:\temp\DEVQueues.html
#environmentloop - dev,dev2,dev3
#{
#queue loop + html
#}
You can use the ConvertTo-Html cmdlet with the option -Fragment to convert a list of objects to an HTML table of the object properties.
Get-WmiObject -Class Win32_PerfFormattedData_msmq_MSMQQueue |
select Name, MessagesInQueue |
ConvertTo-Html -Fragment
Also, when running Get-WmiObject against a remote server using a WMI filter provides better performance than retrieving all results and filtering them on the local host with Where-Object.
$computer = 'myServer'
$filter = 'Name LIKE "%dev3%"'
Get-WmiObject -Class Win32_PerfFormattedData_msmq_MSMQQueue -Computer $computer `
-Filter $filter
However, since you want to filter the same dataset for various criteria, in your case the best approach might be to first fetch all relevant data from the remote host with a more general WMI filter (to avoid multiple remote connections), and then process them locally with several Where-Object filters:
$server = 'myServer'
$wmiFilter = 'NOT (Name LIKE "%private%" OR Name LIKE "%Computer Queues%" ' +
'OR Name LIKE "%uat%")'
$psFilters = { $_.Name -like "*dev3*" },
{ $_.Name -like "*dev2*" },
{ $_.Name -notlike "*dev2*" -and $_.Name -notlike "*dev3*" }
$data = Get-WmiObject -Class Win32_PerfFormattedData_msmq_MSMQQueue `
-Computer $server -Filter $wmiFilter
'<html><head>Whoo Queues</head><body>'
foreach ($filter in $psFilters) {
$data | ? $filter | select Name, MessagesInQueue | ConvertTo-Html -Fragment
}
'</body></html>'

Table not showing output in new line

I'm sure there is a simple solution, but I'm stuck. The output in the members column is like this
{domain\Domain Admins, domain\joerod...
How can I show the
$member
value on each line?
Function Get-AdminGroups{
foreach($i in (Get-Content C:\Users\joerod\Desktop\remove_users.txt)){
#test if machine is on the network
if (-not (Test-Connection -computername $i -count 1 -Quiet -ErrorAction SilentlyContinue)) {
Write-Warning "$i is Unavalible"
"`r"
}
else {
(invoke-command {
$members = net localgroup administrators |
? {$_ -AND $_ -notmatch "command completed successfully"} |
select -skip 4
New-Object PSObject -Property #{
Computername = $env:COMPUTERNAME
Users=$members
}
} -computer $i -HideComputerName |
Select * -ExcludeProperty RunspaceID )
}
}
}
Get-AdminGroups |ft
Iterate through $members and make an object for each one. This creates an empty array, loops through the computers in your text file, and in that loop it pulls a list of the local administrators, and for each one it creates a custom object just like you are doing, and it adds it to that array.
$Results = #()
foreach($i in (GC C:\Users\joerod\Desktop\remove_users.txt)){
#test if machine is on the network
if (!(Test-Connection -computername $i -count 1 -Quiet -ErrorAction SilentlyContinue)) {
Write-Warning "$i is Unavalible`r"
Continue
}
invoke-command {
$members = net localgroup administrators |?{$_ -AND $_ -notmatch "command completed successfully"} | select -skip 4
ForEach($member in $members){
$Results += New-Object PSObject -Property #{
Computername = $env:COMPUTERNAME
Users=$member
}
}
} -computer $i -HideComputerName # | Select * -ExcludeProperty RunspaceID
}
$Results | FT