i'm trying to write a script to popolate uidnumber in active directory.
$SearchBase = "OU=test,DC=xxx,DC=local"
$lastuid = Get-ADUser -Filter * -searchbase $searchbase -Properties * | Where {($_.uidNumber -ne $null)} | select uidnumber | Measure-Object -Property uidnumber -Maximum | select maximum |
Format-Wide
$i= $lastuid
$nouid = Get-ADUser -Filter * -searchbase $searchbase -Properties * | Where {($_.uidNumber -eq $null)} | select samaccountname
$nouid | %{Set-ADUser $_.samAccountName -add @{uidnumber=('{0:D4}' -f $i )}}
This do not produce error but pupulate uidnumber starting from 0, ignoring lastuid. If i use
$i= $lastuid
produce error like
"Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Int32". At C:\-\Documents\uid.ps1:16 char:15... $nouid | %{Set-ADUser $_.samAccountName -replace @{uidnumber=([int] ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidArgument: (:) [], RuntimeException
FullyQualifiedErrorId : ConvertToFinalInvalidCastException"
any suggestion?
CodePudding user response:
The command that determines the currently highest uidNumber is broken; replace it with the following:
[int] $lastuid = (
Get-ADUser -Filter * -searchbase $searchbase -Properties uidnumber |
Measure-Object -Property uidnumber -Maximum
).Maximum
Note:
(...).Maximum
, i.e. direct property access is used to obtain the maximum value from theMeasure-Object
call.- There is no need for
select
(Select-Object
), and especially notFormat-Wide
- see next section.
- There is no need for
There's no need for filtering out
$null
values with aWhere
(Where-Object
) call, asMeasure-Object
will simply ignore them.Using
-Properties *
is expensive and best avoided; here, you only need one (presumably) non-default property,uidnumber
.
A separate problem is that *your code for updating the uidnumber
field doesn't increment the number for each targeted user: [int] $i 1
assigns the same value to all; the simplest solution is to use
:
$noUid | Set-ADUser -replace @{ uidnumber = $i }
Note:
- There is no need for
%
(ForEach-Object
), as you can pipe the user objects stored in$noUid
directly toSet-ADUser
.
There's potential for additional optimization of your code, such as calling Get-ADUser -Filter *
only once, assuming that all users objects fit into memory at once:
$withoutUid, $withtUid =
(Get-ADUser -Filter * -searchbase $searchbase -Properties uidnumber).
Where({ $null -eq $_.uidnumber }, 'Split')
[int] $lastuid = ($withUid | Measure-Object -Property uidnumber -Maximum).Maximum
$withoutUid | Set-ADUser -replace @{ uidnumber = $lastuid }
As for what you tried:
Format-*
cmdlets such asFormat-Wide
emit output objects whose sole purpose is to provide formatting instructions to PowerShell's for-display output-formatting system. In short: only ever useFormat-*
cmdlets to format data for display, never for subsequent programmatic processing - see this answer for more information.- Apart from
Format-Wide
not representing the data you intended, it output multiple objects, which$lastuid = ...
captured in an array. It is that array that caused the error you saw.
- Apart from
Omitting
Format-Wide
wouldn't suffice in your case, becauseselect maximum
(Select-Object maximum
) also wouldn't work as intended: it would create an object with a.Maximum
property, instead of directly emitting the value of the.Maximum
property of the property returned byMeasure-Object
. For the latter you needSelect-Object -ExpandProperty maximum
- see this answer for more information.