six demon bag
Wind, fire, all that kind of thing!
2019-11-13
Catching Exceptions in PowerShell Default Output Formatting
Yesterday I came across a question on StackOverflow that turned out to be rather interesting. The person asking the question used code similar to the below snippet for validating user credentials:
$user = 'user'
$pass = 'pass'
$path = 'LDAP://' + ([ADSI]'').DistinguishedName
New-Object DirectoryServices.DirectoryEntry ($path, $user, $pass)
which produces errors like this when the computer is not a member of a domain:
format-default : The following exception occurred while retrieving member "distinguishedName": "Unknown error (0x80005000)"
or like this when the credentials are invalid:
format-default : The following exception occurred while retrieving member "distinguishedName": "The user name or password is incorrect."
At first I thought, well, put the statement in a try
/catch
, maybe set $ErrorActionPreference = 'Stop'
and you're done. However, that proved to not be the case:
PS C:\> $ErrorActionPreference = 'Stop' PS C:\> try {New-Object DirectoryServices.DirectoryEntry ($path, $user, $pass)} catch {'error'} format-default : The following exception occurred while retrieving member "distinguishedName": "Unknown error (0x80005000)" + CategoryInfo : NotSpecified: (:) [format-default], ExtendedTypeSystemException + FullyQualifiedErrorId : CatchFromBaseGetMember,Microsoft.PowerShell.Commands.FormatD...
Upon closer inspection I realized that the error was not thrown because the creation of the DirectoryEntry
object failed. In fact, that object was created just fine (well, sort of):
PS C:\> $o = New-Object DirectoryServices.DirectoryEntry ($path, $user, $pass) PS C:\> $o | Get-Member TypeName: System.DirectoryServices.DirectoryEntry Name MemberType Definition ---- ---------- ---------- ConvertDNWithBinaryToString CodeMethod static string ConvertDNWithBinaryToString(psobject ... ConvertLargeIntegerToInt64 CodeMethod static long ConvertLargeIntegerToInt64(psobject deI... PS C:\> $o | Format-List * AuthenticationType : Children : Guid : ObjectSecurity : Name : ...
Only when actually trying to output the object the error appears:
PS C:\> $o format-default : The following exception occurred while retrieving member "distinguishedName": "Unknown error (0x80005000)" ...
meaning that apparently the object got passed to PowerShell's output formatting routines, and the error occurred there. Taking a quick look at the object's DefaultDisplayPropertySet
confirmed that there should be 2 properties in the default output, one of them being distinguishedName
.
PS C:\> $o.PSStandardMembers.DefaultDisplayPropertySet ReferencedPropertyNames : {distinguishedName, Path} MemberType : PropertySet Value : DefaultDisplayPropertySet {distinguishedName, Path} TypeNameOfValue : System.Management.Automation.PSPropertySet Name : DefaultDisplayPropertySet IsInstance : False
Now, in my (not so humble) opinion, the best way to deal with this situation would be to check the relevant properties of the object if they have a value:
$o = New-Object DirectoryServices.DirectoryEntry ($path, $user, $pass)
if ($path -eq 'LDAP://') {
'Computer is not member of a domain.'
} elseif ($o.DistinguishedName) {
'Invalid user credentials.'
}
But if for some reason you must retrieve the actual error message, you can do it like this:
$o = New-Object DirectoryServices.DirectoryEntry ($path, $user, $pass)
try {
$o | Out-Default
} catch {
$_.Exception.InnerException.Message
}
Posted 20:46 [permalink]