@@ -60,6 +60,13 @@ Converts (or merges) files via ConvertAPI v2 REST, supporting multiple files/URL
6060- Single URL => passes ?Url=... as a query parameter.
6161- Extra API params via -Parameters.
6262- Use -StoreFile to get time-limited URLs for downloading.
63+ - File-typed parameters: any -Parameters key that ends with 'File' is treated as a file input
64+ when its value is a local path; triggers multipart automatically.
65+
66+ - Use -InputMode to control how inputs are sent:
67+ * Auto (default): 1 input -> single-file; 2+ inputs -> Files[i] multipart
68+ * File force single-file (exactly 1 input required)
69+ * Files force Files[i] multipart (even for 1 input)
6370
6471. EXAMPLE
6572Invoke-ConvertApi -From pdf -To merge -File .\a.pdf, .\b.pdf -OutputPath .\out -StoreFile
@@ -86,7 +93,9 @@ https://www.convertapi.com/a/authentication
8693 [string ]$Token , # overrides env/module token
8794 [int ]$TimeoutSec = 300 ,
8895 [switch ]$Overwrite ,
89- [switch ]$PassThru
96+ [switch ]$PassThru ,
97+
98+ [ValidateSet (' Auto' , ' File' , ' Files' )] [string ]$InputMode = ' Auto'
9099 )
91100
92101 begin {
@@ -146,7 +155,7 @@ https://www.convertapi.com/a/authentication
146155 $streams = @ ()
147156
148157 try {
149- # Add files
158+ # Add file parts
150159 foreach ($kv in $FilesTable.GetEnumerator ()){
151160 $path = $kv.Value
152161 $stream = [System.IO.File ]::OpenRead($path )
@@ -158,12 +167,10 @@ https://www.convertapi.com/a/authentication
158167 $content.Add ($sc )
159168 }
160169
161- # Add URLs as string fields ( Files[i] = 'https://...' )
170+ # Add extra " string" parts (includes Files[i] urls, Url, StoreFile, Parameters, etc. )
162171 foreach ($kv in $UrlsTable.GetEnumerator ()){
163- $content.Add ([System.Net.Http.StringContent ]::new($kv.Value ), $kv.Key )
172+ $content.Add ([System.Net.Http.StringContent ]::new([ string ] $kv.Value ), $kv.Key )
164173 }
165-
166- # Add extra fields (StoreFile, Parameters...)
167174 foreach ($kv in $Fields.GetEnumerator ()){
168175 $content.Add ([System.Net.Http.StringContent ]::new([string ]$kv.Value ), $kv.Key )
169176 }
@@ -186,66 +193,117 @@ https://www.convertapi.com/a/authentication
186193 }
187194 }
188195
189- # Common query/form params
196+ # Common query/form params (cloned later for multipart)
190197 $common = @ {}
191198 if ($StoreFile.IsPresent ) { $common [" StoreFile" ] = " true" }
192199 if ($Parameters ) { foreach ($k in $Parameters.Keys ) { $common [$k ] = $Parameters [$k ] } }
193200 }
194201
195202 process {
196- $fileCount = @ ($File ).Count
197- $urlCount = @ ($Url ).Count
198- if ($fileCount -eq 0 -and $urlCount -eq 0 ) {
199- throw " Provide at least one -File or -Url."
203+ # Safe counts (avoid @($null).Count = 1)
204+ $fileCount = if ($PSBoundParameters.ContainsKey (' File' ) -and $null -ne $File ) { $File.Count } else { 0 }
205+ $urlCount = if ($PSBoundParameters.ContainsKey (' Url' ) -and $null -ne $Url ) { $Url.Count } else { 0 }
206+ $inputTotal = $fileCount + $urlCount
207+ if ($inputTotal -lt 1 -and -not $Parameters ) { throw " Provide at least one -File or -Url." }
208+
209+ # Detect extra file-typed parameters (keys ending with 'File')
210+ $fileParamKeys = @ ()
211+ if ($Parameters ) {
212+ foreach ($k in $Parameters.Keys ) {
213+ if ($k -match ' (?i)File$' ) { $fileParamKeys += $k }
214+ }
215+ }
216+
217+ # Decide how to send primary inputs
218+ $useFilesArray = switch ($InputMode ) {
219+ ' Files' { $true } # force Files[i]
220+ ' File' { if ($inputTotal -ne 1 ) { throw " InputMode 'File' requires exactly one input, but $inputTotal were provided." }; $false }
221+ default { $inputTotal -ge 2 } # Auto: Files[i] only when 2+ inputs
200222 }
201223
202- # MULTI-INPUT (merge etc.) via HttpClient multipart —— PS 5.1 safe
203- if ($fileCount + $urlCount -gt 1 ) {
204- $uri = New-ConvertApiUri - From $From - To $To - Parms $null
224+ # Using multipart: we either use Files[i] OR we have any File-typed parameters
225+ $needsMultipart = $useFilesArray -or ($fileParamKeys.Count -gt 0 )
205226
206- # Build Files[i] in order
227+ if ($needsMultipart ) {
228+ $uri = New-ConvertApiUri - From $From - To $To - Parms $null
207229 $filesTable = [ordered ]@ {}
208- $urlsTable = [ordered ]@ {}
209- $i = 0
210- foreach ($p in $File ) {
211- if (-not (Test-Path $p )) { throw " Input not found: $p " }
212- $resolved = (Resolve-Path $p ).Path
213- $filesTable [" Files[$i ]" ] = $resolved
214- $i ++
230+ $stringParts = [ordered ]@ {} # Url, Files[i] urls, StoreFile, other non-file params
231+
232+ # Primary inputs
233+ if ($useFilesArray ) {
234+ # Files[i] … for local files
235+ $i = 0
236+ foreach ($p in ($File | Where-Object { $_ })) {
237+ if (-not (Test-Path $p )) { throw " Input not found: $p " }
238+ $filesTable [" Files[$i ]" ] = (Resolve-Path $p ).Path
239+ $i ++
240+ }
241+ # Files[i] … for url inputs (as strings)
242+ foreach ($u in ($Url | Where-Object { $_ })) {
243+ $stringParts [" Files[$i ]" ] = $u
244+ $i ++
245+ }
246+ } else {
247+ # Single primary input carried as 'File' or 'Url' in multipart
248+ if ($fileCount -eq 1 -and $urlCount -eq 0 ) {
249+ if (-not (Test-Path $File [0 ])) { throw " Input not found: $ ( $File [0 ]) " }
250+ $filesTable [" File" ] = (Resolve-Path $File [0 ]).Path
251+ } elseif ($urlCount -eq 1 -and $fileCount -eq 0 ) {
252+ $stringParts [" Url" ] = $Url [0 ]
253+ }
215254 }
216- foreach ($u in $Url ) {
217- $urlsTable [" Files[$i ]" ] = $u
218- $i ++
255+
256+ # Add file-typed parameters (…File). If value is a local path -> file part; otherwise send as string
257+ if ($fileParamKeys.Count -gt 0 ) {
258+ foreach ($k in $fileParamKeys ) {
259+ $v = $Parameters [$k ]
260+ $vals = @ ()
261+ if ($v -is [System.Collections.IEnumerable ] -and -not ($v -is [string ])) { $vals = @ ($v ) } else { $vals = @ ($v ) }
262+ $idx = 0
263+ foreach ($item in $vals ) {
264+ if ($item -and (Test-Path $item )) {
265+ $partName = if ($idx -eq 0 ) { $k } else { " $k [$idx ]" }
266+ $filesTable [$partName ] = (Resolve-Path $item ).Path
267+ $idx ++
268+ } else {
269+ # URL or plain string → send as string field
270+ $partName = if ($idx -eq 0 ) { $k } else { " $k [$idx ]" }
271+ $stringParts [$partName ] = [string ]$item
272+ $idx ++
273+ }
274+ }
275+ }
219276 }
220277
221- # Extra fields
278+ # Add remaining simple fields (Parameters + StoreFile) except the ones we already promoted to file/string parts above
222279 $fields = [ordered ]@ {}
223280 foreach ($k in $common.Keys ) {
281+ if ($fileParamKeys -contains $k ) { continue } # skip; already added as file/string parts
224282 $v = $common [$k ]; if ($v -is [bool ]) { $v = $v.ToString ().ToLower() }
225283 $fields [$k ] = [string ]$v
226284 }
227285
228- $label = (" {0} item(s)" -f ( $fileCount + $urlCount ))
286+ $label = (" {0} item(s)" -f [ Math ]::Max( $inputTotal , 1 ))
229287 if ($PSCmdlet.ShouldProcess ($label , " Convert $From -> $To (multipart)" )) {
230- $response = Invoke-ConvertApiMultipart - Uri $uri - FilesTable $filesTable - UrlsTable $urlsTable - Fields $fields - Token $Token - TimeoutSec $TimeoutSec
288+ $response = Invoke-ConvertApiMultipart - Uri $uri - FilesTable $filesTable - UrlsTable $stringParts - Fields $fields - Token $Token - TimeoutSec $TimeoutSec
231289 Save-ConvertApiFiles $response
232290 }
233291 return
234292 }
235293
236- # SINGLE URL
294+ # ---- Single URL (query string) ----
237295 if ($urlCount -eq 1 -and $fileCount -eq 0 ) {
238296 $q = $common.Clone (); $q [" Url" ] = $Url [0 ]
239297 $uri = New-ConvertApiUri - From $From - To $To - Parms $q
240- if ($PSCmdlet.ShouldProcess ($Url [0 ], " Convert $From -> $To (url)" )) {
298+ if ($PSCmdlet.ShouldProcess ($Url [0 ], " Convert $From -> $To (single url)" )) {
241299 $response = Invoke-RestMethod - Uri $uri - Method POST - Headers $headers - TimeoutSec $TimeoutSec
242300 Save-ConvertApiFiles $response
243301 }
244302 return
245303 }
246304
247- # SINGLE LOCAL FILE (octet-stream)
248- if ($fileCount -eq 1 ) {
305+ # ---- Single local file (octet-stream + Content-Disposition) ----
306+ if ($fileCount -eq 1 -and $urlCount -eq 0 ) {
249307 $resolved = (Resolve-Path $File [0 ]).Path
250308 $name = [IO.Path ]::GetFileName($resolved )
251309 $bytes = [IO.File ]::ReadAllBytes($resolved )
@@ -261,6 +319,8 @@ https://www.convertapi.com/a/authentication
261319 }
262320 return
263321 }
322+
323+ throw " Cannot resolve inputs for the chosen InputMode '$InputMode '."
264324 }
265325}
266326
0 commit comments