Jump to content

Recommended Posts

Posted

Hello,

 

We have lots of international students here temporarily.

Accounts are created from a CSV via a powershell script, sets random password to not be changed.

 

Only problem is the password don't sync to Google until reset.

 

I have tried doing this via another powershell script but no luck

Any ideas before I rest over 30 accounts manually one by one?

 

Import-Module ActiveDirectoryImport-Csv "C:\Temp\Users.csv" | ForEach-Object {$samAccountName = $_."Username"$Password = $_."Password"$newPassword = ConvertTo-SecureString -AsPlainText $Password -ForceWrite-Host " AD Password has been reset for: "$samAccountName

Posted

ForEach-Object{
$Pass = ConvertTo-SecureString $_."Password" -AsPlainText -Force 
Set-ADAccountPassword -Identity $_."Username" -NewPassword $pass –Reset
}

Something like this should work in your loop

Posted (edited)

If it's a new account then you'll have to run the google sync (GCDS) first to create the account in Google. You can then reset the password in AD so it will push up to Google (as long as you have Google Password sync installed on all your domain controllers).

 

You could change the powershell script to create the account > run GCDS > Reset password.

 

Edit: Something else you might need to check is how GCDS creates your users and how it handles their first google sign in (force password reset etc).

Edited by RLR
Posted
ForEach-Object{
$Pass = ConvertTo-SecureString $_."Password" -AsPlainText -Force 
Set-ADAccountPassword -Identity $_."Username" -NewPassword $pass –Reset
}

Something like this should work in your loop

 

Thank you so much! :D

You just saved me like 2 hours of work.

Posted

Sorry to jump on this again. Kind of new to powershell.

 

I tried running my new script again and am getting errors. I'm pretty sure it worked the first time...

 

 Import-Module ActiveDirectoryImport-Csv "C:\Temp\Users.csv"ForEach-Object{$Pass = ConvertTo-SecureString $_."Password" -AsPlainText -Force Set-ADAccountPassword -Identity $_."Username" -NewPassword $pass –ResetWrite-Host " AD Password has been reset for: "$samAccountName} 

 

ConvertTo-SecureString : Cannot bind argument to parameter 'String' because it is null.At line:4 char:32+ $Pass = ConvertTo-SecureString $_."Password" -AsPlainText -Force+ ~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [ConvertTo-SecureString], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertToSe cureStringCommand

 

Set-ADAccountPassword : Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid valuefor the argument, and then try running the command again.At line:5 char:33+ Set-ADAccountPassword -Identity $_."Username" -NewPassword $pass –Res ...+ ~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [set-ADAccountPassword], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.SetADAcco untPassword

 

 

 

Please help!

Posted

That code is all on one line. Is it like that in your script?

 

I wonder if it's reading the Set-ADAccountPassword command as part of your ConvertTo-SecureString command (i.e. not on a new line).

Posted

This is a cut-down version of a script I use. Save it as resetPassword.ps1 and use it like in the example block.

 

Test it first, obviously.

 

<#
.DESCRIPTION
Script to reset the password for user accounts based on CSV input.
.PARAMETER InputFile
The path to a CSV file containing the details of users and passwords to be applied.
The CSV file must include columns named 'Username' and 'Password'.
.EXAMPLE
resetPasswords.ps1 -InputFile users.csv
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $InputFile
)

$Users = Import-CSV $InputFile
foreach ($User in $Users)
{
if ($User.Username -and $User.Password) {
	# Username and password are both present in the row.
	Set-ADAccountPassword -Identity $User.Username -Reset -NewPassword (ConvertTo-SecureString -AsPlainText $User.Password -Force)
}
else {
	# A username and/or password is missing from the row.
	Write-Host "A row of the input file is missing a username or password".
}
}

Posted

My code is not actually all on one line.

 

It looks more like this:

 

Import-Module ActiveDirectory

Import-Csv "C:\Temp\Users.csv"

ForEach-Object{

$Pass = ConvertTo-SecureString $_."Password" -AsPlainText -Force

Set-ADAccountPassword -Identity $_."Username" -NewPassword $pass –Reset

Write-Host " AD Password has been reset for: "$samAccountName

}

Posted (edited)

You need to either pipe your CSV into the foreach or store the CSV into an array and call that with foreach

 

Import-Csv "C:\Temp\Users.csv" | Foreach-Object {
...
}

$CSV = Import-Csv "C:\Temp\Users.csv"
Foreach ($Line in $CSV) {
...
}

 

Without doing either, you're importing the CSV data to the console, discarding it, then moving onto the foreach loop. The '$_.' calls are then empty because you've not given it anything to work with, which is what the errors you've posted translate to.

Edited by Sephiroth
More detail
Posted

@Sephiroth is right, the one thing I will add is that if you import that csv in to a var then use %$varname%.foreach({}) as this is way more performant than | foreach.

 

On a small scale this is not a massive issue but at scale the use of the above makes a big difference in the iteration speed

 

I will not go into the why as you can dig it out of my previous posts on here or Google will tell you.

  • Thanks 1
Posted
@Sephiroth is right, the one thing I will add is that if you import that csv in to a var then use %$varname%.foreach({}) as this is way more performant than | foreach.

 

On a small scale this is not a massive issue but at scale the use of the above makes a big difference in the iteration speed

 

I will not go into the why as you can dig it out of my previous posts on here or Google will tell you.

 

Agreed, but the performance saving is miniscule versus using the Foreach statement (the second one that I quoted, and my preferred).

 

See the below code and results. Each command is iterated 1 million times, and measured to see how long that takes.

 

$Time = (Measure-Command {
   1..1E7 | ForEach-Object {
       $_
   }
}).TotalMilliseconds

[pscustomobject]@{
   Type = 'Piped ForEach'
   Time_ms = $Time
}

$Time = (Measure-Command {
   ForEach ($i in (1..1E7)) {
       $i
   }
}).TotalMilliseconds

[pscustomobject]@{
   Type = 'ForEach Statement'
   Time_ms = $Time
}

$Time = (Measure-Command {
   $(1..1E7).ForEach({
       $_
   })
}).TotalMilliseconds

[pscustomobject]@{
   Type = 'Var ForEach'
   Time_ms = $Time
}

 

Type                  Time_ms
----                  -------
Piped ForEach     121874.3961
ForEach Statement  11120.0347
Var ForEach        89841.2608

 

'$Var.Foreach({})' is about 30% faster than piped, but 'Foreach ($I in $Var) {}' is more than 10x faster. extremely noticeable on large datasets (>10k records), but for @plumyeti any of the 3 will likely be fine as long as the syntax is correct.

  • Thanks 1
Posted

You could go old school, and use NET USER in a batch file? Easy to put together in Excel, and then paste into a batch file.

 

net user [username] [password] /DOMAIN

Posted
I love the smell of PowerShell in the morning, interesting note on the performance as that .foreach should out stip the other uses as its a method now and they did a lot of work with the .net team to improve performance. Love that you have done some grunt work @Sephiroth, and yeah not many will work at the scale where it make a significant difference.
  • Thanks 2

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...