2

I have a PowerShell script which will install a TCP/IP printer onto multiple Computers based on user input. The Script worked fine but we wanted to add in a safeguard so the user could not accidental install the printer onto an Asset at another site on a different subnet.

I added the following function

### Function to compare subnet of Printer and Asset
Function CheckSubnet {
    param ($PrinterIP, $ComputerName, $PrinterCaption)
    $Printer = Test-Connection -ComputerName $PrinterIP -Count 1
    $PrintIP = $Printer.IPV4Address.IPAddressToString
    $IPSplit = $PrintIP.Split(".")
    $PrinterSubnet = ($IPSPlit[0]+"."+$IPSplit[1]+"."+$IPSplit[2])
    $getip = Test-Connection -ComputerName $ComputerName -Count 1 
    $IPAddress = $getip.IPV4Address.IPAddressToString
    $AssetIP = $IPAddress.Split(".")
    $AssetSubnet = ($AssetIP[0]+"."+$AssetIP[1]+"."+$AssetIP[2])
    If ($PrinterSubnet -ne $AssetSubnet){
        Write-Host $ComputerName 'is not on the same subnet as ' $PrinterCaption
        $UserInput = Read-Host 'do wish to install anyway?  Y/N'

        If ($UserInput -eq "Y") {
        } Else {
            Continue
        }
    } Else {
    }
}

Now when I run the script i get the following error return

You cannot call a method on a null-valued expression.
At C:\Users\sitblsadm\Desktop\Untitled1.ps1:28 char:1
+ $IPSplit = $PrintIP.Split(".")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

Cannot index into a null array.
At C:\Users\sitblsadm\Desktop\Untitled1.ps1:29 char:1
+ $PrinterSubnet = ($IPSPlit[0]+"."+$IPSplit[1]+"."+$IPSplit[2])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

I understand the null array due to $IPSplit not being given a value, But my understanding of "You cannot call a method on a null-valued expression" is that nothing has been assigned to it but in this instance I am trying to assign it a value.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328

2 Answers2

2

If Test-Connection returns timeouts, $Printer is null. If there is a name resolution failure (no PTR record for the printer on the DNS server, and the printer does not respond to WINS), IPV4Address is empty, therefore you get a null string in $PrintIP. You can fallback to use Destination field as the IP address, or grab plain $PrinterIP, since in this case $PrinterIP will contain an IP address.

if ($PrintIP -eq $null) { continue } # can't add unresponsive printer
if ([String]::IsNullOrEmpty($PrintIP.IPV4Address)) {
    $IPSplit = $PrinterIP.Split(".")
} else {
    $IPSplit = $PrintIP.Split(".")
}

You need to learn how to check against nulls and where. Not every cmdlet throws errors and stops the script, they can return null and continue, and then you get null dereferencing exception out of the blue.

Vesper
  • 18,599
  • 6
  • 39
  • 61
2

If Test-Connection -ComputerName $PrinterIP -Count 1 fails, $Printer and $PrintIP will have a value of $null. You need some more error handling, either use a try-catch-finally block, or check the $? automatic variable and throw an error:

$Printer = Test-Connection -ComputerName $PrinterIP -Count 1
if(-not $?){
    throw "Printer unavailable"
}

Explanation: $? Contains the execution status of the last operation. It contains TRUE if the last operation succeeded and FALSE if it failed.

Community
  • 1
  • 1
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • With the use of your Suggestion the script now throws an error if the printer is unreachable. I made a Change to the script as that did not seem to be the cause of the original error, now the script takes the users input for the printers IP and uses it directly for `$IPSplit` – Ben_Schnitzerling Jul 13 '15 at 01:23