Get the folderpath

A useful property that is obviously missing from the Get-Folder cmdlet, is the path of the folder. In the PowerCLI Community there are regularly threads that ask for this kind of information. Most of the time it concerns scripts to export/import folder structures or scripts to migrate vCenters.

Another property that is obviously missing, is the indication if a specific folder is a so-called “blue” or “yellow” folder.

To solve this problem once and for all, I wrote this short function, called Get-FolderPath, that will return you both of these properties.

The script

Annotations

Line 1: The function requires PowerCLI 4.1

Line 26-29: The function can be used in a pipeline and requires one or more FolderImpl objects on the -Folder parameter .

Line 34: With the use of the -ShowHidden parameter the function can include the hidden folders in the folderpath. This array contains the names of the hidden folders.

Line 41-43: To determine if a folder is yellow or blue, the script tests for the presence of VirtualMachine in the ChildTypes of the folder.

Line 45-50: The script moves towards the root of the vSphere environment. When there is no Parent present on an entity, the script knows it has reached the beginning of the folderpath.

Line 47: The test that decides if a foldername will be included in the path or not.

Samples

The use of the function is quite straightforward.

The returned object contains the basic information, name of the folder, the folderpath and the type of the folder.

We can use the -ShowHidden parameter to display the “hidden” folders in the path.

And the script can of course also be used in a pipeline construct.

The function is handy to find folders with identical names. The Folderpath property makes it easy to locate these.

And you can of course ask for a complete list of the folders defined on your vCenter.

You can easily use this function in combination with other cmdlets.
Let’s for example list all the “blue” folders in a specific datacenter.

Enjoy !

