Getting Started with the MBSDK (Example Scripts Included)

Version 19

    Verified Product Versions

    Endpoint Manager 9.5Endpoint Manager 9.6Endpoint Manager 2016.xEndpoint Manager 2017.x

     

    I - Introduction & Prerequisites

    This article looks in more detail & with practical examples

     

    Note a very basic introduction on talking to the MBSDK via Powershell can be found in this article - How to invoke a LANDesk MBSDK method using Powershell .

     

    The examples in this article will be purely based on PowerShell as well - but you can use any scripting / programming language you prefer which is capable of communicating with and authenticating to WWW-services.

     

    So a .BAT file will not be possible - but VB, Python, Powershell and anything remotely sophisticated should be fine. This also means that ideally YOU should be able to script (awesome reason to get skilled up in this area) ideally. Yes, if you have access to scripters, you can lean on them - but since you (should be /) are the LANDesk specialist, it usually requires less explaining if you know what the tool is capable of & what you want to get done (and how).

     

    In addition, having a foundation in SQL can be helpful - the WWW-method calls tend to refer to certain database-side identifiers (unique ID's for computers, tasks, etc.) and some familiarity with the database and SQL language can help make sense / give context with this.

     

    In summary - having a foundation in SQL language (enough to be able to query the database, so you can resolve various attributes and IDN's that the MBSDK may use) if of strong benefit here. Beyond SQL, the other set of expertise you need to have access to (either yourself or via colleagues) is a scripting language that's capable of communicating via HTTP / www-calls.

     

     

    II - Considerations / Gotchas around invoking the MBSDK

    This section covers common gotchas that catch people out / things that script authors need to be consciously aware of..

     

    II.A - Authentication

    In order to use the MBSDK / WWW-calls, you need to be authenticated (no anonymous access methods are permitted). There are no special creation rules here - the MBSDK ties in automatically / makes use of existing LANDesk Users.

     

    All authentication is NT-based authentication (and requires a valid LANDesk user). This can be used to great effect by simply launching your respective script in a user-context ("run as") of a user you desire - often a service or processing account.

     

    II.B - What can I *DO* / what can I do it *TO*?

    Most (if not all) of your day-to-day operations should already have methods in the MBSDK. Any device that's in the database can be targeted / queried - essentially "if you can do it / access it in the console" you can do the relevant action through the MBSDK.

     

    As mentioned above, you need to authenticate with a valid user to make use of the MBSDK - this is where the rest of the "what can I do / what can I do stuff TO" falls in to place as well. The LANDesk User you authenticate with has one or more Scopes and one or more Roles. THESE are automatically applied as permissions & limitations. So - "whatever you have access to in the console, is what you have access to in the MBSDK".

     

    This makes user configuration fairly easy, as it differs in no way to regular user creation/configuration.

     

    A complete listing of all methods in the MBSDK can be had by accessing the MBSDK "site" via a browser here -- http://YOUR-CORE-NAME/MBSDKService/MsgSDK.asmx -- and as a (very basic) list, you can do the following sorts of things:

    • Add / Remove devices from tasks\
    • Create / delete tasks
    • Start tasks
    • Get the status of a task / of a machine in a task
    • Delete devices from inventory
    • Query device data / essentially run query.
    • Check a user / the current user for a right (i.e. "do I have rights for software distribution")

     

    The beautiful thing around having a (hopefully somewhat) intelligent script language to talk to the MBSDK is that you can use this to automate a lot of things.

     

    What does this look like? Here's a (somewhat complex) possible example that works across multiple systems, showing what you can do through sophisticated use of www-service integration:

    1. Users connect to a www-form and request a new Windows 10 machine
    2. A script talks to the www-calls of VMWare (separate subject alltogether) and creates a basic VM placeholder. This may or may not include details like desired Name of the device, etc.
    3. The script talks to VMWare and pulls back the MAC-address of the newly created device.
    4. A script talks to the MBSDK and creates a new (basic) device entry, based on the MAC-address we've received back from step 3.
    5. The script calls the MBSDK and creates a new provisioning task to deploy a Windows 10 image on to the device.
    6. The script starts the Provisioning task (even though the VM is powered off) - so that the task is active & the Provisioning task is now effectively pre-targeting the device upon boot.
    7. The script sleeps for a bit (say - 30 seconds) to let the task do its thing and initialise properly.
    8. The script calls back to VMWare and starts the VM up.
    9. The VM (being configured to boot over network first) will PXE-boot and (due to PXE pre-targeting mentioned above) automatically be booted into Provisioning & have the WIndows 10 image put down on it.
    10. Depending on what data was collected - we could be naming the device based on what was requested in the www-form - and/or install software applications that have been requested.

     

     

    II.C - Regarding credentials...

    For those who haven't done scripting - please be aware that it's a *HUGE* "No! No!" to hard-code either usernames and/or (especially) passwords into a script.

     

    Certainly while one is technically capable of this - doing so breaks a lot of very basic security rules. If you include a plain text username / password in a stored file (i.e. - a script) you've just made any malicious actors' life a lot easier should they ever come across / get access to said script.

     

    ALWAYS have security as a #1 focus - and don't give a processing user "admin rights" just because it would be potentially convenient to do so. Always treat them like a "proper" user, and only give them only the permissions that they need to do their job. Consider having several processing users for instance with different levels of privileges. Think CAREFULLY about what you actually need.

     

    Automation can be very powerful -- which is precisely why you should treat it with a healthy dose of respect and be ever so mindful of security fundamentals.

     

    Safer methods to deal with credentials include:

    • Query the user running the script for a set of credentials interactively.
    • Pass-through the credentials of the user-context running the script automatically
    • Use an external method to control user context (Windows Scheduled Task / LANDesk software distribution) and then use a "pass-through" authentication, assuming the scripting language supports such (PowerShell does).

     

    II.D - Regarding Scopes & the need to refresh

    This is primarily a "gotcha" around newly added devices.

     

    By default, LANDesk only re-resolves users' scopes & rights about 1x / hour. If a user has a limited scope, and a device is added to them, this may not show up for some time.

     

    There is a method - "ResolveScopeRights" which will resolve that on an on-demand basis where needed. Alternatively, if you give a user the "All Devices" scope then they will have immediate access to any newly added devices.

     

    This is primarily only an issue that is encountered when dealing with the initial provisioning of devices, and there are multiple ways of handling this. Some examples include:

    • As mentioned above - run the "ResolveScopeRights"
    • As mentioned above, give the processing user the "All Devices" scope.
    • If you absolutely don't want any "cross pollination" but want the "All Devices" scope for something else, you can always set up a (separate) LANDesk Core whose sole purpose it is to provision devices up to the point at which they're ready, and then install the "live" Core server's LANDesk agent on them. This logical segregation will guarantee that you've got a highly contained build environment that doesn't risk affecting your live environment for instance.

     

    II.E - Practice Safe Development

    Just as a general precaution against any "whooops"-type accidents, I'd strongly advise that you develop in / author your scripts against a test environment.

     

    That way if you end up breaking something horribly (not something that is particularly LIKELY, but anything's potentially possible, especially if shortcuts such as "full admin accounts" are used) -- no live systems will be affected.

     

    II.F - Public versus private queries / objects

    Certain methods may require access to either LANDesk queries, column sets and similar things - where it becomes very significant whether these are specific objects are publicly owned or (alternatively) personally owned by the process user. Just because you (as an admin) have potential access to all objects doesn't mean that the process user does.

     

    To make your life easier, especially across multiple process users, you may want to make use of public queries / publicly owned items for use with process users as this will prevent you from running into surprises about "user X does not have access to object Y you tried to access".

     

     

    III - The Basics Of Access

    From a browser, you can access the MBSDK calls/methods by simply entering -- http://YOUR-CORE-NAME/MBSDKService/MsgSDK.asmx -- and be greeted with a short description of each method / call that's available to you.

     

    However, in order to access these through a script, you need to follow the WSDL rules (which essentially means adding a "?WSDL" to the path). Just trying to browse to the above path via a script will not work. For scripts, you need to use -- http://YOUR-CORE-NAME/mbSDKService/MsgSDK.asmx?WSDL -- for things to work.

     

     

     

    IV - A Few Example WWW-methods (manual method)

    The manual / browser method is usually quite useful when getting to grips with a particular www-service call and provides quick, visual feedback of either success or failure.

     

    IV.A - Getting to the root of the www-service

    So - let's get a going - connect up to your Core Server, and launch your preferred www-browser - then go to -- http://YOUR-CORE-NAME/mbSDKService/MsgSDK.asmx? -- and authenticate if needed (in case your browser doesn't automatically attempt to pass through your credentials). You would be greeted with a screen like the below.

     

    MBSDK-root.jpg

     

    In order to explore / try these, all you need to do is just click on the relevant call you want to check out. Which brings us to our first test.

     

    IV.B - Getting the LANDesk Version

    As a starting point, let's begin with a really basic / simple www-service call -- The "GetVersion" method-- a request to return the running version for instance. No input required for our first call.

     

    So - from the listing of the www-service calls, scroll to the bottom and click on the "GetVersion" link

     

    Not much to see here (which is the point) beyond the "INVOKE"-button. So let's go ahead and click it - see what happens!

     

    GetVersion-Basic.jpg

    After pressing INVOKE, a new browser tab will open up, and you'll see something along the following:

    GetVersion-Results.jpg

     

    In this case, the Core is a LANDesk Management Suite 2016 Core server (hence version 10). Older version of LANDesk would have strings such as "9.60.x.x" or "9.50.x.x" for instance.

     

    Great - you've just completed your first (albeit interactive) call of a www-method.

     

    IV.B - A Basic input example

    On to a slightly more advanced example - a single data input method, for which we're going to use the "GetTaskStatus" method to report back on the status of an existing task.

     

    For this example, we're going to report back on a task based on the Task ID - the Task ID is a unique identifier which every task ever created / deleted has assigned to it, I've re-arranged the data columns in "Scheduled Tasks" to pull the Task ID field forward for the screenshot below:

    3 - Task ID Console.jpg

     

    Now that we have a few legitimate Task ID's - let's open up the www-method in our browser:

    3 - Task ID MBSDK Entry.jpg

     

    So after adding a valid Task ID & pressing INVOKE, we get back something along the following back:

    3 - Task ID MBSDK Results.jpg

     

    From this we can very easily see various potentially interesting fields:

    • Task Name (in the Console) & current status of the task
    • Start time of the Task
    • Total (2) / Completed (0) / Failed (0) device counts

     

    Whilst in the browser view (/the "manual" method) the XML text can become somewhat rich, different script tools may handle the response XML differently - so some gentle testing with your particular scripting / programming language is advised.

     

    IV.C - A Multi-data Method (GetMachineData)

    This is a www-method which brings back a data set as defined by the column set used for a device.

     

    NOTE:

    This particular example intentionally includes a "bad form" step which results in a vast amount of data being returned.

     

    This is intentionally included to highlight simple things that can have unexpected consequences if not carefully considered.

            

     

    I've configured a public Data Column Set that is public which has the following items (the first three are the default items, I've just added a list of the Software Package Names):

    • "Computer"."Display Name"
    • "Computer"."Type"
    • "Computer"."OS"."Name"
    • "Computer"."Software"."Package"."Name"

     

    For this method, we need a device ID (the unique ID that each device has) as well as the name for a column set ("Test Column Set") for this example.

     

    You can find the device ID of a device in the root of its' inventory tree:

    4.1 - GetMachineData Inv.jpg

     

    So - with a device ID string & a Column set string, we are now ready to use this specific method:

    4.2 - GetMachineData Begin.jpg

    Once we press the INVOKE button, THIS result will likely take somewhat longer to return, and once it's fully loaded it'll be quite long.

    4.3 - GetMachineData Results.jpg

     

    KEY LEARNING & EXPLANATION

    ... the reason for this is that (having defined the Software - Package column, we'll be getting a list of ALL of the packages on a device. Due to the way in which XML formats a list, you end up with a massive vertical list, while in the console you'd have a more sensible X by Y axis. This should serve as encouragement to define your desired data set as precisely as you can - or you'll have to filter through quite a bit of chaff to get your actually desirable nuggets.

     

    The above is just a single line of data - and every line will have to have a repetition of the display name, the type and the OS name - so quite a bit of wasted data for each individual / separate software package.

     

    IV.D - BNF syntax example & gotchas

    Certain MBSDK methods (such "ListMachines" for example) can make use of BNF (Backus Naur Form). You've probably already used it without knowing it. To help clarify what it is & how to use it - you're usually best off building the query you want in the LANDesk Console.

     

    Now - you can also use existing LANDesk queries - which is good if you HAVE those queries at the time. The use of BNF allows you to query dynamically (without having stored this as a LANDesk query first. Let's look at a simple LANDesk Query that looks for the presence of 7-zip on a device for instance:

    5 - BNF in Console.jpg

     

    This is 98% of the BNF you need. The *ACTUAL* string you need to add as a BNF (for a LIKE operator) looks as follows:

    5.1 - BNF in MBSDK.jpg

     

    KEY DIFFERENCES:

    The two strings are nearly identical - there is ONE difference though. That is the presence of the %.

     

    This is actually a SQL thing (see above, where I suggested you pick up on SQL). The % character is used in LIKE statements to clarify on which side (i.e. - to the right, left or both) of a given string you want the LIKE to actually match wildcards.

     

    The Windows Console takes care of this for you (without telling you) and simply encapsulates any LIKE-d strings automatically in %-ages on both sides. If you want to use the BNF in the MBSDK you need to do so yourself (as a simple -- (...) LIKE "7-Zip" -- will fail, as it would attempt an exact string match - as no wildcard starting points have been given).

     

    A few additional BNF example strings to help you along:

    "Computer"."Device Name" LIKE "%MyCoreServer%"
    "Computer"."OS"."Name" EXISTS
    "Computer"."OS"."Name" LIKE "%2012%"
    "Computer"."Software"."Package"."Name" LIKE "7-Zip%"
             

     

    Notice the last (7-zip) based query, which only has a single % -- you don't HAVE to have a % on both sides of your string. This follows the regular SQL rules for this operator.

     

    V - First Steps - Basic Examples of using the MBSDK in a script

    Now that we've covered the basics of dealing with the MBSDK on a manual basis - the next step is to actually start calling the MBSDK through scripts.

     

    While all example scripts used here will be based on PowerShell, you can use the scripting language of your preference. Certain things may be handled differently in different languages -

     

    V.A - My very first WWW-call / script (GetVersion)

    This PowerShell based script is meant to be run locally on the Core Server (due to the use of 'localhost') with a valid LANDesk user. The handling of credentials is dealt with in a "pass through" context here (i.e. - which ever user context is running this script - that's the set of credentials that will get used).

    # Point to the MBSDK www-service methods 
    [string]$where = 'http://localhost/mbSDKService/MsgSDK.asmx?WSDL' 
    
    Try {
        # Pass the current users' NT-credentials for authentication
        $WebService = New-WebServiceProxy -uri $where -UseDefaultCredential
    }
    Catch {
    # Error handling goes in here
    }
    
    # Call the "GETVERSION" method & show me the result:
    $WebService.GetVersion()
    
    <#
    The result / return will look something like this:
    PS C:\Xx> C:\Xx\ZZ_WWW-Service-test.ps1
    
    VersionString
    -------------
    9.60.0.244
    #>
                

     

    The script is provided in a simple "copy & paste" format, so that you don't have to be concerned about downloading an external powershell script.

     

    V.B - Adding a device to a task.

    The next example will involve passing an actual parameter through to a MBSDK method. Here we're going to do a couple of things:

    • We're going to prompt for credentials (even though we've hard-coded the username)
    • We're going to add a device to the Task with Task ID "10".
    • We're going to automatically resolve the device-name of the computer that runs the script (this is what the "$env:COMPUTERNAME" PowerShell bit does at the bottom) as an example of dynamically using a device name. We could just as easily use an actual string.

     

    IMPORTANT NOTES:

    There's an intentional use of "bad manners" here - a hardcoded string (for the username)!

     

    Also - the actual script itself is only about 5-6 lines overall - the vast majority of text here is comment & explanation. No need to be afraid

            

     

    # Point to the MBSDK www-service methods
    $where = 'http://localhost/mbSDKService/MsgSDK.asmx?WSDL' 
    
    # You can choose to either provide a username or just leave the "Get-Credential" command on its own.
    # Please note that in the following line is an (INTENTIONAL) example of a *BAD* scripting/programming practice. It should NOT be encouraged/followed.
    # In the current example, I've (intentionally) 'hard' coded the user-name to one I log in as -- though this can be changed in the GUI-window that'll be prompted easily.
    $Creds = Get-Credential -Credential HELLESPOINT\BOB
    
    # If you REALLY want (and it's a BAD idea), you can hard-code the password to be a secure string. Use the "ConvertTo-SecureString" to get those.
    # $Creds.Password = "{A_SECURE_STRING}"
    # If you just want to be "lazy", simply use Powershell's own option to use passthrough authentication for NT-credentials as the user-context running the script.
    
    
    Try {
        $WebService = New-WebServiceProxy -uri $where -Credential $Creds
    }
    Catch {
        # Error handling goes in here
    }
    
    # Call the "AddDeviceToScheduledTask" method to add a device (based on device-name) to a task (based on task ID #).
    # For instance, in the example below, we use "10" ==> is the LD_TASK_IDN - a PUBLIC task!
    # Currently - with ($env:COMPUTERNAME) - I'm reading out the name of the computer running the PS-script, and using that as the computer name parameter
    # Alternatively, you can hard-code names. For instance "CARTHAGE" as the DEVICENAME.
    $WebService.AddDeviceToScheduledTask("10", ($env:COMPUTERNAME))
    
    # IMPORTANT NOTE -- in order to prevent problems, make sure the task is *PUBLIC* !!
             

     

     

    VI - More advanced example(s) of using the MBSDK in a script

    The following script is one that allows for the deletion of devices using a script & GUI and making use of the MBSDK method.

     

    VI.A - The All Important Disclaimer / "Be careful what you wIsh for"

     

    IMPORTANT REMINDER - use DELETE-s with great *CARE* :

    Using automated steps to delete anything - especially devices or tasks - is something that needs to be done with great care & accuracy. There is no "undo" button for any kind of mistake. Treat any such operation as a potential "high risk" and make double/triple check to ensure you're only going to target what you actually intend to.

     

    So make sure that you've got logging (to keep track of what has been deleted - when - by whom - and why / upon whose request) as well as fact checking (as "close enough" tends to be a rather risky approach to permanently deleting anything). Also thoroughly test your own scripting / programming logic - The MBSDK will behave "as told to", which can be quite different to the "as intended to" line of though. Make sure your logic is accurate.

     

    Also - be aware of consequences. If you delete software distribution tasks for packages - and those packages have uninstall associations ... that will proc the relevant uninstall(s) to run on the devices that previously had the task targeted. The MBSDK methods give you a lot of power that can be automated.

     

    Please, be careful & respectful with it. Bad scripting logic / practices WILL get you into trouble.

     

    VI.B - A script with GUI to delete devices from multiple Core Server

    This script was written by a LANDesk TAM (who prefers to be anonymous but has an awesome beard).

     

    Instructions for use:

    • Copy the script to C:\ on the core server.
    • Create a “del.txt” file on the root of C:\ that lists all devices you want to remove from the database i.e.:
      • DeviceName-1
      • DeviceName-2
      • DeviceName-3
    • Make sure the ExecutionPolicy for PowerShell is set correctly.
    • Run the script and provide your domain credentials:

    6 - MBSDK DeleteDevice - LogonExample.jpg

    • Select the appropriate coreserver name from the list and click on OK:

    6.1 - MBSDK DeleteDevice - Device Deleter Example.jpg

     

    Note: If desired you can remove the list of Cores in the script and only include the one you are targeting.

     

    The process will echo the results to the PS screen and It will create a log file C:\ldms_del_comp.log with the results.

     

    Note: Please make sure the account you authenticate with has the appropriate LDMS rights.

     

    Last thing - *** USE AT YOUR OWN DISCRETION ***  and (as always when operating with deletes), make sure you have the appropriate backups in-place!

     

    $mycreds = Get-Credential #Read credentials
    $username = $mycreds.username
    $password = $mycreds.GetNetworkCredential().password
    
    # Get current domain using logged-on user's credentials
    $CurrentDomain = "LDAP://" + ([ADSI]"").distinguishedName
    $domain = New-Object System.DirectoryServices.DirectoryEntry($CurrentDomain,$UserName,$Password)
    
    if ($domain.name -eq $null)
    {
    write-host "Authentication failed - please verify your username and password."
    exit #terminate the script.
    }
    else
    {
    write-host "Successfully authenticated with domain $domain.name"
    }
    
    
    $CoreServer ='LD2016-1','LD2016-2','LD2016-3' | Out-GridView -OutputMode Single -Title "Select LANDESK Core Server"
    $inputfile = "C:\del.txt"
    write-host $inputfile
    $LogTime = Get-Date -Format "MM-dd-yyyy hh:mm:ss"
    $elapsed = [System.Diagnostics.Stopwatch]::StartNew()
    
    Function LogWrite
    {
       Param ([string]$logstring)
       $logstring = $logtime + " " + $logstring
       Add-content $Logfile -value $logstring
    }
    
    $Logfile = "C:\ldms_del_comp.log"
    Write-Host $Logfile
    $log = "++++++++++ Delete Devices"
    LogWrite $log
    
    $Landesk = New-WebServiceProxy -uri http://$CoreServer/MBSDKService/MsgSDK.asmx?wsdl -Credential $mycreds
    
    foreach ($computer in Get-Content $inputfile)
    {
        $Device=$computer.Trim()
        $Machine = $Landesk.ListMachines('Computer."Device Name" = '+ $Device)
        Write-Host ($Device + " - Trying")
        If ($Machine.Count -eq 1)
            {
                $log = ($Device + " " + "Found")
                  $MachineGuid = $Machine.Devices.Guid
                  $Landesk.DeleteComputerByGUID($MachineGuid) | Out-Null
                  $Machine = $Landesk.ListMachines('Computer."Device Name" = '+$Device)
                If ($Machine.Count -eq 0)
                       {
                        Write-Host ($Device + " - Deleting")
                        $log = ($Device + " " + "Removed" )
                        LogWrite $log
                       }
                  Else
                       {
                        Write-Host ($Device + " - Could Not Delete")
                        $log = ($Device + " " + "NOT Removed")
                        LogWrite $log
                       }
            }
            Else
            {
            Write-Host ($Device + " - Not Found")
            $log = ($Device + " " + "NOT FOUND")
            }
    }
    $RowCount = $inputfile.Count.ToString()
    $log =  $RowCount + " - Total Devices Completed"
    LogWrite $log
    $log = "++++++++++ Finished Tasks in Total Elapsed Time: $($elapsed.Elapsed.ToString())"
    LogWrite $log
          

     

     

    VII -Important information on Column sets (and how to specify them)

    There are two basic ways of defining what data columns you want to have displayed for the devices you're querying.

     

    This is principally relevant for the "GetMachineData"-function but may apply elsewhere too, if the option for a column definition is provided.

     

    VII.A - Basic rules with column sets

    Here are a few general points to bear in mind when handling column sets:

    • This part is *case sensitive* usually in the MBSDK. So make sure you respect case!
    • Your users needs to be able to have access to the relevant column set. So make sure your users owns it, or that it's a public column set!

     

     

    VII.B - Option 1 - using an existing column set from the LANDesk Console

    The easiest way to define data columns (both - WHAT you want to see, and the order which you want to see it) is to just refer to an existing Column set.

     

    Here, I have 2 Column sets in the console (one "Basic" and one "complicated":

    CONSOLE - Basic Column Set.jpg

    and

    CONSOLE - Complex Column Set.jpg

     

    And here's how I make use of them in the "GetMachineData" function.

     

    First, the basic column set example & data return (I am calling a DeviceID / GUID that's relevant to my database):

    MBSDK - Basic Column Set Config.jpg

    which returns the following:

    MBSDK - Basic Column Set Output.jpg

     

    ... whereas, the Complex column set would be called like so ...

    MBSDK - Complex Column Set Config.jpg

    ... and would bring me back the following (partial) result (I had to cut it off as it ran off the screen):

    MBSDK - Complex Column Set Output_Partial.jpg

     

    ... so - quite simple to use. Especially if you have complicated data sets to return, making use of an existing column set is VERY convenient.

     

     

     

    VII.C - Option 2 - Creating a column set on the fly - The basic premise

    But what if you need a "on the fly" column set. What if you have data where you need different data columns all the time & can't pre-plan or don't want to create 100-s of column sets?

     

    Well - that is possible and catered for as well!

     

    This section will go over the "basic layout" of what the "dynamic" column definition XML looks like - it's not going to work (due to changes in IIS validation) in its current state, but it is MUCH easier to read for humans. So - let's explain the basic format. Let's specify a column set which displays the following two attributes:

    • ID (record # in the database)
    • Device Name

     

    The basic column definition would look like so (formatted for "nice" human readability).

     

    <Columns>
        <Column>
            Computer.ID
        </Column>
        <Column>
            Computer."Device Name"
        </Column>
    </Columns>
    

     

    KEY LEARNINGS & EXPLANATION:

    • The columns respect the BNF notation for the inventory attributes
    • If you have attributes / objects that have a space in them (such as - "Device Name) be sure to surround them in quotes
    • ... by and large, that's all there is to it

     

    Now, all you'd need to do is just copy / paste the above text into a single line, and you're good to go. NEARLY... beware the next point!

     

    IMPORTANT NOTE:

    The example shown above is a "style guide" in essence and WILL NOT WORK with current

     

    VII.D - Specifying your desired columns via XML - The ACTUAL truth and format

    While the above is very human-readable, it will not work, if you put the XML column definition into the MBSDK!

     

    IIS will error out with an error message like this one:

    System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client (ColumnDefXML=&quot;&lt;Columns&gt;&lt;Column&gt;Com...&quot;).

       at System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection)

       at System.Web.HttpRequest.ValidateHttpValueCollection(HttpValueCollection collection, RequestValidationSource requestCollection)

       at System.Web.HttpRequest.get_Form()

       at System.Web.Services.Protocols.HtmlFormParameterReader.Read(HttpRequest request)

       at System.Web.Services.Protocols.HttpServerProtocol.ReadParameters()

       at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()

     

    Why? What's going on?

     

    What's happened is that IIS has (over the years) become a lot more security focussed as well, and as part of that, it validates input strings much more carefully.

     

    The basic *SYNTAX* described in the previous sub-chapter is 100% correct. We just need to substitute 2 items. We need to replace the <-s and the >-s.

     

    We need to go from the following:

    <Columns>
        <Column>
            Computer.ID
        </Column>
        <Column>
            Computer."Device Name"
        </Column>
    </Columns>
    

     

    and perform the following changes:

     

    "Old" Character
    "New Syntax" - becomes
    <&lt;
    >&gt;

     

    Pay particular note to the semi-colons at the end!

     

    ... so we end up with :

    &lt;Columns&gt;
        &lt;Column&gt;
            Computer.ID
        &lt;/Column&gt;
        &lt;Column&gt;
            Computer."Device Name"
        &lt;/Column&gt;
    &lt;/Columns&gt;
    
    

     

    And - as a single line this would appear as follows:

    &lt;Columns&gt;&lt;Column&gt;Computer.ID&lt;/Column&gt;&lt;Column&gt;Computer."Device Name"&lt;/Column&gt;&lt;/Columns&gt;
    

     

    ... which is quite a bit more painful to look at. But - it works. Let's give it a try.

     

    First - our MBSDK input for the "GetMachineData"-call (note that our Column definition XML is a lot longer than what the box displays):

    MBSDK - Custom Column Config.jpg

    ... and our output...

    MBSDK - Custom Column Results.jpg

    Beautiful.

     

    That would cover everything around Custom Column Sets - and cover both pre-configured use as well as dynamic / on the fly configuration.

     

    VIII - Other useful snippets

    This is a collection of various - hopefully useful - items that can make life easier / come in useful during various points of interacting with various systems. This section will likely grow as time develops.

     

    VIII.A - Basic example of grabbing HTTP status codes

    This one is from -- http://stackoverflow.com/questions/1473358/how-to-obtain-numeric-http-status-codes-in-powershell#1479204 -- and is a basic example of how to capture HTTP status codes. While this isn't going to be often useful specifically around the MBSDK (as we already return some form of "success / fail" result), it may be useful when integrating with other systems. So this is included for convenience & completeness here.

     

    Here's the relevant code snippet:

    # From -- http://stackoverflow.com/questions/1473358/how-to-obtain-numeric-http-status-codes-in-powershell#1479204
    $url = 'http://google.com'
    $req = [system.Net.WebRequest]::Create($url)
    try {
        $res = $req.GetResponse()
    } catch [System.Net.WebException] {
        $res = $_.Exception.Response
    }
    
    # The below will return "OK"
    $res.StatusCode
    
    # The below returns 200 in this particular example
    [int]$res.StatusCode
               

     

    VIII.B - A Quick & Dirty logger function

    The following is a Logging function that I've developed for some of my longer / more complicated scripts for several reasons. Logging helps you keep track of where you actually are, as well as keeping an eye on performance figures ("how long does it take for me to process a data set").

     

    This is far from ideal, "but it works", and is a nice, lazy copy & paste job that you can then call from within your script. conveniently.

    # Initial global variable declaration
    [string]$WorkingPath = (Get-Location).ToString() + "\" # "Hard"-linking the log-file location to the directory from which the script is executed.
    [string]$LogFilePath = $WorkingPath + "MyLogFile.txt" # Name / Link to our log-file
    
    ### LOGGER FUNCTION ###
    # Simple logger function to keep track of things & write desired strings into out log.
    # Will create an empty line (for white space) if the string handed to it is empty.
    function Logger ([string]$LogString) {
        if ($LogString -eq "") {
        Out-File -FilePath $LogFilePath -inputobject "" -Append
        Write-Host ("")
        }
        else {
        [string]$FullLineString = (Get-Date -Format r).ToString() + " :: " + $LogString
        Out-File -FilePath $LogFilePath -inputobject $FullLineString -Append
        Write-Host $FullLineString
        }
    }
    
    
    # Examples of use:
    # Add an empty line into my log-file:
    Logger("")
    
    # Add actual text into my log file:
    Logger("*** SQL FAILED ***")
    
    <#
    The resulting log-entry from the above will look like so:
    ""
    
    Mon, 30 May 2016 14:31:36 GMT :: *** SQL FAILED ***
    ""
    #>
    
            

     

     

    IX- Additional resources

    General catch-all for various hopefully useful / helpful related links. These links may take you outside of the LANDesk community.

     

    • For PowerShell related resources, you can pretty much google up anything you are likely to need.

     

    • SQL resources:

     

     

     

    X- FAQ

    This section covers various Q&A related items. If there

     

    Q - Does LANDesk patch problems / vulnerabilities / etc. in the MBSDK?

    Yes - absolutely.

     

    It's a component and supported like any other. You just log a case with support, reporting the relevant issue & as appropriate, the normal process for defects will be followed from there on out.

     

    Prior to LANDesk Management Suite 2016, MBSDK updates are part of the "BASE" parts of component patches.

     

    Q - The MBSDK doesn't do something I want it to - what do I do?

    Enhancement Requests (which is what new feature requests are) can be filed here -- Enhancement Requests  -- and follow the normal process around product improvements.

     

     

    XI- In Conclusion

    This article should provide a comprehensive introduction & guide to using the MBSDK along with practical examples & usable scripts to help you get started on writing automation scripts.