Using Powershell and ADSI to set local passwords - powershell

I'm trying to automate setting a bunch of local user accounts' password on a Windows 2008 server. I've tried a few things and this works if I don't use a variable for the username like this:
$user = [adsi]"WinNT://$computer/SomeUserName"
My script block is below... any ideas what I'm doing wrong?
$accounts = Get-Content c:\userlist.txt
$computer = SomeComputerName
$password = "MyPassword"
Foreach($account in $accounts)
{
$user = [adsi]"WinNT://$computer/$account"
$user.SetPassword("$Password")
$user.SetInfo()
}
The error I get when I use the $account variable for the user (from the text file list) is:
The following exception occurred while retrieving member "SetInfo": "The group name could not be found.
Thanks for any help...

It seems that your machine tries to resolve the $account value to a local group name.
You can specify that it is a User object you want, by following the account name with a comma and the string user:
$user = [adsi]"WinNT://$computer/$account,user"

Related

Cannot set manager attribute using ADSI in PowerShell

I update some user information in AD from an HR database.
Text fields or the photo works fine:
$user.Put("telephoneNumber", "1234")
$user.Put("thumbnailPhoto", $binaryfile)
$user.SetInfo()
But I also have to set the manager and tried
$user.Put("manager", "MYDOMAIN\MYUSERNAME")
or
$user.Put("manager", "MYUSERNAME")
That gives the following error:
Exception calling "setinfo" with "0" argument(s): "An invalid dn syntax has been specified."
What's the correct syntax to update the manager using ADSI?
As the error message suggests: the manager attribute expects a distinguished name (dn), not a user logon name, so you need to get the manager's dn first and then put that value into the manager attribute.
$manager = 'MYUSERNAME'
#...
$searcher = New-Object DirectoryServices.DirectorySearcher(([adsi]''))
$searcher.Filter = "(&(objectClass=user)(objectCategory=person)(sAMAccountName=${manager}))"
$dn = $searcher.FindOne().Properties['distinguishedName'][0]
#...
$user.Put('manager', $dn)
$user.SetInfo()

Azure DevOps Get Current User ObjectId

Is there a way to get the ObjectId of the Service Principal that is currently executing an Azure PowerShell task in Azure DevOps at all?
I am creating a resource, and then want to apply permissions for the 'current' user.. but can't work out how to get the current user ObjectId / ApplicationId
Is this possible?
Ok - based of the above, I've made a little function - it may work for a lot of cases:
function Get-CurrentUserObjectID {
$ctx = Get-AzContext
#This is different for users that are internal vs external
#We can use Mail for users and guests
$User = Get-AzADUser -Mail $ctx.Account.id
if (-not $user) { #Try UPN
$User = Get-AzADUser -UserPrincipalName $ctx.Account.Id
}
if (-not $User) { #User was not found by mail or UPN, try MailNick
$mail = ($ctx.Account.id -replace "#","_" ) + "#EXT#"
$User = Get-AzADUser | Where-Object { $_MailNick -EQ $Mail}
}
Return $User.id
}
There seems to be two ways of doing this depending on if it's a user, or a service principal:-
Get-AzADUser
Get-AzADServicePrincipal
These i believe are in the Az.Resources module. So, to give you the ObjectId (for permissions), you could take a two step approach like this:
$x = (Get-AzContext).Account.Id
$x
> df6fc4f6-cb05-4301-91e3-11d93d7fd43d # ApplicationId
$y = Get-AzADServicePrincipal -ApplicationId $x
$y.Id
> c3588e6a-b48b-4111-8241-3d6bd726ca40 # ObjectId
I can't get anything to work reliably with standard users though.. if your user is created in the AzureAD directly, and not external (i.e. gmail.com, outlook.com, etc) this should work:
$x = (Get-AzContext).Account.Id
$x
> sample#your-domain.onmicrosoft.com # UserPrincipalName
$y = Get-AzADUser -UserPrincipalName $x
$y.Id
> c5d4339b-48dc-4190-b9fb-f5397053844b # ObjectId
If your user is external, and has the weird your.email.address_outlook.com#EXT##your-domain.onmicrosoft.com as the UserPrincipalName you'll need to solve that with a bit of string manipulation i think 😕.
But! You shouldn't be scripting things with user accounts anyway, so it probably doesn't matter 😆.
Note: I have not tried this in Azure DevOps, you will probs need to upgrade the PowerShell packages, but i think the same commands should exist as Get-AzureRmADUser, and Get-AzureRmADServicePrincipal. Please let me know.

