PowerShell Remote nutzen
eBook: Layman’s guide to
PowerShell 2.0 remoting
http://www.ravichaganti.com/blog/?p=1305
Sehr lesenswertes kostenfreies Ebook
PSExRemote
Exchange Powerhell Remote
Mittlerweile gehört es zum guten Ton, dass die PowerShell auf jedem halbwegs modernen Server und sogar Client vorhanden ist. PowerShell ist aber nur die Plattform. Erst die verschiedenen Commandlets, die als Module oder Snapins nachgeladen werden können, machen die PowerShell erst richtig leistungsfähig. Um nun eine Funktion auszuführen, die auf dem Server einfach vorhanden ist, muss die PowerShell gestartet und das Snapin oder Modul nachgeladen werden. Allerdings sollten Sie sich vorher überlegen, ob Sie nun auf jedem System die entsprechenden Produkt-Snapins nachinstallieren. Diese Systeme müssen analog zu den Produkten auch aktualisiert werden. Zudem gibt es "Inkompatibilitäten". Wie wollen Sie z.B. von einem Windows 2003 Server (32bit) ein Exchange 2010 Commandlet starten, welche nur für 64bit verfügbar sind?
Lokal, Remote, RemoteCommand
Zuerst müssen wir uns überlegen, wie ein PowerShell überhaupt arbeiten kann. Ich kenne folgende Optionen.
Nr | Variante | Beispiel | Beschreibung |
---|---|---|---|
1 | Der Code läuft lokal und nutzt lokale Quellen |
Alles lokal |
Auf dem lokalen PC kommt nach meinem Wissen keine Serialisierung vor, da einfach ein Pointer auf das entsprechende Objekt oder eine Kopie übergeben werden kann. |
2 | Der Code läuft lokal aber greift auf entfernte Dienste über WMI, RPC o.ä. zu |
Get-WinEvent -computer <computername> Get-Item "\\server\share\*.*" |
Get-WinEvent ist war eine PowerShell, aber holt sich die Daten per WMI vom entfernten Computer. Get-Item nutzt einfach SMB um die Dateien auf einem Server abzufragen |
3 | Der Code läuft lokal aber verbindet sich eine Remote Powershell |
New-PSSessione Alte Exchange PowerShell |
Mit Exchange OnPremises könne Sie entweder lokal die Exchange Admin Tools installieren oder einfach mit New-PSSession eine direkte Verbindung zur Exchange PowerShell des Servers aufbauen. Das sieht auf den ersten Blick gleich aus, aber ist es nicht, wie ich im nächten Kapitel beschreibe. |
4 | Der Code läuft lokal aber verbindet sich über lokale Module mit einem Remote Service |
MGGraph-PowerShell Connect-ExchangeOnline Connect-AzureAD |
Über lokal installierte Module werden entfernte APIs zur Verfügung gestellt. Zwischen dem PC mit der PowerShell und dem entfernten PC muss kein "PowerShell Remoting" erfolgen. Microsoft Graph nutzt z.B. nur HTTPS |
5 | Der Code startet remote eigenen Code |
Invoke-Command -computername <computer> Enter-PSSession |
Hier nutzt die PowerShell selbst die "Remoting"-Fähigkeiten von PowerShell, um ähnlich einem Unix "RCMD" den gewünschten Code auf dem anderen System lokal auszuführen. Dazu müssen natürlich die Befehle dann auf dem anderen System vorhanden sind. |
Soweit mal ein einfacher Versuch ohne dass ich mich als "Entwickler" bezeichnen möchte.
Beachten Sie die Besonderheiten von PS Serialization bei der Nutzung entfernter PowerShells.
PowerShell mit WinRM
Die normale "Remote Funktion" von PowerShell basiert auf WinRM, auch wenn dies auf den ersten Blick gar nicht sichtbar wird. Exchange nutzt seinen eigenen Dienst
Das hat auch nichts mit den Befehlen "Enable-PSRemoting" und "Disable-PSRemoting" zu tun, welche ebenfalls nur für WinRM entsprechende Listener erstelle, Berechtigungen vergeben und die Windows Firewall anpassen.
eBook Update: Layman’s guide to PowerShell 2.0
remoting
http://www.ravichaganti.com/blog/?p=1780
PowerShell mit SSH
Mittlerweile gibt es ja auch PowerShell Core für Windows, Linux, MAC und alle anderen Plattformen, auf denen irgendwann mal ein NET-Code-Framework verfügbar wird. Im Unix-Bereich ist SSH eine gängige Zugriffsoption auf Systeme. Auch PowerShell kann SSH als Transport nutzen. Dazu brauchen wir zwei Dinge:
- Den SSHServer
Den gibt es auch für Windows 10 und ist per Default nicht installiert. - Powershell mit SSH
Beim Verbinden einer Remote PowerShell mit "Enter-PSSession" nutzen wir einfach den Parameter "-SSHTransport
So können wir von einem Computer uns auf einen anderen Server mit SSH-Server und PowerShell eine Verbindung aufbauen.
- Enter-PSSession
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enter-pssession - Windows and PowerShell support for SSH
https://www.thomasmaurer.ch/2015/06/windows-and-powershell-support-for-ssh/ - Enable PowerShell SSH Remoting in PowerShell 7
https://www.thomasmaurer.ch/2020/04/enable-powershell-ssh-remoting-in-powershell-7/ - Getting Started using SSH with PowerShell
https://adamtheautomator.com/powershell-ssh/
SSL und Zertifikate
Auch wenn sie die Anmeldung "eigentlich" mit einem sicheren Kennwortverfahren (NTLM2, Kerberos) absichern, so könnte jemand doch die HTTP-Nutzdaten mitlesen und Rückschlüsse auf Mailadresse, Benutzernamen etc. erhalten. Auch die Verwendung von "Basic" als Anmeldeverfahren ist manchmal erforderlich, weil Proxies vielleicht nicht die NTLM-Anmeldung unterstützen. Die Installation eines Zertifikats erfolgt, wie Sie es von IIS können.
-
IIS Zertifikat einrichten
Mit wenigen Schritten erweitern Sie ihren Webserver um die Fähigkeit, verschlüsselte Verbindungen zu akzeptieren -
E2K7: Zertifikate
So richten Sie Zertifikate für den Einsatz von SSL ein.
Aber auch hier müssen Sie natürlich dafür sorgen, das die Clients das Zertifikat auch akzeptieren. Dazu zählen die vier Grundtugenden:
- Name Im Zertifikate (Antragsteller bzw. SAN-Namen)
- Gültigkeitszeitrum
- Vertrauen der Ausstellende CA
- Zwischenzertifizierungsstellen
- CRL
Allerdings können Sie über einen kleinen Trick natürlich die strengen Prüfungen zumindest temporär abschalten.
Dies kann durchaus für Tests und für Fehlersuche ratsam sein um Fehler bei den Zertifikaten zu ignorieren und andere Fehler zu finden. Eine Dauerlösung darf dies natürlich nicht sein.
Sie müssen dazu einmal eine PSSessionOption mit den entsprechenden Einstellungen generieren
$SkipCertificate = New-PSSessionOption `
-SkipCACheck `
-SkipCNCheck `
-SkipRevocationCheck
Diese Option geben Sie dann als "SessionOption" beim New-PSSession an.
Authentifizierung
Wenn Sie dann die PSSession aufbauen, dann müssen Sie natürlich Anmeldedaten mitgeben. Wenn Sie die explizite Angabe weglassen, dann nutzt das Commandlet einfach die lokalen Credentials. Das funktioniert natürlich nur, wenn ihr PC im gleichen Forest ist und der lokal angemeldete Benutzer sowieso entsprechende berechtigt ist. Ansonsten müssen Sie natürlich die Anmeldedaten mit angeben. Das Ganze funktioniert natürlich über Get-Credential. Allerdings ist es in Skripten immer besser, das Kennwort nicht mit in den Skriptcode zu lesen. Wenn man es schon nicht eingeben will, dann sollte das Kennwort verschlüsselt in einer eigenen Datei liegen, welche dann nachgeladen wird. Das hat auch den Vorteil, dass bei einer KennwortÄnderung nicht das Skript geändert werden muss.
Sicher ist dies natürlich auch, wenn auf die Kennwortdatei nicht von unautorisierten Personen zugegriffen kann.
Technisch könnte das so aussehen. Mit einem Einzeiler können Sie das Kennwort verdeckt eingeben und in einer Datei speichern
read-host -assecurestring | convertfrom-securestring | out-file .\kennwort.txt
Das Kennwort können Sie dann im Skript selbst wieder nachladen mit:
$User = "domain\Username" $pass = (get-content -path $passwordfile | convertto-securestring) $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $User,$pass
Bei Einsatz von New-PSSession werden die Credentials dann mit der Option "-credential" angegeben. Das ist aber noch nicht alles, denn der Parameter "-Authentication" bestimmt, wie die Anmeldung an weiter gegeben wird. möglich ist hier eine Option aus einer Auswahl:
Wert | Beschreibung |
---|---|
Default |
Das eingestellte Standardverfahren wird verwenden |
Basic |
Anmeldedaten werden BASE64-codiert übertragen. Kompatibelste Form aber ohne SSL denkbar unsicher. |
Negotiate |
Client und Server "handeln" das Verfahren aus. Dies ist aber meines Wissens auf Windows Verfahren (also die verschiedenen NTLM-Optionen und Kerberos beschränkt) |
NegotiateWithImplicitCredential |
|
Credssp |
Verfahren um Client Credentials an den Server zu übergeben (Windows XPSP3 oder höher erforderlich |
Digest |
Verfahren zur sicheren Übertragung des Kennworts (Verschlüsselung mit MD5) über eine unsichere Verbindung. |
Kerberos |
Damit ist eine explizite Anmeldung per Kerberos erforderlich. |
Wie bei jeder HTTP-Verbindung auch versucht der Client natürlich einen anonymen Zugriff um dann über die erste 401-Fehlermeldung des Webservers zu erfahren, welche Anmeldeverfahren der Webserver anbietet. Hier muss es natürlich eine Übereinstimmung geben.
In der Praxis versuche ich immer den Einsatz von "Negotiate". Kerberos funktioniert nicht, wenn der Client nicht in der der Zieldomäne selbst ist oder ein Foresttrust vorhanden ist. Basic ist der Fallback, wenngleich ich dann schon auf dem Server SSL erzwinge.
Sehr große Umgebungen und Limit auf 524288000
Niemand würde einen Webservice einfach so im Internet bereit stellen. Daher hat auch Exchange "Obergrenzen", die nicht überschritten werden dürften. Dazu gehört z.B. die maximale Buffergröße für Anfragen und Antworten. Wer also mit einem "Ret-Recipient" viele tausend Empfänger abruft, kann spätestens beim PIPE zum nächsten Befehl auf einen Fehler stoßen:
C:>get-recipient -resultsize unlimited | Update-recipient Sending data to a remote command failed with the following error message: The total data received from the remote clien t exceeded allowed maximum. Allowed maximum is 524288000. für more information, see the about_Remote_Troubleshooting He lp topic. + CategoryInfo : OperationStopped: (System.Manageme...pressionSyncJob:PSInvokeExpressionSyncJob) [], PSRe motingTransportException + FullyQualifiedErrorId : JobFailure
Sie sehen schon, dass "-Resultsize unlimited" schon mal die Grenze von 1000 Objekten auflösen muss, damit es überhaupt so weit kommen kann. Die Lösung ist natürlich einfach: sie können den Aufruf natürlich in kleinere Pakete aufsplittern. Zuverlässiger ist aber die Trennung über eine FOR-Schleife:
$recipients = get-recipient -resultsize unlimited Foreach ($recipient in $recipients) { Update-recipient -identity $recipient }
Zuerst werden also die Daten in eine Variable geladen und erst dann einzeln als Anfragen wieder abgesetzt. Damit umgehen Sie eine weitere Problematik der Pipeline.
Praktischer Einsatz
Mit folgenden Zeilen sollten Sie von einem beliebigen PC, auf dem die PowerShell 2.0 installiert wurde, eine Verbindung zu einem Exchange Server herstellen können. Auf eine umfangreiche Fehlerbehandlung, die für einen automatischen Einsatz natürlich erforderlich ist, wurde zugunsten der Übersichtlichkeit verzichtet:
# Zertifikatsprüfungen für TestUmgebung abschalten $SkipCertificate = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck # Anmeldedaten erfragen $cred = Get-Credential # PS-Session starten $Session = New-PSSession ` -ConfigurationName Microsoft.Exchange ` -ConnectionUri https://<E2K10Server>.domain.com/PowerShell/ ` -Authentication Negotiate ` -SessionOption $SkipCertificate ` -credential $cred # Importieren der erzeugten Session in die aktuelle Session # lokal gleichlautende Commandlets werden ersetzen Import-PSSession -Session $Session -AllowClobber # hier können Sie nun wie gewohnt agieren Get-OrganizationConfig # Wenn Sie fertig sind, dann sollten Sie die Sessions wieder sauber abbauen Remove-PSSession -Session $Session
Sie können dieses Zeile natürlich auch als PS1-Datei speichern aber für eine automatische Verarbeitung fehlt eine sichere Kennwortablage und natürlich jedes Reporting, Alerting o.ä. Starten Sie daher besser eine PowerShell und geben Sie manuell die einzelnen Zeilen ein. Dann können Sie vor dem abschließenden "Remote-PSSession" auch noch weitere Exchange Commandlets ausprobieren.
Pipeline mit Remote PowerShell
Bezüglich Performance und Netzwerkbandbreite müssen Sie bei der Pipeline beachten, dass Sie zwar verwendet werden kann, aber letztlich durch den ausführenden Client geht. Wenn ich also ein "Get-Recipient" per Remote PowerShell ausführe, dann werden die Daten per WebService an den Client gesendet, der sie dann per Pipeline z.B. an das nächste Commandlet auf dem gleichen Server sendet.
Hier ist es natürlich hilfreich schon bei der Abfrage zu filtern, so dass die Datenmenge reduziert ist. Einige Exchange Commandlets erlauben die Angabe von "Filtern". Dies ist immer einer nachgeschaltete "where"-Abfrage vorzuziehen, selbst wenn der Filter nicht 100% passt. Es reicht schon wenn er eine sinnvolle Teilmenge reduziert.
Zudem kann die PowerShell immer nur eine Pipeline gleichzeitig ausführen. Siehe auch
- PS Pipeline
- Exchange Management Shell Error: Pipelines Cannot be
Executed Concurrently
http://www.mikepfeiffer.net/2010/02/exchange-management-shell-error-pipelines-cannot-be-executed-concurrently/
Proxy-Server auf dem Weg
Nun kann es natürlich sein, dass der Client die Gegenstelle, also den IIS, gar nicht direkt erreicht. HTTP und HTTPS sind ja Protokolle, die gerne über Proxy Server geleitet werden. Das kann auf der Clientseite ein Proxy sein, der den Zugriff in das Internet überhaupt erst zulässt und hierbei natürlich eine Authentifizierung erwartet. für diesen Zugriff müssten Sie dann über die PSSessionOption konfigurieren und beim Herstellen der Session angeben.
$PSSessionOptions = New-PSSessionOption ` -ProxyAccessType {None|IEConfig|WinHttpConfig|AutoDetect|NoProxyServer} ` -ProxyAuthentication {Default|Basic|Negotiate|NegotiateWithImplicitCredential|Credssp|Digest|Kerberos} ` -ProxyCredential $PSCredential
Wenn Sie ihrer Powershell also sagen wollen, dass Sie den IE-Settings nutzt, dann wäre folgender Code passend:
$Cred = Get-Credential $proxysettings = New-PSSessionOption -ProxyAccessType IEConfig $Session = New-PSSession ` -ConfigurationName Microsoft.Exchange ` -ConnectionUri https://outlook.office365.com/powershell/ ` -Credential $cred ` -Authentication Basic ` -AllowRedirection ` -SessionOption $proxysettings import-PSSession -AllowClobber $Session
- New-PSSessionOption
http://technet.microsoft.com/de-de/library/dd819436.aspx
Auf der Seite des Servers kann dies ein Reverse-Proxy oder eine Firewall sein, die den Zugang sicher "veröffentlicht". Hier könnte auch noch mal eine Authentifizierung statt finden. Wobei Sie hier schlechte Karten haben, wenn die Gegenseite z.B. eine Portalseite vorgeschaltet hat o.ä. Es hängt schon von der Art ab, wie der Server "/PowerShell" veröffentlicht. Fragen Sie im Zweifelsfall dort nach, wie Sie einen Zugang erhalten können.
PSSession mit %TEMP% und C:\Windows\Temp
Durch den extensiven Einsatz von PowerShell als PRTG-Sensor ist mit ein anderes Verhalten aufgefallen. Jede PowerShell Session lädt einige Daten vom remote Server lokal ab und wenn man die Session nicht mehr sauber schließt, sondern einfach die PowerShell beendet, dann bleiben diese Dateien wohl "über".
Jedes Verzeichnis enthielt ca. 4 MB Daten
Wird das Auswerteskript also alle 5 Minuten gestartet, dann sammeln sich hier schnell über 1 GB/Tag.
Die temporären Daten werden beim "Import-PSSession" angelegt und erst bei einem geordneten "Remove-PSSession" wieder entfernt. Je nach Einstellung liegen die Dateien auch im TEMP-Verzeichnis des aufrufenden Anwenders.
- Import-PSSession
http://technet.microsoft.com/en-us/library/hh849970.aspx - Remove-PSSession
http://technet.microsoft.com/en-us/library/hh849722.aspx - Import-PSSession and temp
files
http://blogs.utexas.edu/dbailey/2011/09/15/import-pssession-and-temp-files/
If you do not delete the
PSSession, the PSSession remains open and
available für use until you close the current
session or until you exit Windows PowerShell.
about_PSSessions
http://technet.microsoft.com/en-us/library/dd347706.aspx
Leider räumt die PowerShell wohl doch nicht alles auf.
Übergabe von Variablen
Variablen werden nicht als Inhalt im Scriptblock übergeben, sondern als Referenz. Wenn Sie also ein einem Skriptblock eine Variable verwenden, dann kommt immer der Werte der aufrufenden Umgebung zum Einsatz. ein Scriptblock kann sogar die Variable ändern. Sie ändert sich dann auch im aufrufenden Environment.
Interessant wird das aber beim Aufruf von "Invoke-Command" in Verbindung mit einem Computernamen. Hier ein Beispiel, welches nicht funktioniert?
[string]$state = "Running" invokecommand -computer Ex01.msxfaq.net -scriptblock {get-service | where{ $_.status -eq $state} }
Das Skript liefert nie eine Ausgabe und das liegt daran, dass Sie den Scope von Variablen nicht beachtet haben. Das Skript wird 1:1 so auf dem entfernten Server ausgeführt. Die Variable "$_" wird "drüben" natürlich durch die Pipeline gefüllt. Der Inhalte der Variable "$state" ist auf dem anderen Computer aber nicht vorhanden. Invoke-Command kopiert nicht per Default die lokalen Variablen oder die lokale Umgebung auf den entfernten Computer. Sie können aber einzelne Variablen so einsetzen, das Sie übertragen werden. folgendes funktioniert:
[string]$state = "Running" invokecommand -computer Ex01.msxfaq.net -scriptblock {get-service | where{ $_.status -eq $using:state} }
- All about PowerShell ScriptBlock
http://www.padisetty.com/2014/05/all-about-powershell-scriptblock.html
Alternativ können Sie natürlich auch einfach "Parameter" an die Funktion übergeben.
Einschränkungen bei Rückgaben
Die Verwendung von Exchange oder Lync per "remote PowerShell" hat im Gegensatz zu lokal installierten Commandlets, die sich dann Remote mit der RBAC verbinden auch einige Einschränkungen. Die wesentlichste Limitierung ist die Konvertierung von Rückgaben. Durch die Zwangsweise Serialisierung der Objekte über HTTPS und das Fehlen entsprechender lokaler DLLs werden einige Objekte z.B. zu Strings umgewandelt. Hier ein paar Beispiele.
Commandlet | Native Rückgabe | Remote PowerShell |
---|---|---|
(Get-mailbox User).primarysmtpaddress |
Length : 14 Local : User Domain : msxfaq.de IsValidAddress : True |
"User@nmsxfaq.de" Rückgabe als String |
(Get-MailboxDatabase -Status)[0].databasesize |
TypeName: Microsoft.Exchange.Data.ByteQuantifiedSize Name MemberType Definition ---- ---------- ---------- CompareTo Method int CompareTo(Micro Equals Method bool Equals(System. GetHashCode Method int GetHashCode() GetType Method type GetType() RoundUpToUnit Method System.UInt64 RoundU ToBytes Method System.UInt64 ToBytes() ToGB Method System.UInt64 ToGB() ToKB Method System.UInt64 ToKB() ToMB Method System.UInt64 ToMB() ToString Method string ToString(), st ToTB Method System.UInt64 ToTB() |
"15.1 GB (15,833,497 bytes)" Rückgabe als String |
Das bedeutet aber auch, dass man beim Auswerten der Ergebnisse nicht immer die Properties komplett nutzen kann und bei Strings sogar absichtlich "Umwege" eingehen muss.
Wann immer man also die "volle Funktion" nutzen will, sollte man auf einem supporteten Betriebssystem die entsprechenden Commandlets installieren oder direkt den befehl auf dem Server mit einem Invoke-Command aufrufen. Aber auch hier gibt es Einschränkungen, dass nämlich die Exchange PowerShell im "restricted language mode" ausgeführt wird und dort u.a. kein Aufgrund von Methoden erlaubt ist.
- Get Full Control over your
Exchange remote PowerShell
session
http://blog.mimecast.com/2011/08/get-full-control-over-your-exchange-remote-PowerShell-session/ - Remote PowerShell
scriptblock execution question...
http://social.technet.microsoft.com/Forums/en-US/winserverPowerShell/thread/46767d4b-e338-4bff-a38e-63b4d4903408 - PowerShell Module Manifests
Tip: allowed cmdlets and
variables
http://huddledmasses.org/PowerShell-module-manifests-tip-allowed-cmdlets-and-variables/ - PSLanguageMode Enumeration
http://msdn.microsoft.com/en-us/library/system.management.automation.pslanguagemode(v=vs.85).aspx - eBook: Layman’s guide to
PowerShell 2.0 remoting
http://www.ravichaganti.com/blog/?p=1305
Powershell per Skype IM - PowerShIM
Einen interessanten Ansatz hat Tom Morgan gewählt. Er hat einfach mal einen Skype für Business BOT geschrieben, der per Instant Message Befehle empfängt und ausführt:
- Development Project: PowerShIM – run
PowerShell on remote servers using Skype für Business Instant Messaging
http://blog.thoughtstuff.co.uk/2015/11/development-project-powershim-run-powershell-on-remote-servers-using-skype-for-business-instant-messaging
Als mehr als ein Experiment würde ich da aber nicht bezeichnen wollen. Es ist aber ein gutes Sample.
Weitere Links
- RBAC
- WinRM
- Create a Manual Remote Shell Connection
http://technet.microsoft.com/en-us/library/dd335083.aspx - New-PSSession
http://technet.microsoft.com/de-de/library/dd347668.aspx - Learn How to use PowerShell
to Run Exchange Commands
Remotely
http://blogs.technet.com/b/heyscriptingguy/archive/2012/01/23/learn-how-to-use-PowerShell-to-run-exchange-server-commands-remotely.aspx - Windows PowerShell: FAQs für Administrators
http://help.outlook.com/en-au/140/cc875890.aspx - Details on secure port
configuration für WS-Management
in Windows 7 and Windows Server
2008 R2
http://technet.microsoft.com/en-us/library/ee922665(v=ws.10).aspx - Enable and use Remote Commands in Windows PowerShell
http://technet.microsoft.com/en-us/magazine/ff700227.aspx - Hey, Scripting Guy! Weekend Scripter: How Can I Run
Windows PowerShell Commands Remotely?
http://blogs.technet.com/b/heyscriptingguy/archive/2010/03/14/hey-scripting-guy-march-14-2010.aspx - PowerShell 2.0 remoting guide: Part 12 – using
CredSSP für multi-hop authentication
http://www.ravichaganti.com/blog/?p=1230 - eBook Update: Layman’s guide to PowerShell 2.0
remoting
http://www.ravichaganti.com/blog/?p=1780 - SharePoint 2010 remoting
http://sharepoint.microsoft.com/blogs/zach/Lists/Posts/Post.aspx?ID=45 - Exchange 2010 remoting
http://www.mikepfeiffer.net/2010/02/managing-exchange-2010-with-remote-PowerShell - Saving remote session to your local disk
http://blogs.msdn.com/b/PowerShell/archive/2009/12/29/saving-remote-session-to-your-local-disk.aspx