Bei Event funktioniert das Powershell Script nicht richtig
Hallo liebe Community,
ich habe hier ein Powershell Script geschrieben, dass bei der Erstellung eines User in einer OU automatisch eine Gruppe mit dem Namen der OU erstellt und ihn dann der Gruppe hinzufügt.
Dann noch ein Script, wenn ein User in eine andere OU verschoben wird, dass er dann aus der alten Gruppe gelöscht wird und einer neuen hinzugefügt wird.
Das erste Script funktioniert, das zweite ab und zu mal, ich konnte noch nicht wirklich feststellen warum es manchmal funktioniert und manchmal nicht.
Manuel ausführen funktioniert immer, das Ausführen nach einem Event dagegen sporadisch.
Ausgeführt wird das auf einem DC.
Hier ist der Code, wenn der Benutzer verschoben wurde.
Ich bin ratlos, irgendwie habe ich den Verdacht dass diese Zeile dafür verantwortlich ist:
Remove-ADGroupMember -Identity $OldGroupName -Members $user -Confirm: $false
Manchmal wird der Benutzer der neuen Gruppe hinzugefügt aber nicht aus der alten gelöscht. Meistens aber aber passiert nichts und selten wird die alte Gruppe gelöscht und neue hinzugefügt.
Irgendwie veräppelt mich Windows ganz schön.
Liebe Grüße
ich habe hier ein Powershell Script geschrieben, dass bei der Erstellung eines User in einer OU automatisch eine Gruppe mit dem Namen der OU erstellt und ihn dann der Gruppe hinzufügt.
Dann noch ein Script, wenn ein User in eine andere OU verschoben wird, dass er dann aus der alten Gruppe gelöscht wird und einer neuen hinzugefügt wird.
Das erste Script funktioniert, das zweite ab und zu mal, ich konnte noch nicht wirklich feststellen warum es manchmal funktioniert und manchmal nicht.
Manuel ausführen funktioniert immer, das Ausführen nach einem Event dagegen sporadisch.
Ausgeführt wird das auf einem DC.
Hier ist der Code, wenn der Benutzer verschoben wurde.
function GetCityName($City)
{
switch($City)
{
"Berlin" {return "BER"}
"München" {return "MUN"}
"London" {return "LON"}
"Madrid" {return "MAD"}
"Paris" {return "PAR"}
"Warschau" {return "WAR"}
default { return $false}
}
}
function GetGroupName($OuName)
{
$groupName = ""
$OuArray = $OuName.Split(",")
$City = GetCityName($OuArray[-6].Split("=")[1])
if($City -eq $false)
{
return $false
}
$specialGroup = ""
$department = ""
if($OuArray[-7].Split("=")[1] -eq "Special Groups")
{
$specialGroup = "SP"
$groupName = "GRP_" + $City + "_" + $specialGroup
for($counter = $OuArray.Count - 8; $counter -ge 0; $counter--)
{
$item = $OuArray[$counter].Split("=")[1]
$groupName = $groupName + "_" + $item
}
}
else
{
#$department = $OuArray[-7].Split("=")[1]
$groupName = "GRP_" + $City
for($counter = $OuArray.Count - 7; $counter -ge 0; $counter--)
{
$item = $OuArray[$counter].Split("=")[1]
$groupName = $groupName + "_" + $item
}
}
return $groupName
}
$BaseOu = "OU=Firma,DC=intern,DC=firma,DC=de"
$message = Get-EventLog -LogName security -InstanceId 5139 -Newest 1 | select message | Format-List | Out-String #Benutzer erstellt
#$user = ([regex]::Match($message,'Account Name:(.*)').NextMatch().groups[1].Value).Trim("")
$objectClass = ([regex]::Match($message,'Class:(.*)').Value).Trim("")
$objectClass = $objectClass.Split(":")[1].Trim(" ")
if($objectClass -ne "user")
{
Exit
}
$OldOu = ([regex]::Match($message,'Old DN:(.*)').Value).Trim("")
$OldOu = $OldOu.Split(":")[1].Trim(" ")
$OldOu = $OldOu.Remove(0, $OldOu.IndexOf(',',0)+1)
$OldOu = $OldOu.Remove(0, $OldOu.IndexOf(',',0)+1)
if($OldOu -eq $null -or $OldOu -eq "")
{
Exit
}
$NewOu = ([regex]::Match($message,'New DN:(.*)').Value).Trim("")
$NewOu = $NewOu.Split(":")[1].Trim(" ")
$NewOu = $NewOu.Remove(0, $NewOu.IndexOf(',',0)+1)
$NewOu = $NewOu.Remove(0, $NewOu.IndexOf(',',0)+1)
if($NewOu -eq $null -or $NewOu -eq "")
{
Exit
}
$userGUID = ([regex]::Match($message,'GUID:(.*)').Value).Trim("")
$userGUID = $userGUID.Split(":")[1].Trim(" ")
$userGUID = $userGUID.Trim("{")
$userGUID = $userGUID.Trim("}")
$user = Get-ADUser -Identity $userGUID
#Write-Host $userGUID
#Write-Host $user
#Write-Host $message
$OldGroupName = GetGroupName($OldOu)
$NewGroupName = GetGroupName($NewOu)
if($NewGroupName -eq $false)
{
Exit
}
if(Get-ADPrincipalGroupMembership $user | select name | where name -eq $OldGroupName)
{
Remove-ADGroupMember -Identity $OldGroupName -Members $user -Confirm: $false
}
if((Get-ADGroup -SearchBase $BaseOu -Filter * | select name | where name -eq $NewGroupName) -ne $true)
{
New-ADGroup -Name $NewGroupName -Path $NewOu -GroupCategory Security -GroupScope Global
}
Add-ADGroupMember -Identity $NewGroupName -Members $user
Ich bin ratlos, irgendwie habe ich den Verdacht dass diese Zeile dafür verantwortlich ist:
Remove-ADGroupMember -Identity $OldGroupName -Members $user -Confirm: $false
Manchmal wird der Benutzer der neuen Gruppe hinzugefügt aber nicht aus der alten gelöscht. Meistens aber aber passiert nichts und selten wird die alte Gruppe gelöscht und neue hinzugefügt.
Irgendwie veräppelt mich Windows ganz schön.
Liebe Grüße
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 354603
Url: https://administrator.de/contentid/354603
Ausgedruckt am: 21.11.2024 um 21:11 Uhr
14 Kommentare
Neuester Kommentar
Moin,
dem Script fehlt's an Fehlerbehandlung... Bau um die "kritschen" Befehle einen Try...Catch block 'rum und lass dir dann evtl. Fehlermeldungen in ein Logfile oder ins Eventlog schreiben.
Ich tippe auf ein Timing-Problem. Ggfs. "spricht" das Script mit einem DC, dem die neuen User/Gruppen noch nicht repliziert wurden - gibt doch mal bei den *-AD* Cmdlets die "-Server" Option mit an.
lg,
Slainte
dem Script fehlt's an Fehlerbehandlung... Bau um die "kritschen" Befehle einen Try...Catch block 'rum und lass dir dann evtl. Fehlermeldungen in ein Logfile oder ins Eventlog schreiben.
Ich tippe auf ein Timing-Problem. Ggfs. "spricht" das Script mit einem DC, dem die neuen User/Gruppen noch nicht repliziert wurden - gibt doch mal bei den *-AD* Cmdlets die "-Server" Option mit an.
lg,
Slainte
Hi,
als erstes würde ich eine Protokolierung einbauen. Lass das Script jeden seiner Schritte in ein Logfile schreiben. Mit Angabe der Daten, wie z.B. $OldOU, $NewOU usw.
z.B. Zeile 88:
Damit bekommst Du heraus, wo er aufhört oder wo ein Fehler auftritt. Alles andere ist doch nur Stochern im Dunkeln.
E.
als erstes würde ich eine Protokolierung einbauen. Lass das Script jeden seiner Schritte in ein Logfile schreiben. Mit Angabe der Daten, wie z.B. $OldOU, $NewOU usw.
z.B. Zeile 88:
'Abbruch weil NewOU leer' | Out-File -FilePath Pfad_zum_Log -append
und selten wird die alte Gruppe gelöscht und neue hinzugefügt.
Gruppe löschen? Oder meinst Du, Benutzer aus der Gruppe entfernen?E.
Zitat von @canlot:
Danke euch,
ich bin einen kleinen Tacken weiter gekommen.
Try Catch Blocks halfen nicht, es kam zu keinem Fehler.
Ich habe aber herausgefunden das $NewOu und $OldOu LEER sind.
Die große Preisfrage ist warum.
Das hier ist ja auch Blödsinn ...Danke euch,
ich bin einen kleinen Tacken weiter gekommen.
Try Catch Blocks halfen nicht, es kam zu keinem Fehler.
Ich habe aber herausgefunden das $NewOu und $OldOu LEER sind.
Die große Preisfrage ist warum.
$message = Get-EventLog -LogName security -InstanceId 5139 -Newest 1 | select message | Format-List | Out-String #Benutzer erstellt
Dazu "subscribed" man das Event oder übergibt im Task-Trigger die passende Variable an das Skript!
Hier steht wie sowas geht (natürlich übertragen auf deine Events)
Windows 2012 R2 RDP-Server - Skript bei Disconnect und Reconnect
Windows 2012 R2 RDP-Server - Skript bei Disconnect und Reconnect
Servus,
das Skript habe ich jetzt nicht im Detail durgesehen, aber ich würde auch dazu raten die Parameter über den Tasktrigger zu übermitteln, dazu passt du die zu übermittelten Variablen wie im Link von @specht zu sehen ist im Tasktrigger-XML an.
Die Variablen stehen im Abschnitt <ValueQueries>.
Hier ein Beispiel wie du die Daten des Events an ein Powershell-Skript via Parameter übermittelst:
(Achtung XML-Datei als Unicode speichern und dann importieren!)
Und nutzen kannst du die Variablen dann so in einem PS-Skript:
Alternativ kann man natürlich auch das Eventlog über ein PS-Skript überwachen. Das müsste dann aber ständig laufen damit die Events dort abgefangen werden können, insofern ist hier ein Tasktrigger die bessere Wahl.
Btw. wenn du es unbedingt via Get-Eventlog auslesen willst wäre
oder auch
die schönere Variante (Bsp zum Auslesen den Usernames bei Useranlage), als erst als Format-Table, dann als String und dann noch mit Regex zu extrahieren, das ist doch sehr unschön .
Grüße Uwe
das Skript habe ich jetzt nicht im Detail durgesehen, aber ich würde auch dazu raten die Parameter über den Tasktrigger zu übermitteln, dazu passt du die zu übermittelten Variablen wie im Link von @specht zu sehen ist im Tasktrigger-XML an.
Die Variablen stehen im Abschnitt <ValueQueries>.
Hier ein Beispiel wie du die Daten des Events an ein Powershell-Skript via Parameter übermittelst:
(Achtung XML-Datei als Unicode speichern und dann importieren!)
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2017-11-13T15:57:48.6636923</Date>
</RegistrationInfo>
<Triggers>
<EventTrigger>
<Enabled>true</Enabled>
<Subscription><QueryList><Query Id="0" Path="Security"><Select Path="Security">*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and EventID=4720]]</Select></Query></QueryList></Subscription>
<ValueQueries>
<Value name="DisplayName">Event/EventData/Data[@Name='DisplayName']</Value>
<Value name="Logged">Event/System/TimeCreated/@SystemTime</Value>
<Value name="PrimaryGroupId">Event/EventData/Data[@Name='PrimaryGroupId']</Value>
<Value name="SamAccountName">Event/EventData/Data[@Name='SamAccountName']</Value>
<Value name="SubjectUserName">Event/EventData/Data[@Name='SubjectUserName']</Value>
<Value name="UserPrincipalName">Event/EventData/Data[@Name='UserPrincipalName']</Value>
</ValueQueries>
</EventTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>S-1-5-18</UserId>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteAppSession>
<UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>P3D</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>powershell.exe</Command>
<Arguments>-NoProfile -File "C:\testscript.ps1" -SamAccountName "$(SamAccountName)" -SubjectUserName "$(SubjectUserName)"</Arguments>
</Exec>
</Actions>
</Task>
param(
[string]$SamAccountName,
[string]$SubjectUserName
)
"Benutzer mit Namen: '$SamAccountName' wurde von Benutzer: '$SubjectUserName' erstellt." | sc 'C:\log.txt'
Alternativ kann man natürlich auch das Eventlog über ein PS-Skript überwachen. Das müsste dann aber ständig laufen damit die Events dort abgefangen werden können, insofern ist hier ein Tasktrigger die bessere Wahl.
Btw. wenn du es unbedingt via Get-Eventlog auslesen willst wäre
$username = Get-Eventlog -LogName Security -InstanceId 4720 -Newest 1 | %{$_.ReplacementStrings}
$username = ([xml](Get-WinEvent -LogName Security -FilterXPath "*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4720)]]" -Max 1).toXML()).Event.EventData.Data | ?{$_.Name -eq 'SamAccountName'} | %{$_.'#text'}
Grüße Uwe
Groß und Kleinschreibung der Variablen im Argument beachten, deine stimmen nicht überein...
OldOU ist nicht gleich OldOu.
OldOU ist nicht gleich OldOu.
Param steht bei dir nicht in der ersten Zeile.
Und für den Rest Binde ein Start-Transcript und Stop-Transcript in dein Skript ein.
Und der Account benötigt natürlich Schreibrechte in den Ziel-Ordner!!
Geht hier problemlos.
Und für den Rest Binde ein Start-Transcript und Stop-Transcript in dein Skript ein.
Und der Account benötigt natürlich Schreibrechte in den Ziel-Ordner!!
Geht hier problemlos.