herbstengel
Goto Top

Powershell-Skipt mit Übergabeparametern

Hallo zusammen,

Ich würde gerne von cmd.exe, mit WIN+R o.ä. eine powershell-Datei test.ps1 aufrufen, und dieser drei Parameter (hier: Stringwerte) übergeben, komme aber nicht
auf die korrekte Syntax dazu.

In test.ps1 soll es eine Main-Funktion als "Einsprungfunktion" geben, in welcher diese Parameter dannweiterverarbeitet werden sollen.

Meine bisherigen Bemühungen:


powershell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File ""C:\test.ps1""' -Wait -WindowStyle Normal}"
--> für cmd.exe, WIN+R, o.ä.

Datei test.ps1:


Function Main()
{

param( [string]$param1, [string]$param2, [string]$param2 )

....

}
Main -param1 "String1" -param2 "String2" -param3 "String3"


Bitte um Vorschläge, vielen Dank.

Viele Grüsse, Roger

Content-ID: 529320

Url: https://administrator.de/forum/powershell-skipt-mit-uebergabeparametern-529320.html

Ausgedruckt am: 22.12.2024 um 20:12 Uhr

mayho33
mayho33 23.12.2019 um 20:27:23 Uhr
Goto Top
Herbstengel
Herbstengel 28.01.2020 um 16:43:30 Uhr
Goto Top
Hallo,

ich habe das mittlerweile so gelöst:

Datei script.bat (ruft script.ps1 auf (ohne darauf zu warten)):

.....
START powershell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File "c:\test\script.ps1" -param1 "Wert_1" -param2 "Wert_2" -param3 "Wert_3"'   -Wait -NoNewWindow}"  
.....

Datei script.ps1: Die im Batchfile übergebenen drei Parameter vom Typ String landen in der Main-Funktion (als gewünschte Einsprungstelle). Die Powershelldatei enthält neben dieser Main-Funktion halt auch noch andere Funktionen.

param(

    [parameter(Mandatory)]
    [string]$param1,

    [parameter(Mandatory)]
    [string]$param2,

    [parameter(Mandatory)]
    [string]$param3
)
....
.....

function Main()
{

    [cmdletbinding()]
    [OutputType([System.Int32])]

    param(
    
        [parameter(Mandatory)]
        [string]$param1,
    
        [parameter(Mandatory)]
        [string]$param2,
    
        [parameter(Mandatory)]
        [string]$param3
    )
    
    .....
    
}

.....

function letzteFunktion
{
    param( .... )
    ...
    ...
}

Main -param1 $param1 -param2 $param2 -param3 $param3                 

Das funktioniert alles auch wie gewünscht.

Problem ist nur: sobald in der Batch-Datei einer der zu übergebenen String-Parameter ein Leerzeichen enthält, z.B "Wert 3" statt "Wert_3" stürzt die Powershell-Verarbeitung ab:

es wurde kein Positionsparameter gefunden, der das Argument "3" akzeptiert.
+CategorieInfo: InvalidArgument: ( : ) [script.ps1], ParentConstrainsErrorRecordException
+FullyQualifiedErrorId: PositionalParameterNotFound, script.ps1

Leider hilft ein einfaches Gänsefüsschen an der Stelle nichts...
.....
START powershell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File "c:\test\script.ps1" -param1 "Wert_1" -param2 "Wert_2" -param3 'Wert 3''   -Wait -NoNewWindow}"  
.....

Bitte um hilfreiche Hinweise, danke schön.
mayho33
Lösung mayho33 28.01.2020 aktualisiert um 18:10:33 Uhr
Goto Top
Zitat von @Herbstengel:

Hallo,

Hi,

A) Deine Parameter haben eine Fehler:
Madatory sollte explizit sein, spricht TRUE oder FALSE
[CmdletBinding()]
Param 
(
    [Parameter(Mandatory=$false)][string]$param1,
    [Parameter(Mandatory=$false)][string]$param2,
    [Parameter(Mandatory=$false)][string]$param3
)

B) -ExecutionPolicy Bypass ist das Commando für Powershell.exe. Das musst du VOR -Command setzen

C) Warum setzt du vor -ExecutionPolicy ein einfaches Anführungszeichen in deinem Beispiel? Das kann nicht hinhauen

D) ein Argument mit Leerzeichen muss entweder zwischen einfachen oder doppelten Anführungszeichen sitzen.

E) Warum so ein komplizierter Aufruf?? Geht so doch viel einfacher:

Test.ps1
[CmdletBinding()]
Param 
(
	[Parameter(Mandatory=$false)][string]$param1,
    [Parameter(Mandatory=$false)][string]$param2,
    [Parameter(Mandatory=$false)][string]$param3
)

BEGIN {
    if([string]::IsNullOrEmpty($param1))
    {
        $param1 = ""  
    }

    if([string]::IsNullOrEmpty($param2))
    {
        $param2 = ""  
    }

    if([string]::IsNullOrEmpty($param3))
    {
        $param3 = ""  
    }
}

