$topDC1="10.254.90.17"
$topDC2="10.225.224.17"
$topDC3="10.110.33.32"
$topDC4="10.88.100.10"
$DomainName="office.adroot.company.net"
TRY{
$hostname = [System.Net.DNS]::GetHostByName($topDC1).HostName.toupper()
$ipaddress = [System.Net.Dns]::GetHostAddresses($DomainName) | select IPAddressToString -ExpandProperty IPAddressToString
# I want the below to loop foreach ip in the object, ns it against all 4 topDC's, then output each result :(
$NS1 = nslookup $ipaddress[0] $topDC1
Write-host $NS1
}
Catch{
write-host "error"
}
Here is my dirty code so far (just to keep it simple)
I am trying to automate this:
NSLOOKUP office.adroot.company.net
put the results into an object
for each ip in results, do an NSLOOKUP against our top level DC's.
find which DC's haven't been cleaned up after decommission (still in dns)
$DCList="10.254.90.17","10.225.224.17","10.110.33.32","10.88.100.10"
$DomainName="office.adroot.blorg.net","pcd.blorg.ca","blorg.ca","percom.adroot.blorg.net", "blorg.blorg.net","ibg.blorg.net","sacmcm.adroot.blorg.net","sysdev.adroot.blorg.net","adroot.blorg.net"
TRY{
foreach ($DomainNameItem in $DomainName){
Write-Host ""
Write-Host ""
Write-Host "Looking UP result"$DomainNameItem -foreground yellow
Write-Host ""
$hostname = [System.Net.DNS]::GetHostByName($DCListItem).HostName.toupper()
$ipaddress = [System.Net.Dns]::GetHostAddresses($DomainNameItem).IPAddressToString
foreach ($ip in $ipaddress){
Write-Host ""
Write-Host "Looking UP result"$ip -foreground green
foreach ($topdns in $DCList){
$RESULTS = nslookup $ip $topdns
Write-host $RESULTS
}
}
}
}
Catch{
write-host "error"
}
Write-Host ""
Write-Host ""
pause
Got it! This will save me tonnes of work determining if a DNS cleanup is necessary. Thanks guys, I'm learning just how great Powershell can be :)
Try this:
$topDomainControllers = #("10.254.90.17", "10.225.224.17", "10.110.33.32", "10.88.100.10")
$DomainName="office.adroot.company.net"
try {
$hostname = [System.Net.Dns]::GetHostByName($topDC1).HostName.ToUpper()
$ipAddresses = [System.Net.Dns]::GetHostAddresses($DomainName) |
select -ExpandProperty IPAddressToString
foreach ($ipAddress in $ipAddresses) {
$nslookupResult = nslookup $ipAddress
$foundIp = $nslookupResult[1] -match "^\D*(\d+\.\d+\.\d+\.\d+)$"
if ($foundIp -eq $false) {
continue
}
$domainController = $Matches[1]
if ($topDomainControllers.Contains($domainController)) {
Write-Output -Verbose "Found domain controller match for $domainController"
break
} else {
Write-Output -Verbose "No match found for domain controller $domainController"
}
}
} catch {
Write-Output "An error has occured: $_"
}
Related
I've got this script, which loops through a foreach loop for each computer, and for each computer it loops through each NIC. Currently the Catch block is not running. What I want to do is catch the error (usually because get-wmi is not able to connect to a machine), do something (add some information to a PSCustomObject), but then continue to the next iteration. How do I catch an error but also continue the foreach loop?
param (
[Alias('Hostname')]
[string[]]$ComputerName = #('pc1','pc2'),
$OldDNSIP = '7.7.7.7',
$NewDNSIP = #('9.9.9.9','8.8.8.8')
)
$FailedArray = #()
$DHCPArray = #()
Foreach ($Computer in $ComputerName){
$NICList = Get-WmiObject Win32_NetworkAdapterConfiguration -computername $Computer | where{$_.IPEnabled -eq "TRUE"}
Foreach($NIC in $NICList){
If($NIC.DHCPEnabled -eq $false){
Try{
$DNSIPs = $NIC.DNSServerSearchOrder
if($DNSIPs -contains $OldDNSIP){
$NewDNS = $DNSIPs | foreach {$_ -replace $OldDNSIP,$NewDNSIP[0]}
$null = $NIC.SetDNSServerSearchOrder($NewDNS)
}
else{
write-host " - Old DNS server IP not found... ignoring"
}
}
Catch{
write-host " - Something went wrong... logging to a CSV for review later" -ForegroundColor Red
$FailedArray += [PSCustomObject]#{
'Computer' = $Nic.pscomputername
'NIC_ID' = $nic.index
'NIC_Descrption' = $nic.description}
}
}
ElseIf($NIC.DHCPEnabled -eq $true){
write-host " - DHCP is enabled. Adding this IP, Hostname, Nic Index and DHCP Server to a CSV for reviewing."
#add pscomputer, nic id, refernece and dhcp server to DHCPNICArray
$DHCPArray += [PSCustomObject]#{
'Computer' = $Nic.pscomputername
'NIC_ID' = $nic.index
'NIC_Descrption' = $nic.description
'DHCPEnabled' =$nic.dhcpenabled
'DHCPServer' = $nic.dhcpserver}
}
}
}
$DHCPArray | export-csv c:\temp\dhcp.csv -NoTypeInformation
$FailedArray | export-csv c:\temp\failed.csv -NoTypeInformation
If the WMI errors are due to a connection fail, they will occur before any of the nics are processed. If you want to catch them, and then continue with the next computer, you have to move the try-catch up to the level of that loop. If you also want to catch nic-specific errors, you need a 2nd try-catch at that level.
Also, consider using -ErrorAction Stop parameter, or specify $ErrorActionPreference = 'Stop', to make sure all errors are terminating (that means, jump right to the catch block).
Here's an example, with comments for explanation:
$ErrorActionPreference = 'Stop'
foreach ($Computer in $ComputerName) {
# add a try-catch per computer,
# to catch WMI errors
# and then continue with the next computer afterwards
try {
# if errors occur here,
# execution will jump right to the catch block the bottom
$NICList = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $Computer -ErrorAction Stop | where {
$_.IPEnabled -eq "TRUE"
}
foreach ($NIC in $NICList) {
# add a try-catch per NIC,
# to catch errors with this specific NIC and then
# continue with the next nic
try {
if ($NIC.DHCPEnabled -eq $false){
$DNSIPs = $NIC.DNSServerSearchOrder
if ($DNSIPs -contains $OldDNSIP) {
$NewDNS = $DNSIPs | foreach {$_ -replace $OldDNSIP,$NewDNSIP[0]}
$null = $NIC.SetDNSServerSearchOrder($NewDNS)
}
else {
write-host " - Old DNS server IP not found... ignoring"
}
}
elseif ($NIC.DHCPEnabled -eq $true){
write-host " - DHCP is enabled. Adding this IP, Hostname, Nic Index and DHCP Server to a CSV for reviewing."
$DHCPArray += [PSCustomObject]#{
'Computer' = $Nic.pscomputername
'NIC_ID' = $nic.index
'NIC_Descrption' = $nic.description
'DHCPEnabled' =$nic.dhcpenabled
'DHCPServer' = $nic.dhcpserver
}
}
}
catch {
write-host " - Configuring a NIC went wrong... logging to a CSV for review later" -ForegroundColor Red
# add nic-specific entry
$FailedArray += [PSCustomObject]#{
'Computer' = $Nic.pscomputername
'NIC_ID' = $nic.index
'NIC_Descrption' = $nic.description
}
}
# continue with next nic...
} # foreach nic
}
catch {
write-host " - Something else went wrong... logging to a CSV for review later" -ForegroundColor Red
# add entry for current computer
# (we don't know about nics, because wmi failed)
$FailedArray += [PSCustomObject]#{
'Computer' = $Computer
}
}
# continue with next computer...
} # foreach computer
Can anyone figure out a clever way to grab the Hostname of a VM while it's still Off using PowerShell?
I only know how to grab the VM's Hostname while the VM is still On.
PS: I want the hostname/DNSName of the VM (not to be confused with the VM Name); which aren't the same thing.
You could try
get-vm |select-object -ExpandProperty network* |select-object -ExpandProperty ipaddresses |Resolve-DnsName
to grab the VM's IP address and do a reverse DNS lookup on it.
Bit late to the show here, but I took Greyula-Reyula's quite efficient answer and turned it into a function that gives more feedback on why you may be getting no output from it. I'm relatively new to this level of scripting, so I'm sure there's a more efficient way to do this, but I'm a fan of "verbosity" and try to make my scripts as easy-to-follow for myself as possible in case I want to mess with them again later. :)
Function Get-HVComputerName
{
[CmdletBinding()]
param(
[Alias("ServerName")][Parameter()]
$HVHostName = $env:COMPUTERNAME,
[Alias("ComputerName")][Parameter()]
[string[]]$VMName
)
#VMWare.VimAutomation.Core also has a "Get-VM" cmdlet,
#so unload that module if it's present first
If (Get-Module -Name VMware*) { Remove-Module -Name VMware* -Verbose:$false }
If (!(Get-Module -Name Hyper-V)) { Import-Module -Name Hyper-V -Verbose:$false }
$VMs = Get-VM -ComputerName $HVHostName -Name "*$VMName*"
If ($VMs)
{
$DNSNameArr = #()
If ($VMs.Count -gt 1)
{
Write-Host "`nFound the following VMs on Hyper-V server $HVHostName with name like `"`*$VMName`*`":" -ForegroundColor Green
$VMs.Name | Out-Default
Write-Host ""
}
ForEach ($VM in $VMs)
{
$Name = $VM.Name
If ($VerbosePreference -eq "Continue")
{
Write-Host ""
}
Write-Verbose "VM: $Name found on server $HVHostName"
If ($VM.State -ne "Running")
{
Write-Verbose "VM: $Name is not in a 'running' state. No IP address will be present.`n"
Continue
}
$VMNetAdapters = $VM | Select-Object -ExpandProperty NetworkAdapters
If ($VMNetAdapters)
{
Write-Verbose "VM $Name - Found the following network adapter(s)"
If ($VerbosePreference -eq "Continue")
{
$VMNetAdapters | Out-Default
}
ForEach ($NetAdapter in $VMNetAdapters)
{
$AdapterName = $NetAdapter.Name
$IPAddresses = $NetAdapter | Select-Object -ExpandProperty IPAddresses
If ($IPAddresses)
{
Write-Verbose "VM: $Name - Adapter: `"$AdapterName`" - Found the following IP address(es) on network adapter"
If ($VerbosePreference -eq "Continue")
{
$IPAddresses | Out-Default
}
ForEach ($IP in $IPAddresses)
{
$DNSName = $IP | Resolve-DnsName -Verbose:$false -ErrorAction SilentlyContinue
If ($DNSName)
{
$DNSFound = $true
$VMDNS = [PSCustomObject]#{
VMName = $Name
IP = $IP
DNSName = $DNSName.NameHost
}
$DNSNameArr += $VMDNS
}
Else
{
Write-Warning "VM: $Name - Adapter: `"$AdapterName`" - IP: $IP - No DNS name found"
Continue
}
}
If (!($DNSFound))
{
Write-Warning "VM: $Name - No DNS entries found for any associated IP addresses"
}
Else
{
$DNSFound = $false
}
}
Else
{
Write-Warning "VM: $Name - Adapter: `"$AdapterName`" - No IP address assigned to adapter"
Continue
}
}
}
Else
{
Write-Warning "VM: $Name - No Network adapters found"
Continue
}
}
If ($DNSNameArr)
{
If ($VerbosePreference -eq "Continue")
{
Write-Host ""
}
Return $DNSNameArr
}
Else
{
Write-Warning "No DNS names found for VM(s) with name like $VMName on server $HVHostName"
}
}
Else
{
Write-Warning "No VM found on server $HVHostName with name like $VMName"
}
} #End function Get-HVComputerName
I'm working on a little script to gather some wisdom and options in one script. For later and for myself. It's a simple one but with lot of informations and "reusability".
I'm now trying to achive a jump in an "running" process of a list. All I could think of till now is to achive this via regex. But I can barley use regex properly.
#Custom Ping to identify the scenario
function Custom-Ping {
Param(
[string]$Address
)
$ping = ping $Address /w 1 /n 1
if (![string]::IsNullOrEmpty($ping -Like "*(100% loss)*")) {
$result = "Error"
} elseif(![string]::IsNullOrEmpty($ping -Like "*expired*")) {
$result = "Warning"
} else {
$result = "succeded"
}
return $result
}
$ErrorActionPreference = "SilentlyContinue"
$tstart = Get-Date
$counter = 0
$unreachable = 0
$IPlist = foreach ($Network in 1..29) {
foreach ($Range in 1..254) {
"10.10.$Network.$Range"
}
}
foreach ($IP in $IPlist) {
$counter ++
try {
if ($unreachable -lt 6) {
#SwitchCase
$case = Custom-Ping $IP
switch ($case) {
succeded {
Write-Host "Response from: $IP" -ForegroundColor Green
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Error {
Write-Host "No Response from: $IP" -ForegroundColor Red
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Warning {
Write-Host "Time Expired on: $IP" -ForegroundColor Yellow
#$IP | Export-CSV -path D:\somepath.csv -Append
$unreachable ++
}
default {
Write-Warning "An Error Occured while processing"
}
}
} else {
#Hop to the next range as this range isnt accesibble
#$IPswap = $IP
#newIP = $Ipswap "$Network from 2 to 3"
#$IP=$newIP
$unreachable = 0
Write-Host "The Network xxxx cant be reached"
}
} catch {
Write-Warning "Other Error"
}
}
$tend = Get-Date
Write-Host "$counter Completed Ping requests"
New-TimeSpan -Start $tstart -End $tend | select Minutes, Seconds
This is the script so far... I didn't find a way till now to achive this jump of the "network".
For Example it got 5 unreachable in 10.10.2.0 network and then sets to 10.10.3.0 network and starts there again with the process.
I was wondering if this is even possible in this scenario.
Use nested loops and labels instead:
:Network # Now we can jump into the next iteration of this loop from an inner loop
foreach ($Network in 0..29)
{
:Host
foreach($Node in 0..254){
$IP = "10.10.$Network.$Node"
#Counter for "Statistic"
$counter ++
try
{
#Check error sum for Range Hop
if($unreachable -lt 6)
{
#SwitchCase
$case = Custom-Ping $IP
switch ($case)
{
succeded
{
Write-Host "Response from: $IP" -ForegroundColor Green
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Error
{
Write-Host "No Response from: $IP" -ForegroundColor Red
#$IP | Export-Csv -Path D:\somepath.csv -Append
}
Warning
{
Write-Host "Time Expired on: $IP" -ForegroundColor Yellow
#$IP | Export-CSV -path D:\somepath.csv -Append
$unreachable ++
}
default
{
Write-Warning "An Error Occured while processing"
}
}
}
else
{
$unreachable = 0
Write-Host "The Network 10.10.$Network.0/24 cant be reached, jumping to 10.10.$($Network + 1).0/24"
# jump forward to the next iteration of the outer "Network" loop
continue Network
}
}
catch
{
Write-Warning "Other Error"
}
}
}
Below function I want to pass multiple value in array. When I'm passing more than one value I am getting an error.
function CheckProcess([String[]]$sEnterComputerNameHere, [String[]]$sEnterProccessNameHere) {
#Write-Host " $sEnterComputerNameHere hello"
#($sEnterComputerNameHere) | ForEach-Object {
# Calling Aarray
#($sEnterProccessNameHere) | ForEach-Object {
if (Get-Process -ComputerName $sEnterComputerNameHere | where {$_.ProcessName -eq $sEnterProccessNameHere}) {
Write-Output "$_ is running"
} else {
Write-Output "$_ is not running"
}
}
}
}
$script:sEnterProccessNameHere = #("VPNUI") # Pass the process agreement here
$script:sEnterComputerNameHere = #("hostname") # Pass the process agreement here
CheckProcess $sEnterComputerNameHere $sEnterProccessNameHere
Give it a try with this one:
Function CheckProcess([String[]]$sEnterComputerNameHere,[String[]]$sEnterProccessNameHere)
{ #Write-host " $sEnterComputerNameHere"
#($sEnterComputerNameHere) | Foreach-Object {
$computer = $_
Write-Host $computer
#($sEnterProccessNameHere) | Foreach-Object {
$process = $_
Write-Host $process
try{
$x = get-process -computername $computer #Save all processes in a variable
If ($x.ProcessName -contains $process) #use contains instead of equals
{
Write-Output "$process is running"
}
else
{
Write-Output "$process is not running"
}
}
catch
{
Write-Host "Computer $computer not found" -ForegroundColor Yellow
}
}
}
}
$script:sEnterProccessNameHere = #("VPNUI","Notepad++","SMSS")
$script:sEnterComputerNameHere = #("remotecomputer1","remotecomputer2")
CheckProcess -sEnterComputerNameHere $sEnterComputerNameHere -sEnterProccessNameHere $sEnterProccessNameHere
In general, it would be great if you write the error you get in your question. That helps others to help you.
If I work with arrays and | Foreach, I always write the $_in a new variable. That helps if I have another | Foreach (like you had) to know for sure, with which object I'm working with..
EDIT: I changed the script, so it uses "-contains" instead of "-eq" and I added a try/catch block, so if the other computer is not found, it gives you a message.. It works on my network
EDIT2: Do you have access to the other computers? If you run get-process -computername "name of remote computer" do you get the processes?
I have script:
$servers = "server01", "s02", "s03"
foreach ($server in $servers) {
$server = (New-Object System.Net.NetworkInformation.Ping).send($servers)
if ($server.Status -eq "Success") {
Write-Host "$server is OK"
}
}
Error message:
An exception occured during a Ping request.
I need to ping each server in $servers array and display status. I think, that Foreach statement is not properly used, but I'm unable to find out where is the problem. Thank you for your advice
You should not be modifying the value of $server within the foreach loop. Declare a new variable (e.g. $result). Also, Ping.Send takes the individual server name, not an array of server names as an argument. The following code should work.
Finally, you will need to trap the PingException that will be thrown if the host is unreachable, or your script will print out a big red error along with the expected results.
$servers = "server1", "server2"
foreach ($server in $servers) {
& {
trap [System.Net.NetworkInformation.PingException] { continue; }
$result = (New-Object System.Net.NetworkInformation.Ping).send($server)
if ($result.Status -eq "Success") {
Write-Host "$server is OK"
}
else {
Write-Host "$server is NOT OK"
}
}
}