Reputation: 553
I'm using a simple net use command to map a network drive
net use \\$HOSTIP $PASSWD /user:$UNAME
i must use net use instead of of New-PSDrive because the scripts runs for more then 400 machines in multiple instances and just wouldn't be doable. I want to filter the error message then net use return like
System error 64 has occurred.
or
System error 67 has occurred.
How can I do this?
Upvotes: 1
Views: 3299
Reputation: 41
Following up on @jdr5ca`s Answer which will work and is good. I made some modifications to make it a little easier to read and understand.
First and foremost, I set some variables that are at the top of the script so that they can be quickly and easily modified.
Clear-Host # I use because of Visual Studio
$drivelettertouse = "Z" # or "*" for any.
$Server = "\\SERVER\"
I then kept the middle section pretty much the same excluding the Arguments. This was because, for my use, I do not need to use the Username and Password.
$pinfo = new-object System.Diagnostics.ProcessStartInfo
$pinfo.Filename = "net.exe"
$pinfo.UseShellExecute = $false
$pinfo.Arguments = @("use", "$($drivelettertouse):", "$($Server)")
$pinfo.redirectstandardError = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.start() | out-null
$p.waitforexit()
Now, for the actual error-handling process. I did this differently. Not because his was not good, but because I find this way a little easier to read.
This will allow you to catch certain System Errors and either go to a function or set a variable for later use.
if($p.exitcode -ne 0){
$err = $p.standardError.ReadToEnd()
# List of Error Codes https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
switch ($err)
{
{$_.contains("System error 3 has")} { $global:syserror=5; break}
{$_.contains("System error 5 has")} { $global:syserror=5; break}
{$_.contains("System error 15 has")} { $global:syserror=15; break}
{$_.contains("System error 53")} { $global:syserror=53; break}
{$_.contains("System error 55")} { $global:syserror=55; break}
{$_.contains("System error 67")} { $global:syserror=67; break}
{$_.contains("System error 85")} { $global:syserror=85; break}
default {$global:syserror=9999; break}
}
}
Additionally, I added if-else statements to manage those errors. The reason I am using If Else statements is because some of these will use more than one function for my use case. If you would also like to use the If Else method, here is how I used mine below, excluding my use.
if ($global:syserror -eq 5) {
Write-Host "Access to $Server denied for user $env:USERNAME."
} elseif ($global:syserror -eq 15) {
Write-Host "The system cannot find the drive specified."
} elseif ($global:syserror -eq 53) {
Write-Host "The network path was not found."
} elseif ($global:syserror -eq 55) {
Write-Host "The specified network resource or device is no longer available."
} elseif ($global:syserror -eq 67) {
Write-Host "The network name cannot be found."
} elseif ($global:syserror -eq 85) {
$inuseby = Get-PSDrive $drivelettertouse | Select -ExpandProperty DisplayRoot
Write-Host "$($drivelettertouse):\ is already in use by $inuseby."
} elseif ($global:syserror -eq "9999") {
Write-Host "Unknown Error."
Write-Host $err
}
I hope this helps anyone who needs it. :)
Full Code.
Clear-Host
$drivelettertouse = "Z"
$Server = "\\SERVER\" + $env:USERNAME
$pinfo = new-object System.Diagnostics.ProcessStartInfo
$pinfo.Filename = "net.exe"
$pinfo.UseShellExecute = $false
$pinfo.Arguments = @("use", "$($drivelettertouse):", "$($Server)")
$pinfo.redirectstandardError = $true
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.start() | out-null
$p.waitforexit()
if($p.exitcode -ne 0){
$err = $p.standardError.ReadToEnd()
# List of Error Codes https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
switch ($err)
{
{$_.contains("System error 3 has")} { $global:syserror=5; break}
{$_.contains("System error 5 has")} { $global:syserror=5; break}
{$_.contains("System error 15 has")} { $global:syserror=15; break}
{$_.contains("System error 53")} { $global:syserror=53; break}
{$_.contains("System error 55")} { $global:syserror=55; break}
{$_.contains("System error 67")} { $global:syserror=67; break}
{$_.contains("System error 85")} { $global:syserror=85; break}
default {$global:syserror=9999; break}
}
}
if ($global:syserror -eq 5) {
Write-Host "Access to $Server denied for user $env:USERNAME."
} elseif ($global:syserror -eq 15) {
Write-Host "The system cannot find the drive specified."
} elseif ($global:syserror -eq 53) {
Write-Host "The network path was not found."
} elseif ($global:syserror -eq 55) {
Write-Host "The specified network resource or device is no longer available."
} elseif ($global:syserror -eq 67) {
Write-Host "The network name cannot be found."
} elseif ($global:syserror -eq 85) {
$inuseby = Get-PSDrive $drivelettertouse | Select -ExpandProperty DisplayRoot
Write-Host "$($drivelettertouse):\ is already in use by $inuseby."
} elseif ($global:syserror -eq "9999") {
Write-Host "Unknown Error."
Write-Host $err
}
Upvotes: 0
Reputation: 5871
You can do the following:
#set process startup info (redirect stderr)
$pinfo = new-object System.Diagnostics.ProcessStartInfo
$pinfo.Filename = "net.exe"
$pinfo.UseShellExecute = $false
$pinfo.Arguments = @("use","\\$($HOSTIP)","$($PASSWD)","/user:$($UNAME)")
$pinfo.redirectstandardError = $true
#start process and wait for it to exit
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.start() | out-null
$p.waitforexit()
#check the returncode
if($p.exitcode -ne 0){
#rc != 0 so we grab the stderr output
$err = $p.standardError.ReadToEnd()
#first line of the output contains the string from your question, matching it against regex
if($err[0] -match "System error ([0-9]*) has occurred"){
#switching the error code
switch($Matches[1]){
64 {do-something64;break;}
67 {do-something67;break;}
}
}
}
This should do the trick, although i cant make a statement about how performant it is, you will have to try. If the output can differ from the string you posted in your question you will have to write your own regexes to handle them.
Keep in mind that the output from net
is localized so the regex in my example will not work on systems where the system language is not english.
Hope that helps
Upvotes: 2
Reputation: 73616
Use cmd
to redirect stderr
to stdout
:
$log = cmd /c "2>&1" net use \\$HOSTIP $PASSWD /user:$UNAME
Now the variable contains an array of strings (2 with text and 2 empty):
System error 53 has occurred.
The network path was not found.
You can parse it:
$log = cmd /c "2>&1" net use \\$HOSTIP $PASSWD /user:$UNAME
if ($LASTEXITCODE -and $log -join "`n" -match '^.+?(\d+).+?\n+(.+)') {
$errCode = [int]$matches[1]
$errMessage = $matches[2]
}
Upvotes: 1