none
Mit Powershell CMD öffnen und Befehle abarbeiten RRS feed

  • Allgemeine Diskussion

  • Hallo Zusammen,

    ich stehe leider vor einem Problem, dass ich nicht gelöst bekomme.

    Ich möchte mit Powershell CMD öffnen und dort ein weiteres Programm mit Befehlen starten. Das klappt leider nicht so wie ich es gerne hätte...

    $Location = Get-Location

    $PathLenovoTool = "$Location"+"\ThinkBiosConfig.hta"

    $BIOSFile = "file=ThinkPadBiosConfig"+"$Name"+".ini" "key=secretkey"' Start-Process cmd.exe -ArgumentList "/c $Path_Lenovo_Tool $BIOSFile" -NoNewWindow -Wait Write-Host "Die BIOS-Settings wurden gefunden"

    Mein Problem besteht darin, dass die Varibale $BIOSFile als Text übergeben wird, sprich es wird in der Konsole nicht die Datei ausgegeben, die ich übergeben will sondern wirklich die Variable als Text. Ich denke das liegt an dern Anführungszeichen.

    Leider weiß ich aber nicht, wie ich die Variable auch als solche übergeben kann, also als Pfad.

    Ich hoffe hier im Forum kann mir geholfen werden.

    Viele Grüße

    Michael

    Montag, 22. November 2021 10:29

