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-Key: 529320

Url: https://administrator.de/contentid/529320

Printed on: April 28, 2024 at 12:04 o'clock

Member: mayho33
mayho33 Dec 23, 2019 at 19:27:23 (UTC)
Goto Top
Member: Herbstengel
Herbstengel Jan 28, 2020 at 15:43:30 (UTC)
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.
Member: mayho33
Solution mayho33 Jan 28, 2020 updated at 17:10:33 (UTC)
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
Member: Herbstengel
Herbstengel Jan 29, 2020 updated at 08:42:36 (UTC)
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!
Member: mayho33
mayho33 Jan 29, 2020 at 09:14:32 (UTC)
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.