Enter-PSSession, try with multiple credentials

I need to create a script that requires multiple credentials for establishing the connection to the computers.
I have tried to achieve this with a "try catch" and "if else", but the script looks pretty ugly and is not scalable if i need to insert more credentials.
There is a better way to achive the same results?
#credentiasl for non domain conputers and domain joined
$credential01 = Get-Credential domain 1\administrador
$credentiall02 = Get-Credential domain 2\administrador
$credentiall03 = Get-Credential workgroup\administrador
$error.clear()
#try to establish a remote sesion to the pc with the credentials01
try { etsn -ComputerName sldb04 -Credential $credential01 }
#if there is an error try to establish a remote sesion to the pc with the credentials02
catch
{
etsn -ComputerName sldb04 -Credential $credential02
#if the second credential is also wrong try the third
If ($? -eq $false )
{
etsn -ComputerName sldb04 -Credential $credential03
}
}
As a best practice, don't attempt to guess the right account. This creates noise in the security logs and might lead into unexpected account lockouts.
Record the proper credentials for each environment and use it. You could store the credential mappings in a hash table like so,
# Add computer names and respective admin accounts into a hash table
$ht = #{"computer01"="domain1\admin";"computer02"="domain2\admin";"computer03"="group\admin" }
# What's the account for computer01?
$ht["computer01"]
domain1\admin
# Print all computers and admin account names
$ht.GetEnumerator() | % { $("Logon to {0} as {1}" -f $_.name, $_.value) }
Logon to computer01 as domain1\admin
Logon to computer03 as group\admin
Logon to computer02 as domain2\admin
This can easily be extended by creating another a hashtable that stores credentials. Like so,
# Create empty hashable
$creds = #{}
# Iterate computer/account hashtable and prompt for admin passwords
$ht.GetEnumerator() | % {
$c= get-credential $_.value
# Add only accounts that don't yet exist on the hashtable
if(-not $creds.Contains($_.value)) {
$creds.Add($_.value, $c) }
}
# What's the account for domain1\admin?
$creds["domain1\admin"]
UserName Password
-------- --------
domain1\admin System.Security.SecureString

creating local users using a xml file as source with powershell scripting

I'm trying to create bulk localusers with xml source file with all details in it using powershell scripting. Below is my sample xml file with code I'm using for creating the users. Can anyone help me out getting this to work?
# To run this script use: & "C:\Users\rLisdonk\Desktop\ToServer\Test.ps1"
$computerName = "USSECAVDSPDWK27"
$serviceAccountWebName = "saAsaWeb"
$serviceAccountWebPassword = "MyPassword123"
"Get computer info"
$computer = [ADSI]("WinNT://" + $computerName + ",computer")
"Determine if user [saAsaWeb] exists"
$serviceAccount = [ADSI]("WinNT://" + $computerName + "/$serviceAccountWebName" + ",user")
if(!$serviceAccount.Name)
{
"Create user [saAsaWeb]"
$user = $computer.Create("user", $serviceAccountWebName)
"Set password"
$user.SetPassword($serviceAccountWebPassword)
$user.SetInfo()
"Disable [User must change password at next logon]"
$user.PasswordExpired = 0
$user.SetInfo()
"Enable [Password never expires]"
$wmiuser = Get-WmiObject -class "Win32_UserAccount" -filter "name=’$serviceAccountWebName’"
$wmiuser.PasswordExpires = $false
$wmiuser.Put()
}
Powershell will only substitute the variable with the value inside double quotes, single quotes will return the literal value. You will want to escape the single quotes with a ` backtick character, so it would be:
$wmiuser = Get-WmiObject Win32_UserAccount -filter "LocalAccount=True AND name=`'$serviceAccountWebName`'"
When you run it, it needs to be ran with elevated permissions. If you are looking to do this on a remote machine, you need to do so via Remoting, or use WMI entirely. Without a specified error I assume it is this WMI query is most likely what is holding you up.

