9

I'm trying to check wheter some network drives are mapped via logon script. If they're not mapped, the script should be able to map them but My Foreach-Object in the code below doesn't work. why? Can't I use it on hashtables?

$Hash = @{
    "h:" = "\\server\share";
    "i:" = "\\server\share";
    "j:" = "\\server\share";
    "k:" = "\\server\share";
    "p:" = "\\server\share";
    "z:" = "\\server\share";
    }
        $Hash | ForEach-Object
        {
            If (!(Test-Path $_.Name))
            {
                $map = new-object -ComObject WScript.Network
                $map.MapNetworkDrive($_.Name, $_.Value, $true)
                Write-Host "Mapped That Stuff"
            }
            else
            {Write-Host ($Hash.Name) + ($Hash.Value)}
        }

How do I have to use foreach in this situation? Or is there a better way to solve this issue instead of a hashtable or a foreach loop?

2 Answers 2

16

To iterate over a [hashtable] you need to get an enumerator for it:

   $Hash.GetEnumerator() | ForEach-Object {
        If (!(Test-Path $_.Name))
        {
            $map = new-object -ComObject WScript.Network
            $map.MapNetworkDrive($_.Name, $_.Value, $true)
            Write-Host "Mapped That Stuff"
        }
        else
        {Write-Host ($_.Name) + ($_.Value)}
    }
3
  • Hello @briantist - thanks for your reply. Is it normal that if I run just this part from the script (with the hash of course). that there is a return which says:" Process[0]:" and wants me to put in some information? what is this
    – SimonS
    Commented Nov 10, 2015 at 7:01
  • 1
    ok i got this one. the "{" has to be on the same line as ForEach-Object
    – SimonS
    Commented Nov 10, 2015 at 8:46
  • @SimonS is correct. ForEach-Object is a cmdlet, unlike foreach which is a statement. Cmdlets are basically functions; they take parameters. With ForEach-Object you pass a [ScriptBlock] as a parameter, so it can't be on a new line unless you use backtick (but don't do that). This is one reason I prefer not to use C# style indentation/brace placement with PowerShell.
    – briantist
    Commented Nov 10, 2015 at 16:10
6

I usually just use the Keys property of a hashtable to iterate over it. So your script would be:

$Hash = @{
    "h:" = "\\server\share";
    "i:" = "\\server\share";
    "j:" = "\\server\share";
    "k:" = "\\server\share";
    "p:" = "\\server\share";
    "z:" = "\\server\share";
    }
        $Hash.Keys | ForEach-Object
        {
            If (!(Test-Path $_))
            {
                $map = new-object -ComObject WScript.Network
                $map.MapNetworkDrive($_, $Hasj.$_, $true)
                Write-Host "Mapped That Stuff"
            }
            else
            {Write-Host ($_) + ($Hash.$_)}
        }

Actually, after looking at it I think I'd take a shorter route, use a Where statement to just find the drives that don't exist, and then map those drives:

$Hash = @{
    "h:" = "\\server\share";
    "i:" = "\\server\share";
    "j:" = "\\server\share";
    "k:" = "\\server\share";
    "p:" = "\\server\share";
    "z:" = "\\server\share";
    }

$Hash.Keys | Where{!(Test-Path $_)} | ForEach{ New-PSDrive -Name $_.trim(':') -PSProvider FileSystem -Root $Hash.$_ -Persist }

I used the New-PSDrive cmdlet there and the -Persist argument which then makes a standard Windows Mapped Drive that you can see and manage through Windows Explorer just like any other mapped drive. If you don't want that kind of mapping just remove the -Persist argument and it will then just be mapped for your script.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.