Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to do this in PowerShell

Status
Not open for further replies.

jbarelds

MIS
Aug 5, 2008
30
NL
Hi all,

I'm used to cmd scripting, and struggle to find Powershell counterparts for some common scripting techniques.

Let's examine the following example:
Code:
C:\Windows\System32\inetsrv>appcmd.exe list vdir

VDIR "Default Web Site/" (physicalPath:C:\inetpub\[URL unfurl="true"]wwwroot)[/URL]
VDIR "Webshop/" (physicalPath:C:\InetPub\Webshop)
VDIR "Webshop/App0/" (physicalPath:C:\Inetpub\Webshop\App0)
VDIR "Webshop/App1/" (physicalPath:C:\Inetpub\Webshop\App1)
VDIR "Webshop/App2/" (physicalPath:C:\Inetpub\Webshop\App2)
VDIR "Webshop/App3/" (physicalPath:C:\Inetpub\Webshop\App3)
VDIR "Webshop/App4/" (physicalPath:C:\Inetpub\Webshop\App4)
VDIR "Webshop/App5/" (physicalPath:C:\Inetpub\Webshop\App5)
VDIR "Webshop/App6/" (physicalPath:C:\Inetpub\Webshop\App6)

Let's say I want to show just the custom 'App' vdirs, and the 2nd property of them (logical path). In cmd I'd do something like:
Code:
C:\Windows\System32\inetsrv>for /f "tokens=2" %i in ('"appcmd.exe list vdir | find "App""') do @echo %i

"Webshop/App0/"
"Webshop/App1/"
"Webshop/App2/"
"Webshop/App3/"
"Webshop/App4/"
"Webshop/App5/"
"Webshop/App6/"

How can I do this in PowerShell? (putting the result in an array of strings)
 
To be more specific, let's examine the following .ps1 script

Code:
$tl=(& tasklist)
$tl

This will create an array identified by $tl which contains strings, one string object per line returned. The second line will output the contents of the array to screen:
Code:
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
System Idle Process              0 Services                   0         24 K
System                           4 Services                   0        308 K
smss.exe                       280 Services                   0      1.228 K
csrss.exe                      468 Services                   0      4.772 K
wininit.exe                    548 Services                   0      4.656 K
csrss.exe                      568 Console                    1     14.664 K
services.exe                   604 Services                   0     14.240 K
...etc...

Now, how do I filter on lines containing '.exe', and then just store the PID per match in a new array (containing strings)?
 
PowerShell actually has a native command for getting process information, Get-Process. Since it returns objects, it's a little easier to work with than parsing the strings. For things that don't have native PowerShell equivalents, there are commands such as Select-String for the equivalent of Find and operators such as -match that can use regular expressions to pull information out of strings.

The following gets all processes, filters to get ones with a value in MainModule (which cuts out ones such as System), selects only the PID, and then assigns all of those to the variable $p. Note that in this case $p is an object with all the IDs assigned to it (instead of an array of strings).
Code:
$p = Get-Process | Where {$_.MainModule -ne $null} | Select ID
$p

Does that help?
 
Thanks for the Select-String suggestion!

Been googling for some time, but I can't find an example of how to use the -match operator with regular expressions in order to split a string in separate fields, delimited by some char.

Also, I think it's weird having to resort to regexps for something this simple and common. I just want the n-th field of a 'tokenized' string. Isn't there an easier approach then regexps?
 