Powershell: How do you set the Read/Write Service Principal Name AD Permissions?

In Powershell, how do you set the Read/Write Service Principal Name AD user permissions?
Normally during my build process, I use ADSIedit to navigate to that object, and then go through all the security tabs to get down to put a checkmark next to:
Read Service Principal Name
Write Service Principal Name
But navigating through ADSIedit can take a long time so I'm trying to script the process. If I have a PowerShell LDAP bind with a new user created, how can I use PowerShell to set both of these properties for this user account?
The following is a hacked out code-snippet of the possible pertinent portions of my install script:
$strDomain = "dc=my,dc=com"
$objDomain = [ADSI] "LDAP://" + strDomain
$strSCCMSQLPW = Read-Host -assecurestring "Please enter a password for the " + $strSCCMSQL + " account: "
New-ADUser -SamAccountName $strSCCMSQL + -Name $strSCCMSQL -AccountPassword $strSCCMSQLPW -Enabled $true -Path $strUsersOU + "," + $strDomain -PasswordNeverExpires $true
You need to add an ActiveDirectoryAccessRule object to the ACL of the target object. For setting property specific rigths the trick is to pass in the schemaIDGUID to the attribute. So first we need to find the schemaIDGUID from the Service-Principal-Name schema entry. In the sample code i statically refer to the Service-Principal-Name, better yet would have been to search for the ldapDisplayname to find the entry but I'm sure you can sort that out. In any case this code should do the job:
Function Set-SpnPermission {
param(
[adsi]$TargetObject,
[Security.Principal.IdentityReference]$Identity,
[switch]$Write,
[switch]$Read
)
if(!$write -and !$read){
throw "Missing either -read or -write"
}
$rootDSE = [adsi]"LDAP://RootDSE"
$schemaDN = $rootDSE.psbase.properties["schemaNamingContext"][0]
$spnDN = "LDAP://CN=Service-Principal-Name,$schemaDN"
$spnEntry = [adsi]$spnDN
$guidArg=#("")
$guidArg[0]=$spnEntry.psbase.Properties["schemaIDGUID"][0]
$spnSecGuid = new-object GUID $guidArg
if($read ){$adRight=[DirectoryServices.ActiveDirectoryRights]"ReadProperty" }
if($write){$adRight=[DirectoryServices.ActiveDirectoryRights]"WriteProperty"}
if($write -and $read){$adRight=[DirectoryServices.ActiveDirectoryRights]"readproperty,writeproperty"}
$accessRuleArgs = $identity,$adRight,"Allow",$spnSecGuid,"None"
$spnAce = new-object DirectoryServices.ActiveDirectoryAccessRule $accessRuleArgs
$TargetObject.psbase.ObjectSecurity.AddAccessRule($spnAce)
$TargetObject.psbase.CommitChanges()
return $spnAce
}
Sample lines for calling the function...
$TargetObject = "LDAP://CN=User,OU=My User Org,DC=domain,DC=net"
$Identity = [security.principal.ntaccount]"domain\user"
Set-SpnPermission -TargetObject $TargetObject -Identity $Identity -write -read
Here is an example using Quest to set the permissions on the service principal name attributes.
First, add Quest:
Add-PSSnapin Quest.ActiveRoles.ADManagement;
Set the permission (using Add-QADPermission):
Get-QADUser UserName | Add-QADPermission -Account 'SELF' -Rights 'ReadProperty,WriteProperty' -Property 'servicePrincipalName' -ApplyTo 'ThisObjectOnly';
You can use Quest AD cmdlets. It makes AD permission stuff very easy in PowerShell.
Read this blog for some examples on how to add AD permissions or even copy the AD permissions.
Just lookup Add-QADPermission and it should do your job.