RSAT-Installation unter Win10 Build 1809 per Powershell

Hier ist eine Auflistung der RSAT-Features, welche unter Windows 10 Build 1809 per Powershell installiert werden k├Ânnen

RSAT: Tools f├╝r Active Directory Domain Services und Lightweight Directory Services

Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0

RSAT: Verwaltungshilfsprogramme f├╝r die BitLocker-Laufwerkverschl├╝sselung

Add-WindowsCapability -Online -Name Rsat.BitLocker.Recovery.Tools~~~~0.0.1.0

RSAT: Active Directory Certificate Services Tools

Add-WindowsCapability -Online -Name Rsat.CertificateServices.Tools~~~~0.0.1.0

RSAT: DHCP-Servertools

Add-WindowsCapability -Online -Name Rsat.DHCP.Tools~~~~0.0.1.0

RSAT: DNS-Servertools

Add-WindowsCapability -Online -Name Rsat.Dns.Tools~~~~0.0.1.0

RSAT: Failoverclustering-Tools

Add-WindowsCapability -Online -Name Rsat.FailoverCluster.Management.Tools~~~~0.0.1.0

RSAT: Tools f├╝r Dateidienste

Add-WindowsCapability -Online -Name Rsat.FileServices.Tools~~~~0.0.1.0

RSAT: Group Policy Management Tools

Add-WindowsCapability -Online -Name Rsat.GroupPolicy.Management.Tools~~~~0.0.1.0

RSAT: IP-Adressverwaltungsclient (IPAM)

Add-WindowsCapability -Online -Name Rsat.IPAM.Client.Tools~~~~0.0.1.0

RSAT: Data Center Bridging LLDP-Tools

Add-WindowsCapability -Online -Name Rsat.LLDP.Tools~~~~0.0.1.0

RSAT: Netzwerkcontroller-Verwaltungstools

Add-WindowsCapability -Online -Name Rsat.NetworkController.Tools~~~~0.0.1.0

RSAT: Tools f├╝r Netzwerklastenausgleich

Add-WindowsCapability -Online -Name Rsat.NetworkLoadBalancing.Tools~~~~0.0.1.0

RSAT: Tools f├╝r die Remotezugriffsverwaltung

Add-WindowsCapability -Online -Name Rsat.RemoteAccess.Management.Tools~~~~0.0.1.0

RSAT: Remote Desktop Services Tools

Add-WindowsCapability -Online -Name Rsat.RemoteDesktop.Services.Tools~~~~0.0.1.0

RSAT: Server-Manager

Add-WindowsCapability -Online -Name Rsat.ServerManager.Tools~~~~0.0.1.0

RSAT: Abgeschirmte VM-Tools

Add-WindowsCapability -Online -Name Rsat.Shielded.VM.Tools~~~~0.0.1.0

RSAT: Storage Migration Service Management-Tools

Add-WindowsCapability -Online -Name Rsat.StorageMigrationService.Management.Tools~~~~0.0.1.0

RSAT: Storage Replica Module for Windows PowerShell

Add-WindowsCapability -Online -Name Rsat.StorageReplica.Tools~~~~0.0.1.0

RSAT: System Insights-Modul f├╝r Windows PowerShell

Add-WindowsCapability -Online -Name Rsat.SystemInsights.Management.Tools~~~~0.0.1.0

RSAT: Volume Activation Tools

Add-WindowsCapability -Online -Name Rsat.VolumeActivation.Tools~~~~0.0.1.0

RSAT: Windows Server Update Services-Tools

Add-WindowsCapability -Online -Name Rsat.WSUS.Tools~~~~0.0.1.0

Powershell: Abfrage des AD-User-Passwortalters

Im Rahmen einer Entst├Ârung von AD-Benutzeraccounts ben├Âtigte ich die aktuelle Passwort-Daten beim Anruf der Benutzer. Dazu habe ich mir ein kleines Skript geschrieben. Dieses ber├╝cksichtigt die folgenden Szenarien:

  • AD-Benutzer gibt es nicht
  • AD-Benutzer ist deaktiviert
  • AD-Benutzer hat ein Ablaufdatum und dieses ist ├╝berschritten
  • AD-Benutzer muss sein Kennwort bei der n├Ąchsten Anmeldung ├Ąndern
  • AD-Benutzer hat keinen Passwort-Ablauf
  • AD-Benutzer ist gesperrt

