Folyamatok

Korábban már találkozhattunk a Get-Process és a Get-Service cmdlettel, amelyek segítségével a rendszerfolyamatok és a szolgáltatások listáját kérhetjük le. A folyamatokkal és szolgáltatásokkal kapcsolatban azonban nem csak listázást, hanem bármilyen más feladatot is elvégezhetünk a PowerShell cmdletjeivel, illetve ha minden kötél szakad, közvetlenül a megfelelő .NET komponensek segítségével.

Először is nézzük meg, hogy milyen cmdleteket használhatunk a folyamatok kezelésére:

[75] PS C:\> Get-Command -noun process

 

CommandType     Name                            Definition

-----------     ----                            ----------

Cmdlet          Debug-Process                   Debug-Process [-Name] <Stri...

Cmdlet          Get-Process                     Get-Process [[-Name] <Strin...

Cmdlet          Start-Process                   Start-Process [-FilePath] <...

Cmdlet          Stop-Process                    Stop-Process [-Id] <Int32[]...

Cmdlet          Wait-Process                    Wait-Process [-Name] <Strin...

Négy cmdlet került a listába. A Debug-Process a paraméterként megadott processzhez tartozó debuggert nyitja meg, igazából fejlesztőknek szánt cmdlet ez.

A Start-Process  segítségével lehet újabb folyamatokat indítani. Például nézzük meg a Notepad.exe indítását:

[1] PS C:\> Start-Process notepad.exe

Ez így nem mutat túl sokat, akár így is elindíthattam volna:

PS C:\> notepad

Ez a megoldás valóban egyszerű, azonban korántsem egyenértékű az előzővel. Merthogy a Start-Process-nek további paramétereket is megadhatunk:

[2] PS C:\> Start-Process notepad.exe -ArgumentList C:\fájl.txt -PassThru

 

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName

-------  ------    -----      ----- -----   ------     -- -----------

     57       7     1256       5144    72     0,19   3176 notepad

A -PassThru paraméterrel visszakapjuk az elindított processz adatait. Ez ahhoz kell nekünk, hogy például pontosan ezt a processzt tudjuk a Stop-Process  segítségével bezárni, mert név alapján a Stop-Process minden adott nevű folyamatot bezár:

[3] PS C:\> stop-process -name "notepad"

Ha tudjuk a processz azonosítóját, akkor a Wait-Process  segítségével várakozhatunk annak befejeződéséig:

[4] PS C:\> Wait-Process -Id 3176

Sajnos a processzek indítása csak helyi gépen történhet. Távoli gépeken próbálkozhatunk az Invoke-Command segítségével:

[5] PS C:\> Invoke-Command -ComputerName member -ScriptBlock {start-process not

epad}

Ezzel az a baj, hogy nem az éppen bejelentkezett felhasználó desktop felületén nyílik meg az alkalmazás, hanem háttérben, így nem sok minden látszik belőle. Konkrétan a Notepad le is áll. Egy másik módszer a távoli indításra a WMI-n keresztül:

[5] PS C:\> Invoke-WmiMethod -Path Win32_Process -Name create -ArgumentList not

epad.exe -ComputerName member

 

 

__GENUS          : 2

__CLASS          : __PARAMETERS

__SUPERCLASS     :

__DYNASTY        : __PARAMETERS

__RELPATH        :

__PROPERTY_COUNT : 2

__DERIVATION     : {}

__SERVER         :

__NAMESPACE      :

__PATH           :

ProcessId        : 1124

ReturnValue      : 0

Ez ugyanúgy háttérben futtatja a processzt, így itt sem érdemes grafikus alkalmazásokkal játszani, csak olyan folyamatokat indítsunk, amelyek nem igényelnek ablakot, például ilyenek általában a parancssori eszközök.

Ki indította a folyamatot?

Se a Get-Process, se a WMI nem adja meg, hogy kinek a nevében fut a folyamat. Viszont a WMI segítségével ez lekérdezhető a process GetOwner metódusa segítségével:

PS C:\> (Get-WmiObject -Class Win32_process -Filter "Name = 'notepad.exe'").get

owner().user

soost

PS C:\> $owner = (Get-WmiObject -Class Win32_process -Filter "Name = 'notepad.e

xe'").getowner()

PS C:\> $owner.domain + "\" + $owner.user

IQJB\soost

Folyamatok szelíd és erőszakos megszakítása

A folyamatokat, azaz a futó programokat bezárhatjuk „szelíden”, azaz az éppen módosított dokumentum elmentését lehetővé tehetjük a felhasználónak. Ezt a következőképpen tehetjük meg:

PS C:\> (Get-Process notepad).CloseMainWindow()

True

Ez – tapasztalatom szerint –mindenképpen „True” értéket ad vissza, függetlenül attól, hogy sikerült-e bezárni az alkalmazást, vagy pedig a felhasználó beavatkozására vár.

Erőszakos bezárás történhet a korábban már látott Stop-Process cmdlettel, vagy a Process objektum Close vagy Kill metódusával. A Kill-el vigyázzunk, mert ennek hatására az alkalmazás által éppen írt fájlok sérülhetnek.

Folyamatok futtatása emelt szintű jogosultságokkal

Windows 7-től kezdődően hiába vagyunk rendszergazdaként, az általunk futtatott folyamatok nem futnak „igazi” rendszergazda jogkörrel, kilistázva a privilégiumokat, a lista elég rövidke:

 

PS C:\> whoami /priv

 

PRIVILEGES INFORMATION

----------------------

 

Privilege Name                Description                          State

============================= ==================================== ========

SeShutdownPrivilege           Shut down the system                 Disabled

SeChangeNotifyPrivilege       Bypass traverse checking             Enabled

SeUndockPrivilege             Remove computer from docking station Disabled

SeIncreaseWorkingSetPrivilege Increase a process working set       Disabled

SeTimeZonePrivilege           Change the time zone                 Disabled

Ha ténylegesen „Run as Administrator” módon futtatjuk a PowerShellt, akkor a lista jóval hosszabb:

PS C:\> whoami /priv

 

PRIVILEGES INFORMATION

----------------------

 

Privilege Name                  Description                              

State

=============================== ========================================= ========

SeIncreaseQuotaPrivilege        Adjust memory quotas for a process        Disabled

SeSecurityPrivilege             Manage auditing and security log          Disabled

SeTakeOwnershipPrivilege        Take ownership of files or other objects  Disabled

SeLoadDriverPrivilege           Load and unload device drivers            Disabled

SeSystemProfilePrivilege        Profile system performance                Disabled

SeSystemtimePrivilege           Change the system time                    Disabled

SeProfileSingleProcessPrivilege Profile single process                    Disabled

SeIncreaseBasePriorityPrivilege Increase scheduling priority              Disabled

SeCreatePagefilePrivilege       Create a pagefile                         Disabled

SeBackupPrivilege               Back up files and directories             Disabled

SeRestorePrivilege              Restore files and directories             Disabled

SeShutdownPrivilege             Shut down the system                      Disabled

SeDebugPrivilege                Debug programs                            Enabled

SeSystemEnvironmentPrivilege    Modify firmware environment values        Disabled

SeChangeNotifyPrivilege         Bypass traverse checking                  Enabled

SeRemoteShutdownPrivilege       Force shutdown from a remote system       Disabled

SeUndockPrivilege               Remove computer from docking station      Disabled

SeManageVolumePrivilege         Perform volume maintenance tasks          Disabled

SeImpersonatePrivilege          Impersonate a client after authentication Enabled

SeCreateGlobalPrivilege         Create global objects                     Enabled

SeIncreaseWorkingSetPrivilege   Increase a process working set            Disabled

SeTimeZonePrivilege             Change the time zone                      Disabled

SeCreateSymbolicLinkPrivilege   Create symbolic links                     Disabled

Ha egy processzt akarunk emelt szintű jogosultsággal futtatni, akkor a Start-Process-nek a -Verb paraméterét használva tudjuk ezt megtenni:

PS C:\> Start-Process -FilePath notepad -Verb runas

Sajnos ez, ha az UAC beállításaink megfelelően szigorúak, megerősítést fog kérni, hogy tényleg akarjuk-e. Azaz ezzel nem feltétlenül tudunk automatikusan futtatni processzeket.

Processzek futtatása szinkron módon, kimenetek rögzítése

A StackOverflow oldalon találtam a következő szkriptet, amivel nagyon profin tudunk úgy processzeket indítani, hogy a PowerShell megvárja a processz futását és minden lényeges információt visszaad:

function Invoke-Executable {

    # Runs the specified executable and captures its exit code, stdout

    # and stderr.

    # Returns: custom object.

    param(

        [Parameter(Mandatory=$true)]

        [ValidateNotNullOrEmpty()]

        [String]$sExeFile,

        [Parameter(Mandatory=$false)]

        [String[]]$cArgs,

        [Parameter(Mandatory=$false)]

        [String]$sVerb

    )

 

    # Setting process invocation parameters.

    $oPsi = New-Object -TypeName System.Diagnostics.ProcessStartInfo

    $oPsi.CreateNoWindow = $true

    $oPsi.UseShellExecute = $false

    $oPsi.RedirectStandardOutput = $true

    $oPsi.RedirectStandardError = $true

    $oPsi.FileName = $sExeFile

    if (! [String]::IsNullOrEmpty($cArgs)) {

        $oPsi.Arguments = $cArgs

    }

    if (! [String]::IsNullOrEmpty($sVerb)) {

        $oPsi.Verb = $sVerb

    }

 

    # Creating process object.

    $oProcess = New-Object -TypeName System.Diagnostics.Process

    $oProcess.StartInfo = $oPsi

 

    # Creating string builders to store stdout and stderr.

    $oStdOutBuilder = New-Object -TypeName System.Text.StringBuilder

    $oStdErrBuilder = New-Object -TypeName System.Text.StringBuilder

 

    # Adding event handers for stdout and stderr.

    $sScripBlock = {

        if (! [String]::IsNullOrEmpty($EventArgs.Data)) {

            $Event.MessageData.AppendLine($EventArgs.Data)

        }

    }

    $oStdOutEvent = Register-ObjectEvent -InputObject $oProcess `

        -Action $sScripBlock -EventName 'OutputDataReceived' `

        -MessageData $oStdOutBuilder

    $oStdErrEvent = Register-ObjectEvent -InputObject $oProcess `

        -Action $sScripBlock -EventName 'ErrorDataReceived' `

        -MessageData $oStdErrBuilder

 

    # Starting process.

    [Void]$oProcess.Start()

    $oProcess.BeginOutputReadLine()

    $oProcess.BeginErrorReadLine()

    [Void]$oProcess.WaitForExit()

 

    # Unregistering events to retrieve process output.

    Unregister-Event -SourceIdentifier $oStdOutEvent.Name

    Unregister-Event -SourceIdentifier $oStdErrEvent.Name

 

    $oResult = New-Object -TypeName PSObject -Property ([Ordered]@{

        "ExeFile"  = $sExeFile;

        "Args"     = $cArgs -join " ";

        "ExitCode" = $oProcess.ExitCode;

        "StdOut"   = $oStdOutBuilder.ToString().Trim();

        "StdErr"   = $oStdErrBuilder.ToString().Trim()

    })

 

    return $oResult

}

A kimeneti objektumban láthatjuk a kilépési kódot, a folyamat standard kimenetét, a hibafolyamot is. Amivel még lehetne fejleszteni ezt, az egy timeout paraméter, ami behatárolná, hogy a processz maximum mennyi ideig futhat.



Word To HTML Converter