Powershell Compare text and replace if it does not meet specific criteria - powershell
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
Related
powershell to edit multiple users phone numbers in active directory
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 }
Expanding System.Object[] for Export to CSV
Hello again and sorry! To keep it really short. What am i doing wrong? Im attempting to export a list of users filtered by using a customobject to a CSV and it outputs it into the same block. Is there no way to change this? I only ask because, all the other pages ive looked at it keeps telling me to use -join, to join them as strings which does the exact same thing. Is it not possible to output it as multiple rows for each user? $GPMem = Get-ADGroupMember -Identity security.group | Select-Object -ExpandProperty Name [array]$TPpl = $GPMem | Where-Object {$_ -like "T*"} [array]$RPpl = $GPMem | Where-Object {$_ -like "r*"} [array]$CPpl = $GPMem | Where-Object {$_ -like "c*"} [pscustomobject]#{ TPeople = (#($TPpl) |Out-String).Trim() TPCount = $TPpl.Count RPeople = (#($RPpl) |Out-String).ToString() RPCount = $TPpl.Count CPeople = $CPpl CPCount = $TPpl.Count } | Export-Csv -Path C:\Users\abraham\Desktop\csv.csv -NoTypeInformation -Force
here is how to insert a ; OR newline into the values of a column ... [grin] $ThingList = #('One Thing', 'Two Thing', 'Three Thing') $ThingList -join '; ' '=' * 20 $ThingList -join [System.Environment]::NewLine output ... One Thing; Two Thing; Three Thing ==================== One Thing Two Thing Three Thing
create 3 more arrays for the count (each array will be exported to a column), then find the array with the most count and generate a psobject for each line. [array]$TPpl = #("T1" ,"T2", "T3") [array]$TPpl_count = #($TPpl.Count) [array]$RPpl = #("R1" ,"R2", "R3", "R4") [array]$RPpl_count = #($RPpl.Count) [array]$CPpl = #("C1" ,"C2", "C3", "C4","C5") [array]$CPpl_count = #($CPpl.Count) $leng = [array]$TPpl.Count,$RPpl.Count,$CPpl.Count $max = ($leng | measure -Maximum).Maximum $csv = for($i=0;$i -lt $max;$i++){ New-Object -TypeName psobject -Property #{ "TPeople" = $(if ($TPpl[$i]) { $TPpl[$i]}) "TPCount" = $(if ($TPpl_count[$i]) { $TPpl_count[$i]}) "RPeople" = $(if ($RPpl[$i]) { $RPpl[$i]}) "RPCount" = $(if ($RPpl_count[$i]) { $RPpl_count[$i]}) "CPeople" = $(if ($CPpl[$i]) { $CPpl[$i]}) "CPCount" = $(if ($CPpl_count[$i]) { $CPpl_count[$i]}) } } $csv | Export-Csv C:\Temp\test.csv -NoTypeInformation result: your final code should be: $GPMem = Get-ADGroupMember -Identity security.group | Select-Object -ExpandProperty Name [array]$TPpl = $GPMem | Where-Object {$_ -like "T*"} [array]$RPpl = $GPMem | Where-Object {$_ -like "r*"} [array]$CPpl = $GPMem | Where-Object {$_ -like "c*"} [array]$TPpl_count = #($TPpl.Count) [array]$RPpl_count = #($RPpl.Count) [array]$CPpl_count = #($CPpl.Count) $leng = [array]$TPpl.Count,$RPpl.Count,$CPpl.Count $max = ($leng | measure -Maximum).Maximum $csv = for($i=0;$i -lt $max;$i++){ New-Object -TypeName psobject -Property #{ "TPeople" = $(if ($TPpl[$i]) { $TPpl[$i]}) "TPCount" = $(if ($TPpl_count[$i]) { $TPpl_count[$i]}) "RPeople" = $(if ($RPpl[$i]) { $RPpl[$i]}) "RPCount" = $(if ($RPpl_count[$i]) { $RPpl_count[$i]}) "CPeople" = $(if ($CPpl[$i]) { $CPpl[$i]}) "CPCount" = $(if ($CPpl_count[$i]) { $CPpl_count[$i]}) } } $csv | Export-Csv C:\Temp\test.csv -NoTypeInformation
Format Array inside array to later use as an E-Mail body
I create an empty $array early in my script and later i loop over some stuff and want to add this stuff to my array. This works as intended. $AspxFiles = gci $path $filter -r | ? { $_.DirectoryName -notlike '*Werkstatt*' -and ` $_.DirectoryName -notlike '*- Kopie*' -and ` $_.DirectoryName -notlike '*.1*' -and ` $_.DirectoryName -notlike '*.0*' -and ` $_.DirectoryName -notlike '*.2*' -and ` $_.Name -notlike '*- Kopie*' } $array = #() foreach ($file in $AspxFiles) { $getURL = sls -Path $file.FullName -Pattern $regex -AllMatches | ? { $_ -notlike '*www.w3.org*' -and ` $_ -notlike '*jquery.com*' -and ` $_ -notlike '*www.mwe*' } | % { $_.Matches } | % { $_.Value } foreach ($URL in $getURL) { $Request = [System.Net.WebRequest]::Create($URL) $Response = $Request.GetResponse() $Status = [int]$Response.StatusCode if ($Status -ne 200 -or $Response.ResponseUri -like '*PageNotFound*') { $x = [PSCustomObject] #{ File = $file.Name URL = $URL } ; $array += $x } $Response.Close() } } But the output of $array is like this: #{File=B-1.56.aspx; URL=http://sdfsdfsdf/b-1.39.4_fr1_d.pdf} #{File=B-1.56.aspx; URL=http://sdfsdfsdfssd/b-1.39.4_fr1_d.pdf} #{File=B-1.58.aspx; URL=https://sdfffssd/b-1.39.6_de_d.pdf} #{File=B-1.58.aspx; URL=https://fsdfsfb-1.39.6_de_d.pdf} How can I get this formatted like a list so I can grab the File and URL Property to send it as an E-Mail body like this?: $body = $array | sort File | ConvertTo-Html -Property File,URL -Head "<html><h2>Folgende Links wurden im Katalog nicht gefunden:</h2><br></html>" | Out-String
Looks like this is still only a part of your script but: I'd transform your anded wildcards into a -notmatch RegEx with OR'ed | entries and set $array = Foreach($file ... gathering all ouput $REDir = '.*Werkstatt.*|.*- Kopie.*|.*\.[012].*' $REURL = '.*www\.w3\.org.*|.*jquery\.com.*|.*www.mwe.*' $AspxFiles = Get-ChildItem $path $filter -r | Where-Object { $_.DirectoryName -notmatch $REDir -and ` $_.Name -notlike '*- Kopie*'} $array = #() $array = foreach ($file in $AspxFiles) { $getURL = Select-String -Path $file.FullName -Pattern $regex -AllMatches | Where-Object { $_ -notmatch $REURL } | ForEach-Object { $_.Matches } | ForEach-Obkect { $_.Value } ForEach ($URL in $getURL) { $Request = [System.Net.WebRequest]::Create($URL) $Response = $Request.GetResponse() $Status = [int]$Response.StatusCode if ($Status -ne 200 -or $Response.ResponseUri -like '*PageNotFound*') { [PSCustomObject] #{ File = $file.Name URL = $URL } } $Response.Close() } } $body = $array | Sort-Object File | ConvertTo-Html -Property File,URL -Head ` "<html><h2>Folgende Links wurden im Katalog nicht gefunden:</h2><br></html>" | Out-String
Export only the machines that meets criteria
I have a script that works great but I would like to only export the machines that meet one of the three conditions in the foreach statement. Right now it exports all the machines, which I have to clean up manually in excel. #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=thomsonreuters,DC=com") #Pass in the ceriteria we are searching for. #In this case we're looking for computers that are enabled and running Windows 7 $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) } }, #{ n = 'DistinguishedName'; e = { $_.DistinguishedName } }, #{ n = 'extensionattribute7'; e = { $_.extensionattribute7 } }, #{ n = 'extensionattribute1'; e = { $_.extensionattribute1 } }, #{ n = 'NewComputerName'; e = { 'Filler' } } | 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}$') -and ($row.CN -notmatch '\d{3}')) { $row.NewComputerName = $row.extensionattribute7 + "-TPL-ZZ" } elseif (($row.CN -notmatch '^U\d{7}') -and ($row.DistinguishedName -like "*Desktops*") -and ($row.extensionattribute7 -match '^U\d{7}$') -and ($row.CN -notmatch '\d{3}')) { $row.NewComputerName = $row.extensionattribute7 + "-TPD-ZZ" } elseif (($row.CN -notmatch '^U\d{7}') -and ($row.DistinguishedName -like "*Virtual*") -and ($row.extensionattribute7 -match '^U\d{7}$') -and ($row.CN -notmatch '\d{3}')) { $row.NewComputerName = $row.extensionattribute7 + "-TPV-ZZ" } } $csv | export-csv c:\temp\fixed.csv -NoTypeInformation -Force
Try this: $csv = $csv | where { ($_.CN -notmatch '^U\d{7}') -and ($_.CN -notmatch '\d{3}') -and ($_.extensionattribute7 -match '^U\d{7}$') -and (($_.DistinguishedName -like "*Laptops*") -or ($_.DistinguishedName -like "*Desktops*") -or ($_.DistinguishedName -like "*Virtual*")) } Before the final line. It should filter out any ones that haven't met any of the criteria in the foreach loop
How to pipe foreach output to export-csv
The code below outputs the following. TYPE System.String Length 100 How can I get it to actually output the content of the strings? $fileIn | % { $array = $_.split(" ") if ($array[0] -eq "User") { $name = $array[1]+"."+$array[2] $remaining = "" for ($i = 3; $i -ne $array.length; $i++) {$remaining+=$array[$i]+" "} Get-ADUser $name -properties description, company | % { $name + " - " + $remaining + " - " + $_.description + " - " + $_.company | Export-CSV $output} } }
Export-CSV is for exporting objects with properties to csv. You're trying to export a single string, which only includes a value and a Length property. Also, - is not a valid delimiter in csv(at least not in .NET). The type information can be removed with a -NoTypeInformation-switch. Try this: $fileIn | % { $array = $_.split(" ") if ($array[0] -eq "User") { $name = $array[1]+"."+$array[2] $remaining = "" for ($i = 3; $i -ne $array.length; $i++) {$remaining+=$array[$i]+" "} Get-ADUser $name -properties description, company | % { New-Object psobject -Property #{ "Name" = $name "Remaining" = $remaining "Description" = $_.Description "Company" = $_.Company } } } } | Select-Object Name, Remaining, Description, Company | Export-CSV $output -Delimiter ';' -NoTypeInformation I tried to understand what you where trying to do here. To give you a summary of the changes: I'm creating an object containing the information you want to export, for every row in your $filein I'm setting the order of the properties with select-object AFTER an object for every line in $filein has been created I'm exporting the array of objects to a csv-file with delimiter ; (just to show how you specify it), and without the type-information at the start. If you use export-csv inside the foreach loop, it would overwrite the file every time and you'd just have one row + header-row in the end. In PS3.0 you could have done it inside the loop, using -Append switch. EDIT If you really need the string format, you need to use something else then Export-CSV, ex. Out-File with -Append switch. Ex: $fileIn | % { $array = $_.split(" ") if ($array[0] -eq "User") { $name = $array[1]+"."+$array[2] $remaining = "" for ($i = 3; $i -ne $array.length; $i++) {$remaining+=$array[$i]+" "} Get-ADUser $name -properties description, company | % { "$name - $remaining - $($_.description) - $($_.company)" | Out-File -Append $output } } }