stefank007
Goto Top

Telefonnummern im Active Directory per Powershell formatieren bzw. vereinheitlichen

Hallo,

ich habe den Auftrag bekommen die Formatierung sämtlicher Telefon/Faxnummern aller Benutzer in unserer Windows 2008 R2 Domäne zu ändern, damit diese aus der Active Directory entsprechend in den Signaturen gezogen werden.

Ich dachte mir, dass ich einen String nehme und diesen durch die neue Formatierung ersetze.
Alter String: +49 (0)123-456789-
Neuer String: +49 123 456789-

Hinter den Strings ist noch jeweils eine 4 stellige Durchwahl.

Exchange 2010 SP1 und damit die entsprechenden Powershell Befehle "get-user" und "set-user" sind vorhanden!

Wie kann ich hier mittels Powershell am besten vorgehen?

Viele Grüße
Stefan

Content-Key: 180245

Url: https://administrator.de/contentid/180245

Ausgedruckt am: 28.03.2024 um 15:03 Uhr

Mitglied: blackhawk17
blackhawk17 21.05.2017 um 18:56:34 Uhr
Goto Top
hallo,
hast du hierzu mal eine Lösung gefunden?
Mitglied: colinardo
Lösung colinardo 23.05.2017, aktualisiert am 17.02.2023 um 22:43:39 Uhr
Goto Top
Zitat von @blackhawk17:
hast du hierzu mal eine Lösung gefunden?
Servus @blackhawk17 / @StefanK007 ,
auch wenn der Beitrag schon ein paar Jahre auf dem Buckel hat, poste ich hier mal eine umfassende Lösung da hier immer wieder die Anfrage zum Thema kommt.

Ich mache das immer mit meinem folgendem Script. Es erkennt den Ländercode sowie deutsche Vorwahlen (inkl. Handynetze) automatisch (selbst wenn keine Trennzeichen dazwischen verwendet wurden!) und formatiert die Nummern per Default im DIN-Format
+[COUNTRYCODE] [AREACODE [SUBSCRIBER]-[EXTENSION]
Das Format lässt sich aber per CMDLet-Parameter (-format) und Platzhaltern nach eigenen Bedürfnissen anpassen.
Sonderzeichen außer Nummern und + werden aus den Nummern entfernt.
Den Default-Country-Code welcher eingesetzt wird wenn eine Nummer keinen Ländercode beinhaltet kannst du im Skript in Zeile 5 angeben.
Ebenfalls lässt sich im Array $attributes die Liste der LDAP Attribute festlegen welche das Skript untersuchen und ändern soll.

Den Download des Skriptes gibt es hier:

back-to-topformat_phone_numbers_180245.zip


Viel Spaß beim Anwenden
Grüße Uwe
Mitglied: blackhawk17
blackhawk17 23.05.2017 um 13:20:19 Uhr
Goto Top
was für ein Hammer Skript genau das habe ich gesucht face-smile
Mitglied: colinardo
colinardo 23.05.2017, aktualisiert am 17.02.2023 um 22:45:56 Uhr
Goto Top
Freut mich wenn es hilft face-smile.
Mitglied: blackhawk17
blackhawk17 23.05.2017 um 13:31:12 Uhr
Goto Top
Gerne face-smile

Sag mal, wenn ich die Klammern () in der Vorwahl behalten möchte, wäre das nen riesen Aufwand die ins Skript wieder rein zu nehmen?

Dann würde eine Nummer z.B. so ausschauen +49 (170) 1234567

vg
Blackhawk
Mitglied: colinardo
colinardo 23.05.2017 aktualisiert um 13:43:16 Uhr
Goto Top
Zitat von @blackhawk17:
Sag mal, wenn ich die Klammern () in der Vorwahl behalten möchte, wäre das nen riesen Aufwand die ins Skript wieder rein zu nehmen?
Nein, kein Problem, ändere Zeile 52 so ab
$acode = "(" + $acode.Substring(0,$_) + ")"  
Mitglied: blackhawk17
blackhawk17 23.05.2017 um 14:01:11 Uhr
Goto Top
ups da ist das face-smile hatte gedacht, dass das im oberen Teil ab Zeile 38 gemacht würde.

Ich muss mich da nochmal mehr mit Regex auseinandersetzen.

Vielen Dank für deine Hilfe. Das Skript kann man jetzt ja auch noch für Vorwahlen anderer Länder anpassen face-smile.

Wirklich Top
Mitglied: blackhawk17
blackhawk17 23.05.2017 um 14:19:34 Uhr
Goto Top
Sorry ich muss nochmal was fragen face-sad

Nach der Vorwahl bei Festnetztelefonen kommt ja meistens die Anschlussnummer z.B: 123 und dann die Durchwahl 456

z.B. +49 (4888) 123456 so wäre es jetzt, man sieht die Durchwahl nicht mehr.

z.B. +49 (4888) 123-456 das aber allgemein zu programmieren halte ich für schwierig, da einige ja vielleicht auch mehr als 3 Zahlen haben werden.

Könnte man nicht sagen "alles was nach der Ortsvorwahl kommt" bleibt so stehen? Dann hätte man die Durchwahl auch immer schön mit drin?

Wäre das in deinem Skript $rest oder machst du das über den regex Schlüssel? Das erschließt sich mir noch nicht ob ich das evtl. schnell selbst anpassen kann.

vg
Mitglied: pixel0815
pixel0815 24.05.2017 um 08:19:45 Uhr
Goto Top
Das wäre genial. Vielleicht eine Varible für die Anzahl der Nummern für die Durchwahl. Drei oder vierstellung :o)
Mitglied: colinardo
colinardo 24.05.2017, aktualisiert am 17.02.2023 um 22:52:50 Uhr
Goto Top
Zitat von @pixel0815:

Das wäre genial. Vielleicht eine Varible für die Anzahl der Nummern für die Durchwahl. Drei oder vierstellung :o)

Hatte ich ihm schon per PN geschickt

#Edit# Skript beinhaltet jetzt per Default auch Extensions, der untere Schnippel ist daher nicht mehr gültig
Zeile 57 folgendes rein quetschen:
# extension
    if(($number.trim() -match '\b(\d+)$')){  
        if ($rest.length -gt 0){
            $rest = $rest.SubString(0,$rest.length - $matches[1].length) + $matches
        }else{
            $acode = $acode.SubString(0,$acode.length - $matches[1].length) + $matches
        }
    }

Grüße Uwe
Mitglied: pixel0815
pixel0815 24.05.2017 um 09:12:50 Uhr
Goto Top
Ok, hab ich gemacht.

Beispiel:

Number Old value New value
--------- ---------
telephoneNumber +49 1234 234 444 +49 1234 234444

So kommt die Nummer trotzdem raus. Sollte diese nicht gleich bleiben?
Mitglied: colinardo
colinardo 24.05.2017 aktualisiert um 09:19:26 Uhr
Goto Top
So kommt die Nummer trotzdem raus. Sollte diese nicht gleich bleiben?
Nein, oben war nur die Rede von der Extension, nicht von Leerzeichen!
Mitglied: pixel0815
pixel0815 24.05.2017 um 09:20:13 Uhr
Goto Top
face-big-smile Stimmt, ist noch der erste Kaffee heute.
Mitglied: blackhawk17
blackhawk17 26.05.2017 um 11:51:02 Uhr
Goto Top
Habe irgendwie was komisches.

Das Skript läuft los, macht auch ne ganze Reihe an Korrekturen und dann bricht es mit einmal ab.

Folgende Meldung:

get-aduser : Vom Server wurde der folgende Fehler zurückgegeben: Ungültiger Aufzählungskontext.
In Zeile:70 Zeichen:1

