xofox
Contributor
Contributor

Create vLans in personal folders with specific permission/role

Jump to solution

Hi, french & junior (vmWare) but still aliveSmiley Wink

Existing :

1DC/1Cluster/3ESXI/Vsphere6.7u2

VMware PowerCLI 11.5.0 build 14912921

PowerShell 5/1/14409/1018

vswitch0(management), vswitch1(vm)

2 Usergroups (G,U)

20 users/group (G201,...G220 ; U101,...U120)

Each user got his own private space (ex for user G201)

VMs&templates/G/G201 : VM1,VM2,,,

storage/G : here, no private folder, all the G group VMs are stored here.

networking/Pedago/G/G201 : G-lan-2010, G-lan-2011,..

vSwitch2 created, nic attached, no vlan created in yet.

Expecting :

Create 10 new vlan for each user of group 'G' (using a .csv import) in vswitch2.

- With role/permission (each user can see & operate only its own vm, & same for it own vlan)

- Each user vlan should reach the network folder of the user (to not have to drag it by mouse)

Bonus :

How can I get the full path to a user folder ? Are the vPG at root or in specific folders ?

For example : Network folder of user G201 is in folder 'G', wich is (i think) in 'Students', wich is (i m still not sure) in 'Pedago', wich is in.... network folder. 'Get-Folder' gave me some informations but I m not sure of the real good fullpath. I have to manage something I didn't instal.

Thanks a lot for your help, I had already some hours of search over the net about it and tried some scripts, sadly without the expected result.

0 Kudos
47 Replies
LucD
Leadership
Leadership

The current code doesn't move the PG yet to the correct folder.
This code was to test the creation of the PGs and the permission.

Is that working now?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

Sorry, I wanted to go to fast...

Yes it worked, PG created ont he 3 ESXi, role has been created (role is : ETUDIANTS..... the screenshot below is the user line permission ). It looks just fine.

pastedImage_0.png

I connected over user UFA213, I could see the PG created. Then I created 2 VMs, selected the created PG and coul ping each other. Great !

0 Kudos
LucD
Leadership
Leadership

Ok, the next stage.
Now the script should create the PG on all ESXi nodes in the cluster.

And create the folder and move the PG in there.

function Get-PGMoRef{

    [cmdletbinding()]

    [OutputType([VMware.Vim.ManagedObjectReference])]

    param(

        [string]$VMHost,

        [string]$Portgroup

    )


    $esxNode = Get-VMHost -Name $VMHost

    (Get-View -Id $esxNode.ExtensionData.Network | where{$_.Name -eq $Portgroup}).MoRef

}


function New-PGPermission{

    [cmdletbinding()]

    param(

        [VMware.Vim.ManagedObjectReference]$PGMoRef,

        [string]$Principal,

        [string]$Role

    )


    $authMgr = Get-View AuthorizationManager


    $perm = New-Object VMware.Vim.Permission

    $perm.Entity = $pgMoRef

    $perm.RoleId = (Get-VIRole -Name $role).ExtensionData.RoleId

    $perm.Principal = $principal

    $perm.Group = $false

    $perm.Propagate = $false


    $authMgr.SetEntityPermissions($PGMoRef,@($perm))

}


$vssName = 'vSwitch0'

$pgName = 'TestPG'

$clusterName = 'cluster'

$principal = 'domain\user'

$roleName = 'Admin'

$folderName = 'TestPGFolder'


# Get DC network folder

$netFolder = Get-Datacenter -Cluster $clusterName | Get-Folder -Name network


# Clean up old folder and PG should they exist

$folder = Get-Folder -Name $folderName -Location $netFolder -ErrorAction SilentlyContinue

if($folder){

    if($folder.ExtensionData.ChildEntity){

        $pg = Get-View -Id $folder.ExtensionData.ChildEntity | where{$_.Name -eq $pgName}

        if($pg){

            Get-View -Id $pg.Host | Get-VIObjectByVIView |

            ForEach-Object -Process {

                Get-VirtualPortGroup -VMHost $_ -Name $pgName -ErrorAction SilentlyContinue |

                Remove-VirtualPortGroup -Confirm:$false

            }

        }

        $folder.ExtensionData.UpdateViewData()

        while($folder.ExtensionData.ChildEntity){

            sleep 1

            $folder.ExtensionData.UpdateViewData()

        }

    }

    Remove-Folder -Folder $folder -Confirm:$false

}


