Loading...

As most of you might know by now, VMware is moving away from SOAP and going to REST API.

Is this something you should know about? Yes, you should!

In a two-part article on TechGenix, I wrote down my thoughts and observations on REST API. The article goes into what this move towards the REST API might mean for you as a scripter/administrator.

Since an article on coding, without a coding example doesn’t make much sense, I added a module, named rCisTag on the PowerCLI Examples repository.

Articles

Enjoy reading Part 1, Understanding the VMware REST API interface!

Part 2 will be published in the coming days.

Read Full Article
Visit website
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Your vSphere environment is a living environment. Inventory objects are created and removed all the time. Together with these inventory objects there are often security permissions that come along. Team X needs Power User access for all VMs in folder Project-X. But the life-cycle management of these permissions is often not as fluent as your VM life cycle management. There is no built in permission cleanup method.

As a result, old permissions might be left behind, and what is worse, redundant permissions might be present. This doesn’t make the task of investigating “Who can do what?” in your vSphere environment any easier.

With the help of the function in this post you can now get rid of all these redundant permissions!

The Script

function Optimize-VIPermission{
<#
.SYNOPSIS
  Find and remove redundant permissions on vSphere objects 
.DESCRIPTION
  The function will recursively scan the permissions on the
  inventory objects passed via the Entity parameter.
  Redundant permissions will be removed.
.NOTES
  Author:  Luc Dekens
.PARAMETER Entity
  One or more vSphere inventory objects from where the scan
  shall start
.EXAMPLE
  PS> Optimize-Permission -Entity Folder1 -WhatIf
.EXAMPLE
  PS> Optimize-Permission -Entity Folder?
.EXAMPLE
  PS> Get-Folder -Name Folder* | Optimize-Permission
#>

  [cmdletbinding(SupportsShouldProcess=$true)]
  param(
    [parameter(ValueFromPipeline)]
    [PSObject[]]$Entity
  )
 
  Begin{
    function Optimize-iVIPermission{
      [cmdletbinding(SupportsShouldProcess=$true)]
      param(
        [parameter(ValueFromPipeline)]
        [VMware.Vim.ManagedObjectReference]$Entity,
        [VMware.Vim.Permission[]]$Permission = $null
      )

      Process{
        $entityObj = Get-View -Id $Entity
        $removePermission = @()
        $newParentPermission = @()
        if($Permission){
          foreach($currentPermission in $entityObj.Permission){
            foreach($parentPermission in $Permission){
              if($parentPermission.Principal -eq $currentPermission.Principal -and
                 $parentPermission.RoleId -eq $currentPermission.RoleId){
                $removePermission += $currentPermission
                break
              }
              else{
                $newParentPermission += $currentPermission
              }
            }
          }
        }
        else{
          $newParentPermission += $entityObj.Permission
        }
        if($removePermission){
          if($pscmdlet.ShouldProcess("$($entityObj.Name)", "Cleaning up permissions")){
            $removePermission | %{
              $authMgr.RemoveEntityPermission($Entity,$_.Principal,$_.Group)
            }
          }
        }
        $Permission += $newParentPermission
       
        if($entityObj.ChildEntity){
            $entityObj.ChildEntity | Optimize-iVIPermission -Permission $Permission
        }
      }
    }
  }
 
  Process{
    foreach($entry in $Entity){
       if($entry -is [System.String]){
        $entry = Get-Inventory -Name $entry
       }
       Optimize-iVIPermission -Entity $entry.ExtensionData.MoRef
    }
  }
}

Annotations

Line 24-25: the function accepts one or more vSphere Inventory objects, as a parameter or through the pipeline

Line 29-70: this is the internal function that does the actual work. The main function is just a wrapper to handle (and eventually convert) the parameter.

Line 39-40: the function recursively descends the inventory tree, and it checks the permissions on each node against the recursive permissions that were assigned in nodes higher up in the tree. To check what is there and what can be removed, the arrays $removePermission and $newParentPermission are used.

Line 44-45: in the current version of the function, the Principal and the Role need to be match, before the permission is considered to be removed

Line 58-64: if redundant permissions were discovered on the current node in the vSphere inventory tree, then the redundant permission will be removed. Or if the WhatIf switch was used, a message will be displayed.

Line 68: the internal function is called recursively for each child of the current node. The permissions that were already encountered on the parent nodes, are passed as a parameter to the internal function.