back-to-topget-aduser -Filter * -ResultSetSize $null -Properties $attributes -PipelineVaria ...

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : NotSpecified: (face-smile [Get-ADUser], ADException
+ FullyQualifiedErrorId : Vom Server wurde der folgende Fehler zurückgegeben: Ungültiger Aufzählungskontext.,Microsoft.ActiveDirectory.Management.Commands.GetADUser


War das nun zu viel für ihn? Kann die Meldung irgendwie nicht deuten.

Hast du nochmal einen Tipp für mich?

vg face-smile
Mitglied: colinardo
colinardo 26.05.2017 aktualisiert um 11:59:05 Uhr
Goto Top
Machst du das Remote per RSAT und hast mehrere tausend User? Dann schlägt hier vermutlich das Throttling zu und du solltest die -ResultPageSize Property bei Get-ADUser aktiv nutzen, oder pro OU in kleineren Steps durchlaufen.
Mehr dazu steht hier:
https://social.technet.microsoft.com/wiki/contents/articles/32418.active ...
Mitglied: blackhawk17
blackhawk17 26.05.2017 um 12:33:48 Uhr
Goto Top
joa es sind schon ein paar User mehr face-smile Lasse halt das komplette AD einmal durchlaufen face-smile
Mitglied: blackhawk17
blackhawk17 26.05.2017 um 12:50:14 Uhr
Goto Top
Der Befehl müsste dann doch eigentlich so heißen oder nicht?

get-aduser -Filter * -ResultSetSize 5000 -Properties $attributes -PipelineVariable user | ?{($attributes | ?{$user.$_ -match '\d+'})} | %{
$changed = @{}

den $null sind ja nur 256 Objekte ich brauche aber mehr.
Mitglied: blackhawk17
blackhawk17 26.05.2017 um 13:03:30 Uhr
Goto Top
sorry so geht's face-smile

get-aduser -Filter * -ResultPageSize 5000 -Properties $attributes -PipelineVariable user | ?{($attributes | ?{$user.$_ -match '\d+'})} | %{
$changed = @{}
Mitglied: colinardo
colinardo 26.05.2017 aktualisiert um 13:05:27 Uhr
Goto Top
Nein, die Seite oben solltest du mal aufmerksamer lesen. In deinem Fall braucht er einfach zu lange für die Pipeline was dann zu einem Timeout führt.
Also speichere die AD-User am einfachsten vorher in einer Variablen dann führt das zu keinem Timeout weil er alle Objekte schon im Voraus geladen hat.
Retrieve your Active Directory objects to a variable first, then send it down the pipeline using the variable. This method is easy to implement in your code without lots of configuration changes in your Active Directory environment. It works because writing the objects to a variable is very fast so your Get-ADUser and Get-ADComputer cmdlets can quickly write all object to the variable and request the next page until all object are received. 

$users = get-aduser -Filter * -ResultSetSize $null -Properties $attributes 
$users | ?{$user = $_;($attributes | ?{$user.$_ -match '\d+'})} | %{   
    $user = $_
# ......
# .......
Mitglied: blackhawk17
blackhawk17 29.05.2017 aktualisiert um 11:44:11 Uhr
Goto Top
Hallo,

kann ich es nicht auch so machen ? :
get-aduser -Filter * -SearchBase "Firma 123,OU=Benutzer,DC=contoso,DC=com" -ResultSetSize $null -Properties $attributes -PipelineVariable user | ?{($attributes | ?{$user.$_ -match '\d+'})} | %{  

Das hat einmal geklappt für eine OU bei der nächsten sagt er mir jetzt:
get-aduser : The object name has bad syntax
At C:\Telefon.ps1:70 char:1
+ get-aduser -Filter * -SearchBase "XXX GmbH,OU=Corporate Group,DC=XXX, ...  
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-ADUser], ADException
    + FullyQualifiedErrorId : ActiveDirectoryServer:8335,Microsoft.ActiveDirectory.Management.Commands.GetADUser
Mitglied: colinardo
colinardo 29.05.2017 aktualisiert um 11:47:23 Uhr
Goto Top
-SearchBase "Firma 123
Das ist kein valider DN! Dir fehlt das "OU=" davor. Sagt dir auch die Fehlermeldung schon ==>
The object name has bad syntax
Muss ich wieder Kaffeeersatz spielen face-smile?!

http://www.selfadsi.de/ldap-path.htm
Mitglied: blackhawk17
blackhawk17 29.05.2017 um 11:49:22 Uhr
Goto Top
ohm pft... sorry das hatte ich durchs rein kopieren überschrieben.

Sorry face-sad
Mitglied: lordofremixes
lordofremixes 03.08.2018 um 13:51:20 Uhr
Goto Top
Uwe bester Mann. Gleich mal ausgeführt...
Mitglied: aehrfoordt
aehrfoordt 26.09.2022 um 15:00:15 Uhr
Goto Top
Hallo Ihr lieben Leute, ich bin der Neue :D

ich verwalte zusammen mit einem Kollegen eine AD mit ca. 400 Leuten.

Nun habe auch ich genau die Aufgabe bekommen. Die Telefonnummern sollen formatiert werden.
Sie liegen in allen möglichen Eingabevarianten vor.

Soweit ich das hier überblicke ist das Script hier die Antwort auf meine Frage.

Bislang hatte ich bei Verwalten von kleinen Netzen keinen Anlass die PowerShell zu nutzen und dementsprechend keine tiefen Power-Shell Vorkenntnisse.

Mich interessiert zu dem Script - Beispiel hier, wie ich sicherstellen kann, daß das Script auf eine bestimmte OU angewendet wird. (z.B.) um aus Vorsichtsgründen in einer Test-OU zu proben.

Ich erhoffe mir nicht mühseelig die 400 Accounts bearbeiten zu müssen , dafür ist die Powershell ja da. face-big-smile

herzlichste Grüße
Mitglied: colinardo
colinardo 26.09.2022 aktualisiert um 15:23:46 Uhr
Goto Top
Servus @aehrfoordt, willkommen auf Administrator.de!
Mich interessiert zu dem Script - Beispiel hier, wie ich sicherstellen kann, daß das Script auf eine bestimmte OU angewendet wird. (z.B.) um aus Vorsichtsgründen in einer Test-OU zu proben.
Zeile 66 einfach den DN der OU mittels -SearchBase Parameter angeben
get-aduser -Filter * -ResultSetSize $null -Properties $attributes -SearchBase 'OU=Verwaltung,DC=mydomain,DC=de' -PipelineVariable user  
Der Rest in der Zeile bleibt natürlich gleich.
Damit du auch was dazu lernst :Get-AdUser

Grüße Uwe

Powershell Leitfaden für Anfänger
Mitglied: aehrfoordt
aehrfoordt 26.09.2022 um 16:17:36 Uhr
Goto Top
Vielen Dank,

"Damit du auch was dazu lernst :Get-AdUser"

wird sorgfältig studiert und zum üben in der Trainings-AD verwendet face-big-smile

mfg

Aehrfoordt
Mitglied: aehrfoordt
aehrfoordt 29.09.2022 um 13:54:03 Uhr
Goto Top
Rückmeldung:

Erster Versuch in einer Test - OU auf meinem Trainings - DC Erfolg
Anwendung auf die gesamte Trainings - AD - Erfolg

Zweiter Versuch in der Produktiv - AD Test - OU - Erfolg
Anwendung auf die Gesamte AD - Erfolg

Das hat mir das Editieren von ca 2000 Einträgen erspart und laut Ausgabe ist nirgendwo eine falsche Nummer herausgekommen.

Herzlichsten Dank nochmal face-smile
Mitglied: colinardo
colinardo 29.09.2022 aktualisiert um 15:04:37 Uhr
Goto Top
So muss das sein 👍. Freut mich für dich 🙂.

Grüße Uwe
Mitglied: pixel0815
pixel0815 17.02.2023 um 11:28:44 Uhr
Goto Top
Welche Regex muss ich da anpassen wenn ich möchte das die Durchwahl erkennbar ist?
Ich krieg es einfach nicht hin.
    # extension
    if(($number.trim() -match '\-(\d+)$')){  
        if ($rest.length -gt 1){
            $rest = $rest.SubString(0,$rest.length - $matches[1].length) + $matches
        }else{
            $acode = $acode.SubString(0,$acode.length - $matches[1].length) + $matches
        }
    }
    # return formatted number
    return "+$ccode $acode $rest".trim()  
Mitglied: colinardo
colinardo 17.02.2023 aktualisiert um 23:17:09 Uhr
Goto Top
Das aktualisierte Skript (17.02.2023) beinhaltet nun auch Extension-Abgrenzung und das Format ist jetzt der Einfachheit halber über die Platzhalter
[[COUNTRYCODE]]
[[AREACODE]]
[[SUBSCRIBER]]
[[EXTENSION]]
und einen Format-String im Parameter -format des CMDLets steuerbar.
Zusätzlich können die minimale und maximale Länge für die Erkennung der Extension über zwei Parameter gesteuert werden, im Default minimal=1 und maximal=4 Digits, eine Abgrenzung der Extension per Leerzeichen/Dash/Slash oder anderen Abgrenzungszeichen muss aber in der Originalnummer vorhanden sein.

Des weiteren bietet die Funktion jetzt auch direkten Pipeline-Support für mehrere Nummern auf einen Rutsch.

    param(
        # number to normalize
        [Parameter(mandatory=$true,ValueFromPipeline=$true)][ValidateNotNullOrEmpty()][string[]]$number,
        # default country code for numbers without it
        [Parameter(mandatory=$false)][string]$DefaultCountryCode = '49',  
        # number output format, supported placeholders (case sensitive): [[COUNTRYCODE]],[[AREACODE]],[[SUBSCRIBER]],[[EXTENSION]]
        [Parameter(mandatory=$false)][string]$format = '+[[COUNTRYCODE]] [[AREACODE]] [[SUBSCRIBER]]-[[EXTENSION]]',  
        # specify min number of digits for detecting extensions
        [Parameter(mandatory=$false)][int]$extension_min_digits = 1,
        # specify max number of digits for detecting extensions
        [Parameter(mandatory=$false)][int]$extension_max_digits = 4
    )
Grüße Uwe
Mitglied: pixel0815
pixel0815 24.04.2023 aktualisiert um 16:14:53 Uhr
Goto Top
Zitat von @colinardo:

Das aktualisierte Skript (17.02.2023) beinhaltet nun auch Extension-Abgrenzung und das Format ist jetzt der Einfachheit halber über die Platzhalter
[[COUNTRYCODE]]
[[AREACODE]]
[[SUBSCRIBER]]
[[EXTENSION]]
und einen Format-String im Parameter -format des CMDLets steuerbar.
Zusätzlich können die minimale und maximale Länge für die Erkennung der Extension über zwei Parameter gesteuert werden, im Default minimal=1 und maximal=4 Digits, eine Abgrenzung der Extension per Leerzeichen/Dash/Slash oder anderen Abgrenzungszeichen muss aber in der Originalnummer vorhanden sein.

Des weiteren bietet die Funktion jetzt auch direkten Pipeline-Support für mehrere Nummern auf einen Rutsch.

    param(
        # number to normalize
        [Parameter(mandatory=$true,ValueFromPipeline=$true)][ValidateNotNullOrEmpty()][string[]]$number,
        # default country code for numbers without it
        [Parameter(mandatory=$false)][string]$DefaultCountryCode = '49',  
        # number output format, supported placeholders (case sensitive): [[COUNTRYCODE]],[[AREACODE]],[[SUBSCRIBER]],[[EXTENSION]]
        [Parameter(mandatory=$false)][string]$format = '+[[COUNTRYCODE]] [[AREACODE]] [[SUBSCRIBER]]-[[EXTENSION]]',  
        # specify min number of digits for detecting extensions
        [Parameter(mandatory=$false)][int]$extension_min_digits = 1,
        # specify max number of digits for detecting extensions
        [Parameter(mandatory=$false)][int]$extension_max_digits = 4
    )
Grüße Uwe

Hallo Uwe,

ich hab das Skript gekauft und es funktioniert wunderbar - bis auf einige Ausnahmen.
Im AD steht unter der Telefonnummer zum Beispiel 012345 4445000
Lasse ich das Skript laufen, erscheint dann folgendes


Korrigiere Nummern für 'xxxxx' 'xxxxx'

Number          Old value    New value      
------          ---------    ---------      
telephoneNumber 012345 4445000 +49 12345 4445000

Die 4 Stellige Extension wird nicht erkannt. Toll wäre, wenn man auch die Rumpfrufnummer einstellen kann. Also z.b. 3 Stellig etc. Ist das sinnvoll?

Einstellungen sind wie folgt

        # number to normalize
        [Parameter(mandatory=$true,ValueFromPipeline=$true)][ValidateNotNullOrEmpty()][string[]]$number,
        # default country code for numbers without it
        [Parameter(mandatory=$false)][string]$DefaultCountryCode = '49',  
        # number output format, supported placeholders (case sensitive): [[COUNTRYCODE]],[[AREACODE]],[[SUBSCRIBER]],[[EXTENSION]]
        [Parameter(mandatory=$false)][string]$format = '+[[COUNTRYCODE]] [[AREACODE]] [[SUBSCRIBER]]-[[EXTENSION]]',  
        # specify min number of digits for detecting extensions
        [Parameter(mandatory=$false)][int]$extension_min_digits = 1,
        # specify max number of digits for detecting extensions
        [Parameter(mandatory=$false)][int]$extension_max_digits = 4
Mitglied: colinardo
colinardo 24.04.2023 aktualisiert um 17:18:41 Uhr
Goto Top
Servus.
Die 4 Stellige Extension wird nicht erkannt.
Du hast scheinbar meinen Hinweis dazu nicht gelesen. Im Wortlaut:
Zitat von @colinardo:
Eine Abgrenzung der Extension per Leerzeichen/Dash/Slash oder anderen Abgrenzungszeichen muss aber in der Originalnummer vorhanden sein.
Extensions werden also nur angewendet wenn diese vorher schon vom Rest durch ein Boundary-String (in Regex: \b) abgetrennt waren.
Ist das bei dir nicht der Fall entferne das \b aus dem Regex dieser Zeile, dann werden Extensions auch angewendet wenn vorher kein Trennzeichen vorhanden war.
if ($num.trim() -match "(\b{$extension_min_digits,$extension_max_digits})$"){  

Grüße Uwe