How can I read file input without any pre-defined

2019-09-07 16:20发布

I have users provide an input txt file as an argument -InputFile which I store as $inputfile. But when I try:

$reader = [System.IO.File]::OpenText("$inputfile")

PowerShell automatically appends the $inputfile path to C:\Windows\system32. How can I have PowerShell not assume a path prefix, so a user could simply pass -InputFile inputfile.txt if the file they want is in the same directory from which they run the script? How can I also support them enumerating a completely different path to the file if it's outside of the current directory without having it automatically append to C:\Windows\system32?

EDIT: Changed the variable "$input" to "$inputfile" per your advice.

4条回答
Lonely孤独者°
2楼-- · 2019-09-07 16:55

First: Be aware that $input is a special variable in PowerShell. See help about_Automatic_Variables for more information. (You don't put enough context in your question for me to know whether you're using that variable properly or not.)

Second, .NET objects don't assume the same working location as PowerShell. They can't, because PowerShell has "drives" other than file system drives. If you're sure you're in the file system, you can use something like this:

$fullPath = Join-Path (Get-Location).Path $inputFilenameFromUser

Cmdlets will use the working location.

查看更多
欢心
3楼-- · 2019-09-07 16:56

Use Resolve-Path for resolving the path before/when you pass it to OpenText():

$reader = [IO.File]::OpenText((Resolve-Path $InputFile).Path)

Since Resolve-Path throws an exception when it can't resolve a path you may want to run this in a try..catch block, e.g. like this:

try {
    $path = (Resolve-Path $InputFile).Path
    $reader = [IO.File]::OpenText($path)
} catch [Management.Automation.ItemNotFoundException] {
    # cannot resolve path
} catch {
    # other error
}

or, better yet, validate the parameter:

[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path -LiteralPath $_ -Type Leaf})]
[string]$InputFile
查看更多
Animai°情兽
4楼-- · 2019-09-07 17:02

First I'd like to second what everybody else has said: that you should not be using $Input as your variable name since that is an automatic variable.

Aside from that I'd like to offer you an alternative. Personally I keep a function around that will pop up an Open File dialog box when I want people to specify an input file.

Function Get-FilePath{
[CmdletBinding()]
Param(
    [String]$Filter = "All Files (*.*)|*.*|Comma Seperated Values (*.csv)|*.csv|Text Files (*.txt)|*.txt",
    [String]$InitialDirectory = "C:\",
    [String]$Title)

    [void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = $InitialDirectory
    $OpenFileDialog.filter = $Filter
    $OpenFileDialog.Title = $Title
    [void]$OpenFileDialog.ShowDialog()
    $OpenFileDialog.filename
}

Then you could just do something like

$InputFilePath = Get-FilePath

That would give you the full path to the file as a string.

查看更多
We Are One
5楼-- · 2019-09-07 17:06

First, don't use $input as a variable name; it's an automatic variable so it could be overwritten or have unexpected results.

Second, are you sure that the "current" directory is not C:\Windows\System32? The working directory is not necessarily (and often isn't) the path where the script is.

If you want it to always use the script directory instead of the working directory, but only when the path is relative, then you have to do some coding to make sure (note I'm replacing your $input variable with one called $Path):

if (($Path | Split-Path -IsAbsolute)) {
    $reader = [System.IO.File]::OpenText($Path)
} else {
    $myPath = $PSScriptRoot | Join-Path -ChildPath $Path
    $reader = [System.IO.File]::OpenText($myPath)
}
查看更多
登录 后发表回答