Line 77-79: a “cheap” implementation of OBN

Sample Usage

The use of the Optimize-VIPermission function is quite straightforward.

As a test environment, we applied some permissions on two different node in the tree. In this case for the Principal LOCAL\test.

In its simplest form, you just pass the name of the object where the optimization should start. Notice how we used the WhatIf switch on the function call. No actual permissions will be removed, but the function will show what it would do.

Optimize-VIPermission -Entity Test1 -WhatIf

And this produces the following output.

The function also accepts multiple starting points, you can pass multiple locations on the Entity parameter.

Optimize-VIPermission -Entity Test1,Test2 -WhatIf

The function output now shows the following (because we added a second redundant permission in the tree under Test2).

And you can use the function in a pipeline construct, like this.

Get-Folder -Name Test? | Optimize-VIPermission -WhatIf

Which produces exactly the same output as the previous example.

Note: it is strongly advised to always run this first with the WhatIf switch. Only when the WhatIf switch is not used, or when it receives a $false value, will the redundant permissions actually be removed!

Enjoy!

Read Full Article
Visit website
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

The Invoke-VMScript cmdlet is definitely one of the PowerCLI cmdlets that is indispensable when you need to do things inside the Guest OS of your VMs.

When you are interacting with a Windows based Guest OS you can run old-fashioned BAT files or use PowerShell scripts. When the Guest OS is Linux based, you currently only can run Bash scripts.

Most Linux flavours have a feature that is called SheBang, and which allows you to specify in the first line of your bash script, which interpreter shall be used to run the following lines of the script. Unfortunately, the current Invoke-VMScript cmdlet doesn’t allow one to use that feature.

Time to tackle that issue, and expand the possibilities for all VMs that have a Linux-based Guest OS. So I decided to write my Invoke-VMScriptPlus function.

When the PowerCLI Feature Request website was announced during VMworld session #SER2529BU, it was no surprise to me, to rather quickly see a request appearing to support other languages, besides bash.

First I did some tests, to check if I could get the Invoke-VMScript cmdlet to work with a the SheBang line.

$vmName = 'ubuntu1'
$vm = Get-VM -Name $vmName

$codeBashPlain = @"
echo "Hello World!"
"@

$codeBashSheBang = @"
#!/usr/bin/env bash
echo "Hello World!"
"@

$sScript = @{
    VM = $vm
    GuestUser = 'lucd'
    GuestPassword = 'Just@Password1!'
    ScriptType = 'Bash'
    ScriptText = $codeBashPlain
}

Invoke-VMScript @sScript

$sScript['ScriptText'] = $codeBashSheBang
Invoke-VMScript @sScript

Unfortunately it doesn’t.

When a cmdlet doesn’t do what you are trying to achieve, there is always the vSphere API that can help. The GuestOperationsManager is the place to look. From there we can access methods to start and monitor a process in the guest  and to handle files inside the guest OS.
The StartProgramInGuest is the central method of the Invoke-VMScriptPlus function. The function uses the arguments property on the GuestProgramSpec object to redirect the stdio of the process.

The following flow-chart shows a high-level view of the logic that is used in the Invoke-VMScriptPlus function, and shows which method is used at which point.

The Code

#requires -Version 5.0
#requires -Modules VMware.VimAutomation.Core

class MyOBNv2:System.Management.Automation.ArgumentTransformationAttribute
{
    [ValidateSet(
        'Cluster','Datacenter','Datastore','DatastoreCluster','Folder',
        'VirtualMachine','VirtualSwitch','VMHost','VIServer'
    )]
    [String]$Type

    MyOBNv2([string]$Type)
    {
        $this.Type = $Type
    }
    [object] Transform([System.Management.Automation.EngineIntrinsics]$engineIntrinsics,[object]$inputData)
    {
        if ($inputData -is [string])
        {
            if (-NOT [string]::IsNullOrWhiteSpace( $inputData ))
            {
                $cmdParam = "-$(if($this.Type -eq 'VIServer'){'Server'}else{'Name'}) $($inputData)"
                $sCmd = @{
                    Command = "Get-$($this.Type.Replace('VirtualMachine','VM')) $($cmdParam)"
                }
                return (Invoke-Expression @sCmd)
            }
        }
        elseif($inputData.GetType().Name -match "$($this.Type)Impl")
        {
            return $inputData
        }
        elseif($inputData.GetType().Name -eq 'Object[]')
        {
            return ($inputData | %{
                if($_ -is [String])
                {
                    return (Invoke-Expression -Command "Get-$($this.Type.Replace('VirtualMachine','VM')) -Name `$_")
                }
                elseif($_.GetType().Name -match "$($this.Type)Impl")
                {
                    $_
                }
            })
        }
        throw [System.IO.FileNotFoundException]::New()
    }
}