Wenn dieses alles nicht zutrifft werden folgende 2 Definitionen zur Berechnung des Passwortalters herangezogen:

  • AD-Benutzer nutzt die Default Domain Policy
  • AD-Benutzer nutzt eine┬áFine-grained Password Policy
Import-Module ActiveDirectory -Force
 
If ($args)
{
$Userlogin = $args[0]
}
 
else
 
{
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
 
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Passwort-Display'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'
 
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
 
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
 
$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Bitte sAMAccountName eingeben:'
$form.Controls.Add($label)
 
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)
 
$form.Topmost = $true
 
$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()
 
if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
    $Userlogin = $textBox.Text
}
 
if ($result -eq [System.Windows.Forms.DialogResult]::Cancel)
{
    exit
}
 
}
 
$Usercheck = Get-Aduser -filter {samaccountname -eq $userlogin}
 
If ($usercheck -eq $NULL)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Der Benutzer existiert nicht.","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Error)
exit
}
 
$employee = Get-AdUser $Userlogin -Properties enabled,PasswordNeverExpires,PasswordLastSet,Displayname,LockedOut,"msDS-UserPasswordExpiryTimeComputed",AccountExpirationDate
 
If ($employee.enabled -like "False")
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Benutzer "+$employee.displayname+" ist deaktiviert","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Error)
exit
}
 
If (($employee.AccountExpirationDate) -eq $null)
{
}
else
{
 
$Ablaufdatum = ((get-date) - ($employee.AccountExpirationDate))
$Ablauftage=$Ablaufdatum.days
 
If ($Ablauftage -gt "0")
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+ "Ablaufdatum des Accounts: "+$employee.AccountExpirationDate,"User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Error)
exit
}
 
}
 
 
If ($employee.PasswordLastSet -eq $null)
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+"Das Passwort des Accounts muss bei der n├Ąchsten Anmeldung ge├Ąndert werden.","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Error)
exit
}
 
If ($employee.passwordneverexpires -like "True")
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+"Das Passwort des Accounts l├Ąuft nicht ab.","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Error)
exit
}
 
If ($employee.LockedOut -like "True")
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+"Der Account ist gesperrt.","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Error)
exit
}
 
$FGPP=(Get-ADUserResultantPasswordPolicy $Userlogin)
 
If($fgpp.name -eq $null) 
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$expireDate=((Get-adUser($Userlogin) -Properties PassWordLastSet).PasswordLastSet + (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Ticks)
$daysleft=($expireDate-(get-date)).Days
 
if($daysleft-le "0")
 
{
$daysnegative =-$daysleft
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+"Regelwerk: Default Domain Policy `n`n"+"Das Passwort ist seit "+<span style="display: inline !important; float: none; background-color: transparent; color: #2b2b2b; cursor: text; font-family: 'Philosopher',sans-serif; font-size: 16px; font-style: normal; font-variant: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-decoration: none; text-indent: 0px; text-transform: none; -webkit-text-stroke-width: 0px; white-space: normal; word-spacing: 0px;">$daysnegative</span>+" Tagen abgelaufen. `n`n"+"Genauer Zeitstempel: "+$expireDate+"","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Warning)
}
 
else{
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+"Regelwerk: Default Domain Policy `n`n"+"Das Passwort muss in "+$daysleft+" Tagen ge├Ąndert werden. `n`n"+"Genauer Zeitstempel: "+$expireDate+"","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Information)
}
exit
}
 
