[PowerShell] "(foo).bar" anders interpretieren & andere workarounds

zeddler

Neues Mitglied
hallo.

ich habe ein befehl:
Code:
(Get-Partition -DriveLetter C).DiskNumber
die ausgabe ist:

meine frage:
wie kann man diesen befahl ohne klammern darstellen?

ich habe es schon versucht:
Code:
Get-Partition -DriveLetter C | Format-List DiskNumber
<LeerZeile>
<LeerZeile>

DiskNumber : 0
<LeerZeile>
<LeerZeile>
<LeerZeile>

ich würde schon gern wissen ob powerschell für "(foo).bar" einen eigenen befehl dafür hat.

vielen dank.
 
Sollte mit Select-Object machbar sein
Get-Partition -DriveLetter C | Select-Object -ExpandProperty DiskNumber
 
oh! das ist interessant.

gibt es auch eine möglichkeit, zusätzlich ohne pipe das darzustellen?
oder kommt man hier an die grenzen?
mir wäre es egal, wenn der befehl sehr lang wird.
$variablen würde ich auch gern vermeiden.
 
Naja, Pipe von Objekten ist das sprachliche Mittel der Wahl in der PowerShell. Ohne geht's halt mit dem Member-Access-Operator alias Punkt. Aber das tendiert schon wieder Richtung C#.NET und das zu vermeiden war ja nun genau deine Frage ;) Also, Pipe ist PowerShell Style. Da ist in aller Regel nicht viel anders zu machen. Natürlich kannst du immer noch mit Stringmanipulation rumhantieren, wie Regex und ähnlichem, um deine Zahl aus der Gesamtausgabe zu extrahieren. Da kommst du aber vom Regen in die Traufe was Performance und Ressourcenverschwendung angeht.

Ich mach nicht viel mit PowerShell, aber ich stell mir ehrlich gesagt auch immer die Frage wie viel Overhead-Code hinter den Kulissen ausgeführt wird, um die Pipe für die jeweiligen Objekte zu implementieren. Im Zweifel bin ich auch schnell mal dabei, die .NET Objekte direkt anzusprechen. Das ist dann auch eine Syntax mit der ich mich wohler fühle und die ich besser verstehe als die Unart in PowerShell möglichst alles in eine Zeile zu quetschen, wenn's geht mit 10 Pipes in Reihe :LOL: Das ist für mich einfach nur komplett unlesbarer Mist...
 
nene. sind eh nur spielereien.
die dienen nur als konzept, wenn ich mal einen workaround basteln muss.
gegen die sprache ist sicher nicht so gedacht, aber "Stringmanipulation, wie Regex" klingt interessant.
kannst du ein beispiel mal konstroieren?
 
Für die Nachwelt - das ist ein absolutes Negativbeispiel.
(Get-Partition -DriveLetter C | Out-String -Stream | Select-String "^\d+").Matches[0].Value
Nein, sorry, funktioniert nicht für dein Exempel, da DiskNumber gar nicht zur Standardausgabe gehört (hatte ich mir im Vorfeld nicht angesehen). Statt dessen bekommst du so die PartitionNumber Eigenschaft, auf die umständlichste Weise die mir einfällt.
 
naja egal.

weil ich ja ger workarounds suche...
primär für übergaben von batch <--> powershell

ich wollte ein powershell in eine batch variable speichern und ausführen:

Code:
set "xVar=(Get-Partition -DriveLetter C).DiskNumber"
powershell -command "$Env:xVar"

aber er zeigt mir nur die codezeile an, statt diese auszuführen
 
Lass mich doch nicht zappeln und sag gleich was du vorhast :D
So wie du das denkst wird es niemals funktionieren. Umgebungsvariablen werden immer vom Eltern- zum Kindprozess vererbt. Eine Änderung der Umgebung im Kindprozess wird nie eine Änderung der Umgebung im Elternprozess nach sich ziehen.

