Validating Computer Names with PowerShell

Note:
If you are new to PowerShell Parameter Validation you may want to have a look at the official documentation first.

As you probably know, validation attributes are some of the very interesting features of PowerShell.
And, among all parameters a function or script can have, -ComputerName (or similar) is probably one of the parameters SysAdmins are using the most.

Now, how could you more efficiently validate a piece of code with -ComputerName as one of its parameters?

This depends on the usage of your function or script and the context:

  • The computer does not yet exist and you want to create it
  • The computer already exists and is supposed to be available for some distant work

Here are some possible validations methods.
Just take and adapt those you need.

Validation examples

Type validation

Usually, a basic validation looks like this:

param(
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

You might think that the [string] validation is useless given that any character combination can constitute a string.
And this is true even with forbidden characters for FQDN names and NetBIOS names.

However, the [string] validation ensures that the parameter is really a string,
and not by mistake another type of object like a date, a secure string, and so on.

It is important because the type of object will determine what you will be able to do later with it in your function or script.

Furthermore, if you use other validation script blocks from the list below, they all require a string as input.

Validating Active Directory computer names

param(
    [ValidateScript({Get-ADComputer -Identity $PSItem})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Note: You need the ActiveDirectory module.

Validating NetBIOS compatible computer names

This can be useful when:

  • You want to work with standalone computers.
  • You want to create a new virtual machine.
param(
    [ValidateLength(1, 15)]
    [ValidateScript({$PSItem -replace '\\|/|:|\*|\?|"||\||\.' -eq $PSItem})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Validating FQDN compatible computer names

This validates only the name and not the full FQDN.

param(
    [ValidateLength(1, 63)]
    [ValidatePattern('^[a-z0-9-]+$')]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Validating full FQDNs

param(
    [ValidateLength(6, 253)]
    [validatePattern('^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$')]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Validating DNS registered computers names

    param(
    [ValidateScript({Resolve-DnsName -Name $PSItem})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Validating PowerShell Remoting capable computers

Note
This is the same validation you would use for CIM remoting capable computers,
except if you force the connection to use DCOM instead.

param(
    [ValidateScript({Test-WSMan -ComputerName $PSItem})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Validating SSH Remoting capable computers

param(
    [ValidateScript({(Test-NetConnection -ComputerName $PSItem -Port 22).TcpTestSucceeded})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Validating SMB capable computers

This can be useful when you want to map a network drive.

param(
    [ValidateScript({(Test-NetConnection -ComputerName $PSItem -CommonTCPPort 'SMB').TcpTestSucceeded})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Validating SQL capable computers

In addition to validating the port availability, it also tries a connection with your current credential.

param(
    [ValidateScript({(Test-DbaConnection $PSItem).ConnectSuccess})]
    [ValidateScript({(Test-NetConnection -ComputerName $PSItem -Port 1433).TcpTestSucceeded})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Note: You need the dbatools module.

Validating a whole list of computer names

To accept a list of computer names you probably already know that you only have a little change to make: replace [string] with [string[]].
Of Course, you will have to adapt your main code accordingly to handle your computer list. But this is out of the scope of this article…

However, what about the validation itself?

Fortunately, PowerShell is “intelligent” enough.
You don’t need to bother with a ForEach-Object cmdlet inside your validation script block.
Each element of your computer name list will be validated separately without changing anything else in your validation code block.

Caveats

Multiple computer names validation

When you use [string[]], your function or script will fail when at least one computer name does not pass the validation tests.

For example, this command line will completely fail if Comp2 is invalid. Even Comp1will not be processed.

MyScript.ps1 -ComputerName 'Comp1','Comp2'

However, if you want to work with valid computer names only, while skipping invalid computer names, you can use the pipeline directly or indirectly with the ForEach-Object cmdlet.

Directly with the pipeline
  1. implement the ValueFromPipeline attribute
  2. implement a process script block
  3. in the command line, use the pipeline to execute the function or the script

For example, if we adapt the registered DNS computer names validation example of above,
the code which includes the two first steps could look like this:

param(
    [Parameter(ValueFromPipeline)]
    [ValidateScript({Resolve-DnsName -Name $PSItem})]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

process{

    #This block will be executed once for each valid computer name

    $ComputerName
}

And for the third step the command line could look like this:

'Comp1','Comp2' | MyScript.ps1

Note: More about the process script block here.

indirectly with the ForEach-Object cmdlet

Alternatively, if you don’t want to change the code of your function or script, you can just use the ForEach-Object cmdlet to run your function or script several times with one computer name at a time.

'Comp1','Comp2' | ForEach-Object -Process {MyScript.ps1 -ComputerName $PSItem}

Required modules

Depending on the audience of your function or script, you may want to give a hint when a required module for a validation script attribute is missing.

However, and unfortunately, the #Requires statement is processed after all parameters are validated.
And inside a validation script block, the #Requires statement is ignored.

But, as a workaround, you can make a check on your own and throw a terminating error.
The second example from the beginning (validating Active Directory computers) could look like:

param(
    [ValidateScript( {
        if (-not(Get-Module -Name 'ActiveDirectory' -ListAvailable)) {
            throw 'The ActiveDirectory module is missing on this computer!'
        }
        else {
            Get-ADComputer -Identity $PSItem
        }
    })]
    [ValidateNotNullOrEmpty()]
    [string]$ComputerName
)

Formerly you would have gotten this error message:

Cannot validate argument on parameter ‘ComputerName’. The term ‘Get-ADComputer’ is not recognized as the name of a cmdlet, function, script file, or operable program.

 
And now you get this error message, which leads PowerShell beginners to the solution:

Cannot validate argument on parameter ‘ComputerName’. The ActiveDirectory module is missing on this computer!

 

Combining multiple validations

You can combine multiple validations.
For example, you may want that a computer name is valid as a NetBIOS name and also as a DNS name at the same time.

Just remember that they are processed reversely compared to the reading order (starting from the variable name and going back)

In the last example above (SQL compatible computers), the effective validation order is:

  1. The value is a string object
  2. The value is not null nor empty
  3. The computer name is reachable over TCP port 1433
  4. A SQL connection with credential is attempted against the computer name

2 thoughts on “Validating Computer Names with PowerShell

  1. Another option is: [System.Uri]::CheckHostName(‘computer’)

    A valid computer name will return Dns, but an invalid computer name will return Unknown.

    Like

    1. Yes it validates a whole FQDN.
      You can use the ValidateScript attribute with your piece of code.
      For example:
      [ ValidateScript ( { if ( [System.Uri]::CheckHostName ($PSItem) -eq ‘Dns’ ) { $true } } ) ]

      Like

Leave a comment