Problem with powershell script for AD server Status - powershell

I have a script that can have a list of AD servers (with Get-ADComputer) and the results goes to a TXT file. I don't know how to only have Online Servers only. I only need their names.
I tried to do some IF {} Else{} with the cmdlet Test-Connection -CN $Server but it doesn't work (I'm probably doing it wrong). Here is my code :
$TXTFile = "C:\Scripts\Serv.txt"
$TXTOutput = #()
Write-Host "INFO: Finding servers from AD"
$Servers = Get-ADComputer -Filter {OperatingSystem -like "*server*" -and Enabled -eq $true} | SORT Name
Write-Host "INFO:"$Servers.Count"Records found"
ForEach ($Server in $Servers) {
$ServerHash = $NULL
$ServerHash = [ordered]#{
"Servers Name" = $Server.Name
}
$TXTOutput += New-Object PSObject -Property $ServerHash
}
$TXTOutput
I want, if possible, to have all of my AD Online Servers name in a TXT file. For now I only have all of my servers (Online and Offline). It's my first post so sorry if I made it wrong !

You can use -Quiet parameter with Test-Connection cmdlet in order to get just True or False and then make a decision based on that result.
$TXTFile = "C:\Temp\Serv.txt"
$TXTOutput = #()
$servers=Get-ADComputer -Filter {OperatingSystem -like "*server*" -and Enabled -eq $true} | select -expandproperty Name
ForEach ($Server in $Servers) {
if ((Test-Connection $Server -Count 2 -Quiet) -eq $true) {
$TXTOutput += $Server
}
}
$TXTOutput | Out-File $TXTFile
You can pipe $TXTOutput to sort if you want. Keep in mind that this might take a while since you are basically pinging each server twice -Count 2.

Related

Powershell Conditional filter without regex

