I wrote a very simple script to acquire a random free drive letter.
The function finds a random free letter , creates a new empty text file of that drive letter name eg. Q.txt
I then return the value as $new_letter but when it comes out of the function somehow newly file created path is a part of the variable C:\AppPack\Logs\Q.txt Q
Is it something New-Item
messing up with my $new_letter
variable ?
function get_drive_letter()
{
$letter_acquired = $false
Do
{
$new_letter = Get-ChildItem function:[h-z]: -Name | ForEach-Object { if (!(Test-Path $_)){$_} } | random -Count 1 | ForEach-Object {$_ -replace ':$', ''}
write-host ("RIGHT AFTER " + $new_letter)
if (!(test-path "C:\AppPack\Logs\$new_letter.txt"))
{
New-Item -Path C:\AppPack\Logs\ -Name "$new_letter.txt" -ItemType "file"
write-host ("FROM FUNCTION " + $new_letter)
$letter_acquired = $true
return $new_letter
}
else
{
write-host ("LETTER USED ALREADY")
write-host ($new_letter)
}
}
while($letter_acquired = $false)
}
$drive_letter = $null
$drive_letter = get_drive_letter
write-host ("RIGHT AFTER FUNCTION " + $drive_letter)
OUTPUT :
RIGHT AFTER Q
FROM FUNCTION Q
RIGHT AFTER FUNCTION C:\AppPack\Logs\Q.txt Q
A PowerShell function outputs everything, not just the result of the expression right after return
!
The additional file path you see is the output from New-Item ...
- it returns a FileInfo
object for the file you just created.
You can suppress output by assigning it to the special $null
variable:
# Output from New-Item will no longer "bubble up" to the caller
$null = New-Item -Path C:\AppPack\Logs\ -Name "$new_letter.txt" -ItemType "file"
return $new_letter
Or by piping to Out-Null
:
New-Item ... |Out-Null
Or by casting the entire pipeline to [void]
:
[void](New-Item ...)
Although I recommend explicitly handling unwanted output at the call site, you can also work around this behavior with a hoisting trick.
To demonstrate, consider this dummy function - let's say we "inherit" it from a colleague who didn't always write the most intuitive code:
function Get-RandomSquare {
"unwanted noise"
$randomValue = 1..100 |Get-Random
"more noise"
$square = $randomValue * $randomValue
return $square
}
The function above will output 3 objects - the two garbage strings one-by-one, followed by the result that we're actually interested in:
PS ~> $result = Get-RandomSquare
PS ~> $result
unwanted noise
more noise
6400
Let's say we've been told to make as few modifications as possible, but we really need to suppress the garbage output.
To do so, nest the entire function body in a new scriptblock literal, and then invoke the whole block using the dot-source operator (.
) - this forces PowerShell to execute it in the function's local scope, meaning any variable assignments persist:
function Get-RandomSquare {
# suppress all pipeline output
$null = . {
"unwanted noise"
$randomValue = 1..100 |Get-Random
"more noise"
$square = $randomValue
return $square
}
# variables assigned in the block are still available
return $square
}