Also, funktioniert nur wenn du die PowerShell in einer FOR /F Schleife in deinem Batch Script ausführst um die Ausgabe zu parsen, à la
Batch:
@echo off &setlocal
for /f %%i in ('powershell -nop -ep Bypass -c "Get-Partition -DriveLetter C | Select-Object -ExpandProperty DiskNumber"') do set "disk=%%i"
echo Disk number is %disk%.
pause
 
Lass mich doch nicht zappeln und sag gleich was du vorhast
das weiß ich selber nicht.
z.Z. überlege ich nur welche probleme ich mal hatte.
z.Z. keine festen projekte, alles läuft... :D

zurück zum thema:
naja, ne for-schleife habe ich schon. :sneaky:
mein gedanke ist der:
- ich erstelle eine batch-variable
- powershell kann diese fehlerfrei auslesen
...es fehlt nur noch der letzte schritt, diese auszuführen... :unsure:

p.s.
ja das Eltern/Kind-problem ist mir bewusst.
ich geh jedes problem erstmal einzeln an.
diese "module" erwiesen sich meist dann für andere aufsgaben als nützlich ( --> ab ins archiv.)
die ausgabe interessiert erstmal nicht.
wobei man es vielleicht mit einer globalen systemvariable lösen könnte...
...solange es keine adminrechte erfordert...


/ot: perfomence
ich arbeite gern mit batch für kleine & kleinst aufgaben,
da bis eine powershell instanz mal losarbeitet, vergehen jahre im vergleich zu batch.
besonders ärger ich mich, dass jeder batch-powershell-befehl quasi eine neue instanz erstellt.
ich kann zwar teile teiweise zeitgleich ablaufen lassen, aber existiert eine abhänigkeiten,
dann wartet das script wieder auf powershell.

komplett auf powershell umzusteigen lohnt nicht bei mir,
dazu ist der leidensdruck noch nicht groß genug... 😆
 
Hmpf, Powershell ist der Kindprozess. Eine Umgebungsvariable die im cmd.exe Prozess erstellt wurde, bevor dieser den PowerShell.exe Prozess spawnt, ist problemlos abgreifbar.
Batch:
@echo off &setlocal
set "mydrive=C"
for /f %%i in ('powershell -nop -ep Bypass -c "Get-Partition -DriveLetter $env:mydrive | Select-Object -ExpandProperty DiskNumber"') do set "disk=%%i"
echo Disk number is %disk%.
pause
An der Tatsache dass es etwas dauert, bis die PowerShell die ganzen Abhängigkeiten lädt, ändert das natürlich nichts. Bisschen Zeit lässt sich sparen, wenn Assemblies vorkompiliert sind. Kannst du mit diesem kleinen Script tun:
Batch:
@if (@a)==(@b) @end /*
@echo off &setlocal EnableExtensions DisableDelayedExpansion
>nul 2>&1 net.exe session || (
  cscript.exe //nologo //e:jscript "%~fs0"
  exit /b
)

powershell.exe -nop -ep Bypass -c ^"^
$Env:Path=[Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory();^
[AppDomain]::CurrentDomain.GetAssemblies() ^| %% {^
  if (-not $_.Location) {continue};^
  Write-Host -ForegroundColor Cyan ('Compiling ' + (Split-Path -Leaf $_.Location));^
  ngen.exe install $_.Location;^
  '';^
}^"

pause

goto :eof */ WScript.CreateObject('Shell.Application').ShellExecute('cmd.exe', ' /c ""' + WScript.ScriptFullName + '""', '', 'runas', 1);
Muss aber bei jedem .NET Update das reinflattert wiederholt werden ...
 
Powershell ist der Kindprozess. Eine Umgebungsvariable die im cmd.exe Prozess erstellt wurde,
bevor dieser den PowerShell.exe Prozess spawnt, ist problemlos abgreifbar.
ja soweit waren wir ja schon.
jetzt fehlt nur noch >wie< man eine variable ausführt, ohne eine forschleife zu basteln.

das ist ja was mich stört. der befehl kann gelesen werden,
nur was fehlt, ist diese dann auch auszuführen.
muss man die variable vielleicht konvertieren?

