Kategorieauswahl

Scripting

Alles was man Script gesteuert erledigen kann…

Microsoft Kommandozeile

Die Windows Command Line Reference ist verfügbar unter:

https://download.microsoft.com/download/5/8/9/58911986-D4AD-4695-BF63-F734CD4DF8F2/ws-commands.pdf

Diese erklärt alle möglichen Befehle im Detail.

(De-)Aktive Benutzer des Active-Directory auflisten

Das Benutzer-Attribut UserAccountControl enthält im 2. Bit die Information ob ein Benutzerkonto aktiviert (=0) oder deaktiviert (=1) ist.
In Powershell ist das eigentlich gar kein Problem, da hier ein Attribut Enabled ($true oder $false) geliefert wird, dies ist im Active-Directory so aber gar nicht vorhanden.
Möchte man also einen LDAP-Filter nutzen um alle aktiven Benutzer zu listen geht das so:
(!(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2)))
oder alle deaktivierten Benutzer:
(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))

SID-History mit PowerShell migrieren

Normaler Weise kann bei einer Migration das SID-History-Attribut nicht einfach mit der SID aus der alten Domäne eines zu migrierenden Benutzer beschrieben werden.

Auch wenn alle Berechtigungen korrekt gesetzt sind und an der Vertrauensstellung SID-Filter abgeschaltet ist kann man mit den Standardtools, oder selbst mit PowerShell wenig ausrichten.

Nur mit speziellen Migrationstools wie ADMT von Microsoft (kostenlos) oder Quest-Migration-Manager von DELL (sehr cool, aber teuer) ist dies möglich.

Es gibt jedoch von Microsoft auf die SIDCloner.dll, die schon völlig ausreicht um auch mit PowerShell die SID-History per Script zu befüllen. Was man dafür tun muss beschreibt dieser Artikel:

https://migration-blog.com/2013/11/05/how-to-write-or-migrate-sidhistory-with-powershell-2/

PowerShell 5 fehlende Help about Informationen

In PowerShell 5.0 gibt es einen Fehler in update-help. Die „about“-Files werden zwar heruntergeladen, haben jedoch den falschen Namen. Daher werden diese nicht angezeigt, wenn man help about eintippt. Die „about“-Files, haben nur die Dateinamenerweitung .txt müssten aber .help.txt haben.

Lösung:

Get-ChildItem C:\Windows\System32\WindowsPowerShell\v1.0\en-US\*.txt | ? {$_.name -notlike „*.help.txt“} | % {Rename-Item $_.name $_.name.insert($_.name.indexof(„.“),“.help“)}

bzw. für die Deutschen Help-Files:

Get-ChildItem C:\Windows\System32\WindowsPowerShell\v1.0\de-DE\*.txt | ? {$_.name -notlike „*.help.txt“} | % {Rename-Item $_.name $_.name.insert($_.name.indexof(„.“),“.help“)}

PowerShell Cmdlet Test-Connection liefert falsche IP-Adresse zurück

Neulich hatte ich ein interessantes Phänomen.

Ping 10.8.10.12

Wer antwortet? 10.8.10.12!

Test-Connection 10.8.10.12. Wer steht unter IPv4Address? 10.8.10.13!

Scheinbar macht Test-Connection kein einfaches ICMP hin und zurück, sondern wertet PTR-Records im DNS aus. Da lag dann auch der Fehler. Es gab 2 PTR Einträge auf einen anderen Rechner den ich gar nicht erreichen wollte. 12+13 verwiesen beide auf ein anderes System. Nachdem ich den mit der 12 am Schluss im DNS gelöscht hatte und dafür einen auf das gewünschtes Zielsystem ein trug, lieferte auch Test-Connection unter IPv4Address die erwartete 10.8.10.12. Leider war die Zeit knapp und so habe ich leider keinen Netzwerkmitschnitt gemacht, um zu sehen wie Test-Connection auf die Idee kommt auf den fehlerhaften PTR-Eintrag zu schauen.

Tesla Model S und X per PowerShell fernsteuern, mithilfe der Restful WebAPI von TESLA

Ich liebe meinen Tesla Model S und ich liebe PowerShell. Na dann bringe ich doch mal beides zusammen. 😀

