Get Hostname and MAC address from all PCs in AD - powershell

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

Related

PowerShell not running all lines in Function

Below Function is not running the lines "If ($script:AADServersTable)" down... I have put a write-host and that is working, however the variables are not working below that
Function get-AADVariables
{
$script:AADServersTable = New-Object 'System.Collections.Generic.List[System.Object]'
$scriptBlockaadinstalled = {
Get-WmiObject -Class Win32_Product |
where name -eq "Microsoft Azure AD Connect synchronization services" | select Name, Version}
##$scriptBlockaadinstalled = {hostname}
Import-Module ActiveDirectory
$servers = Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"' | Select-Object -Property Name -ExcludeProperty Release
## just a single invoke-command
foreach ($server in $servers) {
$aadinstalledresults = Invoke-Command -ComputerName $server.name -ScriptBlock $scriptBlockaadinstalled ##-HideComputerName
$aadinstalledresults = $aadinstalledresults.PSComputerName
$script:AADServersTable.Add($aadinstalledresults)
}
If ($script:AADServersTable) {
Write-Host 'working'
$AADServers = ($script:AADServersTable | Group-Object -NoElement).Name | Get-Unique
$AADServers = $AADServers -split "`n"
$AADServer = $AADServers[0]
$StandByAADServer = $AADServers[1]
$SecondStandByAADServer = $AADServers[2]
}
}

i trying to collect different info with Get-ADComputer, Get-WmiObject and Get-windowsfeature