wenn ich die variable in powershell setze verhält diese sich anders...
Code:
$xPS1 = (Get-Partition -DriveLetter C).DiskNumber

wenn ich diese anders abspeichere, dann verhält sie sich wie eine $env:*-variable
Code:
$xPS2 = "(Get-Partition -DriveLetter C).DiskNumber"
(Get-Partition -DriveLetter C).DiskNumber

also müsste ich die zweite variable in die erste variable umwandeln.
 
Geht nicht. Du kannst nicht davon ausgehen dass die cmd.exe ein PowerShell CmdLet ausführt. Das kann nun mal nur ein PowerShell Prozess. Und wie gesagt, was auch immer mit einer Umgebungsvariable im PowerShell.exe Prozess gemacht wird, hat keine Wirkung auf den cmd.exe Prozess. Änderungen der Umgebung im Child-Prozess sind im Parent-Prozess nicht abgreifbar. Das ist eine Einbahnstraße. Umgekehrt geht nur über Workarounds wie DLL-Injection, wo ein Prozess in den Speicherbereich eines anderen schreibt. Da bist du dann schon ziemlich nah an einem Virus.
 
naja die powershell eingabe, ist für mich erstmal auch nur text.
nur wird dieser ausgeführt.
meine variable (vergiss mal cmd) liegt jetzt auch als string vor.
jetzt müsste diese so verarbeitet werden, dass diese wieder funktioniert.
 
Du willst einen String als PowerShell Kommando ausführen? Invoke-Expression
Batch:
@echo off &setlocal
set "myCmd=(Get-Partition -DriveLetter C).DiskNumber"
powershell -nop -ep Bypass -c "Invoke-Expression $env:myCmd"
pause
 
Zuletzt bearbeitet:
hmmm...
mir gehen meine verrückten ideen aus.
so eine schnelle problemlösung hatte ich noch nie... :D

wenn du mal eine (hardcore) aufgabe willst,
die man eigendlich nicht braucht

dynamisch generierte verschachtelte variablen,
also variablen in variablen, die sich erst langsam auflösen... 😆

ich hab das mal in batch umgesetzt
muss mal schauen ob ich es noch finde... 😰

Code:
for   /F "tokens=1* delims==" %%a in ('findstr /b "!%xPf%e01!ext" "%xCfg%"') do call set xExt=%%b
Code:
 call cmd /c echo. for /F "tokens=1* delims==" %%%%a in ('findstr /b "%%%%%%xPf%%s0%%xCount%%%%%%" "%xCfg%"') do call echo.%%%%b

aber frag mich nicht wie das funktioniert hatte,
das/die strings/scripte versteh ich selbst nicht mehr und bereiten mir nur noch kopfschmerzen
ich habe es seitdem auch nicht mehr angefasst...

heute bastel ich sowas lieber neu und viel simpler.

aber das wichtigste... es ist machbar und hatte funktioniert... XD
 
Zuletzt bearbeitet:
Haha, nee mit sowas hab ich kein Problem. Das hab ich vollständig verstanden ;)
Batch:
@echo off &setlocal
set "a=b"
set "b1=c"
set "c=4711"
call call echo %%%%%%%a%1%%%%%%
pause
 
ja, ich weiß. man darf sich nicht verzählen... XD
und wie kann man sowas in powershell umsetzen?

ich hatte mir variablen erstellt, die ich von 1 bis 1000 abfragen konnte indem ich einfach nur
ein, loop + counter + for-schleife gebastelt habe
statt 1000 mal eine forschleife zu copy/pasten und den wert anzupassen...
 
Code:
$foo="bar"
$bar="baz"
(Get-Variable $foo).Value
Das ist so ähnlich gelagert wie deine vorherige Aufgabe. In diesem Fall soll ein String als Variablenname interpretiert werden. Zumindest denke ich dass du das meinst. Andererseits klingt sowas wie "1 bis 1000" auch schon wieder nach einem Array :unsure:
 
Zurück
Oben Unten