I need some help. I wrote a PowerShell script that grabs a text file as an input with a list of computer names. It then checks the Active Directory for the machine name. If the machine is found it writes it to one text file, and if the machine is not found, it writes it to a separate file. The idea being I get two lists... A "good" and a "bad" list. the problem is that it only queries the domain I am in and I need it to query all the domains in a forest and am stuck. can someone lend a hand? Here is my code as it stands:
Import-Module ActiveDirectory
$AdminCredentials = Get-Credential "Domain\AdminAccount"
$objForest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$domains = #($objForest.Domains | Select-Object Name)
$computers = gc -Path "C:\MachinesInDifferentAds.txt"
$computer_count = $Computers.Length;
$i = 0;
foreach ($computer in $computers) {
Try
{
(Get-ADComputer $computer -Credential $AdminCredentials | FT Name)
$computer | out-file -append -filepath "C:\ComputersInAd.txt"
}
Catch
{
$computer | out-file -append -filepath "C:\ComputersNotInAd.txt"
}
$computer_progress = [int][Math]::Ceiling((($i / $computer_count) * 100))
Write-Progress "Querying the AD" -PercentComplete $computer_progress -Status "Percent Complete - $computer_progress%" -Id 1;
Sleep(1);
$i++;
}
Related
I am using powershell to pull basic computer information from all computers on a LAN. These computers are not, and will never be on, a domain. I have had some success in my test runs getting the output for all of the machines to save into the c:\scripts folder on the host machine. I am, however, having to use the Invoke-command for every cmdlet so that I can put the Output destination outside of the {}.
$computers = Get-Content -Path 'c:\scripts\livePCs.txt'
foreach ($computer in $computers) {
$username = '$computer\Administrator'
$password = Get-Content 'C:\scripts\encrypted_password.txt' | ConvertTo-SecureString
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
# Local Mounted Shares Enumeration
Invoke-Command -Computername $computer -Credential $credential {Get-SmbMapping | Format-Table -AutoSize} | Out-File "c:\scripts\ComputerInformation\$computer.mountedshares.ps.txt"
# Local Shares Enumeration
Invoke-Command -Computername $computer -Credential $credential {Get-SmbShare | Format-Table -AutoSize} | Out-File "c:\scripts\ComputerInformation\$computer.localshares.ps.txt"
I would prefer not to have to do this and it becomes problematic when I have to use If/Else statements, where, because I cannot put the destination outside of braces, I get a file cannot be found error (since it is trying to save on the remote host). I tried using a share instead, in the below but now am getting an access to the file path is denied error.
Invoke-Command -Computername $computer -Credential $credential {
$computername = hostname.exe
If ($PSVersionTable.PSVersion -ge '4.0') {
If (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Get-WindowsOptionalFeature -Online -FeatureName *Hyper-V* | Format-Table -AutoSize | Out-File -Width 1024 "\\$env:computername\scripts\ComputerInformation\$computername.hyperv.admin.ps.txt"
if (Get-Command Get-VM -ErrorAction SilentlyContinue) {
Get-VM | Format-Table -AutoSize | Out-File -Width 1024 -Append "c:\scripts\ComputerInformation\$computername.hyperv.admin.ps.txt"
Get-VM | Get-VMNetworkAdapter | Format-Table -AutoSize | Out-File -Width 1024 -Append "c:\scripts\ComputerInformation\$computername.hyperv.admin.ps.txt"
} else {
Write-Host -ForegroundColor Yellow " Hyper-V feature not installed on this host"
}
} else {
Write-Host -ForegroundColor Red " You do not have required permissions to complete this task ..."
}
} else {
Write-Host -ForegroundColor Red " This commands requires at least PowerShell 4.0 ... manual inspection is required"
}
How do I run this one a remote machine using Invoke-Command but save the output to the local c:\scripts folder?
If the goal is to give yourself the option to output to multiple files on the calling system, you could use a hash table ($results) inside of your script block to store your results. Then output that table at the end of your script block. Based on those keys/values, you could output to file.
foreach ($computer in $computers) {
$Output = Invoke-Command -Computername $computer -Credential $credential {
$results = #{}
$computername = hostname.exe
If ($PSVersionTable.PSVersion -ge '4.0') {
If (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
$HyperV = Get-WindowsOptionalFeature -Online -FeatureName *Hyper-V* | Format-Table -AutoSize
if (Get-Command Get-VM -ErrorAction SilentlyContinue) {
$VMInfo = Get-VM | Format-Table -AutoSize
$VMNic = Get-VM | Get-VMNetworkAdapter | Format-Table -AutoSize
} else {
Write-Host -ForegroundColor Yellow " Hyper-V feature not installed on this host"
}
} else {
Write-Host -ForegroundColor Red " You do not have required permissions to complete this task ..."
}
} else {
Write-Host -ForegroundColor Red " This commands requires at least PowerShell 4.0 ... manual inspection is required"
}
$results.Add('HyperV',$HyperV)
$results.Add('VMInfo',$VMInfo)
$results.Add('VMNic',$VMNic)
$results
}
$Output.HyperV | Out-File -Width 1024 "c:\scripts\ComputerInformation\$computer.hyperv.txt"
$Output.VMInfo | Out-File -Width 1024 "c:\scripts\ComputerInformation\$computer.VMInfo.txt"
$Output.VMNic | Out-File -Width 1024 "c:\scripts\ComputerInformation\$computer.VMNic.txt"
}
If the goal is to simply output all data to one location, you can simply store your Invoke-Command result into a variable. Then write the variable contents to file:
$Output = Invoke-Command -Computername $computer -Scriptblock { # my code runs here }
$Output | Out-File "C:\Folder\$computer.txt"
If you are looking to capture Write-Host output in a variable, you will need to send the information stream to the success stream ( { script block } 6>&1 }
You can redirect the output
$YourScriptBlock = { your script }
$result = Invoke-Command -ScriptBlock $YourScriptBlock 4>&1 -Computer $c -Credential $c
Afterwards the contents are in $result
write-output $result
I am very new at Powershell, but I recently decided to try and recreate an old tool we sometimes use but as a Powershell script. The script takes in user input to get an IP Range then pings, gets hostname, checks if service exists and is running, and then exports it to a CSV file. I haven't done too much cleaning up of the code yet. It does what I want but when I was testing it on larger IP ranges it was taking several minutes ie. 1-254 took around 10 minutes. Any tips would be appreciated.
Add-Content -Path ".\$fullrange.csv" -Value '"Ping","IP","Hostname","Service State","Startup","Version"'
ForEach($IP in $range) {
$status = test-connection -computername ($IP) -count 1 -Quiet -ErrorAction SilentlyContinue
if ($status) {
$hostname = [System.Net.Dns]::GetHostbyAddress("$IP")."HostName"
$service = Get-WmiObject -Class Win32_Service -ComputerName $IP -ErrorAction SilentlyContinue | Where-Object Name -like "SysaidAgent"
if ($service) {
$xml = [xml](Get-Content "\\$IP\C$\Program Files\SysAid\Configuration\AgentConfigurationFile.xml")
$ver = $xml.SelectSingleNode("//AgentVersion")."#text"
}
else{
$service = "Not Found"
$ver = "N/A"
}
Add-Content -Path .\$fullrange.csv -Value "$status,$IP,$hostname,$service.state,$service.startmode,$ver"
}
else{
Add-Content -Path .\$fullrange.csv -Value "$status,$IP"
}
}
Have a bit of an issue whereby would like to figure out the best way to handle success or failures. Have a powershell query which checks the dcom port range, if it is within the specified value output to a success file, if not a failure file. The issue is, it seems to be outputting the entire serverlist.txt for a success and need to know a way to break this down so it only appends a server (either success/failure) to it, not all at once.
Here is the powershell script contents:
powershell -executionpolicy bypass .\DCOMPortRange.ps1
Where DCOMPortRange.ps1 contains
$computername = Get-Content -Path "C:\Folderpath\serverlist.txt"
$val = (Get-ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -ExpandProperty Ports
if($val -eq "50000-50500")
{
Write-Output "$computername" | out-file C:\folderpath\Success.log -append
} Else {
Write-Output "$computername" | out-file C:\folderpath\Failure.log -append
}
The issue is the error path lets say is a success it appends the entire server list.
Please advise?
This is how I would do it. This does require that you do have PSremoting enabled on the servers
$computername = Get-Content -Path "C:\Folderpath\serverlist.txt"
ForEach ($server in $computername) {
$val = Invoke-Command -Computername $server -ScriptBlock {(Get-ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -ExpandProperty Ports}
if ($val -ge 50000 -and $val -le 50500) {
Write-Output "$server" | out-file C:\folderpath\Success.log -append
}
Else {
Write-Output "$server" | out-file C:\folderpath\Failure.log -append
}
}
Edit: A change to the if statement
/Anders
$remotecomputername = #("PC1","PC2","RealServerName")
ForEach ($computer in $remotecomputername) {
Invoke-Command -Computername $computer -ScriptBlock { $val = (Get-
ItemProperty "hklm:SOFTWARE\Microsoft\Rpc\Internet") | Select-Object -
ExpandProperty Ports} }
if($val -eq "50000-50500") {
write-host $computer DCOM Port in Range
} else {
write-host $computer DCOM Port not in range
}
Hi I am running this script again multiple servers (initially posted here) & I would like to get each specific servers names to be appeared in the result. But right now, I am able to get with the heading CPU & Memory Usage & then the usage for each server one after the other. Pls let me know how to get each server name & the result.
$Output = 'C:\temp\Result.txt'
$ServerList = Get-Content 'C:\temp\ServerNames.txt'
$ScriptBLock = {
$CPUPercent = #{
Label = 'CPUUsed'
Expression = {
$SecsUsed = (New-Timespan -Start $_.StartTime).TotalSeconds
[Math]::Round($_.CPU * 10 / $SecsUsed)
}
}
$MemUsage = #{
Label ='RAM(MB)'
Expression = {
[Math]::Round(($_.WS / 1MB),2)
}
}
Get-Process | Select-Object -Property Name, CPU, $CPUPercent, $MemUsage,
Description |
Sort-Object -Property CPUUsed -Descending |
Select-Object -First 15 | Format-Table -AutoSize
}
foreach ($ServerNames in $ServerList) {
Invoke-Command -ComputerName $ServerNames {Write-Output "CPU & Memory Usage"}
| Out-File $Output -Append
Invoke-Command -ScriptBlock $ScriptBLock -ComputerName $ServerNames |
Out-File $Output -Append
I see you're running with a loop on the servers names ($ServerNames is each server for each iteration), so why don't you use:
"Working on $ServerNames.." | Out-File $Output -Append
on the first line after the "foreach" statement?
Anyway, I think you can change your script like this:
On the script block add:
Write-Output "CPU & Memory Usage"
hostname | out-file $output -Append # this will throw the server name
Once you have this on the Scriptblock, you can run it like this:
Invoke-Command -ScriptBlock $ScriptBLock -ComputerName $ServerList
($ServerList is the original servers' array, which "Invoke-Command" knows how to handle).
I have put together a script from various sources, but cannot understand why i am getting duplicated entries in my results..
eg..
I need to check the scheduled tasks on remote servers, and verify which ones didnt complete sucesfully, and then investigate those.
I have a schedulers.csv file, which has two comlumns IP, and Name.
I downloaded the script Get-ScheduledTask.ps1 from https://gallery.technet.microsoft.com/scriptcenter/Get-Scheduled-tasks-from-3a377294
Works great and does what i needed.
I then wanted to from a list retrieve the servers names, run the above script as a parameter, then get back the scheduled tasks in a csv file.
NextRunTime Author Trigger State UserId ComputerName Name LastRunTime LastTaskResult Description NumberOfMissedRuns Enabled Path
The headers for the above script give me Name and LastTaskResult, which is what I wanted to query further.
The LastTaskResult should be 0 if it completed sucesfully, otherwise i would investigate further.
The code i have so far is :
$servers = Import-Csv "C:\test\schedulers.csv"
foreach($server in $servers){
$ServerName = $server.Name
$ServerAddress = $server.IP
Write-Host $ServerName : $ServerAddress
$importfile = Get-ScheduledTask.ps1 -ComputerName $ServerName
|Export-Csv -Path c:\test\scheds.csv -NoTypeInformation
$Lines = Import-Csv "C:\test\scheds.csv"
ForEach($line in $lines){
$lines | %{
$TaskName = $_.name
$taskresult = $_.LastTaskResult
if ($_.LastTaskResult -ne "0")
{
Write-Host $line.LastTaskResult : $_.name : $_.Path
}else{
}
}
}
}
There should be 3 results that show, that have a value of 1 in LastTaskResult, but i get about 38 which is the total amount of tasks on the two servers that i am testing on.
the 3 entries are there also as well, plus all the rest..
please can anyone see where i have gone wrong.. Many Thanks
not tested because i don't have your Get-ScheduledTask.ps1, but here's what i might change
$servers = Import-Csv "C:\test\schedulers.csv"
foreach ($server in $servers) {
$ServerName = $server.Name
$ServerAddress = $server.IP
Write-Host $ServerName : $ServerAddress
$importfile = Get-ScheduledTask.ps1 -ComputerName $ServerName
$importfile | Export-Csv -Path c:\test\scheds.csv -NoTypeInformation
foreach ($line in $importfile) {
if ($line.LastTaskResult -ne '0') {
Write-Host $line.LastTaskResult : $line.Name : $line.Path
}
}
}