Extension Attribute to find the Parallels Desktop VM OS Details

karthikeyan_mac
Valued Contributor

Hi,

We have to get the Parallels Desktop Virtual machines Operating Systems details.

We can see VmInfo.pvi in .pvm has the details like RealOsType, RealOsVersion and RealOsDetails, but the files is not a plist to query those details in Extension Attribute.

Is there any other plist file to check the VM OS Version or does anyone using extension attribute to query this data?

Thanks,
Karthikeyan

18 REPLIES 18

stevewood
Honored Contributor II
Honored Contributor II

You can still query that information even if it isn't a plist, you just can't use defaults to do it. Simply using cat with grep and sed (maybe even cut) can get you what you are looking for. While not pretty, this will get you the RealOsType info:

cat /<path>/<to>/<VM>/VmInfo.pvi | grep -E 'RealOsType' | sed 's/RealOsType//g' | sed 's/<//g' | sed 's/>//g' | sed 's#/##g'

Wrap that in <result></result> and you've got an EA you can use.

hunter99
New Contributor

OK I am new to administering Casper. I am pretty good about finding stuff but my one big area of weakness, I am working on, is scripting and command line. I am starting to get command line but I have a real long way to go for scripting.

I hate to ask but how exactly should the script above look. I have tried it several different ways but so far no luck. Sorry to ask such a dumb question but I have tinkered with this for a while without luck.

mm2270
Legendary Contributor III

@hunter99,

Scripts will always need to start with something called the shebang. IN this case something like #!/bin/sh should suffice, but you can also use #!/bin/bash

Then you have your script commands after. In the case of an Extension Attribute, the result you want to populate the filed, needs to get wrapped in the following tags, usually with an echo command in front and double quotes around it, so like this-

echo "<result> </result>"

So in the example above, the end result could look something like this

#!/bin/sh

ParallelsVMOS=`cat /<path>/<to>/<VM>/VmInfo.pvi | grep -E 'RealOsType' | sed 's/RealOsType//g' | sed 's/<//g' | sed 's/>//g' | sed 's#/##g'`

echo "<result>$ParallelsVMOS</result>"

What that's doing is setting up a variable called "ParallelsVMOS" that uses the command to create a string. Note the tick marks surrounding the command ( ` ) Then we echo it back with the "result" tags around it to make it into a valid Extension Attribute.

Make sure to change the /path/to/ stuff to an actual path though!

Make sense?

hunter99
New Contributor

mm270,

Thank you so much. That is exactly what I needed. I had several mistakes when I tried to do this. I didn't put the "!" in the bash command, had spaces wrong, and completely messed up putting in the <results></results>. Needless to say I still have a long way to go. I'll get it. Thank you again.

stevewood
Honored Contributor II
Honored Contributor II

To take it a step further, I decided to try throwing a script together that would cycle through all PVM files located in a directory. The default for this script is to look at /Users/<user>/Documents/Parallels which is the default location where Parallels stores VM files. However you can edit one variable if you do not store in that location.

#!/bin/sh

# Global variables

# Set the location of your VMs if not the standard Parallels location of
# /Users/<user>/Documents/Parallels