Im trying to filter ADComputer by Name.
Our naming convention is a follows <CuntryCode>-<Location>-<DeviceType And Number> we have diferent locations in both USA and MX, we also have serval type of devices
Example:
<Device Type>
Servers = S
Desktops = D
Laptops = L
Tablet = T
Routers = R
Switches = U
example of actual naming:
MX-BCN-D002 or US-TAM-L001
Im creating a Script that will look at a remote PC file system, and check if user has a local .PST file. I only want devices that are Type: Desktops and Laptops, but cant seem to create a condition to filter all other devce type
Partial Script:
$Enabled_PC_list =#()
$Enabled_Online_PC_List =#()
# $Enabled_Offline_PC_list =#()
$data = #()
$PCs = Get-ADComputer -filter "Enabled -eq '$true'" -SearchBase "DC=some,DC=domain" -properties name | Select-Object -ExpandProperty name
$Enabled_PC_list += $PCs
foreach($device in $Enabled_PC_list){
Write-Output ">>> testing Device: $device <<<"
if ($device -like "*-*-D*" -or $device -like "*-*-L*" ) {
if(Test-Connection -TargetName $device -Count 1 -Quiet){
$Enabled_Online_PC_List += $device
}
}else{
Write-Output "Device $device not valid "
}
}
}
So with this line if ($device -like "*-*-D*" -or $device.name -like "*-*-L*" ) i was hoping to filter out all devices that matched what im looking for and proceed to do a Test-Connection on those devices .
Do i need to use regex on this ?
How can i use regex in powershell?
Is there a better way ?
You can do this better by letting Active Directory do the filtering for you, instead of filtering from your side. You can generate an LDAP Filter via string manipulation adding an LDAP Clause for each device type:
$filter = '(&(!userAccountControl:1.2.840.113556.1.4.803:=2)(|'
'S', 'D', 'L', 'T', 'R', 'U' | ForEach-Object {
$filter += '(name=*-*-{0}*)' -f $_
}
$filter += '))'
$onlinePCs = Get-ADComputer -LDAPFilter $filter -SearchBase "DC=some,DC=domain" | Where-Object {
Test-Connection -TargetName $_.DNSHostName -Count 1 -Quiet
}
The generated LDAP Filter would look like this (with some formatting):
(&
(!userAccountControl:1.2.840.113556.1.4.803:=2)
(|
(name=*-*-S*)
(name=*-*-D*)
(name=*-*-L*)
(name=*-*-T*)
(name=*-*-R*)
(name=*-*-U*)
)
)
And can be read as, all enabled objects (computers in this case because we're using Get-ADComputer) which Name attribute is like *-*-S* or *-*-D* or *-*-L* and so on.
Reading though your replies, it got me thinking if LDAP can do the filtering, could powershsell do it to? so i tried this and it works
the where clause did the trick Where-Object {$_.Name -like "*-*-D*" -or $_.Name -like "*-*-L*" -or $_.Name -like "*-*-T*"}
$Enabled_Online_PC_List =[System.Collections.ArrayList]#()
$Enabled_Offline_PC_list =[System.Collections.ArrayList]#()
# $data = #()
$searchBase = "OU=USA,DC=some,DC=domain"
$Enabled_PC_list = Get-ADComputer -filter "Enabled -eq '$true'" -SearchBase $searchBase -properties name | Where-Object {$_.Name -like "*-*-D*" -or $_.Name -like "*-*-L*" -or $_.Name -like "*-*-T*"} | Select-Object -ExpandProperty name
foreach($device in $Enabled_PC_list){
# Write-Output "testing now $device"
if(Test-Connection -ComputerName $device -Count 1 -Quiet){
Write-Output " Now Adding $device to Enabled_Online_PC-List"
$Enabled_Online_PC_List.Add($device)
}else{
Write-Output " Now Adding $device to Enabled_Offline_PC_list"
$Enabled_Offline_PC_list.Add($device)
}
}
Write-Output $Enabled_Online_PC_List
so script is working time is cut off dramatically, now i ask again is there a better way? for some reason LDAP does not want to stick in my head

Catching errors within powershell script

I have written a script to pull permissions from file directories so that we can audit access to folders. I just want to see what groups we have not what users so I wrote this script to pull out all group names and remove the domain name from the value so that it can then run it through a second script that corrects the AD group name for us if its incorrect at all since we ran into an issue where for some reason some were coming back with slightly different names. The problem is all the AD users named in permissions come back as errors. I want those errors to not even show up on screen is there a way to do that? As you can see I have been trying a few different ways to pipe them to a log or the -ea ignore option but it still shows the errors on screen.
$filelocationscsv = "C:\AD\Excel\File Share migration.csv"
$filelocationcsvcontents = Get-Content -LiteralPath $filelocationscsv
$AllFolders = #()
foreach ($location in $filelocationcsvcontents) {
$AllFolders += $location.Substring(0,$location.Length-1)
}
$outputfilelocation = "C:\AD\Excel\permissions.csv"
$Results = #()
$errResults = #()
Foreach ($i in $Allfolders) {
if (Test-Path $i){
Write-Host "Obtaining file permissions for $i."
$acl = (Get-Acl $i -Filter *).Access | select -ExpandProperty IdentityReference
foreach($Access in $acl) {
if ($Access.Value -notlike "BUILTIN\Administrators" -and $Access.Value -notlike "domain\Domain Admins" -and $Access.Value -notlike "CREATOR OWNER" -and $access.Value -notlike "NT AUTHORITY\SYSTEM" -and $access.Value -notlike "Everyone" -and $access.Value -notlike "BUILTIN\Users" -and $access.Value -notlike "s-1*") {
[string]$perm = $Access.Value.Split('\')[1]
if($checkgroup = Get-ADGroup $perm){
#try
#{
## if( $LASTEXITCODE -gt 0 ){
## # Handle the error here
## # This example writes to the error stream and throws a terminating error
## $errResults += $LASTEXITCODE
## Write-Error "Unable to ping server, ping returned" -EA Ignore
## }
$Properties = [ordered]#{'AD Group'=$perm}
$Results += New-Object -TypeName PSObject -Property $Properties
#}
#Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
#{
# Write-Verbose "$perm skipped." -Verbose
# #$ErrorMessage =
# #$FailedItem = $_.Exception.ItemName
# #$errResults += $ErrorMessage + $FailedItem
#}
}
}
}
}
else {
Write-Host "$i is not accessible"
}
}
$Results | select -Property 'AD Group' -Unique | Export-Csv $outputfilelocation -NoTypeInformation
Its worth noting these errors do not stop my script from running its more of an aesthetic function as well as a learning opportunity for myself. I can use my script like it is but I would love to make it look cleaner and learn how to handle errors better.
As you
indicate you are interested in learning more about error handling, one thing I learned this week are these common Parameters for error handling and recording:
-ErrorAction
-WarningAction
-ErrorVariable
-WarningVariable
You can silence the error messages by using the parameter -ErrorAction SilentlyContinue but capture the error by using the parameter -ErrorVariable
EXAMPLE: get-adgroup -ErrorAction SilentlyContinue -ErrorVariable MyErrors
You can read and manipulate the errors by calling $MyErrors
The warnings work the same way
It might give an alternative to Try/Catch.
Thank you #pwnosh you're a genius!
I changed line 20 to
if($errResults += try {$checkgroup = Get-ADGroup $perm -ErrorAction Stop } catch {[Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]}){
This line forces the users into my CSV as well but then the second script cleans them out anyways with
$results = #()
foreach($Group in ($Groups = Import-csv C:\AD\Excel\permissions.csv)){
$groupname = $Group.'AD Group'
Write-Host "Confirming $groupname group name in AD."
$results += get-adgroup -Filter "name -like '$groupname'" -Properties * -SearchBase "dc=domain,dc=local,dc=net" | select name
}
$results | Export-Csv C:\AD\Excel\ADGroups.csv -NoTypeInformation

How to export the list of username and computername that is incorrect or not avaialble in AD from the below script?

How can this script below modified to export the list of the both servers.txt and Accounts.txt that is not available in Active Directory?
The below script is working fine to import the lists from both files that are available and online, but I need to get the list of wrong or unavailable accounts & computer name into separate log files like:
failed_username.log and failed_computername.log respectively.
$Servers = Get-Content "C:\Users\$env:username\desktop\servers.txt" | Where-Object { ((Get-ADComputer -Filter "Name -eq '$($_)'" -Properties OperatingSystem).OperatingSystem -like '*Windows Server*') -and (Test-Connection -ComputerName $_ -Count 2 -Quiet) }
$Users = Get-Content "C:\Users\$env:username\desktop\Accounts.txt" | Where-Object { (Get-ADUser -Filter "SamAccountName -eq '$($_)'") }
ForEach ($Server in $Servers)
{
$ComputerName = $Server.Trim()
Write-Host "Processing $ComputerName" -ForegroundColor Green
ForEach ($Username in $Users)
{
$UserName = $User.Trim()
Write-Host "Processing $UserName" -ForegroundColor DarkGreen
}
}
May I suggest another approach? I think it wouldn't make that much sense to put users and computers to the same list.
I'd do it this way: I'd collect the information about the computers in a list like this:
$ServerInputList =
Get-Content "C:\Users\$env:username\desktop\servers.txt"
foreach ($ComputerName in $ServerInputList) {
[PSCustomObject]#{
Name = $ComputerName
OS = (Get-ADComputer -Filter "Name -eq '$($ComputerName)'" -Properties OperatingSystem).OperatingSystem
Online = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
}
}
Now you can easily filter for the computers you want.
The same would work for the users.

Powershell AD-GetComputer with Array Variable

I'm trying to create a loop that tests the connection to specific computers in the Active Directory. The output is #{name=KY-WH-DT01} when I'm looking for KY-WH-DT01. I'm not sure what I'm doing wrong.
As a workaround, I've pulled the list manually and properly inserted it into the variable as hard code.
function testConnection {
$computers = Get-ADComputer -filter 'Name -like "KY-WH*" -or name -like "KY-SR"' | select name
$pass = 0
$fail = 0
foreach ($computer in $computers) {
$testConnection = Test-Path "\\$computer\C$" -ErrorAction Stop
if ($testConnection -eq $true) {
Write-Host $computer -ForegroundColor Green
$pass = $pass + 1
}
else {
Write-Host $computer -ForegroundColor Red -BackgroundColor Black
$fail = $fail + 1
}
}
Write-Host $null
Write-Host "Passed: $pass | Failed: $fail"
}
testConnection
...
This code should output a list of computer names with colors determining whether the connection test passed or failed by turning them either red or green.
You need to drill down a little bit in your variable.
foreach ($computer in $computers.Name) {
This will do it if you only want the name or the computer and no other variable.
You can also change your initial search to include the -ExpandProperty switch and you will not need to dig down into the property.
$computers = Get-ADComputer -filter 'Name -like "KY-WH*" -or name -like "KY-SR"' | select -ExpandProperty name

Get Hostname and MAC address from all PCs in AD

I'm trying to get the hostname and the MAC address from all PCs in the Active Directory. I know that MAC addresses are not in the Activce Directory. That's why I already used a small script from someone else. The point is that I have to make a list of hostnames, which I can do, but then the other script runs into a problem because some computers are not online.
Can anyone help me get a list with only the pc's that are online?
This is the part that searches the list I create with hostnames.
$Computers = Import-CSV C:\Users\admin_stagiair\Desktop\Computers.txt
$result = #()
foreach ($c in $Computers){
$nic = Invoke-Command {
Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"'
} -ComputerName $c.Name
$x = New-Object System.Object | select ComputerName, MAC
$x.Computername = $c.Name
$x.Mac = $Nic.MACAddress
$result += $x
}
$result | Export-Csv C:\Users\admin_stagiair\Desktop\Computers.csv -Delimiter ";" -NoTypeInformation
And this is the part that I tried to make search the list and filter out the online computers, which absolutely does not work and I can't figure out how to do it.
$Computers = Import-Csv C:\Users\admin_stagiair\Desktop\Computers.txt
foreach ($c in $Computers) {
$ping = Test-Connection -Quiet -Count 1
if ($ping) {
$c >> (Import-Csv -Delimiter "C:\Users\admin_stagiair\Desktop\online.txt")
} else {
"Offline"
}
}
Last bit, this is the part I use to create a list of all computers in the Active Directory.
Get-ADComputer -Filter {enabled -eq $true} -Properties * |
select Name > C:\Users\(user)\Desktop\Computers.txt
If you only want one property from Get-ADComputer don't fetch all
a computer could have more than one MAC, to avoid an array be returned join them.
$result += inefficiently rebuilds the array each time, use a PSCustomObject instead.
Try this (untested):
EDIT: first test connection, get MAC only when online
## Q:\Test\2018\09\18\SO_52381514.ps1
$Computers = (Get-ADComputer -Filter {enabled -eq $true} -Property Name).Name
$result = ForEach ($Computer in $Computers){
If (Test-Connection -Quiet -Count 1 -Computer $Computer){
[PSCustomPbject]#{
ComputerName = $Computer
MAC = (Invoke-Command {
(Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').MACAddress -Join ', '
} -ComputerName $Computer)
Online = $True
DateTime = [DateTime]::Now
}
} Else {
[PSCustomPbject]#{
ComputerName = $Computer
MAC = ''
Online = $False
DateTime = [DateTime]::Now
}
}
}
$result | Export-Csv C:\Users\admin_stagiair\Desktop\Computers.csv -Delimiter ";" -NoTypeInformation
What about trying something like this:
# Get all computers in list that are online
$Computers = Import-Csv C:\Users\admin_stagiair\Desktop\Computers.txt |
Select-Object -ExpandProperty Name |
Where-Object {Test-Connection -ComputerName $_ -Count 1 -Quiet}
# Grab the ComputerName and MACAddress
$result = Get-WmiObject -ComputerName $computers -Class Win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"' |
Select-Object -Property PSComputerName, MacAddress
$result | Export-Csv C:\Users\admin_stagiair\Desktop\Computers.csv -Delimiter ";" -NoTypeInformation