External commands arguments

Welcome Forums General PowerShell Q&A External commands arguments

This topic contains 7 replies, has 4 voices, and was last updated by

 
Participant
6 months, 2 weeks ago.

  • Author
    Posts
  • #100077

    Participant
    Points: 0
    Rank: Member

    I am learning how to pass arguments to external commands in Powershell. I decided to settle on schtasks.exe as a scenario to play with.

    What I have decided to do as an exercise to learn is to create functions to getting scheduledtasks and creating scheduledtasks.

    During my creation of the function, I hit a bit of a snag. I want to parameterize the arguments and pass that to schtasks.exe.
    So I tried this from the schtasks.exe based of an example from schtasks.exe
    SCHTASKS /Create /S ABC /U user /P password /RU runasuser /RP runaspassword /SC WEEKLY /TN report /TR notepad.exe
    and parameterize it like so:

    $comp = "server1"
    $Server = "/S $comp"
    $schedule = " /SC WEEKLY"
    $taskname = "/TN report"
    $taskrun = "/TR notepad.exe"
    SCHTASKS "/Create $server $schedule $taskname $taskrun"
    

    It totally bombs with:

    SCHTASKS : ERROR: Invalid argument/option - '/s win2k12-dc1'.
    At line:6 char:1
    + SCHTASKS /Create $server $schedule $taskname $taskrun
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (ERROR: Invalid ...s win2k12-dc1'.:String) [], RemoteException
        + FullyQualifiedErrorId : NativeCommandError
     
    Type "SCHTASKS /CREATE /?" for usage.
    

    I saw an example on the internet:

    $arg1 = "filename1"
    $arg2 = "-someswitch"
    $arg3 = "C:\documents and settings\user\desktop\some other file.txt"
    $arg4 = "-yetanotherswitch"
    
    $allArgs = @($arg1, $arg2, $arg3, $arg4)
    
    & "C:\Program Files\someapp\somecmd.exe" $allArgs
    

    My question is how does it know what arguments apply to what in schtasks? Or is there a better way to pass arguments to the external command in powershell? Thanks in advance for any help.

  • #100083

    Participant
    Points: 59
    Rank: Member

    You need to remove the quotes in

    SCHTASKS "/Create $server $schedule $taskname $taskrun"
    
  • #100089

    Participant
    Points: 0
    Rank: Member

    Hi Sam,

    I tried it as

    SCHTASKS /Create $server $schedule $taskname $taskrun
    

    It still doesnt work.....

  • #100092

    Participant
    Points: 160
    Helping Hand
    Rank: Participant

    To control the switches, you need to really leverage a Powershell function or minimally parameters. You have a great deal of control of how to build the command such as ValidateSet. To call a exe, you'll need to use .\SCHTASKS.EXE... or & SCHTASKS.EXE..., there is a lot of information out there on calling cmd utilities with Powershell. However, I would recommend using Start-Process because you can pass arguments as an array. Here is an example:

    Output:

    VERBOSE: SCHTASKS.EXE /CREATE /S server1 /SC WEEKLY /TN report /TR notepad.exe
    

    Code:

    function Create-ScheduledTask {
        [CmdletBinding()]
        param (
            [Parameter(Position=0, Mandatory=$true)]
            [Alias('ServerName')]
            [string]$ComputerName,
            [Parameter(Position=1, Mandatory=$true)]
            [ValidateSet('MINUTE','HOURLY','DAILY','WEEKLY','MONTHLY','ONCE','ONSTART','ONLOGON','ONIDLE','ONEVENT')]
            [Alias('SC')]
            [string]$Schedule,
            [Parameter(Position=2, Mandatory=$true)]
            [Alias('TN')]
            [string]$TaskName,
            [Parameter(Position=3, Mandatory=$true)]
            [Alias('TR')]
            [string]$TaskRun
        )
        begin {}
        process {
            $argList = @('/CREATE')
    
            if ($PSBoundParameters.ContainsKey('ComputerName')) {
                $argList += '/S {0}' -f $ComputerName
            }
    
            if ($PSBoundParameters.ContainsKey('Schedule')) {
                $argList += '/SC {0}' -f $Schedule
            }
    
            if ($PSBoundParameters.ContainsKey('TaskName')) {
                $argList += '/TN {0}' -f $TaskName
            }
    
            if ($PSBoundParameters.ContainsKey('TaskRun')) {
                $argList += '/TR {0}' -f $TaskRun
            }
    
            $tskParams = @{
                FilePath = 'SCHTASKS.EXE'
                ArgumentList = $argList
                Wait = $true
                NoNewWindow = $true
            }
            
            #Start-Process @tskParams
            
            Write-Verbose -Message ('SCHTASKS.EXE {0}' -f ($argList -join ' '))
        }
        end {}
    }
    
    $params = @{
        ComputerName = "server1"
        Schedule     = "WEEKLY"
        Taskname     = "report"
        Taskrun      = "notepad.exe"
    }
    
    Create-ScheduledTask @params -Verbose
    
  • #100093

    Participant
    Points: 0
    Rank: Member

    Thanks Rob,

    Thats the explaination I was looking for . Thats perfect! Many thanks

  • #100096

    Participant
    Points: 0
    Rank: Member

    Rob, If its ok to ask what does the {0} mean?

    • #100101

      Participant
      Points: 165
      Helping Hand
      Rank: Participant
      Write-Verbose -Message ('SCHTASKS.EXE {0}' -f ($argList -join ' '))

      This old thing? Okay, so as you've seen, PowerShell will natively insert the value of a variable in a double-quoted string. It won't do this for single-quoted strings, however:

      $Var = "hello"
      PS C:\>"this says $Var"
      this says hello
      PS C:\>'this says $Var'
      this says $var

      So, Powershell has a string operator, -f. If you're at all familiar with .NET, or any of the old C-family printf functions, it behaves similarly. You insert markers, like {0}, {1}, etc., into the string, and after the -f operator, you give it a comma-separated list of the different things to insert:

      PS C:\>"{0}..{1}..{0}" -f 99,1
      99..1..99

      It can do a lot of interesting things, too, like specify a date format for a datetime object, force a number to display to a certain number of decimal places, force a number to display leading zeroes, etc., etc. It's quite versatile, allowing you to convert values to various string equivalents with ease.

      Some examples:

      PS C:\>"Date: {0:yyyyMMdd}" -f (Get-Date)
      Date: 20180501
      PS C:\>"{0:0000}, {1:0000}, {2:0000}" -f 1, 100, 10000
      0001, 0100, 10000
      PS C:\>"{0:N2}, {0:0000}, {0:X}" -f 100
      100.00, 0100, 64 

      Though it's not clear, that very last one? Hexadecimal display. Basically anything you can usually do in .NET with format strings, you can do in PS natively with the -f operator. It works with both single and double quoted strings, so it's extremely versatile.

  • #100099

    Participant
    Points: 160
    Helping Hand
    Rank: Participant

    The -f indicates a string format. The curly brackets are placeholders and the number is an index number of the item in the array you are passing:

    $personName = 'Jane'
    $dogName = 'Spot'
    
    "See {0} run. See {1} run." -f $personName, $dogName
    

    Output:

    See Jane run. See Spot run.
    

    It's strictly preference, but you can also do formatting for dates, numbers, timepans and many other things. For instance, numbers: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings

    $total = 2.75
    
    "Your total is {0:c}" -f $total
    

    This will automatically format it as currency. Using other string concatenation methods, while they work, string formats have never failed me.

The topic ‘External commands arguments’ is closed to new replies.