Benutzer-Werkzeuge

Webseiten-Werkzeuge


coding:powershell

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

Packages

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
Um Packages zu installieren sollte TLS1.1 aktiviert sein.
PS C:\> [Net.ServicePointManager]::SecurityProtocol
Tls11
 
PS C:\> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
 
PS C:\> [Net.ServicePointManager]::SecurityProtocol
Tls12

Updates

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

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()

Active Directory

Active Directory

//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

Benutzer

//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"

Gruppen

# 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

Organisationseinheiten (OU)

//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

Gruppenrichtlinien

//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

DHCP Verwaltung

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-Verwaltung

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
    }
 
}

Firewall

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

Replikation

# 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")

Exchange

Verwaltung einer Microsoft Exchange OnPremise Installation

Inbox Rules

Get-InboxRule -Mailbox "**********"

Name                            Enabled Priority RuleIdentity
----                            ------- -------- ------------
Mails an Walter Friedrich und I True    1        17352165469276078081
Remove-InboxRule -Mailbox "*****" -Identity 17352165469276078081

Postfach

// 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>

Verteiler

//Verteilergruppe erstellen:
New-DistributionGroup -Name "Vertriebsgruppe" -Alias "Vertrieb" -Members user1, user2, user3
 
//Sicherheitsgruppe erstellen:
New-DistributionGroup -Name "IT-Sicherheit" -Alias "ITSecurity" -SecurityEnabled $true

Datenbank

//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

Microsoft365

Benutzer

//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

Gruppen

//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

Richtlinien

//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

# Exchange Online-Modul importieren
Import-Module ExchangeOnlineManagement
 
# Verbindung zu Exchange Online herstellen
Connect-ExchangeOnline -UserPrincipalName admin@example.com

Postfach

# 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

Berechtigungen

# 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:

  • SendAs: Berechtigt den Benutzer, E-Mails im Namen eines anderen Postfachs zu senden.
  • SendOnBehalf: Berechtigt den Benutzer, E-Mails im Auftrag eines anderen Postfachs zu senden.
  • ReadPermission: Berechtigt den Benutzer, den Inhalt eines Postfachs zu lesen.
  • WritePermission: Berechtigt den Benutzer, den Inhalt eines Postfachs zu ändern oder zu bearbeiten.
  • DeleteItem: Berechtigt den Benutzer, Elemente aus dem Postfach zu löschen.
  • CreateItems: Berechtigt den Benutzer, neue Elemente im Postfach zu erstellen.
  • EditOwnedItems: Berechtigt den Benutzer, die eigenen Elemente im Postfach zu bearbeiten.
  • EditAllItems: Berechtigt den Benutzer, alle Elemente im Postfach zu bearbeiten, einschließlich Elementen, die anderen Benutzern gehören.
  • FolderVisible: Berechtigt den Benutzer, den Ordnerinhalt im Postfach anzuzeigen.
  • FolderOwner: Berechtigt den Benutzer, die Eigentumsrechte für einen Ordner im Postfach zu besitzen und zu ändern.

Migration

# 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"

Berichterstellung

# 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"

AzureAD

Import-Module AzureAD
Connect-AzureAD
Connect-AzureAD -TenantId <Tenant-ID>

Benutzer

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>

Gruppen

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>

Apps und Zugriffe

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>

Scripting

Variables

# 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

Arrays

$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

Module

Datei als psm1 speichern.

function Test {
    Write-Output "Test"
}
Import-Module .\ModuleName.psm1
Test

Objekte

$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"
    }
)

Argumente

# 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"

If elseif else

# Ü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"
}

Schleifen

For

# Zählt von 1 bis 5 und gibt jeden Wert aus
for ($i = 1; $i -le 5; $i++) {
    Write-Output $i
}

While

# 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++
}

Do

# Eine Variable initialisieren
$i = 1
 
# Die do-while-Schleife ausführen
do {
    Write-Output $i
    $i++
} while ($i -le 5)

Kontroll Statements

$i = 1
while ($i -le 10) {
 
    $i++
 
    if($i -eq 3) {
        continue
    }
 
    if($i -eq 4) {
        break
    }
}

Funktionen

# 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

Klassen

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

Filter

# 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}}

Firewall

//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}

Loops

$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)

Complex Datatypes

$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);

AD Commands

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*"}

Run Code in Powershell

#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)

Load Assembly into Powershell

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)

Syntax Examples

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") }

Networking

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
}

Scripts

Get Nested Groups

$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"

Exchange Abwesenheitsnotiz GUI

<#
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

Check Updates Remote

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 AD Kontakte importieren

Example

$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."
 
}

Powershell Wissen

#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
coding/powershell.txt · Zuletzt geändert: 2025/04/14 12:55 von jango