i have a text file containing arround 100 servers, how can i push these into a script and test if they exist within AD? I have a simple script below:
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
if (Get-ADComputer $serverlist ) {
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
else {
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
}
the above does not work returning a error:
Get-ADComputer : Cannot convert 'System.Object[]' to the type 'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter 'Identity'. Specified method is not supported.
Can someone please explain does the get-adcomputer only allow a single object? Also if i remove the txt file and add a server shown below:
if (Get-ADComputer "server name" )
The above provides only results if the server exists within AD, if the server does not the error is shown below:
Get-ADComputer : Cannot find an object with identity: 'iuiub' under: 'DC=####,DC=#####,DC=#####'
Thank you for any insight / help!
Phil
Create an array - #(). If the array has 1 or more objects in it - which is $true - then you know the computer exists. If the array has 0 objects in it - which is $false- then you know the computer doesn't exist. I know some people don't like the ErrorAction to be set to SilentlyContinue but you're "Outputting an Error" if an error does occur.
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
if (#(Get-ADComputer $server -ErrorAction SilentlyContinue).Count) {
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
else {
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
}
Another thing you could try are try catch blocks. Sorta like this:
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
try{
Get-ADComputer $server -ErrorAction Stop
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
catch{
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
}
Line 3, change $serverlist to $server
With regards to handling a not found result. I'd try flipping the logic :
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
$tempVar = Get-ADComputer $server
if ($tempVar -like "Get-ADComputer : Cannot find an object with identity" ) {
Write-Host "#########################"
Write-Host "Computer object NOT FOUND"
Write-Host "#########################"
}
else{
Write-Host "#########################"
Write-Host "Computer object exists"
Write-Host "#########################"
}
}
In order to get a more helpful output, I'd go with the following... You'll just have a list of green and red lines indicating which server was found and which one wasn't.
$serverlist = get-content ServerList.txt
foreach ($server in $serverlist) {
try {
Get-ADComputer $server -ErrorAction Stop | Out-Null
Write-Host "$($server) exists" -ForegroundColor DarkGreen
}
catch {
Write-Host "$($server) NOT FOUND" -ForegroundColor DarkRed
}
}
Related
I'm using the following script to run through all of the servers in a specified Active Directory OU and log out the specified user. This runs perfectly well for the first 35 servers but always errors out on the very last server it iterates through. The error is:
Program 'quser.exe' failed to run: Object reference not set to an instance of an object. At line:6 char:24
+ $result = (quser $userAccount)
+ ~~~~~~~~~~~~~~~~~~.
At \\path\to\script.ps1:79 char:5
+ invoke-command -ComputerName $server -ScriptBlock $scriptBlock -A ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Program 'quser....~~~~~~~~~~~~~~.:String) [], RuntimeException
+ FullyQualifiedErrorId : Program 'quser.exe' failed to run: Object reference not set to an instance of an object.At line:6 char:24
+ $result = (quser $userAccount)
+ ~~~~~~~~~~~~~~~~~~.
My reading of the error is that it thinks $userAccount has no value. Is that correct and, if so, can anyone point at what I'm missing? Thank you in advance!
Write-Host " "
Write-Host "This script will log out all active sessions for the specified user. Proceed with caution." -ForegroundColor Black -BackgroundColor Yellow
Write-Host " "
$servers = [System.Collections.ArrayList]::new()
foreach ($server in (Get-ADComputer -SearchBase "OU=FictionalDepartment,DC=Company,DC=net" -Filter "OperatingSystem -like 'Windows Server*'" -Properties Name | select -ExpandProperty name))
{
$servers.add($server) | Out-Null
}
$servers.Sort()
$userAccount = Read-Host "Enter account to log out"
Write-Host " "
foreach ($server in $servers)
{
$scriptBlock = {
param($userAccount)
$ErrorActionPreference = 'Stop'
try
{
$result = (quser $userAccount)
$session = ((quser $userAccount)[1] -split "\s+")[2]
logoff $session
Write-Host " The user was logged into session #$session. They have been LOGGED OFF." -ForegroundColor Yellow
}
catch
{
if ($_.Exception.Message -match 'No user exists')
{
Write-Host " User is not logged in." -ForegroundColor Green
}
else
{
throw $_.Exception.Message
}
}
}
Write-Host "$server"
Invoke-Command -ComputerName $server -ScriptBlock $scriptBlock -ArgumentList $userAccount
$session = $null
}
Based on feedback, I modified the script so that it no longer uses Invoke-Command, but parses the active sessions by running quser <user> /SERVER:<server> as follows:
Write-Host "Will log specified user out of all servers..." -ForegroundColor Black -BackgroundColor Yellow
Write-Host " "
$servers = [System.Collections.ArrayList]::new()
foreach ($server in (Get-ADComputer -SearchBase "OU=Fictional,DC=Company,DC=net" -Filter "OperatingSystem -like 'Windows Server*'" -Properties Name | select -ExpandProperty name))
{
$servers.add($server) | Out-Null
}
$servers.Sort()
$userAccount = Read-Host "Enter account to scan for"
Write-Host ""
foreach ($server in $servers)
{
Write-Host "$server"
$ErrorActionPreference = 'Stop'
try
{
$session = ((quser $userAccount /SERVER:$server)[1] -split "\s+")[3]
logoff /SERVER:$server $session
Write-Host " The user was logged into session #$session. They have been LOGGED OFF." -ForegroundColor Yellow
}
catch
{
if ($_.Exception.Message -match 'No user exists')
{
Write-Host " User is not logged in." -ForegroundColor Green
}
}
}
I cannot get PowerShell to run this .txt file, what am I doing wrong? I tried changing the name of the .txt and checked passed scripts and everything seems to be the same but I keep getting an error saying that the ".txt in invalid"
$POSName = "$PSScriptRoot\Bex.txt"
foreach ($POS in (Get-Content $POSName)) {
$Bex = Get-Service -ComputerName $POSName | Where-Object { $_.name -eq "BexServ" }
}
If ($Bex -eq $null) {
# Service does not exist
Write-Host " doesn't exist." -ForegroundColor Red
}
Else {
# Service does exist
Write-Host "The $($Bex.Name) service found." -ForegroundColor Green
If ($Bex.Status -eq "Running") {
# Stop Service
Set-Service -status stopped -ComputerName $POSName -name $Box.Name -ErrorAction Stop
Write-Host "The $($Bex.Name) successfully stopped." -ForegroundColor Green
}
else {
#service already stopped
If ($Bex.Status -eq "Stopped") {
Write-Host "The $($Bex.Name) service already Stopped." -ForegroundColor Green
}
}
}
As commented, you are using the wrong variable in the loop. The code is reading the text file just fine, it is Get-Service that cannot deal with a path to a file in the -ComputerName parameter.
Also, the placing of the if..else should be inside the loop, not after.
Try
$POSName = "$PSScriptRoot\Bex.txt"
foreach ($POS in (Get-Content $POSName)) {
$Bex = Get-Service -ComputerName $POS | Where-Object { $_.name -eq "BexServ" }
If (!$Bex) {
# Service does not exist
Write-Host " doesn't exist." -ForegroundColor Red
}
Else {
# Service does exist
Write-Host "The $($Bex.Name) service found." -ForegroundColor Green
If ($Bex.Status -eq "Running") {
# Stop Service
Set-Service -status stopped -ComputerName $POSName -name $Box.Name -ErrorAction Stop
Write-Host "The $($Bex.Name) successfully stopped." -ForegroundColor Green
}
else {
#service already stopped
If ($Bex.Status -eq "Stopped") {
Write-Host "The $($Bex.Name) service already Stopped." -ForegroundColor Green
}
}
}
}
It might also be a good idea to output the computername ($POS) in the Write-Host lines too
Wrote a small script to find the number Multipaths from the windows servers using WMI query. It works well for the servers which can connect directly without any issue. But if one server is pingable but not able to reach through WMI script, it takes long time to return the error ( for example if a linux server hostname is present in the servers.txt list).. Can somebody help me to do the same in a faster way..?
$Servers = Get-Content .\Servers.txt
$ErrorActionPreference = ‘SilentlyContinue’
FOREACH ($Server in $Servers) {
Write-Host $Server -nonewline
if (test-connection -computername $Server -Count 1 -quiet) {
$Name = $null
$NoPath =$null
$MPIODisks =$null
$MPIODisks = Get-WmiObject -Namespace root\wmi -Class mpio_disk_info -ComputerName "$Server" |Select-Object "DriveInfo"
if ($MPIODisks -eq $Null) {
write-host "`t - Unable to connect" -fore "RED"
} else {
write-host ""
write-host "Drive Name `tNo.Path" -fore "yellow"
Foreach ($Disk in $MPIODisks) {
$mpiodrives = $disk.DriveInfo
foreach ($Drive in $mpiodrives) {
$Name = $Drive.Name
$NoPath = $Drive.Numberpaths
If ($NoPath -lt 4) {
Write-Host $Name `t -nonewline
write-host $NoPath -fore "Red"
} else {
Write-Host $Name `t -nonewline
write-host $NoPath -fore "Green"
}
}
}
}
write-host ""
} else {
write-host "`t- Unknown Host" -fore "Red"
write-host ""
}
}
There is a connect item for Get-WmiObject to add a timeout parameter. A workaround noted in that item is to just pipe your WMI command to Wait-Job and specify a timeout period in seconds.
As long as your on PS version 3.0 or higher, this should work for you:
Get-WmiObject win32_computersystem -ComputerName <hostname> -AsJob | Wait-Job -Timeout 10 | Receive-Job
As an alternative, you could ask all servers for the result at once by passing them all into the query and avoiding the slow loop querying one server at a time. I don't have any MPIO drives to test with, but it could look something like this (using Get-Ciminstance which takes a timeout parameter):
$servers = Get-Content .\Servers.txt
# Get data from all servers with timeout
$servers_ok = Get-CimInstance -computername $servers -Namespace root\wmi -Class mpio_disk_info -ErrorAction SilentlyContinue -OperationTimeoutSec 1 | group pscomputername
# Output which servers gave no result back
foreach($no_result in $($servers | where { $_ -NotIn $servers_ok.Name })) {
write-host "No result for $no_result" -ForegroundColor Red
}
# Loop over the results and output
foreach($server in $servers_ok) {
Write-Host $server.Name
foreach($mpiodisk in $server.group) {
$mpiodrives = $mpiodisk.DriveInfo
foreach ($mpiodrive in $mpiodrives) {
$name = $mpiodrive.Name
$noPath = $mpiodrive.NumberPaths
If ($NoPath -lt 4) {
write-host $name `t -nonewline
write-host $noPath -fore "Red"
} else {
write-host $name `t -nonewline
write-host $noPath -fore "Green"
}
}
}
}
I have few numbers of server where "tempadmin" and "Administrator" are exist as local admin user. I need to delete "tempadmin" id if "Administrator" is also exist. else "tempadmin" needs to rename as "Administrator". Could anyone help me create one PowerShell script?
cls
$strComputer = Get-Content "c:\patch\clientlist.txt"
$password = Read-Host "Enter the password : " -AsSecureString
foreach ($server in $strComputer) {
Write-Host "Working on server $server"
if (Test-Connection $server -Quiet) {
$usertest1 = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True AND Name='test1'" -ComputerName $server
if ($usertest1.name -ne 'test1') {
$user = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True AND Name='test'" -ComputerName $server
$result = $user.Rename('test1')
if ($result.name -eq 'test') {
$result
# you may just print a message here
}
Write-host "$server -> ID renamed and resetting password...."
$user1 = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True AND Name='test1'" -ComputerName $server
([adsi]("WinNT://" + $server + "$user1")).SetPassword("$password")
Write-Host "$server -> Password reset successfully"
} else {
Write-Host "$server -> Test1 ID already exist"
}
} else {
Write-Host "$server -> server is not reachable"
}
}
Here I am user "test" and "test1". I tried the above code and I can successfully rename and reset the password. But I am unable to delete if both ID's are exist.
I would try something like this:
$VerbosePreference = 'Continue'
foreach ($C in $Computer) {
if (Test-Connection $C -Quiet) {
Write-Verbose "$C > Online"
$Users = Get-WMIObject Win32_UserAccount -Filter "LocalAccount=True" -ComputerName $C
if ($Users.Name -contains 'Administrator') {
Write-Verbose "User 'Administrator' found"
if ($Users.Name -contains 'tempadmin') {
Write-Verbose "Delete user 'tempadmin'"
$ADSI = [ADSI]"WinNT://$C"
$ADSI.Delete('User','tempadmin')
}
}
else {
Write-Verbose "User 'Administrator' not found"
# Here you can rename the 'tempadmin' account or create a new 'Administrator'
}
}
else {
Write-Verbose "$C > Offline"
}
}
It's not complete but I'm sure you get the idea here. It's always better to query a client once and then loop through the collection of objects instead of querying multiple times to check for different objects in each query.
I hope this helps you out or gives you some ideas.
More info can be found on Boe Pox's excellent blog.
Basically I want to check and see if the computers in the text file are online. If they aren't online then write-host "$computer is down". If the $computer is online then check to see if this service exists, if it exists then write-host "$computer installed, if not then write-host "$computer not installed". The Test-connection seems to work but if the computer is online they all return write-host "$computer installed" even though I have a test machine that I know doesn't have this service running.
function Get-RunService {
$service = get-service -name ABCService
Get-Content "C:\powershell\computers.txt" |
foreach {if (-not (Test-Connection -comp $_ -quiet))
{
Write-host "$_ is down" -ForegroundColor Red
}
if ($service )
{
write-host "$_ Installed"
}
else {
Write-host "$_ Not Installed"
}
}
}
get-RunService
Have a look at this cleaned up version of your code.
function Get-RunService {
Get-Content "C:\powershell\computers.txt" |
foreach {
if (-not (Test-Connection -comp $_ -quiet)){
Write-host "$_ is down" -ForegroundColor Red
} Else {
$service = get-service -name ABCService -ComputerName $_ -ErrorAction SilentlyContinue
if ($service ){
write-host "$_ Installed"
} else {
Write-host "$_ Not Installed"
}
}
}
}
get-RunService
I tried to clean up how the brackets were working. Your check if the host was alive did not have an Else to separate the case off the server being contactable or not. Side note is that ping could fail but the host could still be alive and that all depends on your environment but be aware of the possibility. Also moved the $service line into the foreach adding the -ComputerName $_
Currently you have no margin for error with this. That function is possible to not exist and you should account for that. Best advice would be to look into -ErrorAction of Get-Service and possibly a Try/Catch block.
It's been a while, but I think this version is a bit more clear. Why check for it to be offline instead of only performing the actions if the computer is online.
function Get-RunService {
Get-Content "C:\powershell\computers.txt" |
foreach
{
if (Test-Connection -comp $_ -quiet)
{
$service = get-service -name ABCService -ComputerName $_ -ErrorAction SilentlyContinue
if ($service ) { Write-Host "$_ Installed" }
else { Write-Host "$_ Not Installed" }
}
else
{ Write-Host "$_ is offline!" -ForegroundColor Red }
}
}