Jawab Convert a simple BASH construct to Powershell?

  • viernes, 02 de marzo de 2012 8:52
     
     

    Hello MS World. I'm looking for a simple Powershell construct to emulate a BASH shell script or even a dos For /f loop. I need to cycle through a csv file of 4 fields per record until EOF.

    The BASH loop is like this:

    While read -r f1 f2 f3 f4

    do

        stuff with f1-f4

    done < inputfile.txt

    Even the old dos
    FOR /f "tokens=1,2,3,4 delims=," etc gives me 4 variables I can use in my little script.

    It has been suggested that I convert my data file to XML - is this the best way? I do need PS 'cos I need the emailing, power file handling attributes it brings.

    Sorry, I'm brand new to Windows scripting and cannot find a simple answer.

    Thanks in advance.

Todas las respuestas

  • viernes, 02 de marzo de 2012 9:22
     
      Tiene código

    How about running this:

    cat 1.csv | % {$_.split(",") | select -first 4}

    I am unfamiliar with what you are doing with bash exactly but this will give you the first 4 variables on every line in the csv. You can pipeline these four directly into the next command. Does that resolve your issue?

  • viernes, 02 de marzo de 2012 10:19
     
     

    Hello Jaap, thanks for the prompt response.

    The coding is indeed simple: would I capture each record by feeding the output into a function and use the  $Args_ array to seperate the values? Is this what you would recommend?

    Thanks again.

    Peter

  • viernes, 02 de marzo de 2012 10:38
     
     Respondida Tiene código

    If you want to feed it into a function you can do it like this:

    cat 1.csv | % {functioname ($_.split(",") | select -first 4) }

    Then it feeds the 4 values into the function as four separate arguments.

    • Marcado como respuesta Peter Neilon viernes, 02 de marzo de 2012 10:43
    •  
  • viernes, 02 de marzo de 2012 10:54
     
     

    Hmm, yes. Thanks very much, Jaap.

    On reflection, perhaps it is time to leave the old behind and attack the problem with a different mindset.

    My data is related to my staff who are all in the AD therefore, by adding a couple of fields to the AD, I can do all my querying directly there.

    Seems sensible (at least to me.)

    Thanks for your time.

    Peter

  • viernes, 02 de marzo de 2012 18:13
    Moderador
     
     Respondida Tiene código

    Hi,

    If the file is a csv file, you can also use import-csv; e.g.:

    PS C:\>import-csv myfile.csv | select-object "Col1","Col2","Col3","Col4"

    Bill

    • Marcado como respuesta Peter Neilon sábado, 03 de marzo de 2012 11:11
    •  
  • sábado, 03 de marzo de 2012 11:17
     
     

    Hello Bill, yes it is a csv file and I have just stumbled on to the Blog of Mr Wilson (I think he is The Scripting Guy) who exactly demonstrates what you have shown here to me. Amazing what working from home with a beer in hand can produce rather than working at the office with a deadline over the head.

    Thanks for your help, everyone.

    Peter

  • viernes, 09 de marzo de 2012 7:22
     
      Tiene código

    I hope this is ok on this forum. I tackled the task with due enthusiasm, and in a relatively short period I converted the BASH script to Powershell. I would like to list the script with my notes on what I learned in case any other newbie can gain something from it. The script does useful work if anyone wants to use it.

    # Originally written as a BASH script running in a SAMBA environment under Linux.
    #
    # Script is designed to fetch stuff from a well-known place and deliver it to whomsoever it is meant for.
    # Used mainly by computer-using exam candidates to 'dump' their marking for a specific teacher.
    # Each candidate has a shortcut to a write-only share (on our file-server) on their desktop. They drag to and drop their stuff on the shortcut which swallows it.
    
    $data = "C:\Data\Users\pneilon\Scripts\dropboxscript\data.csv"
    
    # csv file has headers: code, user, fname, place, HowTheySeeIt
    # headers are automatically allocated as variable names by Import-CSV cmdlet - very useful.
    #
    # as an example: pn, pneilon@myplace.co.za, Peter, c:\data\users\pneilon\workdump, H:\workdump
    #
    # the code is the thing: any file/folder coded with 'pn' at the beginning of its name will be sent to pneilon's workdump place
    
    $logfile = "C:\Data\Users\pneilon\Scripts\dropboxscript\log.txt"
    
    #
    # we keep a log file so pupils can verify that they did send that answer to the teacher (who has lost it.)
    #
    
    $dump = "C:\Dump"
    
    # well known place on our file server. Shared to everyone as Writeable but not readable/listable. Admins can read. Normally the kids name the shortcut as Teacher Dump
    # They seem to find that amusing.
    
    $subject = "New stuff has arrived in your workdump folder."
    $from = "root@myplace.co.za"
    #
    # constants for the email section
    #
    
    If ((@(get-childitem $dump).count) -gt 0 ) {
    
    # Hmm, big lesson here. Want to check if there is actual stuff in the dump before we work too hard.
    # Get-Childitem.count returns empty with zero OR one object in the place of interest. The @ thingy converts to an array (I believe) which then counts correctly.
    # wasted hours on this one. Also, you can never have enough parenthesis pairs :)
    #
       import-csv $data | foreach-object {  
    #
    # the heart of the script. Reads the data file one record at a time - treats the first record as field names which we can use as the loop loops on.
    #
         if (test-path $dump\$($_.code)* ) {
    #
    # check the dump for any file(s) starting with current record's code ($_,code)* eg pn*
    #
    # 
           $dest = $_.place 
    
    # just me being anal.
    #
           if (!(test-path $dest -pathtype container)) {new-item $dest -type directory | out-null} 
    #
    # check if the destination folder exists. if not, create it and kill any success story it may want to tell us.
    #
           get-childitem -name $dump\$($_.code)* | foreach-object {
    #
    # now we move through the collection of files/folders marked for the current record (eg pn*)
    #
             $_ >> $logfile 
    #
    # and append the file name to our log file. If the log file does not exist, it will be created automatically.
    #
             $now = get-date -format yyMMddhhmmss
             $newname = $now + $_
    #
    # tack the time onto the filename to probably avoid any conflicts of similar filenames with multiple drops of same file by pupil. It happens!
    #
             move-item $dump\$_ $dest\$newname -force
    #
    # Move the file rather than copy it.
    #
           }
    
    # loop for next file in the pn* collection
    #
    # All the individual files of the associated record have been moved.
    # email news of file(s) arrival
    #
         $Body = "Hello $($_.fname). New work/stuff/marking has been left for you in your workdump folder - $($_.howtheyseeit). Please attend to this soonest."	 
    #
    # I tried defining the body of the message in the constants section above, but it failed to fill in the variable placeholders when needed.
    # According to some reading, one does not need to bracket 'normal' variable placeholders in strings, but with the $_. types I found you have to $ bracket them to get it to work properly.
    # 
    #
         Send-MailMessage -From $From -To $_.user -Subject $Subject -Body $Body -SmtpServer 192.168.1.2
    #
    # very simple to do. Right up there with linux.
    
    # chown permissions
    # 
         icacls $dest\* /reset /Q /T | out-null
    #
    # use icacls to reset the destination folder's files to the parent folder's permissions - otherwise the move leaves the files useless to the receiver!
    #
         } 
      }
    }

  • viernes, 09 de marzo de 2012 16:51
     
     
    Nice, thanks for sharing Peter. It is always good to see someone come in with a question and come back a few days later with a working script. Keep up the nice work!