How to select specific string from the output table in PowerShell - powershell

I am trying to create the script which will resolve the IP address to DNS name and then
ping output computer number:
$name = Read-Host "Please enter IP address"
$comp = Resolve-DnsName $name | select NameHost -First 1
The output is
NameHost
COMPPL01-NB0128.domain.com ```
When I try to format the output, it gives me
#{NameHost=COMPPL01-NB0128.domain.com}
So then I can't ping the result using the command test connection
Test-Connection -ComputerName $comp
As I understood, test-connection cmdl is trying to ping the whole string NameHost=COMPPL01-NB0128.domain.com
How can I select only the computer name from that output and ping it?
So far it gives me an error message:
Test-Connection : Testing connection to computer '#{NameHost=COMPPL01-NB0128.domain.com}' failed:
A non-recoverable error occurred during a database
lookup
At line:1 char:1
Test-Connection -ComputerName $comp
CategoryInfo : ResourceUnavailable: (#{NameHost=COMPPL01-NB0128.domain.com}:String) [Test-Connection], PingException
FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand

There are two options:
Resolve-DnsName 8.8.8.8 | Select-Object -ExpandProperty NameHost
You can use Expand property to get host name value alone.
(Resolve-DnsName 8.8.8.8).NameHost
Using the Dot operator to get its properties.

Related

Retrieving Computer Names That Produced an Error From Invoke-Command

I'm working on speeding the execution of a script and long story short, the core of it would look similar to this (minus Measure-Command):
$devices = Get-Content "list.txt"
Measure-Command{
try{
$Result = Invoke-Command -ComputerName $devices -ScriptBlock {
Get-LocalUser | Select-Object -Property #{N="Computer"; E={$env:COMPUTERNAME}},
Name, Enabled, PasswordChangeableDate, PasswordExpires, UserMayChangePassword,
PasswordRequired, PasswordLastSet, LastLogon,
#{n="Groups"; E={
$user = $_
Get-LocalGroup | Where-Object { $user.SID -in ($_ | Get-LocalGroupMember | Select-Object -ExpandProperty "SID") } | Select-Object -ExpandProperty "Name"
}}
} 2>> "errors.txt"
}catch{
Write-Host "Uh oh..." -ForegroundColor Red
Write-Host $Error[0]
}
}
What I'm trying to figure out is, in the case of an error on one of the devices, I want to store that device name in a separate file. In the past I was doing all of this process via a foreach loop with try/catch, which made this part very easy. I'm looking to avoid that with this solution.
Right now, I'm using 2>> "errors.txt" courtesy of this post, but this records the full error, which I don't want. Example:
[EXAMPLE DEVICE] Connecting to remote server EXAMPLE DEVICE failed with the following error message : WinRM cannot process the
request. The following error occurred while using Kerberos authentication: Cannot find the computer EXAMPLE DEVICE. Verify that
the computer exists on the network and that the name provided is spelled correctly. For more information, see the
about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (EXAMPLE DEVICE:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : NetworkPathNotFound,PSSessionStateBroken
I'd like the only record the name of the device (in this case "EXAMPLE DEVICE") in the file. Is there a way to do this?
One way to handle is to set -ErrorActions SilentlyContinue -ErrorVariable Errs.
This enables the program to flow normally without bleeding red errors all over the screen. Then you can look at the error records stored in $Errs to report on which machines had issues. In your case $Errs.TagrgetObject.
Demo might be something like
Invoke-Command -ComputerName $Computers -ScriptBlock { "Whatever..." } -ErrorAction SilentlyContinue -ErrorVariable Errs
# PostOp Check which machines had errors:
$Errs.TargetObject
This should return:
MrBogus
MrsBogus
Of course, if you want to format that more robustly you can do any arbitrary processing on the error records.

Cannot convert System Object to String Powershell

Hi I am trying to use the below powershell script
$get_AD_Server = (Get-WmiObject -Class Win32_NetworkAdapterConfiguration).DnsDomain | Out-String
$get_Nearest_DC = (Get-ADDomainController -DomainName $get_AD_Server -Discover -NextClosestSite).Name
The output of $get_AD_Server contains contoso.com, however when i pass the variable $get_AD_Server in the next variable it always errors out, any idea on what am i doing wrong?
Get-ADDomainController : The format of the specified domain name is invalid
At line:2 char:20
+ ... arest_DC = (Get-ADDomainController -DomainName $get_AD_Server.ToStrin ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-ADDomainController], ADException
+ FullyQualifiedErrorId : GetADDomainController:BeginProcessingOverride:DiscoverDC:1212,Microsoft.ActiveDirectory.Management.Commands.GetADDomainController
Automatic variable unrolling will return a collection.
DNSDomain property may not be populated. In my case it isn't. Assuming you've got that covered I think you might have better luck if you isolate the NIC configuration you care about. If you narrow the return to 1 object .DNSDomain will be a string.
In my case this looks like:
(Get-WmiObject win32_NetworkAdapterCOnfiguration -Filter "IPEnabled = 'True'").DnsDomain
If needed just work on the filter until you find something that reliably only returns the NIC you care about.
Note: I may have misread something, but I worry you'll have an issue with the next step. You may have trouble querying the AD domain when you aren't authenticated. If you do hit something like that you may consider using the -Credential parameter on Get-ADDomainController. Of course it'd be interactive at that point.
Instead of fetching the DNS domain associated with the NIC, pull the computers domain from the Win32_ComputerSystem class:
$domain = (Get-WmiObject -Class Win32_ComputerSystem).Domain
$nearestDC = (Get-ADDomainController -DomainName $domain -Discover -NextClosestSite).Name

Powershell variable not being populated

Here's the simple script:
$groups = Get-WMIObject -Class Win32_GroupUser -ComputerName $server | Select-object #{N="Group";E={($_.PartComponent -split "Name=")[1].Replace('"','')}}
$groups
However, $groups is null!
I've checked the interwebs and cannot find a solution.
I'm sure there's a simple answer...
Query is syntactically correct. Check if you are storing the correct value in the $server parameter and that your WMI service is running.
Nothing wrong with what you have here, as it pulls the data when I test this.
Note I am using my localhost, not a remote system here.
(
$groups = Get-WMIObject -Class Win32_GroupUser -ComputerName $env:COMPUTERNAME `
| Select-object #{N="Group";E={($_.PartComponent -split "Name=")[1].Replace('"','')}}
)
Group
-----
postanote
...
IUSR
...
SYSTEM
...
INTERACTIVE
Authenticated Users
...
DefaultAccount
Guest
Administrator
...
SYSTEM
...
$groups.Count
27
And fine on a remote system.
(
$groups = Get-WMIObject -Class Win32_GroupUser -ComputerName 'ws01' `
| Select-object #{N="Group";E={($_.PartComponent -split "Name=")[1].Replace('"','')}}
)
Group
-----
Administrator
Domain Admins
...
Guest
SYSTEM
...
INTERACTIVE
Authenticated Users
Domain Users
SYSTEM
$groups.Count
18
So, something environmental in your environment, is the catch 22 for you.
Run this on your localhost host and see if you can get anything back from your targets.
Test-WSMan -ComputerName ws01
wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor : Microsoft Corporation
ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0

validate IP address entered by user

I am making a script to set the IP, subnet mask, gateway and DNS server address on a localhost. I have a working script but I would like to make sure that the IP addresses entered are numeric characters and within the range 0-255 for each Octet.
Any help would be appreciated.
$IP = Read-Host -Prompt 'Please enter the Static IP Address. Format 192.168.x.x'
$MaskBits = 24 # This means subnet mask = 255.255.255.0
$Gateway = Read-Host -Prompt 'Please enter the defaut gateway IP Address. Format 192.168.x.x'
$Dns = Read-Host -Prompt 'Please enter the DNS IP Address. Format 192.168.x.x'
$IPType = "IPv4"
# Retrieve the network adapter that you want to configure
$adapter = Get-NetAdapter | ? {$_.Status -eq "up"}
# Remove any existing IP, gateway from our ipv4 adapter
If (($adapter | Get-NetIPConfiguration).IPv4Address.IPAddress) {
$adapter | Remove-NetIPAddress -AddressFamily $IPType -Confirm:$false
}
If (($adapter | Get-NetIPConfiguration).Ipv4DefaultGateway) {
$adapter | Remove-NetRoute -AddressFamily $IPType -Confirm:$false
}
# Configure the IP address and default gateway
$adapter | New-NetIPAddress `
-AddressFamily $IPType `
-IPAddress $IP `
-PrefixLength $MaskBits `
-DefaultGateway $Gateway
# Configure the DNS client server IP addresses
$adapter | Set-DnsClientServerAddress -ServerAddresses $DNS
Check this link. You can cast the given string to [ipaddress].
PS C:\Windows\system32> [ipaddress]"192.168.1.1"
Above sample does not produce an error. If you're using an invalid ip address:
PS C:\Windows\system32> [ipaddress]"260.0.0.1"
Cannot convert value "260.0.0.1" to type "System.Net.IPAddress". Error: "An
invalid IP address was specified."
At line:1 char:1
+ [ipaddress]"260.0.0.1"
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastParseTargetInvocation
You'll receive an exception that can be caught.
Here is the aproach that combines the above two answers.
For a basic validation this oneliner could help
[bool]("text" -as [ipaddress])
But user may type something like "100" and it will successfully validate to ip address 0.0.0.100.
That's might be something not what you expect.
So i like to use regex and type validation combined:
function IsValidIPv4Address ($ip) {
return ($ip -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$" -and [bool]($ip -as [ipaddress]))
}
Use regular expressions
$ipRegEx="\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
if($ip -notmatch $ipRegEx)
{
#error code
}
You can search online about regular expressions and examples for IP. Just keep in mind that powershell is built on top of .NET, therefore when searching and reading for regular expressions, focus on the .NET or C# ones. For example this.
update
As it was pointed out afterwards by comments, the regex is not correct but it was posted as an example for the regular expressions validation. An alternative could be ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)

calling a variable in select -expandproperty

I'm trying to make a report that lists a server name, vm name, and notes section from the vm but I cannot seem to get this code to run, it always gives me this error:
Select-Object : Cannot convert 'System.Object[]' to the type
'System.String' required by parameter 'ExpandProperty'. not supported.
At C:\Cooper\Jobs\Get-VmNotes - Copy.ps1:32 char:48 + get-vm -server
FA0150 | Select -expandproperty $server, Name, Notes +
~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument:
(:) [Select-Object], ParameterBindingException +
FullyQualifiedErrorId :
CannotConvertArgument,Microsoft.PowerShell.Commands.SelectObjectCommand
I can get the vmname and notes to output together but I just want to have a column that lists the vcenter server it is associated with.
Expand property is like the same as saying (Get-VM -Server FA0150).Name. It expands the property name you are selecting. You were trying to expand 3 properties (System.Object[]), but it is looking for just a string name of the property you want to expand. Use -Property instead.
get-vm -server FA0150 | Select-Object -Property Name,Notes
get-vm -server FA0150 | Select-Object -Property Name,Notes | Format-Table -Autosize
To also include the server name I made it into a script form since it can no longer be a one-liner:
[CmdletBinding()]
Param ( $Server )
$VMs = Get-VM -Server $Server
$VMs | Select-Object -Properties #(
#{ Label = 'Server';Expression = { $Server } }
'Name'
'Notes'
)
I found a solution to my problem using New-ViProperty. The only problem is now it creates four separate csv files and I want to combine them all into one based on the filename, keeping the same format, and delete the four others based on their filename. Is there an easy way to do this?