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?
Your 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 the Measure-Object
call.
select
(Select-Object
), and especially not Format-Wide
- see next section.There's no need for filtering out $null
values with a Where
(Where-Object
) call, as Measure-Object
will simply ignore them.
Using -Properties *
is expensive and best avoided; here, you only need one 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:
%
(ForEach-Object
), as you can pipe the user objects stored in $noUid
directly to Set-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 as Format-Wide
emit output objects whose sole purpose is to provide formatting instructions to PowerShell's for-display output-formatting system. In short: only ever use Format-*
cmdlets to format data for display, never for subsequent programmatic processing - see this answer for more information.
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.Omitting Format-Wide
wouldn't suffice in your case, because select 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 by Measure-Object
. For the latter you need Select-Object -ExpandProperty maximum
- see this answer for more information.