Powershell:在自定义属性中使用带有表达式的 if/else 语句

问题描述 投票:0回答:1

这与使用 powershell 检索 AD 中每个用户的管理员名称

有类似的前提

问题:在为自定义属性定义表达式值时,我们是否可以包含 try/catch 或 if 条件来处理错误和/或捕获错误详细信息以用于记录目的,而不弄乱表达式值本身?

详细信息:在下面的代码中,我们将管理器属性传递回

Get-ADUser
以检索管理器的sAMAccountName:

Start-Transcript -Path 'c:\temp\log.txt' -Force
## List of AD user objects
$OU = "OU=Users,DC=company,DC=com"
$Users = Get-ADUser -LDAPFilter '(&(objectCategory=Person)(sAMAccountName=*))' -SearchBase $OU -Properties *

## this array will make sense later...
$missingMgrs = [System.Collections.ArrayList]@()

## Defined properties through splatting:
$ChosenProperties = @{
  "Property" = @(
    # built-in attributes:
    'Name', 'sAMAccountName', 'EmailAddress'
    # custom attributes below:
    @{
      Label = "ManagerSAmAccountName"
      Expression = { 
        Get-ADUser $_.Manager -Properties DisplayName |Select -Expand sAMAccountName  
      }      
    }
  )
}

$Users | Select-Object @ChosenProperties
Stop-Transcript

文字摘录可能如下所示:

Name              sAMAccountName EmailAddress              ManagerSAmAccountName
----              -------------- ------------              ---------------------
Person One        pone           [email protected]          managera
Person Two        ptwo           [email protected]          managerb
>> TerminatingError(Get-ADUser): "Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again."
Person Three      pthree         [email protected]        
>> TerminatingError(Get-ADUser): "Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again."
Person Four       pfour          [email protected]         
Person Five       pfive          [email protected]         managera

由于人员 3 和人员 4 没有经理,因此自定义表达式针对空经理值调用

Get-ADUser

我想我可以用 if 语句替换表达式,以便仅在经理存在时调用

Get-ADUser
,并进行增值,以记录哪个用户遇到此问题:

      Expression = {   
          if ($($_.Manager.Length) -gt 0) {
          Get-ADUser $_.Manager -Properties DisplayName |Select -Expand sAMAccountName 
          } else {
              $missingMgrs.Add("$($_.Name) is missing a manager.")
          }
        }  

最后,就在停止转录之前:

Write-Output $missingMgrs

但是,这会产生如下结果:

Name              sAMAccountName EmailAddress              ManagerSAmAccountName
----              -------------- ------------              ---------------------
Person One        pone           [email protected]          managera
Person Two        ptwo           [email protected]          managerb
>> TerminatingError(Get-ADUser): "Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again."
Person Three      pthree         [email protected]        0
>> TerminatingError(Get-ADUser): "Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again."
Person Four       pfour          [email protected]         1
Person Five       pfive          [email protected]         managera
[...]
Person Three is missing a manager.
Person Four is missing a manager.

尽管 if/else 确实成功记录了无管理员用户,但它并没有阻止

Get-ADUser
行在这些条目上运行。此外,
ManagerSAmAccountName
的表达式现在计算为递增整数,而不是 $null。

回到最初的问题:有没有办法使用 if/else 编写自定义属性,以便仅在满足 if 条件时才计算表达式的值?

谢谢!

powershell active-directory
1个回答
0
投票

关于:

此外,

ManagerSAmAccountName
的表达式现在计算为递增整数,而不是
$null

这是因为

.Add(..)
中的
ArrayList
输出一个整数,表示添加项目的索引。要解决此问题,请将其更改为
List<T>
(请参阅代码)。


回到主要问题,我没有解释为什么您在成绩单中看到异常,特别是因为在表达式块的上下文中完全忽略终止错误:

'' | Select-Object @{ N = 'Test'; E = { throw 'hi' } }

# Test
# ----
# 

我能为你提供的是不会抛出任何错误的代码,我还添加了缓存机制,这样你就不会查询已经查询过的管理器,主要是为了提高效率。

Start-Transcript -Path 'c:\temp\log.txt' -Force

$getADUserSplat = @{
    LDAPFilter = '(sAMAccountName=*)'
    SearchBase = 'OU=Users,DC=company,DC=com'
    Properties = 'EmailAddress', 'Manager'
}

## this array will make sense later...
$missingMgrs = [System.Collections.Generic.List[string]]::new()
$managerCache = @{}

Get-ADUser @getADUserSplat | ForEach-Object {
    # if `.Manager` is populated and has not yet been added to the cache
    if ($_.Manager -and -not $managerCache.ContainsKey($_.Manager)) {
        $managerCache[$_.Manager] = try {
            ($_.Manager | Get-ADUser).SamAccountName
        }
        catch {
            # `catch` block is left empty here in case the manager's distinguishedName
            # points to a deleted object.
            # can also include here adding to `$missingMgrs` if needed, see below:
            # $missingMgrs.Add("$($_.Exception.Message): $($_.TargetObject)")
        }
    }
    else {
        $missingMgrs.Add("$($_.Name) is missing a manager.")
    }

    [pscustomobject]@{
        Name                  = $_.Name
        sAMAccountName        = $_.sAMAccountName
        EmailAddress          = $_.EmailAddress
        # the `[string]` cast here avoids getting an exception if `.Manager` was null
        ManagerSAmAccountName = $managerCache[[string] $_.Manager]
    }
}

Stop-Transcript
© www.soinside.com 2019 - 2024. All rights reserved.