Alle Antworten

  • Hallo erstmal und willkommen im deutschen MSFT Windows PowerShell Forum.

    Du möchtest also eine Kommandozeile aus einer anderen Kommandozeile starten, die dann ein externes Programm startet, richtig?  ;-)  Warum nicht gleich nur eine davon benutzen?

    Davon unabhängig ist mir nicht klar, was Du als Argument übergeben möchtest. $Name wird in dem Code, den Du gepostet hast nicht definiert. 

    Wie genau würde die Kommandozeile denn aussehen, die Du gestartet haben möchtest?


    Live long and prosper!

    (79,108,97,102|%{[char]$_})-join''

    • Bearbeitet BOfH-666 Montag, 22. November 2021 12:08
    Montag, 22. November 2021 12:07
  • Hallo und vielen Dank für deine Antwort :)

    $Name wird durch die folgende Funktion übergeben:

    function Get_HardwareInformation
    {
        [hashtable]$Return = @{}
        $Vendor = Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object  -ExpandProperty Vendor
        $Version = Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object  -ExpandProperty Version
        $Name = Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object  -ExpandProperty Name
        
        $Return.Vendor = $Vendor
        $Return.Version = $Version
        $Return.Name = $Name
            
        return $Return 
    }

    Danach wird später hier an der Stelle $Name aufgerufen:

    $Location = Get-Location
    $PathLenovoTool = "$Location"+"\ThinkBiosConfig.hta"
    $Result = Get_HardwareInformation
    $Name = $Result.Get_Item("Name")
    
    $BIOSFile = '"file=ThinkPadBiosConfig"+"$Name"+".ini"' "key=secretkey"'                       
                          
    $NewFile = '"file='$Name'" "key=secretkey"'
    Start-Process cmd.exe -ArgumentList "/c ThinkBiosConfig.hta $NewFile" -NoNewWindow -Wait

    Tatsächlich mache ich dies so, da ich diese Lösung auf der Lenovo Seite zu ihrem Script vorgeschlagen bekomme. Allerdings ist in ihrem Beispiel $Name direkt als Datei angegeben:

    $tag = "$($env:ProgramData)\Lenovo\ThinkBiosConfig\ThinkBiosConfig.tag"
    $arg = '"file=ThinkPadBiosConfig.ini" "key=secretkey"'
    $log = '"log=%ProgramData%\Lenovo\ThinkBiosConfig\""'
    
    try {
        if (!(Test-Path -Path $tag -PathType Leaf)) {
            Write-Host "Creating TBCT directory..."
            New-Item -ItemType File -Path $tag -Force -ErrorAction Stop
            Set-Content -Path $tag -Value "Bios Settings Configured"
            Write-Host "Tag file created..."
    
            Start-Process cmd.exe -ArgumentList "/C ThinkBiosConfig.hta $arg $log" -NoNewWindow -Wait
            Write-Host "Bios Settings Configured"
            Exit 3010
        }
        else {
            Write-Host "Bios Settings already configured..."
            Exit 0
        }
    }
    catch [System.IO.IOException] {
        Write-Host "$($_.Exception.Message)"
    }
    catch {
        Write-Host "$($_.Exception.Message)"
    }

    Mein Problem ist jetzt halt, dass $Name nicht aufgelöst wird.

    Ich muss an der Stelle mit einer Variable arbeiten, da sich der Dateiname immer ändert und anhand der ausgelesenen Hardwareinformation identifizieren kann.

    Falls es einen leichteren Weg gibt, bin ich offen für Vorschläge :)



    • Bearbeitet Fixxer_182 Montag, 22. November 2021 13:17
    Montag, 22. November 2021 13:15
  • ... hab's grad nur überflogen ... die erste Funktion schreibt man besser so:

    function Get-HardwareInformation {
        $ComputerSystemProduct = Get-CimInstance -ClassName Win32_ComputerSystemProduct
        [PSCustomObject]@{
            Vendor  = $ComputerSystemProduct.Vendor
            Version = $ComputerSystemProduct.Version
            Name    = $ComputerSystemProduct.Name
        }
    }

    ... den Rest schau ich mir nachher an ... 

    Kannst Du bitte nochmal posten, wie genau die endgültige Kommandozeile aussehen sollte? Also so, wie man sie z.B. in der CMD manuell starten würde.

    Danke schon mal im Voraus


    Live long and prosper!

    (79,108,97,102|%{[char]$_})-join''

    Montag, 22. November 2021 16:13
  • So ... weiter geht's ...  ;-) 

    $Location = Get-Location
    $PathLenovoTool = "$Location" + "\ThinkBiosConfig.hta"

    ... ist nicht falsch ... funktioniert ... geht aber kürzer ... und die Gänsefüsschen um die Variablen kannst Du in den meisten Fällen weglassen ... liest sich leichter. ;-) 

    PowerShell erzeugt beim Aufruf eines Skriptes eine automatische Variable $PSScriptRoot, die Du für sowas verwenden kannst. Und da Variablen in doppelten Anführungszeichen erweitert werden, brauchst Du auch kein Plus dazwischen, sondern kannst die Variable einfach als Teil des Strings verwenden.

    $PathLenovoTool = "$($PSScriptRoot)\ThinkBiosConfig.hta"

    Eine weitere Möglichkeit einen validen Pfad zusammenzubauen ist, das cmdlet Join-Path. ;-)

    Mit der neuen Funktion zum Ermitteln der Hardware-Info aus meiner Antwort oben, ändern sich die folgenden beiden Zeilen von:

    $Result = Get_HardwareInformation
    $Name = $Result.Get_Item("Name")

    zu:

    $Result = Get-HardwareInformation
    $Name = $Result.Name

    Ich würde Dir dringend empfehlen, sich an die Best Practices und Style-Guides zu halten. Das macht Dir und Deinen Kollegen das Leben einfacher, wenn sie die Skripte irgendwann erweitern oder anpassen müssen.

    Hier mal ein bissl Lektüre:

    https://github.com/PoshCode/PowerShellPracticeAndStyle#the-powershell-best-practices-and-style-guide

    In den folgenden beiden Zeilen hast Du entweder jeweils mindestens einen Rhythmus-Fehler drin oder jeweils ein Plus-Zeichen vergessen. 

    $BIOSFile = '"file=ThinkPadBiosConfig"+"$Name"+".ini"' "key=secretkey"'
    $NewFile = '"file='$Name'" "key=secretkey"'

    Wie oben schon erwähnt kann man Variablen einfach als Teil eines Strings (in doppelten Anführungszeichen) angeben - PowerShell erweitert diese dann bei der Ausführung.

    Ich lehn mich mal ein Stück aus dem Fenster und vermute, dass die Optionen wie folgt zusammengebaut werden können:

    $BIOSFile = "file=ThinkPadBiosConfig$($Name).ini key=secretkey"
    $NewFile = "file=$($Name) key=secretkey"

    Die Variablen in Subexpressions ( $() ) zu packen, wäre hier vermutlich nicht nötig gewesen, aber es liest sich meiner Meinung nach leichter und stört nicht. Noch besser .. es macht die zusätzliche Variablenzuweisung für $Name überflüssig, wenn Du es so machst:

    $BIOSFile = "file=ThinkPadBiosConfig$($Result.Name).ini key=secretkey"
    $NewFile = "file=$($Result.Name) key=secretkey"
    So ... ab hier wird es mir zu verworren. ;-)  Wie schon gesagt - Du postest mal bitte, wie die Kommandozeile wirklich aussehen sollte und dann machen wir an der Stelle weiter.


    Live long and prosper!

    (79,108,97,102|%{[char]$_})-join''

    • Bearbeitet BOfH-666 Montag, 22. November 2021 23:25
    Montag, 22. November 2021 23:21
  • Guten Morgen :-)

    Erstmal: WOW!

    Danke dir schon einmal vielmals für deine tatkräftige Unterstützung. Du hast ja schon festgestellt, dass ich mit Powershell noch nicht so ganz fit bin und deswegen möchte ich dir für diene Geduld, Hilfe und den Link danken. Ich werde mich dort definitiv heute schon einmal durch wuseln :-)

    $($PSScriptRoot)


    Überall eingefügt, wo zuvor $Location vorhanden war. Die Variable war mir tatsächlich nicht geläufig und innerhalb einer Powershell Schulung wurde mir Get-Location nahe gelegt zu verwenden. Dein Tipp macht es aber deutlich leserlicher :-)

    $Result = Get-HardwareInformation
    $Name = $Result.Name

    Ebenfalls geändert, mir war nicht bewusst, dass das so einfach funktioniert. Im Web hatte ich nur Code gefunden, indem die Klammer mit ("Was auch immer") integriert wurde. Funktioniert - Haken dran :-)

    $BIOSFile = "file=ThinkPadBiosConfig$($Result.Name).ini key=secretkey"
    $NewFile = "file=$($Result.Name) key=secretkey"

    Hier fehlte bei $NewFile ein .ini

    $NewFile = "file=$($Result.Name)ini key=secretkey"

    Daneben war ich irgendwie mit den Anführungszeichen aus dem Lenovo Beispiel dermaßen verwirrt, dass ich es nicht hinbekommen hatte. Jetzt wird die Variable auch richtig übergeben :-)

    Laut meinem Code soll das Tool jetzt lauffähig sein. Muss mir jetzt ein Lenovo Gerät schnappen und es dort testen.

    Aber hier noch, wie das Tool über CMD.exe aufgerufen wird.

    Nur das Tool starten um die GUI anzuzeigen:

    c:\AutoBios>start ThinkBiosConfig.hta


    Ausführung des Tools direkt mit Übergabe der Config, die eingespielt werden soll müsste wie folgt lauten:

    c:\AutoBios>start ThinkBiosConfig.hta "file=C:\AutoBios\Hardware\Modelle\Lenovo P73 Gen2.ini"

    Da Syntax per SCCM-Konfiguration lautet laut Lenovo (kommt bei mir nicht in Frage, da keine Tasksequenz verwendet werden kann/soll:

    cmd.exe /c ThinkBiosConfig.hta "Config.ini"

    Dienstag, 23. November 2021 07:08
  • Hmmm ... gefühlt hast Du mir immernoch nicht die Kommandozeile gepostet, wie sie am Ende komplett aussehen sollte. Einmal hast Du nur eine INI-Datei hinter einem "file=" als Argument, dann wieder zusätzlich noch ein "key=secretkey".

    Im Wesentlichen sollte so etwas Ähnliches wie das hier genügen:

    function Get-HardwareInformation {
        $ComputerSystemProduct = Get-CimInstance -ClassName Win32_ComputerSystemProduct
        [PSCustomObject]@{
            Vendor  = $ComputerSystemProduct.Vendor
            Version = $ComputerSystemProduct.Version
            Name    = $ComputerSystemProduct.Name
        }
    }
    
    $HW = Get-HardwareInformation
    
    Start-Process -FilePath 'C:\Windows\System32\mshta.exe' -ArgumentList "$($PSScriptRoot)\ThinkBiosConfig.hta file=C:\AutoBios\Hardware\Modelle\$($HW.Version).ini" -NoNewWindow -Wait
    Im Zweifel würde ich alle nötigen Dateien in den gleichen Ordner mit einem sehr kurzen Pfad packen und den eventuell noch als "Working-Directory" zusätzlich angeben.


    Live long and prosper!

    (79,108,97,102|%{[char]$_})-join''

    Dienstag, 23. November 2021 20:54
  • Hallo,

    ich lass dir mal das ganze Script hier, dann siehst du besser worum es geht:

    #Code entfernt, ist an sich irrelevant

    Deine Idee lässt leider das LenovoTool abschmieren mit Script Errors seitens Lenovo. Warum weiß ich leider nicht, da du ja nichts anderes machst, als hta direkt zu öffnen statt über die Konsole...

    Laut Lenovo soll die Zeile, die ich versuche in meinem Script ans laufen zu kriegen wie folgt aussehen:

    $arg = '"file=ThinkPadBiosConfig.ini" "key=secretkey"'
    $log = '"log=%ProgramData%\Lenovo\ThinkBiosConfig\""'
    
    Start-Process cmd.exe -ArgumentList "/C ThinkBiosConfig.hta $arg $log" -NoNewWindow -Wait


    • Bearbeitet Fixxer_182 Donnerstag, 25. November 2021 10:09
    Mittwoch, 24. November 2021 14:30
  • .... das komplette Script ignoriere ich jetzt einfach mal ... ;-)

    lässt leider das LenovoTool abschmieren mit Script Errors seitens Lenovo

    Ich gehe davon aus, dass die "Script Errors" Text enthalten, richtig? ;-) Fehlermeldungen sind ein wichtiges Feature. Sie helfen aber nur, wenn man sie auch auswertet ... Fehlermeldungen also immer auch posten (auch als Code formatiert bitte.)

    Wenn die Pfade Leerzeichen enthalten, könnte es noch daran liegen. Du könntest versuchen die Pfade - und nur diese - in doppelte doppelte Anführungszeichen zu packen.

    Laut Lenovo soll die Zeile, die ich versuche in meinem Script ans laufen zu kriegen wie folgt aussehen:

    Warum verwendest Du das ganze eigentlich nicht so, wie Lenovo das empfiehlt?


    Live long and prosper!

    (79,108,97,102|%{[char]$_})-join''

    Mittwoch, 24. November 2021 15:43
  • Guten Morgen,

    den Fehlercode muss ich nachliefern, ich komme heute leider nicht an mein Lenovo Testgerät heran...

    Wenn die Pfade Leerzeichen enthalten, könnte es noch daran liegen.

    Du könntest versuchen die Pfade - und nur diese - in doppelte doppelte Anführungszeichen zu packen.


    Das werde ich ausprobieren :)

    Die Lenovo Empfehlung ist ja wie folgt:

    $tag = "$($env:ProgramData)\Lenovo\ThinkBiosConfig\ThinkBiosConfig.tag"
    $arg = '"file=ThinkPadBiosConfig.ini" "key=secretkey"'
    $log = '"log=%ProgramData%\Lenovo\ThinkBiosConfig\""'
    
    try {
        if (!(Test-Path -Path $tag -PathType Leaf)) {
            Write-Host "Creating TBCT directory..."
            New-Item -ItemType File -Path $tag -Force -ErrorAction Stop
            Set-Content -Path $tag -Value "Bios Settings Configured"
            Write-Host "Tag file created..."
    
            Start-Process cmd.exe -ArgumentList "/C ThinkBiosConfig.hta $arg $log" -NoNewWindow -Wait
            Write-Host "Bios Settings Configured"
            Exit 3010
        }



    Mein Code ist ja nicht viel anders, nur das "file=...." eben als "file=$Variable" vorhanden ist:

     
    elseif ($Vendor -ceq $VendorLenovo) #Ab hier klappt es noch nicht ganz
            {
                Write-Host "Das BIOS-Settings-Tool des Herstellers '$Vendor' wird gestartet..."
                Blank_Lines
    
                $Model = $Return.Name 
                #Einfach halber hier mal: 
                #$Model = Lenovo X12 Detachable Gen 1
                $tag = "E:\Lenovo\ThinkBiosConfig.tag"
                $arg = "file=$($Model).ini key=" #key=Vorzugsweise NULL
                $log = '"log=%ProgramData%\Lenovo\ThinkBiosConfig\""'
    
                if (Test-Path $File)
                {
                    Write-Host "Konfigurationsdatei gefunden..."
                    try 
                    {
                        if (!(Test-Path -Path $tag -PathType Leaf)) #muss evtl weg
                        {
                            Write-Host "LogFile Ordner wird erstellt..."
                            Sleep 1
                            New-Item -ItemType File -Path $tag -Force -ErrorAction Stop
                            Set-Content -Path $tag -Value "Bios Settings Configured"
                            Blank_Lines
                            Write-Host "LogFile erstellt..."
                            Sleep 1
                            Start-Process cmd.exe -ArgumentList "/C ThinkBiosConfig.hta $arg $log" -NoNewWindow -Wait #klappt noch nicht
                            Blank_Lines
                            Write-Host "Die BIOS-Settings wurden für das Modell übernommen."
                            timeout 30
                            Exit 3010
                        } 

    Einziger Unterschied für mich, sieht nach dem Dateinamen aus. Ich denke du könntest also recht haben mit den Leerzeichen im Dateinamen!

    Donnerstag, 25. November 2021 10:08