Occasionally it is useful and even necessary to use console applications in PowerShell scripts. In the previous tip, for example, we looked at ways to remove mapped network drives, and even though Remove-PSDrive claims to be able to do this, the most reliable way is to still use the old net.exe console command.
Let’s take a quick look at how you can check whether or not a console command completed successfully.
Let’s try that by mapping a new network drive, then removing it, with console applications. Of course, you can apply the same principles to any console application you may need to run within your PowerShell script:
PS> net use z: \\127.0.0.1\c$
The command completed successfully.
PS> net use z: /delete
z: was deleted successfully.
PS> net use z: /delete
net : The network connection could not be found.
At line:1 char:1
+ net use z: /delete
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (The network con...d not be found.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
More help is available by typing NET HELPMSG 2250.
The mapped drive was created, then removed again. However, status messages are localized (so it is hard to compare them to expected values in multinational environments), and errors surface as exceptions.
By using $?, you can turn the output to a mere $true or $false: $true meaning the command completed successfully, and $false indicating (any) error:
PS> $null = net use z: \\127.0.0.1\c$; $result = $?; $result
True
PS> $null = net use z: \\127.0.0.1\c$; $result = $?; $result
net : System error 85 has occurred.
At line:1 char:9
+ $null = net use z: \\127.0.0.1\c$; $result = $?; $result
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (System error 85 has occurred.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
The local device name is already in use.
False
That’s much better because your script could then evaluate $result and in case of an error take appropriate steps or write messages to log files.
In case of errors, though, the detailed error information would still be emitted to the console, and there is no (apparent) way to remove it. Even full-blown try…catch error handlers do not respond to them:
PS> $null = try { net use z: \\127.0.0.1\c$} catch {}; $result = $?; $result
net : System error 85 has occurred.
At line:1 char:15
+ $null = try { net use z: \\127.0.0.1\c$} catch {}; $result = $?; $res ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (System error 85 has occurred.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
The local device name is already in use.
False
The reason is: console applications do not throw .NET exceptions. When an error occurs, console applications just emit information via output stream #2.
And this coincidentally is the solution to wrap console applications: redirect all streams to the output stream. This maps a network drive: the first call succeeds; all subsequent calls fail:
PS> $null = net use z: \\127.0.0.1\c$ *>&1; $? True PS> $null = net use z: \\127.0.0.1\c$ *>&1; $? False PS> $null = net use z: \\127.0.0.1\c$ *>&1; $? False
Likewise, this removes the mapped drive again, and like before the first call succeeds, all remaining calls fail:
PS> $null = net use z: /delete *>&1; $result = $?; $result True PS> $null = net use z: /delete *>&1; $result = $?; $result False PS> $null = net use z: /delete *>&1; $result = $?; $result False