Powershell5 → Net-Framework Powershell7 → .NET
$command = 'Get-ACL .\test' $bytes = [System.Text.Encoding]::Unicode.GetBytes($command) $encodedCommand = [Convert]::ToBase64String($bytes) $encodedCommand # RwBlAHQALQBBQ0wAIAAuAFwAdABlAHMAdA== #encodedCommand #powershell.exe -eC "RwBlAHQALQBBQ0wAIAAuAFwAdABlAHMAdA=="
Get-Process | Get-Member -MemberType Properties Get-Service | Get-Member -MemberType Method Get-Process | Get-Member -MemberType Event Get-Process | Format-Table -Property Name, CPU, Memory -AutoSize Get-Service | Format-List -Property DisplayName, Status Get-Process | Select-Object Name, Id, CPU, SessionId | Where-Object { $_.SessionId -gt 4 } Get-Process | Out-GridView Get-Service | Out-GridView Get-WmiObject Win32_UserAccount | Where-Object { $_.Name -eq "administrator" } Import-Module ActiveDirectory $user = Get-ADUser -Identity "username" -Properties * $user | Format-Table Name, SamAccountName, Email, Enabled
PS C:\> Get-PackageSource Name ProviderName IsTrusted Location ---- ------------ --------- -------- Nuget API v2 NuGet False https://www.nuget.org/api/v2/ GrapeCity NuGet False https://nuget.grapecity.com/nuget Microsoft Visual Studio Offli... NuGet False C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\ PSGallery PowerShellGet False https://www.powershellgallery.com/api/v2 PS C:\> Unregister-PackageSource -Name "GrapeCity" PS C:\> Get-PackageSource Name ProviderName IsTrusted Location ---- ------------ --------- -------- Nuget API v2 NuGet False https://www.nuget.org/api/v2/ Microsoft Visual Studio Offli... NuGet False C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\ PSGallery PowerShellGet False https://www.powershellgallery.com/api/v2 PS C:\> Register-PackageSource -Name "GrapeCity" -ProviderName "NuGet" -Location "https://nuget.grapecity.com/nuget" -Trusted Name ProviderName IsTrusted Location ---- ------------ --------- -------- GrapeCity NuGet True https://nuget.grapecity.com/nuget PS C:\> Get-PackageSource Name ProviderName IsTrusted Location ---- ------------ --------- -------- Nuget API v2 NuGet False https://www.nuget.org/api/v2/ GrapeCity NuGet True https://nuget.grapecity.com/nuget Microsoft Visual Studio Offli... NuGet False C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\ PSGallery PowerShellGet False https://www.powershellgallery.com/api/v2
PS C:\> [Net.ServicePointManager]::SecurityProtocol Tls11 PS C:\> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 PS C:\> [Net.ServicePointManager]::SecurityProtocol Tls12
Install-Module -Name PSWindowsUpdate Get-WUSettings Get-WindowsUpdate -MicrosoftUpdate [-IsInstalled] (von Microsoft) Get-WindowsUpdate -IsInstalled (von managment [wsus] server) Get-WindowsUpdate -IsAssigned (von managment [wsus] server) Get-WindowsUpdate | Format-List KB, Title, Description, Size Get-WindowsUpdate -KBArticleID KB4023057, KB5034582 Get-WindowsUpdate -Category "Critical Updates" Get-WindowsUpdate -NotCategory "Drivers" Get-WindowsUpdate -Category "Critical Updates" -NotCategory "Drivers" -Download Get-WindowsUpdate -Title "Antivirus" -Install -Verbose -AcceptAll [-AutoReboot] Get-WURebootStatus Get-WUHistory -MaxDate (Get-Date).AddDays(-1)
MySQL Client DLL von https://dev.mysql.com/downloads/file/?id=526912 herunterladen und installieren.
$mysql_server = "172.21.0.13" $mysql_user = "root" $mysql_password = "Pa$$w0rd" $dbName = "testDB" [void][system.reflection.Assembly]::LoadFrom("C:\Program Files (x86)\MySQL\MySQL Connector NET 8.4\MySql.Data.dll") $Connection = New-Object -TypeName MySql.Data.MySqlClient.MySqlConnection $Connection.ConnectionString = "SERVER=$mysql_server;DATABASE=$dbName;UID=$mysql_user;PWD=$mysql_password" $Connection.Open() $sql = New-Object MySql.Data.MySqlClient.MySqlCommand $sql.Connection = $Connection $sql.CommandText = "INSERT INTO test.a (id, test) VALUES (0,""Testtext"")" # WRITE DATA $sql.ExecuteNonQuery() # Read Data $reader = $sql.ExecuteReader() while ($reader.Read()) { for ($i = 0; $i -lt $reader.FieldCount; $i++) { Write-Host "$($reader.GetName($i)): $($reader.GetValue($i))" } Write-Host "---------" # Trennlinie zwischen Datensätzen } $reader.Close() $Connection.Close()
//Verbindung mit dem Active Directory herstellen: Import-Module ActiveDirectory // Domäne abrufen Get-ADDomain //Domänencontroller abrufen: Get-ADDomainController //Aktuelles Active Directory-Forest abrufen: Get-ADForest //Organisationseinheiten (OU) abrufen: Get-ADOrganizationalUnit
//Benutzerkonto erstellen: New-ADUser -SamAccountName "Username" -UserPrincipalName "username@domain.com" -Name "Full Name" -GivenName "First Name" -Surname "Last Name" -Enabled $true -PasswordNeverExpires $true -AccountPassword (ConvertTo-SecureString "Password" -AsPlainText -Force) -PassThru //Benutzerkonto deaktivieren: Disable-ADAccount -Identity "Username" //Benutzerkonto aktivieren: Enable-ADAccount -Identity "Username" //Benutzerkonto löschen: Remove-ADUser -Identity "Username" -Confirm:$false //Benutzerkonto suchen: Get-ADUser -Filter "SamAccountName -eq 'Username'" //Benutzerkontoattribute aktualisieren: Set-ADUser -Identity "Username" -Office "New Office" -Description "New Description"
# Benutzergruppe erstellen: New-ADGroup -Name "RODC Admins" -SamAccountName RODCAdmins -GroupCategory Security -GroupScope Global -DisplayName "RODC Administrators" -Path "CN=Users,DC=Fabrikam,DC=Com" -Description "Members of this group are RODC Administrators" # Benutzerkonto löschen: Remove-ADGroup -Identity RODCAdmins
//OU erstellen: New-ADOrganizationalUnit -Name "OUName" -Path "OU=ParentOU,DC=domain,DC=com" //OU verschieben Move-ADObject -Identity "OU=Sales,OU=Department,DC=domain,DC=com" -TargetPath "OU=Marketing,OU=Department,DC=domain,DC=com" //OU löschen: Remove-ADOrganizationalUnit -Identity "OU=OUName,OU=ParentOU,DC=domain,DC=com" -Confirm:$false
//Gruppenrichtlinie erstellen: New-GPO -Name "GPOName" //Gruppenrichtlinie verknüpfen: New-GPLink -Name "GPOName" -Target "OU=OUName,OU=ParentOU,DC=domain,DC=com" //Gruppenrichtlinie löschen: Remove-GPO -Name "GPOName" -Confirm:$false // Gruppenrichtlinien einer Gruppe Import-Module GroupPolicy $gruppenname = "GroupName" $gruppe = Get-ADGroup -Filter { Name -eq $gruppenname } $gruppenID = $gruppe.ObjectGUID $gruppenrichtlinien = Get-GPO -All | Where-Object { $_.User.DistinguishedName -contains "CN=$gruppenID" } $gruppenrichtlinien //Gruppenrichtlinien eines benutzer Import-Module GroupPolicy $benutzername = "Username" $benutzer = Get-ADUser -Filter { SamAccountName -eq $benutzername } $benutzerID = $benutzer.ObjectGUID $gruppenrichtlinien = Get-GPO -All | Where-Object { $_.User.DistinguishedName -contains "CN=$benutzerID" } $gruppenrichtlinien
Get-DhcpServerv4Scope Get-DhcpServerv4Lease -ScopeId "10.0.0.0" Import-Module DhcpServer # DHCP-Bereich Parameter $ScopeName = "TestScope" $StartRange = "192.168.1.100" $EndRange = "192.168.1.200" $SubnetMask = "255.255.255.0" # DHCP-Bereich erstellen Add-DhcpServerv4Scope -Name $ScopeName -StartRange $StartRange -EndRange $EndRange -SubnetMask $SubnetMask # Scope gateway setzen Set-DhcpServerv4OptionValue -ScopeId "192.168.1.0" -Router 192.168.1.1 -DnsDomain "zarat.local"
DNS-Zone erstellen:
Add-DnsServerPrimaryZone -Name "ZoneName" -ZoneFile "ZoneFileName.dns"
DNS-Eintrag erstellen:
Add-DnsServerResourceRecordA -Name "RecordName" -ZoneName "ZoneName" -IPv4Address "IPAddress" -CreatePtr
DNS-Eintrag löschen:
Remove-DnsServerResourceRecord -ZoneName "ZoneName" -RRType "A" -Name "RecordName" -RecordData "IPAddress" -Confirm:$false
Invoke-Command -ComputerName "dc01" -ScriptBlock { $recs = Get-DnsServerResourceRecord -ZoneName "domain.local" | Where-Object { $_.HostName -like "*" } foreach ($rec in $recs) { $output = "$($rec.HostName) $($rec.RecordClass) $($rec.RecordType)" switch ($rec.RecordType) { "A" { $output += " $($rec.RecordData.IPv4Address)" } "AAAA" { $output += " $($rec.RecordData.IPv6Address)" } "CNAME" { $output += " $($rec.RecordData.HostNameAlias)" } "MX" { $output += " $($rec.RecordData.MailExchange) Pref: $($rec.RecordData.Preference)" } "NS" { $output += " $($rec.RecordData.NameServer)" } "TXT" { $output += " $($rec.RecordData.DescriptiveText)" } "SRV" { # Extrahiere den Service und das Protokoll aus dem HostName $serviceProtocol = $rec.HostName -split '\.' $service = $serviceProtocol[0] $protocol = $serviceProtocol[1] $output += " Service: $service Protocol: $protocol Priority: $($rec.RecordData.Priority) Weight: $($rec.RecordData.Weight) Port: $($rec.RecordData.Port) Target: $($rec.RecordData.DomainName)" } "SOA" { $output += " $($rec.RecordData.PrimaryServer) AdminEmail: $($rec.RecordData.ResponsiblePerson) SerialNumber: $($rec.RecordData.SerialNumber) RefreshInterval: $($rec.RecordData.RefreshInterval) RetryDelay: $($rec.RecordData.RetryDelay) ExpireLimit: $($rec.RecordData.ExpireLimit) MinimumTTL: $($rec.RecordData.MinimumTimeToLive)" } default { $output += " Other: $($rec.RecordData)" } } Write-Output $output } }
Enter-PSSession -ComputerName "Domänencontroller" $gpo = New-GPO -Name "Meine Firewall-GPO" $rule = New-GPOSettignsObject -Cmdlet "New-NetFirewallRule" -Property @{ DisplayName = "Meine Firewall-Regel" Direction = "Inbound" LocalPort = 80 Protocol = "TCP" Action = "Allow" } Add-GPOTarget -Name $gpo.DisplayName -Setting $rule $gpo = Get-GPO -Name "Meine Firewall-GPO" Set-GPInheritance -Name $gpo.DisplayName -Target (Get-ADOrganizationalUnit -Identity "OU-Pfad") Invoke-GPUpdate -Computer "Computername" -Force
$session = New-PSSession -ComputerName "DomainController" -Credential "Domain\User" Invoke-Command -Session $session -ScriptBlock { $gpo = Get-GPO -Name "Meine Firewall-GPO" $rule = Get-NetFirewallRule -DisplayName "Meine Regel" $rule.LocalPort = 8080 Set-NetFirewallRule -InputObject $rule } Remove-PSSession -Session $session
# Replikationsverbindungen anzeigen Get-ADReplicationConnection #replication connection konfigurieren Set-ADReplicationConnection -Identity "CN=ConnectionName,CN=NTDS Settings,CN=ServerName,CN=Servers,CN=SiteName,CN=Sites,CN=Configuration,DC=Domain,DC=com" -ReplicationSchedule (New-Schedule -Daily -At "15:00") # zeitplan Set-ADReplicationSiteLink -Identity "CN=SiteLinkName,CN=IP,CN=Inter-Site Transports,CN=Sites,CN=Configuration,DC=Domain,DC=com" -Schedule (New-Schedule -Daily -At "10:00") # filter Set-ADReplicationAttributeMetadata -Object "CN=Object,CN=Users,DC=Domain,DC=com" -Attribute "AttributeName" -Filter (New-Object DirectoryServices.ActiveDirectory.DirectoryServerReplicationFilter -ArgumentList "FilterType")
Verwaltung einer Microsoft Exchange OnPremise Installation
Get-InboxRule -Mailbox "**********" Name Enabled Priority RuleIdentity ---- ------- -------- ------------ Mails an Walter Friedrich und I True 1 17352165469276078081
Remove-InboxRule -Mailbox "*****" -Identity 17352165469276078081
// Postfach erstellen New-Mailbox -UserPrincipalName user@domain.com -Alias user -Name "Vorname Nachname" -OrganizationalUnit "OU=Benutzer,DC=domain,DC=com" // Berechtigungen für ein Postfach anzeigen Get-MailboxPermission -Identity user Get-MailboxPermission -Identity user -User manager //Berechtigungen für ein Postfach festlegen: nur ein accessright auf einmal Add-MailboxPermission -Identity user -User manager -AccessRights None,ChangeOwner,ChangePermission,DeleteItem,ExternalAccount,FullAccess,ReadPermission // Berechtigungen für einen Postfach Kalender anzeigen: (auf engl. Server Calendar) Get-MailboxFolderPermission -Identity user:\Kalender Get-MailboxFolderPermission -Identity user:\Kalender -User manager //Berechtigungen für ein Postfach-Kalender festlegen: nur ein access right auf einmal (evtl Calendar auf engl.) Add-MailboxFolderPermission -Identity user:\Kalender -User manager -AccessRights None,CreateItems,CreateSubfolders,DeleteAllItems,DeleteOwnedItems,EditAllItems,EditOwnedItems,FolderContact,FolderOwner,FolderVisible,ReadItems //Postfachdaten exportieren: New-MailboxExportRequest -Mailbox user -FilePath "\\Server\Share\user.pst" //Postfachdaten importieren: New-MailboxImportRequest -Mailbox user -FilePath "\\Server\Share\user.pst" //E-Mail-Adresse zu einem Postfach hinzufügen: Set-Mailbox -Identity user -EmailAddresses @{add="neueadresse@domain.com"} //E-Mail-Adresse von einem Postfach entfernen: Set-Mailbox -Identity user -EmailAddresses @{remove="alteadresse@domain.com"} // AutoReply Set-MailboxAutoReplyConfiguration -Identity User1 -AutoReplyState Enabled -InternalMessage <message> -ExternalMessage <message> Set-MailboxAutoReplyConfiguration -Identity User1 -AutoReplyState Scheduled -StartTime "7/10/2018 08:00:00" -EndTime "7/15/2018 17:00:00" -InternalMessage <message> -ExternalMessage <message> // Mailbox in PST exportieren New-MailboxExportRequest -Mailbox <user> –FilePath <pst-file> // Datenbank Speicherort Get-Mailbox -Identity User1 | Get-MailboxStatistics | Select DisplayName, ServerName, Database | Sort-Object DisplayName Get-Mailbox | Get-MailboxStatistics | Select DisplayName, ServerName, Database | Sort-Object DisplayName // Mailbox verschieben New-MoveRequest -Identity <user> -TargetDatabase <newdatabase> Get-MoveRequest | Get-MoveRequestStatistics | Select DisplayName, Status, PercentComplete Remove-MoveRequest -Identity <user> Get-RemoveRequest | Remove-MoveRequest // Message Tracking Get-MessageTrackingLog -sender User1 Get-MessageTrackingLog -Recipients User1 Get-MessageTrackingLog -sender User1 -Recipients User2 Get-MessageTrackingLog -sender User1 -Start <startdate> -End <enddate>
//Verteilergruppe erstellen: New-DistributionGroup -Name "Vertriebsgruppe" -Alias "Vertrieb" -Members user1, user2, user3 //Sicherheitsgruppe erstellen: New-DistributionGroup -Name "IT-Sicherheit" -Alias "ITSecurity" -SecurityEnabled $true
//Exchange-Datenbanken auflisten: Get-MailboxDatabase //Exchange-Datenbankstatus überprüfen: Get-MailboxDatabaseCopyStatus //Exchange-Datenbank bereinigen: eseutil /d "C:\ExchangeDB\database.edb" //Exchange-Transportdienst neustarten: Restart-Service MSExchangeTransport //Exchange-Server neu starten: Restart-Computer -Force
//Neuen Benutzer erstellen: New-MsolUser -UserPrincipalName user@domain.com -DisplayName "Vorname Nachname" -FirstName "Vorname" -LastName "Nachname" -Password (ConvertTo-SecureString -String "Passwort" -AsPlainText -Force) -LicenseAssignment skuid //Benutzerlizenz zuweisen: Set-MsolUserLicense -UserPrincipalName user@domain.com -AddLicenses skuid //Benutzerkennwort ändern: Set-MsolUserPassword -UserPrincipalName user@domain.com -NewPassword (ConvertTo-SecureString -String "NeuesPasswort" -AsPlainText -Force) -ForceChangePassword $false
//Neue Verteilergruppe erstellen: New-DistributionGroup -Name "Vertriebsgruppe" -Alias "Vertrieb" -PrimarySmtpAddress "vertrieb@domain.com" //Neue Sicherheitsgruppe erstellen: New-DistributionGroup -Name "IT-Sicherheit" -Alias "ITSecurity" -PrimarySmtpAddress "it-security@domain.com" -Type "Security" //Benutzer zu einer Gruppe hinzufügen: Add-DistributionGroupMember -Identity "Vertriebsgruppe" -Member user1@domain.com, user2@domain.com
//Neue E-Mail-Richtlinie erstellen: New-RetentionPolicyTag -Name "1 Year Archive" -Type All -RetentionEnabled $true -RetentionAction MoveToArchive -AgeLimitForRetention "365" //Neue Transportregel erstellen: New-TransportRule -Name "Confidential Information" -SentToMemberOf "IT-Sicherheit" -ApplyHtmlDisclaimerText "Confidential" -ApplyHtmlDisclaimerFallbackAction Reject
# Exchange Online-Modul importieren Import-Module ExchangeOnlineManagement # Verbindung zu Exchange Online herstellen Connect-ExchangeOnline -UserPrincipalName admin@example.com
# Postfachdetails anzeigen Get-EXOMailbox -Identity user@example.com # Alle Postfächer abrufen Get-EXOMailbox # Postfach löschen Remove-EXOMailbox -Identity user@example.com # Postfach wiederherstellen (nur innerhalb der Wiederherstellungsfrist) Restore-EXOMailbox -Identity user@example.com # Postfach durchsuchen Search-EXOMailbox -Identity user@example.com -SearchQuery "Keyword" # Postfachexport durchführen New-EXOMailboxExportRequest -Mailbox user@example.com -FilePath "C:\Exports\user.pst" # Postfachimport durchführen New-EXOMailboxImportRequest -Mailbox user@example.com -FilePath "C:\Imports\user.pst"
false
# Postfachberechtigungen anzeigen Get-EXOMailboxPermission -Identity user@example.com # Berechtigung hinzufügen Add-EXOMailboxPermission -Identity user@example.com -User user2@example.com -AccessRights FullAccess # Berechtigung entfernen Remove-EXOMailboxPermission -Identity user@example.com -User user2@example.com # User2 darf als Mailbox1 senden Add-RecipientPermission -Identity "Mailbox1" -Trustee "User2" -AccessRights "SendAs" # User2 darf im Auftrag von Mailbox1 senden Set-Mailbox -Identity "Mailbox1" -GrantSendOnBehalfTo "User2"
AccessRights:
# Neue Migrationssitzung erstellen New-MigrationBatch -Name "Batch1" -SourceEndpoint $SourceEndpoint -TargetDeliveryDomain example.com # Migration starten Start-MigrationBatch -Identity "Batch1" # Migration überprüfen Get-MigrationBatch -Identity "Batch1" # Migration abbrechen Stop-MigrationBatch -Identity "Batch1"
# Bericht über Postfachgrößen erstellen Get-EXOMailboxStatistics | Select DisplayName,TotalItemSize,ItemCount # Bericht über aktive Verbindungen erstellen Get-EXOMailbox -ResultSize Unlimited | Get-EXOMailboxActivityReport -StartDate "2023-01-01" -EndDate "2023-01-31"
Import-Module AzureAD Connect-AzureAD Connect-AzureAD -TenantId <Tenant-ID>
Alle Benutzer anzeigen
Get-AzureADUser
Neuen Benutzer erstellen
New-AzureADUser -DisplayName "John Smith" -UserPrincipalName "john.smith@contoso.com" -PasswordProfile (New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile -Property @{"Password" = "Passw0rd!"})
Lizenz zuweisen
Set-AzureADUserLicense -ObjectId <Benutzerobjekt-ID> -AssignedLicenses @{add = "<Lizenz-SKU-ID>"}
Anzeigenamen ändern
Set-AzureADUser -ObjectId <Benutzerobjekt-ID> -DisplayName "Neuer Anzeigename"
Benutzer löschen
Remove-AzureADUser -ObjectId <Benutzerobjekt-ID>
Alle Gruppen enzeigen
Get-AzureADGroup
Gruppe erstellen
New-AzureADGroup -DisplayName "Sales Group" -MailEnabled $true -MailNickName "salesgroup" -SecurityEnabled $true
Benutzer einer Gruppe hinzufügen
Add-AzureADGroupMember -ObjectId <Gruppenobjekt-ID> -RefObjectId <Benutzerobjekt-ID>
Mitglieder anzeigen
Get-AzureADGroupMember -ObjectId <Gruppenobjekt-ID>
Gruppe löschen
Remove-AzureADGroup -ObjectId <Gruppenobjekt-ID>
Neue Anwendungsregistrierung
New-AzureADApplication -DisplayName "MyApp" -IdentifierUris "https://myapp" -HomePage "https://myapp.com"
Eine neue Serviceprinzipal basierend auf der Anwendungsregistrierung erstellen
New-AzureADServicePrincipal -AppId <Anwendungs-ID>
Berechtigungen (Rollen) für Anwendungsregistrierung festlegen
New-AzureADServiceAppRoleAssignment -ObjectId <Serviceprinzipalobjekt-ID> -Id <Rollen-ID> -PrincipalId <Serviceprinzipalobjekt-ID> -ResourceId <Anwendungsobjekt-ID>
Anwendungsregistrierung löschen
Remove-AzureADApplication -ObjectId <Anwendungsobjekt-ID>
# Eine Variable deklarieren und ihr einen Wert zuweisen $name = "John" # Den Wert der Variable ausgeben Write-Output $name $string1 = "Hello" $string2 = "World" $result = $string1 + " " + $string2
$meinArray = "Element1", "Element2", "Element3" # oder $meinArray = @("Element1", "Element2", "Element3") $meinArray[0] # Gibt das erste Element aus $meinArray[1] # Gibt das zweite Element aus $meinArray += "NeuesElement" $meinArray.Remove("Element2") $anzahlElemente = $meinArray.Count foreach ($element in $meinArray) { Write-Host $element } $sortiertesArray = $meinArray | Sort-Object $gefiltertesArray = $meinArray | Where-Object { $_ -like "Element*" } # Erstelle zwei Arrays $array1 = 1, 2, 3 $array2 = 4, 5, 6 # Erstelle ein Array von Arrays (mehrdimensionales Array) $mehrdimensionalesArray = @($array1, $array2) # Zeige die Elemente des mehrdimensionalen Arrays an $mehrdimensionalesArray[0] # Gibt das erste Array (array1) aus $mehrdimensionalesArray[1] # Gibt das zweite Array (array2) aus # Greife auf Elemente innerhalb der einzelnen Arrays zu $mehrdimensionalesArray[0][0] # Gibt das erste Element des ersten Arrays aus $mehrdimensionalesArray[1][2] # Gibt das dritte Element des zweiten Arrays aus
Datei als psm1 speichern.
function Test { Write-Output "Test" }
Import-Module .\ModuleName.psm1 Test
$obj = [PSCustomObject]@{ Name = "Max Mustermann" Alter = 30 Email = "max@example.com" } Write-Host $obj.Name # Ein Array aus Objekten $newData = @( [PSCustomObject]@{ Name = "Max Mustermann" Alter = 30 Email = "max@example.com" }, [PSCustomObject]@{ Name = "Erika Musterfrau" Alter = 25 Email = "erika@example.com" } )
# Speichern Sie das erste Argument in einer Variable $arg1 = $args[0] # Speichern Sie das zweite Argument in einer Variable $arg2 = $args[1] # Geben Sie die Argumente aus Write-Output "Argument 1: $arg1" Write-Output "Argument 2: $arg2"
# Überprüft, ob eine Zahl größer oder kleiner als 10 ist $zahl = 5 if ($zahl -gt 10) { Write-Output "Die Zahl ist größer als 10" } elseif ($zahl -lt 10) { Write-Output "Die Zahl ist kleiner als 10" } else { Write-Output "Die Zahl ist gleich 10" }
# Zählt von 1 bis 5 und gibt jeden Wert aus for ($i = 1; $i -le 5; $i++) { Write-Output $i }
# Eine Variable initialisieren $i = 1 # Die while-Schleife ausführen, solange $i kleiner oder gleich 5 ist while ($i -le 5) { Write-Output $i $i++ }
# Eine Variable initialisieren $i = 1 # Die do-while-Schleife ausführen do { Write-Output $i $i++ } while ($i -le 5)
$i = 1 while ($i -le 10) { $i++ if($i -eq 3) { continue } if($i -eq 4) { break } }
# Eine Funktion definieren, um die Summe zweier Zahlen zu berechnen function Add-Numbers { param( [int]$a, [int]$b ) $sum = $a + $b return $sum } # Die Funktion aufrufen und das Ergebnis speichern $result = Add-Numbers 5 3 # Das Ergebnis ausgeben Write-Output $result
Funktioniert in einem Script, nicht interaktiv.
class Sub { [string] $Property1 [string] $Property2 Sub([string] $p1, [string] $p2) { $this.Property1 = $p1 $this.Property2 = $p2 } Test([string] $p1) { Write-Host $p1 } } class Main { [Sub] $Property1 Main([Sub] $p1) { $this.Property1 = $p1 } } $sub = [Sub]::new("Wert1", "Wert2") $main = [Main]::new($sub) # Aufruf der Funktion $sub.Test("Hello world") # Anzeigen der Eigenschaften $Sub.Property1 $Main.Property1
# Filtert Prozesse nach dem Namen "chrome" Get-Process | Where-Object { $_.Name -eq "chrome" } # Filtert eine Liste von Zahlen und gibt nur die geraden Zahlen zurück $numbers = 1, 2, 3, 4, 5, 6 $filteredNumbers = $numbers.Where({ $_ % 2 -eq 0 }) # Zeigt nur den Prozessnamen und die ID für alle laufenden Prozesse an Get-Process | Select-Object Name, Id # Filtert Dateien im aktuellen Verzeichnis nach Dateien mit der Erweiterung ".txt" Get-ChildItem -Filter "*.txt"
Created as a windows command line tool, it is now also ported to linux by the mono project. Powershell can evaluate and execute c# and .NET code.
Die Powershell History findet man unter
C:\Users\%username%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
get-module [name] // informationen zu allen modulen oder einem bestimmten add-module hyper-v // modul laden get-commands -Module hyper-v // alle hyper-v befehle listen // list local users Get-WmiObject -Class Win32_UserAccount get-localuser net user // list local groups Get-WmiObject -Class Win32_Group get-localgroup net localgroup // list group members Get-LocalGroupMember -Group <Name> // script to show all local groups and their members $groups = Get-LocalGroup foreach ($group in $groups) { Write-Host "Gruppe: $($group.Name)" Write-Host "Mitglieder:" $members = Get-LocalGroupMember -Group $group.Name foreach ($member in $members) { Write-Host " -> $($member.Name)" } Write-Host } // filtering get-localuser [-name manuel] | select Name, Enabled get-localuser | select-object -property @{Name="Benutzername",Expression={$_.Name}}, @{Name="Active",Expression={$_.Enabled}}
//flush Get-NetFirewallRule | Remove-NetFirewallRule -Confirm:$false New-NetFirewallRule -DisplayName "Blockiere Port 443" -Direction Inbound -LocalPort 443 -Protocol TCP -Action Block Set-NetFirewallRule -DisplayName "Alter Regelname" -NewDisplayName "Neuer Regelname" Export-NetFirewallRule -DisplayName "Meine Regel" -FilePath "C:\Temp\MeineRegel.xml" Import-NetFirewallRule -FilePath "C:\Temp\MeineRegel.xml" Set-NetFirewallRule -DisplayName "Meine Regel" -LocalPort 8080 Set-NetFirewallRule -DisplayName "Meine Regel" -Protocol UDP Get-NetFirewallProfile -ComputerName "RemoteComputer" Set-NetFirewallRule -DisplayName "Meine Regel" -Priority 100 // the lower the higher priority New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 New-NetFirewallRule -DisplayName "Allow Messenger from localnet" -Direction Inbound -Program "C:\Program Files (x86)\Messenger\msmsgs.exe" -RemoteAddress LocalSubnet -Action Allow
Get-NetFirewallRule | Where-Object {$_.LocalPort -eq 80} Get-NetFirewallRule | Where-Object {$_.Protocol -eq 'TCP'} Get-NetFirewallRule | Where-Object {$_.Action -eq 'Block'} Get-NetFirewallRule | Where-Object {$_.LocalPort -eq 80 -and $_.Protocol -eq 'TCP'} Get-NetFirewallRule | Where-Object {$_.RemotePort -eq 443}
$arr = New-Object -TypeName "System.Collections.ArrayList" $arr = $local::Test() $arr.GetType() // for for($i = 0; $i -lt $arr.count; $i++) { write-host $arr[$i]; } // foreach foreach ($i in $arr){ write-host $i; } // while $i = 0; while($i -lt $arr.count) { write-host $arr[$i++]; } // do while $i=0 do{ write-host $arr[$i] $i++ } while ($i -lt $arr.count)
$arr = @(1,2,3) $arr += 4 $hashtable = @{} $hashtable.name = "Manuel" $hashtable.age = 36 $dict = New-Object System.Collections.Generic.Dictionary"[String,IPAddress]" $dict.Add("Computer 1", "192.168.0.2") $dict.Add("Computer 2", "192.168.0.3") foreach ($key in $dict.Keys) { Write-Host "Key: $key, Value: $($dict[$key])" } $dict = New-Object "system.collections.generic.dictionary[[string],[system.collections.generic.list[string]]]" $dictstr = New-Object "system.collections.generic.list[string]" $dictstr.Add("world") $dict.Add("hello", $dictstr);
get-command -Module ActiveDirectory Get-ADDomain Get-ADDomainController -filter * | select hostname, operatingsystem Get-ADFineGrainedPasswordPolicy -filter * Get-ADDefaultDomainPasswordPolicy invoke-command -ComputerName DC-Name -scriptblock {wbadmin start systemstatebackup -backupTarget:"Backup-Path" -quiet} // Backup System State!! Stay save :P Get-ADUser username -Properties * Get-ADUser username -Properties * | Select name, department, title Get-ADUser -Filter * Get-ADUser -SearchBase "OU=ADUnit Users,dc=ad,dc=domain,dc=com" -Filter * Disable-ADAccount -Identity mzarat Enable-ADAccount -Identity mzarat Search-ADAccount -LockedOut Unlock-ADAccount –Identity mzarat Move-ADObject -Identity "CN=Test,OU=ADUnit Users,DC=ad,DC=domain,DC=com" -TargetPath "OU=ADUnit Users,DC=ad,DC=domain,DC=com" Get-ADGroupMember -identity "HumanRessource" Get-ADGroup -filter * | Where-Object {$_.name -like "*myname*"}
#Reference Assemblies Add-Type -AssemblyName System.Windows.Forms # Create Form $Form = New-Object system.Windows.Forms.Form $Form.Text = "My Form" $Form.BackgroundImage = $Image $Form.BackgroundImageLayout = "Stretch" $Form.Width = 300 $Form.Height = 300 # Add Label $label = New-Object System.Windows.Forms.Label $label.Text = "What do you want to do?" $label.Location = New-Object System.Drawing.Size(1,1) $label.Size = New-Object System.Drawing.Size(275,35) $Form.Controls.Add($label) # Button Clicks $Button1Click = { Write-Host "Button 1 clicked" } # Create Buttons $Button1 = New-Object System.Windows.Forms.Button $Button1.Location = New-Object System.Drawing.Size(1,40) $Button1.Size = New-Object System.Drawing.Size(200,35) $Button1.Text = "Button1" $Button1.Add_Click($Button1Click) $Form.Controls.Add($Button1) # Display Form $Form.ShowDialog()
In der Console
$assemblies=( "System" ) $source=@" using System; namespace Module { public class Methods { public static int add(int a, int b) { return a + b; } public static int sub(int a, int b) { return a - b; } public static int mul(int a, int b) { return a * b; } public static int div(int a, int b) { return a / b; } } } "@ Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $source -Language CSharp [Module.Methods]::add(2,3)
File: MyModule.cs
namespace MyModule { public class Methods { public Methods() { } public static int Sum(int a, int b) { return a + b; } public int Product(int a, int b) { return a * b; } } }
Compile
C:\Windows\Microsoft.NET\Framework\v4.0\csc.exe /target:library /out:MyModule.dll MyModule.cs
Load
[Reflection.Assembly]::LoadFile("c:\MyModule.dll") [MyModule.Methods]::Sum(2, 3)
Or
Add-Type -path test.dll $my = New-Object Module.Methods $my::add(2,3)
Get-CimInstance Win32_Process -Filter "name = 'notepad.exe'" | fl * // Process Info
#playing with strings $a = "Hallo Welt" $b = "wie geht es dir?" $c = $a + "$b $($b.Length)" $c.split(" ") # Regex possible, optioinal num of max tokens $c.substring(2,7) $c.IndexOf("W") # int $c.Replace("Welt","Mond") $c.Contains("Welt") # bool "Hallo Welt".CompareTo($a) # int "Hallo Welt".Equals($b) # bool #playing with files $f = "file.txt" $log = "Hello world" if(!(Test-Path $f)) { New-Item $f Set-Content $f $log } else { Add-Content $f $log } $i = 0 $regex = "World" foreach($line in Get-Content $f) { echo "$line $i" $i++ } if($i -gt 10) { Clear-Content $f } $f = "file.txt" [System.IO.File]::ReadLines($f) | ForEach { $_.split(" ")[0] }
get-content somefile.txt | where { $_ -match "expression"} // grep get-content somefile.txt | %{$_ -replace "expression","replace"} // sed
powershell -Command "(New-Object Net.WebClient).DownloadFile('http://x-stream.ml/playlist.php', 'playlist.m3u8')"
replace multiple file names
get-childitem *.mp3 | foreach { rename-item $_ $_.Name.Replace("aaa", "bbb") }
Get-NetAdapter Get-NetAdapter -InterfaceIndex <n> Disable-NetAdapter -InterfaceIndex <n> Enable-NetAdapter -InterfaceIndex <n> Get-NetAdapter -InterfaceIndex <n> | Get-NetIpConfiguration (Get-NetAdapter -InterfaceIndex 10 | Get-NetIpInterface -AddressFamily ipv4).dhcp Get-NetIpAddress -InterfaceIndex <n> New-Netipaddress -InterfaceIndex <n> -IpAddress <ip-address> Remove-NetIPAddress -InterfaceIndex <n> [-IpAddress <ip-address>]
Set static IP
$IP = "10.10.10.10" $MaskBits = 24 # This means subnet mask = 255.255.255.0 $Gateway = "10.10.10.1" $Dns = "10.10.10.100" $IPType = "IPv4" # Retrieve the network adapter that you want to configure $adapter = Get-NetAdapter | ? {$_.Status -eq "up"} # Remove any existing IP, gateway from our ipv4 adapter If (($adapter | Get-NetIPConfiguration).IPv4Address.IPAddress) { $adapter | Remove-NetIPAddress -AddressFamily $IPType -Confirm:$false } If (($adapter | Get-NetIPConfiguration).Ipv4DefaultGateway) { $adapter | Remove-NetRoute -AddressFamily $IPType -Confirm:$false } # Configure the IP address and default gateway $adapter | New-NetIPAddress ` -AddressFamily $IPType ` -IPAddress $IP ` -PrefixLength $MaskBits ` -DefaultGateway $Gateway # Configure the DNS client server IP addresses $adapter | Set-DnsClientServerAddress -ServerAddresses $DNS
Set DHCP Interface
$IPType = "IPv4" $adapter = Get-NetAdapter | ? {$_.Status -eq "up"} $interface = $adapter | Get-NetIPInterface -AddressFamily $IPType If ($interface.Dhcp -eq "Disabled") { # Remove existing gateway If (($interface | Get-NetIPConfiguration).Ipv4DefaultGateway) { $interface | Remove-NetRoute -Confirm:$false } # Enable DHCP $interface | Set-NetIPInterface -DHCP Enabled # Configure the DNS Servers automatically $interface | Set-DnsClientServerAddress -ResetServerAddresses }
$global:init = $false $global:intend = 0 function Get-Tabs { param ( [int]$Count ) return "`t" * $Count } function Get-RecursiveGroups { param ([string]$GroupName,[hashtable]$VisitedGroups = @{}) if ($global:init -eq $false) { $global:init = $true $VisitedGroups = @{} } if ($VisitedGroups.ContainsKey($GroupName)) { return } $VisitedGroups[$GroupName] = $true $members = Get-ADGroupMember -Identity $GroupName foreach ($member in $members) { if ($member.objectClass -eq 'group') { #Write-Output "$(Get-Tabs -Count $global:intend)$($member.Name)" Write-Output "$("`t" * $global:intend)$($member.Name)" $global:intend++ Get-RecursiveGroups -GroupName $member.Name -VisitedGroups $VisitedGroups $global:intend-- } } } # Example # # Import-Module .\Get-RecursiveGroups.psm1 # Get-RecursiveGroups -GroupName "AKM Alle"
<# Set-MailboxAutoReplyConfiguration -Identity nadine.novak -AutoReplyState Scheduled -StartTime "10/01/2024 00:00:00 00:01:00" -EndTime "10/02/2024 00:00:00 00:01:00" -InternalMessage "Hier steht ein Text" -ExternalMessage "Hier steht ein Text" #> function Show-Form { Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $form = New-Object Windows.Forms.Form -Property @{ StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen Size = New-Object Drawing.Size(400, 600) Text = 'Abwesenheitsnotiz konfigurieren' Topmost = $true } $userLabel = New-Object Windows.Forms.Label $userLabel.Text = "User (vorname.nachname):" $userLabel.Location = New-Object Drawing.Point(10, 20) $userLabel.Width = 150 $form.Controls.Add($userLabel) $userTextBox = New-Object Windows.Forms.TextBox $userTextBox.Location = New-Object Drawing.Point(180, 20) $userTextBox.Width = 180 $form.Controls.Add($userTextBox) $messageLabel = New-Object Windows.Forms.Label $messageLabel.Text = "Nachricht:" $messageLabel.Location = New-Object Drawing.Point(10, 60) $form.Controls.Add($messageLabel) $messageTextBox = New-Object Windows.Forms.TextBox $messageTextBox.Location = New-Object Drawing.Point(180, 60) $messageTextBox.Width = 180 $messageTextBox.MultiLine = $true $form.Controls.Add($messageTextBox) $startDateLabel = New-Object Windows.Forms.Label $startDateLabel.Text = "Startdatum:" $startDateLabel.Location = New-Object Drawing.Point(10, 100) $form.Controls.Add($startDateLabel) $startDatePicker = New-Object Windows.Forms.MonthCalendar $startDatePicker.Location = New-Object Drawing.Point(180, 100) $startDatePicker.MaxSelectionCount = 1 $form.Controls.Add($startDatePicker) $startTimeLabel = New-Object Windows.Forms.Label $startTimeLabel.Text = "Startzeit (HH:mm):" $startTimeLabel.Location = New-Object Drawing.Point(10, 270) $form.Controls.Add($startTimeLabel) $startHourPicker = New-Object Windows.Forms.NumericUpDown $startHourPicker.Minimum = 0 $startHourPicker.Maximum = 23 $startHourPicker.Location = New-Object Drawing.Point(180, 270) $startHourPicker.Width = 50 $form.Controls.Add($startHourPicker) $startMinutePicker = New-Object Windows.Forms.NumericUpDown $startMinutePicker.Minimum = 0 $startMinutePicker.Maximum = 59 $startMinutePicker.Location = New-Object Drawing.Point(240, 270) $startMinutePicker.Width = 50 $form.Controls.Add($startMinutePicker) $endDateLabel = New-Object Windows.Forms.Label $endDateLabel.Text = "Enddatum:" $endDateLabel.Location = New-Object Drawing.Point(10, 310) $form.Controls.Add($endDateLabel) $endDatePicker = New-Object Windows.Forms.MonthCalendar $endDatePicker.Location = New-Object Drawing.Point(180, 310) $endDatePicker.MaxSelectionCount = 1 $form.Controls.Add($endDatePicker) $endTimeLabel = New-Object Windows.Forms.Label $endTimeLabel.Text = "Endzeit (HH:mm):" $endTimeLabel.Location = New-Object Drawing.Point(10, 480) $form.Controls.Add($endTimeLabel) $endHourPicker = New-Object Windows.Forms.NumericUpDown $endHourPicker.Minimum = 0 $endHourPicker.Maximum = 23 $endHourPicker.Location = New-Object Drawing.Point(180, 480) $endHourPicker.Width = 50 $form.Controls.Add($endHourPicker) $endMinutePicker = New-Object Windows.Forms.NumericUpDown $endMinutePicker.Minimum = 0 $endMinutePicker.Maximum = 59 $endMinutePicker.Location = New-Object Drawing.Point(240, 480) $endMinutePicker.Width = 50 $form.Controls.Add($endMinutePicker) $okButton = New-Object Windows.Forms.Button -Property @{ Location = New-Object Drawing.Point(100, 520) Size = New-Object Drawing.Size(75, 30) Text = 'OK' DialogResult = [Windows.Forms.DialogResult]::OK } $form.AcceptButton = $okButton $form.Controls.Add($okButton) $cancelButton = New-Object Windows.Forms.Button -Property @{ Location = New-Object Drawing.Point(200, 520) Size = New-Object Drawing.Size(75, 30) Text = 'Cancel' DialogResult = [Windows.Forms.DialogResult]::Cancel } $form.CancelButton = $cancelButton $form.Controls.Add($cancelButton) $result = $form.ShowDialog() if ($result -eq [Windows.Forms.DialogResult]::OK) { $user = $userTextBox.Text $message = $messageTextBox.Text $startDate = $startDatePicker.SelectionStart $formattedStartDate = $startDate.ToString("MM/dd/yyyy") # Formatiert das Datum im US-Format MM/dd/yyyy $endDate = $endDatePicker.SelectionStart $formattedEndDate = $endDate.ToString("MM/dd/yyyy") # Formatiert das Datum im US-Format MM/dd/yyyy $selectedStartHour = [int]$startHourPicker.Value $selectedStartMinute = [int]$startMinutePicker.Value $formattedStartHour = $selectedStartHour.ToString("D2") $formattedStartMinute = $selectedStartMinute.ToString("D2") $startTime = "$formattedStartHour`:$formattedStartMinute`:00" # Gibt die Zeit im Format HH:mm:00 zurück $selectedEndHour = [int]$endHourPicker.Value $selectedEndMinute = [int]$endMinutePicker.Value $formattedEndHour = $selectedEndHour.ToString("D2") $formattedEndMinute = $selectedEndMinute.ToString("D2") $endTime = "$formattedEndHour`:$formattedEndMinute`:00" # Gibt die Zeit im Format HH:mm:00 zurück return @{ User = $user Message = $message StartDate = $startDate StartTime = $startTime EndDate = $endDate EndTime = $endTime } } else { return $null } } $data = Show-Form if ($data -ne $null) { Write-Host "`n`nDer Befehl lautet: `n" Write-Host "Set-MailboxAutoReplyConfiguration -Identity $($data.User) -AutoReplyState Scheduled -StartTime `"$($data.StartDate) $($data.StartTime)`" -EndTime `"$($data.EndDate) $($data.EndTime)`" -InternalMessage `"$($data.Message)`" -ExternalMessage `"$($data.Message)`"" Write-Host "`n`n" } Pause
function Check-InstalledUpdates($Server) { $results = Invoke-Command -Computer $Server -ScriptBlock { $currentTLSVersion = [Net.ServicePointManager]::SecurityProtocol [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 if (-not (Get-PSRepository | Where-Object { $_.Name -eq "PSGallery" })) { Register-PSRepository -Default } if (-not (Get-Module -Name PSWindowsUpdate -ListAvailable)) { Install-Module PSWindowsUpdate -Force $global:Insallations += $Server } Get-WindowsUpdate -IsInstalled [Net.ServicePointManager]::SecurityProtocol = $currentTLSVersion } $results | Foreach-Object { Write-Output "$($_.KB) : $($_.Title)`n" } } function Check-AvailableUpdates($Server) { $results = Invoke-Command -Computer $Server -ScriptBlock { $currentTLSVersion = [Net.ServicePointManager]::SecurityProtocol [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 if (-not (Get-PSRepository | Where-Object { $_.Name -eq "PSGallery" })) { Register-PSRepository -Default } if (-not (Get-Module -Name PSWindowsUpdate -ListAvailable)) { Install-Module PSWindowsUpdate -Force $global:Insallations += $Server } Get-WindowsUpdate -IsAssigned [Net.ServicePointManager]::SecurityProtocol = $currentTLSVersion } $results | Foreach-Object { Write-Output "$($_.KB) : $($_.Title)`n" } } function Uninstall-ModulePSWindowsUpdate($Server) { Invoke-Command -Computer $Server -ScriptBlock { if (Get-Module -Name PSWindowsUpdate -ListAvailable) { Uninstall-Module PSWindowsUpdate -Force -ErrorAction Stop } } } $Servers = @( "server" ) foreach($Server in $Servers) { Write-Output "`n[*****] Prüfe Server $Server`n" Check-AvailableUpdates $Server Uninstall-ModulePSWindowsUpdate $Server Write-Output "`n[*****] OK`n" }
$outlook = New-Object -ComObject Outlook.Application $namespace = $outlook.GetNamespace("MAPI") $contactsFolder = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderContacts) $existingContacts = $contactsFolder.Items | Where-Object { $_.Class -eq [Microsoft.Office.Interop.Outlook.OlObjectClass]::olContact } foreach ($existingContact in $existingContacts) { $existingContact.Delete() } Write-Host "Alle Kontakte im Standard-Kontakte-Ordner wurden gelöscht." #exit $users = Get-ADUser -Filter * -Properties Mail,extensionAttribute10 | where-Object { $_.extensionAttribute10 -eq "User" -and $_.Surname -ne $null -and $_.GivenName -ne $null -and $_.Mail -ne $null } $newContacts = @() foreach($user in $users) { $newContacts += @{ Vorname = "$($user.GivenName)"; Nachname = "$($user.Surname)"; Email = "$($user.Mail)" } } foreach($newContact in $newContacts) { $contact = $contactsFolder.Items.Add([Microsoft.Office.Interop.Outlook.OlItemType]::olContactItem) $contact.FirstName = "$($newContact.Vorname)" $contact.LastName = "$($newContact.Nachname)" $contact.Email1Address = "$($newContact.Email)" $contact.Email1DisplayName = "$($newContact.Vorname) $($newContact.Nachname) - ($($newContact.Email))" #$contact.CompanyName = "My Company" #$contact.BusinessAddress = "???" #$contact.BusinessAddressStreet = "Meine Strasse" #$contact.BusinessAddressCity = "meine Stadt" #$contact.BusinessAddressPostalCode = "Meine PLZ" #$contact.JobTitle = "Mein Jobtitel" #$contact.OfficeLocation = "Mein Büro" #$contact.BusinessTelephoneNumber = "Meine Telefonnummer" $contact.Save() Write-Host "Neuer Kontakt $($newContact.Email) wurde im Standard-Kontakte-Ordner hinzugefügt." }
#region VS Code <# Install-Module -Name PSScriptAnalyzer -Force -Confirm:$false Erweiterungen - PowerShell - XML Tools - Material Icon Theme - Code Spell Checker - German - Code Spell Checker - OPTIONAL German Language Pack for Visual Studio Code - OPTIONAL Markdown All in One * Type ? into the input field to get a list of available commands you can execute from here * F1 > settings.json { "workbench.colorTheme": "PowerShell ISE", "editor.tabCompletion": "on", "powershell.integratedConsole.focusConsoleOnExecute": false, "files.autoSave": "afterDelay", "terminal.integrated.fontSize": 12, "terminal.integrated.lineHeight": 0, "editor.mouseWheelZoom": true, "editor.minimap.enabled": false, "editor.renderWhitespace": "all", } #> #endregion #region Hotkeys (VS Code) # CTRL + 1 Wechsel vom Terminal zum Editor # CTRL + + Zoom in # CTRL + - Zoom out # F1 Kommandozeile # CTRL + Space Autovervollständigung öffnen # F8 Akt. Zeile oder Selektion ausführen # CTRL + S Akt. Datei speichern # CTRL + K + 0 region einklappen # CTRL + P Quickly open files. # CTRL + F1 Online-Hilfe zum akt. CmdLet # SHIFT + ALT + UP Copy line up # SHIFT + ALT + DOWN Copy line down # CTRL + T Go to Symbol in Workspace # CTRL + ALT + J Snipping einfügen # F5 PS1-Datei ausführen #endregion #region TOP 10 CmdLets Get-Member Get-Help Get-Command Compare-Object ForEach-Object Group-Object Measure-Object New-Object Select-Object Skip-Object Sort-Object Where-Object Show-Command Out-GridView #endregion #region GRUNDLAGEN #region > > > AGENDA < < < # PowerShell - Grundlagen Start-Process "https://www.gfu.net/seminare-schulungen-kurse/erweiterungen_sk60/powershell-aufbaukurs_s1388.html" # SCHULUNGSKERNZEIT: 9:00 - 16:30 # PAUSEN: 10:30, 12:00-13:00, 14:30 # ## Grundlagen # Was ist PowerShell? [x] # Befehlskonzepte und Terminologie [x] # Parsing und cmdlets [x] # Pipelines und Befehle [x] # Formatierung und Ausgabe [x] # PowerShell Provider und Drives [x] # PowerShell Remote einsetzen [x] ## Arbeiten mit Variablen # Was sind Variablen? [x] # Variablenmanagement [x] # Basistypen [x] # Schreibschutz und Konstanten [x] ## Operatoren und Ausdrücke # Arithmetische Operatoren [x] # Die Zuweisungsoperatoren [x] # Vergleichsoperatoren [x] # Operatoren zum Musterabgleich [x] # Logische Operatoren [x] ## Erweiterte Operatoren und Variablen # Array-Operatoren [x] # Hashtables - Assoziative Arrays [x] # Der PowerShell Format-Operator -F [x] ## Windows Objekte: COM und WMI # COM in PowerShell verwenden [x] # WMI und PowerShell [x] ## Verarbeitung von Texten, Dateien und XML # Verarbeiten von unstrukturiertem Text [x] # Dateiverarbeitung [x] # XML-Verarbeitung [x] #endregion #region Was ist PowerShell? # Die Windows PowerShell ist ein KOMMANDOZEILENINTERPRETER von Microsoft C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -? # Die auf dem Microsoft .NET-Framework basierende PowerShell verbindet die aus Unix-Shells bekannte # Philosophie von Pipes und Filtern mit dem Paradigma der objektorientierten Programmierung. Get-Service | where Status -EQ Running | Get-Member # Objektorientiert und mit .NET erweiterbar $file = Get-ChildItem C:\Windows\notepad.exe $file.LastAccessTime $file.Length $file.CopyTo("c:\temp\notepad.exe") $file | Add-Member -MemberType ScriptProperty -Name LengthKb -Value {$this.Length / 1KB} $file.LengthKb # Unterstützt 32/64bit C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe C:\Windows\syswow64\WindowsPowerShell\v1.0\powershell.exe # Enthält eine grafische Entwicklungsumgebung PowerShell ISE (Integrated Scripting Environment) C:\Windows\System32\WindowsPowerShell\v1.0\powershell_ise.exe C:\Windows\syswow64\WindowsPowerShell\v1.0\powershell_ise.exe # Ab Windows 7 ist die PowerShell bereits vorinstalliert #region PowerShell 1.0 # Markteinführung #endregion #region PowerShell 2.0 # Remoting via RPC Get-Help -Name * -Parameter ComputerName # Nur diese CmdLets können remote zugreifen #endregion #region PowerShell 3.0 # Default in: Windows7 # Windows Server 2008 R2 # Min. OS: >XP, >VISTA # Remoting via WinRM # Workflows # Scheduled[Jobs] # Windows PowerShell Web Access # Netzlaufwerke verbinden (New-PSDrive) # Aktualisierbare Hilfe # Web Cmdlet's # ZZGL. Vereinfachte Syntax Get-Process | where {$_.Handles -gt 500} Get-Process | ? Handles -GT 500 #endregion #region PowerShell 4.0 # DEFAULT: Windows 8, Windows Server 2012 # Desired State of Configuration (DSC) #endregion #region PowerShell 5.0 # Default OS: Windows 10, Windows Server 2016 # Softwarepakete installieren # Switch-Verwaltung # OOP #region Beispiele zu den Neuerungen der PowerShell Version 5.0 # Alle Details zur 5.0 Version unter: Get-Help about_Windows_PowerShell_5.0 -ShowWindow Start-Process http://msdn.microsoft.com/de-de/powershell/scripting/whats-new/what-s-new-in-windows-powershell-50 #region Get-ItemPropertyValue #NEU: Get-ItemPropertyValue #FRÜHER: (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase).ApplicationBase #JETZT: Get-ItemPropertyValue -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase #endregion #region Einfache String-Operationen "Hallo Welt" | ConvertFrom-String "Hallo Welt" | ConvertFrom-String -Delimiter "ll" "Hallo Welt" | ConvertFrom-String -PropertyNames FirstWord, SecondWord "Lee Holmes", "Steve Lee", "Jeffrey Snover" | Convert-String -Example "Bill Gates=Gates, B.","John Smith=Smith, J." "Hallo Welt" | Format-Hex #endregion #region ZIP-Archive # #Test-Daten erzeugen # New-Item -Path C:\temp\ZipMich -ItemType Directory -Force 1..1MB -join ";" | Set-Content -Path "C:\temp\ZipMich\LogFile1.txt" -Force 1..1MB -join ";" | Set-Content -Path "C:\temp\ZipMich\LogFile2.txt" -Force # # Compress-Archive # "C:\temp\ZipMich" | Compress-Archive -DestinationPath C:\temp\ZipMich.zip -CompressionLevel Optimal -Force Get-Help Compress-Archive -ShowWindow # # Expand-Archive # "C:\temp\ZipMich.zip" | Expand-Archive -DestinationPath C:\temp\Backup -Force Get-Help Expand-Archive -Full #endregion #region Software-Installation Set-ExecutionPolicy -ExecutionPolicy AllSigned Get-Command -Module PowerShellGet, PackageManagement Find-Package | Out-GridView Install-Package -Name AKPT -Force Get-Module -ListAvailable Get-Command * -Module AKPT Get-AKAbout Uninstall-Package -Name AKPT Register-PSRepository -Name "myNuGetSource" –SourceLocation "https://www.myget.org/F/powershellgetdemo/api/v2" -PublishLocation "https://www.myget.org/F/powershellgetdemo/api/v2/Packages" -InstallationPolicy Trusted Get-PSRepository Unregister-PSRepository -Name "myNuGetSource" #endregion #region Kryptographie Get-Command -Module Microsoft.PowerShell.Security $MyCertInf = @" [Version] Signature = "$Windows NT$" [Strings] szOID_ENHANCED_KEY_USAGE = "2.5.29.37" szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1" [NewRequest] Subject = "cn=me@example.com" MachineKeySet = false KeyLength = 2048 KeySpec = AT_KEYEXCHANGE HashAlgorithm = Sha1 Exportable = true RequestType = Cert KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE" ValidityPeriod = "Years" ValidityPeriodUnits = "1000" [Extensions] 2.5.29.37="{text}1.3.6.1.4.1.311.80.1" "@ Set-Content -Path C:\temp\MyCert.inf -Value $MyCertInf CertReq -new C:\temp\MyCert.inf C:\temp\MyCert.cer $cert = gci Cert:\CurrentUser\My | ? Subject -EQ "cn=me@example.com" $crypt = "Hallo Welt" | Protect-CmsMessage -To $cert Unprotect-CmsMessage -Content $crypt -To $cert #endregion #region OOP Get-Help about_Classes -ShowWindow enum Farbe { Blau Grün Rot } $meineFarbe = [Farbe]::Grün $meineFarbe class Auto { [Farbe]$Farbe $PS } $meinAuto = New-Object -TypeName Auto $meinAuto.Farbe = [Farbe]::Grün $meinAuto.PS = 100 $meinAuto | Get-Member #endregion #region Weitere neue CmdLetds Set-Clipboard -Value "Hallo Köln!" Get-Clipboard Clear-RecycleBin -DriveLetter c: -Confirm:$false New-TemporaryFile New-Guid # symbolischer Verknüpfungen New-Item -ItemType SymbolicLink -Name MySymLinkDir -Target $pshome # -Depth 2 Get-ChildItem c:\ -Recurse -Depth 2 -Force #endregion #region DataCenter Abstraction Layer (DAL) <# Mit dieser Technologie können Sie direkt auf bestimmte Netzwerkkomponenten wie Switches und Router zugreifen. Dazu muss die Hardware diese Technik aber auch unterstützen. In diesem Bereich spielen vor allem Cisco und Huawei eine wichtige Rolle. #> $Session = New-CimSession -ComputerName "NetworkSwitch08" Get-NetworkSwitchFeature -CimSession $Session <# Name IsEnabled InstanceID PSComputerName ---- --------- ---------- -------------- SSH True Contoso:Feature:2 10.19.26.49 Tacacs True Contoso:Feature:3 10.19.26.49 BGP False Contoso:Feature:4 10.19.26.49 VLAN True Contoso:Feature:5 10.19.26.49 LACP True Contoso:Feature:6 10.19.26.49 DHCP False Contoso:Feature:7 10.19.26.49 LLDP True Contoso:Feature:8 10.19.26.49 #> Get-Help Get-NetworkSwitchFeature -Full Get-Command -Module NetworkSwitchManager | Out-GridView #endregion #region Open Data Protocol <# Das Open Data Protocol, kurz OData ist ein von Microsoft veröffentlichtes HTTP-basiertes Protokoll für den Datenzugriff zwischen kompatiblen Softwaresystemen. Aufbauend auf älteren Protokollen wie ODBC und JDBC kann OData u.a. innerhalb von Cloud-Diensten (Azure), MySQL, Java und Rails eingebunden werden und ist in der Lage, in der Client-Server-Kommunikation eine einheitliche Semantik für den Datenaustausch zur Verfügung zu stellen. #> Export-ODataEndpointProxy -Uri 'http://services.odata.org/v3/(S(snyobsk1hhutkb2yulwldgf1))/odata/odata.svc' ` -MetadataUri 'http://services.odata.org/v3/(S(snyobsk1hhutkb2yulwldgf1))/odata/odata.svc/$metadata' ` -AllowUnsecureConnection ` -OutputModule C:\Temp\GeneratedScript.psm1 ` -ResourceNameMapping @{Products = 'Merchandise'} #endregion #region Optimierte Unterstützung für'Desired State Configuration' (DSC) <# Weitere Neuerungen in der PowerShell betreffen die mit der PowerShell 4.0 eingeführte Technologie Desired State Configuration (DSC). Hauptsächlich gibt es neue Optionen um festzulegen auf wievielen Computern gleichzeitig die Änderungen implementiert werden sollen. Mit dem Modul 'PowerShellGet' können Sie DSC-Ressourcen in der 'PowerShell Resource Gallery' nutzen, installieren oder hochladen. #> #endregion #endregion #endregion # Welche Version ist installiert? Get-Host #endregion #region Befehlskonzepte und Terminologie #region CmdLets (Verb-Substantiv) # CmdLets-Quellen können sein *.dll (CmdLet) oder Funktionen (function) Test-NetConnection 192.168.50.10 Get-Process Get-Verb # Welche Verben gibt es? Get-Command -Noun Process # Was kann ich mit Process machen? Get-Command -Verb Get # Welche Informationen können noch ermittelt werden? # CmdLets sind keine EXE-Dateien, sie sind *.dll oder in *.ps1 definiert # Mögliche CmdLets werden durch PowerShell-Module hinzugefügt, z.B. AD-CmdLets finden Get-Module -ListAvailable Get-Command -Module ActiveDirectory Get-ADUser #endregion #region Alias ls *.txt # (Alias für Get-ChildItem) dir *.txt # (Alias für Get-ChildItem) gci *.txt # (Alias für Get-ChildItem) Get-Command -Name dir Get-Alias -Name ls # ls ist ein Alias für? Get-Alias -Definition Get-ChildItem # Gibt es ein Alias für Get-ChildItem? # Console => Alias nutzen ! # PS-Skripte => Alias NICHT nutzen ! #endregion #region Pipelining Get-Service | Out-GridView ls | Out-GridView Get-Process *notepad* | Out-GridView -OutputMode Single | Stop-Process #endregion #region Filtering ls -Path *.txt # Nicht alle Parameter unterstützen Wildcard! ls | Where-Object Name -Like "*.txt" # so geht filtern immer! #endregion #region PowerShell-Providers/-Drives ls c: # C: => PowerShell-Drive (C: d:, etc. => PowerShell-Provider FileSystem) ls hkcu: # hkcu: => PowerShell-Drive (hkcu:, hklm:, etc. => PowerShell-Provider Registry) ls env: # Weitere PS-Provider: Zertifikate, Exchange, ADS, SharePoint, VMWare, ... Get-PSProvider Get-PSDrive #endregion #region Remoting Get-Process -ComputerName 192.168.50.41 # .NET Framework $sw = New-Object -TypeName System.Diagnostics.Stopwatch # Erzeugt ein Stopuhr-Objekt $sw.Start() $sw.Stop() $sw #endregion #region Zugriff auf WMI Get-WmiObject -Class Win32_Product Get-WmiObject -Class Win32_Processor Get-WmiObject -List | Measure-Object #endregion #region Erweiterbar durch Module Get-Module -ListAvailable Get-Command -Module ActiveDirectory # Informationen zu einem AD-Computer über: Get-ADComputer ... Find-Module * # Ab PowerShell 5.0 #endregion #endregion #region PowerShell Parsing # Ein PowerShell Kommando wird bei parsen in token aufgeteillt und analysiert: Write-Host Buch # Token Write-Host und Token Buch # Token werden wie folgt analysiert: # Example Mode Result # ------------------ ---------- ---------------- 2+2 # Expression 4 (integer) Write-Output 2+2 # Argument "2+2" (string) Write-Output (2+2) # Expression 4 (integer) $a = 2+2 # Expression $a = 4 (integer) Write-Output $a # Expression 4 (integer) Write-Output $a/H # Argument "4/H" (string) Write-Output !1 # Argument "!1" (string) Write-Output (!1) # expression False (Boolean) Write-Output (2) # expression 2 (integer) # STOP PARSING Möglichkeiten: icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F # <= Problem icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F # <= Lösung 1 # Lösung 2: Stop das parsing nach --% => icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F # # Weitere Schreibweisen: # $true # Boolean $false # Boolean 10 # Integer 10.5 # Double 'Hallo Köln $PSCulture' # String ' "PowerShell-Kultur $PSCulture" # String " "Köln", "München", "Berlin", "Stuttgart" # Array , (ping.exe 127.0.0.1)[8] # Array-Element [ ] (tnc 192.168.50.10).PingSucceeded # Ausdruck-Auswerten () zzgl. Eigenschaft des Ausw.-Objektes (Get-Process -Name notepad).Kill() # Aufruf von Methoden Get-Process; Get-Command # Abschluß einer Befehlskette mit ; [datetime]"2016-12-31" # DateTime [typenname]Objekt => Konvertierung [DateTime]::Today # :: Ruft STATISCHE Member eines Objektes ab #endregion #region PowerShell Console # -> Mehrzeilig schreiben = Ausdrücke in Klammern "()" setzen # Tastaturbefehle (<= 4.0) # TAB ...................... Befehlszeilenergänzung # STRG + C ................. Abbruch # PFEIL-OBEN/-UNTEN ........ Blättert im Befehls-Cache # MARKIERUNG + ENTER ....... Kopiert die Markierung in die Zwischenablage # RECHTS-KLICK ............. Fügt dir Zwischenablage ein # Tastaturbefehle (>= 5.0) # STRG + C ................. Kopieren # STRG + V ................. Einfügen Get-History $MaximumHistoryCount = 50 # Default: 4096 #region Konsolen-Ein-/Ausgabe protokollieren Start-Transcript -Path C:\Temp\PowerShellConsole.log Get-Process | Stop-Process -Force -WhatIf Remove-Item c:\ -Recurse -Force -WhatIf Stop-Transcript Get-Content -Path C:\Temp\PowerShellConsole.log #endregion #region max. Anzeige von Enumerationen (-1 ohne Grenze, Default: 4) Get-Command -Name ForEach-Object | select -First 1 | fl * # Siehe Eigenschaft: Parameters $FormatEnumerationLimit = 4 Get-Command -Name ForEach-Object | select -First 1 | fl * # Siehe Eigenschaft: Parameters #endregion #endregion #region Integrated Scripting Environment (ISE) # * = Noch nicht gespeichert # STRG + S = Speichern # F8 = Führt die aktuelle Auswahl aus bzw. die Course-Zeile # F5 = Führt das ganze Skript aus # TAB = Auswahl aus IntelliScense bestätigen # STRG + LEER = öffnet IntelliScense # STRG + M = Auf-/Zuklappen von Region und Kommentaren # STRG + J = Snippets ausfüllen # Siehe auch: # ISE-Menü "Add-Ons" Get-Help about_PowerShell_Ise.exe Get-Help about_Windows_PowerShell_ISE #endregion #region PowerShell-Hilfe (Get-Help) #region Hilfe installieren und aktuallisieren Update-Help -Module * -UICulture en-US, de-DE -Force # Für Computer ohne Internet-Zugang Save-Help -DestinationPath C:\temp\PSHelpFiles -Module * Update-Help -Module * -SourcePath C:\temp\PSHelpFiles #endregion #region Hilfe zu CmdLet's Get-Process -? Get-Help Get-Process Get-Help Get-Process -Full Get-Help Get-Process -ShowWindow # oder F1 in der ISE Get-Help Get-Process -Online # oder F1 in der ISE per MENÜ:\Tools\Optionen\... # SYNTAX-Block: # -Name <String[]> => String-Array # <CommonParameters> => Verweis auf CommonParameters # [] => Optional # [-FileVersionInfo] => Switch-Parameter # # Parameter-Beschreibung (z.B. Id): # Erforderlich? true oder: false # Position? named oder: 1, 2, 3, 4, 5, etc. # Standardwert none oder: ...... # Pipelineeingaben akzeptieren? True (ByPropertyName) oder: False, True (ByValue) # Platzhalterzeichen akzeptieren? false oder: true #endregion #region Hilfe zur/um die PowerShell (about-Seiten) Get-Help about_* Get-Help about_wildcards -ShowWindow Get-Help about_if -ShowWindow Get-Help about_CommonParameters -ShowWindow # Enthält infos von Parameter die für alle CmdLet's gelten Get-Process | Stop-Process -WhatIf Get-Process -FileVersionInfo -ErrorAction SilentlyContinue Get-Process -FileVersionInfo -ErrorAction Stop Get-Process | Stop-Process -Confirm #endregion #region Hilfe erstellen # HILFE-ARTEN # Cmdlet => The Help topics that describe cmdlets in a module are XML files that use the command help schema # Provider => The Help topics that describe providers in a module are XML files that use the provider help schema. # Function => The Help topics that describe functions in a module can be XML files that use the command help schema or comment-based Help topics within the function, or the script or script module # Script => The Help topics that describe scripts in a module can be XML files that use the command help schema or comment-based Help topics in the script or script module. # Conceptual ("About") => You can use a conceptual ("about") Help topic to describe the module and its members and to explain how the members can be used together to perform tasks. Conceptual Help topics are text files with Unicode (UTF-8) encoding. The file name must use the about_<name>.help.txt format, such as about_MyModule.help.txt. By default, Windows PowerShell includes over 100 of these conceptual About Help topics, and they are formatted like the following example. # <ModulePath> # \Mymodule # \en-US # \about_SampleModule.help.txt # \SampleModule.dll-help.xml # \fr-FR # \about_SampleModule.help.txt # \SampleModule.dll-help.xml # Supporting Updatable Help Start-Process "https://msdn.microsoft.com/de-de/library/hh852754(v=vs.85).aspx" # Supporting Online Help Start-Process "https://msdn.microsoft.com/de-de/library/hh852737(v=vs.85).aspx" # PowerShell Cmdlet Help Editor Start-Process "https://pscmdlethelpeditor.codeplex.com" #endregion # WICHTIG Get-Help intensiv nutzen # WICHTIG about-Seiten (wiedeholt) lesen #endregion #region Mögliche PowerShell-Kommandos (Get-Command, Get-Verb) # => Get-Command ruf eine Übersicht der möglichen PS-Kommandos ab. # => Dieser Funktionsumfang hängt von den installierten Modulen ab. # => Default-Anzeige von: CmdLets, Alias, Funktionen, PSDrives, Anwendungen (*.exe) # => Vor PS3.0 werden nur CmdLets angezeigt von geladen Modulen Get-Command * -CommandType All Get-Command * -CommandType Cmdlet Get-Command -Name *computer* -CommandType All # # Verb-Substantiv # Get-Command -Noun Computer Get-Verb Get-Command -Verb Stop Get-Command -Verb Optimize # ÜBUNG: Wie lautet das CmdLet um eine Netzwerk-Karte einzuschalten/auszuchalten bzw. neustarten? # Und wie haben Sie das CmdLet gefunden? # # Kommandos nach Modulen finden # Get-Module -ListAvailable Get-Command -Module NetTCPIP Get-Help Test-NetConnection -ShowWindow Test-NetConnection 192.168.50.10 # ÜBUNG: Wie heißt das CmdLet um eine IP-Adresse zu ändern? # Und wie haben Sie das CmdLet gefunden? #endregion #region Aliase für CmdLet's (*-Alias) Get-Alias Get-Alias ls Get-Alias -Definition Get-ChildItem Get-Command -CommandType Alias Get-Alias -Definition Test-NetConnection Get-Alias tc Get-Command -Noun alias Get-Help New-Alias -ShowWindow New-Alias ping Test-NetConnection ping # Nutzen Get-Process | Where-Object Company -like "Microsoft*" | Sort-Object Name | Format-Table Name, Company gp | ? Company -like "Microsoft*" | sort Name | ft Name, Company #endregion #region Pipeline (|) # => Windows PowerShell überträgt über die Pipeline KEINE TEXTE zwischen den Befehlen, # es werden immer OBJEKT über die Pipeline übertragen. # => 1. CmdLet liefert das erste Objekt just-in-time an das 2. CmdLet # => Pipeline-Objekte werden an den Parameter des 2. CmdLet's gebunden, # dass Pipeline-Eingabe (byValue) zulässt (Siehe Get-Help) # Zum vertiefen & verstehen: Trace-Command -PSHost -Name ParameterBinding -Expression {Get-Process winlogon | Format-Wide} # # Voarb analysieren (Wo bin ich & wo will ich hin?) # Get-Process Get-Process | Get-Member Get-Process | Format-Table -Property * Get-Process | Format-Table -pro Name, Company Get-Process | Format-List * Get-Process | Where-Object Company -like "Microsoft*" | Sort-Object Name | Format-Table Name,Company # Endgültige Ausgabe z.B. zum schreiben in eine Datei Get-Process | Where-Object Company -like "Microsoft*" | Sort-Object Name | Select-Object Name,Company # Zum Weiterverarbeiten Get-Process | # Nach der P. sind Umbrüche erlaubt Where-Object Company -like "Microsoft*" | # Nach der P. sind Umbrüche erlaubt Sort-Object Name | # Nach der P. sind Umbrüche erlaubt Select-Object Name,Company | # Nach der P. sind Umbrüche erlaubt Out-File c:\temp\Process.txt -Force Get-Process | Where-Object Company -like ` "Microsoft*" | Sort-Object Name | Select-Object Name, Company | Out-File c:\temp\PSTest\Process.txt -Force (Get-Process | Where-Object Company -like "Microsoft*").TotalProcessorTime.TotalSeconds | Measure-Object -Average -Sum -Maximum -Minimum # # Weitere Beispiele: # Get-ChildItem C:\ -Recurse | more # Besser nicht benutzten, lieber so: Get-ChildItem C:\ -Recurse | Out-Host -Paging "192.168.50.10", "192.168.50.11", "192.168.50.12" | ForEach-Object -Process {tnc $_} ((ping.exe 127.0.0.1) | Select-String -Pattern 'Verloren = 0' | Measure-Object).Count -eq 1 # ÜBUNG (Pipeline1): Anzeige der Gesamtbelegung im RAM aller Microsoft-Prozesse in MegaByte # ÜBUNG (Pipeline2): Welches ist die älteste Datei im C:\Windows-Order? # ls, Get-Member, Format-List *, Sort-Object, Select-Object #endregion #region Rückgabe-Objekte managen (*-Object) # # Übersicht # Get-Command -Noun Object -Module Microsoft.PowerShell.* | Out-GridView Where-Object # Filtern (Zeile) Select-Object # Filtern (Spalten) Sort-Object # Sortieren Group-Object # Gruppieren Measure-Object # Messen Compare-Object # Vergleichen ForEach-Object # Schleife New-Object # Erstellen Tee-Object # Verzweigen & loggen #region Where-Object (Siehe auch region Operatoren (Vergleichso.)) # Einfache Schreibweise erst seit PS3.0 Get-Process | Where-Object -Property Company -Like -Value "Microsoft*" Get-Process | where -Property Company -Like -Value "Microsoft*" Get-Process | ? -Property Company -Like -Value "Microsoft*" Get-Process | ? Company -Like "Microsoft*" # UND Get-Process | ? Company -Like "Microsoft*" | ? WorkingSet64 -GT 1000 # UND-Verknüpfung # ODER: Ausführliche Schreibweise seit PS1.0 Get-Process | ? -FilterScript {$_.Company -like "Microsoft*" -or $_.Company -like "Adobe*"} | ft Name, Company Get-Process | ? {$_.Company -like "Microsoft*" -or $_.Company -like "Adobe*"} | ft Name, Company # Die Variable $_ ist die Laufzeit-Variabe in der Pipeline und stellt das übergebene Objekt dar! #endregion #region ForEach-Object 31,32,33,34,35,36 | ForEach-Object -Process {"192.168.50." + $_} 31,32,33,34,35,36 | ForEach-Object {"192.168.50." + $_} 31,32,33,34,35,36 | foreach {"192.168.50." + $_} 31,32,33,34,35,36 | % {"192.168.50." + $_} 31,32,33,34,35,36 | % {"TNC ausführen für"; "192.168.50." + $_} 31,32,33,34,35,36 | % {"TNC ausführen für" "192.168.50." + $_} 31,32,33,34,35,36 | % { "TNC ausführen für" "192.168.50." + $_ } Get-ChildItem C:\Windows\Logs -Fo -File -ea SilentlyContinue -Re | ? Extension -EQ ".log" | Get-Content -ea SilentlyContinue | Select-String -Pattern "error" # Problem: Es fehlt die Information des Dateinamens :-( # LÖSUNG: ForEach-Object Get-ChildItem C:\Windows\Logs -Force -File -ErrorAction SilentlyContinue -Recurse | Where-Object -Property Extension -EQ -Value ".log" | ForEach-Object -Process { "#####################################" + $_.FullName # Ausgabe $_ | Get-Content | Select-String -Pattern "error" # Ausgabe des Dateiinhaltes die das Wort "error" enthalten } # Beispiele: Get-EventLog -LogName System -Newest 1000 | ForEach-Object -Begin {Get-Date} ` -Process {Out-File -Filepath Events.txt -Append -InputObject $_.Message} ` -End {Get-Date} #endregion #region New-Object $o1 = New-Object -TypeName System.Windows.Forms.Form # Erstellt ein Objekt aus der .NET-Framework-Klasse 'Form' $o1.ShowDialog() # .NET Wissen $o2 = New-Object -ComObject "Excel.Application" $o2.Visible = $true # VBA for Application #endregion #region Tee-Object Get-Process | Stop-Process -WhatIf Get-Process | Tee-Object -FilePath c:\temp\procs.txt | Stop-Process -WhatIf Get-Process | Stop-Process -WhatIf | Tee-Object -FilePath c:\temp\procs.txt #endregion #region Compare-Object Compare-Object -DifferenceObject 1 -ReferenceObject 2 Compare-Object -DifferenceObject 1 -ReferenceObject 1 $a = "Hallo Köln", "Hallo München" $b = "Hallo Köln", "Hallo Stuttgart" Compare-Object -DifferenceObject $b -ReferenceObject $a #endregion #region Group-Object (Gruppiert zu Objektgruppen) Get-Service | Group-Object -Property Status | Get-Member (Get-Service | Group-Object -Property Status -AsHashTable -AsString).Running (Get-Service | Group-Object -Property Status).Group Get-Service | Sort-Object Status | Format-Table -GroupBy Status # Gruppiert die Ausgabe #endregion #endregion #region Mit PowerShell-Objekten umgehen (Get-Member) # Alle CmdLets liefern Objekte zurück die intensiv ausgewertet werden können / müssen # '*.exe' liefern nur String-Auflistungen zurück deren Weiterverarbeitung umständlich ist. # Am Unterschied zwischen ping.exe (DOS-Welt) und Test-NetConnection (PowerShell-Welt) # den Mehrwert von Objekten schätzen lernen. Hier eine Prüfung ob ein Zeilhost erreichbar ist: ping.exe 127.0.0.1 (ping.exe 127.0.0.1)[8] (ping.exe 127.0.0.1) | Select-String -Pattern 'Verloren = 0' (ping.exe 127.0.0.1) | Select-String -Pattern 'Verloren = 0' | Measure-Object ((ping.exe 127.0.0.1) | Select-String -Pattern 'Verloren = 0' | Measure-Object).Count -eq 1 Test-NetConnection -ComputerName 127.0.0.1 (Test-NetConnection -ComputerName 127.0.0.1).PingSucceeded # # Rückgabe-Objekte analysieren mit Get-Member # ping.exe 127.0.0.1 | Get-Member Test-NetConnection -ComputerName 127.0.0.1 | Get-Member # Get-Member analysiert jedes Objete in der Pipeline und liefert gruppiert die Antwort auf: # Vom welchen Typ ist das Objekt # Welche Eigenschaften, Methoden und Ereignisse unterstützt das Objekt Get-ChildItem c:\ -Force | Get-Member # z.B. 2 unterschiedliche Objekt-Typen Get-Process -Name notepad | Get-Member # Erklährung zum Ergebnis von Get-Member: # # TypeName <= Vollständige Typ-Name, z.B.: System .IO .FileInfo # NAMESPACE.NAMESPACE.TYPENAME # siehe google, bing, etc. # Name <= Name des Member's # MemberType <= Art des Members # *Property TypeName PropertyName {get; set;} # Methode void => Ohne Rückgabe # ... MethodName(EingabeTyp'en) # Definition <= Beschreibung Set-Content -Path c:\temp\test.txt -Value "Hallo Köln" $datei = Get-ChildItem -Path C:\temp\test.txt $datei.Length # long Length {get;} $datei.Length = 99 $datei.CreationTime $datei.CreationTime = "2000-12-31" # datetime CreationTime {get;set;} $datei | Get-Member $datei | Add-Member -MemberType NoteProperty -Name Bemerkung -Value "Eine Eigenschaft die diesem O. hinzugefügt wurde" $datei | Get-Member $datei.Bemerkung # Mehrwert hinzufügen $datei.VersionInfo # Mehrwert hinzufügen # z.B. Enthält Length die größe der Datei? Bzw. wenn ja, was KB, MB, ...? # Evtl. im Internet nachlesen über den Typenname! $datei.Delete() # void Delete() (Get-ChildItem -Path C:\temp -File).Delete() Get-Process -Name notepad | Get-Member (Get-Process -Name notepad).WaitForExit(5000) (Get-Process -Name notepad).WaitForExit() # ÜBUNG Köln in "Hallo Köln!" durch Würzburg ersetzen # ÜBUNG Alle Dateien finden die älter sind als 180 Tage (OPTIONAL vom 1.1.2015 gerechnet) #endregion #region Formatierung & Ausgabe (Format-*, ConvertTo-* Write-*, Out-*) # # Übersicht # Get-Command -Verb Format, ConvertTo, Out, Write -Module Microsoft.PowerShell.* #region Format-* # # Format-Table # Get-Process # Autom. mit Default-Einstellung an ft Get-Process | Format-Table * # Alle Spalten Get-Process | ft Name, Company, CPU # Spezielle Spalten Get-Process | ft Name, Company, CPU -AutoSize # Performance !? Get-Process | Format-Table Name, WorkingSet64 Get-Process | ft Name, @{Label="WS (MB)"; Expression={[Math]::Round($_.WorkingSet64 / 1MB, 2)}} Get-Process | ft Name, @{Name="RAM (MB)"; Expression={"{0,6:0.00}" -F ($_.WorkingSet / 1MB)}} # Siehe F-Operator Get-EventLog -LogName System -Newest 10 Get-EventLog -LogName System -Newest 10 | ft -Wrap # Lange Text in Zeilen umbrechen Get-EventLog -LogName System -Newest 10 | Get-Member | ft -Wrap Get-EventLog -LogName System -Newest 50 | ft -GroupBy EntryType Get-EventLog -LogName System -Newest 50 | Sort-Object EntryType | ft -GroupBy EntryType Get-EventLog -LogName System -Newest 50 | Sort-Object EntryType | ft -GroupBy EntryType | Out-File -FilePath c:\temp\test.txt # # Format-List # Get-Process | fl Name, Company, CPU # Spezielle Spalten Get-Process | fl * Get-Process | Select-Object -First 1 | fl * (Get-Process)[0] | fl * # # Format-Wide # Get-Alias | fw Name -Column 8 # WICHTIG # Die CmdLet's Format-* sind für die Endausgabe gedacht, diese Ergebnisse können # nicht weiter verwertet werden !!!!!!! # ------------------------------------- #endregion #region Write-* "Hallo Köln!" # Default ist Write-Host "Hallo Köln!" | Write-Host "Hallo Köln!" | Write-Host -ForegroundColor Red # Nicht nutzen um Warnung und Fehler auszugeben Write-Host "Standort: " -NoNewline; Write-Host "Köln" "Hallo Köln!" | Write-Output # Das Ziel kann agegeben werden z.B. Datei, etc. Write-Error "Achtung ich bin ein Fehler" # Stop das Script -ErrorAction ...... Write-Warning "und ich bin eine Warnung" # Evtl. wird das Script gestopt -WarningAction .............. Write-Debug "und ich eine Debug-Meldung" # -Debug # # Beispiel I: # for ($i = 1 ; $i -lt 10 ; $i++) # $i++ => $i = $i + 1 { [System.Threading.Thread]::Sleep(500) # Last-Simulator (Aufruf einer statischen Methode aus dem .NET Framework []::) Write-Host "." -ForegroundColor Yellow -NoNewline } # # Beispiel II: # $guthaben = 12345.98 $konto = 47110815 Write-Host "Auf ihrem Konto `"$konto`" ist ein Guthaben von $guthaben!" Write-Host 'Auf ihrem Konto $konto ist ein Guthaben von $guthaben!' . "c:\$guthaben.txt" #endregion #region OUT-* Get-Command -Verb Out -Module Microsoft.PowerShell.* "Jetzt ist " + (Get-Date) | Out-File C:\temp\JetztIst.txt Get-Content C:\temp\JetztIst.txt "Jetzt ist " + (Get-Date) | Out-File C:\temp\JetztIst.txt -Append Get-Content C:\temp\JetztIst.txt Get-Process | ft * | Out-String -Width 500 #endregion #region ConvertTo- Get-Command -Verb ConvertTo -Module Microsoft.PowerShell.* Get-Process | ConvertTo-Csv | out-File C:\temp\procs.csv Get-Process | Select-Object Name, Company, WorkingSet64 | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | out-File C:\temp\procs.csv . C:\temp\procs.csv Get-Process | Select-Object Name, Company, WorkingSet64 | ConvertTo-Html | out-File C:\temp\procs.html . C:\temp\procs.html #endregion # Übung: Eine Liste der laufenden Processes für # Excel (csv) aufbereiten mit den Spalten # Name, Arbeitsspeicher, Beschreibung # ÜBUNG: CSV-Datei aller laufenden Dienste für die spätere analyse! (import/export) #endregion #region PowerShell-Provider und -Laufwerke als standadisierte Schnittstellen # Mit PowerShell-Provider werden div. 'DB' in/um Windows in der PS zur Verfügung gestellt, z.B.: # - Dateisystem # - Umgebungsvariablen # - PowerShell-Variablen # - PowerShell-Funktionen # - Registrierungsdatenbank # - X.509-Zertifikatsspeicher # - [OPTIONAL] ActiveDirectory # - [OPTIONAL] Exchange-Postfächer/-Ordner # - [OPTIONAL] MS SQL-Server # - u.v.m. Get-PSProvider # Durch das Laden eines Modules können weitere PS-Provider hinzukommen Import-Module -Name ActiveDirectory Get-PSProvider # Für die Interaktion mit den PS-Provider'n gibt es PSDrive's (Laufwerke) Get-PSDrive # Releative und absolute Pfade: # . = Aktueller Ordner # .. = Übergeordneter # \ = Stamm # ~ = Basis (Home-Verzeichnis) gci . gci .. gci \ gci ~ gci c:\ gci variable:\ gci cert:\ gci env:\ gci hkcu:\ Set-Location C:\Windows\System32 Resolve-Path -Path .\msinfo32.exe Test-Path -Path C:\Windows\System32\msinfo32.exe Test-Path -Path variable:\a Split-Path -Path C:\Windows\System32\msinfo32.exe -Parent Split-Path -Path C:\Windows\System32\msinfo32.exe -Leaf Join-Path -Path C:\Windows\System32\ -ChildPath \msinfo32.exe # Kennt man einen kennt man alle :-) # Befehle in einem PSProvider sind zu 100% übertragbar auf andere PSProvider Get-Command rm Get-Command del Get-Alias -Definition Remove-Item ri C:\Temp\test.htm -Force -WhatIf ri HKCU:\SOFTWARE\7-Zip\FM\Columns -Force -WhatIf # # ÜBERSICHT # Get-Command -Name *item*, Set-Location -Module Microsoft.PowerShell.Management | Out-GridView Set-Location c: Get-ChildItem cd C:\Windows # Alias für? Set-Location env: Get-ChildItem Set-Location hkcu: Set-Location Software Set-Location .. # Exemplarisches Handling für den PSProvider "Registry" # Schlüssel 'Abc' erstellen New-Item -Path HKCU:\Software\Abc -Force -ItemType key New-Item -Path c:\temp\abc.txt -Force -ItemType file New-Item -Path c:\temp\abc.txt -Force -ItemType directory # Default-Wert für 'Abc' erstellen New-Item -Path HKCU:\Software\Abc -Value "Def von Abc" -ItemType String -Force # Eine NEUE Eigenschaft für den Schlüssel "Abc" erstellen New-ItemProperty -Path HKCU:\Software\Abc -Name "Heute" -Value '2016-01-19' -PropertyType 'String' -Force New-ItemProperty -Path HKCU:\Software\Abc -Name "Anzahl" -Value 112 -PropertyType 'DWord' -Force | Out-Null # Eine VORHANDENE Eigenschaft geändert Set-ItemProperty -Path HKCU:\Software\Abc -Name "Anzahl" -Value 113 -Type QWord # Den Schlüssel 'Abc' lesen Get-Item -Path HKCU:\Software\Abc # BTW: Achtung Get-Item -Path C:\Windows Get-ChildItem -Path C:\Windows Get-ChildItem -Path HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\ | ? Name -Like 'Run*' Get-ChildItem -Path HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\ | fl * Get-ChildItem -Path HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\ | ? PSChildName -Like 'Run*' # Den Wert von Heute des Schlüssels 'Abc' lesen: Get-ItemProperty -Path HKCU:\Software\Abc -Name "Heute" $heute = Get-ItemProperty -Path HKCU:\Software\Abc -Name "Heute" $heute.Heute (Get-ItemProperty -Path HKCU:\Software\Abc -Name "Heute").Heute (Get-ItemProperty -Path HKCU:\Software\Abc).Heute [datetime](gp HKCU:\Software\Abc).Heute # Den Default-Wert des Schlüssels 'Abc' lesen: (Get-ItemProperty -Path HKCU:\Software\Abc).'(default)' # Die Eigenschaft 'Heute' löschen: Remove-ItemProperty -Path HKCU:\Software\Abc -Name 'Heute' # Den Default-Wert des Schlüssels 'Abc' leeren: Set-ItemProperty -Path HKCU:\Software\Abc -Name '(default)' -Value $null # Oder löschen und neu erstellen # Den Schlüssel 'Abc' mit allen Eigenschaften und Unterschlüssel löschen Remove-Item -Path HKCU:\Software\Abc -Force # # Zum Beispiel PSProvider "Function" # Get-ChildItem function: | Out-GridView Get-ChildItem Function:\C: | Select-Object -Property Name, Definition function hkcu: { Set-Location hkcu: } hkcu: Get-ChildItem Function:\hkcu: | Format-List * # # Weitere Beispiele: # New-Item -Path C:\temp\Scripts -ItemType directory -Force New-PSDrive -Name Skripts -PSProvider FileSystem -Root C:\temp\Scripts Set-Location skripts: New-Item -Path .\test.txt -ItemType 'file' Get-PSDrive Get-ChildItem -Path HKLM:, HKCU: -Include '*PowerShell*' -Recurse -ErrorAction SilentlyContinue Get-ChildItem $HOME -Force #endregion #region PowerShell und Remoting # WICHTIG: Das Netzwerk muss sicg im Domänen- bzw. Privaten-Netzwerkprofil befinden Set-NetConnectionProfile -NetworkCategory Private Get-NetConnectionProfile # Version 1: RPC (ab PowerShell 2.0) # + Das geht immer, muss nicht aktiviert oder eingerichtet werden # + Seit PowerShell 2.0 # - Nur möglich mit ausgewählten CmdLets Get-NetFirewallProfile Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False Get-Help * -Parameter "ComputerName" | Out-GridView # Auf 2.0 ausführen!!! Get-Service -ComputerName 192.168.50.41, 192.168.50.50 | ft Name, Status, MachineName # Version 2: WinRM (ab PowerShell 3.0) # - Muss aktiviert und eingerichtet (Client / Server) # + Geht mit allen CmdLets/Scripten !!! # Wichtig: Firewall TCP 5985 # Einmal WinRM aktivieren (Für Quell- und Zielsystem auch gerne über eine GPO) Enable-PSRemoting -Force # Einmal eine Client- und Zielsystem-Vertrauensstellung einrichten $value = (gci -Path WSMan:\localhost\Client\TrustedHosts).Value Set-Item -Path wsman:\localhost\client\trustedhosts -Value ($value + ", 192.168.50.41, 192.168.50.50") # Möglich Werte sind auch: SqlServer01, ADS01.abc.local, *, 192.168.50.0 Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value "*" gci -Path wsman:\localhost\client\trustedhosts # # Nutzen # # OPTIONAL wenn anderen Credential benötigt werden als der aktuelle Context $cred = Get-Credential -Message "Bitte anmelden für ..." -UserName "Administrator" # EINE Session zum Zielsystem öffnen $session1 = New-PSSession -ComputerName 192.168.50.50 -Credential $cred # Informationen über aktuelle Sessions Get-PSSession # Eine offene Session nutzen Enter-PSSession -Session $session1 Enter-PSSession -Id 1 Enter-PSSession -ComputerName 192.168.50.50 -Credential (Get-Credential) # TEST New-Item c:\temp\Ak.txt -Value "Erzeug vom PC.. für PC.." -ItemType file # Zurück zur eigenen lokalen Session Exit-PSSession Get-PSSession # Session bleiben offen und aktiv # Aktive Sessions löschen Remove-PSSession -Session $session1 Remove-PSSession -Id 1 Get-PSSession # ------------------------------------------------------------------------- # # Ein Script/CmdLet auf VIELE Zielssysteme ausführen # # Mehrere Session erstellen $sessions = New-PSSession -ComputerName 192.168.50.41, 192.168.50.50 -Credential $cred # Session-Array $Session1 = New-PSSession -ComputerName 192.168.50.41 -Credential $cred # Single Session $Session2 = New-PSSession -ComputerName 192.168.50.41 -Credential $cred # Single Session # Offene Sessions nutzen Invoke-Command -Session $sessions -ScriptBlock {Get-Process} Invoke-Command -Session $session1, $session1 -ScriptBlock {Get-Process} # Sessions beenden Remove-PSSession -Session $sessions # ------------------------------------------------------------------------- # Was passiert beim starten einer UI-App? Invoke-Command -Session $sessions -ScriptBlock {Start-Process calc.exe} # Siehe auch Get-Command -Noun PSSession | Out-GridView Get-Help about_*remote_* | Out-GridView # ------------------------------------------------------------------------- # -> 6. PSRemoting deaktivieren Set-Item wsman:\localhost\client\trustedhosts "" -Force Disable-PSRemoting -Force Set-NetConnectionProfile -NetworkCategory Public #endregion #region PowerShell-Funktionen erweitern (Module) # -> 1. Welche Module sind z.Zt. installiert? Get-Module -ListAvailable # Übersicht installierte Module, gruppiert nach Modul-Ordner <# Module die PC-Weit gelten: C:\Windows\system32\WindowsPowerShell\v1.0\Modules Module die nur für den entsprechenden User gelten: C:\Users\a.krick\Documents\WindowsPowerShell\Modules Expliziet eingebundene Module-Ordner, siehe: #> $env:PSModulePath -split ";" # -> 2. Benötigte Module installieren: <# Zum Beispiele: Microsoft Exchange Server Windows Server (WS2K8=Features, W7=RSAT installieren anschl. Programme u. Funktionen) SQL Server SharePoint System Center Operations Manager System Center Virtual Machine Manager System Center Data Protection Manager Windows Compute Cluster Server PowerTools for Open XML (Office2007+) Internet Information Services Windows 7 Troubleshooting Center Deployment Toolkit LOGINventory IBM Transporter Suite for Lotus Domino WebSphere MQ VMware Infrastructure Toolkit Quest Management Shell for Active Directory DIVERS Special Operations Software Specops Command U.V.M. #> Start-Process -FilePath "http://www.powershellgallery.com" # Siehe auch # # 1. SCHRITT: Modul installieren # Durch eine setup.exe, *.msi oder über Eweitertete Installation eines Server-Produkts # # # z.B.: PowerShell Community Extensions (PSCX auf http://pscx.codeplex.com) # . "C:\temp\Pscx-3.2.0 für PS40 Module.msi" gci -Path "C:\Program Files (x86)\PowerShell Community Extensions\Pscx3" $env:PSModulePath -split ";" # Fehlt ein NEUER Eintrag PowerShell, ISE oder sogar PC neustarten Get-Module -Name PSCX -ListAvailable # Installiert? # # z.B.: Attila Krick PowerShell Tools (AKPT) # manuell in einen der Modul-ORdner kopieren # Copy-Item -Path C:\temp\AKPT -Destination C:\Users\akric\Documents\WindowsPowerShell\Modules\AKPT\ -Force -Recurse Get-Module -Name AKPT -ListAvailable # Installiert? Find-Module -Name AKPT # AB PS5.0 direkt aus dem Intenet- oder Firmenspeicher installieren Install-Module -Name AKPT # AB PS5.0 direkt aus dem Intenet- oder Firmenspeicher installieren # # 2. SCHRITT: Modul nutzbar machen # Get-Module # Übersicht der GELADENEN Modul (Nutzbar) Import-Module -Name AKPT # Bei starten einer PS-Sitzung erneut ausführen Get-Module Remove-Module -Name AKPT # Entläd ein Modul (Nicht mehr nutzbar) Get-Module # Seit der PowerShell 3.0 wird Import-Module automatisch ausgeführt Get-HotKeys Get-Module Get-Command -Module AKPT Read-Window -Title "TITEL" -Message "NACHRICHT" Get-Command -Module PSCX | Out-GridView gci function:\Out-Speech | select -ExpandProperty Definition #endregion #region Variablen (*-Variable) # # Übersicht # Get-Help about_Variables -ShowWindow # Grundlagen Get-Help about_Scopes -ShowWindow # Geltungsbereich Get-Help about_Automatic_Variables -ShowWindow # Systemvariable Get-Help about_Hash_Tables -ShowWindow # Hashtable Get-Help about_Objects -ShowWindow # Objekt-Handling Teil 1 Get-Help about_Object_Creation -ShowWindow # Objekt-Handling Teil 2 Get-Help about_Special_Characters -ShowWindow # ` Backtick (SHIFT + Akzent) Sonderzeichen wie z.B. Tab, NewLine, etc. # CmdLets um das Thema Variable Get-Command -Name *variable* -Module Microsoft.PowerShell.Utility | Out-GridView # PowerShell-Provider für Variable Get-ChildItem -Path variable: -Force | Out-GridView # Der Inhalt einer V. bleibt über die komplette Sitzung erhalten! (Nicht nur zur Laufzeit eines Skriptes) $einfach = 12 # In Variablen können einfache atomare Objekte gespeichert werden... $komplex = (Get-Service)[0] # ... aber auch KOMPLEXE Objekte. # # Zuweisungen # $PI = 99.9 # Variablen werden autom. mit der ersten Benutzung deklariert... New-Variable -Name PI -Value 3.14 -Description "Kreiszahl Pi" -Option ReadOnly -Force # ... ODER per CmdLet. $var1 = "Hallo Köln" # Atomar String $var2 = Get-Process # ALLE komplexen Process-Objekte $var3 = (Get-Process)[0] # EIN komplex Process-Objekt $var4 = $var2[0] # ---------- " ------------- $var5 = {Get-Process} # Script-Block $array1 = 1, 2, 3, 4 # eindimenmsionals Array $array2 = (11,12,13), (21,22,23), (31,32,33) # zweidimenmsionals Array (usw.) $array3 = "Hallo", 12, (Get-Process) # Gemischtes Array $pc1 = [ordered]@{"Hostname"="PC1"; "IPv4"="192.168.50.51"; "Leasing"=123.68} # Hashtable $array4 = "PC1", "192.168.50.51", 123.68 # Array $env:windir # Windows Umgebungsvariablen $Function:prompt # ${c:\temp\JetztIst.txt} = Get-Date # Datei asl Variable # # Lesen / Nutzen # $var1 Write-Host -Object $var1 $var5 # Anzeige Inhalt Script-Block . $var5 # Script-Block ausführen (BTW: Datei werden so auch ausgeführt) $array2[0] $array2[1][1] $array3 | select -Last 1 $array3.Length $pc1["Hostname"] $pc1["IPv4"] $pc1["Leasing"] # # Variablen auch gerne als Temp-Note nutzen, z.B.: # $var4 = gci c:\ -File -Recurse -ErrorAction SilentlyContinue $var4.Length $var4 $var5 = $var4 | ? Name -Like "*Microsoft*" $var5.Length $var5 # # Prüfen ob eine Variable (PSProvider) vorhanden ist # Test-Path -Path variable:var1 Test-Path -Path variable:varX # # Eine Variable muss immer von einem Typ sein # $text = "Hallo Köln!" # System.String $zahl1 = 123 # System.Int32 $zahl2 = 123.5 # System.Double $istWahr = $true # System.Boolean $objekt1 = (Get-Process)[0] # System.Diagnostics.Process $objekt2 = Get-Process # System.Object[] # Typ der Variablen ermitteln $objekt1.GetType() | ft Name, FullName, BaseType $objekt2.GetType() | ft Name, FullName, BaseType $objekt1 | Get-Member $objekt2 | Get-Member # ACHTUNG: richtet sich immer an Array-Elemente $IchBinEineDateiOderOrdner -is [System.IO.FileInfo] $zahl1 -is [System.Int64] # TIP: i.d.R. den Typen fest angeben [Int32]$alter = 12 $alter = "Hallo Köln!" # z.B. [datetime]$eingabe = Read-Host -Prompt "Alte Dateien finden vor welchen Datum (yyyy-MM-dd z.B. 2015-12-31)?" gci C:\ -Recurse | ? LastAccessTime -le $eingabe $deDE = New-Object -TypeName System.Globalization.CultureInfo -ArgumentList "de-DE" $eingabe2 = Read-Host -Prompt "Alte Dateien finden vor welchen Datum?" gci C:\ -Recurse | ? LastAccessTime -le $eingabe2.ToDateTime($deDE) # # Variablen evtl. aufräumen # Remove-Variable -Name alter Remove-Variable -Name PI -Force Remove-Variable -Name * -Force -ErrorAction SilentlyContinue # # Beispiele mit Variablen # $geld = 123456.78 $geldSchön = $geld.ToString("#,##0.00 €") # Zahlen- / Datumstypen nach String formatieren "Ihr Guthaben ist: $geldSchön" # Inhalt einer V. in einen String betten $heute = Get-Date -DisplayHint Date $heute.ToString("yyyy-MM-dd HH:mm:ss.fffffff") $heute = Get-Date $heute.ToString("yyyy yy MMMM MMM MM M dddd ddd dd d HH hh mm ss fffffff") # Datum des letzten Tages im akt. Monat? $letzterTagImMonat = Get-Date -Year (Get-Date).Year -Month (Get-Date).Month -Day 1 -Hour 0 -Minute 0 -Second 0 -Millisecond 0 $letzterTagImMonat = $letzterTagImMonat.AddMonths(1).AddDays(-1) $letzterTagImMonat # Anzahl Tage bis Neujahr [datetime]$neuJahr = "2017-01-01" $dauer = $neuJahr - (Get-Date) # [System.DateTime] MINUS [System.DateTime] GLEICH [System.TimeSpan] $dauer | Get-Member $dauer | fl * $dauer.Days # # Gültigkeitsbereichen # $wert = 23 function TestBereich { "Wert in der Funktion: $wert" $wert = 43 "Neuer Wert in der Funktion: $wert" } TestBereich "Wert außerhalb der Funktion: $wert" . TestBereich # . Abschirmung deaktiviert ehr NOGO! "Wert außerhalb der Funktion: $wert" $global:wert2 = 123 # globale Variable NOGO $private:wert3 = 321 # private Variable $script:wert3 = 321 # skriptglobale Variable NOGO #endregion #region Operatoren # # ÜBERSICHT # Get-Help about_Operators -ShowWindow # Übersicht aller Operatoren Get-Help about_Operator_Precedence -ShowWindow # Vorrangregeln Get-Help about_Arithmetic_Operators -ShowWindow # Arithmetische Operatoren Get-Help about_Assignment_Operators -ShowWindow # Zuweisungs- Operatoren Get-Help about_Logical_Operators -ShowWindow # Logische Operatoren Get-Help about_Comparison_Operators -ShowWindow # Vergleichs- Operatoren Get-Help about_Type_Operators -ShowWindow # Objekt- Operatoren Get-Help about_Split -ShowWindow # Objekt- Operatoren Get-Help about_Join -ShowWindow # Objekt- Operatoren #region about_Assignment_Operators $zahl=1 # Start: 1 $zahl++ # $zahl = $zahl + 1 $zahl-- # $zahl = $zahl - 1 $zahl+=2 # $zahl = $zahl + 2 $zahl-=3 # $zahl = $zahl - 3 $zahl++ # $zahl = $zahl + 1 $zahl # Ergebnis: 1 $zahl=-10 # Ergebnis: ??? $zahl #endregion #region about_Arithmetic_Operators # Siehe About-Seite! #endregion #region about_Logical_Operators $true -and $true $true -or $false ($true -and $true) -or ($true -or $false) !$true -and $true -not $true -and $true #endregion #region about_Comparison_Operators "Köln" -eq "köln" # eq = ieq "Köln" -ceq "köln" "Köln" -ieq "köln" "Köln" -cin "Köln", "Hamburg", "München" "Köln", "Hamburg", "München" -contains "Köln" # ACHTUNG "010" -eq 010 # False 010 -eq "010" # True [Int32]"010" -eq 010 # True # # -like # "abc" -like "?b?" # *, ?, ... # -match (Reguläre Ausdrücke, kurz "regex", Wikipedia) <# REGEX = TARGET a = a [abc] = a b c a{2,5} = aa aaa aaaa aaaaa . = Alle Zeichen außer Zeilenumbrüche \ = Maskieren ^ = Vom ersten Zeichen $ = Bis zum lezten Zeichen + = {1,} * = {0,} #> "AB678.docx" -match "^[A-Z]{2,2}[0-9]{3,3}\.doc[x]{0,1}$" # True "AB678.doc" -match "^[A-Z]{2,2}[0-9]{3,3}\.doc[x]{0,1}$" # True "XX678.doc" -match "^[A-Z]{2,2}[0-9]{3,3}\.doc[x]{0,1}$" # True "XX123.docx" -match "^[A-Z]{2,2}[0-9]{3,3}\.doc[x]{0,1}$" # True "X123.docx" -match "^[A-Z]{2,2}[0-9]{3,3}\.doc[x]{0,1}$" # False "AA1.docx" -match "^[A-Z]{2,2}[0-9]{3,3}\.doc[x]{0,1}$" # False "AA123.xlsx" -match "^[A-Z]{2,2}[0-9]{3,3}\.doc[x]{0,1}$" # False "a.krick@gfu.net" -match "^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$" # # Array-Vergleich # 10,11,12,13,14,10 -eq 10 10,11,12,13,14,10 -ne 10 10,11,12,13,14,10 -gt 10 # # Vergleichsoperatoren z.B. nutzen in: Where-Object, if(){} # if(10 -gt 5) { # CmdLet } else # Optional { # CmdLet } 10,11,12,13 -contains 10 (10,11,12,13), (14,15,16,17) | Where-Object -FilterScript {$_ -contains 10} (10,11,12,13), (14,15,16,17) | ForEach-Object -Process {$_ -contains 10} #endregion #region about_Type_Operators (Get-Process)[0] -is [System.Diagnostics.Process] # Ist ein Objekt von einem bestimmten Typen (Get-Process) -is [System.Array] "2015-03-18" -is [DateTime] [DateTime]"2015-03-18" -is [DateTime] #endregion #region -f (Format-Operator) s. about_operators # "FORMAT" -f Value[s] "Wert 1 ist {0}, der letzte Wert ist {3} und die anderen sind: {1}, {2}" -f 10,11,99,230,1024 "Zahlenformat: {0}" -f 123456.6789 "Zahlenformat: {0:#,##}" -f 123456.6789 "Zahlenformat: {0:0.0}" -f 123456.6789 "Zahlenformat: {0:#,##0.00}" -f 123456.6789 "Heute ist {0}" -f (Get-Date) "Heute ist {0} und wir haben {1} Uhr" -f (Get-Date), (Get-Date) "Heute ist {0} und wir haben {0} Uhr" -f (Get-Date) "Heute ist {0:dd.MM.yyyy} und wir haben {0:HH:mm} Uhr" -f (Get-Date) "Heute ist {0:dddd.} der {0:d. MMMM} anno {0:yyyy HH:mm} und {0:ss.fffffff} Sekunden" -f (Get-Date) "{0,-10:0.0} | {1,-10:0.0} | {2,-10:0.0}" -f "Wert A", "Wert B", "Sum" "{0, 10:0.0} | {1, 10:0.0} | {2, 10:0.0}" -f 12, 23, 167.889 "{0, 10:0.0} | {1, 10:0.0} | {2, 10:0.0}" -f 212, 123, 67.89 "{0, 10:0.0} | {1, 10:0.0} | {2, 10:0.0}" -f 3312, 3, 7.8 Write-Host "{0, 10:0.0} | {1, 10:0.0} | {2, 10:0.0}" -f 3312, 3, 7.8 # # Beispiele # $pcs = (1..99 | ForEach-Object -Process {"PC{0:000}" -f $_}) $session = New-PSSession -ComputerName $pcs Invoke-Command -Session $session -ScriptBlock {Restart-Computer} "Log_{0:yyyyMMddHH}.log" -f (Get-date) #endregion #region about_Split $result = "ADS001;127.0.0.1;1234.67;" -split ";" $result[1] #endregion #region about_join $result = "Hallo Köln!", "127.0.0.1", 123.45 $result -join ";" #endregion #region replace "Hallo Köln!" -replace "Köln", "Berlin" #endregion #endregion #region WMI Get-WmiObject -List Win32_ $FormatEnumerationLimit = -1 Get-WmiObject -List Win32_Product | fl Methods, Properties, Events Get-WmiObject -Class Win32_Product # Software-Inventarisierung Get-WmiObject -Class Win32_Product | select -First 1 | fl * Get-WmiObject -List Win32_printer # Drucker #region Ein MSI-Paket installieren $msi = "c:\7z920-x64.msi" $produkte = Get-WmiObject -Class Win32_Product -List "Installation läuft ...." $ergebnis = $produkte.Install($msi) "... Installation fertig mit dem Ergebnis {0}" -f $ergebnis.ReturnValue Get-WmiObject -Class Win32_Product | where Name -like "*7-zip*" | Get-Member # ReturnValue siehe http://msdn.microsoft.com/en-us/library/aa390890(v=vs.85).aspx #endregion # # Invoke-CimMethod # $inst = Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE name like 'notepad%'" Invoke-CimMethod -InputObject $inst -MethodName GetOwner # # s. Register-WmiEvent # #endregion #region COM-Objekte # # BEISPIEL Excel # # (Excel bzw. Office muss installiert sein, Office PIA 2010 downloaden) # BESSER: CSV, 'OpenXML for Office' $xls = New-Object -ComObject "Excel.Application" $xls.Visible = $true # Debugging $wb = $xls.Workbooks.Add() $ws = $wb.Worksheets.Add() $a1 = $ws.Range("A1") $a1.Value2 = "PowerShell ist spitze!" $wb.SaveAs("c:\temp\meinmappe.xlsx") $xls.Quit() # # BEISPIEL Word # $word=New-Object -ComObject "Word.Application" $word.Visible=$true $doc=$word.Documents.Add() $win=$doc.Windows.Item(1) $win.View.ShowAll=$true $objAbs=$doc.Paragraphs.Item(1) $objAbs.Range.Text="Titel`rAbsatztext" $objAbs.Range.Text=($objAbs.Range.Text + "zweite Zeile") $objAbs=$doc.Paragraphs.Item(1) $objAbs.Style="Überschrift 1" $erg=$doc.PrintOut([ref]$false) # VORTEIL von COM-Object $erg=$doc.prin $doc.SaveAs([ref]"c:\Temp\PS und Word.docx") $doc.Close([ref]$false) $word.Quit() $word=$null Get-WmiObject Win32_COMClass # Davon können COM-Objekte erzeugt werden #endregion #region Registry #s. region 'PowerShell-Provider' #endregion #region Verarbeiten von TXT # # ÜBERSICHT # Get-Command -Noun Content -Module Microsoft.PowerShell.* gci C:\Windows\Logs -Recurse -File -ea SilentlyContinue | ? Extension -EQ ".log" | Get-Content -ea SilentlyContinue | Select-String -Pattern "Error" | Add-Content -Path C:\Temp\PSTest\errors.txt Send-MailMessage ` -To "a.krick@outlook.com" ` -From "teilnehmer@gfu.net" ` -Subject "Error" ` -Body ([String]::Concat("C:\Temp\PSTest\errors.txt")) ` -Attachments "C:\Temp\PSTest\errors.txt" ` -SmtpServer 192.168.50.10 ` -Port 25 ` -ErrorAction Stop Remove-Item -Path c:\temp\errors.txt # Was machen Sie so mit *.txt-Dateien? #endregion #region Verarbeiten von CSV # Schreiben Get-Process | Select-Object -Property Name, Company | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Add-Content -Path c:\temp\procs.csv # Lesen $result = Get-Content -Path c:\temp\procs.csv foreach($item in $result) { "NAME {0} FIRMA {1}" -f ($item -split ";") } #endregion #region Verarbeiten von XML # # Auswerten # Invoke-WebRequest -Uri "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" | Select-Object -ExpandProperty Content | Set-Content "C:\temp\eurofxref-daily.xml" -Force $xmlDokument = [xml](Get-Content -Path "C:\temp\eurofxref-daily.xml") $xmlDokument.Envelope.Cube.Cube.Cube | ? currency -EQ "RUB" | Select-Object -ExpandProperty rate $xmlDokument.Envelope.Cube.Cube.Cube | Out-GridView -OutputMode Single $xmlDokument | Get-Member -MemberType Properties $xmlDokument.Envelope | Get-Member -MemberType Properties $xmlDokument.Envelope.Cube | Get-Member -MemberType Properties $xmlDokument.Envelope.Cube.Cube | Get-Member -MemberType Properties $xmlDokument.Envelope.Cube.Cube.Cube | Get-Member -MemberType Properties $xmlDokument.Envelope.Cube.Cube.Cube.currency $xmlDokument.Envelope.Cube.Cube.Cube.rate # # Schreiben # # z.B. Konfigurationsdatei $config = [xml]@" <?xml version="1.0" encoding="utf-8" ?> <Einstellungen> <Server Name="ADC01" IP="127.0.0.1" /> <Server Name="ADC02" IP="127.0.0.1" /> </Einstellungen> "@ $config.Einstellungen.Server | Select-Object -ExpandProperty Ip $config.Einstellungen.Server | ? Name -Like "*02" ($config.Einstellungen.Server | ? Name -Like "*02").IP = "192.168.50.32" $config.Einstellungen.Server | ? Name -Like "*02" $config.Save("C:\temp\einstellung.xml") $result = [xml](Get-Content "C:\temp\einstellung.xml") $result.Einstellungen.Server #endregion #region Verarbeiten von Ordner & Dateien # Siehe Move-Item Copy-Item Remove-Item New-Item Get-Item # # Rechte # Get-Acl -Path C:\temp | fl * $DogACL = Get-Acl C:\temp\einstellung.xml $DogACL | Get-Member $DogACL.SetAccessRuleProtection($true, $false) # isProtected, preserveInheritance Vererbung aktivieren Set-Acl -Path C:\Cat.txt -AclObject $DogACL # Etwas auf allen Laufwerken suchen Get-PSDrive -PSProvider FileSystem | Select-Object -ExpandProperty Root | gci -Force -File -ea SilentlyContinue # Pfad und Besitzer anzeigen "C:\Windows" | gci -Force -File -ea SilentlyContinue | Select-Object -ExpandProperty FullName "C:\Windows" | gci -Force -File -ea SilentlyContinue | Get-Acl | Select-Object -ExpandProperty Owner "C:\Windows" | gci -Force -File -ea SilentlyContinue | % -Process { $ht = @{"FullName"=$_.FullName; "Owner" =($_ | Get-Acl | Select-Object -ExpandProperty Owner)} New-Object PSObject -Property $ht } | Out-GridView # Oder so "C:\Windows" | gci -Force -File -ea SilentlyContinue | % -Process { $_ | Add-Member -MemberType NoteProperty -Name Owner ` -Value ($_ | Get-Acl | Select-Object -ExpandProperty Owner) $_ } | Select-Object FullName, Owner | Out-GridView # Belegter / Freier Speicher auf Festplatten Get-PSDrive -PSProvider FileSystem # Doppelte Dateien finden Get-FileHash C:\Windows\explorer.exe -Algorithm SHA512 # Dateien- / Ordner überwachen $fsw = New-Object System.IO.FileSystemWatcher $fsw.Path = "c:\temp" $fsw.Filter="*.txt" $action = { Write-Warning ("Dateiänderung: {0} {1}" -f $eventArgs.FullPath, $eventArgs.ChangeType) } Register-ObjectEvent -InputObject $fsw -EventName Created -Action $action Register-ObjectEvent -InputObject $fsw -EventName Deleted -Action $action Get-EventSubscriber Unregister-Event -SubscriptionId 3 Unregister-Event -SubscriptionId 4 #region Netzwerk-Freigabe erstellen New-SmbShare -Name Data -Path C:\Windows Remove-SmbShare -Name Data -Confirm:$false #endregion #endregion #endregion #region AUFBAU (Scripting) #region > > > AGENDA < < < #PowerShell - Aufbau Start-Process "https://www.gfu.net/seminare-schulungen-kurse/erweiterungen_sk60/powershell-aufbaukurs_s1388.html" ## FLUSSKONTROLLE IN SKRIPTEN ### Das if/elseif/else Statement [X] ### Das switch Statement [X] ### Die while Schleife [X] ### Die do ... while/until Schleife [X] ### Die for Schleife [X] ### foreach Schleife [X] ### break & continue Klausel [X] ## BENUTZERDEFINIERTE FUNKTIONEN & SKRIPTE ### Grundlagen von Funktionen [X] ### Der Dot Operator [X] ### Formale Parameter und das param-Statement [X] ### Rückgabewerte von Funktionen [X] ### Function vs. Filter [X] ## OBJEKTHANDLING ### SkriptBlock - Grundlagen [x] ### Erzeugen & Manipulieren von Objekten [x] ### Arbeiten am Typsystem [x] ### Typerweiterung [x] ## FEHLER-MANAGEMENT ### Was-wäre-wenn Szenarien [x] ### Fehlertoleranz festlegen [x] ### Fehler erkennen und darauf reagieren [x] ### Error Records - Details zum Fehler [x] ### Exceptions verstehen [x] ### Code schrittweise ausführen: Haltepunkte [x] ## SICHERHEIT ### Absichern der PowerShell-Umgebung [x] ### Signieren von Skripten [x] ## .NET, C# UND VB.NET ### PowerShell & .NET-OOP Einblick [x] ### GUI mit .NET (WinForms, WPF) Einblick [X] #endregion #region Kontrollstrukturen (if, switch, while, do, for & foreach) # TIP: STRG + J (Snippets) # # if # get-help about_if -ShowWindow if (10 -lt 11) { "10 ist kleiner 11" } $x = 12 if ($x -lt 20) { "$x ist kleiner 20" } else { "$x ist größer 20" } $x = 16 if ($x -lt 15) { "$x ist kleiner 15" } elseif ($x -lt 20) { "$x ist kleiner 20 und größer 15" } else { "$x ist größer 20" } # # switch # get-help about_switch -ShowWindow $x = "Value3" switch -casesensitive ($x) { 'value1' # Prüfung gegen $x { # ... Code break # Option: Und Fertig } {$_ -in 'A','B','C'} # Prüfung gegen $x { } 'value3' {} Default # Optional, Wenn keine Prüfung passt { } } # # do / while # get-help about_do -ShowWindow do { # Code } until ($x -gt 0) # Fußgesteuerte Schleife, Solange eine Be. nicht zutrifft do { # Code } while ($x -gt 0) # Solange die Be. zutrifft while ($x -gt 0) # Kopfgesteuerte Schleife { # Code } # # for # get-help about_if -ShowWindow for ($i = 1 ; $i -lt 99 ; $i++) # $i = $i + 1 { # Code $i #break } $prozesse = Get-Process for ($i = 0; $i -lt $prozesse.length; $i++) { $prozesse[$i] if($prozesse[$i].Company -eq "Virus Inc.") { $prozesse[$i].Kill() } } Get-Process | ? Company -eq "Virus Inc." | Stop-Process # # foreach # get-help about_foreach -ShowWindow foreach ($item in $collection) { } foreach ($item in (Get-Process)) { if($item.Company -eq "Virus Inc.") { $item.Kill() } } # # Alle Syntax-Blöcke können per CTRL + J als Vorlage erzeugt werden # #endregion #region Bentuzerdefnierte Funktionen (eigene CmdLet's) # # CmdLets können auf zwei Arten definiert werden: # 1. per C# oder VisualBasic.NET-Code über VisualStudio => MeineCmdLets.DLL # 2. per PowerShell-Funktion mit dem Namen VERB-NOUN => MeineCmdLets.PS1 # WICHTIG: Diese CmdLets können erst genutzt werden, wenn sie im PSDrive function: etnhalten sind. # => Durch AUSFÜHREN der Definition # # # ÜBERSICHT # Get-Help about_Comment_Based_Help -ShowWindow # Beschreibung der eigenen CmdLet-Hilfe für das PS-Hilfesystem. Get-Help about_Functions -ShowWindow # Grundlagen zu benutzerdefinierten Funktion Get-Help about_Functions_Advanced -ShowWindow # Grundlagen zu benutzerdefinierten CmdLet Get-Help about_Functions_Advanced_Methods -ShowWindow Get-Help about_Functions_Advanced_Parameters -ShowWindow # Beschreibung der eigenen CmdLet-Parameter u.a. Validierung Get-Help about_Functions_CmdletBindingAttribute -ShowWindow # Beschreibung der eigenen CmdLet-Parameter bzgl. Pipeline-Verarbeitung Get-Help about_Functions_OutputTypeAttribute -ShowWindow # Beschreibung von Rückgabe-Objekte wie PSCustomObject # # Lernen von vorhanden CmdLets: # Get-Command -CommandType Function | measure gci Function:\New-Guid | Select-Object -ExpandProperty Definition [GUID]::NewGuid() # Ah-ha, das führt das CmdLet New-Guid aus. # BTW ACHTUNG: Passwörter haben im Code nichts verloren!!!!! #region Einführungsbeispiel Get-About um die tägliche Arbeit mit der Hilfe zu erleichtern Get-Help about_* # Täglich neu suchen ist doof :-( Get-Help about_* | Out-GridView # Täglich viel tippen ist auch doof :-( Get-Help about_remote_disconnnnected_Sessssions # Tippfehler ist erst recht doof :-( Get-Help about_remote_disconnected_Sessions -ShowWindow # Schonwieder viel tippen :-( Get-Help about_* | Out-GridView -OutputMode Multiple | Get-Help -ShowWindow # Schon besser, aber immer noch zuviel zu tippen # # Lösung: Eigenes CmdLet # function Get-About { Get-Help about_* | Out-GridView -OutputMode Multiple | Get-Help -ShowWindow } Get-About # # o.a. Lösung verfeinern: # function Get-About { param([string]$Filter) $result = Get-Help -Name "about_*$Filter*" if($result -is [array]) { $result | Out-GridView -OutputMode Multiple | Get-Help -ShowWindow } else { Get-Help -Name "about_*$Filter*" -ShowWindow } } Get-About -Filter if #endregion #region Unterschied Funktion vs. CmdLet-Funktion function Fläche([int]$Breite, [int]$Länge) { $fläche = $Breite * $Länge return $fläche } # Um eine Funktion benutzen zu können muss diese in den # PowerShell-Provider function abgelegt werden # durch das Ausführen der Definition gci Function:\Fläche Fläche 10 10 # wird die Session beendet wird die Funktion wieder gelöscht Remove-Item Function:\Fläche -Force Fläche 10 10 # Nachteile Funktion 'Fläche' # Keine Parameter-Prüfung # Keine Interaktion mit Get-Help # Keine Interaktion Pipline-Verarbeitung # LÖSUNG: die Funktion als CmdLet ausbauen, # möglich könnte sein: Get-Help Get-Fläche -ShowWindow Get-Fläche -Breit 10 -Länge 15.5 Get-Fläche 10 15.5 Get-Fläche 10 15.5 | Out-GridView "10x20", "55x99", "1.5x0.5" | Get-Fläche Get-Fläche 10 # Fehler Get-Fläche -10 15.5 # Fehler Get-Fläche 101 101 # Fehler Get-Fläche zehn zwölf # Fehler # # Umsetzung: # Wichtig: in einer eigenständigen *.ps1 entwickeln um mit F5 den Funktionsspeicher zu aktualisieren # function Get-Fläche { <# .Synopsis Flächenberechnung .DESCRIPTION Berechnet die Fläche aus Breit und Länge. .EXAMPLE Get-Fläche -Breit 10 -Länge 15.5 Berechnet die Fläche aus Breit 10 mal Länge 15,5 .EXAMPLE Get-Help Get-Fläche -Full .EXAMPLE Get-Fläche -Breit 10 -Länge 15.5 .EXAMPLE Get-Help Get-Fläche -Full .EXAMPLE Get-Fläche 10 15.5 -Verbose .EXAMPLE Get-Fläche 10 15.5 | Out-GridView .EXAMPLE "10x20", "55x99", "1.5x0.5" | Get-Fläche .EXAMPLE "10x20", "55x99", "1.5x0.5" | Get-Fläche | Out-GridView .EXAMPLE "10x20", "55x99", "1.5x0.5" | Get-Fläche | Sort-Object Result -Descending #> [CmdletBinding()] [Alias('gf')] [OutputType([PSObject])] Param ( # Breite der Fläche [Parameter(ParameterSetName = 'BreiteLänge', Mandatory = $true, Position = 0)] [ValidateRange(0.1, 99)] [double]$Breite = 1, # Länge der Fläche [Parameter(ParameterSetName = 'BreiteLänge', Mandatory = $true, Position = 1)] [ValidateRange(0.1, 99)] [double]$Länge = 1, [Parameter(ParameterSetName = 'Pipline', Mandatory = $true, ValueFromPipeline = $true)] [ValidatePattern('^[0-9\.]{1,4}x[0-9\.]{1,4}$')] [string]$InputObject = [string]::Empty ) Begin { Write-Verbose -Message "Get-Fläche gestartet...." } Process { if($PSCmdLet.ParameterSetName -eq 'Pipline') { $splits = $InputObject.Split('x') $Breite = [double]$splits[0] $Länge = [double]$splits[1] } $definition = '{0,5:0.00} x {1,5:0.00}' -F $Breite, $Länge $fläche = $Breite * $Länge $result = New-Object -TypeName PSObject -Property ([ordered]@{Definition=$definition; Result=$fläche}) return $result } End { } } #endregion # # Weitere Beispiele siehe 'TIPPS, TRICKS und BEISPIELE' am Ende dieser Datei # #endregion #region Benutzer-Interaktion (Einfach UI) # # Read-Host # - Ließt die Eingabe über die Tastatur bis zu einem 'Enter' # - Rückgabe ist immer ein 'System.String' # Read-Host -Prompt "Wieviel Geld wollen Sie abheben" # i.d.R. in eine Variable speichern oder über die | weiter geben $userInput = Read-Host -Prompt "Wieviel Geld wollen Sie abheben" # # Einmal Perfekt: # $deDE = New-Object -TypeName System.Globalization.CultureInfo -ArgumentList 'de-DE' $userInput = Read-Host -Prompt "Wieviel Geld wollen Sie abheben" [decimal]$betrag = $userInput.ToDecimal($deDE) $betrag $betrag.GetType() [decimal]1000 - $betrag # z.B. auch bei einem Datum: $userInput = Read-Host -Prompt "Dateien finden die älter sind als" [datetime]$datum = $userInput.ToDateTime($deDE) $datum # # Nicht so gut ist: # # Keinen Einfluss auf die Konvertierung, z.B. fürs Deutsche [decimal]$eingabe = Read-Host -Prompt "Wieviel Geld wollen Sie abheben" # Eine falsche Zuweisung ist später immer noch möglich $eingabe = [decimal](Read-Host -Prompt "Wieviel Geld wollen Sie abheben") $eingabe = Get-Process # # Out-GridView # $processes = Get-Process -IncludeUserName | ? UserName -Match 'akric' $killMe = $processes | Out-GridView -Title 'Welche Prozesse sollten beendet werden' -OutputMode Multiple $killMe | Stop-Process -Force -WhatIf # Als Einzeiler Get-Process -IncludeUserName | ? UserName -Match 'akric' | Out-GridView -Title 'Welche Prozesse sollten beendet werden' -OutputMode Multiple | Stop-Process -Force -WhatIf # # Weitere Beispiele für Out-GridView und Interaktion mit einem User # $betrag = 10, 25, 50, 100, 250 | Out-GridView -OutputMode Single $antwort = "JA, Dateien archivieren", "NEIN, Dateien am Ort belassen" | Out-GridView -OutputMode Single $antwort.StartsWith('NEIN') # # 'richtige' MessageBox'en nur über das .NET Framework: # [System.Windows.Forms.MessageBox]::Show('Hallo Köln') $title = "Dateien archivieren" $message = "Alte Dateien archivieren? (Werden am Ursprungsort gelöscht auf ... kopiert)" $buttons = [System.Windows.Forms.MessageBoxButtons]::OK $icon = [System.Windows.Forms.MessageBoxIcon]::Question $defaultButton = [System.Windows.Forms.MessageBoxDefaultButton]::Button1 $antwort = [System.Windows.Forms.MessageBox]::Show($message, $title, $buttons, $icon, $defaultButton) if($antwort -eq [System.Windows.Forms.DialogResult]::Yes) { "OK, die Dateien werden archiviert..." } #endregion #region Debug- und Ausnahme-Management <# Errors sind OUT Exceptions sind IN Reagieren auf Ex. per "trap"-Block oder "try-catch"-Block oder auch nicht! WICHTIG: Ex. nur behandeln wenn eine Lösung vorhanden ist (Meldungen sind keine Lösungen) #> $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Continue $WarningPreference = [System.Management.Automation.ActionPreference]::Continue $VerbosePreference = [System.Management.Automation.ActionPreference]::SilentlyContinue $InformationPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue $DebugPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue $ConfirmPreference = [System.Management.Automation.ConfirmImpact]::High # # 1. Ausnahme analysieren (d.h. Ausnahme reproduzieren) # 1/0 # Div durch 0 $error.Count $error[0] # Die letzte Ausnahme $error[0] -is [System.Management.Automation.RuntimeException] # Oder... $error[0] -is [System.Management.Automation.ErrorRecord] $error[0].Exception -is [Exception] # 1. Ebene $error[0].Exception | fl * -Force $error[0].Exception.Message $error[0].Exception.GetType() $error[0].Exception.StackTrace $error[0].Exception.InnerException -eq $null # 2. Ebene $error[0].Exception.InnerException | fl * -Force $error[0].Exception.InnerException.Message $error[0].Exception.InnerException.GetType() $error[0].Exception.InnerException.StackTrace $error[0].Exception.InnerException.InnerException -eq $null # Wenn 'Exception.InnerException.InnerException' = null, keine weiteren Ebenen, sonst wie 2. Ebene verfahren # TRAP # Muss vor der Ex aufgestellt werden trap # Alle { } # Code mit Fehler trap [DivideByZeroException] { # Was soll bei Ex passieren: "Fehler gefangen für: {0}" -f $_.Exception.Message continue #break #exit } $Erg = (100 / 0) echo $Erg Write-Output "Anweisung nach dem Laufzeitfehler" # # TRY-CATCH-Block # WICHTIG Nur nutzen wenn eine LÖSUNG vorhanden ist! # MsgBox SIND KEINE LÖSUNG!!!! # try { # Codezeil(en) die evtl. eine Ex. auslösen $xmlFile = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xmlx" $xmlDokument = New-Object -TypeName xml $xmlDokument.Load($xmlFile) Write-Host "Alles OK!" # Die letzte Zeile wird nur erreicht wenn keine Ex aufgetreten ist! } catch [System.Net.WebException] { # Code für WebException } catch # Dieser Catch-Block fängt ALLE Ex ab (ideal für Ex-Analyse, Protokollieren) { # Die Lösung: In eine Datei loggen... $_.Exception.GetType() $_.Exception.InnerException.GetType() $_.Exception.InnerException.Message #throw # Ex erneut werfen } # Eigene Ex werfen Write-Error -Message "Meldungstext" # # DEBUGGING # # 1. Nur *.ps1-Dateien können vom DEBUG profitieren # 2. *.ps1-Datei muss vorher gespeichert sein # # F9 => Haltepunkt setzen # F5 => Debugger wird gestartet # Bleibt beim ersten HP stehen # F11 => Führt die nächste Code-Zeile aus (gelbe Zeile wurde NOCH NICHT ausgeführt) # s. ToolTip Variablen # SHIFT + F5 = DEBUG beenden # Get-Command -Noun PSBreakPoint -Module Microsoft.PowerShell.* Write-Debug -Message "Meldungstext" -Debug Write-Verbose -Message "Meldungstext" -Verbose Write-Warning -Message "Meldungstext" # # Analyse zwischen CmdLets # Trace-Command ParameterBinding {Get-Alias ls | fl} -PSHost #endregion #region PowerShell-Dateiendungen # *.ps1 = Windows PowerShell Shell-Skript Version 1.0 -Datei (Beachte Ausführungsrichtlinien) # *.ps1xml = Windows PowerShell Format- und Typdefinitionen -Datei, z.B.: gci C:\Windows\System32\WindowsPowerShell\v1.0\*.ps1xml . C:\Windows\System32\WindowsPowerShell\v1.0\types.ps1xml # *.psc1 = Windows PowerShell Console -Datei Export-Console -Path c:\temp\myconsole.psc1 powershell.exe -PSConsoleFile c:\temp\myconsole.psc1 # *.psd1 = Windows PowerShell Modul-Manifest -Datei # *.psm1 = Windows PowerShell Modul -Datei (Beachte Ausführungsrichtlinien) # psd1 definiert die Eckdaten eines Modules und psdm1 den Inhalt des Modules, z.B. siehe: gci C:\Windows\System32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Archive #endregion #region Ausführungsrichtlinien für Script-Dateien (*.ps1, *.psm1) # In das Thema einlesen Get-Help about_Execution_Ploicys -ShowWindow Get-Help about_Signing -ShowWindow # Default Restricted Get-ExecutionPolicy # Für Test-/Entwicklungszwecke Set-ExecutionPolicy -ExecutionPolicy RemoteSigned # Produktivsysteme (Alle *.ps1-Dateien müssen signiert werden) Set-ExecutionPolicy -ExecutionPolicy AllSigned # Einstellung bleiben dauerhaft erhalten # Einstellung kann auch per GPO vergenommen werden # Einstellung kann nur mit Admin-Rechten vorgenommen werden Set-ExecutionPolicy -ExecutionPolicy Unrestricted Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser # # Möglichkeiten *.ps1-Datei auszuführen: # # - GPO # - Aufruf in der Console, z.B. . "c:\temp\test.ps1" # - Per Rechtsklick / Mit PowerShell ausführen # - Per Verknüpfung auf => powershell.exe -File "c:\temp\test.ps1" -WindowStyle Hidden # powershell.exe -File "c:\temp\test.ps1" -NoExit # - Per MyPSScript.exe => z.B. über das Tool PowerGui oder VisualStudio und C# # - Aufruf der *.ps1-Datei in einer der möglichen Autostart-Dateien # - Aufgabenplanung, RUN-Schlüssel, etc. #endregion #region Auto-Start-Script-Dateien # Default-Dateien # WICHTIG: Ordner und Dateien evtl. erstellen # Auswirkung für: LocalMachine $env:windir + "\system32\WindowsPowerShell\v1.0\profile.ps1" # Host, Console, ISE $env:windir + "\system32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1" # Console $env:windir + "\system32\WindowsPowerShell\v1.0\Microsoft.PowerShellISE_profile.ps1" # ISE # Auswirkung für: CurrentUser $env:USERPROFILE + "\Documents\WindowsPowerShell\profile.ps1" # Host, Console, ISE $env:USERPROFILE + "\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1" # Console $env:USERPROFILE + "\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1" # ISE # z.B. das ständige Ausführen einer *.ps1-Datei Add-Content -Force ` -Path "$env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1" ` -Value ". ""C:\temp\CmdLib.ps1""" #endregion #region Dynamischer Aufruf von *.ps1-Dateien # Test immer in einer ps1-Datei in der Console, nicht in der ISE $aktuellerPfad = $MyInvocation.MyCommand.Definition $aktuellerPfad # C:\Temp\MachWas.ps1 $aktuellerOrdner = Split-Path -Path $aktuellerPfad -Parent $aktuellerOrdner # C:\Temp $pfadNeu = Join-Path -Path $aktuellerOrdner -ChildPath "AnderesScript.ps1" $pfadNeu # C:\Temp\AnderesScript.ps1 . $pfadNeu #endregion #region Ein- / Ausgabe-Parameter von "*.ps1" # -> Einfach einen Param-Block einfügen (siehe Function) #endregion #region Scripte (*.ps*1) signieren # # 0. VORBEREITUNG # Set-Location C:\Temp Copy-Item -Path "$env:USERPROFILE\OneDrive\Wissen\PowerShell\MakeCert.exe" -Destination .\ -Force # s. MSDN Test-Path -Path .\Get-EuroExchange.ps1 # Vorhanden? Set-ExecutionPolicy -ExecutionPolicy AllSigned -Scope CurrentUser -Force # Auch per GPO möglich. Get-ExecutionPolicy -List # Check? $CAName = "_PowerShell Root CA TEMP" # Zertifizierungsstelle $PSDeveloperName = "_Attila Krick (PS Developer)" # Der Signierer $PS1Name = "Get-EuroExchange.ps1" # Die zu signierende Datei # WARUM? # a) Schutz gegen Manipulation von PS-Scriptdateien (ps1, psm1, ps1xml, ...) # b) Ausführungsrichtlien auf "AllSigned" d.h. PS-Scriptdateien nur noch ausgeführt werden, wenn: # 1. o.a. Dateien X.509 signiert sind. # 2. o.a. X.509 von einer "Vertrauenswürdigen Stammzertifizierungsstelle" abstammt (engl. Root) # 3. o.a. X.509 im Zertifikatspeicher für "Vertrauenswürdige Herausgaber" enthalten ist (engl. TrustPublisher) # Problem ... & "C:\temp\$PS1Name" #Lösung ... Lösung => Signieren! # 1. Vielleicht besitzen Sie schon so ein x.509 Zertifikat mit Verwendungszweck "Codesigning" inkl. des "Private Key"? Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert # ... Wenn vorhanden dan weiter mit Punkt 5. # 2. ROOT-CA erstellen .\MakeCert.exe -n "CN=$CAName" -a sha512 -r -sv "$CAName.pvk" "$CAName.cer" gci .\ | ? Extension -IN '.cer', '.pvk' . ".\$CAName.cer" # 3. Öffentlich Root-CA verteilen (z.B. über GPO) in den Speicher für vertrauenswürdige Stammzertifizierungsstellen (Root) $CACert = Import-Certificate -FilePath "$CAName.cer" -CertStoreLocation Cert:\LocalMachine\Root gci Cert:\ -Recurse | ? Thumbprint -EQ $CACert.Thumbprint . ".\$CAName.cer" # 4. Signierungszertifikate pro Benutzer in "Eigene Zertifikate (MY)" installieren .\MakeCert.exe -n "CN=$PSDeveloperName" -a sha512 -eku 1.3.6.1.5.5.7.3.3 -pe -ss MY -ic "$CAName.cer" -iv "$CAName.pvk" $PSDeveloperCert = gci Cert:\CurrentUser\My -CodeSigningCert | ? Subject -EQ "CN=$PSDeveloperName" gci Cert:\CurrentUser\My -CodeSigningCert | ? Thumbprint -eq $PSDeveloperCert.Thumbprint | Export-Certificate -Type CERT -FilePath "$PSDeveloperName.cer" -Force . ".\$PSDeveloperName.cer" # 5. Jetzt Können *.ps1-Dateien signiert werden Set-AuthenticodeSignature -FilePath ".\$PS1Name" -Certificate $PSDeveloperCert -Force -HashAlgorithm SHA512 -IncludeChain all . ".\$PS1Name" # 6. OPTIONAL Das öffentliche Benutzer-Zertifikat von 3. muss z.B. per GPO auf alle betroffenen Host's verteillt Import-Certificate -FilePath "$PSDeveloperName.cer" -CertStoreLocation Cert:\LocalMachine\TrustedPublisher gci Cert:\LocalMachine\TrustedPublisher . ".\$PS1Name" # 7. Kontrollieren (Mit / Ohne eine Änderung an der signierten Datei) Get-Content ".\$PS1Name" Get-AuthenticodeSignature -FilePath ".\$PS1Name" | fl * Start-Process -FilePath ".\$PS1Name" # TEST: Einmal Code manipulieren Get-AuthenticodeSignature -FilePath ".\$PS1Name" | fl * # TEST: Valid? . ".\$PS1Name" # TEST: Wird ausgeführt? # 8. Empfohlene Einstellung für den Entwicklungs-Rechner Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force # -------------------------------------------------------- AUFRÄUMEN --------------------------------------------- gci Cert:\LocalMachine\TrustedPublisher | ? Subject -EQ "CN=$PSDeveloperName" | Remove-Item gci Cert:\CurrentUser\My | ? Subject -EQ "CN=$PSDeveloperName" | Remove-Item gci Cert:\LocalMachine\Root | ? Subject -EQ "CN=$CAName" | Remove-Item gci C:\Temp\ | ? Extension -IN '.cer', '.pvk' | Remove-Item Set-ExecutionPolicy -ExecutionPolicy Bypass -Force -Scope CurrentUser #endregion #region eigene Module erstellen (Module) Get-Help about_modules -ShowWindow # # 0. Vorbereitung # $moduleName = "GFU" $moduleGuid = "cdca8770-8bd2-48ee-971a-e2456349f3b7" # z.B. New-Guid aufrufen $destinationModulePath = "C:\Users\Administrator\Documents\WindowsPowerShell\Modules" # $env:PSModulePath s.a. region Module # # 1. Modul-Ordner erstellen # $destinationModulePath = Join-Path -Path $destinationModulePath -ChildPath $moduleName New-Item -Path $destinationModulePath -ItemType Directory -Force Set-Location -Path $destinationModulePath # # 2. PSM1-Datei erstellen (Diese Datei wird ausgeführt, wenn das Module geladen wird (Evtl. signieren)) # New-Item -Path .\$moduleName.psm1 -ItemType File -Force Get-Content -Path '\\srv00\disk\Raum7\Attila Krick\Get-OldFile.ps1' | Add-Content .\$moduleName.psm1 Get-Content -Path '\\srv00\disk\Raum7\Attila Krick\Get-BigFile.ps1' | Add-Content .\$moduleName.psm1 Get-Content -Path '\\srv00\disk\Raum7\Attila Krick\Get-EuroExchange.ps1' | Add-Content .\$moduleName.psm1 "New-Alias -Name gee -Value Get-EuroExchange -Force" | Add-Content .\$moduleName.psm1 # # 3. PSD1-Datei erstellen (Manifest-Informationen über unser Module) # New-ModuleManifest -Path .\$moduleName.psd1 ` -RootModule $moduleName ` -Guid $moduleGuid ` -Author "Attila Krick" ` -CompanyName "GFU AG" ` -Copyright "(c) 2019 by Tata" ` -Description "Test-Module aus der PowerShell-Schulung - Aufbaukurs" ` -ModuleVersion "1.0.1.3" ` -AliasesToExport "gee" ` -CmdletsToExport "Get-OldFile", "Get-BigFile", "Get-EuroExchange" # Bzgl. ModuleVersion: a.b.c.d => a+b (Neue Feature), c (Bugfix'ing), d (Ausroll-Varianten) Start-Process -FilePath .\$moduleName.psd1 # # 4. Check! # Get-ChildItem -Path . -Force -Recurse # C:\Users\Administrator\Documents\WindowsPowerShell\Modules\GFU mit GFU.psd1 und GFU.psm1 *.Length > 0 Start-Process -FilePath .\$moduleName.psd1 # Angaben prüfen Start-Process -FilePath .\$moduleName.psm1 # Evtl. Kommentare entfernen? Get-ExecutionPolicy -List # Process, CurrentUser, LocalMachine = RemoteSigned oder Unrestricted oder Bypass Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force Get-Module -Name GFU -ListAvailable # Vorhanden ?, ExportedCommands ? Import-Module -Name GFU # Fehlerfrei? Get-Module -Name GFU # Vorhanden ? Remove-Module -Name GFU # Fehlerfrei ? Get-Module -Name GFU # Nicht Vorhanden ? gee -Currency USD # Fehlerfrei ? Get-Module -Name GFU # Vorhanden ? # # siehe auch # Show-Command Get-Command *module* -Module PowerShellGet Publish-Module # => PowerShellGallery #endregion #region UI (ohne G und nur mit PowerShell) # Siehe Thema "Ausgabe" $eingabe = Read-Host -Prompt "Bitte Datum eingeben" $eingabe | Get-Member # System.String $eingabe "12.12.12", "13.12.12", "14.12.12" | Out-GridView -Title "Bitte Datum wählen" -OutputMode Single Show-Command -Name Get-EuroExchange -NoCommonParameter -ErrorPopup | Out-GridView 1..100 | % {Start-Sleep -Milliseconds 200 ; Write-Progress -Activity "Bitte warten" -PercentComplete $_ } $title = "Delete Files" $message = "Do you want to delete the remaining files in the folder?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Deletes all the files in the folder." $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" , "Retains all the files in the folder." $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 {"You selected Yes."} 1 {"You selected No."} } #endregion #region .NET-Code direkt nutzen # Siehe auch Tipps und Tricks # # z.B. .NET Framework (eine Art Library) nutzen # [System.Reflection.Assembly]::LoadWithPartialName("System.Diagnostics.Stopwatch") # Lädt ein Assembly aus GAC über den Namespace-Namen $sw = New-Object -TypeName System.Diagnostics.Stopwatch # "StopWatch" => Klasse im Namensraum "System.Diagnostics" $sw.Start() [System.Threading.Thread]::Sleep(2500) $sw.Stop() $sw # # z.B. .NET nutzen => OOP (C# oder VisualBasic) # $source = @" public class Rechner { public static int Addiere(int a, int b) { return (a + b); } public int Multipliziere(int a, int b) { return (a * b); } } "@ Add-Type -TypeDefinition $source -Language CSharp # ACHTUNG bis PS5.0 war die Klasse Rechner unveränderbar [Rechner]::Addiere(10, 10) $obj = New-Object -TypeName Rechner $obj.Multipliziere(10, 2) # # AB PowerShell 5.0 auch so: # enum Color { Blue Green Red } $myColor = [Color]::Green $myColor class Car { [Color]$Color [int]$HP } $myCar = New-Object -TypeName Car $myCar.Color = [Color]::Green $myCar.HP = 100 $myCar | Get-Member Get-Help -Name about_Class -ShowWindow #endregion #region GUI # Siehe auch TIPPS, TRICKS und BEISPIELE #region GUI ALT (WinForms) nach dem Namespace System.Windows.Forms $url = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" $xml = [xml](Invoke-WebRequest -Uri $url | select -exp Content) $cubes = $xml.Envelope.Cube.Cube.Cube $currencys = $cubes | sort currency | select -exp currency function EuroRateRechnen() { try { $aktWährung = $währungComboBox.SelectedItem [decimal]$rate = $cubes | ? currency -eq $aktWährung | select -exp rate $euro = $euroTextBox.Text $ergebnis = $rate * $euro } catch { $rate = 0 $ergebnis = 0 } $eregbnisTextBox.Text = $ergebnis $rateTextBox.Text = $rate } $währungLabel = New-Object -TypeName System.Windows.Forms.Label $währungLabel.Text = "&Währung:" $währungLabel.Top = 15 $währungLabel.Left = 15 $währungComboBox = New-Object -TypeName System.Windows.Forms.ComboBox $währungComboBox.Top = $währungLabel.Top + $währungLabel.Height $währungComboBox.Left = 15 $währungComboBox.AutoCompleteSource = [System.Windows.Forms.AutoCompleteSource]::ListItems $währungComboBox.AutoCompleteMode = [System.Windows.Forms.AutoCompleteMode]::SuggestAppend $währungComboBox.Items.AddRange($currencys) $währungComboBox.Add_TextChanged({EuroRateRechnen}) $währungComboBox.SelectedIndex = 0 $rateLabel = New-Object -TypeName System.Windows.Forms.Label $rateLabel.Text = "&Rate:" $rateLabel.Top = $währungComboBox.Top + $währungComboBox.Height + 10 $rateLabel.Left = 15 $rateTextBox = New-Object -TypeName System.Windows.Forms.TextBox $rateTextBox.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Right $rateTextBox.ReadOnly = $true $rateTextBox.Top = $rateLabel.Top + $rateLabel.Height $rateTextBox.Left = 15 $rateTextBox.Text = "0" $euroLabel = New-Object -TypeName System.Windows.Forms.Label $euroLabel.Text = "&Euro(s):" $euroLabel.Top = $rateTextBox.Top + $rateTextBox.Height + 10 $euroLabel.Left = 15 $euroTextBox = New-Object -TypeName System.Windows.Forms.TextBox $euroTextBox.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Right $euroTextBox.Top = $euroLabel.Top + $euroLabel.Height $euroTextBox.Left = 15 $euroTextBox.Add_TextChanged({EuroRateRechnen}) $ergebnisLabel = New-Object -TypeName System.Windows.Forms.Label $ergebnisLabel.Text = "&Ergebnis:" $ergebnisLabel.Top = $euroTextBox.Top + $euroTextBox.Height + 10 $ergebnisLabel.Left = 15 $eregbnisTextBox = New-Object -TypeName System.Windows.Forms.TextBox $eregbnisTextBox.TextAlign = [System.Windows.Forms.HorizontalAlignment]::Right $eregbnisTextBox.ReadOnly = $true $eregbnisTextBox.Top = $ergebnisLabel.Top + $ergebnisLabel.Height $eregbnisTextBox.Left = 15 $HauptForm = New-Object -TypeName System.Windows.Forms.Form $HauptForm.Text = "EURO EXCHANGER XP V10.9.1 NT PLUS PROF EDITION LIGHT" $HauptForm.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $HauptForm.Height = 300 $HauptForm.Controls.AddRange(( ` $währungLabel, $währungComboBox, ` $rateLabel, $rateTextBox, ` $euroLabel, $euroTextBox, ` $ergebnisLabel, $eregbnisTextBox)) $euroTextBox.Text = "1" $HauptForm.ShowDialog() #endregion #region GUI NEU (WPF) nach dem Namespace System.Presentation $url = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" $xml = [xml](Invoke-WebRequest -Uri $url | select -exp Content) $cubes = $xml.Envelope.Cube.Cube.Cube $currencys = $cubes | sort currency | select -exp currency function EuroRateRechnen() { try { $aktWährung = $WährungenCtrl.SelectedItem [decimal]$rate = $cubes | ? currency -eq $aktWährung | select -exp rate $euro = $eurosCtrl.Text $ergebnis = $rate * $euro } catch { $rate = 0 $ergebnis = 0 } $RateCtrl.Text = $rate $ErgebnisCtrl.Text = $ergebnis } Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName System [XML]$xaml = @" <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="€CALC" Width="220" Height="255" WindowStartupLocation="CenterScreen"> <Grid Margin="20"> <StackPanel> <Label>Währungssymbol</Label> <ComboBox x:Name="Währungen" /> <abel>Rate</Label> <TextBox x:Name="Rate" IsReadOnly="True" TextAlignment="Right" /> <Label>Euro(s)</Label> <TextBox x:Name="Euros" TextAlignment="Right" /> <Label>Ergebnis</Label> <TextBox x:Name="Ergebnis" IsReadOnly="True" TextAlignment="Right" /> </StackPanel> </Grid> </Window> "@ $reader = New-Object System.Xml.XmlNodeReader $xaml $window = [Windows.Markup.XamlReader]::Load($Reader) $WährungenCtrl = $window.FindName('Währungen') $RateCtrl = $window.FindName('Rate') $EurosCtrl = $window.FindName('Euros') $ErgebnisCtrl = $window.FindName('Ergebnis') $currencys | % { $WährungenCtrl.Items.Add($_) | Out-Null } $WährungenCtrl.Add_SelectionChanged({EuroRateRechnen}) $WährungenCtrl.SelectedIndex = 0 $EurosCtrl.Add_TextChanged({EuroRateRechnen}) $EurosCtrl.Text = "1" $window.ShowDialog() #endregion #endregion #endregion #region ADS #region AGENDA PowerShell für Active Directory-Administratoren Start-Process "http://www.gfu.net/seminare-schulungen-kurse/erweiterungen_sk60/powershell_active_directory_administratoren_s1317.html" # Grundlagen der PowerShell # Was ist PowerShell? # Parsing und PowerShell # Pipelines und Befehle # # Active Directory Verwaltung mit der Powershell # Verwaltung von Active Directory Objekten (OU, User, Computer, Group) # Gruppenrichtlinien in der PowerShell # Anlegen und Verwalten von Password Settings Objects # Anlegen und Verwendung des Active Directory Papierkorbs # Active Directory-Verwaltungscenter # Verwaltung von Active Directory Standorten # ADSI und die Powershell # # Arbeiten mit Typen, Operatoren und Ausdrücke # Array-Operatoren # Flusskontrolle und Funktionen # .NET und WinForms #endregion #region 1. ADS Forest aufsetzen Add-WindowsFeature -Name AD-Domain-Services -IncludeAllSubFeature -IncludeManagementTools -LogPath C:\Users\Administrator\Desktop\AddWinFeature.log Import-Module ADDSDeployment Install-ADDSForest -CreateDnsDelegation:$false ` -DatabasePath "C:\Windows\NTDS" ` -DomainMode "Win2012R2" ` -DomainName "abc.local" ` -DomainNetbiosName "ABC" ` -ForestMode "Win2012R2" ` -InstallDns:$true ` -LogPath "C:\Windows\NTDS" ` -NoRebootOnCompletion:$false ` -SysvolPath "C:\Windows\SYSVOL" ` -Force:$true ` -SafeModeAdministratorPassword (Read-Host -AsSecureString) #endregion #region 2. AD & PS Vorbereitung Update-Help -Module * -UICulture de-DE, en-US -Force #evtl. dcpromo $cred = Get-Credential Add-Computer -DomainName "abc" -Credential $cred #endregion #region Module Get-Module -ListAvailable # Installiert Module? Get-Module # z.Zt. geladenen Module? Get-WindowsFeature RSAT* Add-WindowsFeature -Name RSAT-AD-PowerShell, RSAT-AD-Tools, RSAT-ADDS # für Windows Server 2012 # 1. Für Windows-Client RSAT-Packet (*.msu) installieren # 3. Add-WindowsFeature -Name RSAT-AD-PowerShell Get-Module -Name ActiveDirectory -ListAvailable Import-Module -Name ActiveDirectory Get-Module Get-PSDrive -PSProvider ActiveDirectory # Grund für das manuelle Laden Remove-Module -Name ActiveDirectory #endregion #region Active Directory-Objekte Get-Command -Module ActiveDirectory | Out-GridView New-ADOrganizationalUnit -Name "AK" -Path "DC=abc, DC=local" Show-Command New-ADUser New-ADUser -Name sauer2 -Path "OU=AK, DC=abc, DC=local" $ms = New-ADUser -Name mittelsauer -Path "OU=AK, DC=abc, DC=local" -PassThru $ms | Get-Member New-ADUser -Name sauer5 -Path "OU=AK, DC=abc, DC=local" -Enabled $true -AccountPassword (ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force) # 1. Anmeldung Pwd ändern # 2. Anmeldename fehlt # 3. Job-Titel fehlt New-ADUser -Name sauer6 -UserPrincipalName "sauer6" ` -ChangePasswordAtLogon $true ` -Title "Supporter" ` -Path "OU=AK, DC=abc, DC=local" -Enabled $true -AccountPassword (ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force) # # Benutzer über CSV hinzufügen # $csv = @" UserName;InizialPassword Uwe;P@ssw0rd Inge;P@ssw0rd Horst;P@ssw0rd "@ Set-Content -Path c:\temp\NewUsers.csv -Value $csv Import-Csv -Path C:\temp\NewUsers.csv -Delimiter ";" | ForEach-Object { New-ADUser -Name $_.UserName ` -UserPrincipalName $_.UserName ` -Path "OU=AK, DC=abc, DC=local" ` -Enabled $true -AccountPassword (ConvertTo-SecureString -String $_.InizialPassword ` -AsPlainText ` -Force) } $FormatEnumerationLimit = -1 Get-ADUser -Identity "lustig" | Get-Member (Get-ADUser -Identity "lustig").gettype() $Identity = "lustig" $InitPassword = [System.IO.Path]::GetRandomFileName() -replace "\.", "@" $bx = Get-ADUser -Identity $Identity | Set-ADAccountPassword -Reset -NewPassword (ConvertTo-SecureString $InitPassword -A -f) -PassThru $bx | Set-ADUser -ChangePasswordAtLogon $true -AccountExpirationDate (Get-Date).AddMinutes(3) function Reset-ADUserPassword { <# .SYNOPSIS bla bla bla .DESCRIPTION hmmm hmmm hmm .EXAMPLE Reset-ADUserPassword -Identity "lustig" bla bla bla #> param ( # Geben Sie ..... [Parameter(Mandatory=$true)] [string]$Identity ) $InitPassword = [System.IO.Path]::GetRandomFileName() -replace "\.", "@0G" $bx = Get-ADUser -Identity $Identity | Set-ADAccountPassword -Reset -NewPassword (ConvertTo-SecureString $InitPassword -A -f) -PassThru $bx | Set-ADUser -ChangePasswordAtLogon $true -AccountExpirationDate (Get-Date).AddMinutes(3) [pscustomobject]@{"Inizial Passwort für die erste Anmeldung"=$InitPassword} } Reset-ADUserPassword -Identity "lustig" | Out-GridView Show-Command Reset-ADUserPassword -ErrorPopup # # AD Gruppen # Get-ADGroup -Identity administratoren $a = Get-ADGroup -Identity S-1-5-32-544 -Properties member $a.member | Get-Member $a.member[0] $a.member | Get-ADObject Get-ADGroup -Filter 'GroupCategory -eq "Security" -and GroupScope -ne "DomainLocal"' Get-ADGroup -Server localhost -Filter {GroupScope -eq "DomainLocal"} -SearchBase "DC=abc,DC=local" $zeroGrps = @() $a = Get-ADGroup -Properties member -Filter * foreach ($item in $a) { if($item.member.Count -eq 0) { $zeroGrps += $item } } $filename = "LeereGruppen_vom_{0:yyyy-MM-dd}.html" -f (Get-Date) $zeroGrps | ConvertTo-Html -Property Name -PreContent "Leere AD-Gruppen vom $(Get-Date)" | Out-File ".\$filename" # vs. Get-ADGroup -Properties member -Filter * | where {$_.member.Count -eq 0} | ConvertTo-Html -Property Name -PreContent "Leere AD-Gruppen vom $(Get-Date)" Get-ADUser -Identity Administrator Get-Command -Name *group* -Module ActiveDirectory # Wo ist der Administrator mitglied? Get-ADPrincipalGroupMembership -Identity Administrator | ft Name # Wo ist Wer mitglied? Get-ADUser -Filter * | ForEach-Object { $user = $_ $_ | Get-ADPrincipalGroupMembership | ForEach-Object { [pscustomobject]@{Username=$user.Name;GoupName=$_.Name} } } | ConvertTo-Html | Out-File .\UsersGroups.html #endregion Get-ADForest [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest() #region ADSI & LDAP Start-Process http://www.powershellpraxis.de/index.php/active-directory/activedirectory-provider $rootDSE = [ADSI]"LDAP://rootDSE" $adRootPath = $rootDSE.defaultNamingContext $ad = [ADSI]"LDAP://$adRootPath" $adComputer = [ADSI]'LDAP://CN=Computers,DC=abc,DC=local' $adComputer.Children $User = [ADSI]"LDAP://cn=lustig, ou=ak, dc=abc, dc=local" $UAC = $User.UserAccountControl[0] -bor 65536 # Password never expire $User.Put("userAccountControl",$UAC) $User.SetInfo() $admin = [ADSI]"LDAP://cn=Administrator,cn=Users,dc=abc,dc=local" $admin.class $admin.objectclass $admin = [ADSI]"LDAP://cn=Administrator,cn=Users,dc=abc,dc=local" $groups = $admin.MemberOf | ForEach-Object {[ADSI]"LDAP://$_"} $groups ([ADSI]'WinNT://lunar80/Administratoren,group').Add('WinNT://DOMAIN/USER,user') # Add a domain user to a remote server local group, if your current user has admin over the remote machine ([ADSI]'WinNT://lunar80,computer').psbase.children | where { $_.psbase.schemaClassName -eq 'group' } | foreach { ($_.name)[0]} # Get all local groups on a remote server ([ADSI]'WinNT://lunar80/Administratoren,group').psbase.Invoke('Members') | foreach { $_.GetType().InvokeMember('ADspath', 'GetProperty', $null, $_, $null).Replace('WinNT://', '') } # Find members of the local Administrators group on a remote server $a=([ADSI]'WinNT://lunar80/Administrator,user'); $a.UserFlags=2; # Enable the local Administrator account on a remote server $a.CommitChanges() $a=([ADSI]'WinNT://SERVER/Administrator,user'); $a.UserFlags=512; # Disable the local Administrator account on a remote server $a.CommitChanges() Start-Process https://technet.microsoft.com/en-us/library/ff730967.aspx Get-ADObject -LDAPFilter "(&(operatingSystem=Windows Server 2012 R2 Datacenter)(objectClass=computer))" -SearchBase "dc=abc,dc=local" -SearchScope Subtree Search-ADAccount -PasswordExpired -UsersOnly -SearchBase "dc=abc,dc=local" -SearchScope OneLevel $adSearcher = New-Object -TypeName DirectoryServices.DirectorySearcher $adSearcher.Filter = "(objectCategory=user)" $adSearcher.SearchRoot = "LDAP://DC=abc,DC=local" $result = $adSearcher.FindAll() $result | Get-Member $result | fl * $ACCOUNTDISABLE = 0x000002 $DONT_EXPIRE_PASSWORD = 0x010000 $PASSWORD_EXPIRED = 0x800000 $searcher = [adsisearcher]"(&(objectClass=user)(objectCategory=person))" $searcher.FindAll() | ForEach-Object { $user = [adsi]$_.Properties.adspath[0] [PSCustomObject]@{ SamAccountName = $user.sAMAccountName[0] Name = $user.name[0] Mail = $user.mail[0] PasswordLastSet = [DateTime]::FromFileTime($_.Properties.pwdlastset[0]) Enabled = -not [bool]($user.userAccountControl[0] -band $ACCOUNTDISABLE) PasswordNeverExpires = [bool]($user.userAccountControl[0] -band $DONT_EXPIRE_PASSWORD) PasswordExpired = [bool]($user.userAccountControl[0] -band $PASSWORD_EXPIRED) } } # # ODER per ActiveDirectory-Module: # Import-Module ActiveDirectory $attributes = 'SamAccountName', 'Name', 'Mail', 'PasswordLastSet', 'Enabled','PasswordNeverExpires', 'PasswordExpired' Get-ADUser -Filter * -Properties $attributes | select $attributes #endregion #region GPO Import-Module GroupPolicy -Verbose Get-Command -Module GroupPolicy Backup-GPO # Mit diesem Cmdlet sichert man das angegebene Gruppenrichtlinienobjekt (GPO) oder alle Gruppenrichtlinienobjekte in einer angegebenen Domäne in ein Sicherungsverzeichnis. Dabei muss das Sicherungsverzeichnis bereits existieren. Restore-GPO # Dieses Cmdlet stellt eine GPO-Sicherung in der Domäne wieder her, in der sie ursprünglich gespeichert wurde. Ist die ursprüngliche Domäne oder die GPO nicht mehr in der Domäne vorhanden, tritt ein Fehler auf. Get-GPO # Eine bestimmte GPO oder alle GPOs innerhalb einer Domäne kann man sich mit diesem Cmdlet anzeigen lassen. Copy-GPO # Dieses Cmdlet erstellt eine neue GPO und kopiert die Einstellungen aus der Quell-GPO in die neue GPO. Mit diesem Cmdlet kann eine GPO aus einer Domäne in eine andere Domäne innerhalb der gleichen Gesamtstruktur kopiert werden. New-GPO # Eine neue GPO wird mit diesem Cmdlet erstellt. Remove-GPO # Eine GPO wird mit samt allen Verlinkungen, mit diesem Cmdlet gelöscht. Import-GPO # Dieses Cmdlet importiert die Einstellungen aus einer gesicherten GPO in die angegebene Ziel-GPO. Dabei kann sich das Ziel-GPO in einer anderen Domäne oder in einer anderen Gesamtstruktur befinden als die Sicherungs-GPO und muss vorher nicht existieren. Rename-GPO # Mit diesem Cmdlet kann man eine GPO umbenennen bzw. der GPO einen anderen Anzeigenamen zuweisen. Dabei bleibt die GUID der umbenannten GPO erhalten. Get-GPInheritance # Informationen zur Gruppenrichtlinienvererbung für eine angegebene Domäne oder Organisationseinheit kann man sich mit diesem Cmdlet ausgeben lassen. Get-GPOReport # Hiermit wird ein Bericht im XML- oder HTML-Format generiert, in dem die Eigenschaften und Richtlinieneinstellungen für eine angegebene GPO oder für alle GPOs einer Domäne angezeigt werden. Dieses Cmdlet eignet sich ideal zu Dokumentationszwecken. Möchte man alle Richtlinieneinstellungen aller GPOs innerhalb der Domäne in eine HTML Datei exportieren, so gilt es diesen Befehl auszuführen: Get-GPOReport -All -Domain <Domäne.de> -ReportType HTML -Path C:\GPOReport\GPOReport.html. Das Zielverzeichnis muss bereits existieren, sonst erhält man eine Fehlermeldung. Get-GPPermissions # Die Berechtigungen für einen oder mehrere Sicherheitsprinzipale kann man mit diesem Cmdlet in der angegebenen GPO abrufen. Get-GPPrefRegistryValue # Dieses Cmdlet zeigt eine oder mehrere Registrierungseinstellungen die unterhalb der Computerkonfiguration oder der Benutzerkonfiguration in einer GPO getätigt wurden an. Get-GPRegistryValue # Bei diesem Cmdlet werden eine oder mehrere registrierungsbasierte Richtlinieneinstellungen aus der Computerkonfiguration oder der Benutzerkonfiguration in einer GPO abgerufen. Get-GPResultantSetOfPolicy # Mit diesem Cmdlet kann man die Richtlinienergebnissatz-Informationen für einen Benutzer, einen Computer oder für beide in eine Datei im HTML- oder XML-Format ausgeben lassen. Get-GPStarterGPO # Ein bestimmtes oder alle Starter-GPOs werden mit diesem Cmdlet angezeigt. New-GPLink # Eine GPO wird auf eine Organisationseinheit (OU), einen AD-Standort oder auf die Domäne mit diesem Cmdlet verlinkt. New-GPStarterGPO # Mit diesem Cmdlet wird eine neue Starter-GPO erstellt. Remove-GPLink # Dieses Cmdlet entfernt eine GPO-Verklinkung von einer OU, einem AD-Standort oder von der Domäne. Remove-GPPrefRegistryValue # Eine oder mehrere Registrierungseinstellungen werden aus der Benutzerkonfiguration oder Computerkonfiguration innerhalb einer GPO mit diesem Cmdlet entfernt. Remove-GPRegistryValue # Um eine oder mehrere Registrierungsbasierte Richtlinieneinstellungen aus der Benutzerkonfiguration oder Computerkonfiguration innerhalb einer GPO zu entfernen, muss dazu dieses Cmdlet verwendet werden. Set-GPInheritance # Die Vererbung einer GPO kann mit diesem Cmdlet deaktiviert werden. Oder die Deaktivierung der Vererbung für eine angegebene OU oder Domäne lässt sich ebenfalls mit diesem Cmdlet aufheben. Set-GPLink # Die Eigenschaften einer GPO-Verknüpfung lassen sich mit diesem Cmdlet festlegen. Set-GPPermissions # Die Berechtigungen einer GPO oder für alle GPOs innerhalb einer Domäne lassen sich mit diesem Cmdlet bearbeiten. Set-GPPrefRegistryValue # Dieses Cmdlet konfiguriert eine Registrierungseinstellung unter der Benutzerkonfiguration oder der Computerkonfiguration in einer GPO. Set-GPRegistryValue # Mit diesem Cmdlet konfiguriert man eine oder mehrere registrierungsbasierte Richtlinieneinstellungen unter der Benutzerkonfiguration oder der Computerkonfiguration in einer GPO. Get-GPO -Name "Default Domain Policy" Get-GPO -Name "Default Domain Policy" | Get-GPOReport -ReportType Html | Out-File -Encoding utf8 -FilePath .\ddp_report.html # Kennwort muss Komplexitätsvoraussetzungen entsprechen? $xmlDoc = [xml](Get-GPO -Name "Default Domain Policy" | Get-GPOReport -ReportType Xml) $xmlDoc.GPO.Computer.ExtensionData.Extension.Account | ? Name -EQ PasswordComplexity | select -ExpandProperty SettingBoolean # Oder nativ in den Richtlinien lesen $gpo = Get-GPO -Name "Default Domain Policy" gci "\\lunar80\SYSVOL\abc.local\Policies\{$($gpo.Id)}\MACHINE\" #endregion #region Password Settings Objects New-ADFineGrainedPasswordPolicy -Name "DomainUsersPSO" -Precedence 500 -ComplexityEnabled $true -Description "The Domain Users Password Policy" -DisplayName "Domain Users PSO" -LockoutDuration "0.12:00:00" -LockoutObservationWindow "0.00:15:00" -LockoutThreshold 10 Set-ADFineGrainedPasswordPolicy -Identity ‘DomainUsersPSO’ -Replace @{‘msDS-PSOAppliesTo’=’CN=PSOTest, OU=AK, DC=abc, DC=local’} $allPSOUsers = Get-ADFineGrainedPasswordPolicySubject "DomainUsersPSO" | ? {$_.objectClass -eq "group"}| % {Get-ADGroupMember $_.Name -Recursive} | ? {$_.objectClass -eq "user"} | select -Unique $allUsers = Get-AdUser -Filter * $allUsersNotinPSO = Compare-Object -ReferenceObject $allUsers -DifferenceObject $allPSOUsers -PassThru | select Name $allUsersNotinPSO #endregion #region Active Directory Papierkorbs Get-Command -Noun ADOptionalFeature Get-ADOptionalFeature -Filter * Enable-ADOptionalFeature -Identity "Recycle Bin Feature" -Scope ForestOrConfigurationSet -Target "abc.local" Get-ADObject -Filter {name -like "Inge*"} –IncludeDeletedObjects Get-ADObject -Filter {name -like "Inge*" -and Deleted -eq $true} –IncludeDeletedObjects | Restore-ADObject #endregion #region Active Directory-Verwaltungscenter # Siehe "Windows PowerShell-Verlauf History" "$env:windir\system32\dsac.exe" # siehe auch: https://technet.microsoft.com/de-de/library/jj574144(v=ws.11).aspx #endregion #region Active Directory Standorten Get-Command "*ADReplication*" -Module ActiveDirectory New-ADReplicationSite -Name "Würzburg" $Schedule = New-Object -TypeName System.DirectoryServices.ActiveDirectory.ActiveDirectorySchedule $Schedule.ResetSchedule() $Schedule.SetDailySchedule("Twenty","Zero","TwentyTwo","Thirty"); New-ADReplicationSite -Name "München" -ReplicationSchedule $schedule New-ADReplicationSiteLink -Name "Würzburg-München" -SitesIncluded Würzburg, München -Cost 100 -ReplicationFrequencyInMinutes 15 -InterSiteTransportProtocol IP New-ADReplicationSubnet -Name "192.168.50.0/24" -Site (Get-ADReplicationSite -Identity "Würzburg") New-ADReplicationSubnet -Name "192.168.51.0/24" -Site (Get-ADReplicationSite -Identity "München") Get-ADReplicationSite -Filter * Get-ADReplicationSiteLink -Filter * Get-ADReplicationSubnet -Filter * ## Alle DC-Server an einem Standort $serverContainerDN = “CN=Servers, CN=Default-First-Site-Name, CN=Sites, CN=Configuration, DC=abc, DC=local” Get-ADObject -SearchBase $serverContainerDN -SearchScope OneLevel -Filter "ObjectClass -eq 'server'" -Properties “DNSHostName”, “Description” | Select Name, DNSHostName, Description # Get replication metadata for the attributes of a group Get-ADReplicationAttributeMetadata -Object "CN=Domänen-Admins, CN=Users, DC=abc, DC=local" -Server localhost -ShowAllLinkedValues # Get filtered replication metadata for all groups Get-ADObject -Filter 'objectclass -eq "group"' | Get-ADReplicationAttributeMetadata -Server localhost | Where-Object {$_.LastOriginatingChangeTime -like "*2017*"} | Format-Table object Get-ADReplicationConnection -Filter * Get-ADReplicationFailure -Target localhost #endregion #region Zeigt vereinfacht ob die Rechte-Vererbung aktiviert ist oder nicht: $result = gci -Path 'C:\Program Files' -Recurse -Force -Directory -ErrorAction SilentlyContinue | % { $acl = $_.FullName | Get-Acl [PSCustomObject]@{ IsInherited = $acl.Access[0].IsInherited; # ACHTUNG !!!! Name = $_.Name; FullName = $_.FullName; DeleteMe = $false; AccessToString = $acl.AccessToString; } } $result | % { if($_.IsInherited) { $parenPath = Split-Path -Path $_.FullName -Parent $parent = $result | ? { $_.FullName -eq $parenPath -and $_.DeleteMe -eq $false} if($parent.IsInherited) { $_.DeleteMe = $true } } } $result | Out-GridView $result | ? DeleteMe -EQ $false | Out-GridView #endregion #endregion #region Microsoft SQL Server Set-Location -Path 'C:\Program Files\Microsoft SQL Server\MSSQL12.SS2014\MSSQL' Get-Service MSSQLSERVER, SQLSERVERAGENT | Start-Service Import-Module -Name SqlServer # früher SQLPS Get-Command -Module SqlServer Get-ChildItem SQLSERVER:\SQL\AK4GFU\DEFAULT\Databases\AdventureWorks2014\Tables\Person.Person Invoke-Sqlcmd -Database AdventureWorks2014 -Query "SELECT TOP 10 * FROM Person.Person" #endregion #region TIPPS, TRICKS und BEISPIELE #region BASICS: Datum & Zeit #region Eine Dauer von einem Datum subtrahieren, um ein Vergangenheits-Datum zu berechnen $dauer = New-TimeSpan -Days 100 -Hours 31 -Minutes 12 $dauer (Get-Date).Subtract($dauer) #endregion #endregion #region PowerShell #region Neuerungen der PowerShell 5.0 # Alle Details zur 5.0 Version unter: Get-Help about_Windows_PowerShell_5.0 -ShowWindow Start-Process http://msdn.microsoft.com/de-de/powershell/scripting/whats-new/what-s-new-in-windows-powershell-50 #region Get-ItemPropertyValue #NEU: Get-ItemPropertyValue #FRÜHER: (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase).ApplicationBase #JETZT: Get-ItemPropertyValue -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase #endregion #region Einfache String-Operationen "Hallo Welt" | ConvertFrom-String "Hallo Welt" | ConvertFrom-String -Delimiter "ll" "Hallo Welt" | ConvertFrom-String -PropertyNames FirstWord, SecondWord "Lee Holmes", "Steve Lee", "Jeffrey Snover" | Convert-String -Example "Bill Gates=Gates, B.","John Smith=Smith, J." "Hallo Welt" | Format-Hex #endregion #region ZIP-Archive # #Test-Daten erzeugen # New-Item -Path C:\temp\ZipMich -ItemType Directory -Force 1..1MB -join ";" | Set-Content -Path "C:\temp\ZipMich\LogFile1.txt" -Force 1..1MB -join ";" | Set-Content -Path "C:\temp\ZipMich\LogFile2.txt" -Force # # Compress-Archive # "C:\temp\ZipMich" | Compress-Archive -DestinationPath C:\temp\ZipMich.zip -CompressionLevel Optimal -Force Get-Help Compress-Archive -ShowWindow # # Expand-Archive # "C:\temp\ZipMich.zip" | Expand-Archive -DestinationPath C:\temp\Backup -Force Get-Help Expand-Archive -Full #endregion #region Software-Installation Set-ExecutionPolicy -ExecutionPolicy AllSigned Get-Command -Module PowerShellGet, PackageManagement Find-Package | Out-GridView Install-Package -Name AKPT -Force Get-Module -ListAvailable Get-Command * -Module AKPT Get-AKAbout Uninstall-Package -Name AKPT Register-PSRepository -Name "myNuGetSource" –SourceLocation "https://www.myget.org/F/powershellgetdemo/api/v2" -PublishLocation "https://www.myget.org/F/powershellgetdemo/api/v2/Packages" -InstallationPolicy Trusted Get-PSRepository Unregister-PSRepository -Name "myNuGetSource" #endregion #region Kryptographie Get-Command -Module Microsoft.PowerShell.Security $MyCertInf = @" [Version] Signature = "$Windows NT$" [Strings] szOID_ENHANCED_KEY_USAGE = "2.5.29.37" szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1" [NewRequest] Subject = "cn=me@example.com" MachineKeySet = false KeyLength = 2048 KeySpec = AT_KEYEXCHANGE HashAlgorithm = Sha1 Exportable = true RequestType = Cert KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE" ValidityPeriod = "Years" ValidityPeriodUnits = "1000" [Extensions] 2.5.29.37="{text}1.3.6.1.4.1.311.80.1" "@ Set-Content -Path C:\temp\MyCert.inf -Value $MyCertInf CertReq -new C:\temp\MyCert.inf C:\temp\MyCert.cer $cert = gci Cert:\CurrentUser\My | ? Subject -EQ "cn=me@example.com" $crypt = "Hallo Welt" | Protect-CmsMessage -To $cert Unprotect-CmsMessage -Content $crypt -To $cert #endregion #region OOP Get-Help about_Classes -ShowWindow enum Farbe { Blau Grün Rot } $meineFarbe = [Farbe]::Grün $meineFarbe class Auto { [Farbe]$Farbe $PS } $meinAuto = New-Object -TypeName Auto $meinAuto.Farbe = [Farbe]::Grün $meinAuto.PS = 100 $meinAuto | Get-Member #endregion #region Weitere neue CmdLetds Set-Clipboard -Value "Hallo Köln!" Get-Clipboard Clear-RecycleBin -DriveLetter c: -Confirm:$false New-TemporaryFile New-Guid # symbolischer Verknüpfungen New-Item -ItemType SymbolicLink -Name MySymLinkDir -Target $pshome # -Depth 2 Get-ChildItem c:\ -Recurse -Depth 2 -Force #endregion #region DataCenter Abstraction Layer (DAL) <# Mit dieser Technologie können Sie direkt auf bestimmte Netzwerkkomponenten wie Switches und Router zugreifen. Dazu muss die Hardware diese Technik aber auch unterstützen. In diesem Bereich spielen vor allem Cisco und Huawei eine wichtige Rolle. #> $Session = New-CimSession -ComputerName "NetworkSwitch08" Get-NetworkSwitchFeature -CimSession $Session <# Name IsEnabled InstanceID PSComputerName ---- --------- ---------- -------------- SSH True Contoso:Feature:2 10.19.26.49 Tacacs True Contoso:Feature:3 10.19.26.49 BGP False Contoso:Feature:4 10.19.26.49 VLAN True Contoso:Feature:5 10.19.26.49 LACP True Contoso:Feature:6 10.19.26.49 DHCP False Contoso:Feature:7 10.19.26.49 LLDP True Contoso:Feature:8 10.19.26.49 #> Get-Help Get-NetworkSwitchFeature -Full Get-Command -Module NetworkSwitchManager | Out-GridView #endregion #region Open Data Protocol <# Das Open Data Protocol, kurz OData ist ein von Microsoft veröffentlichtes HTTP-basiertes Protokoll für den Datenzugriff zwischen kompatiblen Softwaresystemen. Aufbauend auf älteren Protokollen wie ODBC und JDBC kann OData u.a. innerhalb von Cloud-Diensten (Azure), MySQL, Java und Rails eingebunden werden und ist in der Lage, in der Client-Server-Kommunikation eine einheitliche Semantik für den Datenaustausch zur Verfügung zu stellen. #> Export-ODataEndpointProxy -Uri 'http://services.odata.org/v3/(S(snyobsk1hhutkb2yulwldgf1))/odata/odata.svc' ` -MetadataUri 'http://services.odata.org/v3/(S(snyobsk1hhutkb2yulwldgf1))/odata/odata.svc/$metadata' ` -AllowUnsecureConnection ` -OutputModule C:\Temp\GeneratedScript.psm1 ` -ResourceNameMapping @{Products = 'Merchandise'} #endregion #region Optimierte Unterstützung für'Desired State Configuration' (DSC) <# Weitere Neuerungen in der PowerShell betreffen die mit der PowerShell 4.0 eingeführte Technologie Desired State Configuration (DSC). Hauptsächlich gibt es neue Optionen um festzulegen auf wievielen Computern gleichzeitig die Änderungen implementiert werden sollen. Mit dem Modul 'PowerShellGet' können Sie DSC-Ressourcen in der 'PowerShell Resource Gallery' nutzen, installieren oder hochladen. #> #endregion #endregion #region Escape characters, Delimiters and Quotes http://ss64.com/ps/syntax-esc.html "Hallo `n Köln!" # z.B. #endregion #region Konsolen-Ein-/Ausgabe protokollieren Start-Transcript -Path C:\Temp\PowerShellConsole.log Get-Process | Stop-Process -Force -WhatIf Remove-Item c:\ -Recurse -Force -WhatIf Stop-Transcript Get-Content -Path C:\Temp\PowerShellConsole.log #endregion #region Wartezeit visualisieren for ($i = 1; $i -le 100; $i++) { [System.Threading.Thread]::Sleep(100) Write-Progress -Activity "Bitte warten" -PercentComplete $i if($i -ge 20) { Write-Progress -Activity "Bitte warten" -PercentComplete $i -Status "Gleich geschaft..." } } #endregion #region max. Anzeige von Enumerationen (-1 ohne Grenze, Default: 4) Get-Command -Name ForEach-Object | select -First 1 | fl * # Siehe Eigenschaft: Parameters $FormatEnumerationLimit = 4 Get-Command -Name ForEach-Object | select -First 1 | fl * # Siehe Eigenschaft: Parameters #endregion #region PowerShell-Transaktion (*-Transaction) Get-Command -Noun Transaction -Module Microsoft.PowerShell.* # Gilt nur für CmdLets die den Parameter UseTransaction besitzen Get-Help * -Parameter UseTransaction # # BEISPIELE # Set-Location -Path hkcu:\software Start-Transaction New-Item _ABC -UseTransaction New-ItemProperty -Path _ABC -name Heute -value (Get-Date) -UseTransaction Complete-Transaction Get-ItemProperty -Path _ABC Remove-Item -Path _ABC -Force Start-Transaction New-Item _ABC -UseTransaction New-ItemProperty -Path _ABC -name Heute -value (Get-Date) -UseTransaction Undo-Transaction Get-ItemProperty -Path _ABC #endregion #region Job's # Lang anhaltene Aufgaben in Jobs auslagern und Session schließen Start-Job -Name MyJob -ScriptBlock {[System.Threading.Thread]::Sleep(2000); Get-Process} Get-Job Receive-Job -Name MyJob Stop-Job -Name MyJob Wait-Job -Name MyJob Remove-Job -Name MyJob #endregion #region ScriptBlock-Code in eine EXE kompelieren Set-Location C:\temp Remove-Item .\start.* -Force $csharpCode = @" using System; using System.Diagnostics; namespace WindowsFormsApplication1 { static class Program { [STAThread] static void Main() { var filename = "PowerShell.exe"; var parameter = "-NoExit -Command \"& {Write-Host -ForegroundColor Yellow -Object 'Hallo Kööln!'}\""; Process.Start(filename, parameter); } } } "@ Set-Content start.cs -Force -Value $csharpCode C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /target:exe /out:start.exe start.cs #https://msdn.microsoft.com/en-us/library/78f4aasd.aspx .\start.exe # Testen... #endregion #region Beep StarWars [console]::beep(440,500) [console]::beep(440,500) [console]::beep(440,500) [console]::beep(349,350) [console]::beep(523,150) [console]::beep(440,500) [console]::beep(349,350) [console]::beep(523,150) [console]::beep(440,1000) [console]::beep(659,500) [console]::beep(659,500) [console]::beep(659,500) [console]::beep(698,350) [console]::beep(523,150) [console]::beep(415,500) [console]::beep(349,350) [console]::beep(523,150) [console]::beep(440,1000) #endregion #region Die Anzahl von Gruppen-Elementen bestimmen Get-ChildItem -Path C:\Windows\System32 -File -Force | Group-Object -Property Extension -NoElement | ? Count -gt 1 | Sort-Object -Property Count -Descending #endregion #region Eine Anzahl an Sekunden warten Start-Sleep -Seconds 3 #endregion #region Eine eindeutige Id erstellen # z.B. für Dateinamen, Primärschlüssel, ... New-Guid | select -ExpandProperty Guid #endregion #endregion #region CmdLet Beispiele #region CmdLet: Get-EuroExchangeRate function Get-EuroExchangeRate { <# .DESCRIPTION Zeigt und rechnet Euros in Nicht-Euro-Währung um. .PARAMETER Currency Die Ziel-Währung in die Euro's umgerechnet werden soll .PARAMETER Value Der umzurechnende Euro-Betrag. .PARAMETER ListCurrencys Listet alle möglichen Nicht-Euro-Währungen auf. .EXAMPLE Get-EuroExchangeRate -Currency usd .EXAMPLE "USD", "CAD" | Get-EuroExchangeRate -Value 100 .EXAMPLE "USD", "CAD" | Get-EuroExchangeRate -Value 100 | ConvertTo-Html .EXAMPLE Get-EuroExchangeRate -ListCurrencys .NOTES Folgende Aufrufe dürfen nicht laufen: Get-EuroExchangeRate -ListCurrencys -Currency usd #> [CmdletBinding()] Param ([Parameter(Mandatory=$true, ValueFromPipeLine=$True, Position=0, ParameterSetName="rechnen")] [string]$Currency, [Parameter(Position=1, ParameterSetName="rechnen")] [PSDefaultValue(Help = '1')] [int]$Value = 1, [Parameter(Position=0, ParameterSetName="anzeige")] [Switch] [bool]$ListCurrencys = $false ) Begin { [xml]$doc = New-Object Xml $doc.Load("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml") $cubes = $doc.Envelope.Cube.Cube.Cube if($ListCurrencys) { return new-object PSObject -Property @{"Currency" = ($cubes).currency} } } Process { if($ListCurrencys) { return } if($cubes.currency -contains $Currency) { [decimal]$rate = ($cubes | where currency -eq $Currency).rate return new-object PSObject -Property @{ "Currency" = $Currency.ToUpper(); "EUR" = $Value; "ExchangeRate" = $rate * $Value} } else { Write-Warning -Message "Das Währungssymbol '$Currency' wurde nicht gefunden!" } } } #endregion #region CmdLet: Get-News function Get-News { <# .Synopsis Zeigt RSS-Feeds an. .DESCRIPTION Zeigt ATOM Version 1.0 RRS-Feeds aus dem Internet oder Dateisystem an. .EXAMPLE Get-News -Uri http://rss.golem.de/rss.php?feed=ATOM1.0 Liefert alle RSS-News-Feed von Golem.de. .EXAMPLE Get-News -Uri http://rss.golem.de/rss.php?feed=ATOM1.0 -First 3 .EXAMPLE "http://www.heise.de/newsticker/heise-top-atom.xml", "http://rss.golem.de/rss.php?feed=ATOM1.0", "http://rss.golem.de/rss.php?tp=wirtschaft&feed=ATOM1.0" | Get-News -First 3 .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" | ft .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" | where Titel -Like "E*" | ft .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" | Out-GridView .EXAMPLE Get-News -Uri "http://rss.golem.de/rss.php?feed=ATOM1.0" -First 2 -OpenLinkInBrowser #> Param ( [Parameter( Mandatory = $true, ValueFromPipeLine = $true)] [string] $Uri, [uint32] $First = [System.UInt32]::MaxValue, [switch] [bool] $OpenLinkInBrowser = $false ) Begin # Zum Beginn 1x { $enUS = New-Object -TypeName System.Globalization.CultureInfo -ArgumentList "en-US" $xmlDokument = New-Object -TypeName System.Xml.XmlDocument } Process # Je Objekt was über die Pip kommt { $FirstTemp = $First $xmlDokument.Load($Uri) foreach ($item in $xmlDokument.feed.entry) { if ($FirstTemp -gt 0) { $FirstTemp-- $link = $item.link.href if($OpenLinkInBrowser) { [System.Diagnostics.Process]::Start($link) continue } $title = $item.title.InnerText $published = [datetime]::Parse($item.published, $enUS) $author = $item.author.name $summery = $item.summary.InnerText $result = @{"Titel"=$title; "StandUTC"=$published; "Autor"=$author; "Link"=$link; "Beschreibung"=$summery} New-Object psobject -Property $result | Select-Object Titel, StandUTC, Autor, Link, Beschreibung } else { break } } } End # Zum Ende 1x { } } #endregion #endregion #region Diagnose & Debugging #region Die Dauer einer Ausführung messen Measure-Command -Expression {gci C:\Users -File -Force -Recurse -ea SilentlyContinue} #endregion #endregion #region Windows PowerShell ISE #region Eigene Snippets für die ISE erstellen (STRG + J) New-Item -Path "$env:USERPROFILE\Documents\WindowsPowerShell\Snippets\" -Force -ItemType Directory Set-Content -Path "$env:USERPROFILE\Documents\WindowsPowerShell\Snippets\Comment-BasedHelp.snippets.ps1xml" -Force -Value @" <?xml version='1.0' encoding='utf-8' ?> <Snippets xmlns='http://schemas.microsoft.com/PowerShell/Snippets'> <Snippet Version='1.0.0'> <Header> <Title>Comment-BasedHelp</Title> <Description>A template for comment-based help.</Description> <Author /> <SnippetTypes> <SnippetType>Expansion</SnippetType> </SnippetTypes> </Header> <Code> <Script Language='PowerShell' CaretOffset='0'><![CDATA[ <# .SYNOPSIS .DESCRIPTION .PARAMETER <Parameter-Name> .INPUTS .OUTPUTS .EXAMPLE .LINK #> ]]></Script> </Code> </Snippet> </Snippets> "@ # s. STRG + J #endregion #endregion #region Windows #region BitLocker-CmdLet's Get-Command -Module BitLocker #endregion #region ADS # Group Policy Cmdlets in Windows PowerShell # https://technet.microsoft.com/en-us/library/ee461027.aspx # Managing Group Policy with PowerShell # http://www.powershellmagazine.com/2012/05/14/managing-group-policy-with-powershell/ # Use PowerShell to Import Group Policy Objects # http://blogs.technet.com/b/heyscriptingguy/archive/2014/01/05/use-powershell-to-import-group-policy-objects.aspx # ADSI Scripting with Windows PowerShell # http://blogs.msdn.com/b/arulk/archive/2006/07/25/678137.aspx # https://technet.microsoft.com/en-us/magazine/2007.06.powershell.aspx $objOU = [ADSI]"LDAP://localhost:389/ou=HR,dc=NA,dc=fabrikam,dc=com" $objGroup = $objOU.Create("group", "cn=Atl-Users") $objGroup.Put("sAMAccountName", "Atl-Users") # Festlegenn (put/get) $objGroup.SetInfo() # Übernehmen # Active Directory Recycle Bin Step-by-Step Guide # https://technet.microsoft.com/en-us/library/dd392261(v=ws.10).aspx # PowerShell and Active Directory Recycle Bin # http://blogs.technet.com/b/heyscriptingguy/archive/2014/09/29/powershell-and-active-directory-recycle-bin.aspx # http://blogs.msdn.com/b/dsadsi/archive/2009/08/26/restoring-object-from-the-active-directory-recycle-bin-using-ad-powershell.aspx $oDomain = Get-ADDomain $DeletedObjects = $oDomain.DeletedObjectsContainer Restore-ADObject # # ActiveDirectory-Modul # Get-Module -ListAvailable ActiveDirectory Start-Process 'https://technet.microsoft.com/de-de/library/dd378937(v=ws.10).aspx' #Active Directory Administration with Windows PowerShell # z.B.: Get-ADUser -Filter "Surname -like 'Ber*'" Get-ADUser -Filter "Surname -like 'Ber*'" -SearchBase "OU=IT,DC=contoso,DC=com" Get-ADUser -Filter "Surname -like 'Ber*'" -Properties * Get-ADUser -Filter "StreetAddress -eq 'Rosenweg 1'" Search-ADAccount -PasswordNeverExpires -UsersOnly Get-ADUser -Filter "StreetAddress -eq 'Marsstr. 3'"|Set-ADUser -StreetAddress "Rosenweg 1" Get-ADUser -Filter * -SearchBase "OU=Marketing,DC=contoso,DC=com" | Set-ADUser -Manager PHuber Get-ADComputer -Filter "Name -like 'Win81*'" Get-ADDomainController #endregion #region Ein MSI-Paket installieren $msi = "c:\7z920-x64.msi" $produkte = Get-WmiObject -Class Win32_Product -List "Installation läuft ...." $ergebnis = $produkte.Install($msi) "... Installation fertig mit dem Ergebnis {0}" -f $ergebnis.ReturnValue Get-WmiObject -Class Win32_Product | where Name -like "*7-zip*" | Get-Member # ReturnValue siehe http://msdn.microsoft.com/en-us/library/aa390890(v=vs.85).aspx #endregion #region CmdLet: Get-Product function Get-Product { <# .Synopsis Kurzbeschreibung .DESCRIPTION Lange Beschreibung .EXAMPLE Beispiel für die Verwendung dieses Cmdlets .EXAMPLE Ein weiteres Beispiel für die Verwendung dieses Cmdlets #> [CmdletBinding()] [OutputType([int])] Param ( # Hilfebeschreibung zu Param1 [Parameter(ValueFromPipeline=$true)] [string[]]$ComputerName = "." ) Begin { [datetime]$heute = Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0 Write-Debug -Message ("HEUTE: {0}" -f $heute) } Process { $produkte = Get-WmiObject -ComputerName $ComputerName -Class Win32_Product | Sort-Object -Property Name foreach ($item in $produkte) { if($item.Name -eq $null) {continue} $installDate = Get-Date -Year $item.InstallDate.Substring(0, 4) ` -Month $item.InstallDate.Substring(4, 2) ` -Day $item.InstallDate.Substring(6, 2) ` -Hour 0 -Minute 0 -Second 0 -Millisecond 0 $resultset = [ordered]@{ "Name" = $item.Name.Trim(); "Version" = $item.Version; "InstallDate" = $installDate; "DurationInDays"= ($heute - $installDate).TotalDays; "ComputerName" = $item.PSComputerName;} New-Object -TypeName psobject -Property $resultset } } } Get-Product -Debug | ft #Get-Product -ComputerName 192.168.50.50 | ft #Get-Product -ComputerName 192.168.50.50, "." #".", 192.168.50.50 | Get-Product #Get-Product | Out-GridView #Get-Product | where Name -Like *office* #Get-Product | Out-File C:\Temp\produkte.txt #Get-Help Get-Product -ShowWindow #endregion #region Control-Panel's anzeigen Get-ControlPanelItem | sort Name Get-ControlPanelItem -Name "Windows To Go" | Show-ControlPanelItem #endregion #endregion #region Office #region Auf Outlook zugreifen # Outlook muss installiert sein # zzgl. Office PIA bis Office 2010 AB in Office-Installation # ALTERNATIVE: Exchange PowerShell-Modul installieren $outlook = new-object -ComObject Outlook.Application $namespace = $outlook.GetNamespace("MAPI") $inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox) Write-Host "ORDNER:" $inbox.Name foreach($item in $inbox.Items) { Write-Host " SUBJECT:" $item.Subject } #endregion #endregion #region Netzwerk #region Netzwerk-Freigabe erstellen New-SmbShare -Name Data -Path C:\Windows Remove-SmbShare -Name Data -Confirm:$false #endregion #region Netzwerk-Adapter neustarten Get-NetAdapter -IncludeHidden # Übersicht Restart-NetAdapter -Name WLAN # Einen Restart-NetAdapter -Name * -PassThru -IncludeHidden # Alle #endregion #endregion #region IO, FileSystem, OneDrive, Database, Web #region Eine temporäre Datei erstellen $temp = New-TemporaryFile $temp #endregion #region Alle temporären Dateien löschen $path = Join-Path -Path $env:USERPROFILE -ChildPath "AppData\Local\Temp\" Remove-Item -Path $path -Recurse -Force -ea SilentlyContinue #endregion #region Hash einer Datei berechnen # ... um identische Dateien zu finden, oder der Unversehrtheit z.B. beim übertragen zu gewehrleisten Get-FileHash -Path C:\Windows\explorer.exe #endregion #region Dateien in ein Archiv kompremieren Get-ChildItem -Path C:\windows\Logs -File -Force -Recurse -ea SilentlyContinue | ? Extension -EQ ".log" | Compress-Archive -DestinationPath C:\temp\logs.zip -CompressionLevel Optimal -ErrorAction SilentlyContinue #endregion #region Den tatsächlien Ort von Spezial-Ordner lokalisieren [Environment]::GetFolderPath([System.Environment+SpecialFolder]::DesktopDirectory); # RICHTIG "$env:USERPROFILE\Desktop" # falsch #endregion #region .NET: Datei beschreiben $datei = New-Item -Path C:\temp\meinlog3.txt -ItemType File -Force $writer = $datei.CreateText() # Für Byte-Daten .OpenWrite() for ($i = 1; $i -lt 99; $i++) { $logText = ("{0:yyyyMMddTHHmmss.ff}: Meldung Nr. {1}" -f (Get-Date), $i) $writer.WriteLine($logText) } $writer.Close() Get-Content -Path C:\temp\meinlog3.txt | Out-GridView #endregion #region .NET: Datei lesen $datei = Get-Item -Path C:\Windows\Logs\DirectX.log # | Get-Member $reader = $datei.OpenText() # | Get-Member # Siehe auch .OpenRead() für Byte-Datei while (-not $reader.EndOfStream) { $zeile = $reader.ReadLine() $zeile } $reader.Close() #endregion #region CmdLet: Get-BigFile function Get-BigFile { <# .SYNOPSIS Zeigt eine Übersicht von großen Dateien und deren Besitzer. .EXAMPLE Get-BigFile -Path C:\ -GE 100MB .EXAMPLE "C:\Users", "C:\Program Files" | Get-BigFile -GE 100MB #> [CmdletBinding( HelpUri = 'http://www.gfu.net/')] [Alias("gbf")] [OutputType([PSCustomObject])] Param ( # Pfad an dem große Dateien gefunden werden sollen [Parameter(ValueFromPipeLine = $true)] [string] $Path = ".", # Eine Datei ist Groß wenn sie größer gleich diesem Wert ist [Parameter(Mandatory = $true)] [uint32] $GE = 10MB, [switch] [bool] $Recurse = $false ) Process { Get-ChildItem -Path $Path -Recurse:$Recurse -File -Force -ea SilentlyContinue | Where-Object -Property Length -GE -Value $GE | ForEach-Object -Process { [PSCustomObject]@{ Name = $_.Name; Length = $_.Length; Owner = $_ | Get-Acl -ea SilentlyContinue | select -exp Owner; LastAccessTime = $_.LastAccessTime; FullName = $_.FullName; } } } } New-Alias -Name gbf -Value Get-BigFile -Force #Get-Help Get-BigFile -ShowWindow #Show-Command Get-BigFile #Get-BigFile -Path c:\ -GE 100MB -Recurse #Get-BigFile -GE 100MB #"C:\Users", "C:\Program Files" | Get-BigFile -GE 100MB -Recurse | Out-GridView #endregion #region CmdLet: Get-OldFile function Get-OldFile { <# .SYNOPSIS Ermittelt alte Dateien. .DESCRIPTION Ermittelt alte Dateien nach Anzahl Tage. .INPUTS .OUTPUTS Liefert ein ein PSObject mit folgenden Eigenschaften..... .EXAMPLE Get-OldFile -Path C:\Windows -OlderThanDays 180 Alle alte Datei aus c:\windows die älter sind als 180 Tage. .EXAMPLE Get-OldFile -Path C:\Windows -OlderThanDays 180 -Recurse Alle alte Datei aus c:\windows und Unterordner die älter sind als 180 Tage. #> param( [Parameter(ParameterSetName = "Days", ValueFromPipeline = $true)] [Parameter(ParameterSetName = "DateTime", ValueFromPipeline = $true)] [ValidateScript({Test-Path $_})] [string]$Path = ".", # Gültige Werte für Tag sind 1 bis 4000 [Parameter(Mandatory = $true, ParameterSetName = "Days")] [ValidateRange(1, 4000)] [UInt32]$OlderThanDays, [Parameter(ParameterSetName = "Days")] [Parameter(ParameterSetName = "DateTime")] [switch] [bool]$Recurse, [Parameter(Mandatory = $true, ParameterSetName = "DateTime")] [ValidateScript({$_ -le (Get-Date)})] [datetime]$OlderThan ) begin { # Inizialisierungs-Code $lastAccessTime = $null switch ($psCmdLet.ParameterSetName) { 'Days' {$lastAccessTime = (Get-Date).AddDays($OlderThanDays * -1)} 'DateTime' {$lastAccessTime = $OlderThan} } } process { Get-ChildItem -Path $Path -Recurse:$Recurse -File -ErrorAction SilentlyContinue | Where-Object -Property LastAccessTime -lt $lastAccessTime | ForEach-Object -Process { $now = Get-Date $owner = $_ | Get-Acl | Select-Object -ExpandProperty Owner $result = [ordered]@{ Name = $_.Name; AgeInDays = [Math]::Round(($now - $_.LastAccessTime).TotalDays, 2); Owner = $owner; LastAccessTime = $_.LastAccessTime; FullName = $_.FullName} New-Object PSObject -Property $result } } } #Get-Help Get-OldFile -ShowWindow #Show-Command Get-OldFile Get-OldFile -Path c:\ -Recurse -OlderThanDays 1200 | Out-GridView Get-OldFile -Path c:\ -Recurse -OlderThan "2013-12-31" | Out-GridView # # KOMPONENTENTEST # #Get-OldFiles -Path C:\Windows -OlderThanDays 180 -Recurse #Get-OldFiles -Path C:\Windows -OlderThanDays 180 | Out-GridView #Get-OldFiles -OlderThanDays 180 -Path C:\Windows -Recurse #Get-help Get-OldFiles -ShowWindow #Get-OldFiles -Path C:\Windows -OlderThanDays 180 -OlderThan (Get-Date).AddMonths(-50) #Get-OldFiles -Path C:\Windows -OlderThanDays 180 #Get-OldFiles -Path C:\Windows -OlderThan (Get-Date) #Get-Help Where-Object -Online #"c:\windows", "C:\windows\System32" | Get-OldFiles -OlderThanDays 180 #endregion #region CmdLet: Get-XFile (Kombination aus Get-OldFile und Get-BigFile) function Get-XFile { <# .SYNOPSIS Ermittelt alte und oder große Dateien. #> param( [Parameter(ParameterSetName = "Days", ValueFromPipeline = $true)] [Parameter(ParameterSetName = "DateTime", ValueFromPipeline = $true)] [ValidateScript({Test-Path $_})] [string]$Path, # Gültige Werte für Tag sind 1 bis 4000 [Parameter(ParameterSetName = "Days")] [ValidateRange(1, 4000)] [UInt32]$OlderThanDays, [Parameter(ParameterSetName = "DateTime")] [ValidateScript({$_ -le (Get-Date)})] [datetime]$OlderThan, # Eine Datei ist Groß wenn sie größer gleich diesem Wert ist [Parameter(ParameterSetName = "Days")] [Parameter(ParameterSetName = "DateTime")] [uint32] $LengthGE = 0, [Parameter(ParameterSetName = "Days")] [Parameter(ParameterSetName = "DateTime")] [switch] [bool]$AgeOrBig, [Parameter(ParameterSetName = "Days")] [Parameter(ParameterSetName = "DateTime")] [switch] [bool]$Recurse ) begin { # Inizialisierungs-Code $lastAccessTime = $null switch ($psCmdLet.ParameterSetName) { 'Days' {$lastAccessTime = (Get-Date).AddDays($OlderThanDays * -1)} 'DateTime' {$lastAccessTime = $OlderThan} } $filterScript = $null if($AgeOrBig) { $filterScript = {$_.LastAccessTime -lt $lastAccessTime -or $_.Length -ge $LengthGE } } else { $filterScript = {$_.LastAccessTime -lt $lastAccessTime -and $_.Length -ge $LengthGE } } } process { Get-ChildItem -Path $Path -Recurse:$Recurse -File -ErrorAction SilentlyContinue | Where-Object -FilterScript $filterScript | ForEach-Object -Process { $now = Get-Date $owner = $_ | Get-Acl | Select-Object -ExpandProperty Owner $result = [ordered]@{ Name = $_.Name; Length = $_.Length; AgeInDays = [Math]::Round(($now - $_.LastAccessTime).TotalDays, 2); Owner = $owner; LastAccessTime = $_.LastAccessTime; FullName = $_.FullName} New-Object PSObject -Property $result } } } Get-Help -Name Get-XFile -ShowWindow Show-Command -Name Get-XFile Get-XFile -Path c:\ -Recurse -OlderThanDays 300 | Out-GridView Get-XFile -Path c:\ -Recurse -LengthGE 10MB | Out-GridView Get-XFile -Path c:\ -Recurse -OlderThanDays 300 -LengthGE 10MB | Out-GridView Get-XFile -Path c:\ -Recurse -OlderThanDays 300 -LengthGE 10MB -AgeOrBig | Out-GridView #endregion #region CmdLet: Test-ReadAccess function Test-ReadAccess { <# #about_Comment_Based_Help .DESCRIPTION Prüft ob Lese-Rechte vorliegen .EXAMPLE Test-ReadAccess c:\test.html .EXAMPLE Test-ReadAccess c:\geheim.txt .EXAMPLE "c:\test.html" | Test-ReadAccess .EXAMPLE "c:\geheim.txt" | Test-ReadAccess .EXAMPLE ls c:\*.* -Force | Test-ReadAccess .INPUTS Hinweise zur Eingabe .OUTPUTS Hinweise zur Ausgabe .NOTES Siehe auch Get-Acl #> [CmdletBinding()] Param ([Parameter(Mandatory=$true, ValueFromPipeLine=$True)] [string]$Path ) Process { try { Get-Content $Path -ErrorAction Stop -ReadCount 1 | Out-Null return new-object PSObject -Property @{ "Path" = $Path; "IsReadAccess" = $true} } catch [UnauthorizedAccessException] { return new-object PSObject -Property @{ "Path" = $Path; "IsReadAccess" = $false} } } } #endregion #region .NET: Datenbank zugriff (ADO.NET) # # 1. Connection-Objekt erstellen # # Microsoft SQL Server => System.Data.SqlClient # Diverse DBMS => System.Data.Odbc ODER System.Data.OleDb # MySql => Siehe Hersteller bzgl. .NET Treiber # PostgreSQL => Siehe Hersteller bzgl. .NET Treiber # Orcale => Siehe Hersteller bzgl. .NET Treiber # # Connection-String siehe http://www.connectionstrings.com # $conn = New-Object -TypeName System.Data.SqlClient.SqlConnection $conn.ConnectionString = "Server=.; Database=AdventureWorks2014; Trusted_Connection=True;" $conn.Open() #$ta = $conn.BeginTransaction() # # 2. Command-Objekt erstellen # $cmd = New-Object -TypeName System.Data.SqlClient.SqlCommand $cmd.Connection = $conn $cmd.CommandText = "SELECT * FROM Person.Person" # # 3.1 Nutzen (z.B. Reader-Objekt) # $reader = $cmd.ExecuteReader() while ($reader.Read()) { "VN: {0} NN: {1} BusinessEntityID {2}" -f $reader["FirstName"], $reader["LastName"], $reader["BusinessEntityID"] } #$ta.Commit() $conn.Close() # # 3.2 Nutzen (z.B. Datensatz ändern) # $conn.Open() $cmd.CommandText = "UPDATE Person.Person SET LastName='MÜLLLER' WHERE BusinessEntityID='hmmmmmm'" $ergebnis = $cmd.ExecuteNonQuery() "Betroffene Zeilen: {0}" -f $ergebnis $conn.Close() # # 3.3 Nutzen (z.B. analysieren) # $conn.Open() $cmd.CommandText = "SELECT COUNT(*) FROM Person.Person" $ergebnis = $cmd.ExecuteScalar() "In der Tabelle Person.Person sind {0} Datensätze enthalten" -f $ergebnis $conn.Close() #endregion #region .NET: Dateiauswahl (WinForms.CommonDialogs) $Dlg = New-Object System.Windows.Forms.OpenFileDialog $Dlg.Filter = "PowerShell-Skripten (*.ps1)|*.ps1|Text-Dateien (*.txt)|*.txt|Alle Dateien (*.*)|*.*" $Dlg.InitialDirectory = "C:\Temp" $DialogResult = $Dlg.ShowDialog() if ($DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { $Dlg.Filename } $Dlg = New-Object System.Windows.Forms.FolderBrowserDialog $Dlg.Description = "Bitte Ordner für das Archivieren auswählen" $Dlg.RootFolder = [System.Environment+SpecialFolder]::Desktop $Dlg.ShowNewFolderButton = $true $DialogResult = $Dlg.ShowDialog() if ($DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { $Dlg.SelectedPath } # SaveAsDialog, ColorPicker, FontPicker #endregion #region HTTP-Kommunikation (Web-Request) $webrequest = Invoke-WebRequest -Uri "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" $xml = [xml]$webrequest.Content $xml.Envelope.Cube.Cube.Cube | ? currency -eq "USD" #endregion #region Proxy-Server $webProxy = New-Object System.Net.WebProxy("proxy.gewkoelnag.de:8080", $true) $webProxy.Credentials = New-Object Net.NetworkCredential("user","password","domain.local") $netCred = New-Object System.Net.NetworkCredentials("user", "pwd", "domain"); $webClient = New-Object System.Net.WebClient #$webClient.Proxy = $webProxy $webClient.Credentials=$netCred $page = $webClient.DownloadString("http://intranet/content/de/index.php") #$webClient.Upload..... #endregion #region Bing-Images downloaden $ImageUrl = "http://www.bing.com/HPImageArchive.aspx?format=xml&idx=1&n=8&mkt=de-DE"; $response = Invoke-WebRequest -Uri $ImageUrl; $xmlDocument = [xml]$response.Content $xmlDocument.images.image | % { $uri = "http://www.bing.com$($_.url -replace "_1366x768.jpg", "_1920x1080.jpg")" $filename = "C:\temp\BingImage $($_.startdate) $($_.copyright.Replace('/', '; ')).jpg" Invoke-WebRequest -Uri $uri -OutFile $filename } #endregion #region Zugriff auf OneDrive Install-Module -Name OneDrive -Scope CurrentUser -AllowClobber -Force Start-Process https://apps.dev.microsoft.com/?referrer=https%3A%2F%2Fdev.onedrive.com#/appList $auth = Get-ODAuthentication -ClientID "00000000....." $accessToken = $auth.access_token # ODER Start-Process https://dev.onedrive.com/auth/msa_oauth.htm $accessToken = "EwAoA61DBAAUGCCXc..." Add-ODItem -LocalFile (Join-Path -Path $env:USERPROFILE -ChildPath "Desktop\PowerShell V.5.12.ps1") -Path "/Wissen/PowerShell" -AccessToken $accessToken #endregion #endregion #region .NET Framework, CLI #region using namespace-Anweisung (Require PS 5.0) using namespace System.Diagnostics; #endregion #endregion #region UserInterface, GUI #region Keyboard-Taste vom User abfragen $key = [console]::ReadKey($true) $key.KeyChar #endregion #region .NET: Dateiauswahl (WinForms.CommonDialogs) $Dlg = New-Object System.Windows.Forms.OpenFileDialog $Dlg.Filter = "PowerShell-Skripten (*.ps1)|*.ps1|Text-Dateien (*.txt)|*.txt|Alle Dateien (*.*)|*.*" $Dlg.InitialDirectory = "C:\Temp" $DialogResult = $Dlg.ShowDialog() if ($DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { $Dlg.Filename } $Dlg = New-Object System.Windows.Forms.FolderBrowserDialog $Dlg.Description = "Bitte Ordner für das Archivieren auswählen" $Dlg.RootFolder = [System.Environment+SpecialFolder]::Desktop $Dlg.ShowNewFolderButton = $true $DialogResult = $Dlg.ShowDialog() if ($DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { $Dlg.SelectedPath } # SaveAsDialog, ColorPicker, FontPicker #endregion #region .NET: Eingabefenster/InputBox (WinForms) function inputbox([System.String]$strPrompt="", [System.String]$strTitel="", [System.String]$strWert="") { $form="" $global:erg=$false $global:eingabe="" $farbe=0 $pruefen={ if ($eingabefeld.Text.Trim() -gt "") { $bttOK.Enabled=$true } else { $bttOK.Enabled=$false } } $farbe=[System.Drawing.Color]::FromArgb(255, 0, 0) $form=New-Object "System.Windows.Forms.Form" $form.TopMost = $true $form.Text=$strTitel $label=New-Object "System.Windows.Forms.Label" $label.Height=20 $label.Text=$strPrompt $label.Top=10 $label.Width=$form.width-10 $label.Left=5 $label.ForeColor=$farbe #Einabefeld erzeugen $eingabefeld=New-Object "System.Windows.Forms.Textbox" $eingabefeld.Height=20 $eingabefeld.Text=$strWert $eingabefeld.Top=$label.Top +$label.Height+5 $eingabefeld.Left=$label.Left $eingabefeld.TabIndex=0 #Buttons erstellen $bttOK= New-Object "System.Windows.Forms.Button" $bttOK.Text = "OK" $bttOK.Left=$label.Left $bttOK.Top=$eingabefeld.top + $eingabefeld.height + 10 $bttOK.Width=70 $bttOK.TabIndex=1 $bttAbbrechen= New-Object "System.Windows.Forms.Button" $bttAbbrechen.Text = "Abbrechen" $bttAbbrechen.Top=$bttOK.top $bttAbbrechen.Width=70 $bttAbbrechen.Left=$bttOK.left + $bttOK.width + 10 $bttAbbrechen.TabIndex=2 $farbe=[System.Drawing.Color]::FromArgb(255, 128, 0) $bttOK.BackColor=$farbe $bttAbbrechen.BackColor=$farbe $form.Backcolor=[System.Drawing.Color]::FromArgb(255, 255, 0) $form.Controls.Add($label) $form.Controls.Add($bttOK) $form.Controls.Add($bttAbbrechen) $form.Controls.Add($eingabefeld) $form.Height=$eingabefeld.top + $eingabefeld.height + 10 + $bttOK.height + $bttOK.top #Eventhandler erstellen $bttAbbrechen.Add_Click({ $global:erg=$false; $global:eingabe=""; $form.Close(); $form.Dispose(); }) $bttOK.Add_Click({ $global:erg=$true; $global:eingabe=$eingabefeld.Text; $form.Close(); $form.Dispose()}) $form.Add_Load({&$pruefen}) $eingabefeld.Add_TextChanged({&$pruefen}) $temp=$form.ShowDialog() #Rueckgabewert pruefen if ($global:erg -eq $true) { return $global:eingabe } else { return $false } } #Skriptinhalt #echo (getScriptName) $Erg=[reflection.assembly]::LoadWithPartialName("System.Windows.Forms") $Erg=[reflection.assembly]::LoadWithPartialName( "System.Drawing") echo (inputbox "Bitte Wert eingeben!" "Eingabe notwendig!" ) #endregion #region .NET: MessageBox (WinForms.CommonDialogs) #System.Windows.Forms.dll (Assembly aus dem GAC) laden $erg=[reflection.assembly]::LoadWithPartialName("System.Windows.Forms") [System.Windows.Forms.MessageBox]::Show("Hallo Welt!") if ([System.Windows.Forms.MessageBox]::Show( "Moechten Sie das Skript abbrechen?", ("PowerShell:" + $meinName), [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Question) ` -eq [System.Windows.Forms.DialogResult]::Yes) { echo "Abbruch durch den Benutzer ..." exit } else { #hier folgt weiterer Code echo "Skript wird fortgesetzt ..." } #[System.Windows.Forms.MessageBox]::Show("Fehler!","",0,16) #[System.Windows.Forms.MessageBox]::Show("Info!","",0,64) #[System.Windows.Forms.MessageBox]::Show("Warnung!","",0,48) #endregion #region .NET: 'Hallo Welt'-Fenster (WPF) function Start-WpfHalloWelt { Add-Type -AssemblyName PresentationFramework Add-Type -AssemblyName System [XML]$XAML = @" <Window x:Class="FSM.PS_WPF_Sample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="PS_WPF_Sample" Height="200" Width="300"> <Grid> <TextBox x:Name="PSText" Text="Hello World" HorizontalAlignment="Left" Margin="65,40,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="175"/> <Label x:Name="PSLabel" Content="Type in the box and click OK" HorizontalAlignment="Left" Margin="65,80,0,0" VerticalAlignment="Top" Width="175" BorderThickness="1"/> <Button x:Name="PSBtnOK" Content="OK" HorizontalAlignment="Left" Margin="65,130,0,0" VerticalAlignment="Top" Width="75"/> <Button x:Name="PSBtnExit" Content="Exit" HorizontalAlignment="Left" Margin="165,130,0,0" VerticalAlignment="Top" Width="75"/> </Grid> </Window> "@ $XAML.Window.RemoveAttribute("x:Class") $Reader = New-Object System.Xml.XmlNodeReader $XAML $Form = [Windows.Markup.XamlReader]::Load($Reader) $PSText = $Form.FindName('PSText') $PSLabel = $Form.FindName('PSLabel') $PSBtnOK = $Form.FindName('PSBtnOK') $PSBtnExit = $Form.FindName('PSBtnExit') $btnOKClick = {$PSLabel.Content = $PSText.Text} $btnExitClick = {$Form.Close()} $PSBtnOK.Add_Click($btnOKClick) $PSBtnExit.Add_Click($btnExitClick) $Form.ShowDialog() } Start-WpfHalloWelt #endregion #region .NET: Komplexe Fenster z.B. Uhr (WPF) function Start-WpfUhr { <# .SYSNOPSIS Displays a clock on the screen with date. .DESCRIPTION Displays a clock on the screen with date. .PARAMETER TimeColor Specify the color of the time display. .PARAMETER DateColor Specify the color of the date display. Default is White .EXAMPLE .\ClockWidget.ps1 Description ----------- Clock is displayed on screen .EXAMPLE .\ClockWidget.ps1 -TimeColor DarkRed -DateColor Gold Description ----------- Clock is displayed on screen with alternate colors .EXAMPLE .\ClockWidget.ps1 –TimeColor "#669999" –DateColor "#334C4C" Description ----------- Clock is displayed on screen with alternate colors as hex values #> Param ( [parameter()] [string]$TimeColor = "White", [parameter()] [string]$DateColor = "White" ) $Clockhash = [hashtable]::Synchronized(@{}) $Runspacehash = [hashtable]::Synchronized(@{}) $Runspacehash.host = $Host $Clockhash.TimeColor = $TimeColor $Clockhash.DateColor = $DateColor $Runspacehash.runspace = [RunspaceFactory]::CreateRunspace() $Runspacehash.runspace.ApartmentState = “STA” $Runspacehash.runspace.ThreadOptions = “ReuseThread” $Runspacehash.runspace.Open() $Runspacehash.psCmd = {Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase}.GetPowerShell() $Runspacehash.runspace.SessionStateProxy.SetVariable("Clockhash",$Clockhash) $Runspacehash.runspace.SessionStateProxy.SetVariable("Runspacehash",$Runspacehash) $Runspacehash.runspace.SessionStateProxy.SetVariable("TimeColor",$TimeColor) $Runspacehash.runspace.SessionStateProxy.SetVariable("DateColor",$DateColor) $Runspacehash.psCmd.Runspace = $Runspacehash.runspace $Runspacehash.Handle = $Runspacehash.psCmd.AddScript({ $Script:Update = { $day,$Month, $Day_n, $Year, $Time, $AMPM = (Get-Date -f "dddd,MMMM,dd,yyyy,HH:mm,tt") -Split ',' $Clockhash.time_txtbox.text = $Time.TrimStart("0") $Clockhash.day_txtbx.Text = $day $Clockhash.ampm_txtbx.text = $AMPM $Clockhash.day_n_txtbx.text = $Day_n $Clockhash.month_txtbx.text = $Month $Clockhash.year_txtbx.text = $year } [xml]$xaml = @" <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" WindowStyle = "None" WindowStartupLocation = "CenterScreen" SizeToContent = "WidthAndHeight" ShowInTaskbar = "False" ResizeMode = "NoResize" Title = "Weather" AllowsTransparency = "True" Background = "Transparent" Opacity = "1" Topmost = "True"> <Grid x:Name = "Grid" Background = "Transparent"> <TextBlock x:Name = "time_txtbox" FontSize = "72" Foreground = "$($Clockhash.TimeColor)" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0,-26,0,0"> <TextBlock.Effect> <DropShadowEffect Color = "Black" ShadowDepth = "1" BlurRadius = "5" /> </TextBlock.Effect> </TextBlock> <TextBlock x:Name = "ampm_txtbx" FontSize= "20" Foreground = "$($Clockhash.TimeColor)" Margin = "133,0,0,0" HorizontalAlignment="Left"> <TextBlock.Effect> <DropShadowEffect Color = "Black" ShadowDepth = "1" BlurRadius = "2" /> </TextBlock.Effect> </TextBlock> <TextBlock x:Name = "day_n_txtbx" FontSize= "38" Foreground = "$($Clockhash.DateColor)" Margin="5,42,0,0" HorizontalAlignment="Left"> <TextBlock.Effect> <DropShadowEffect Color = "Black" ShadowDepth = "1" BlurRadius = "2" /> </TextBlock.Effect> </TextBlock> <TextBlock x:Name = "month_txtbx" FontSize= "20" Foreground = "$($Clockhash.DateColor)" Margin="54,48,0,0" HorizontalAlignment="Left"> <TextBlock.Effect> <DropShadowEffect Color = "Black" ShadowDepth = "1" BlurRadius = "2" /> </TextBlock.Effect> </TextBlock> <TextBlock x:Name = "day_txtbx" FontSize= "15" Foreground = "$($Clockhash.DateColor)" Margin="54,68,0,0" HorizontalAlignment="Left"> <TextBlock.Effect> <DropShadowEffect Color = "Black" ShadowDepth = "1" BlurRadius = "2" /> </TextBlock.Effect> </TextBlock> <TextBlock x:Name = "year_txtbx" FontSize= "38" Foreground = "$($Clockhash.DateColor)" Margin="0,42,0,0" HorizontalAlignment="Left"> <TextBlock.Effect> <DropShadowEffect Color = "Black" ShadowDepth = "1" BlurRadius = "2" /> </TextBlock.Effect> </TextBlock> </Grid> </Window> "@ $reader=(New-Object System.Xml.XmlNodeReader $xaml) $Clockhash.Window=[Windows.Markup.XamlReader]::Load( $reader ) $Clockhash.time_txtbox = $Clockhash.window.FindName("time_txtbox") $Clockhash.ampm_txtbx = $Clockhash.Window.FindName("ampm_txtbx") $Clockhash.day_n_txtbx = $Clockhash.Window.FindName("day_n_txtbx") $Clockhash.month_txtbx = $Clockhash.Window.FindName("month_txtbx") $Clockhash.year_txtbx = $Clockhash.Window.FindName("year_txtbx") $Clockhash.day_txtbx = $Clockhash.Window.FindName("day_txtbx") #Timer Event $Clockhash.Window.Add_SourceInitialized({ #Create Timer object Write-Verbose "Creating timer object" $Script:timer = new-object System.Windows.Threading.DispatcherTimer #Fire off every 1 minutes Write-Verbose "Adding 1 minute interval to timer object" $timer.Interval = [TimeSpan]"0:0:1.00" #Add event per tick Write-Verbose "Adding Tick Event to timer object" $timer.Add_Tick({ $Update.Invoke() [Windows.Input.InputEventHandler]{ $Clockhash.Window.UpdateLayout() } }) #Start timer Write-Verbose "Starting Timer" $timer.Start() If (-NOT $timer.IsEnabled) { $Clockhash.Window.Close() } }) $Clockhash.Window.Add_Closed({ $timer.Stop() $Runspacehash.PowerShell.Dispose() [gc]::Collect() [gc]::WaitForPendingFinalizers() }) $Clockhash.month_txtbx.Add_SizeChanged({ [int]$clockhash.length = [math]::Round(($Clockhash.day_txtbx.ActualWidth,$Clockhash.month_txtbx.ActualWidth | Sort -Descending)[0]) [int]$Adjustment = $clockhash.length + 52 + 10 #Hard coded margin plus white space $YearMargin = $Clockhash.year_txtbx.Margin $Clockhash.year_txtbx.Margin = ("{0},{1},{2},{3}" -f ($Adjustment), $YearMargin.Top,$YearMargin.Right,$YearMargin.Bottom) }) $Clockhash.time_txtbox.Add_SizeChanged({ If ($Clockhash.time_txtbox.text.length -eq 4) { $Clockhash.ampm_txtbx.Margin = "133,0,86,0" } Else { $Clockhash.ampm_txtbx.Margin = "172,0,48,0" } }) $Clockhash.Window.Add_MouseRightButtonUp({ $This.close() }) $Clockhash.Window.Add_MouseLeftButtonDown({ $This.DragMove() }) $Update.Invoke() $Clockhash.Window.ShowDialog() | Out-Null }).BeginInvoke() } Start-WpfUhr #endregion #region .NET: Read-Window (WinForm, CmdLet) function Read-Window { <# .EXAMPLE Read-Window .EXAMPLE Read-Window -Title "BANK-O-MAT" -Message "Wieviel wollen Sie abheben?" -DefaultText 100 #> Param( [string]$Title = [string]::Empty, [string]$Message = [string]::Empty, [string]$DefaultText = [string]::Empty ) $a = [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") $b = [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") $messageLabel = New-Object System.Windows.Forms.Label $messageLabel.Text = $Message $messageLabel.Left = 10 $messageLabel.Top = 10 $messageLabel.Width = 250 $messageLabel.Height = 30 $messageLabel.Anchor = [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Right #$messageLabel.BackColor = [System.Drawing.Color]::Pink # DEBUG-Farbe $inputTextBox = New-Object System.Windows.Forms.TextBox $inputTextBox.Left = $messageLabel.Left $inputTextBox.Top = $messageLabel.Top + $messageLabel.Height + 5 $inputTextBox.Width = $messageLabel.Width $inputTextBox.Multiline = $true $inputTextBox.Height = 20 $inputTextBox.Text = $DefaultText $inputTextBox.Anchor = [System.Windows.Forms.AnchorStyles]::Left -bor ` [System.Windows.Forms.AnchorStyles]::Top -bor ` [System.Windows.Forms.AnchorStyles]::Right -bor ` [System.Windows.Forms.AnchorStyles]::Bottom $okButtom = New-Object System.Windows.Forms.Button $okButtom.Text = "&OK" $okButtom.Left = 105 $okButtom.Top = $inputTextBox.Top + $inputTextBox.Height + 10 $okButtom.DialogResult = [System.Windows.Forms.DialogResult]::OK $okButtom.Anchor = [System.Windows.Forms.AnchorStyles]::Right -bor ` [System.Windows.Forms.AnchorStyles]::Bottom $cancelButton = New-Object System.Windows.Forms.Button $cancelButton.Text = "&Abbruch" $cancelButton.Left = $okButtom.Left + $okButtom.Width + 5 $cancelButton.Top = $okButtom.Top $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $cancelButton.Anchor = [System.Windows.Forms.AnchorStyles]::Right -bor ` [System.Windows.Forms.AnchorStyles]::Bottom $inputboxForm = New-Object System.Windows.Forms.Form $inputboxForm.AcceptButton = $okButtom $inputboxForm.CancelButton = $cancelButton $inputboxForm.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $inputboxForm.MinimizeBox = $false $inputboxForm.MaximizeBox = $false $inputboxForm.Text = $Title $inputboxForm.Height = 180 $inputboxForm.Controls.AddRange(($messageLabel, $inputTextBox, $okButtom, $cancelButton)) $inputboxForm.Scale(3) $formClosingAction = { if($inputboxForm.DialogResult -eq [System.Windows.Forms.DialogResult]::OK) { Out-Host -InputObject $inputTextBox.Text } else { Out-Host -InputObject ([string]::Empty) } } $inputboxForm.Add_FormClosing($formClosingAction) $inputboxForm.ShowDialog() | Out-Null } #endregion #region UI-Abfrage per PromptForChoice $title = "Delete Files" $message = "Do you want to delete the remaining files in the folder?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` "Deletes all the files in the folder." $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` "Retains all the files in the folder." $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) $result = $host.ui.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 {"You selected Yes."} 1 {"You selected No."} } #endregion #region Diagramm erstellen per DataVisualization using namespace System.Windows.Forms.DataVisualization.Charting using namespace System.Windows.Forms [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization") $datasource = Get-Process | sort PrivateMemorySize -Descending | Select-Object -First 5 $chart1 = New-object Chart $chart1.Width = 1000 $chart1.Height = 1000 $chart1.BackColor = [System.Drawing.Color]::White $chart1.Dock = [DockStyle]::Fill $chart1.Titles.Add("Top 5 - Memory Usage (as: Column)") | Out-Null $chart1.Titles[0].Font = "Arial,13pt" $chart1.Titles[0].Alignment = "topLeft" $chartarea = New-Object ChartArea $chartarea.Name = "ChartArea1" $chartarea.AxisY.Title = "Memory (MB)" $chartarea.AxisX.Title = "Process Name" $chartarea.AxisY.Interval = 100 $chartarea.AxisX.Interval = 1 $chart1.ChartAreas.Add($chartarea) $legend = New-Object system.Windows.Forms.DataVisualization.Charting.Legend $legend.name = "Legend1" $chart1.Legends.Add($legend) $chart1.Series.Add("VirtualMem") | Out-Null $chart1.Series["VirtualMem"].ChartType = "Column" $chart1.Series["VirtualMem"].BorderWidth = 3 $chart1.Series["VirtualMem"].IsVisibleInLegend = $true $chart1.Series["VirtualMem"].chartarea = "ChartArea1" $chart1.Series["VirtualMem"].Legend = "Legend1" $chart1.Series["VirtualMem"].color = "#62B5CC" $datasource | ForEach-Object { $chart1.Series["VirtualMem"].Points.addxy( $_.Name , ($_.VirtualMemorySize / 1MB)) | Out-Null} $chart1.Series.Add("PrivateMem") | Out-Null $chart1.Series["PrivateMem"].ChartType = "Column" $chart1.Series["PrivateMem"].IsVisibleInLegend = $true $chart1.Series["PrivateMem"].BorderWidth = 3 $chart1.Series["PrivateMem"].chartarea = "ChartArea1" $chart1.Series["PrivateMem"].Legend = "Legend1" $chart1.Series["PrivateMem"].color = "#E3B64C" $datasource | ForEach-Object { $chart1.Series["PrivateMem"].Points.addxy( $_.Name , ($_.PrivateMemorySize / 1MB)) | Out-Null } # z.B. als PNG speichern, oder $chart1.SaveImage("c:\temp\SplineArea.png", "png") # z.B. im Fenster anzeigen $Form = New-Object Form $Form.Width = 1024 $Form.Height = 820 $Form.controls.add($chart1) $Form.Add_Shown({$Form.Activate()}) $Form.ShowDialog() #endregion #endregion #endregion #region EINARBEITEN function Join-Object { <# .SYNOPSIS Join data from two sets of objects based on a common value .DESCRIPTION Join data from two sets of objects based on a common value For more details, see the accompanying blog post: http://ramblingcookiemonster.github.io/Join-Object/ For even more details, see the original code and discussions that this borrows from: Dave Wyatt's Join-Object - http://powershell.org/wp/forums/topic/merging-very-large-collections Lucio Silveira's Join-Object - http://blogs.msdn.com/b/powershell/archive/2012/07/13/join-object.aspx .PARAMETER Left 'Left' collection of objects to join. You can use the pipeline for Left. The objects in this collection should be consistent. We look at the properties on the first object for a baseline. .PARAMETER Right 'Right' collection of objects to join. The objects in this collection should be consistent. We look at the properties on the first object for a baseline. .PARAMETER LeftJoinProperty Property on Left collection objects that we match up with RightJoinProperty on the Right collection .PARAMETER RightJoinProperty Property on Right collection objects that we match up with LeftJoinProperty on the Left collection .PARAMETER LeftProperties One or more properties to keep from Left. Default is to keep all Left properties (*). Each property can: - Be a plain property name like "Name" - Contain wildcards like "*" - Be a hashtable like @{Name="Product Name";Expression={$_.Name}}. Name is the output property name Expression is the property value ($_ as the current object) Alternatively, use the Suffix or Prefix parameter to avoid collisions Each property using this hashtable syntax will be excluded from suffixes and prefixes .PARAMETER RightProperties One or more properties to keep from Right. Default is to keep all Right properties (*). Each property can: - Be a plain property name like "Name" - Contain wildcards like "*" - Be a hashtable like @{Name="Product Name";Expression={$_.Name}}. Name is the output property name Expression is the property value ($_ as the current object) Alternatively, use the Suffix or Prefix parameter to avoid collisions Each property using this hashtable syntax will be excluded from suffixes and prefixes .PARAMETER Prefix If specified, prepend Right object property names with this prefix to avoid collisions Example: Property Name = 'Name' Suffix = 'j_' Resulting Joined Property Name = 'j_Name' .PARAMETER Suffix If specified, append Right object property names with this suffix to avoid collisions Example: Property Name = 'Name' Suffix = '_j' Resulting Joined Property Name = 'Name_j' .PARAMETER Type Type of join. Default is AllInLeft. AllInLeft will have all elements from Left at least once in the output, and might appear more than once if the where clause is true for more than one element in right, Left elements with matches in Right are preceded by elements with no matches. SQL equivalent: outer left join (or simply left join) AllInRight is similar to AllInLeft. OnlyIfInBoth will cause all elements from Left to be placed in the output, only if there is at least one match in Right. SQL equivalent: inner join (or simply join) AllInBoth will have all entries in right and left in the output. Specifically, it will have all entries in right with at least one match in left, followed by all entries in Right with no matches in left, followed by all entries in Left with no matches in Right. SQL equivalent: full join .EXAMPLE # #Define some input data. $l = 1..5 | Foreach-Object { [pscustomobject]@{ Name = "jsmith$_" Birthday = (Get-Date).adddays(-1) } } $r = 4..7 | Foreach-Object{ [pscustomobject]@{ Department = "Department $_" Name = "Department $_" Manager = "jsmith$_" } } #We have a name and Birthday for each manager, how do we find their department, using an inner join? Join-Object -Left $l -Right $r -LeftJoinProperty Name -RightJoinProperty Manager -Type OnlyIfInBoth -RightProperties Department # Name Birthday Department # ---- -------- ---------- # jsmith4 4/14/2015 3:27:22 PM Department 4 # jsmith5 4/14/2015 3:27:22 PM Department 5 .EXAMPLE # #Define some input data. $l = 1..5 | Foreach-Object { [pscustomobject]@{ Name = "jsmith$_" Birthday = (Get-Date).adddays(-1) } } $r = 4..7 | Foreach-Object{ [pscustomobject]@{ Department = "Department $_" Name = "Department $_" Manager = "jsmith$_" } } #We have a name and Birthday for each manager, how do we find all related department data, even if there are conflicting properties? $l | Join-Object -Right $r -LeftJoinProperty Name -RightJoinProperty Manager -Type AllInLeft -Prefix j_ # Name Birthday j_Department j_Name j_Manager # ---- -------- ------------ ------ --------- # jsmith1 4/14/2015 3:27:22 PM # jsmith2 4/14/2015 3:27:22 PM # jsmith3 4/14/2015 3:27:22 PM # jsmith4 4/14/2015 3:27:22 PM Department 4 Department 4 jsmith4 # jsmith5 4/14/2015 3:27:22 PM Department 5 Department 5 jsmith5 .EXAMPLE # #Hey! You know how to script right? Can you merge these two CSVs, where Path1's IP is equal to Path2's IP_ADDRESS? #Get CSV data $s1 = Import-CSV $Path1 $s2 = Import-CSV $Path2 #Merge the data, using a full outer join to avoid omitting anything, and export it Join-Object -Left $s1 -Right $s2 -LeftJoinProperty IP_ADDRESS -RightJoinProperty IP -Prefix 'j_' -Type AllInBoth | Export-CSV $MergePath -NoTypeInformation .EXAMPLE # # "Hey Warren, we need to match up SSNs to Active Directory users, and check if they are enabled or not. # I'll e-mail you an unencrypted CSV with all the SSNs from gmail, what could go wrong?" # Import some SSNs. $SSNs = Import-CSV -Path D:\SSNs.csv #Get AD users, and match up by a common value, samaccountname in this case: Get-ADUser -Filter "samaccountname -like 'wframe*'" | Join-Object -LeftJoinProperty samaccountname -Right $SSNs ` -RightJoinProperty samaccountname -RightProperties ssn ` -LeftProperties samaccountname, enabled, objectclass .NOTES This borrows from: Dave Wyatt's Join-Object - http://powershell.org/wp/forums/topic/merging-very-large-collections/ Lucio Silveira's Join-Object - http://blogs.msdn.com/b/powershell/archive/2012/07/13/join-object.aspx Changes: Always display full set of properties Display properties in order (left first, right second) If specified, add suffix or prefix to right object property names to avoid collisions Use a hashtable rather than ordereddictionary (avoid case sensitivity) .LINK http://ramblingcookiemonster.github.io/Join-Object/ .FUNCTIONALITY PowerShell Language #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, ValueFromPipeLine = $true)] [object[]] $Left, # List to join with $Left [Parameter(Mandatory=$true)] [object[]] $Right, [Parameter(Mandatory = $true)] [string] $LeftJoinProperty, [Parameter(Mandatory = $true)] [string] $RightJoinProperty, [object[]]$LeftProperties = '*', # Properties from $Right we want in the output. # Like LeftProperties, each can be a plain name, wildcard or hashtable. See the LeftProperties comments. [object[]]$RightProperties = '*', [validateset( 'AllInLeft', 'OnlyIfInBoth', 'AllInBoth', 'AllInRight')] [Parameter(Mandatory=$false)] [string]$Type = 'AllInLeft', [string]$Prefix, [string]$Suffix ) Begin { function AddItemProperties($item, $properties, $hash) { if ($null -eq $item) { return } foreach($property in $properties) { $propertyHash = $property -as [hashtable] if($null -ne $propertyHash) { $hashName = $propertyHash["name"] -as [string] $expression = $propertyHash["expression"] -as [scriptblock] $expressionValue = $expression.Invoke($item)[0] $hash[$hashName] = $expressionValue } else { foreach($itemProperty in $item.psobject.Properties) { if ($itemProperty.Name -like $property) { $hash[$itemProperty.Name] = $itemProperty.Value } } } } } function TranslateProperties { [cmdletbinding()] param( [object[]]$Properties, [psobject]$RealObject, [string]$Side) foreach($Prop in $Properties) { $propertyHash = $Prop -as [hashtable] if($null -ne $propertyHash) { $hashName = $propertyHash["name"] -as [string] $expression = $propertyHash["expression"] -as [scriptblock] $ScriptString = $expression.tostring() if($ScriptString -notmatch 'param\(') { Write-Verbose "Property '$HashName'`: Adding param(`$_) to scriptblock '$ScriptString'" $Expression = [ScriptBlock]::Create("param(`$_)`n $ScriptString") } $Output = @{Name =$HashName; Expression = $Expression } Write-Verbose "Found $Side property hash with name $($Output.Name), expression:`n$($Output.Expression | out-string)" $Output } else { foreach($ThisProp in $RealObject.psobject.Properties) { if ($ThisProp.Name -like $Prop) { Write-Verbose "Found $Side property '$($ThisProp.Name)'" $ThisProp.Name } } } } } function WriteJoinObjectOutput($leftItem, $rightItem, $leftProperties, $rightProperties) { $properties = @{} AddItemProperties $leftItem $leftProperties $properties AddItemProperties $rightItem $rightProperties $properties New-Object psobject -Property $properties } #Translate variations on calculated properties. Doing this once shouldn't affect perf too much. foreach($Prop in @($LeftProperties + $RightProperties)) { if($Prop -as [hashtable]) { foreach($variation in ('n','label','l')) { if(-not $Prop.ContainsKey('Name') ) { if($Prop.ContainsKey($variation) ) { $Prop.Add('Name',$Prop[$Variation]) } } } if(-not $Prop.ContainsKey('Name') -or $Prop['Name'] -like $null ) { Throw "Property is missing a name`n. This should be in calculated property format, with a Name and an Expression:`n@{Name='Something';Expression={`$_.Something}}`nAffected property:`n$($Prop | out-string)" } if(-not $Prop.ContainsKey('Expression') ) { if($Prop.ContainsKey('E') ) { $Prop.Add('Expression',$Prop['E']) } } if(-not $Prop.ContainsKey('Expression') -or $Prop['Expression'] -like $null ) { Throw "Property is missing an expression`n. This should be in calculated property format, with a Name and an Expression:`n@{Name='Something';Expression={`$_.Something}}`nAffected property:`n$($Prop | out-string)" } } } $leftHash = @{} $rightHash = @{} # Hashtable keys can't be null; we'll use any old object reference as a placeholder if needed. $nullKey = New-Object psobject $bound = $PSBoundParameters.keys -contains "InputObject" if(-not $bound) { [System.Collections.ArrayList]$LeftData = @() } } Process { #We pull all the data for comparison later, no streaming if($bound) { $LeftData = $Left } Else { foreach($Object in $Left) { [void]$LeftData.add($Object) } } } End { foreach ($item in $Right) { $key = $item.$RightJoinProperty if ($null -eq $key) { $key = $nullKey } $bucket = $rightHash[$key] if ($null -eq $bucket) { $bucket = New-Object System.Collections.ArrayList $rightHash.Add($key, $bucket) } $null = $bucket.Add($item) } foreach ($item in $LeftData) { $key = $item.$LeftJoinProperty if ($null -eq $key) { $key = $nullKey } $bucket = $leftHash[$key] if ($null -eq $bucket) { $bucket = New-Object System.Collections.ArrayList $leftHash.Add($key, $bucket) } $null = $bucket.Add($item) } $LeftProperties = TranslateProperties -Properties $LeftProperties -Side 'Left' -RealObject $LeftData[0] $RightProperties = TranslateProperties -Properties $RightProperties -Side 'Right' -RealObject $Right[0] #I prefer ordered output. Left properties first. [string[]]$AllProps = $LeftProperties #Handle prefixes, suffixes, and building AllProps with Name only $RightProperties = foreach($RightProp in $RightProperties) { if(-not ($RightProp -as [Hashtable])) { Write-Verbose "Transforming property $RightProp to $Prefix$RightProp$Suffix" @{ Name="$Prefix$RightProp$Suffix" Expression=[scriptblock]::create("param(`$_) `$_.'$RightProp'") } $AllProps += "$Prefix$RightProp$Suffix" } else { Write-Verbose "Skipping transformation of calculated property with name $($RightProp.Name), expression:`n$($RightProp.Expression | out-string)" $AllProps += [string]$RightProp["Name"] $RightProp } } $AllProps = $AllProps | Select -Unique Write-Verbose "Combined set of properties: $($AllProps -join ', ')" foreach ( $entry in $leftHash.GetEnumerator() ) { $key = $entry.Key $leftBucket = $entry.Value $rightBucket = $rightHash[$key] if ($null -eq $rightBucket) { if ($Type -eq 'AllInLeft' -or $Type -eq 'AllInBoth') { foreach ($leftItem in $leftBucket) { WriteJoinObjectOutput $leftItem $null $LeftProperties $RightProperties | Select $AllProps } } } else { foreach ($leftItem in $leftBucket) { foreach ($rightItem in $rightBucket) { WriteJoinObjectOutput $leftItem $rightItem $LeftProperties $RightProperties | Select $AllProps } } } } if ($Type -eq 'AllInRight' -or $Type -eq 'AllInBoth') { foreach ($entry in $rightHash.GetEnumerator()) { $key = $entry.Key $rightBucket = $entry.Value $leftBucket = $leftHash[$key] if ($null -eq $leftBucket) { foreach ($rightItem in $rightBucket) { WriteJoinObjectOutput $null $rightItem $LeftProperties $RightProperties | Select $AllProps } } } } } } #region Übungen $request = Invoke-WebRequest -Uri "http://www.bing.com/HPImageArchive.aspx?mbl=1&mkt=de-DE&idx=0&n=1" $xImages = [xml]$request.Content $xImages.images.image.url $xImages.images.image.copyright $url2 = "http://www.bing.com//az/hprichbg/rb/BerchtesgadenAlps_DE-DE12607487459_1366x768.jpg" Invoke-WebRequest -Uri $url2 -OutFile C:\PowerShell\test.jpg # Alle *.temp löschen die älter sind als 1 Minuten <# ÜBUNG 1.) Für den aktuellen Benutzer einen Schlüssel erstellen "gfu" in Software 2.) Eigenschaft Erstellungsdatum mit Datum von heute 2.) NUR das Datum anzeigen lassen und darauf 5 Monate addieren #> <# ÜBUNG "Was kann ich mit Datei-Objekten anfangen" a) Finden Sie alle (auch Versteckte) große (> 5MB) Dateien in c:\temp und Unterordner um diese zu löschen. b) Kürzen Sie den Aufruf auf ein maximum C) Finden Sie zum löschen eine Variante als CmdLet Hinweise: a) Get-ChildItem findet NUR ALLE Dateien auch in Unterordner (siehe Hilfe) b) Erstellen Sie für Test-Zwecke z.B. große TXT-Dateien in den o.a. Ordnern c) Das Where-Object filtert z.B. nach Datei-Größe d) Get-Member zeigt Ihnen welche Eigenschaft die Größe (in Byte) enthält e) Get-Member zeigt Ihnen die Methode zum löschen f) ()-Paar spielt eine entscheidente Rolle #> <# ÜBUNG "Was kann ich mit Datei-Objekten anfangen" a) Finden Sie alle (auch Versteckte) große (> 5MB) Dateien in c:\temp und Unterordner um diese zu löschen. b) Kürzen Sie den Aufruf auf ein maximum C) Finden Sie zum löschen eine Variante als CmdLet Hinweise: a) Get-ChildItem findet NUR ALLE Dateien auch in Unterordner (siehe Hilfe) b) Erstellen Sie für Test-Zwecke z.B. große TXT-Dateien in den o.a. Ordnern c) Das Where-Object filtert z.B. nach Datei-Größe d) Get-Member zeigt Ihnen welche Eigenschaft die Größe (in Byte) enthält e) Get-Member zeigt Ihnen die Methode zum löschen f) ()-Paar spielt eine entscheidente Rolle #> <# ÜBUNG: "Umgang mit PS-Provider'n und Filterung" a) Finden Sie alle Schlüssel die mit Run beginnen in HKey Current User b) Finden Sie alle Schlüssel die mit Run beginnen in HKey Current User und HKey Local Machine AUF EINMAL !!!! HINWEISE Get-PSDrive, Get-ChildItem, Where-Object, Get-Member, Format-List führen zum Erfolg !!! ****** #> <# ÜBUNG: "Module" a) Ist das ActiveDirectory Modul installiert? b) Wie lautet das CmdLet um einen Benutzer im AD zu ändern? n) Wieviele CmdLets aus dem ActiveDirectory-Modul gibt es? #> <# ÜBUNG: "Module" (PowerShell Community Extensions) http://pscx.codeplex.com a) Installieren Sie das PSCX-Modul b) Welche sinnvollen CmdLets enthält diese Modul für SIE? #> <# ÜBUNG "Remoting" a) Sammeln Sie von min. 2 Remotecomputern die MAC-Adresse über das CmdLet Invoke-Command b) und geben eine Tabelle zurück mit den Spalten für PowerShell-RemoteComputername, ComputerNamen und MAC-Adresse c) Die MAC-Adresse soll ohne "-" angezeigt werden #> #endregion #endregion