I am trying to collect different properties from all computer listed from my AD but I can't get format to recolected querys
I run get-adcomputer query
$computerList = Get-ADComputer -Filter 'Name -like "SCPW*" -and ObjectClass -eq "Computer"' | Select-Object -Property Name,objectClass`
I collect info from al computer listed in $computerlist
$list = foreach ($computer in $computerList) {Get-WmiObject -Class Win32_Product | Select-Object -Property Name }
$WFeature = foreach ($computer in $computerList) {Get-windowsfeature | Where {$_.installed -Eq $true} | Select-Object -Property Name}
$Wrole = foreach ($computer in $computerList) {Get-WmiObject -Class Win32_ServerFeature -Property * | select pscomputername,name }
Finally I try to list all info collected in a unique table with
%{[PSCustomObject]#{
'ComputerName' = $computer.Name
'features' = $WFeature.name
'Role' = $Wrole.name
'list' = $list.name
} } | Format-table
but the table listed is only in one line
ComputerName features Role list
------------ -------- ---- ----
SCPWEXC0101 {File-Services, FS-FileServer, Remote-Desktop-Services, RDS-RD-Server...} {Web Server (IIS), File Services, Print and Document Services, Remote Desktop Services...} {Microsoft Ap...
the table listed only in one line (screenshot)
I really will be much gratefull if somebody give me some help, I'm learning PS and I really lossed with this query. I've been running Ps 5.1
Thanks!!
You will have to put the queries inside a loop for each single computer to keep the correlation between the collected information and the computer name. Something like this should get you started:
$computerList = Get-ADComputer -Filter 'Name -like "SCPW*" -and ObjectClass -eq "Computer"'
$Result =
foreach ($computer in $computerList) {
$CimSession = New-CimSession -ComputerName $computer.name
[PSCustomObject]#{
ComputerName = $computer.Name
WindowsFeatureList = (Get-windowsfeature -ComputerName $computer.name | Where-Object { $_.installed } | Select-Object -Property Name) -join ', '
W32ServerFeatureList = (Get-CimInstance -CimSession $CimSession -ClassName Win32_ServerFeature | Select-Object -Property Name) -join ', '
W32ProductList = (Get-CimInstance -CimSession $CimSession -ClassName Win32_Product | Select-Object -Property Name) -join ', '
}
}
$Result

System.String[] - Result

I did a search and I understand the issue that some of these are arrays. What I am not sure I understand is why I am getting this when I am specifically trying to return just one value.
I am using a ForEach loop and pulling from a text file the names of the computers I want to query.
I want to verify that the IP address I am pinging is the same computer I want to connect to. We have many users on VPN and the DNS doesn't update fast enough. This means we get some incorrect information.
$NIC2 = Get-WmiObject win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object {$_.DNSDomain -eq "usms.contoso.com"} | Select-Object IPAddress
This should give me only one IP address and not an array, but unfortunately I get the System.String[] in the CSV output. If I just type this command out in the PowerShell command line it works beautifully, but not when I put it into a CSV.
any ideas?
Thanks in advance.
Entire code below - I get the results for everything except the $NIC2 and doing $NIC2.IPAddress[0] doesn't seem to work.
Putting $NIC2[0] just give me this in that column
dapterConfiguration -ComputerName $computer | Where-Object {$_.DNSDomain -eq "contoso.com"} | Select-Object IPAddress
#Definitions of variables
#************************
#Defines the location and name of the text file from where computers will be pulled
$Computers = Get-Content "c:\Temp\computers.txt"
#Defines the variable and format for Date
$Date = Get-date -UFormat %h_%d_%y_%H%M
#Define the name of the files to output
$OutputFile = "C:\Temp\Verify-Computer-$Date.csv" #All Computers On-Line Status will be provided in this file
#Defines the Array where to put the data and the $Ping variable to store the IP address
$DataArray = #()
$Resolution = New-Object System.Object.NetworkInformation.Ping
#Define A Function that will test which computers are on-line and create files to use in the other function.
ForEach ($computer in $Computers)
{
#Defining the variables
$TESTConnection = $null
$Object = $null
$Value = $null
$IPAddress = $null
$NameResolution = $null
$PingAddress = $null
$NIC = $null
$NIC2 = $null
$NICIP = $null
# Ping computer
$TESTConnection = Test-NetConnection -ComputerName $computer | Select-Object PingSucceeded
#If connection is live Get IP address
IF ($TESTConnection.PingSucceeded -eq "True") {
$IPAddress = Test-NetConnection -ComputerName $computer -InformationLevel "Detailed" | Select-Object RemoteAddress
$NIC = Get-WmiObject win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object {$_.DNSDomain -eq "contoso.com"} | Select-Object MACAddress, DNSHostName
$NIC2 = {Get-WmiObject win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object {$_.DNSDomain -eq "contoso.com"} | Select-Object IPAddress}
$Value = $TESTConnection.PingSucceeded
$PingAddress = $IPAddress.RemoteAddress
}
Else {
$Value = $TESTConnection.PingSucceeded
$PingAddress = $IPAddress.RemoteAddress
$NICIP = "NOT REACHABLE"
}
# Create object
$Object = New-Object PSObject -Property ([ordered]#{
Computer_Target = $computer
ONLINE = $Value
IPAddress_PING = $PingAddress
IPResolved = $NIC2.IPAddress
NameResolved = $NIC.DNSHostName
MACAddress = $NIC.MACAddress
})
# Add object to array
$DataArray += $Object
#Display object
}
If($DataArray)
{
#Output Array Data into a CSV File
$DataArray | Export-Csv -Path $OutputFile -NoTypeInformation
}
#end of file
OK - I finally figured it out because I kept going around in circles and getting nowhere.
Thank you to Zett42 who led me in the right direction but I was still failing.
My first problem was that I hadn't identified $NIC2 as an Array which was part of my issue when trying $NIC2[0]. However, even after being Defined as an Array it still didn't work.
I then created another array and did this $NICIP = $NIC2.IPAddress and then output $NICIP[0] which works. Not exactly sure why that works.
Here is the entire code
#Definitions of variables
#************************
#Defines the location and name of the text file from where computers will be pulled
$Computers = Get-Content "c:\Temp\computers.txt"
#Defines the variable and format for Date
$Date = Get-date -UFormat %h_%d_%y_%H%M
#Define the name of the files to output
$OutputFile = "C:\Temp\Verify-Computer-$Date.csv" #All Computers On-Line Status will be provided in this file
#Defines the Array where to put the data and the $Ping variable to store the IP address
$DataArray = #()
$Resolution = New-Object System.Object.NetworkInformation.Ping
#Define A Function that will test which computers are on-line and create files to use in the other function.
ForEach ($computer in $Computers)
{
#Defining the variables
$TESTConnection = $null
$Object = $null
$Value = $null
$IPAddress = $null
$NameResolution = $null
$PingAddress = $null
$NIC = $null
$NIC2 = #()
$NICIP = #()
# Ping computer
$TESTConnection = Test-NetConnection -ComputerName $computer | Select-Object PingSucceeded
#If connection is live Get IP address
IF ($TESTConnection.PingSucceeded -eq "True") {
$IPAddress = Test-NetConnection -ComputerName $computer -InformationLevel "Detailed" | Select-Object RemoteAddress
$NIC = Get-WmiObject win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object {$_.DNSDomain -eq "contoso.com"} | Select-Object MACAddress, DNSHostName
$NIC2 = Get-WmiObject win32_NetworkAdapterConfiguration -ComputerName $computer | Where-Object {$_.DNSDomain -eq "contoso.com"} | Select-Object IPAddress
$Value = $TESTConnection.PingSucceeded
$PingAddress = $IPAddress.RemoteAddress
$NICIP = $NIC2.IPAddress
}
Else {
$Value = $TESTConnection.PingSucceeded
$PingAddress = "NOT REACHABLE"
}
# Create object
$Object = New-Object PSObject -Property ([ordered]#{
Computer_Target = $computer
ONLINE = $Value
IPAddress_PING = $PingAddress
IPResolved1 = $NICIP[0]
NameResolved = $NIC.DNSHostName
MACAddress = $NIC.MACAddress
})
# Add object to array
$DataArray += $Object
#Display object
}
If($DataArray)
{
#Output Array Data into a CSV File
$DataArray | Export-Csv -Path $OutputFile -NoTypeInformation
}
#end of file

Looking for pograms on client machines

i got a client who wants to find all of the companys installed programs i wrote a script but i dont want the script show me the same same programs for each comuter every time,i want to see overall installations
$computers = get-adcomputers -filter *
foreach($computer in $computers){
Get-ItemProperty
HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-
Table –AutoSize}
I did not test this, but you can try
$computers = (Get-ADComputer -Filter *).DNSHostName # or use .Name or .CN
$software = Invoke-Command -ComputerName $computers {
Get-ItemProperty -Path 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
}
$software | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate -Unique |
Format-Table -AutoSize
P.S.1 You need to have admin permissions on all computers to do this
P.S.2 Don't forget there is also HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
Apparently you are running into problems where computers are off-line.
To overcome that, you need to add a loop so you can test if a machine is reachable or not.
$computers = (Get-ADComputer -Filter *).Name # or use .CN
# loop through the collection and (if reachable) get the software list
$result = foreach ($computer in $computers) {
# test if the computer is online
if (Test-Connection -ComputerName $computer -Count 1 -Quiet) {
# output the properties you need to get collected in variable $result
Invoke-Command -ComputerName $computer {
Get-ItemProperty -Path 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
} | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate
}
else {
Write-Warning "Computer $computer is off-line"
}
}
$software = $result | Select-Object * -Unique
# output to console
$software | Format-Table -AutoSize
# output to CSV file
$software | Export-Csv -Path 'D:\Software.csv' -NoTypeInformation

Use WMI to convert a remote SID to username

I am using Invoke-WMIMethod to identify all SIDS beginning with S-1-5-21, like so (thanks to Mathias R. Jessen):
$Keys = Invoke-WmiMethod -Path $ClassPath -Name EnumKey -ArgumentList 2147483651,''
| Select-Object -ExpandProperty sNames | Where-Object {$_ -match 'S-1-5-21-[\d\-]+$'}
I want to convert these SIDs from the remote system to usernames on the remote system using WMI. Is this possible through WMI or Invoke-WmiMethod?
You can use the Win32_SID class to obtain the account name:
foreach($Key in $Keys)
{
$SID = [wmi]"\\$RemoteComputer\root\cimv2:Win32_SID.SID=$Key"
New-Object psobject -Property #{
SID = $Key
Username = $SID.ReferencedDomainName,$SID.AccountName -join '\'
}
}
Rather than grabbing from the registry you could get the same information from the Win32_UserProfile provider. Then if folder name is good enough, consider something like this:
$Computer = "ExampleComputer"
Get-WMIObject Win32_UserProfile -Filter "SID like 'S-1-5-21-*'" -ComputerName $Computer |
select SID,#{name=LocalPath;Expression={Split-Path -leaf $_.LocalPath}}
Otherwise Win32_UserAccount exists but can be really slow with a large domain.
$Computer = "ExampleComputer"
$SIDs = Get-WMIObject Win32_UserProfile -Filter "SID like 'S-1-5-21-*'" -ComputerName $Computer | select -ExpandProperty SID
$UserAccounts = Get-WMIObject Win32_UserAccount -ComputerName $Computer
foreach ($SID in $SIDs) {
foreach ($Account in $UserAccounts) {
If ($SID -eq $Account.SID) {
$Account
}
}
}