I have a text file that contains called MY-OU.txt
OU=offic-Computers,OU=comp-computers,DC=my,DC=company,DC=com
I can get a list of all the computers in that OU:
ForEach ($OU in Get-Content "C:\temp\MY-OU.txt")
{
Get-ADComputer -SearchBase $OU -Filter '*' | Select -Exp Name | Out-File -filepath "C:\temp\MY-OU-computers.txt"
}
And I can get the current logged on users from the output of the code above:
$content = Get-Content C:\temp\MY-OU-computers.txt
$output = foreach ($PC in $content) {Get-WmiObject –ComputerName $PC –Class Win32_ComputerSystem | Select-Object UserName}
$output | Out-File -filepath "C:\temp\CAD-OU-computers-users.txt"
How to combine both parts and get the current logged on users in a specific OU?
Instead of outputting the results from Get-ADComputer to a file, you can assign them to a variable ($Computers), then use that as the input for your next foreach loop:
foreach ($OU in Get-Content "C:\temp\MY-OU.txt"){$Computers += Get-ADComputer -SearchBase $OU -Filter '*' | Select -ExpandProperty Name}
$output = foreach ($PC in $Computers) {Get-WmiObject –ComputerName $PC –Class Win32_ComputerSystem | Select-Object UserName}
$output | Out-File -filepath "C:\temp\CAD-OU-computers-users.txt"
Related
How do I get a list of computers in a particular OU along with the Description and Last logged on user in a .csv?
$userName = (Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $machine -ErrorAction:SilentlyContinue).UserName
$DisComp = Get-ADComputer -LDAPFilter "(Name=LN-*)" -SearchBase "OU=Computers - Disabled,DC=XXXXX,DC=com" | Select-Object Name
$results = foreach ($Machine in $DisComp) {
$Description = Get-AdComputer -Identity $Machine -Properties * | Select-Object Description
$UserName
$Machine
$Description
}
$results | Export-Csv -Path C:\XXXXX
Define the OU and CSV file paths
$ouPath = "OU=Workstations,DC=contoso,DC=com"
$csvPath = "C:\temp\computer-list.csv"
Use the Get-ADComputer cmdlet to get a list of computers in the OU
$computers = Get-ADComputer -SearchBase $ouPath -Filter * -Properties lastlogondate,description
Loop through each computer and get the description and last logged on user
foreach ($computer in $computers) {
$description = $computer.Description
$lastLoggedOnUser = $computer.LastLogonUser
$data = [PSCustomObject]#{
"Computer Name" = $computer.Name
"Description" = $description
"Last Logged On User" = $lastLoggedOnUser
}
Add the computer data to the CSV file
$data | Export-Csv -Path $csvPath -Append -NoTypeInformation
}
AFAIK there is no AD computer property called LastLogonUser or any other property that holds this information.
To get the user that last logged on, you need to query the windows Eventlog on that computer and search for events with ID 4672
As aside, don't use -Properties * if all you want on top of the default properties returned is the Description property.
Try:
$searchBase = "OU=Computers - Disabled,DC=XXXXX,DC=com"
$Computers = Get-ADComputer -LDAPFilter "(Name=LN-*)" -SearchBase $searchBase -Properties Description
$results = foreach ($machine in $Computers) {
# to get the username who last logged on, you need to query the Security log
$events = Get-WinEvent -ComputerName $machine.Name -FilterHashtable #{Logname='Security';ID=4672} -MaxEvents 50 -ErrorAction SilentlyContinue
$lastLogon = if ($events) {
(($events | Where-Object {$_.Properties[1].Value -notmatch 'SYSTEM|NETWORK SERVICE|LOCAL SERVICE'})[0]).Properties[1].Value
}
else {
"Unknown"
}
# output an object
[PsCustomObject]#{
ComputerName = $machine.Name
Description = $machine.Description
LastLoggedOnUser = $lastLogon
CurrentUser = (Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $machine.Name -ErrorAction SilentlyContinue).UserName
}
}
$results | Export-Csv -Path 'C:\Somewhere\Computers.csv' -NoTypeInformation
P.S. You of course need admin permissions to query the eventlog, so perhaps (if you are not a domain admin) you need to use the -Credential parameter on the Get-WinEvent line aswell.
$ErrorActionPreference = 'SilentlyContinue'
$ComputerName =Get-ADComputer -Filter {(Name -like "*")} -SearchBase "OU=AsiaPacific,OU=Sales,OU=UserAccounts,DC=FABRIKAM,DC=COM" | Select-Object -ExpandProperty Name
$results = #{}
ForEach ($computer in $ComputerName) {
$Results += Get-NetAdapter -CimSession $ComputerName | Select-Object PsComputerName, InterfaceAlias, Status, MacAddress
}
$results | Export-csv -path C\users\bret.hooker\desktop\macaddress.csv -Append
Please note the base and filter are just examples and not the actual code due to work place confidentiality. Code currently will pull from AD all computer name, then will run the ForEach command to get the NetAdapter Information. I am unable to get it to output to the CSV file however. Any advice would be great.
My recommendations are 1) don't continuously append objects to an array, 2) avoid the -Append parameter of Export-Csv, and 3) take advantage of the pipeline. Example:
$computerNames = Get-ADComputer -Filter * -SearchBase "OU=AsiaPacific,OU=Sales,OU=UserAccounts,DC=FABRIKAM,DC=COM" | Select-Object -ExpandProperty Name
$computerNames | ForEach-Object {
Get-NetAdapter -CimSession $_ | Select-Object PSComputerName,InterfaceAlias,Status,MACAddress
} | Export-Csv "C\users\bret.hooker\desktop\macaddress.csv" -NoTypeInformation
I am putting together a script that will check all of my web servers certificates so that I can monitor when they are set to expire. When the script goes to execute the Invoke-Command I am getting this error:
Here is my code:
Import-Module WebAdministration
$results = #()
$ou = 'OU=test,OU=test,OU=Servers,DC=contoso,DC=com'
$subtree = Get-ADOrganizationalUnit -SearchBase $ou -SearchScope Subtree -filter * | Select-Object -ExpandProperty DistinguishedName
ForEach($dn in $subtree){
$servers = Get-ADComputer -Filter * -SearchBase $dn | select Name
$results += $servers
}#ForEach($dn in $subtree)
$scriptBlock = [scriptblock]::Create({
Import-Module WebAdministration; Get-ChildItem -Path IIS:SSLBindings | ForEach-Object -Process `
{
If($_.Sites){
$certificate = Get-ChildItem -Path CERT:LocalMachine/My |
Where-Object -Property Thumbprint -EQ -Value $_.Thumbprint
[PSCustomObject]#{
Sites = $_.Sites.Value
CertificateDNSNameList = $certificate.DnsNameList
CertificateNotAfter = $certificate.NotAfter
}#[PSCustomObject]
}#If($_.Sites)
}#Import-Module
})#ScriptBlock
ForEach($server in $results){
Invoke-Command -ComputerName $server -ScriptBlock $scriptBlock | Select Sites,CertificateDNSNameList,CertificateNotAfter,PSComputerName #ScriptBlock
}#ForEach($server in $results)
Now, If I take the following line out of the loop and replace $server with an actual server name, I get the results I am looking for:
Invoke-Command -ComputerName ServerName -ScriptBlock $scriptBlock | Select Sites,CertificateDNSNameList,CertificateNotAfter,PSComputerName
Any ideas what I am doing wrong?
Your Results-Array is not an array of string, it is an array of object. Each object have the attribute name. Change your last ForEach-Loop into this and your script will work:
ForEach($server in $results){
Invoke-Command -ComputerName $server.name -ScriptBlock $scriptBlock | Select Sites,CertificateDNSNameList,CertificateNotAfter,PSComputerName #ScriptBlock
}#ForEach($server in $results)
It looks to me like "select Name" is returning an object rather than a string. Try changing the line that fetches the servers to this:
$servers = Get-ADComputer -Filter * -SearchBase $dn | select -ExpandProperty Name
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...
I can only get the command to return the services on the first computer in the text file.
Is there a better way than for-each for this task?
Get-Service *vault* -ComputerName (Get-Content c:\users\sean\desktop\js.txt) | select name,status,machinename | sort machinename | format-table -autosize
Try it without the get-content. Try this:
Get-Service *vault* -ComputerName c:\users\sean\desktop\js.txt | select name,status,machinename | sort machinename | format-table -autosize
If that doesn't work, then try:
$Computers = Get-Content c:\users\sean\desktop\js.txt
Get-Service *vault* -computername $Computers | Select name,status,machinename |sort machinename |format-table -autosize
If you are eager for a one-liner then try this:
Get-Content c:\users\sean\desktop\js.txt | Get-Service *vault* | Select name,status,machinename |sort machinename |format-table -autosize
I would try the top one first. I would test, but I don't have access to anything I can do a proper test right now.
$Computers = get-content .\desktop\test.txt
$Service = "Vault"
foreach ($computer in $computers) {
$computer
$Servicestatus = get-service -name $Service -ComputerName $computer
}
$Servicestatus | select-object Name,Status,MachineName | format-table -Autosize
This works for me, it gives me each of the computers in the text file, and it looks for the service.
This is what I use. I get the list of computers from an OU in AD.
Import-Module ActiveDirectory
$ou = "OU=Servers,DC=Domain,DC=com"
$servers = Get-ADComputer -Filter * -SearchBase $ou | select-object -expandproperty name
Foreach ($server in $servers){
$Data = Get-Service -ServiceName *IIS*,*TomCat*,*httpd* -ComputerName $server | select machinename,name | sort machinename | format-table -AutoSize
Write($Data) | Out-File .\WebServices.txt -Append
}
$servers = Get-Content .\servers.txt
Foreach ($server in $servers) {
"$server"
Get-Service -ComputerName $Server -name -like "*vault*"
"-------------------"
}
Following a memory limitation limit with older versions of PowerShell, I was required to refresh my code:
Old code:
gwmi win32_service -computer $allcomputers | Select-Object __SERVER,Name,state,startmode,StartName
New code:
`$servers = Get-Content "computers.txt"
Foreach ($server in $servers) {
Get-WmiObject -Class WIN32_service -ComputerName $server |
Select-Object __SERVER,Name,state,startmode,StartName |
Export-Csv -path "Report.CSV" -NoTypeInformation -Append
}`
This is how you can get list of all services in your AD domain:
Get-ADComputer -Filter {OperatingSystem -Like “Windows 10*”} | ForEach-Object {Get-WmiObject -Class Win32_Service -Computer $_.Name}
More useful examples on this (get list of services for all computer listed in a text file, etc.):
https://www.action1.com/kb/list_of_services_on_remote_computer.html
Get-Service -ComputerName ... has a bug in PowerShell 2.0 that only returns the first computer. This is fixed in newer versions so if you upgrade to PowerShell 3.0 or newer, your original code will work fine.
As a workaround, use a foreach-loop to run Get-Service once for each computer:
Get-Content c:\users\sean\desktop\js.txt |
ForEach-Object { Get-Service -Name *vault* -ComputerName $_ } |
Select-Object -Property Name, Status, MachineName |
Sort-Object -Property MachineName |
Format-Table -AutoSize
Nick's solution totally doesn't work for me. I ended up writing a quick and dirty one that works:
$servers = Get-Content .\servers.txt
Foreach ($server in $servers) {
"$server"
Get-Service *vault*
"-------------------"
}