Witaj Stack Community :)
Mam prosty cel. Chciałbym uruchomić skrypt PowerShell z innego skryptu PowerShell, ale są 3 warunki:
- Muszę przekazać poświadczenia (wykonanie łączy się z bazą danych, która ma określonego użytkownika)
- Musi wziąć kilka parametrów
- Chciałbym przekazać dane wyjściowe do zmiennej
Istnieje podobne pytanie Link . Ale odpowiedzią jest użycie plików jako sposobu komunikacji między 2 skryptami PS. Chciałbym tylko uniknąć konfliktów dostępu. @Update: Skrypt główny uruchomi kilka innych skryptów. więc rozwiązanie z plikami może być trudne, jeśli wykonanie zostanie wykonane przez wielu użytkowników jednocześnie.
Script1.ps1 to skrypt, który powinien mieć ciąg wyjściowy. (Żeby było jasne, to fikcyjny skrypt, prawdziwy ma 150 wierszy, więc chciałem tylko dać przykład)
param(
[String]$DeviceName
)
#Some code that needs special credentials
$a = "Device is: " + $DeviceName
$a
Plik ExecuteScripts.ps1 powinien wywoływać ten z tymi 3 warunkami wymienionymi powyżej
Próbowałem wielu rozwiązań. Ten na przykład:
$arguments = "C:\..\script1.ps1" + " -ClientName" + $DeviceName
$output = Start-Process powershell -ArgumentList $arguments -Credential $credentials
$output
Nie otrzymuję z tego żadnych danych wyjściowych i nie mogę po prostu wywołać skryptu
&C:\..\script1.ps1 -ClientName PCPC
Ponieważ nie mogę przekazać -Credential
parametru do niego ..
Z góry dziękuję!
źródło
Odpowiedzi:
Uwaga:
Poniższe rozwiązanie działa z dowolnym programem zewnętrznym i niezmiennie przechwytuje dane wyjściowe jako tekst .
Aby wywołać inną instancję programu PowerShell i przechwycić dane wyjściowe jako obiekty bogate (z ograniczeniami), zapoznaj się z wariantem rozwiązania w dolnej części lub rozważ pomocną odpowiedź Mathiasa R. Jessena , która korzysta z zestawu SDK programu PowerShell .
Oto dowód koncepcji oparty na bezpośrednim użyciu typów
System.Diagnostics.Process
iSystem.Diagnostics.ProcessStartInfo
.NET do przechwytywania danych wyjściowych procesu w pamięci (jak podano w pytaniu,Start-Process
nie jest opcją, ponieważ obsługuje tylko przechwytywanie danych wyjściowych w plikach , jak pokazano w tej odpowiedzi ) :Uwaga:
Ze względu na to, że działa jako inny użytkownik, jest obsługiwany tylko w systemie Windows (od .NET Core 3.1), ale w obu tam wersjach PowerShell.
Ze względu na potrzeby działać jako inny użytkownik i konieczności wyjścia przechwytywania,
.WindowStyle
nie mogą być wykorzystane do uruchomienia polecenia ukryty (ponieważ używając.WindowStyle
wymaga.UseShellExecute
się$true
, co jest niezgodne z tymi wymaganiami); Jednakże, ponieważ cała produkcja jest zrobione , ustawienie.CreateNoNewWindow
się$true
skutecznie prowadzi ukryte wykonania.Z powyższego wynika coś takiego, co pokazuje, że proces został pomyślnie uruchomiony z podaną tożsamością użytkownika:
Ponieważ wywołujesz inną instancję programu PowerShell , możesz skorzystać ze zdolności interfejsu PowerShell CLI do reprezentowania danych wyjściowych w formacie CLIXML, co umożliwia deserializację danych wyjściowych w obiekty bogate , aczkolwiek z ograniczoną wiernością typów , jak wyjaśniono w tej pokrewnej odpowiedzi .
Powyższe dane wyjściowe wyglądają mniej więcej tak, jak pokazano, pokazując, że dane wyjściowe
[datetime]
instance (System.DateTime
)Get-Date
zostały zdezrializowane jako takie:źródło
Start-Process
byłby moim ostatecznym wyborem przy wywoływaniu programu PowerShell z programu PowerShell - szczególnie dlatego, że wszystkie operacje we / wy stają się ciągami, a nie obiektami (bez deserializacji).Dwie alternatywy:
1. Jeśli użytkownik jest lokalnym administratorem i skonfigurowano PSRemoting
Jeśli zdalna sesja na komputerze lokalnym (niestety ograniczona do lokalnych administratorów) jest opcją, zdecydowanie wybrałbym
Invoke-Command
:$strings
będzie zawierać wyniki.2. Jeśli użytkownik nie jest administratorem w systemie docelowym
Możesz napisać własny „tylko lokalny
Invoke-Command
”, rozbijając obszar roboczy poza procesem poprzez:PowerShellProcessInstance
, pod innym loginemZłożyłem taką funkcję poniżej, zobacz komentarze do przewodnika:
Następnie użyj tak:
źródło
rcv.ps1
wykonanie z innego skryptu:
wynik:
źródło
Co możesz zrobić, aby przekazać parametr do skryptu ps1.
Pierwszym skryptem może być origin.ps1, w którym piszemy:
Skrypt docelowy dest.ps1 może zawierać następujący kod do przechwytywania zmiennych
I wynik będzie
źródło
-Credential $credentials
parametr do tego wykonania i uzyskać wynik z niego w zmiennej. PS1. Skrypt, który wykonuję, wyrzuca na końcu pojedynczy ciąg słów. Spójrz tylko, jak to zrobiłem,Start-process
ale ta funkcja nie generuje danych wyjściowych$output
zmiennej, jest NULL. Innym pomysłem pochodzącym z @ mklement0 jest zapisanie danych wyjściowych w pliku. Ale w moim przypadku spowoduje to ogromną liczbę plików w jednym miejscu. Wszystkie utworzone przez różnych użytkowników z różnymi skryptami