vmLocation=""
loggedInUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`

echo -n "<result>"

# Look for VMs

if [ "$vmLocation" == "" ]; then
# VMs stored in standard location

    VM=/Users/$loggedInUser/Documents/Parallels/*.pvm
    for f in $VM
    do
        cat "$f/VmInfo.pvi" | grep -E 'RealOsType' | sed 's/RealOsType//g' | sed 's/<//g' | sed 's/>//g' | sed 's#/##g'
    done

else 
# VMs stored in alternate location

    VM=$vmLocation/*.pvm
    for f in $VM
    do
        cat "$f/VmInfo.pvi" | grep -E 'RealOsType' | sed 's/RealOsType//g' | sed 's/<//g' | sed 's/>//g' | sed 's#/##g'
    done

fi

echo "</result>"

There's more that can be done to this, I'm sure, but it's a good start.

hunter99
New Contributor

Again, thank you for the help. I'll modify it to also look in another folder too only because our .pvm files are supposed to be in /users/shared but that is not always the case. Poor oversight for a while of the desktop techs has led to a half and half solution. I just needed to do this since XP is about to be purged and I needed to follow suit on the mac clients. We already have been integrating Windows 7 but there are those ones that are still out there.

hunter99
New Contributor

Sorry, I just noticed you already did that. When i first looked at it it didn't register in my head. I guess since I was looking at it from a tablet. Awesome! And to try and fully understand any scripts I see I get out my resources so i understand what all of the different commands are doing. It's a big part of helping me learn.

JPDyson
Valued Contributor

@hunter99 Jeff, let's get lunch (assuming you're still where I left). Same old address?

hunter99
New Contributor

Josh, that sounds great. Yeah, i'm still here. I got lucky and inherited all of this. It'll have to be a couple of weeks but then I should be good sometime after that.

Heavy_D
Contributor III

Awesome!

Heavy_D
Contributor III

@stevewood Thank you for this script however I tried setting it to a EA and I am collecting no Data from it all.
c473971a00cd44779138b23099607a27
Trying to gather as much intel as I can on the VM machine and your script seems like a great start but it's currently not working with Parallels 15 on Mojave 10.14.6

tlarkin
Honored Contributor

Here is a script I wrote a year ago or so that uses Spotlight to find any Parallels VM in /Applications or in /Users and grabs OS type and then tracks what OSes people are running on their Mac. I did not get any more details, but the code could be easily modified to get any info you want from the XML files.

#!/usr/bin/python

"""
this is a script to detect what VMs are on a sytsem and escrow what OS they are
You can run this daily or in another workflow
It will use Spotlgith to find files with the .pvm extension to locate where the files are on the file system
then parse the PvInfo file for Parallels VMs
"""

# import modules
import xml.etree.ElementTree as et
from Foundation import NSMetadataQuery, NSPredicate, NSRunLoop, NSDate


# start functions


def get_vms():
    """use spotlight to find parallels VM files"""
    file_list = []
    query = NSMetadataQuery.alloc().init()
    query.setPredicate_(NSPredicate.predicateWithFormat_("(kMDItemContentType == 'com.parallels.vm.vmpackage')"))
    query.setSearchScopes_(['/Applications', '/Users'])
    query.startQuery()
    start_time = 0
    max_time = 20
    while query.isGathering() and start_time <= max_time:
        start_time += 0.3
        NSRunLoop.currentRunLoop(
        ).runUntilDate_(NSDate.dateWithTimeIntervalSinceNow_(0.3))
    query.stopQuery()
    # get the results of the file names, and find their file path via spotlight attribute
    for item in query.results():
        pathname = item.valueForAttribute_('kMDItemPath')
        if pathname:
            file_list.append(pathname)
    return file_list


def get_vm_os(vm_list):
    """feed this function a list of results from Spotlight to parse what VM is running what OS"""
    os_list = []
    for vm in vm_list:
        path = str(vm + '/VmInfo.pvi')
        tree = et.ElementTree(file=path)
        for element in tree.iter(tag='RealOsType'):
            vm_os = str(element.text)
            os_list.append(vm_os)
    return os_list


def main():
    """main to rule them all"""
    final_vm_list = []
    ea_list = []
    files = get_vms()
    results = get_vm_os(files)
    for result in results:
        if 'Mac' in result:
            final_vm_list.append('macOS')
        if 'Linux' in result:
            final_vm_list.append('Linux')
        if 'Windows' in result:
            final_vm_list.append('Windows')
    for item in final_vm_list:
        if item not in ea_list:
            ea_list.append(item)
    print('<result>%s</result>' % ea_list)


if __name__=='__main__':
    main()

stevewood
Honored Contributor II
Honored Contributor II

@JarvisUno

Wow, way back to 2014 with this one. I stopped using Parallels years ago for Fusion, so I had to fire up a copy of Parallels to check on this. It looks like that file does not get populated until you have the Parallels Tools installed. Before installing the tools those values were blank. After installing I had the OS info.

I would try the relevant commands from Terminal to see if they are working. Also, make sure you have the proper path to the VM set.

I just threw a new version of that together that searches the user's home folder for PVM files and then tries to read the VmInfo.pvi file. Try this out:

#!/bin/bash

loggedInUser=$(/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }')
userHome=$(/usr/bin/dscl . -read /Users/"$loggedInUser" NFSHomeDirectory | awk '{print $2}')


# Find VmInfo.pvi files in user's home folder
vm_files=$(mdfind "kMDItemFSName == '*.pvm'")

echo -n "<result>"

while IFS= read -r line
do
    cat "$line"/VmInfo.pvi | grep -w 'RealOsType' | sed 's/RealOsType//g' | sed 's/<//g' | sed 's/>//g' | sed 's#/##g' | tr -d '[:blank:]'

done < <(printf '%s
' "$vm_files")

echo "</result>"

You might save that as a shell script and run it locally on a machine that has a few VMs just to test before putting it in as an EA.

mschroder
Valued Contributor

When I see something like

cat FILE | grep | sed | sed | sed | ...

I always think "there must be a neater way to do this." What about

awk -F">|<" '/RealOsType>/ {print $3}' FILE?

awk is so much better at extracting snippets from structured files than grep and sed are. But I admit I always forget the syntax for using multiple field-separators, so I need some trials before it does what I want...

tlarkin
Honored Contributor

@mschroder There are XML parsers that are in fact made for this. xmllint, xmlstarlet are two tools that support xpath and can be ran on macOS. You can of course also use XML parsers from Perl, Ruby, or Python as well.

All of the awk, grep and sed stuff is just manipulating output of text in a more regex way, where XML parses actually read in keys and give you values.

mschroder
Valued Contributor

@tlarkin Thanks for the hint, I will try to keep that in mind, but it might take me some time to memorise expressions like xmllint --xpath "string(//RealOsType)" VmInfo.pvi.

tlarkin
Honored Contributor

@mschroder just toss it in a bunch of gists on github or something because that is the proper way to parse XML over using all the GNU tools that aren't really meant to parse structured data. So, those are great skills to have and maintain.

It is also why I went with Python in my code to leverage Spotlight to locate my Parallels files (since users can put them anywhere) and then a XML parser to get all the key values out of the file with no extra crud.

Heavy_D
Contributor III

Thank you all for reviving this thing, You all are rockstars!! I just want to start by saying I am not a HUGE fan of Parallels at all and would love to be on Fusion but the powers that be, went with Parallels. All I truly want to do is put in a EA that there is a VM and Grab all he installed applications on that VM.

Is that possible to do with EA?