0

The code below is part of a switch and it's working fine, but the problem is: I need to change my file name to 15... Is it possible to to change it so that when I start it, it waits to select for a file with the tab key? Something like when you write Import-Csv in a PowerShell console and press Tab it shows all possbile paths and files.

$names = Import-Csv 15.csv -Header Givenname,Surname -Delimiter ";"
Write-Host "Rename your csv file to '15' and put it in same folder with this script" -ForegroundColor Cyan 
pause
foreach ($Name in $Names) {
    $FirstFilter = $Name.Givenname
    $SecondFilter = $Name.Surname
    Get-ADUser -Filter {GivenName -like $FirstFilter -and Surname -like $SecondFilter} |
        select Enabled, SamAccountName, DistinguishedName,
            @{n="ou";e={($_.DistinguishedName -split ",*..=")[2]}} |
        Export-Csv .\sam.csv -NoTypeInformation -Append
}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • https://code.adonline.id.au/folder-file-browser-dialogues-powershell/ – f6a4 Jun 30 '18 at 09:28
  • thats not what im looking for i just want to simply scroll in that directory with tab key like when u press tab after a command with file input – saeed badali Jun 30 '18 at 09:57

3 Answers3

3

So you want Intellisense in your script. Ambitious move. Most people would settle for the file browser dialog box. Anyway, I am going to have to refer you to smarter men than me. I was thinking ValidateSet attribute would serve your purpose but I realized that the traditional param block is not enough. So I looked up DynamicParams and this is what I found. This should work for you.

https://blogs.technet.microsoft.com/pstips/2014/06/09/dynamic-validateset-in-a-dynamic-parameter/

Sid
  • 2,586
  • 1
  • 11
  • 22
  • Populating the DynamicParams with directory `Name` instead of `FullName` would IMO make more sense. Good find +1. OTOH I think OP had something else in mind selecting a folder with TAB [maybe this](https://stackoverflow.com/questions/17576015/powershell-menu-selection-like-grub-curses-etc) –  Jun 30 '18 at 11:18
  • Inside a script, user input is achieved through `Read-host` or `param()`. AFAIK, `Read-Host` will expect input from the user. It does not give any hints or suggestions. So `Param()` is the next best option I could think of. At least it has the avenues to provide something along the lines of intellisense. I could be wrong and that is why, I will let smarter men pave the road. – Sid Jun 30 '18 at 13:14
  • In PSv5+ you can use the `[ArgumentCompleter({...})]` attribute on individual parameters inside a `param()` block. – mklement0 Jun 30 '18 at 23:04
  • seems to be right answer... I will try it.. but not sure how to use it in my code – saeed badali Jul 01 '18 at 09:54
  • The Technet link is broken. Do we have an alternative, or the text of the article? – YorSubs Mar 18 '20 at 04:00
1

The simplest solution is to make your script accept the target file as an argument, by declaring a parameter:

param(
  # Declare a mandatory parameter to which the file path of the CSV
  # file to import must be passed as an argument on invocation.
  [Parameter(Mandatory)]
  [string] $FilePath
)

$names = Import-Csv $FilePath -Header Givenname,Surname -Delimiter ";"
foreach ($Name in $Names) {
    $FirstFilter = $Name.Givenname
    $SecondFilter = $Name.Surname
    Get-ADUser -Filter {GivenName -like $FirstFilter -and Surname -like $SecondFilter} |
        select Enabled, SamAccountName, DistinguishedName,
            @{n="ou";e={($_.DistinguishedName -split ",*..=")[2]}} |
        Export-Csv .\sam.csv -NoTypeInformation -Append
}

If you invoke your script without a file path, you will be prompted for it; let's assume your script is located in the current dir. and its name is someScript.ps1:

./someScript    # invocation with no argument prompts for a value for $FilePath

Unfortunately, such an automatic prompt is not user-friendly and offers no tab completion.

However, on the command line PowerShell's tab completion defaults to completing file and directory names in the current location, so that:

./someScript <press tab here>

cycles through all files and directories in the current folder.

You can even type a wildcard expression and tab-complete that, if you don't know the full filename or don't want to type it in full:

./someScript *.csv<press tab here>

This will cycle through all *.csv files in the current dir. only.

If you want to go even further and customize tab completion to only cycle through *.csv files, you can use an [ArgumentCompleter({ ... })] attribute (PSv5+):

param(
  [Parameter(Mandatory)]
  # Implement custom tab-completion based on only the *.csv files in the current dir.  
  [ArgumentCompleter({
    param($cmd, $param, $wordToComplete)
    Get-ChildItem -Name "$wordToComplete*.csv"
  })]
  [string] $FilePath
)

# ...

Now,

./someScript <tab>

will cycle only through the *.csv files in the current directory, if any.

Caveat: As of PowerShell 7.0, tab-completing an argument for which the ArgumentCompleter script block returns no matches (in this case, with no *.csv files present) unexpectedly falls back to the default file- and directory-name completion - see this GitHub issue.

Similarly,

./someScript 1<tab>

will cycle only through the *.csv files in the current directory whose name starts with 1, if any.


As an alternative to using an attribute as part of a script's / function's definition, you can use the PSv5+ Register-ArgumentCompleter cmdlet to attach tab completions to the parameters of any command, i.e., including preexisting ones.


In PSv4- you have two (cumbersome) options for custom tab completion:

  • Use a dynamic parameter with a dynamically constructed [ValidateSet()] attribute - see the link in Rohin Sidharth's answer.

  • Customize the tabexpansion2 (PSv3, PSv4) / tabexpansion (PSv1, PSv2) function, but be sure not to accidentally replace existing functionality.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

Below is my example.ps1 file that I use to write 1-off scripts. In your case I think you can get what you want with it. For example (no pun intended) you could call this script by typing

C:\PathToYourScripts\example.ps1 [tab]

where [tab] represents pressing the tab key. Powershell intellisense will kick in and offer autocompletion for file names. If your .csv file is not in the current director you can easily use Powershell intellisense to help you find it

C:\PathToYourScripts\example.ps1  C:\PathToCSvFiles[tab]

and powershell will autocomplete. Would-be-downvoters might notice that powershell autocomplete is definitely NOT a complete file-picker but this seems to fulfill the intent of the asked question. Here's the sample.

<#
.NOTES
    this is an example script
.SYNOPSIS
    this is an example script
.DESCRIPTION
    this is an example script

.Example
    this is an example script
.LINK
    https://my/_git/GitDrive
#>
[CmdletBinding(SupportsShouldProcess=$True, ConfirmImpact="Low")]
param (
      [string] $fileName
)
Begin {
}

Process {
    if ($PSCmdlet.ShouldProcess("Simulated execution to process $($fileName):  Omit -Whatif to process ")) {
       Write-Information -Message "Processing $fileName" -InformationAction Continue
    }
}

End {
}

If you want to get autocomplete help for multiple parameters just type in the parameter name(s) and press [tab] after each one. Note that leaving the parameters blank will not break the script but you can either extend this to mark the parameters required or just fail with a helpful message. That seems a bit beyond the original question so I'll stop here.

No Refunds No Returns
  • 8,092
  • 4
  • 32
  • 43