Für die Anmeldung beim Tesla Restful Webservice müssen Sie dieselben Anmeldeinformationen (Benutzername und Kennwort), wie auf mytesla (https://my.teslamotors.com/de_DE/user/login) angeben. Also zunächst mal zur Authentifizierung:

# Fenster für Anmeldeinfos anzeigen
$Credential=Get-Credential
# Kennwort für die SSL-gesicherte Übergabe „vorbereiten“
$ptr=[Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password)
$pwd=[Runtime.InteropServices.Marshal]::PtrToStringAuto($Ptr)

# Notwendige Anmeldeinformationen zusammensetzen
$LoginInfo=@{
‚grant_type‘ = ‚password‘
‚client_id‘ = „e4a9949fcfa04068f59abb5a658f2bac0a3428e4652315490b659d5ab3f35a9e“
‚client_secret‘ = „c75f14bbadc8bee3a7594412c31416f8300256d7668ea7e6e7f06727bfb9d220“
‚email‘ = $Credential.UserName
‚password‘ = $pwd
}

Dann können Sie die Verbindung unter Angabe der Anmeldeinfos herstellen:

$Connect = Invoke-RestMethod -Uri „https://owner-api.teslamotors.com/oauth/token“ -Method Post -Body $LoginInfo

Als Rückgabewert erhalten Sie dann einen Zugriffsschlüssel (Token) mit dem alle weiteren Aktionen durchgeführt werden können:

$Token=$Connect.access_token

Hier noch ein paar allgemeine, notwendige http Header Informationen zusammen schrauben:

$Header=@{
„Authorization“=“Bearer $Token
„Accept-Encoding“=“gzip,deflate“
}

Gehen wir mal davon aus, Sie haben nur einen Tesla, dann finden Sie mit dem nachfolgenden Kommando in $car allgemeine Informationen zu Ihrem Fahrzeug wie Farbe, Name u.v.a.m.

$car = (Invoke-RestMethod -Uri „https://owner-api.teslamotors.com/api/1/vehicles“ -Method Get -Headers $Header).response

Falls Ihr Dornröschen noch schläft, müssen Sie es erst mal wach küssen:

if ($car.state -ne „online“) {Invoke-RestMethod -Uri „https://owner-api.teslamotors.com/api/1/vehicles/$($car.id)/wake_up“ -Method Post -Headers $Header}

Jetzt können Sie Ihren Liebling mal etwas genauer untersuchen, wie z.B. die eingestellten Einheiten (gui_settings) abfragen:

(Invoke-RestMethod -Uri „https://owner-api.teslamotors.com/api/1/vehicles/$($car.id)/data_request/gui_settings“ -Method Get -Headers $Header).response

Den Teil gui_settings können Sie gegen die folgenden Begriffe austauschen:

charge_state = Zeigt den Akkustatus an

climate_state = Klima Anlage

drive_state = GPS Infos

vehicle_state = Zustandsinformationen: km-Stand, Schiebedach auf? etc…

Sie dürfen natürlich auch gerne Einstellungen vornehmen (z.B. hupen):

Invoke-RestMethod -Uri „https://owner-api.teslamotors.com/api/1/vehicles/$($car.id)/command/honk_horn“ -Method Post -Headers $Header

Auch hier gibt’s wieder einen ganzen Sack voll weiterer Begriffe, die Sie gegen honk_horn austauschen können:

flash_lights = Lichthupe

charge_port_door_open = Ladeanschluß öffnen

charge_standard = Ladelimit auf Standard setzen

charge_max_range = Ladelimit auf max. Reichweite (100%) setzen

set_charge_limit?percent=75 = Ladelimit beliebig einstellen

charge_start und charge_stop = Ladevorgang starten bzw. beenden

door_lock und door_unlock = Türen auf bzw. zu

set_temps?driver_temp=23.7&passenger_temp=18.1 = wie warm soll’s darf’s denn sein?

auto_conditioning_start und auto_conditioning_stop = Klima an bzw. aus

sun_roof_control?state=open&percent=50 = Schiebedach steuern

remote_start_drive?password=StrengGeheim = Kennwort für den Start ohne Schlüssel im Fahrzeug festlegen. Verfällt nach 2 Minuten, wenn das Fahrzeug nicht bis dahin gestartet wird.

 

PowerShell Script um Quest-Migration-Manager Datenbank aufzuräumen

Das folgende Script löscht Einträge aus der Ressource Processing Datenbank des Quest Migration Manager, die älter als 3 Monate sind:

# Bitte unter dem Namen cleanQuestDB.ps1 abspeichern, damit das u.a. Beispiel passt
 param(
 [String]$Server=“localhost“,
 [int]$Port=50000,
 [int]$Month=3,
 [String]$LogPath=“~\Desktop\DeletedQuestDBEntries.log“
)
Import-Module ActiveDirectory
$ErrorActionPreference=“SilentlyContinue“
Get-ADObject -filter * -server „$($Server):$($Port)“ -searchbase *
$Root=($Error[0] | select -expandprop Exception | select -expandprop message).split(„:“)[1].split(„,“)[-1].substring(1).trimend(„‚.“)
$ErrorActionPreference=“Continue“
$Project=(Get-ADObject -filter * -server „$($Server):$($Port)“ -searchbase $Root -searchscope Onelevel | ? {$_.ObjectClass -eq „aelita-Amm-Workspace“}).Distinguishedname
$ComputerLogCollection=Get-ADObject -filter * -server „$($Server):$($Port)“ -searchbase „cn=Computers,cn=ResourceProcessing,$Project“ -searchscope onelevel -properties aelita-Amm-LastOperationTime,aelita-Amm-Name
$TimeSpan=(get-date)-(new-timespan -days ($Month*30))
$ToDelete=@()
$TotalCounter=$ComputerLogCollection.count
$DeleteCounter=0
„Searching Database. Please be patient!“
foreach ($Item in $ComputerLogCollection) {
 $Timestamp=$Item | select -expandprop aelita-Amm-LastOperationTime
 if ($Timestamp -and $Timestamp -lt $TimeSpan) {
  $ToDelete+=$Item  
  $DeleteCounter++
 }
}
if ((read-host -prompt „$DeleteCounter from $TotalCounter to delete, proceed (Yes/No)“) -notlike „Y*“) {„Aborted!“;exit}
„Deleted Entries of Questdatabase“ > $LogPath
„Run from: $(get-date)“ >> $LogPath
foreach ($Item in $ToDelete) {
 $Name=$Item | select -expandprop aelita-Amm-Name
 $Timestamp=$Item | select -expandprop aelita-Amm-LastOperationTime
 „Deleting $Name from $Timestamp“ | tee $LogPath -Append
 $Item | Remove-ADObject -Recursive -confirm:$false
}

Im einfachsten Fall starten Sie einfach das Script. Zunächst wird geschaut wieviele Einträge insgesamt vorhanden sind und wieviele davon gelöscht werden würden. Dann fragt es, ob Sie den Vorgang durchführen möchten und listet Ihnen die entsprechenden Objekte auf. Nebenbei werden diese Angaben in eine LogDatei auf Ihrem Desktop protokolliert. Sie können das Skript natürlich auch mit anderen Parametern aus dem Parameter Block aufrufen, wie z.B.:

./cleanQuestDB.ps1 -Server QuestServer -Port 40000 -Month 2 -LogPath C:\Quest.log

Voraussetzungen:
PowerShell 2.0 oder höher
AD-Modul verfügbar
Der Benutzer unter dem das Script läuft benötigt Vollzugriff auf die Quest-Datenbank
Muss mit erhöhten Rechten (UAC – Benutzerkontensteuerung) ausgeführt werden

XML-Abfrage Ereignisanzeige

Die Filter für die Windows Ereignisanzeige (Eventlog) sind sehr mächtig geworden. Mit den standard Optionen in der grafischen Oberfläche kann man schon viel machen, aber leider nicht im Nachrichtentext filtern. Das geht auch mit XML Abfragen. Klicken Sie dazu zunächst einmal auf ein ähnliches Ereignis und klicken Sie dort die Detailansicht an. Dort wählen Sie XML View:

Dann erstellen Sie einen benutzerdefinierten Filter und wählen dort den Reiter XML. Setzen Sie das Häkchen bei Abfrage manuell bearbeiten. Wenn Sie bereits bei Filter Reiter Einstellungen gemacht haben, sind diese auch schon im XML hier vordefiniert. Haben Sie z.B. das Anwendungslog ausgewählt steht dort:
<QueryList>
<Query Id=“0″ Path=“Application“>
<Select Path=“Application“>*</Select>
</Query>
</QueryList>
Oben habe ich Sie den XML-View auswählen lassen. Warum? Dort sehen Sie, wie die jeweiligen Felder nach denen Sie suchen können benannt sind. Um nun also z.B. nach dem Benutzernamen zu suchen ergänzen Sie die XML Zeilen wie folgt:
<QueryList>
Id=“0″ Path=“Security“>
<Select Path=“Security“>*</Select>
*[EventData[Data[@Name=‘TargetUserName‚] and (Data=‘s‚)]]
</Select>
</Query>
</QueryList>

Selbstverständlich dürfen Sie das gerne weiter verkomplizieren:
*[EventData[Data[@Name=’SubjectUserName‘] and (Data=’abc‘ or Data=’123’)]]
Dies würde alle mit der Angabe abc oder 123 finden bei UserName finden.

Möchten Sie in mehreren Logs suchen:
<Select Path=“Security“>*[System[(EventID=’1234′)]]</Select>
<Select Path=“Application“>*[System[(EventID=’4321′)]]</Select>
Würde alle Ereignisse aus dem Eventlog Security mit der ID 1234 und alle Ereignisse aus dem Applicationlog mit der ID 4321 anzeigen.

Um die Filter in der PowerShell zu nutzen können Sie die XML-Abfrage genauso in einen String schreiben und mit Get-WinEvent abfragen:
$Query=@“
<QueryList>
Id=“0″ Path=“Security“>
<Select Path=“Security“>
*[EventData[Data[@Name=’TargetUserName‘] and (Data=’s‘)]]
</Select>
</Query>
</QueryList>
„@
$Evts=Get-WinEvent -log Security -FilterXPath $Query -maxevents 1000

PowerShell OpenBook

Es gibt eine neue Website die kostenlos für Sie ein Buch über PowerShell online bereit stellt.

Das Buch bietet im ersten Teil eine einfache Einführung in die PowerShell, die auch ohne Programmier- oder Skriptkenntnisse leicht verständlich geschrieben ist. (Stand: Vollständig)

Im zweiten Teil befasst sich das Buch mit den Unterschieden zwischen den PowerShell Versionen 1.0, 2.0 und 3.0. Andere Bücher über PowerShell Version 3.0 enthalten zu 95% Informationen die ein gestandener PowerShell 2.0 Skripter bereits kennt. Die Unterschiede sind irgendwo in den 95% gut versteckt. Hier haben Sie alle Neuerungen auf einen Blick!(Stand: 1.0 und 2.0 vollständig, Version 3.0 in der Entstehung)

Der 3. Teil ist voll mit Praxisbeispielen, wie man die Registry, das Filesystem, AD, Hyper-V oder IIS administriert, aber auch Excel steuert oder grafische Oberflächen baut. (Stand: 1/2 fertig)

Der letzte Teil ist der Anhang mit Lösungen zu Kontrollfragen und Aufgabenstellungen, sowie verschiedenen Tabellen z. B. zum -f Operator und einem Glossar. Ein Index darf natürlich auch nicht fehlen. (1/2 fertig)

Sie selbst dürfen gerne Fragen aus der Praxis stellen, deren Lösungen, wenn sie interessant genug sind, dann in den Praxisteil des Buches einfließen.

In PowerShell Remote-Session auf UNC Netzwerkpfade zugreifen

Hat man Windows Remoting konfiguriert und Enter-PSSession als auch Invoke-Command klappen problemlos, fängt man an diese tollen Möglichkeiten rege zu nutzen. Ab und an will man dann aber vielleicht auch einmal aus so einer Remote-Session heraus auf einen Netzwerkpfad in Form von \\Servername\Freigabename zugreifen und man bekommt immer so nette Fehlermeldungen wie:

Get-ChildItem : Cannot find path ‚\\Servername\Freigabename‘ because it does not exist.
+ CategoryInfo          : ObjectNotFound: (\\Servername\Freigabename:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Doch der Server ist online und wenn Sie am entfernten Computer lokal angemeldet versuchen darauf zuzugreifen ist alles fein. Was läuft hier schief? Das ist wieder einmal so ein „Sicherheitsfeature“.

Der Quick and Dirty Way ist einfach mit:

net use n: \\Servername\Freigabename

eine Netzlaufwerksverbindung herzustellen (tolle Sicherheit). New-PSDrive und andere Experimente können Sie sich sparen…habe ich alles schon ausprobiert. N: können Sie dann ganz normal ansprechen. Nun der offizielle Weg:

Mittels Gruppenrichtlinien müssen Sie unter Computer Configuration\Policies\Administrative Templates\Windows Components\Windows Remote Management (WINRM) bei den Unterpunkten WINRM Client als auch WINRM Service „Allow CredSSP authentication“ aktivieren. Des Weiteren müssen Sie unter Computer Configuration\Policies\Administrative Templates\System\Credentials Delegation die beiden Einträge Allow Delegating Fresh Credentials und noch einmal der Eintrag mit Allow Delegating Fresh Credentials with NTLM-only Server Authentication mit so einem Eintrag schmücken:

wsman/NameDesRechnersAufDenSieSichRemoteDraufSchaltenMöchten

Diese Policy muss an eine OU gehängt werden welche die Computer enthalten von denen aus Sie Enter-PSSession bzw. Invoke-Command ausführen möchten.

Haben Sie keine GPOs (z.B. weil kein AD) dann geht es auch in der PowerShell auf den einzelnen Systemen (aber nicht remote 😉 ) mit:

Enable-WSManCredSSP –Role Server

und

Enable-WSManCredSSP –Role Client -DelegateComputer NameDesServers

Um sich dann mit dem Server zu verbinden, müssen Sie die zusätzlichen Schalter -cred und -auth mit angeben. Zuvor sollten Sie sich allerdings die Anmeldeinformationen in einer Variablen hinterlegen, z.B. so:

$cred=get-credential

Dann können Sie Ihr eigentliches Enter-PSSession in dieser Form ausführen:

Enter-PSSession Remoteserver -cred $cred -auth credssp

Verrückte Welt! Ich nehme net use 😉