else{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$expireDate=((Get-adUser($Userlogin) -Properties PassWordLastSet).PasswordLastSet + (Get-ADUserResultantPasswordPolicy -Identity $Userlogin).MaxPasswordAge.Ticks)
$daysleft=($expireDate-(get-date)).Days
 
if($daysleft-le "0")
 
{
$daysnegative =-$daysleft
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+"Regelwerk: "+$fgpp.Name+" `n`n"+"Das Passwort ist seit "+$daysnegative+" Tagen abgelaufen. `n`n"+"Genauer Zeitstempel: "+$expireDate+"","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Warning)
}
 
else{
[System.Windows.Forms.MessageBox]::Show("Benutzer: "+$employee.displayname+"  `n`n"+"Regelwerk: "+$fgpp.Name+" `n`n"+"Das Passwort muss in "+$daysleft+" Tagen ge├Ąndert werden. `n`n"+"Genauer Zeitstempel: "+$expireDate+"","User " +$Userlogin,0,[System.Windows.Forms.MessageBoxIcon]::Information)
}
exit

Damit die Daten ordnungsgem├Ą├č abgefragt werden k├Ânnen, ben├Âtigt der Ausf├╝hrende die Leseberechtigungen auf den Container „Password Setting Objects“ im System-Ordner der Dom├Ąne.

Das Skript kann per GUI sowie per Skript gestartet werden.

PowerShell: DHCP-Leases exportieren

Manchmal kann es Sinn ergeben, dass man die gezogenen Leases eines Servers ausgibt. Dieses ist mit einem kleinen Skript m├Âglich:

Get-DHCPServerV4Scope 
| ForEach {
    Get-DHCPServerv4Lease -ScopeID $_.ScopeID
} 
| Select-Object IPAddress,HostName,ClientID,AddressState,LeaseExpiryTime 
| Export-Csv ".\$($env:COMPUTERNAME)-Reservations.csv" -NoTypeInformation

Dieses ist gedacht direkt auf dem Server aufgerufen zu werden. Dabei werden alle DHCP-Scopes berücksichtigt. Der Dateiname des Exports wird mit dem Servernamen als Start definiert.

Entsprechend werden aktive und inaktive Reservierungen neben den dynamisch verteilten IP-Adressen aufgelistet. Die aus dem jeweiligen Pool des Servers vergebenen Adressen werden inklusive dem Ablaufdatum ausgegeben.

 

Powershell: Ausdrucke pro Drucker ermitteln

Vor einer Umstellung oder auch einer Abschaltung eines Druckservers kann ein Audit der Druckdaten sinnvoll sein. Dabei wird ermittelt das Skript in den Parametern eines Zeitfensters, welcher Drucker wieviel Druckauftr├Ąge verarbeitet hat.

$Startzeit = "24.11.2018 00:00:00"
$Endzeit = "24.11.2018 23:59:59"
 
$ZentralDatei ="E:\Audit\Zentraldatei.csv"
$Auswertung ="E:\Audit\Auswertung.csv"
 
$Druckerliste = @()
 
$Resultate = Get-WinEvent -FilterHashTable @{LogName="Microsoft-Windows-PrintService/Operational"; ID=307; StartTime=$Startzeit; EndTime=$Endzeit;}
 
ForEach($Resultat in $Resultate){
  $Datensatz = [xml]$Resultat.ToXml()
  $DatenDetails = New-Object -TypeName psobject -Property @{
 
      Druckername = $Datensatz.Event.UserData.DocumentPrinted.Param5
      Zeitstempel = $Resultat.TimeCreated
 
      }
    $Druckerliste += $DatenDetails
  }
 
 
$Druckerliste | Export-Csv -LiteralPath $ZentralDatei -NoTypeInformation
 
 
Import-Csv $ZentralDatei | Group-Object Druckername | Select-Object Name, Count | Sort-Object -Property name | Export-csv $Auswertung -NoTypeInformation

Das eingesetzte CMDlet „Get-WinEvent“ steht seit Windows Server 2008 R2 und sp├Ąteren Betriebssystemen zur Verf├╝gung.

Um die Daten zu erhalten, muss allerdings in der Ereignisanzeige das Log f├╝r „Microsoft \ Windows \ Printservices \ Operational“ aktiviert worden sein. Dieses sollte auch vorzeitig durchgef├╝hrt worden sein, um l├Ąngere Zeitr├Ąume zu ├╝berwachen. Die Daten k├Ânnen nicht r├╝ckwirkend erstellt werden. Anbei die schnelle Umsetzung per PowerShell-Aufruf:

$EventLogging = Get-WinEvent -ListLog 'Microsoft-Windows-PrintService/Operational'
$EventLogging.IsEnabled = $true
$EventLogging.MaximumSizeInBytes = 1000000
$Eventlogging.LogMode = "Circular"
$EventLogging.SaveChanges()

Mit diesem Befehlssatz wird das erforderliche Eintrag in der Ereignisanzeige aktiviert. Dabei wird ein 1 GigaByte gro├čes Log erstellt. Wenn der Schwellwert erreicht ist, wird beim Hinzuf├╝gen eines neuen Ereignisses das ├älteste entfernt.

In der Datei „Auswertung.csv“ stehen dann die Druckernamen sowie die Anzahl der Ausdrucke im Zeitraum ausgedruckt wurden.

Powershell: Pers├Ânliches Laufwerk bei AD-Benutzern setzen

In einem Projekt sollte das Benutzer-Verzeichnis aus dem Bereich des Loginskriptes entfernt und in das Benutzer-Objekt des Active Directory verlagert werden. Da es sich um eine 4-stellige der Anzahl sowie mehreren Verzeichnispfaden handelte, wollte ich dieses gern ├╝ber PowerShell abarbeiten lassen.

Bei einem meiner Tests kam es dann zum Problem, dass nicht der geplante Laufwerksbuchstabe im Benutzerprofil genutzt wurde. Der letzte freie Buchstabe, in meinem Fall „Z:“, wurde in meinem Fall verbunden. Im AD-Objekt wurde auch der korrekte Buchstabe angezeigt. Bei dem hier korrekt abgebildeten Befehl hatte ich den Doppelpunkt „vergessen“:

Set-ADUser tester01 -HomeDrive "P:" -HomeDirectory "\\Server01\Freigabe\Home\tester01"

Dieses wird in PowerShell ohne Fehlermeldung angenommen. Aus diesem Grund fiel mir diese „Unsch├Ąrfe“ erst beim Test auf.

PowerShell: Sonderzeichen in Pfaden nutzen

Am gestrigen Tag hatte ich die Aufgabe bei einem┬áOrdnerpfad eine Ver├Ąnderung vorzunehmen. Dieses hatte ich auch bereits f├╝r andere Ordner auf dem Dateisystem vorgenommen. Somit nahm ich meinen Befehlsaufruf zur Hand. Schon beim Hinzuf├╝gen des Ordnerpfades in der PowerShell ISE merkte ich, dass etwas nicht stimmte.

Aufgrund eines Dollarzeichens in der Pfadangabe erwartete der Befehl┬ánun die Angabe einer Variable. Ich hatte allerdings keine Lust in Zukunft f├╝r eine Handvoll Ordner erst Variablen zu definieren. Der Pfad war ja eigentlich korrekt. Die Interpretation von PowerShell st├Ârte in diesem Fall.

Nach ein bisschen experimentieren fand ich heraus, dass ein „Gravis“ (engl.: Backtick) mein Problem l├Âsen kann:

#Defekte Pfade
Get-childitem \\server\Freigabe\Ordner$Data1
Get-childitem \\server\Freigabe\Ordner$Data2
Get-childitem \\server\Freigabe\Ordner$Data3
 
#Funktionierende Pfade
Get-childitem \\server\Freigabe\Ordner`$Data1
Get-childitem \\server\Freigabe\Ordner`$Data2
Get-childitem \\server\Freigabe\Ordner`$Data3

Mit diesem Zeichen definiert man, dass das Sonderzeichen ignoriert wird. Die Variable wird somit zum Pfad-Bestandteil. Dieses funktioniert auch bei weiteren Sonderzeichen wie zum Beispiel Klammern.

PowerShell: Anmeldung an MS Online Services

Microsoft bietet verschiedene Services unter Office 365 an. Diese k├Ânnen neben der Webapplikation auch per PowerShell angesprochen werden. Die verschiedenen Dienste ├╝ber eine PowerShell-Session, wenn man die folgendes Skript nutzt:

$domainHost="domain"
$credential = Get-Credential
 
 
#Verbindungsaufbau ├╝ber Azure Active Directory PowerShell for Graph module
#Connect-AzureAD -Credential $credential
 
#Verbindungsaufbau ├╝ber Azure Active Directory Module for Windows PowerShell module
#Connect-MsolService -Credential $credential
 
 
Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
Connect-SPOService -Url https://$domainHost-admin.sharepoint.com -credential $credential
Import-Module SkypeOnlineConnector
$sfboSession = New-CsOnlineSession -Credential $credential
Import-PSSession $sfboSession
$exchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $credential -Authentication "Basic" -AllowRedirection
Import-PSSession $exchangeSession
$SccSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.compliance.protection.outlook.com/powershell-liveid/" -Credential $credential -Authentication "Basic" -AllowRedirection
Import-PSSession $SccSession -Prefix cc

Zur Nutzung der Befehlsauflistung muss die Variable „$domainHost gegen die pers├Ânlich definierte Microsoft-Domain ausgetauscht werden.
F├╝r die Verbindung zu Domain muss der jeweilig gew├╝nschte AD-Connector durch die Entfernung des # freigeben.

Weitere Informationen sind bei Microsoft zu finden