【问题标题】:How to condense this PowerShell script?如何压缩这个 PowerShell 脚本?
【发布时间】:2017-10-09 15:54:00
【问题描述】:

如果用户在某个 AD 组中并且连接到某个网络,我正在创建一个代码来打开一个网站。这是我到目前为止所得到的:

$user = $env:username
$group1 = "examplegroup1"
$group2 = "examplegroup2"

if (Test-Connection "examplenetwork" -Quiet)
{      
$members1 = Get-ADGroupMember -Identity $group1 | Select -ExpandProperty 
SamAccountName

$members2 = Get-ADGroupMember -Identity $group2 | Select -ExpandProperty 
SamAccountName

If ($members1 -contains $user -or $members2 -contains $user) {Start-Process 
"examplewebsite"}
}

它可以正常工作,如果用户在正确的组中并且在网络上,则打开网站,但是我只是想知道是否有办法压缩代码?

必须创建 2 '$groups' 然后再重复 Get-ADGroupMember 似乎很浪费。我玩过“ForEach”,但没能成功。

关于如何浓缩这个的任何想法?最好使用 ForEach cmdlet。

【问题讨论】:

  • 我投票决定将此问题作为题外话结束,因为工作代码是题外话,用于审查/建议对工作代码进行更改的 SE 站点是 codereview.stackexchange.com
  • 您还假设最终用户的计算机将安装 AD 模块。如果您将其设计为登录脚本,您将遇到这个问题。

标签: powershell


【解决方案1】:

虽然我的另一个答案是“不要那样做”,但如果您确实想要您的代码,请精简:

$groups = 'group1', 'group2'

if ((Test-Connection -ComputerName "examplenetwork" -Quiet) -and 
    ($env:USERNAME -in ($groups | Get-ADGroupMember -Recursive).SamAccountName))
{
    Start-Process "www.example.com"
}

你真的不需要foreach。

【讨论】:

  • 谢谢,TessellatingHeckler。这就是我一直在寻找的。我对 Powershell 很陌生(您可能会说),管道是我需要增加知识的一件事!至于广告问题......我明天必须解决这个问题!再次感谢。
【解决方案2】:

我可能会倒着做:

$user = $env:username
$groups = "examplegroup1", "examplegroup1"

$CheckMembership = Get-ADUser -Identity $user -Property MemberOf | Select-Object -ExpandProperty MemberOf | Where-Object { $_ -in $groups }

if ($CheckMembership) {
   Start-Process "http://www.example.com"
}

您希望确保您的组列表是可分辨名称列表,但除此之外,这会将 AD 查询的数量减少到 1。

【讨论】:

    【解决方案3】:
    If (("examplegroup1", "examplegroup2" | % {Get-ADGroupMember -Identity $_} | Select -ExpandProperty SamAccountName) -Contains $env:username) {Start-Process "examplewebsite"} 
    

    【讨论】:

    • 如果用户同时包含在两个组中,这可能会启动该过程两次。
    • @TToni: 不,-unique 参数应该防止这种情况发生
    • 事实上,-unique 甚至不是必需的(我已将其从答案中删除)因为If (<group member collection> -contains $env:username) {<ScripBlock>} 将永远不会运行给定的<scriptblock> 一次,即使<group member collection> 包含重复成员。
    • 不必要的 % {} - 您可以将组名直接通过管道传递到 Get-ADGroupMember。
    【解决方案4】:

    任何依赖 Get-AD___ 的东西都需要 RSAT 工具来获取 ActiveDirectory 模块,这对于作为 @Rohin Sidharth cmets 的最终用户工作站来说是不太可能的假设。

    @James C. 目前接受的答案不会处理递归组成员身份(需要 -Recursive 参数),但还涉及列出两个组的所有成员 - 想象一下,如果每个组有十亿个成员 -并且有数组加法的不良习惯。

    @Bacon Bits 回答获取用户的组成员身份,这对于“获取更少的数据”更好,但仍然不会处理递归组成员身份,并且仍然依赖于 ActiveDirectory 模块。

    为避免 RSAT,可以使用 ADSI 之类的东西 - 它由 System.DirectoryServices.AccountManagement 包装。 Richard Siddaway 讨论了here

    这有一个很好的方法来列出用户的组成员,这似乎被打破了 - 从 Terry Tsay 的 C# 回答类似问题here 中捏出来,我将他的代码移植到这个,但我专注于当前用户和默认包含的通讯组:

    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    
    Function IsUserInGroup([string] $groupName)
    {
        # Remove DOMAIN\ from the start of the groupName.
        $groupName = $groupName -replace '^.*\\'
    
    
        # Get an AD context for the current user's domain
        $context = New-Object -TypeName System.DirectoryServices.AccountManagement.PrincipalContext -ArgumentList 'Domain', $ENV:USERDOMAIN
    
    
        # Find the current user account in AD, and refresh the security and distribution groups 
        $user = [System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($context, 'SAMAccountName', $env:USERNAME)
        $userEntry = [System.DirectoryServices.DirectoryEntry] $user.GetUnderlyingObject()
        $userEntry.RefreshCache(@('tokenGroupsGlobalAndUniversal'))
    
    
        # Get all the security and distribution groups the user belongs to, including nested memberships
        $usersGroupSIDs = foreach ($sid in $userEntry.Properties.tokenGroupsGlobalAndUniversal.Value)
        {
            New-Object System.Security.Principal.SecurityIdentifier -ArgumentList $sid, 0   
        }
    
    
        # Get the AD details for the group to test, and test membership
        $group = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, 'SamAccountName', $groupName)
    
        $usersGroupSIDs.Contains($group.Sid)
    }
    

    例如

    PS C:\> IsUserInGroup 'parent-nested-group-here'
    True
    

    这不是精简或简单的,但它应该以更少的 AD 连接开销来处理更多的条件,尤其是当组的成员数量增加时,并且对额外模块的需求更少,只需使用 .Net 框架。

    然后你可以修改它来做

    $group2 = [System.DirectoryServices.AccountManagement.GroupPrincipal]::FindByIdentity($context, 'SamAccountName', $group2Name)
    
    $usersGroupSIDs.Contains($group.Sid) -or $usersGroupSIDs.Contains($group2.Sid)
    

    【讨论】:

      【解决方案5】:

      您可以添加一个foreach 循环,但这样做会使已经非常小而简单的脚本变得复杂。

      我最想做的就是将两个组的成员加在一起......

      $user = $env:username
      $group1 = "examplegroup1"
      $group2 = "examplegroup2"
      
      if (Test-Connection "examplenetwork" -Quiet)
      {      
          $members = Get-ADGroupMember -Identity $group1 | Select -ExpandProperty SamAccountName
      
          $members += Get-ADGroupMember -Identity $group2 | Select -ExpandPropertySamAccountName
      
          If ($members -contains $user) {Start-Process "http://www.example.com"}
      }
      

      【讨论】:

      • 这不能解决“必须重复 Get-ADGroupMember”部分,但它确实改变了它,因此如果 Group1 有只有一个成员。
      猜你喜欢
      • 1970-01-01
      • 2019-07-30
      • 1970-01-01
      • 2019-12-17
      • 2019-04-23
      • 1970-01-01
      • 1970-01-01
      • 2018-05-19
      • 1970-01-01
      相关资源
      最近更新 更多