I am looking to update every user in AD both Telephone numbers from the general tab and pager, mobile and fax. What I am looking to update is any user in our AD from +44 (0) +44 0
I have tried with the following but did not work but can't see why
$UserSplat = #{
LDAPFilter = "(|(homephone=*)(othermobile=*)(mobile=*))"
Properties = #('homephone', 'othermobile', 'mobile')
SearchBase = 'OU=NoAdm,OU=Users,DC=xxxxx,DC=xxxxx,DC=xxxxx,DC=net'
}
Get-ADUser #UserSplat | ForEach-Object {
$CurrentUser = New-Object -TypeName PSCustomObject -Property #{
Name = $_.Name
HomePhone = (-join $_.homephone) -replace '\s'
OtherMobile = (-join $_.othermobile) -replace '\s'
Mobile = (-join $_.mobile) -replace '\s'
}
$CurrentUser
if ($CurrentUser.homephone -notmatch '^\(0)') {
$_ | Set-ADUser -Replace #{homephone = "0$($CurrentUser.HomePhone)" } -WhatIf
}
}
I unfortunately can't test this, I believe -LDAPFilter should be capable of filtering only those users that actually have their homephone, othermobile and mobile attributes starting with +44 (0) hence I added that to save a step. I also left the -WhatIf switch to be sure the script is doing what is supposed to do.
$startsWith = '+44 (0)'
$UserSplat = #{
LDAPFilter = "(|(homephone=$startsWith*)(othermobile=$startsWith*)(mobile=$startsWith*))"
Properties = #('homephone', 'othermobile', 'mobile')
SearchBase = 'OU=NoAdm,OU=Users,DC=xxxxx,DC=xxxxx,DC=xxxxx,DC=net'
}
$startsWith = [regex]::Escape($startsWith)
foreach($user in Get-ADUser #UserSplat)
{
$replaceHash = #{}
foreach($prop in 'homephone', 'othermobile', 'mobile')
{
if(($replace = $user.$prop) -match $startsWith) {
$replaceHash[$prop] = $replace -replace '\(|\)'
}
}
Set-ADUser $user -Replace $replaceHash -WhatIf
}
Related
Its pretty "simple" what i want to achieve. I have people creating Computer Objects on my AD and leaving there without moving them to the appropiate OU.
I would like a powershell script to read the list of computers from the Computers OU, and depending the first 5 or 6 letters from the Computer name, move it to the appropiate OU, reading the list of destination OUs from a CSV or txt or whatever file type.
I need to move more than 100 computers and I would like to scan them, and move them to their corresponding OU.
I've thought to use a variable for the computer accounts, then a foreach and a switch or something similar, and 1-by-1 start moving the accounts. But I'm stuck.
Thank you!!!!
Turning my comment into an answer. You could create a lookup Hashtable for this:
# create a lookup Hashtable for all OU's in your organisation
# You can limit this using parameters like '-SearchScope' and '-SearchBase' depending on the structure in your AD environment
$allOUs = #{}
Get-ADOrganizationalUnit -Filter 'Name -like "*"' | ForEach-Object {
$allOUs[$_.Name] = $_.DistinguishedName
}
# next, get all computers in the default Computers OU
$result = Get-ADComputer -Filter * -SearchBase "CN=Computers,DC=Contoso,DC=com" | ForEach-Object {
$computerName = $_.Name
$found = $false
if ($computerName.Length -ge 6) {
$targetOU = $computerName.Substring(0,6)
$found = $allOUs.ContainsKey($targetOU)
}
if (!$found -and $computerName.Length -ge 5) {
$targetOU = $computerName.Substring(0,5)
$found = $allOUs.ContainsKey($targetOU)
}
if ($found) {
try {
$_ | Move-ADObject -TargetPath $allOUs[$targetOU] -ErrorAction Stop -WhatIf
# add success to the $result
[PsCustomObject]#{
'Computer' = $computerName
'TargetOU' = $targetOU
'Result' = 'Moved'
}
}
catch {
# add exception to the $result
[PsCustomObject]#{
'Computer' = $computerName
'TargetOU' = $targetOU
'Result' = 'Not moved. {0}' -f $_.Exception.Message
}
}
}
else {
# add failure to the $result
[PsCustomObject]#{
'Computer' = $computerName
'TargetOU' = ''
'Result' = 'Not moved. Computername does not begin with a valid OU name'
}
}
}
# output on screen
$result
# output to file
$result | Export-Csv -Path 'ComputersMoved.CSV' -NoTypeInformation
Remove the -WhatIf switch if you are satisfied with the results shown in the console.
This should be dynamic enough. You can replace the Map object with a CSV.
$Map = [PSCustomObject]#{
AABBCC = "OU=ABC,DC=Contoso,DC=com";
CCBBAA = "OU=CBA,DC=Contoso,DC=com"
}
$Prefixlist = ($Map.PSObject.Members | Where-Object { $_.MemberType -eq "NoteProperty" }).Name
$Report = #()
$MissingPrefix = #()
Get-ADComputer -filter * -searchbase "CN=Computers,DC=Contoso,DC=com" -Properties Name | ForEach-Object {
$obj = $_
$Prefix = ($obj.Name).Substring(0, 6)
if ($Prefixlist -contains $Prefixlist) {
try {
$obj | Move-AdObject -Targetpath $Map.$Prefix -erroraction stop
$Report += [PSCustomObject]#{
Name = $Obj.Name
Move = $true
}
}
catch {
$_.Exception.ErrorRecord
$Report += [PSCustomObject]#{
Name = $Obj.Name
Move = $false
}
}
}
else {
$MissingPrefix += $Prefixlist
$Report += [PSCustomObject]#{
Name = $Obj.Name
Move = $false
}
}
}
"Result"
$Report | Format-Table -AutoSize
"Not found prefix list"
$MissingPrefix
Option 2 to make the path based on the prefix
$Report = #()
Get-ADComputer -filter * -searchbase "CN=Computers,DC=Contoso,DC=com" -Properties Name | ForEach-Object {
$obj = $_
$Prefix = ($obj.Name).Substring(0, 6)
try {
$obj | Move-AdObject -Targetpath "OU=Computers,OU=$Prefix,DC=Contoso,DC=com" -erroraction stop
$Report += [PSCustomObject]#{
Name = $Obj.Name
Move = $true
}
}
catch {
$_.Exception.ErrorRecord
$Report += [PSCustomObject]#{
Name = $Obj.Name
Move = $false
}
}
}
"Result"
$Report | Format-Table -AutoSize
I have list of accounts as below in a text file-
AccountName
Mahin\user1
Mahin\user2
Mahin\group5
user12
usert1
groupt3
This way, I have around 400 accounts (mix of various users and some groups),
as you can see from above, some accounts have format as <Domain>\<AccountName>
and some with just <AccountName>.
I was trying to find a way to segregate users and groups from this list,
how can I achieve this using powershell?
Looking for something like
AccountName, IsUser, IsGroup, IsExists
Mahin\user1,1,0,1
Mahin\user2,1,0,1
Mahin\group5,0,1,1
user12,1,0,1
usert1,,,0 //-> This Account DOES NOT EXIST, so, IsUser, IsGroup and IsExists (0) can be empty or some distiguishable number
groupt3,,,0 //-> This Account DOES NOT EXIST, so, IsUser, IsGroup and IsExists (0) can be empty or some distiguishable number
So far, I know how to get members of various groups using below script, but not sure of above part.
$groups = Get-Content "C:\AD\groups.txt"
$resultsarray =#()
foreach ($group in $groups) {
$resultsarray += Get-ADGroupMember -Id $group | select
samaccountname,name,#{Expression={$group};Label="Group Name"}
}
$resultsarray| Export-csv -path "C:\AD\output\GroupMembers.csv" -notypeinformation
Note: Im not very familiar with the Active Directory Cmdlets, there is probably a better solution for this.
However, I would retrieve all users and groups first, then iterate over your text file and try to find any user or group:
$users = Get-ADUser -filter *
$groups = Get-ADGroup -filter *
Get-Content 'YOUR_FILE_PATH'| ForEach-Object {
$adObject = $_ -replace '(.*)\\(.*)', '$2#$1' # fix search string
if ($users | Where { $_.SamAccountName -eq $adObject -or
$_.UserPrincipalName -like "$adObject*"} )
{
[PSCustomObject]#{
AccountName = $_
IsUser = $true
IsGroup = $false
Exist = $true
}
}
elseif ($groups | Where Name -eq $adObject)
{
[PSCustomObject]#{
AccountName = $_
IsUser = $false
IsGroup = $true
Exist = $true
}
}
else
{
[PSCustomObject]#{
AccountName = $_
IsUser = $false
IsGroup = $false
Exist = $false
}
}
} | Export-csv -path "C:\output\GroupMembers.csv" -notypeinformation
On my AD I have to transform Mahin\group5 to group5#Mahin and search for group5#Mahin*, thats why I replace the string within the script.
Here is a sample of the csv file I import.
CN,DistinguishedName,extensionattribute7,extensionattribute1
CNPTL73J79ZN1,"CN=CNPTL73J79ZN1,OU=Laptops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",tianyang.li,
USPTD079YZLN1,"CN=USPTD079YZLN1,OU=Desktops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",gary.ortiz,
USPTD07WM53M1,"CN=USPTD07WM53M1,OU=Desktops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",allen.watson,
USPTL7CC1P0P1,"CN=USPTL7CC1P0P1,OU=Laptops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",u0147066,
USPTL77BTZ4R1,"CN=USPTL77BTZ4R1,OU=Laptops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",U0172604,
U0165724-TPL-A,"CN=U0165724-TPL-A,OU=Laptops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",U0165724,167
U0130173-TPL-A,"CN=U0130173-TPL-A,OU=Laptops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",U0130173,167
U0068498-TPL-A,"CN=U0068498-TPL-A,OU=Laptops,OU=Workstations,OU=MSP01,DC=ten,DC=domain,DC=com",u0068498,167
A couple of things I need to do :
Check if the format of CN starts with UXXXXXXX
If it does not, check extensionattribute7 for proper formatted user id of Uxxxxxxx
If that exists, replace the CN with the name of Uxxxxxxx-TPL-ZZZ. the -TPL-ZZZ will be consistent though out all names.
I am totally confused how to search for the Uxxxxxxx but I need something like this, although I know this is completely incorrect.
Import-Csv c:\Temp\Windows7_Only.csv
if ($_CN -NotMatch'[U][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]')
{
Replace the name if extensionattribute7 contains a value of U####### and add the suffix of -TPL-ZZZ
}
Here is my script so far:
#Create an LDAP searcher object and pass in the DN of the domain we wish to query
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://DC=ten,DC=domain,DC=com")
#Pass in the ceriteria we are searching for.
$Searcher.Filter = "(&(objectCategory=computer)(objectClass=computer)(!UserAccountControl:1.2.840.113556.1.4.803:=2)(operatingSystem=Windows 7*))"
$Searcher.PageSize = 100000
# Populate General Sheet(1) with information
$results = $Searcher.Findall()
$results | ForEach-Object { $_.GetDirectoryEntry() } |
select #{ n = 'CN'; e = { $_.CN -replace "'", "''" } },
#{ n = 'DistinguishedName'; e = { $_.DistinguishedName -replace "'", "''" } },
#{ n = 'extensionattribute7'; e = { $_.extensionattribute7 -replace "'", "''" } },
#{ n = 'extensionattribute1'; e = { $_.extensionattribute1 -replace "'", "''" } } |
Export-Csv 'C:\temp\Windows7_Only.csv' -NoType -Force
$csv = Import-Csv -Path "c:\Temp\Windows7_Only.csv"
foreach ($row in $csv)
{
if (($row.CN -notmatch '^U\d{7}') -and ($row.DistinguishedName -like "*Laptops*") -and ($row.extensionattribute7 -match '^U\d{7}$'))
{
$row.CN = $row.extensionattribute7 + "-TPL-ZZZ"
}
elseif (($row.CN -notmatch '^U\d{7}') -and ($row.DistinguishedName -like "*Desktops*") -and ($row.extensionattribute7 -match '^U\d{7}$'))
{
$row.CN = $row.extensionattribute7 + "-TPD-ZZZ"
}
$csv | export-csv c:\fixed.csv -Force
}
Good start, though let me say that if you have access to the Active Directory snap-in you should totally use that rather than creating LDAP searchers and what not.
Now, about your comparison... As Matt said your Match should be against $.CN. What that means is $, which represents the current record as it loops through records, and the .CN portion indicates that it should look at the CN property of the record.
Then you can use -Match and (again) like Matt said (he's new here but proving to be knowledgeable), that can be shortened to "U\d{8}".
Now, you actually want to find those that aren't like U\d{8}, so let's precede that with a ! which is an alias for -Not. Then let's check and see if ExtendedAttribute7 is the right thing. So then this looks like:
!$_.CN -like "U\d{8}" -and $_.ExtendedAttribute7 -match "U\d{8}"
Excellent! We have our filter for the rows that need updating. That is pretty much what Alexander did. As for me, I'd go more (using your script as a base):
#Create an LDAP searcher object and pass in the DN of the domain we wish to query
$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://DC=ten,DC=domain,DC=com")
#Pass in the ceriteria we are searching for.
#In this case we're looking for users with a particular SAM name.
$Searcher.Filter = "(&(objectCategory=computer)(objectClass=computer)(!UserAccountControl:1.2.840.113556.1.4.803:=2)(operatingSystem=Windows 7*))"
$Searcher.PageSize = 100000
# Populate General Sheet(1) with information
$results = $Searcher.Findall()
$Computers = #()
ForEach($Item in $results){
$Comp = $Item.GetDirectoryEntry()
If($Comp.distinguishedName -like "*desktops*"){$Suffix = "TPD-ZZZ"}else{$Suffix = "TPL-ZZZ"}
$CN = If(!$Comp.CN -match "U\d{8}" -and $Comp.extensionattribute7 -match "U\d{8}"){$Comp.extensionattribute7+$Suffix}else{$Comp.CN}
$Computers += [PSCustomObject][Ordered]#{
'CN' = $CN -replace "'", "''"
'DistinguishedName' = $Comp.DistinguishedName[0] -replace "'", "''"
'extensionattribute7' = $Comp.extensionattribute7[0] -replace "'", "''"
'extensionattribute1' = $Comp.extensionattribute1[0] -replace "'", "''"
}
}
$Computers | Export-Csv 'C:\temp\Windows7_Only.csv' -NoType -Force
$Computers
Assuming that I understand your requirements correctly:
$csv = Import-Csv -Path "c:\Temp\Windows7_Only.csv"
foreach ($row in $csv) {
if ($row.DistinguishedName -like "*Desktops*") {
$suffix = "-TPD-ZZZ"
}
elseif ($row.DistinguishedName -like "*Laptops*") {
$suffix = "-TPL-ZZZ"
}
if ( ($row.CN -notmatch '^U\d{7}') `
-and ($row.extensionattribute7 -match '^U\d{7}$') ) {
$row.CN = $row.extensionattribute7 + $suffix
}
}
$csv | export-csv c:\fixed.csv -Force -NoTypeInformation
I have a script that gives me all members of a group with certain desired information. I want this same format but for all groups that a specified username belongs to. I want information about each group, such as group type (ie security, distribution list). How would I do this? I want a different row for each group, with information about each group in the columns.
Add-PSSnapin Quest.ActiveRoles.ADManagement
$myCol = #()
ForEach ($Group in (Get-QADGroup "CN=research,OU=Security,OU=Groups,DC=xxx,DC=com" -GroupType Security))
{
ForEach ($Member in (Get-QADGroupMember $Group -SizeLimit 0))
{
$myObj = "" | Select Group, Type, Member, Email, Username, Department
$myObj.Group = $Group.Name
$myObj.Type = $Group.groupType
$myObj.Member = $Member.Name
$myObj.Email = $Member.Email
$myObj.Department = $Member.Department
$myObj.Username = $Member.sAMAccountName
$myCol += $myObj
}
}
$myCol | Export-Csv -Path "C:\Users\sdevito\Desktop\test.csv" -NoTypeInformation
or. there is this code that i found that does something similar, but each group is in the same row, different column. i cannot figure out how to edit this code to make each group on a new row.
$alist = "Name`tAccountName`tDescription`tEmailAddress`tLastLogonDate`tManager`tTitle`tDepartment`tCompany`twhenCreated`tAcctEnabled`tGroups`n"
$userlist = Get-ADUser sdevito -Properties * | Select-Object -Property Name,SamAccountName,Description,EmailAddress,LastLogonDate,Manager,Title,Department,Company,whenCreated,Enabled,MemberOf | Sort-Object -Property Name
$userlist | ForEach-Object {
$grps = $_.MemberOf | Get-ADGroup | ForEach-Object {$_.Name} | Sort-Object
$arec = $_.Name,$_.SamAccountName,$_.Description,$_.EmailAddress,$_LastLogonDate,$_.Manager,$_.Title,$_.Department,$_.Company,$_.whenCreated,$_.Enabled
$aline = ($arec -join "`t") + "`t" + ($grps -join "`t") + "`n"
$alist += $aline
}
$alist | Out-File C:\Users\sdevito\Desktop\testt.csv
How about something like:
#Requires -Version 3.0
Add-PSSnapin Quest.ActiveRoles.ADManagement
function Get-UsersGroups {
[cmdletbinding()]
param (
[Parameter(Position=0,Mandatory)][string]$Identity,
[Parameter(Position=1)][ValidateSet('all','nested','normal')][string]$MemberType
)
$user = Get-QADUser -Identity $Identity
switch ( $MemberType ) {
'all' { $groups = $user.AllMemberOf }
'nested' { $groups = $user.NestedMemberOf }
default { $groups = $user.MemberOf }
}
foreach ( $group in $groups ) {
$groupinfo = Get-QADGroup -Identity $group
$props = [ordered]#{
Group = $groupinfo.Name
Type = $groupinfo.GroupType
Member = $user.Name
Email = $user.Email
Department = $user.Department
Username = $user.sAMAccountName
}
$obj = New-Object -TypeName PSObject -Property $props
$obj
}
}
Get-UsersGroups -Identity bob | Export-Csv -Path "C:\Users\sdevito\Desktop\test.csv" -NoTypeInformation
New to powershell, and I can't figure out why the SamAccountName column in the output file is empty. while the IsDisabled column has the account status results.
Import-Csv $filename | Foreach-Object{
$user = ([ADSISEARCHER]"(samaccountname=$($_.SamAccountName))").FindOne()
if($user)
{
New-Object -TypeName PSObject -Property #{
SamAccountName = $user.SamAccountName
IsDisabled = $user.GetDirectoryEntry().InvokeGet('AccountDisabled')
}
}
else
{
Write-Warning "Can't find user '$($_.SamAccountName)'"
}
} | Export-Csv $filename
You have to change the 6th line to:
SamAccountName = $user.Properties.samaccountname
You need to specify sAMAccountName as one of the properties to return. In addition you can specify the userAccountControl property and test the ADS_UF_ACCOUNTDISABLE bit to see if the user account is disabled. This will avoid the overhead of binding to each user object to test if disabled. Here is a short sample script:
param(
[String[]] $sAMAccountName
)
$ADS_UF_ACCOUNTDISABLE = 2
$sAMAccountName | foreach-object {
$searcher = [ADSISearcher] "(sAMAccountName=$($_))"
$searcher.PropertiesToLoad.AddRange(#("samaccountname","useraccountcontrol"))
$result = $searcher.FindOne()
if ( $result ) {
$samName = $result.Properties["samaccountname"][0]
$disabled = ($result.Properties["useraccountcontrol"][0] -band
$ADS_UF_ACCOUNTDISABLE) -ne 0
new-object PSObject -property #{
"Name" = $samName
"Disabled" = $disabled
}
} else {
write-warning "Can't find user $_"
}
}
Bill
IIRC this is a known issue (bug) with case-sensitive ldap property names. To avoid that you can use the hashtable syntax and not worry about case:
$user.Properties['SAMACCOUNTNAME']