# Create folder

$folder = New-Folder -Name $folderName -Location $netFolder


# Assign permission on folder

New-VIPermission -Entity $folder -Principal $principal -Role $roleName | Out-Null


# Create PG on all ESXi nodes

Get-Cluster -Name $clusterName | Get-VMHost -PipelineVariable esx |

ForEach-Object -Process {

    $vss = Get-VirtualSwitch -Name $vssName -VMHost $esx


    # Create new portgroup

    $pg = New-VirtualPortGroup -Name $pgName -VirtualSwitch $vss


    # Get PG MoRef

    $pgMoRef = Get-PGMoRef -Portgroup $pg.Name -VMHost $esx.Name

    while($pgMoRef -eq $null){

        $pgMoRef = Get-PGMoRef -Portgroup $pg.Name -VMHost $esx.Name

        sleep 1

    }


    # Move PG into Folder

    $folder.ExtensionData.MoveIntoFolder($pgMoRef)

  

    # Assign permission on PG

    New-PGPermission -PGMoRef $pgMoRef -Principal $principal -Role $roleName

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

Nice !

Before I launch this new script, the user net folder already exists, Do I need to delete it or is it not important to delete it or not ?(Because of new-Permissions ? Helps me to understand vsphere way of thinking/working).

One more question, how & on which lines I can/need to inform the vLanId ?

I launched the script... And to to break it running (Ctrl + C), because after a few minutes, it was still look like running but not really working. The screenshots :

PS C:\Windows\system32> C:\Users\adminl\Desktop\10032020\NewPGPermission3.ps1

New-VirtualPortGroup : 14/03/2020 12:57:42    New-VirtualPortGroup        The specified key, name, or identifier 'pgName' already exists.   

At C:\Users\adminl\Desktop\10032020\NewPGPermission3.ps1:127 char:11

+     $pg = New-VirtualPortGroup -Name $pgName -VirtualSwitch $vss

+           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [New-VirtualPortGroup], VimException

    + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.Host.NewVirtualPortGroup

pastedImage_2.png

0 Kudos
LucD
Leadership
Leadership

The script should take care of existing folders and portgroups.

But there is a timing issue with removing a PG and seeing an empty network folder.

That is why I built in some loops.

When I run it, with an existing folder and/or existing PG, it hangs for a while, but ultimately completes correctly.

You can of course remove existing folders and PG to be on the safe side.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

I ran once more the script, with existing PG, it ran red (errors) and after +/- 20 minutes I had to kill the process.

I tried after deleting PG. Everything went nice.

Permissions on folder & PG are the right one.

Network folder is in "root network folder", I need it in the folder GRETA, itself in the folder PEDAGO

UFA213                 DATACENTER - SIO\network\PEDAGO\GRETA\UFA213          yellow

(from get-folderpath)

Do you think something is possible here ?

$netFolder = Get-Datacenter -Cluster $clusterName | Get-Folder -Name network

I added the VlanId by this way, is it ok or do I need to add somewhere else ?

$VlanId = '2137'

# Create new portgroup
$pg = New-VirtualPortGroup -Name $pgName -VirtualSwitch $vss -VlanId $VlanId
0 Kudos
LucD
Leadership
Leadership

We will come to the correct folder once the concept works.

I'm doing this step-by-step.

When the PG already exists, where is it located?
And can you see it when you do a Get-VirtualPortgroup?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

Ok, sorry. I'm too much impatient. You know the job, I listen to you. I'm impressed when I see the script becoming more & more complex.

I launched again your last script and no more trouble... I had an ESXi disconnect at the first try, maybe that caused the failure of the running script.?

Existing PG are here :

GRETA                DATACENTER - SIO\network\PEDAGO\GRETA               yellow

The user I used  to test the scripts is UFA213, his folder was there :

UFA213               DATACENTER - SIO\network\PEDAGO\GRETA\UFA213        yellow

Yes I can see the PG when I do a Get-VirtualPortgroup:

GRETA-LAN-2137       key-vim.host.PortGroup-GRET... 2137 
0 Kudos
LucD
Leadership
Leadership

Where is all the input coming from?

Is that from a CSV?

And if yes, which columns are in that CSV?

Does it include the VlanId?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

Actually, I just have a simple column .csv file only with users.

You'll find also the .csv I made in december, in relation with my 1st post on the vmware.community.

I attached the script I tried to use a few days ago. You'll be able to see how I tried to manage the $vlanID and $portgroupname.

Maybe I need to decompose, in the .csv, my 'User' in 'UserWord' and 'UserFigure', mean $UserW=UFA ; $UserF=213 ; $User="$UserW"+"$UserF" ?..

What the best way to do the job ? Or  the best practice ?

1 file for user, 1 file for Vlans, something else  ?

Domain=SIO
Users=UFA201 to UFA220
Vlans 0 to 9 for each user
VLanId=user+vlan
Ex : User UFA213 should have 10 Vlans, from 2130 to 2139

I hope I gave you enough clear and significant informations even if I understand it doesn't answer exactly to your question.  

0 Kudos
LucD
Leadership
Leadership

Let me update the script with that info.

Hold on.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
LucD
Leadership
Leadership

Ok, I think this covers all your requirements.

# Values to be defined

$csvPath = '.\users.csv'

$vlanlist = 0..2

$vssName = 'vSwitch1'

$netFolderBase = 'PEDAGO\GRETA'


function Get-PGMoRef {

    [cmdletbinding()]

    [OutputType([VMware.Vim.ManagedObjectReference])]

    param(

        [string]$VMHost,

        [string]$Portgroup

    )


    $esxNode = Get-VMHost -Name $VMHost

    (Get-View -Id $esxNode.ExtensionData.Network | where { $_.Name -eq $Portgroup }).MoRef

}


function New-PGPermission {

    [cmdletbinding()]

    param(

        [VMware.Vim.ManagedObjectReference]$PGMoRef,

        [string]$Principal,

        [string]$Role

    )


    $authMgr = Get-View AuthorizationManager


    $perm = New-Object VMware.Vim.Permission

    $perm.Entity = $pgMoRef

    $perm.RoleId = (Get-VIRole -Name $role).ExtensionData.RoleId

    $perm.Principal = $principal

    $perm.Group = $false

    $perm.Propagate = $false


    $authMgr.SetEntityPermissions($PGMoRef, @($perm))

}


function Invoke-CleanupNetworkFolder{

    [cmdletbinding()]

    param(

        [VMware.VimAutomation.ViCore.Types.V1.Inventory.Folder]$NetFolder,

        [string]$User

    )


    $folder = Get-Folder -Name $User -Location $netFolder -ErrorAction SilentlyContinue

    if ($folder) {

        if ($folder.ExtensionData.ChildEntity) {

            Get-View -Id $folder.ExtensionData.ChildEntity -PipelineVariable pg | where{$_ -is [VMware.Vim.Network]} |

            ForEach-Object -Process {

                Get-View -Id $pg.Host | Get-VIObjectByVIView |

                ForEach-Object -Process {

                    Get-VirtualPortGroup -VMHost $_ -Name $pg.Name -ErrorAction SilentlyContinue |

                    Remove-VirtualPortGroup -Confirm:$false

                }

            }

            $folder.ExtensionData.UpdateViewData()

            Write-Host -NoNewline "Wait for PG removal in $($folder.Name) "

            while ($folder.ExtensionData.ChildEntity) {

                sleep 1

                Write-Host -NoNewline '.'

                $folder.ExtensionData.UpdateViewData()

            }

            Write-Host ' Done'

        }

        Remove-Folder -Folder $folder -Confirm:$false

    }

}


# Loop over all users

Import-Csv -Path $csvPath -UseCulture -PipelineVariable row |

ForEach-Object -Process {

    # Extract required values

    $domain,$userName = $row.User.Split('/')

    $principal = "$domain\$userName"

    $dcName = "DATACENTER - $($domain)"

    $dc = Get-Datacenter -Name $dcName

    $cluster = Get-Cluster -Location $dcName


    # Get DC network folder

    $netFolder = Get-Folder -Location $dc -Name network

    $netFolderBase.Split('\') | ForEach-Object -Process {

        $netFolder = Get-Folder -Name $_ -Location $netFolder

    }


    # Clean up old folder and PGs, should they exist

    Invoke-CleanupNetworkFolder -NetFolder $netFolder -User $userName


    # Create network folder

    $folder = New-Folder -Name $userName -Location $netFolder


    # Assign permission on folder

    New-VIPermission -Entity $folder -Principal $principal -Role $roleName | Out-Null


    # Create all PG on all ESXi nodes

    Get-VMHost -Location $cluster -PipelineVariable esx |

    ForEach-Object -Process {

        $vss = Get-VirtualSwitch -Name $vssName -VMHost $esx


        $vlanlist | ForEach-Object -Process {

            # Create new portgroup

            $pgName = "$userName$_"

            $pg = New-VirtualPortGroup -Name $pgName -VirtualSwitch $vss -VLanId $_

  

            # Get PG MoRef

            $pgMoRef = Get-PGMoRef -Portgroup $pg.Name -VMHost $esx.Name

            Write-Host -NoNewline "Waiting for PG $($pg.Name) creation "

            while ($pgMoRef -eq $null) {

                $pgMoRef = Get-PGMoRef -Portgroup $pg.Name -VMHost $esx.Name

                sleep 1

                Write-Host -NoNewline '.'

            }

            Write-Host ' Done'

  

            # Move PG into Folder

            $folder.ExtensionData.MoveIntoFolder($pgMoRef)

      

            # Assign permission on PG

            New-PGPermission -PGMoRef $pgMoRef -Principal $principal -Role $roleName

        }

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

Hi Luc,

Should I expect some troubles with existing VMs connected to existing PG, in existing users net folders ?

Should I need to disconnect each VMs of their networks(s) ?

Should I try my my test user and its 2 connected VMs ?

Already existing PGs in an other Vswitch could make troubles ?

Or just keep cool & confident and run your incredible script ? Smiley Happy

0 Kudos
LucD
Leadership
Leadership

This script doesn't connect any VMs to a PG.

If there are already existing PGs, same as the ones the script is making, with connected VMs, the removal of the PG will probably fail.

If there are VMs connected to those existing PGs, you will probably need to disconnect them (if that is possible).

Existing PGs in the vSwitch, different from the ones the script is creating, are not impacted.

If these existing PGs are in the same Folder, there could be an issue.

It is always safer to first test.

Try to test with a realistic as possible setup.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

I launched a first test with my favorite user account test... UFA213. Here some returns :

  • A second network folder has been created for UFA213 (FolderS.jpg)
  • VLanID need to look like 2137, 2138, 2139, for UFA213's VLans 7,8,9 (VlanID.jpg), maybe next step ?
  • $rolename missing ? Else ? (4-result1.rtf & .txt)

About my previous message, I shall need a script to pick up and export network adapters from each VMs of each users in the matching group. But that's for the next step, I remember what you wrote to me, about step by step.

So, I gonna try with user UFA214,, with no VMs, no PGs in its actual existing folder & and the $rolename line in parameters.

A way to delete all PGs in a folder by CLI (to erase a test stage easily than clicking each with the mouse) ? Thanks.

0 Kudos
LucD
Leadership
Leadership

What do you mean by

A second network folder has been created for UFA213 (FolderS.jpg)

Didn't you ask that all new folders had to be created under 'PEDAGO\GRETA'?

Does the script also need to check if the folder already exists somewhere else?

And remove it?

I understood that the VLANId for a user's PGs needed to be in the range 0 to 9.

But it seems you want the number at the username + the number 0 to 9.

Is that correct?

Yes, the content of the variable $roleName needs to be set at the start of the script.

I'll correct that.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
LucD
Leadership
Leadership

This version should contain the fix for the missing $roleName and the incorrect VLANId.
I'm waiting for your feedback on the double folders.

# Values to be defined

$csvPath = '.\users.csv'

$vlanlist = 0..9

$vssName = 'vSwitch1'

$roleName = 'Admin'

$netFolderBase = 'PEDAGO\GRETA'


function Get-PGMoRef {

    [cmdletbinding()]

    [OutputType([VMware.Vim.ManagedObjectReference])]

    param(

        [string]$VMHost,

        [string]$Portgroup

    )


    $esxNode = Get-VMHost -Name $VMHost

    (Get-View -Id $esxNode.ExtensionData.Network | where { $_.Name -eq $Portgroup }).MoRef

}


function New-PGPermission {

    [cmdletbinding()]

    param(

        [VMware.Vim.ManagedObjectReference]$PGMoRef,

        [string]$Principal,

        [string]$Role

    )


    $authMgr = Get-View AuthorizationManager


    $perm = New-Object VMware.Vim.Permission

    $perm.Entity = $pgMoRef

    $perm.RoleId = (Get-VIRole -Name $role).ExtensionData.RoleId

    $perm.Principal = $principal

    $perm.Group = $false

    $perm.Propagate = $false


    $authMgr.SetEntityPermissions($PGMoRef, @($perm))

}


function Invoke-CleanupNetworkFolder{

    [cmdletbinding()]

    param(

        [VMware.VimAutomation.ViCore.Types.V1.Inventory.Folder]$NetFolder,

        [string]$User

    )


    $folder = Get-Folder -Name $User -Location $netFolder -ErrorAction SilentlyContinue

    if ($folder) {

        if ($folder.ExtensionData.ChildEntity) {

            Get-View -Id $folder.ExtensionData.ChildEntity -PipelineVariable pg | where{$_ -is [VMware.Vim.Network]} |

            ForEach-Object -Process {

                Get-View -Id $pg.Host | Get-VIObjectByVIView |

                ForEach-Object -Process {

                    Get-VirtualPortGroup -VMHost $_ -Name $pg.Name -ErrorAction SilentlyContinue |

                    Remove-VirtualPortGroup -Confirm:$false

                }

            }

            $folder.ExtensionData.UpdateViewData()

            Write-Host -NoNewline "Wait for PG removal in $($folder.Name) "

            while ($folder.ExtensionData.ChildEntity) {

                sleep 1

                Write-Host -NoNewline '.'

                $folder.ExtensionData.UpdateViewData()

            }

            Write-Host ' Done'

        }

        Remove-Folder -Folder $folder -Confirm:$false

    }

}


# Loop over all users

Import-Csv -Path $csvPath -UseCulture -PipelineVariable row |

ForEach-Object -Process {

    # Extract required values

    $domain,$userName = $row.User.Split('/')

    $principal = "$domain\$userName"

    $userId = $userName -replace "^\D+"

    $dcName = "DATACENTER - $($domain)"


    $dc = Get-Datacenter -Name $dcName

    $cluster = Get-Cluster -Location $dcName


    # Get DC network folder

    $netFolder = Get-Folder -Location $dc -Name network

    $netFolderBase.Split('\') | ForEach-Object -Process {

        $netFolder = Get-Folder -Name $_ -Location $netFolder

    }


    # Clean up old folder and PGs, should they exist

    Invoke-CleanupNetworkFolder -NetFolder $netFolder -User $userName


    # Create network folder

    $folder = New-Folder -Name $userName -Location $netFolder


    # Assign permission on folder

    New-VIPermission -Entity $folder -Principal $principal -Role $roleName | Out-Null


    # Create all PG on all ESXi nodes

    Get-VMHost -Location $cluster -PipelineVariable esx |

    ForEach-Object -Process {

        $vss = Get-VirtualSwitch -Name $vssName -VMHost $esx


        $vlanlist | ForEach-Object -Process {

            # Create new portgroup

            $pgName = "$userName$_"

            $pg = New-VirtualPortGroup -Name $pgName -VirtualSwitch $vss -VLanId [int]("$userId$_")

  

            # Get PG MoRef

            $pgMoRef = Get-PGMoRef -Portgroup $pg.Name -VMHost $esx.Name

            Write-Host -NoNewline "Waiting for PG $($pg.Name) creation "

            while ($pgMoRef -eq $null) {

                $pgMoRef = Get-PGMoRef -Portgroup $pg.Name -VMHost $esx.Name

                sleep 1

                Write-Host -NoNewline '.'

            }

            Write-Host ' Done'

  

            # Move PG into Folder

            $folder.ExtensionData.MoveIntoFolder($pgMoRef)

      

            # Assign permission on PG

            New-PGPermission -PGMoRef $pgMoRef -Principal $principal -Role $roleName

        }

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

About the second folder, sorry, it's because one of my last try was done in network and not in network/GRETA. No problem here.

Yes VLanID need to be username (digital part...)+0 to 9. For example user UFA213 should have VLanID from 2130 to 2139.

$roleName set at the start of the script.

On a 2nd corrected test, the script ran perfectly, with no error.

0 Kudos
LucD
Leadership
Leadership

So, what is still missing now?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
xofox
Contributor
Contributor

I Launch the last script you sent me and tell you how it went.

0 Kudos