<#
.SYNOPSIS
Configure new role and assign permission into the vCenter
.DESCRIPTION
This script configure global permissions in to the vCenter.
.PARAMETER vCenterName
Specify vCenter FQDN or
.PARAMETER Username
Specify vCenter Username who has access to assign permission
.PARAMETER Password
Specify vCenter Username Password
.PARAMETER JSONFile
Specific the path of the JSON file
.EXAMPLE
./vCenter-Role-Management.ps1 -vCenterName "vcsa01.example.com" -Username "administrator@vsphere.local" -Password "Password123!" -JSONFile "C:\temp\roles.json"
.CREDITS
https://www.powershellgallery.com/packages/VIPerms/0.0.6
https://williamlam.com/2017/03/automating-vsphere-global-permissions-with-powercli.html
#>
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true)]
[System.String]$vCenterName,
[Parameter(Position=1, Mandatory=$true)]
[System.String]$Username,
[Parameter(Position=2, Mandatory=$true)]
[System.String]$Password,
[Parameter(Position=3, Mandatory=$true)]
[System.String]$JSONFile
)
$JSONFile = "D:\Abhishek\Lab\Roles.json";
function Logger {
<#
.DESCRIPTION
This function is created for logging purpose
.PARAMETER <paramName>
There are two param available to this function
$MessageType - Expected value should be I, W, E
$Message - This is the message
.EXAMPLE
Logger -MessageType E -Message "This is error message"
Logger -Message "This is info message"
Logger -MessageType W -Message "This is warning message"
#>
param (
[Parameter(
Position = 0,
Mandatory = $false
)]
[string] $MessageType,
[Parameter(
Position = 1,
Mandatory = $true
)]
[string] $Message
)
$Message = $(Get-Date -Format "yyyy-MM-dd hh:mm:ss.fff") + " - " + $Message
switch ($MessageType) {
"W" {
Write-Host -ForegroundColor Yellow $Message
}
"E" {
Write-Host -ForegroundColor Red $Message
}
default {
Write-Host -ForegroundColor Green $Message
}
}
}
function Connect-VIMobServer {
<#
.SYNOPSIS
Connect to the vSphere Managed Object Browser (MOB).
.DESCRIPTION
This function will first test the connection to the specified vCenter server MOB. If successful
the Uri and PSCredentials object are stored in the global variable $Global:VIPerms for use
with other functions in this module.
.PARAMETER Server
Specify the name of a vCenter server.
.PARAMETER Credential
Specify the credentials to use to authenticate against the MOB.
This is usually administrator@vsphere.local
.PARAMETER SkipCertificateCheck
Skip certificate verification.
.EXAMPLE
Connect-VIMobServer -Server "vcenter.example.com"
#>
param (
[Parameter(
Position = 0,
Mandatory = $true
)]
[string] $Server,
[Parameter(
Position = 1,
Mandatory = $true
)]
[PSCredential] $Credential,
[Parameter(
Position = 2,
Mandatory = $false
)]
[Switch] $SkipCertificateCheck
)
try {
$ProPref = $ProgressPreference
$ProgressPreference = "SilentlyContinue"
if ($SkipCertificateCheck) {
Set-CertPolicy -SkipCertificateCheck
}
$Global:VIPerms = @{
Server = $Server
Credential = $Credential
SkipCertificateCheck = $true
}
Invoke-Login -Server $Server -Credential $Credential
[PSCustomObject] @{
Server = $Server
User = $Credential.GetNetworkCredential().UserName
}
Invoke-Logoff
if ($SkipCertificateCheck) {
Set-CertPolicy -ResetToDefault
}
$ProgressPreference = $ProPref
} catch {
$Err = $_
throw $Err
}
}
function Invoke-Login {
<#
.SYNOPSIS
Authenticate against vCenter MOB
.DESCRIPTION
Authenticate against vCenter MOB and grab the vmware-session-nonce. This is then stored in the global
VIPerms hashtable along with the session variable from the web request.
#>
try {
$ProPref = $ProgressPreference
$ProgressPreference = "SilentlyContinue"
if (!($Global:VIPerms.Server) -or ([String]::IsNullOrEmpty($Global:VIPerms.Server)) -or
!($Global:VIPerms.Credential) -or ([String]::IsNullOrEmpty($Global:VIPerms.Credential))) {
throw "Please authenticate using Connect-VIMobServer first!"
}
$Uri = ("https://$($Global:VIPerms.Server)/invsvc/mob3/?moid=authorizationService&" +
"method=AuthorizationService.GetRoles")
# Initial login to vSphere MOB to store session variable
$Params = @{
Uri = $Uri
SessionVariable = "MobSession"
Credential = $Global:VIPerms.Credential
Method = "GET"
}
$Res = Invoke-WebRequest @Params
# Extract hidden vmware-session-nonce which must be included in future requests to prevent CSRF error
# Credit to https://blog.netnerds.net/2013/07/use-powershell-to-keep-a-cookiejar-and-post-to-a-web-form/ for
# parsing vmware-session-nonce via Powershell
if ($Res.StatusCode -eq 200) {
$null = $Res -match 'name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"'
$Global:VIPerms.SessionNonce = $Matches[1]
$Global:VIPerms.WebSession = $MobSession
} else {
throw "Failed to login to vSphere MOB"
}
$ProgressPreference = $ProPref
} catch {
$Err = $_
throw $Err
}
}
function Invoke-Logoff {
<#
.SYNOPSIS
Logout of the authenticated vCenter MOB web session and clear up the global variable VIPerms.
#>
try {
$ProPref = $ProgressPreference
$ProgressPreference = "SilentlyContinue"
$Uri = "https://$($Global:VIPerms.Server)/invsvc/mob3/logout"
$Res = Invoke-WebRequest -Uri $Uri -WebSession $Global:VIPerms.WebSession -Method GET
$Global:VIPerms.WebSession = $null
$Global:VIPerms.SessionNonce = $null
$ProgressPreference = $ProPref
} catch {
$Err = $_
throw $Err
}
}
function Set-CertPolicy {
<#
.SYNOPSIS
Ignore SSL verification.
.DESCRIPTION
Using a custom .NET type, override SSL verification policies.
#>
param (
[Switch] $SkipCertificateCheck,
[Switch] $ResetToDefault
)
try {
if ($SkipCertificateCheck) {
try {
[Net.ServicePointManager]::SecurityProtocol = "Tls12, Tls11, Tls"
[Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
} catch {
$Err = $_
if ($Err.Exception.Message.StartsWith("Cannot find type [TrustAllCertsPolicy]")) {
Add-Type -TypeDefinition @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
} else {
throw $Err
}
}
} else {
[Net.ServicePointManager]::CertificatePolicy = $null
}
} catch {
$Err = $_
throw $Err
}
}
function New-VIGlobalPermission {
<#
.SYNOPSIS
Add a global permission for a user/group.
.DESCRIPTION
Creates a global permission assigning either a user or group to a specific role.
.PARAMETER Name
Specify the name of user or group including the domain.
.PARAMETER IsGroup
Specify whether the target is a group object or not.
.PARAMETER RoleId
Specify the identifier for the specific role to assign to the global permission.
.PARAMETER Propagate
Specify whether the permission should propagate to all children objects or not.
.PARAMETER SkipCertificateCheck
Skip certificate verification.
.EXAMPLE
New-VIGlobalPermission -Name "VSPHERE.LOCAL\joe-bloggs" -RoleId -1
.EXAMPLE
New-VIGlobalPermission -Name "VSPHERE.LOCAL\group-of-users" -IsGroup -RoleId -1
.EXAMPLE
New-VIGlobalPermission -Name "VSPHERE.LOCAL\joe-bloggs" -RoleId -1 -Propagate:$false
#>
param (
[Parameter(
Position = 0,
Mandatory = $true
)]
[String] $Name,
[Parameter(
Position = 1,
Mandatory = $false
)]
[Switch] $IsGroup,
[Parameter(
Position = 2,
Mandatory = $false
)]
[String] $RoleId,
[Parameter(
Position = 3,
Mandatory = $false
)]
[Switch] $Propagate = [Switch]::Present,
[Parameter(
Position = 4,
Mandatory = $false
)]
[Switch] $SkipCertificateCheck
)
try {
$ProPref = $ProgressPreference
$ProgressPreference = "SilentlyContinue"
if ($SkipCertificateCheck -or $Global:VIPerms.SkipCertificateCheck) {
Set-CertPolicy -SkipCertificateCheck
}
Invoke-Login
$Uri = ("https://$($Global:VIPerms.Server)/invsvc/mob3/?moid=authorizationService&" +
"method=AuthorizationService.AddGlobalAccessControlList")
$Group = switch ($IsGroup) {
$true {"true"}
$false {"false"}
}
$Prop = switch ($Propagate) {
$true {"true"}
$false {"false"}
}
$Body = ("vmware-session-nonce=$($Global:VIPerms.SessionNonce)&" +
"permissions=%3Cpermissions%3E%0D%0A+++%3Cprincipal%3E%0D%0A++++++" +
"%3Cname%3E$([Uri]::EscapeUriString($Name))%3C%2Fname%3E" +
"%0D%0A++++++%3Cgroup%3E$Group%3C%2Fgroup%3E%0D%0A+++%3C%2Fprincipal%3E%0D%0A+++" +
"%3Croles%3E$RoleId%3C%2Froles%3E%0D%0A+++" +
"%3Cpropagate%3E$Prop%3C%2Fpropagate%3E%0D%0A%3C%2Fpermissions%3E")
$Params = @{
Uri = $Uri
WebSession = $Global:VIPerms.WebSession
Method = "POST"
Body = $Body
}
$Res = Invoke-WebRequest @Params
Invoke-Logoff
if ($SkipCertificateCheck -or $Global:VIPerms.SkipCertificateCheck) {
Set-CertPolicy -ResetToDefault
}
$ProgressPreference = $ProPref
Logger -Message "Permission assigned to $Name"
} catch {
$Err = $_
Logger -MessageType E -Message $Err.Exception.Message
}
}
function New-VCRole {
<#
.SYNOPSIS
Create new role using PowerCLI cmdlet New-VIRole
.DESCRIPTION
This function will fetch the privileges and then create a new role
.PARAMETER Privilege_Ids
Specify the privileges ids
.PARAMETER RoleName
Specify the name of new role
.EXAMPLE
New-VCRole -Privilege_Ids "System.View","System.Read","Global.CancelTask" -RoleName "New_Role"
#>
param (
[Parameter(
Position = 0,
Mandatory = $true
)]
[string[]] $Privilege_Ids,
[Parameter(
Position = 1,
Mandatory = $true
)]
[string] $RoleName
)
try {
$privileges = Get-VIPrivilege -Id $Privilege_Ids;
$null = New-VIRole -Name $RoleName -Privilege $privileges -ErrorAction SilentlyContinue
if($? -eq $true){
Logger -Message "Role $RoleName has been created"
$Global:IsRoleCreated = $true;
}
elseif ($error[0].Exception.ErrorId -eq "Client20_InventoryServiceImpl_TryValidateUniqueRoleName_DuplicateName" ) {
$Global:IsRoleCreated = $true;
Logger -MessageType W -Message "Role $RoleName already exists"
}
else{
$Global:IsRoleCreated = $false;
Logger -MessageType E -Message "Role $RoleName unable to create -> $($error[0].Exception.Message)"
}
}
catch {
$Global:IsRoleCreated = $false;
Logger -MessageType E -Message "Role $RoleName unable to create -> $($_.Exception.Message)"
}
}
if($(Test-Path -Path $JSONFile) -eq $true)
{
$Roles = $(Get-Content $JSONFile | ConvertFrom-Json).roles
}
else{
Logger -MessageType E -Message "File path is not valid - $JSONFile"
return;
}
$SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($Username,$SecurePassword)
#Connect vCenter
$vCenter_Connection = Connect-VIServer $vCenterName -Force -Credential $Credential
if($vCenter_Connection.IsConnected -ne $true)
{
Logger -MessageType E -Message "$vCenterName - Unable to connect using $Username -> $($error[0].Exception.Message)"
return;
}
Logger -Message "$vCenterName - Connected using $Username"
$vCenter_MOB_Connection = Connect-VIMobServer -Server $vCenterName -Credential $Credential -SkipCertificateCheck
foreach($role in $Roles)
{
$roleId = $(Get-VIRole -Name $role.rolename).ExtensionData.RoleId;
if($role.roleaction -eq "create")
{
New-VCRole -Privilege_Ids $role.privileges -RoleName $role.rolename
if($Global:IsRoleCreated -eq $false){
continue;
}
foreach($obj in $role.assignment)
{
$is_group = $false;
if($obj.type -eq "group")
{
$is_group = $true;
}
New-VIGlobalPermission -Name $obj.name -IsGroup $is_group -RoleId $roleId
}
}
}
if($vCenter_Connection.IsConnected -ne $true){
$null = Disconnect-VIServer * -Force -Confirm:$false
}