function Invoke-VMScriptPlus
{
<#
.SYNOPSIS
  Runs a script in a Linux guest OS.
  The script can use the SheBang to indicate which interpreter to use.
.DESCRIPTION
  This function will launch a script in a Linux guest OS.
  The script supports the SheBang line for a limited set of interpreters.
.NOTES
  Author:  Luc Dekens
.PARAMETER VM
  Specifies the virtual machines on whose guest operating systems
  you want to run the script.
.PARAMETER GuestUser
  Specifies the user name you want to use for authenticating with the
  virtual machine guest OS.
.PARAMETER GuestPassword
  Specifies the password you want to use for authenticating with the
  virtual machine guest OS.
.PARAMETER GuestCredential
  Specifies a PSCredential object containing the credentials you want
  to use for authenticating with the virtual machine guest OS.
.PARAMETER ScriptText
  Provides the text of the script you want to run. You can also pass
  to this parameter a string variable containing the path to the script.
  Note that the function will add a SheBang line, based on the ScriptType,
  if none is provided in the script text.
.PARAMETER ScriptType
  The supported Linux interpreters.
  Currently these are bash,perl,python3,nodejs,php,lua
.PARAMETER CRLF
  Switch to indicate of the NL that is returned by Linux, shall be
  converted to a CRLF
.PARAMETER Server
  Specifies the vCenter Server systems on which you want to run the
  cmdlet. If no value is passed to this parameter, the command runs
  on the default servers. For more information about default servers,
  see the description of Connect-VIServer.  
.EXAMPLE
  $pScript = @'
  #!/usr/bin/env perl
  use strict;
  use warnings;
 
  print "Hello world\n";
  '@
    $sCode = @{
      VM = $VM
      GuestCredential = $cred
      ScriptType = 'perl'
      ScriptText = $pScript
  }
  Invoke-VMScriptPlus @sCode
.EXAMPLE
  $pScript = @'
  print("Happy 10th Birthday PowerCLI!") 
  '@
    $sCode = @{
      VM = $VM
      GuestCredential = $cred
      ScriptType = 'python3'
      ScriptText = $pScript
  }
  Invoke-VMScriptPlus @sCode
#>    
    [cmdletbinding()]    
    param(
        [parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [MyOBNv2('VirtualMachine')]
        [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine[]]$VM,
        [Parameter(Mandatory=$true,ParameterSetName='PlainText')]
        [String]$GuestUser,
        [Parameter(Mandatory=$true,ParameterSetName='PlainText')]
        [String]$GuestPassword,
        [Parameter(Mandatory=$true,ParameterSetName='PSCredential')]
        [PSCredential[]]$GuestCredential,
        [Parameter(Mandatory=$true)]
        [String]$ScriptText,
        [Parameter(Mandatory=$true)]
        [ValidateSet('bash','perl','python3','nodejs','php','lua')]
        [String]$ScriptType,
        [Switch]$CRLF,
        [MyOBNv2('VIServer')]
        [VMware.VimAutomation.ViCore.Types.V1.VIServer]$Server = $global:DefaultVIServer

    )

    Begin
    {
        $si = Get-View ServiceInstance
        $guestMgr = Get-View -Id $si.Content.GuestOperationsManager
        $gFileMgr = Get-View -Id $guestMgr.FileManager
        $gProcMgr = Get-View -Id $guestMgr.ProcessManager

        $shebangTab = @{
            'bash' = '#!/usr/bin/env bash'
            'perl' = '#!/usr/bin/env perl'
            'python3' = '#!/usr/bin/env python3'
            'nodejs' = '#!/usr/bin/env nodejs'
            'php' = '#!/usr/bin/env php'
            'lua' = '#!/usr/bin/env lua'
        }
    }

    Process
    {
        foreach($vmInstance in $VM){
            # Preamble
            if($vmInstance.PowerState -ne 'PoweredOn')
            {
                Write-Error "VM $($vmInstance.Name) is not powered on"
                continue
            }
            if($vmInstance.ExtensionData.Guest.ToolsRunningStatus -ne 'guestToolsRunning')
            {
                Write-Error "VMware Tools are not running on VM $($vmInstance.Name)"
                continue
            }

            $moref = $vmInstance.ExtensionData.MoRef

            # Test if code contains a SheBang, otherwise add it
            $targetCode = $shebangTab[$ScriptType]
            if($ScriptText -notmatch "^$($targetCode)"){
                $ScriptText = "$($targetCode)`n`r$($ScriptText)"
            }
    
            # Create Authentication Object (User + Password)
            
            if($PSCmdlet.ParameterSetName -eq 'PSCredential')
            {
                $GuestUser = $GuestCredential.GetNetworkCredential().username
                $GuestPassword = $GuestCredential.GetNetworkCredential().password
            }
    
            $auth = New-Object VMware.Vim.NamePasswordAuthentication
            $auth.InteractiveSession = $false
            $auth.Username = $GuestUser
            $auth.Password = $GuestPassword
            
            # Copy script to temp file in guest
            
            # Create temp file for script
            Try{
                $tempFile = $gFileMgr.CreateTemporaryFileInGuest($moref,$auth,"$($env:USERNAME)_","_$($PID)",'/tmp')
            }
            Catch{
                Throw "$error[0].Exception.Message"
            }
            
            # Create temp file for output
            Try{
                $tempOutput = $gFileMgr.CreateTemporaryFileInGuest($moref,$auth,"$($env:USERNAME)_","_$($PID)_output",'/tmp')
            }
            Catch{
                Throw "$error[0].Exception.Message"
            }
           
            # Copy script to temp file
            $lCode = $ScriptText.Split("`r") -join ''
            $attr = New-Object VMware.Vim.GuestFileAttributes
            $clobber = $true
            $filePath = $gFileMgr.InitiateFileTransferToGuest($moref,$auth,$tempFile,$attr,$lCode.Length,$clobber)
            $copyResult = Invoke-WebRequest -Uri $filePath -Method Put -Body $lCode
            
            if($copyResult.StatusCode -ne 200)
            {
                Throw "ScripText copy failed!`rStatus $($copyResult.StatusCode)`r$(($copyResult.Content | %{[char]$_}) -join '')"
            }
                
            # Make temp file executable
            $spec = New-Object VMware.Vim.GuestProgramSpec
            $spec.Arguments = "751 $($tempFile.Split('/')[-1])"
            $spec.ProgramPath = '/bin/chmod'
            $spec.WorkingDirectory = '/tmp'
            Try{
                $procId = $gProcMgr.StartProgramInGuest($moref,$auth,$spec)
            }
            Catch{
                Throw "$error[0].Exception.Message"
            }
            
            # Run temp file
            
            $spec = New-Object VMware.Vim.GuestProgramSpec
            $spec.Arguments = " > $($tempOutput)"
            $spec.ProgramPath = "$($tempFile)"
            $spec.WorkingDirectory = '/tmp'
            Try{
                $procId = $gProcMgr.StartProgramInGuest($moref,$auth,$spec)
            }
            Catch{
                Throw "$error[0].Exception.Message"
            }
            
            # Wait for script to finish
            Try{
                $pInfo = $gProcMgr.ListProcessesInGuest($moref,$auth,@($procId))
                while($pInfo.EndTime -eq $null){
                    sleep 1
                    $pInfo = $gProcMgr.ListProcessesInGuest($moref,$auth,@($procId))
                }
            }
            Catch{
                Throw "$error[0].Exception.Message"
            }

            # Retrieve output from script
            
            $fileInfo = $gFileMgr.InitiateFileTransferFromGuest($moref,$auth,$tempOutput)
            $fileContent = Invoke-WebRequest -Uri $fileInfo.Url -Method Get
            if($fileContent.StatusCode -ne 200)
            {
                Throw "Retrieve of script output failed!`rStatus $($fileContent.Status)`r$(($fileContent.Content | %{[char]$_}) -join '')"
            }
            
            # Clean up

            # Remove output file
            $gFileMgr.DeleteFileInGuest($moref,$auth,$tempOutput)
            
            # Remove temp script file
            $gFileMgr.DeleteFileInGuest($moref,$auth,$tempFile)
    
            New-Object PSObject -Property @{
                VM = $vmInstance
                ScriptOutput = &{
                    $out = ($fileContent.Content | %{[char]$_}) -join ''
                    if($CRLF)
                    {
                        $out.Replace("`n","`n`r")
                    }
                    else
                    {
                        $out
                    }
                }
                Pid = $procId
                PidOwner = $pInfo.Owner
                Start = $pInfo.StartTime
                Finish = $pInfo.EndTime
                ExitCode = $pInfo.ExitCode
                ScriptType = $ScriptType
                ScriptText = $ScriptText
            }
        }
    }
}

Annotations

Line 1: The function requires PowerShell v5 or higher

Line 2: The function requires the PowerCLI Core module

Line 4-48: The latest version of my OBN (Object By Name) class. It allows one to pass or the actual .Net object, or the name of the object, as an argument to a parameter.

Line 132: Most Linux OS return output with only a LF. This switch can be used to convert the LF to a CRLF, when the resulting output of the script is returned.

Line 145-152: A hard-coded table with the supported interpreters, and their corresponding SheBang line.

Line 159-168: If the VM is not powered on, or if the VMware Tools are not running, the function will return with a result.

Line 173-176: Tests if there is a SheBang line in the ScriptText. If not, it will add a line based on the ScriptType value.

Line 193-207: The function uses two temporary files to store the script and the script’s output.

Line 210-219: The ScriptText is copied to the temporary file. This is done over HTTPS with the Invoke-WebRequest cmdlet.

Line 222-231: The file containing the ScriptText needs to be made “executable”

Line 235-256: Script execution is started, and the function waits till the process completes.

Line 236: The function uses the Arguments property to redirect stdio to the second temporary file

Line 260-265: The output is fetched, again with an Invoke-WebRequest.

Line 270-273: Clean up the temporary files

Line 275-295: Return an object containing the script output and further info about the script execution

Sample Use

The use of the function Invoke-VMScriptPlus is quite similar to the use of the original Invoke-VMScript.

Some examples.

Bash

$codeBash = @"
#!/usr/bin/env bash
echo "Hello World!"
"@

$sCode = @{
  VM = $vm
  GuestCredential = $cred
  ScriptTYpe = 'bash'
  ScriptText = $codeBash
}

Invoke-VMScriptPlus @sCode

And the result

Python3

In this example we are not adding the SheBang line in the ScriptText, but through the ScriptType value, the function will add this line.

$codePython = @"
print("Happy 10th Birthday PowerCLI!")
"@

$sCode = @{
 VM = $vm
 GuestCredential = $cred
 ScriptTYpe = 'python3'
 ScriptText = $codePython
}

Invoke-VMScriptPlus @sCode

And the result.
Notice how the Invoke-VMScriptPlus function added the SheBang line.

Other

During the VMworld Breakout session, where this function was first demonstrated, we showed the additional examples in the following video.

Since there are many Linux falvours out there, and since I obviously couldn’t test them all, I would appreciate if you can send me feedback about which Linux flavours/versions work, and which don’t.
If there are requests for other languages, feel free to forward me your requests.

Enjoy!

Read Full Article
Visit website
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

It is no secret that PowerCLI has lots of amazing options and well-thought trough features. But there is one feature that most of PowerCLI’s users take for granted, and most probably do not even realise that they are using what is called Object By Name or OBN. In this post I’ll show you one way of creating your own OBN, a home made Object By Name, which you can use in your own functions and modules.

OBN allows you to refer to a PowerCLI object by name, instead of passing an actual PowerCLI object. A classic example is “Get-VM -Datastore DS1“, where we are retrieving all VMs that live on a specific datastore. If one looks at the description of the Datastore parameter, it clearly states that a value of type StorageResource is expected, but we are able to provide the datastorename, a string. Under the cover, PowerCLI converts this string to the required PowerCLI object for the parameter.

When we are writing our own functions, it would be very handy to have the same functionality at our disposal. Define a parameter to be of the type of a PowerCLI object, but then be able to pass the name of the object, instead of the object itself.
The solution is there, with the MyOBN attribute, we will now have the same functionality available, that was until now only available for PowerCLI cmdlets.

Some History

To have a better understanding, I’ll show some example functions.

The first function, Invoke-Test1, uses a Datastore parameter, that accepts a PowerCLI Datastore object.

Function Invoke-Test1{
    param(
        [VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore]$Datastore
    )

    Process{
        $Datastore | Select Name,CapacityGB
    }
}

$dsName = 'DS1'
$ds = Get-Datastore -Name $dsName

Invoke-Test1 -Datastore $ds

If we execute this, we get the Name and the Capacity, in GB, of said datastore.

But if try to use the name of the datastore, as we are used with the Datastore parameter on the Get-VM cmdlet, we get an error.

To get our function to behave more like OBN on the PowerCLI cmdlets, we can define the parameter as a general PSObject object. And perform the type casting inside the function. Something like this.

Function Invoke-Test2{
    param(
        [PSObject]$Datastore
    )

    Process{
        if($Datastore -is [System.String]){
            $Datastore = Get-Datastore -Name $Datastore
        }

        Get-VM -Datastore $Datastore | select Name
    }
}

$dsName = 'DS1'
$ds = Get-Datastore -Name $dsName

Invoke-Test2 -Datastore $ds

Our function now works with a Datastore object

but also with a String.

Note that this way of simulating the OBN functionality is far from fool-proof. There is for example no strict type checking, we could pass a VirtualMachine object on the Datastore parameter, and our function would throw an error.

When I first read about Custom Attributes, in a blog post, named Powershell: Creating and using custom attributes, from Kevin Marquette, I immediately saw the potential to get one step closer to a proper OBN in my functions.

For now, I have implemented the Attribute as a class, which implies its use is limited to PowerShell v5.* or higher.

The Code

#requires -Version 5.0

class MyOBN:System.Management.Automation.ArgumentTransformationAttribute
{
    [ValidateSet(
        'Cluster','Datacenter','Datastore','DatastoreCluster','Folder',
        'VirtualMachine','VirtualSwitch','VMHost'
    )]
    [String]$Type

    MyOBN([string]$Type)
    {
        $this.Type = $Type
    }

    [object] Transform([System.Management.Automation.EngineIntrinsics]$engineIntrinsics, [object]$inputData)
    {
        if ($inputData -is [string])
        {
            if (-NOT [string]::IsNullOrWhiteSpace( $inputData ))
            {
                return (Invoke-Expression -Command "Get-$($this.Type) -Name `$inputData")
            }
        }
        elseif($inputData.GetType().Name -match "$($this.Type)Impl"){
            return $inputData
        }

        throw [System.IO.FileNotFoundException]::New()
    }
}
Annotations

Line 1: this code requires PowerShell v5 or up

Line 3: we base the MyOBN class on the ArgumentTransformationAttribute class. We inherit the Transform method from this class. Our override of the Transform method will contain the logic to simulate the OBN functionality.

Line 5-8: currently the Transform method in the MyOBN class supports these PowerCLI types.

Line 9: We need a way to tell the Transform method, which objecttype we want to use. That’s why we add a property Type to the MyOBN class.

Line 11-14: the class has a constructor which allows us to initiate the Type property.

Line 16-30: the Transform method override is where all the magic happens

Line 18: we need to detect if the parameter is a String, in other words if the parameter was passed as an “Object By Name”.

Line 22: with the help of the Type property we invoke the correct PowerCLI cmdlet to convert the String to a PowerCLI obejct

Line 25-27: if the value passed to the parameter was already a PowerCLI object, we just pass that object along

Sample Runs

To use this new parameter attribute is quite straightforward. Make sure the MyOBN class is loaded (this can be through dot-sourcing, adding it to your profile or just including it in your .ps1 file).

Then add the MyOBN attribute like any other parameter attribute. Make sure to specify the “Type” for which you want MyOBN to work. Like this

function Invoke-Test3{
  [CmdletBinding()]
  param(
    [MyOBN('Datastore')]
    [VMware.VimAutomation.ViCore.Types.V1.DatastoreManagement.Datastore]$Datastore
  )

  Process{
    Get-VM -Datastore $Datastore
  }
}

We can now call our function with a Datastore object

but also with a String that contains the name of the Datastore.

And all that without adding any extra code in our function, besides the MyOBN attribute.

Enjoy!

Read Full Article
Visit website
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Separate tags by commas
To access this feature, please upgrade your account.
Start your free month
Free Preview