我试图针对AD运行查询以向我提供用户列表。由于我们的组织添加了标签" LastName,FirstName"在计算机对象的描述字段中,我还想列出每个用户分配的机器。这就是我到目前为止所做的:
$ADGroup = "SomeADGroup"
$UserList = Get-ADGroupMember -Identity $ADGroup -Recursive `
| Select SamAccountName `
| foreach-object {(Get-ADUser -Identity $_.SamAccountName `
| Select @{n='AssignedUser';e={$_.Surname + ", " + $_.GivenName}}).AssignedUser}
$Results = New-Object System.Collections.Generic.List[System.Object]
foreach ($User in $UserList)
{
$MachineList = @(((Get-ADComputer -Filter "Description -like `"*$User*`"" | Select Name).Name) -join $_ + ",").ToUpper()
foreach ($Machine in $MachineList)
{
$Results +=
@{
'User' = $User
'Machine' = $Machine
}
}
}
$Results | ForEach-Object { [pscustomobject] $_ } | Format-Table
结果是这样的:
User Machine
---- -------
White, Scott W107175
Jones, Henry W107195
Flinstone, Fred L109531,W108812
由于可以为每个用户分配多台计算机,因此我试图想出一种方法来动态添加"列"到数组,以便每个机器名称元素驻留在一列中。这最终可以更轻松地导出到CSV。我正在寻找类似于此的输出:
User Machine Machine2
---- ------- -------
White, Scott W107175
Jones, Henry W107195
Flinstone, Fred L109531 W108812
答案 0 :(得分:3)
好的,您要为现有对象添加未知数量的属性。使用Add-Member
cmdlet并不难。接下来,您只需要构建一个循环,以便添加这些属性很容易理解,我们可以使用For
循环来完成。最后,您需要确保数组中的第一条记录具有所有潜在属性。当我们到达那里时,我会解释一下。
首先,我们得到了用户。我改变了你所拥有的东西,因为我严格反对使用反引号作为续行字符,因为它很容易被空格所挫败。我还将$UserList
从一个字符串数组更改为一个对象数组,因为无论如何你以后都想要对象。我们仍会捕获名字和姓氏,但作为User
上的[PSCustomObject]
属性。
$ADGroup = "SomeADGroup"
$UserList = Get-ADGroupMember -Identity $ADGroup -Recursive |
Select SamAccountName |
foreach-object {
Get-ADUser -Identity $_.SamAccountName |
Select @{n='User';e={$_.Surname + ", " + $_.GivenName}}
}
所以现在我们有一个带有一个属性的对象数组。现在我们循环遍历,搜索计算机,并将计算机捕获为字符串数组。这只是略微修改过的代码。
foreach ($User in $UserList)
{
$MachineList = Get-ADComputer -Filter {Description -like "*$($User.User)*"} | Select -ExpandProperty Name
现在是我们改变一点点的地方。对于我们发现的每台机器,我们需要为我们已有的对象添加属性。由于我们不知道有多少,我们可以使用For
循环并相应地对属性进行编号。
for($i=0;$i -le $MachineList.Count;$i++)
{
Add-Member -InputObject $User -NotePropertyName "Machine$($i+1)" -NotePropertyValue $MachineList[$i]
}
}
所以现在$UserList
是一个对象数组,每个对象都有User
属性,但对于该用户而言,有许多Machine#
属性。问题是PowerShell根据数组中的第一个对象输出对象数组。所以在你的例子中:
User Machine Machine2
---- ------- -------
White, Scott W107175
Jones, Henry W107195
Flinstone, Fred L109531 W108812
Machine2
列永远不会显示,因为该属性并不存在于Scott White的第一条记录中。因此,为了解决这个问题,我们需要找出数组中任何给定对象的所有可能属性,并将任何缺少的对象添加到第一条记录中。这可以使用PowerShell中每个对象的隐藏PSObject
属性轻松完成。
首先,我们得到所有可能的属性名称列表:
$AllProps = $UserList | ForEach{$_.PSObject.Properties.Name} | Select -Unique
然后我们过滤掉第一条记录上已有的任何属性,剩下的任何内容都会再次使用Add-Member
cmdlet作为新属性添加到记录中。
$AllProps |
Where{ $_ -notin $UserList[0].psobject.properties.name } |
ForEach{ Add-Member -InputObject $UserList[0] -NotePropertyName $_ -NotePropertyValue $null }
然后没有什么要做但输出结果,这些结果已经存储在$UserList
中,因为我们制作了用户列表,并且只是用每个用户的机器更新了现有列表,而不是制作用户列表,然后是新的用户和机器列表。
$UserList | Format-Table
答案 1 :(得分:0)
你很好地进入变量"变量"问领域;从根本上说你永远不会写
$User.Machine1
$User.Machine2
$User.Machine...
因为您不知道有多少台机器,所以您无法在代码中编写属性名称。数组就是答案,你的代码中有一个引用数组的变量,其中包含所有机器。那么你的代码是有意义的,它既简单又合理又有效,但它与你的CSV梦想不一致 - 因为你的数据不是CSV形的。
如果您为每个用户添加一台属性,则会让一些用户拥有一台计算机,而某些用户拥有四台...并且会使Format-Table
,ConvertTo-Csv
,{{3因为他们把他们看到的第一个对象作为模板,然后在第一个对象上没有的其他对象上的任何列,它们就会掉落。
所以你必须做TheMadTechnician正在做的事情,然后返回并动态地将所有空白的MachineN属性添加到所有对象,如果你只是说出前面的话就会非常简单"会有N列&#34 34。
然后你可以计算它们,我明白了:
$ADGroup = "SomeADGroup"
$ColumnCount = 10
Get-ADGroupMember -Identity $ADGroup -Recursive | Get-ADUser | ForEach-Object {
$User = [ordered]@{ 'User' = $_.SurName + ", " + $_.GivenName }
$Machines = @((Get-ADComputer -Filter "Description -like '*$($User.User)*'").Name)
for ($i=0; $i -lt $ColumnCount; $i++)
{
$User["Machine$i"] = $Machines[$i]
}
[PSCustomObject]$User
} | ConvertTo-Csv
NB。我依赖数组越界行为。如果您需要避免这种情况,请将10列空字符串添加到Machines列表的末尾作为缓冲区。
但是我仍然很想通过字符串操作自己混合CSV,而不是完全通过对象,因为你并没有使用它们,因为它们应该'#' 39;可以使用,但只是在制作正确的属性方面只需要将它们扔掉以获得CSV。
偏离主题,您的代码非常错综复杂:
$UserList = Get-ADGroupMember -Identity $ADGroup -Recursive `
| Select SamAccountName `
| foreach-object {(Get-ADUser -Identity $_.SamAccountName `
| Select @{n='AssignedUser';e={$_.SurName + ", " + $_.GivenName}}).AssignedUser}
你得到AD组成员,然后你以一种绝对没有任何方式选择SamAccountName,然后你循环结果而不是将它们直接流水线化到Get-ADUser,没有任何好处,那么你选择一个计算属性和然后扔掉它并获得价值。代替:
Get-ADGroupMember -Identity $ADGroup -Recursive | Get-ADUser | ForEach-Object { $_.SurName + ', ' + $_.GivenName }
获取群组成员,获取其AD用户,并根据这些结果计算字符串。
和
$Results = New-Object System.Collections.Generic.List[System.Object]
->
$Results = @()
或者,更好的是:
$Results = @()
foreach ($x in $y) {
$Results += ...
}
->
$Results = foreach ($x in y ) {
...
}
并在
| ForEach-Object { [pscustomobject] $_ } |
你......当你制作它们时可以让它们Out-GridView
,然后你就不需要它了。
答案 2 :(得分:0)
$ADGroup = "Some AD Group"
$UserList = Get-ADGroupMember -Identity $ADGroup -Recursive | Get-ADUser
$Results = @()
$MaxMachineCount = 0
foreach ($User in $UserList)
{
if ($User.SurName -and $User.GivenName -ne $null)
{
$CurrentUser = [ordered]@{ 'User' = $User.SurName + ", " + $User.GivenName }
$MachineList = @(((Get-ADComputer -Filter "Description -like `"*$($CurrentUser.User)*`"") | Select -ExpandProperty Name))
for ($i=0; $i -lt $MachineList.Count; $i++)
{
$CurrentUser.Add("Machine $i","$($MachineList[$i].ToUpper())")
if ($MaxMachineCount -le $i) {$MaxMachineCount++}
}
$Results += [PSCustomObject]$CurrentUser
}
}
for ($i=0; $i -lt $MaxMachineCount; $i++){$Results[0] | Add-Member -Name "Machine $i" -Value $null -MemberType NoteProperty -ErrorAction Ignore}
$Results | Format-Table -AutoSize
代码Format-Table -AutoSize
的结尾部分也可以替代ConvertTo-CSV | Out-File "C:\Some\Directory\File.csv"
我添加了这个以在我的结果中创建其他列。以前,每个用户最多只能显示两台计算机。现在,该脚本返回每个用户的所有已分配的计算机。
for ($i=0; $i -lt $MachineList.Count; $i++){$Results[0] | Add-Member -Name "Machine $i" -Value $null -MemberType NoteProperty -ErrorAction Ignore
这是我的结果:
User Machine 0 Machine 1 Machine 2 Machine 3 Machine 4 Machine 5 Machine 6 Machine 7 Machine 8
---- --------- --------- --------- --------- --------- --------- --------- --------- ---------
Froeman, Abe L110911
Maclatchie, Matthew W109370 L108518
White, Walter V999100 L107800 V999109 V999108 V999107 V999102 V999106 V999105 V999101
感谢@TessellatingHeckler和@TheMadTechnician提供的意见。