Home > Back-end >  Array of characters instead of array of strings
Array of characters instead of array of strings

Time:11-25

I am trying to get a list of SMB shares on a remote file server. Unfortunately because of the type of server I am querying WMI and CIM won't work. The only thing I can get to work is net view (which I believe uses netbios).

I am running the following code which gets the shares:

$shares = net view \\server1 /all | select -Skip 7 | ?{$_ -match 'disk*'} | %{$_ -match '^(. ?)\s Disk*'|out-null;"\\server1\$($matches[1])"}
$shares  = net view \\server2 /all | select -Skip 7 | ?{$_ -match 'disk*'} | %{$_ -match '^(. ?)\s Disk*'|out-null;"\\server2\$($matches[1])"}


foreach ($share in $shares) {
    $logdir1 = @("$share\App_Data\","errorlogs")
    $logdirs = @($logdir1)

    foreach ($log in $logdirs) {
        write-host $log[0]

However, instead of getting a list of paths, I am getting the first character of each path. So basically $log[0] is a character - not a string as I an expecting.

I think this has to do with the net view command returning characters instead of an object.

I tried using ToString() in various places to no avail. Anyone help me figure out how to get this to work?

Thanks!

CodePudding user response:

Update:

Your problem came down to the misconception that @(...), the array-subexpression operator is an array constructor, which it is not: instead, think of it as an array guarantor.

Thus, replace:

$logdirs = @($logdir1) # WRONG: same as $logDirs = $logdir1 in this case.

with:

$logdirs = , $logdir1

... in order to create a nested array whose one and only element is the two-element array contained in $logDir, using , the array constructor operator, which you can then enumerate with foreach and refer to its elements with [0] and [1].

For background information on @(...), see this answer.


Original answer:

$logdir1 = @("$share\App_Data\","errorlogs")
$logdirs = @($logdir1)

... can be reduced to $logdirs = @("$share\App_Data\", "errorlogs")

    foreach ($log in $logdirs) {

... then enumerates the elements of the array of string values in $logDirs

    write-host $log[0]

... then refers to the first character ([0]) of the string value at hand (indexing into a string extracts the character at the specified position; e.g., 'abc'[1] yields 'b')

Therefore, everything works as expected.

Perhaps you meant to enumerate the files inside the directory referenced by each $log value (renamed to $logDir for clarity below)?

foreach ($logdir in $logdirs) {
  $filesInDir = Get-ChildItem -File -LiteralPath $logdir
  $filesInDir[0]
}

CodePudding user response:

I believe you could simplified your code to this:

$servers = 'server1', 'server2'
$logdirs = 'App_Data', 'ErrorLogs'

foreach($server in $servers) {
    net view \\$server /all | Select-String -Pattern '^(. ?)\s Disk*' | ForEach-Object {
        foreach($logdir in $logdirs) {
            [IO.Path]::Combine('\\', $server, $_.Matches.Groups[1], $logdir)
        }
    }
}

Seem to work fine in my test lab. This would return the UNC paths of all shares concatenating each element of $logdirs at the end.

CodePudding user response:

External tools always return string[] with each line of output being an element in the output array.

You need to parse those lines for use with Powershell first, assuming of course "line of output" is sufficient (as in DIR /B output from cmd). The -replace operator might be of help there (NB: uses regex patterns rather than string matching).

It's probably a good idea to extract such interop code into its own function / module.

  • Related