44 Comments

    KS

    Hello Lucd

    Do you have any script to get the Full Folder path for all the VM’s in Vcenter

    Example:
    VMname, VMID Folder path
    ABCD VM-1234 User/Windows/Server/ abcd

    I am able to get the folder path using this function ( Get-vmFp), However it is bit slow…
    Do you have any faster way to retrieve folder path.

    ————————————————–
    function Get-vmFp{

    param(
    [parameter(valuefrompipeline = $true,
    position = 0,
    HelpMessage = “Enter a folder”)]
    [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl[]]$Folder,
    [switch]$ShowHidden = $false
    )
    begin{
    $excludedNames = “Datacenters”,”vm”,”host”
    }
    process{
    $Folder | %{
    $fld = $_.Extensiondata
    $fldType = “yellow”
    if($fld.ChildType -contains “VirtualMachine”){
    $fldType = “blue”
    }
    $path = $fld.Name
    while($fld.Parent){
    $fld = Get-View $fld.Parent
    if((!$ShowHidden -and $excludedNames -notcontains $fld.Name) -or $ShowHidden){
    $path = $fld.Name + “\” + $path
    }
    }
    $row = “” | Select Name,Path,Type
    $row.Name = $_.Name
    $row.Path = $path
    $row.Type = $fldType
    $row
    }
    }
    }

      LucD

      You could have a go with the function in Get-InventoryPlus – Inventory Of All VSphere Objects
      That returns all objects, not just VMs.
      But it lists for VMs both folder paths (type Host&Cluster and type VM&Template)

    anton

    is it possible to use this function to identify if a VM has been placed into a specific folder ? and to expand on that, can I do it in a historic way ?

    I was looking at the Get-View commandlet, I can query a VM and find out where its residing but I really want to know where it was residing 10 hours, or 10 days, or 90 days ago.

    $vm = get-vm VMtest1
    $vm | get-view | Select Name,@{N=”Folder”;E={Get-View $_.Parent | Select -ExpandProperty Name}}

    Name Folder
    —- ——
    VMtest1 VMwareFolder001

    Thank you!

      LucD

      Hi Anton,
      I’m afraid that this information is not kept in Events.
      There is a Task event when a VM is moved to a specific folder, but in that event it only shows the target folder.
      The VM and the source folder are not in there.

      You can check for yourself with something like this

      Get-VIEvent -Start (Get-Date).AddMinutes(-60) -MaxSamples ([int]::MaxValue) |
      where{$_ -is [VMware.Vim.TaskEvent] -and $_.Info.Name -eq 'MoveIntoFolder_Task'}

        Anton

        Luc, when I run that query I get a few things returned but none that specify the target folder like you mentioned;

        I ran this:
        Get-VIEvent -Start (Get-Date).AddMinutes(-600) -MaxSamples ([int]::MaxValue) |
        where{$_ -is [VMware.Vim.TaskEvent] -and $_.Info.Name -eq ‘MoveIntoFolder_Task’}

        Return was:

        Info : VMware.Vim.TaskInfo
        Key : 228107024
        ChainId : 228107024
        CreatedTime : 7/1/2019 9:58:14 AM
        UserName : myDomain\SomeServiceAccount
        Datacenter : VMware.Vim.DatacenterEventArgument
        ComputeResource :
        Host :
        Vm :
        Ds :
        Net :
        Dvs :
        FullFormattedMessage : Task: Move entities
        ChangeTag :

        is it possible to dive deeper or perhaps look at something else to get the results I am looking for ? Thanks!

          LucD

          The target folder can be found under the Info property.

    Mark

    Hello LucD

    I’m attempting to use this function to move clusters, but i can’t quite get it to work.

    I have multiple host and cluster folders named the same thing, and i can easily identify them using your function. I just can’t figure out how to move my clusters into the clusters.

    Got any ideas how to make this work?

    Regards.

      LucD

      Hi Mark,
      I’m not quite sure I understand what you are trying to do.
      If you have the destination folder object, you can just do a

      Move-Cluster -Cluster MyCluster -Destination $folder

      Or are you trying to do something else?

      Perhaps you need to use my Get-FolderByPath function to get the Destination folder?
      Luc

    Syteck

    Hi LucD,

    It’s very nice script, I need to get VM folders path but your way of getting it is really long on my environment (+800 folders for our smallest datacenter), and it’s worst with an -AutoSize…

    Have you ever tried to do a tree with Get-Folder command only ? Like putting the command in a variable to reuse it in the whole script to save time and use properties like ParentId to build the tree ?

    It’s the fastest way I could thought of, but it’s pretty tricky to write and I’m going mad at it.

    Anyway thanks for your help through every VMWare Community topic 😉

      LucD

      Have a look at my Get-InventoryPlus function.

    Sunny

    Hi Lucd

    Thank you for the quick update.

    i have a unique issue. It seems like Powercli is unable to pick up VM\’s in nested folders.

    C:\\> Get-VM | select Name,@{N=\”Folder\”;E={$_.Folder.Name}}

    Name Folder
    —- ——
    XXXsvrmax03 MigratedVM\’s
    XXXsvrtek03 MigratedVM\’s
    XXXsvrtek01 MigratedVM\’s
    XXXSVRSN406 MigratedVM\’s
    sdcsvrprdctx00
    XXXSVRSN4531 MigratedVM\’s
    tools-vm2
    XXXSVRSN443 MigratedVM\’s
    sdcsvrprdmen01
    sdcsvrprdcsf02
    XXXSVRREP01 MigratedVM\’s
    sdcsvrprdvb01
    XXXSVRSN4551 MigratedVM\’s
    test01
    sdcsvrprdadc02
    sdcsvrprdvcs01 VMware_Linux
    sdcsvrprdvo01
    XXXsvrmax02 MigratedVM\’s
    XXXsvrsn432 MigratedVM\’s
    XXXSVRSN446 MigratedVM\’s
    XXXSVRSN4511 MigratedVM\’s
    sdcsvrprdcns01 Citrix_Linux
    XXXSVRSN444 MigratedVM\’s
    XXXSVRSN442 MigratedVM\’s
    sdcsvrprdadc01
    XXXSVRSN402 MigratedVM\’s
    XXXsvredi01 MigratedVM\’s
    XXXSVRDAXMR01 MigratedVM\’s

    from the above example output, Folders are not displaying against the VM\’s (Even though the VM\’s are definitely in the folder and folder type is \”VM\”)

    :\\> Get-Folder -Type VM

    Name Type
    —- —-
    vm VM
    Discovered virtual machine VM
    MigratedVM\’s VM
    SDCTemplates VM
    Production VM
    POC VM
    Test VM
    Infrastructure VM
    Windows Servers VM
    Linux Servers VM
    Citrix VM
    Veeam VM
    VMware VM
    Citrix_Windows VM
    Citrix_Linux VM
    Veeam_Windows VM
    VMware_Linux VM

    All VM\’s in top level folder are displaying fine but the Sub-folders are not displaying

    Citrix(Top Folder)
    Citrix_Windows (Sub Folder)
    Citrix_Linux (Sub Folder)

    From the above example, if the VM sits in Citrix folder it will be displayed. If the vm sits in Citrix_windows or Citrix_Linux then it fails

    C:\\> Get-VM -Location \”citrix_windows\”
    Get-VM : 29/01/2019 4:19:55 PM Get-VM Exception has been thrown by the target of an invocation.
    At line:1 char:1
    + Get-VM -Location \”citrix_windows\”
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-VM], VimException
    + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVM

    Any idea why Powercli is unable to update vm folder paths?

    Thank you
    Sunny

      LucD

      That seems to be working for me.
      WHich PowerCLI version are you using?

    Selene

    Nice script. However, is there a way to show all the client hostnames in the folders as well? Thanks!!

      LucD

      Hi,
      You could do something like this

      Get-Folder |
      Select Name,
      @{N='Path';E={$_ | Get-FolderPath}},
      @{N='VM';E={(Get-VM -Location $_ | Select -ExpandProperty Name) -join '|'}}

      Luc

        Sunny

        Hi Luc

        Nice script and exactly what i’m after.

        We have few folder structures in my vCenter with multiple Sub directories with VM’s. Is there a way to query sub directories and the VM names in these Folder?

        Example:

        Path 1 – “SDC\Production\Infrastructure\Veeam\Windows Servers”
        Path 2 – “SDC\Production\Infrastructure\Veeam\Linux Servers”
        Path 3 – “SDC\Production\Infrastructure\Veeam”

        We would like to get the VM’s that are in Path 1 (Folder Windows Servers)
        Then Path 2 – Linux Folder
        Then path 3 – VEEAM folder

        Currently am trying something like this but no luck

        Get-vm -location “SDC\Production\Infrastructure\Veeam\Windows Servers”

        C:\> get-vm -Location “SDC\Production\Infrastructure\Citrix\Windows Servers”
        get-vm : 25/01/2019 9:14:47 PM Get-VM Could not find VIContainer with name
        ‘SDC\Production\Infrastructure\Citrix\Windows Servers’.
        At line:1 char:1
        + get-vm -Location “SDC\Production\Infrastructure\Citrix\Windows Server …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : ObjectNotFound: (SDC\Production\…Windows Servers:String) [Get-VM]
        , VimException
        + FullyQualifiedErrorId : Core_ObnSelector_SelectObjectByNameCore_ObjectNotFound,VMware.VimAu
        tomation.ViCore.Cmdlets.Commands.GetVM

        And tried this

        C:\> get-vm -Location @{Name=”Windows Servers”; Path=”SDC\Production\Infrastructure\Veeam\Windows Servers”}
        Get-VM : Cannot bind parameter ‘Location’. Cannot convert the
        “System.Collections.DictionaryEntry” value of type “System.Collections.DictionaryEntry” to type
        “VMware.VimAutomation.ViCore.Types.V1.Inventory.VIContainer”.
        At line:1 char:18
        + … m -Location @{Name=”Windows Servers”; Path=”SDC\Production\Infrastruc …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : InvalidArgument: (:) [Get-VM], ParameterBindingException
        + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,VMware.VimAutomation.ViCore.Cmdlets.
        Commands.GetVM

        Tried this

        C:\> Get-Folder Production | Get-Folder Infrastructure | Get-Folder Citrix | Get-Folder “Windows Servers” | Get-vm
        Get-vm : 25/01/2019 9:19:46 PM Get-VM Exception has been thrown by the target of an
        invocation.
        At line:1 char:104
        + … structure | Get-Folder Citrix | Get-Folder “Windows Servers” | Get-vm
        + ~~~~~~
        + CategoryInfo : NotSpecified: (:) [Get-VM], VimException
        + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Co
        mmands.GetVM

        Really appreciate your help

        Thanks
        Sunny

          LucD

          Hi Sunny,
          You mean something like this?

          Get-Folder -Type VM |
          Select @{N='Folder';E={(Get-FolderPath -Folder $_).Path}},
          @{N='VM';E={(Get-VM -Location $_).Name -join '|'}}

            Sunny4422000

            Thank you for the reply. I updated my Powercli version and its working fine now

        Godwin

        YOU ARE AWESOME

    Mark

    @Matthew Tiffany

    Hi Matthew Your add-on script is exactly what I am looking for. However, every time I use it the “path” column is empty for all VMs. If I run $folders it shows the folders and folder paths so the information is there. I’ve tried with the function you added as part of the script. I’ve tried running the function at the PowerCLI command line. I’ve tried importing the function as a module into PowerCLI and then calling the function from the script. The path column in results always ends up empty. Any ideas?

    Denis

    Hi Luc,
    I try to use your function in a mutliconnection environnement and get a error messages in loop:

    Get-View : Cannot validate argument on parameter ‘VIObject’. The argument is null, empty, or an element of the
    argument collection contains a null value. Supply a collection that does not contain any null values and then try
    the command again.
    + $fld = Get-View $fld.Parent
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Get-View], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.DotNet
    Interop.GetVIView
    Thanks in advance for your help
    Best Regards
    Denis

      Trevor

      I have the same issue, not sure why it doesn’t like being connected to multiple vCenter instances. In my case, I get around it by just gathering the folder info on one instance at a time, disconnecting between each operation.

        Jason

        I was able to get around this by adding a server parameter and then using it in the Get-View command, however you then have to specify a folder that only exists on a specific VC.

        Hopefully this helps someone.

        param(
        [parameter(valuefrompipeline = $true,position = 0,HelpMessage = “Enter a folder”)]
        [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl[]]$Folder,
        [string]$server,
        [switch]$ShowHidden = $false
        )

        while($fld.Parent){
        $fld = Get-View -server $server $fld.Parent

        I now call it this way:
        $vc = “vc.domain.local”
        #Get specific folder, folder must exist on the specified VC
        Get-Folder | ?{$_.Name -match “FolderName”} | Get-FolderPath -server $vc

        #Get all folders from a specific VC
        Get-Folder -server $vc | Get-FolderPath -server $vc

    Ron Klimaszewski

    Great script. Without the datacenter folder there is a missing link back to the root level. I added an End{} block to retrieve this information. In the version below I also changed your ‘Type’ column to the actual folder type, moving the color to info to a ‘Color’ column. I also added the FolderId and ParentFolderId information.

    function Get-FolderPath {

    param (
    [parameter(valuefrompipeline = $true,
    position = 0,
    HelpMessage = “Enter a folder”)]
    [VMware.VimAutomation.ViCore.Impl.V1.Inventory.FolderImpl[]]$Folder,
    [switch]$ShowHidden = $false
    )

    begin {
    $excludedNames = “Datacenters”, “vm”, “host”
    $hash = @{ };
    }

    process {
    $Folder | %{
    $fld = $_.Extensiondata
    $fldColor = “yellow”
    if ($fld.ChildType -contains “VirtualMachine”) {
    $fldColor = “blue”
    }
    $path = $fld.Name
    while ($fld.Parent) {
    $fld = Get-View $fld.Parent
    if ((!$ShowHidden -and $excludedNames -notcontains $fld.Name) -or $ShowHidden) {
    $path = $fld.Name + “\” + $path
    }
    }
    $row = “” | Select Name, Path, Color, Type, Id, ParentId
    $row.Name = $_.Name
    $row.Path = $path
    $row.Color = $fldColor
    $row.Type = $_.Type
    $row.Id = $_.Id
    $row.ParentId = $_.ParentId
    $hash.Add($_.Id,$_.Name)
    $row
    }
    }

    end {
    Get-Datacenter | %{

    $row = “” | Select Name, Path, Color, Type, Id, ParentId
    $row.Name = $_.Name
    $row.Path = $hash.Item($_.ParentFolderId) + “\” + $_.Name
    $row.Color = “yellow”
    $row.Type = “Datacenter”
    $row.Id = $_.Id
    $row.ParentId = $_.ParentFolderId
    $row

    }

    }
    }

      LucD

      Thanks for sharing that useful improvement.

    jeff mcdermott

    I installed powershell 4 & powercli 5.5u2 but running get-pssnapin shows vmw* as psversion 2.0 despite Microsoft components showing as psversion 4.0

    so I do not understand how to satisfy the requirement 4.1 stmt on line 1 of get-folderpath & get the following error

    PowerCLI C:\windows\system32> . get-folderpath.ps1
    . : The script ‘get-folderpath.ps1’ cannot be run because the following
    snap-ins that are specified by the “#requires” statements of the script are
    missing: VMware.VimAutomation.Core (Version 4.1).
    At line:1 char:3
    + . get-folderpath.ps1
    + ~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ResourceUnavailable: (get-folderpath.ps1:String)
    [], ScriptRequiresException
    + FullyQualifiedErrorId : ScriptRequiresMissingPSSnapIns

      LucD

      Hi Jeff, just leave out that line.
      It was added at the time to make sure you had at least PowerCLI v4.1, but by now everyone should be running a more recent version I guess.

    Matthew Tiffany

    Thanks LucD,
    Your posts and scripts around here and the powercli forums have really helped out. This function is no different. In fact it helped me take a script I had from 6 hours to run to around 15 mins.

    Mainly it’s because we’re using folder paths to identify who owns what VM so when I collect a list of VMs also been the Paths, before it would process the path each time but I figured getting a list the folders and processing the paths than just matching them to the VMs would be faster. Here the script incase anyone else is interested.

    $date = Get-Date -format M-d-yyyy

    . “C:\chargeback\Chargeback Scripts\Get-FolderPath.ps1″

    $folders = Get-Folder -type vm | Get-FolderPath | Sort-Object Id

    function Set-Path{
    param($Object)
    foreach ($folder IN $folders){
    if( $folder.Id -eq $Object.Id){
    $result = $folder.Path
    break
    }
    }
    $result
    }

    Get-VM | Sort-Object FolderID | Select Name, Uid, NumCpu, MemoryGB, ProvisionedSpaceGB, @{N=”Path”;E={Set-Path -Object $_.Folder}}, ResourcePoolId, ResourcePool, @{N=”ToolsStatus”;E={$_.ExtensionData.Summary.Guest.ToolsVersionStatus}} | `
    Export-Csv “C:\vServerCSVs\ashburn-vServer-$date.csv” -NoTypeInformation -UseCulture

    Philip

    Hi Luc

    I know this a well tried and tested script, however I am getting some strange results, no doubt because of my environment.

    I am trying to migrate form one VC to a new VC, I have used the Cheap DR Scrips (https://www.gabesvirtualworld.com/cheap-disaster-recovery/) but it fails beacuse we have duplicate folders

    I wanted to modify these scripts and use your get-folderbypath function to help resolve this.

    We have a folder structure, as sample of which is as follows:

    DataCenter1
    Customer1
    Production
    SubTeam1
    Production

    If I run you script get-folderbypath -Path “DataCenter1\Customer1\Production” it gives me the following results

    Name Type
    —- —-
    Production VM
    Production VM

    Which is not as I expected, it seem to recuse to the subteam1 folder rather than return the folder id of the path entered

    Could you help please?

      LucD

      Hi Philip,
      Are you sure you didn’t mean the function in Folder by Path ?
      And by coincidence we had a similar comment on there, and the user even found the solution.
      See the -NoRecursion switch you can add.

    YWM

    Hi Lucd, I also try to use your script to export the folder from VCenter, but I got many error and can’t export the result. I check the attached script file and find that there are many corruption word (ame?) like below in the script. How can I resolve it? Thank you.

    https://communities.vmware.com/thread/268411

    $ret | Add-Member -Type noteproperty -Name ame?-Value $role.name
    $ret | Add-Member -Type noteproperty -Name abel?-Value $role.info.label
    $ret | Add-Member -Type noteproperty -Name ummary?-Value $role.info.summary
    $ret | Add-Member -Type noteproperty -Name oleId?-Value $role.roleId
    $ret | Add-Member -Type noteproperty -Name ystem?-Value $role.system
    $ret | Add-Member -Type noteproperty -Name rivilege?-Value $role.privilege

    YWM

    Dear LucD,
    I’m going to move all ESX host and VMs from VCenter 4.1(under the same domain) to new Virtual Centre 5.1(under the same domain). Is there a migrate script or easy way that I can move them and place VMs in correct folder and apply the role attributes/ folder permissions back into the new VC server?
    move steps like below:
    1.Export folders
    2.Export VM locations in Folders
    3.Export Permissions
    4.Export Custom Attributes
    5.Create Folders on the new vCenter
    6.Disable DRS/HA
    7.Remove ESX hosts from Source vCenter and add to Destination vCenter
    8.Enable DRS/HA again
    9.Move all vm’s to correct folders
    10.Apply the permissions back
    11.Apply custom attributes and notes

    Sorry, my english isn’t well, hope you can understand and really appreciate your help. Thanks!

    brendan62269

    Luc;
    You rock!

    Arvinth

    Thanks For the reply Luc,

    I was searching for this option a long time and finally came to know from you its the problem with Vsphere.

    I would like to comment that your forums and scripts is saving the day of many administrators.

    especially I have learnt many stuffs from your forums and benefited.. Keep rocking Friend.

    wish you a happy advance x-mas & great new year a head.

      LucD

      Thanks, much appreciated.
      Glad you find my posts useful.

    Arvinth

    Luc,

    Is there any option to find out who has moved the VM from a folder A to the folder B using power CLI

      LucD

      @Arvinth, well there is the Tasks and Events you query for all MoveIntoFolder_Task entries, but unfortunately the VM property seems to be empty in the Task object and in the related Events. The target folder is available.

      This is not a PowerCLI problem, but it appears to be a vSphere problem.

    Jason

    This is great. Works perfectly for export. How do I create a blue folder with the new-folder cmdlet?

    AnasAA

    we assume that there are two blue folders:
    DC1\Folder\Folder171 and DC1\Folder\Folder1\Folder171

    Now i would like to move a VM1 to e.g. DC1\Folder\Folder1\Folder171 per script.
    How can i do that?

    Thanks

      LucD

      @AnasAA, you could do something like this

      $source = "DC1\Folder\Folder171"
      $destination = "DC1\Folder\Folder1\Folder171"
      $srcFld = Get-Folder -Name Backup | where {(Get-FolderPath -Folder $_).Path -eq $source}
      $dstFld = Get-Folder -Name Backup | where {(Get-FolderPath -Folder $_).Path -eq $destination}
      Get-VM -Name VM1 -Location $srcFld | Move-VM -Destination $dstFld -Confirm:$false

    Robin

    Thanks so much, as always Luc! I’ve used this to export text file lists of VMs based on them belonging to blue folders (with some exclusions also) 🙂

    Suresh

    Very nice script Luc. Thanks!

    Doug Youd

    Nice script. I’ll be using it shortly as part of an automated “clone workload to test” procedure. So thanks for making my life that little bit easier. 🙂
    -Cni

    Eugene

    How do I register this custom Get-FolderPath function in order to use it?

      LucD

      @Eugene, there are several ways you can make this function available.
      1) Place it in one of your profile files.
      2) Save the function in a .ps1 file and then dot-source the file (PS> . Get-FolderPath.ps1).
      In both cases you will be able to call the function in your scripts or from the prompt.
      3) Insert the function in your script. Make sure the function comes before the first call to it.

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.