Something like this seems to work:
Code:
[COLOR=#0000ff]# Run from command line:[/color]
[COLOR=#0000ff]# powershell -ExecutionPolicy RemoteSigned .\find_exe_task.ps1[/color]

[COLOR=#008080]$tl[/color] = tasklist | [COLOR=#804040][b]sort-object[/b][/color]

[COLOR=#0000ff]# writing all lines[/color]
echo [COLOR=#ff00ff]"* Lines containing .EXE:"[/color]
[COLOR=#804040][b]foreach[/b][/color]([COLOR=#008080]$line[/color] [COLOR=#804040][b]in[/b][/color] [COLOR=#008080]$tl[/color]){
  [COLOR=#804040][b]if[/b][/color] ([COLOR=#008080]$line[/color] -[COLOR=#804040][b]match[/b][/color] [COLOR=#ff00ff]".exe"[/color]) {
    echo [COLOR=#008080]$line[/color]
  }
}

echo [COLOR=#ff00ff]""[/color]

[COLOR=#0000ff]# writing only first column -i.e EXE name[/color]
echo [COLOR=#ff00ff]"* Tasks containing .EXE (case sensitive):"[/color]
[COLOR=#804040][b]foreach[/b][/color]([COLOR=#008080]$line[/color] [COLOR=#804040][b]in[/b][/color] [COLOR=#008080]$tl[/color]){
  [COLOR=#0000ff]# split line into array[/color]
  [COLOR=#008080]$line_arr[/color] = [COLOR=#2e8b57][b][regex][/b][/color]::split([COLOR=#008080]$line[/color],[COLOR=#ff00ff]"\s+"[/color])
  [COLOR=#0000ff]# if first array element contains EXE, then print it [/color]
  [COLOR=#804040][b]if[/b][/color] ([COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][0][/b][/color] -cmatch [COLOR=#ff00ff]".EXE"[/color]) {
    echo [COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][0][/b][/color]
  }
}
Output:
Code:
C:\_mikrom\Work\PowerShell>powershell -ExecutionPolicy RemoteSigned .\find_exe_task.ps1
* Lines containing .EXE:
amswmagt.exe                1796 Console                 0      5.860 K
ati2evxx.exe                 548 Console                 0      4.752 K
...
...
winlogon.exe                1156 Console                 0      7.552 K
wmiprvse.exe                3992 Console                 0      6.004 K
xtagent.exe                 1416 Console                 0      3.748 K

* Tasks containing .EXE (case sensitive):
DWRCS.EXE
DWRCST.EXE
TOTALCMD.EXE
 
Yes, I tried the function split() before but I think it didn't work as I expected: $line_arr[0] was ok, but $line_arr[1] was wrong.
 
The example below is the comparision of string split and the regex split function.
This is what I found wrong with string split function:
Code:
[COLOR=#0000ff]# Run from command line:[/color]
[COLOR=#0000ff]# powershell -ExecutionPolicy RemoteSigned .\split_example.ps1[/color]

[COLOR=#008080]$tl[/color] = tasklist | [COLOR=#804040][b]sort-object[/b][/color]

echo [COLOR=#ff00ff]"* Processing output of command:"[/color]
[COLOR=#804040][b]foreach[/b][/color]([COLOR=#008080]$line[/color] [COLOR=#804040][b]in[/b][/color] [COLOR=#008080]$tl[/color]){
  echo [COLOR=#008080]$line[/color]
}

echo [COLOR=#ff00ff]""[/color]

echo [COLOR=#ff00ff]"* Using string split function:"[/color]
[COLOR=#804040][b]foreach[/b][/color]([COLOR=#008080]$line[/color] [COLOR=#804040][b]in[/b][/color] [COLOR=#008080]$tl[/color]){
  [COLOR=#0000ff]# split line into array[/color]
  [COLOR=#008080]$line_arr[/color] = [COLOR=#008080]$line[/color].split()
  [COLOR=#0000ff]# array elements[/color]
  [COLOR=#008080]$e01[/color] = [COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][0][/b][/color]
  [COLOR=#008080]$e02[/color] = [COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][1][/b][/color]
  [COLOR=#008080]$e03[/color] = [COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][2][/b][/color]
  echo [COLOR=#ff00ff]"e01 = '$e01', e02= '$e02' , e03 = '$e03'"[/color] 
}

echo [COLOR=#ff00ff]""[/color]

echo [COLOR=#ff00ff]"* Using regex split function:"[/color]
[COLOR=#804040][b]foreach[/b][/color]([COLOR=#008080]$line[/color] [COLOR=#804040][b]in[/b][/color] [COLOR=#008080]$tl[/color]){
  [COLOR=#0000ff]# split line into array[/color]
  [COLOR=#008080]$line_arr[/color] = [COLOR=#2e8b57][b][regex][/b][/color]::split([COLOR=#008080]$line[/color],[COLOR=#ff00ff]"\s+"[/color])
  [COLOR=#0000ff]# array elements[/color]
  [COLOR=#008080]$e01[/color] = [COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][0][/b][/color]
  [COLOR=#008080]$e02[/color] = [COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][1][/b][/color]
  [COLOR=#008080]$e03[/color] = [COLOR=#008080]$line_arr[/color][COLOR=#2e8b57][b][2][/b][/color]
  echo [COLOR=#ff00ff]"e01 = '$e01', e02= '$e02' , e03 = '$e03'"[/color] 
}
Output:
Code:
* Processing output of command:

========================= ====== ================ ======== ============
amswmagt.exe                1288 Console                 0      5.860 K
ati2evxx.exe                 552 Console                 0      4.748 K
ati2evxx.exe                1448 Console                 0      3.176 K
avp.exe                     1916 Console                 0    211.432 K
avp.exe                     3632 Console                 0      4.528 K
avp.exe                     5868 Console                 0     14.484 K
CAF.exe                     2236 Console                 0     15.124 K
cam.exe                     1948 Console                 0      3.548 K
capmuamagt.exe              2100 Console                 0      4.660 K
...
...
wmiprvse.exe                2448 Console                 0      6.004 K
xtagent.exe                 1432 Console                 0      3.748 K

* Using string split function:
e01 = '', e02= '' , e03 = ''
e01 = '=========================', e02= '======' , e03 = '================'
e01 = 'amswmagt.exe', e02= '' , e03 = ''
e01 = 'ati2evxx.exe', e02= '' , e03 = ''
e01 = 'ati2evxx.exe', e02= '' , e03 = ''
e01 = 'avp.exe', e02= '' , e03 = ''
e01 = 'avp.exe', e02= '' , e03 = ''
e01 = 'avp.exe', e02= '' , e03 = ''
e01 = 'CAF.exe', e02= '' , e03 = ''
e01 = 'cam.exe', e02= '' , e03 = ''
e01 = 'capmuamagt.exe', e02= '' , e03 = ''
...
...
e01 = 'wmiprvse.exe', e02= '' , e03 = ''
e01 = 'xtagent.exe', e02= '' , e03 = ''

* Using regex split function:
e01 = '', e02= '' , e03 = ''
e01 = '=========================', e02= '======' , e03 = '================'
e01 = 'amswmagt.exe', e02= '1288' , e03 = 'Console'
e01 = 'ati2evxx.exe', e02= '552' , e03 = 'Console'
e01 = 'ati2evxx.exe', e02= '1448' , e03 = 'Console'
e01 = 'avp.exe', e02= '1916' , e03 = 'Console'
e01 = 'avp.exe', e02= '3632' , e03 = 'Console'
e01 = 'avp.exe', e02= '5868' , e03 = 'Console'
e01 = 'CAF.exe', e02= '2236' , e03 = 'Console'
e01 = 'cam.exe', e02= '1948' , e03 = 'Console'
e01 = 'capmuamagt.exe', e02= '2100' , e03 = 'Console'
...
...
e01 = 'wmiprvse.exe', e02= '2448' , e03 = 'Console'
e01 = 'xtagent.exe', e02= '1432' , e03 = 'Console'
I really don't understand how the string split function works, because the array elements $line_arr[1], $line_arr[2],.. etc seems to be empty.
IMHO, the regex split function is ok, but the string split function is wrong.
 
Now I understand: string split function splits by default only by one space, i.e the following code
Code:
$tl = tasklist | sort-object

foreach($line in $tl){
  echo $line
  # split line into array
  #$line_arr = [regex]::split($line,"\s+")
  $line_arr = $line.split(" ")
  # array elements
  $i=0
  foreach ($elem in $line_arr){
    echo "elem[$i] = $elem"
    $i++
  }
}
delivers this result
Code:
...
amswmagt.exe                1288 Console                 0      6.280 K
elem[0] = amswmagt.exe
elem[1] = 
elem[2] = 
elem[3] = 
elem[4] = 
elem[5] = 
elem[6] = 
elem[7] = 
elem[8] = 
elem[9] = 
elem[10] = 
elem[11] = 
elem[12] = 
elem[13] = 
elem[14] = 
elem[15] = 
elem[16] = 1288
elem[17] = Console
elem[18] = 
elem[19] = 
elem[20] = 
elem[21] = 
elem[22] = 
elem[23] = 
elem[24] = 
elem[25] = 
elem[26] = 
elem[27] = 
elem[28] = 
elem[29] = 
elem[30] = 
elem[31] = 
elem[32] = 
elem[33] = 
elem[34] = 0
elem[35] = 
elem[36] = 
elem[37] = 
elem[38] = 
elem[39] = 
elem[40] = 6.280
elem[41] = K
...
But I still don't understand this behaviour of the string split function.

For example using similar function in perl:
Code:
$line="amswmagt.exe                1288 Console                 0      5.860 K";
@line_arr = split(" ", $line);
$i=0;
foreach my $elem (@line_arr) {
  printf "elem[%d] = %s\n", $i, $elem;
  $i++;
}
delivers this result
Code:
elem[0] = amswmagt.exe
elem[1] = 1288
elem[2] = Console
elem[3] = 0
elem[4] = 5.860
elem[5] = K

and Python delivers the same:
Code:
>>> s = "amswmagt.exe                1288 Console                 0      5.860 K"
>>> print s.split()
['amswmagt.exe', '1288', 'Console', '0', '5.860', 'K']
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top