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
}
}
}