PROCESS {
    #nested methodes

    $result = Main -param1 $param1 -param2 $param2 -param3 $param1

    Function Main()
    {
        Param 
        (
	        [Parameter(Mandatory=$false)][string]$param1,
            [Parameter(Mandatory=$false)][string]$param2,
            [Parameter(Mandatory=$false)][string]$param3
        )

        ...
        ...

        return second -param1 $param1 -param2 $param2 -param3 $param1
    }

    Function Second()
    {
        Param 
        (
	        [Parameter(Mandatory=$false)][string]$param1,
            [Parameter(Mandatory=$false)][string]$param2,
            [Parameter(Mandatory=$false)][string]$param3
        )
        ...
        ...
    }
}
END {
    #final doings like return a value
    return $result
}

Call aus der CMD:
Powershell.exe -ExecutionPolicy Bypass -File "<Pfad zur PS1>" -param1 "das ist der erste Streich" -param2 "und nochmal mit LZ" -param3 OhneLZ  

Grüße!

EDIT:

ein Start-Process mit mehr Kontrolle innerhalb einer Methode kannst du so anlegen:

$pinfo                        = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName               = $FilePath
$pinfo.RedirectStandardError  = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.CreateNoWindow         = $true
$pinfo.WindowStyle            = ([System.Diagnostics.ProcessWindowStyle]::Hidden)
$pinfo.UseShellExecute        = $false
$pinfo.Arguments              = $ArgumentList
$p                            = New-Object System.Diagnostics.Process
$p.StartInfo                  = $pinfo

$p.Start() | Out-Null

Auf das Ende des Processes warten erreichst du mit:

$p.WaitForExit

oder mit einer Schleife nach dem Aufruf:

$p.Start() | Out-Null

$ProResult   = Get-Process -Id $p.Id -ErrorAction SilentlyContinue

while( (($ProResult).HandleCount -gt 0) -or ($ProResult -ne $null) )
{
    Start-Sleep -Milliseconds 200
    try{
    $ProResult   = Get-Process -Id $p.Id -ErrorAction SilentlyContinue
    }
    catch{$ProResult = $null}
}

Den Return von $p bekommst du dann so:
return $p.ExitCode
Herbstengel
Herbstengel 29.01.2020 aktualisiert um 09:42:36 Uhr
Goto Top
Hallo mayhoo33,

danke für Deinen Vorschlag. Hab Deinen Code noch etwas umgestellt (u.a. MAIN-Aufruf $result = Main -param1 $param1 -param2 $param2 -param3 $param3 unter alle Funktionsdefinitionen, alle Übergabeparameter sind verpflichtend...)

So funktioniert es nun:

[CmdletBinding()]
Param 
(
	[Parameter(Mandatory=$true)][string]$param1,
    [Parameter(Mandatory=$true)][string]$param2,
    [Parameter(Mandatory=$true)][string]$param3
)

BEGIN {
    if([string]::IsNullOrEmpty($param1))
    {
        $param1 = ""  
    }

    if([string]::IsNullOrEmpty($param2))
    {
        $param2 = ""  
    }

    if([string]::IsNullOrEmpty($param3))
    {
        $param3 = ""  
    }
}

PROCESS {
    #nested methodes

    Function Main()
    {
        Param 
        (
	        [Parameter(Mandatory=$true)][string]$param1,
            [Parameter(Mandatory=$true)][string]$param2,
            [Parameter(Mandatory=$true)][string]$param3
        )

        Read-host "in Function MAIN() drin"  

        Write-Host $param1
        Write-Host $param2
        Write-Host $param3

<#
        ...
        ...
#>

Read-host "gleich ruft Function MAIN() die Function Second() auf"  

        return second -param1 $param1 -param2 $param2 -param3 $param3
    }

    Function Second()
    {
        Param 
        (
	        [Parameter(Mandatory=$true)][string]$param1,
            [Parameter(Mandatory=$true)][string]$param2,
            [Parameter(Mandatory=$true)][string]$param3
        )



        Read-host "jetzt in Function Second() drin"  

        Write-Host $param1
        Write-Host $param2
        Write-Host $param3

<#
        ...
        ...
#>

Read-host "gleich aus Function Second() und wegen dem return in Funktion MAIN aus Funktion MAIN() und damit ganz aus dem Skript draussen"  

    }

    $result = Main -param1 $param1 -param2 $param2 -param3 $param3
    #Main -param1 $param1 -param2 $param2 -param3 $param1
}
END {
    #final doings like return a value
    return $result
}

Was genau meinst Du mit ein Start-Process mit mehr Kontrolle innerhalb einer Methode kannst du so anlegen:

Löst das diesen Code dann ab

...
    }

    $result = Main -param1 $param1 -param2 $param2 -param3 $param3
    #Main -param1 $param1 -param2 $param2 -param3 $param1
}
END {
    #final doings like return a value
    return $result
}

und ist Dein Code dann innerhalb der MAIN-Funktion anzulegen?

Grüße, Roger!
mayho33
mayho33 29.01.2020 um 10:14:32 Uhr
Goto Top
Zitat von @Herbstengel:

Was genau meinst Du mit ein Start-Process mit mehr Kontrolle innerhalb einer Methode kannst du so anlegen:

Löst das diesen Code dann ab

Nein! Das löst den Code nicht ab. Du hast in deinem vorherigen Post mit - Command ein Start-Process angestoßen.

Das war natürlich Nonsens. Ich wollte dir nur zeigen wie du einen Parameter übergeben kannst, wenn du einen Prozess (z. B. Ein Setup) mit bestimmten Bedingungen anstoßen willst.