Privileged Account Discovery Script: Reduce Privilege Escalation Attacks


Privileged accounts are accounts on computer systems with more access than standard user accounts. These accounts, for example, can execute processes in the system context, run system-wide services, or modify system configuration files.

Privileged accounts are often targets for privilege escalation attacks, where attackers are able to gain access to network-wide resources after making a beachhead on a system using a standard user account.

The Story of the Discovery Script

There are several great tools out there for discovering and managing privileged accounts. I was determined to find a free tool that would provide the level of detail I was looking for.

After conducting research, I could not find what I was looking for so I decided to write a custom script.

Download Script: Privileged Account Scanner V1

This script focuses on six main types of Windows privileged accounts:

  1. Windows Local Administrator Accounts
  2. Windows Service Accounts
  3. Windows Scheduled Task Accounts
  4. Windows COM+ Application Service Accounts
  5. Windows DCOM Application Service Accounts
  6. Microsoft SQL Accounts

The Script requires Windows PowerShell Remoting to be enabled.

Furthermore, the account you execute the script with must have Local Administrator privileges on the target system, and GRANT CONTROL SERVER on SQL servers.

“I could not find what I was looking for so I decided to write a custom script”

Provide an array of computer names to the parameter ListOfTargets and the script will gather privileged account information on each of the target computers.

The result will be a CSV file generated in the TEMP folder. That path can be modified with the ReportExportPath parameter, as seen in the below command.

.\PrivilegedAccountScanner.ps1 -ListOfTargets “DB01”,”ERPM01” -ReportExportPath “C:\users\SuperAman\desktop\”

Running this command produces a report that looks like this:

In this example report you see examples of most of the types of accounts the script scans for. Below are the columns found in the report and a brief description of each:

  • ComputerName – The computer targeted for scanning.
  • Account – The name of the discovered privileged account.
  • Type – Shows which of the six types of account this account falls under.

The data in the name and note columns will change depending on the type of account.

Additionally, below is an outline of how different account types affect other columns:

  • Local Admins
    Shows “N/A” for name, and the type of account discovered. Above you see that the account is actually a group.
  • Service Accounts
    The Name column shows the service name and the note column shows the service description.
  • Scheduled Tasks
    The name column is the name of the Scheduled task and the note column will display “N/A”.
  • COM+ and DCOM
    Application accounts, the Name column shows the application name and the note column is the application key.
  • SQL Accounts
    The name column shows the associated SQL Instance and the Note column shows a summation of what roles and explicit permissions are assigned to the account./

Customizing Data

You can do further customization of the data your collecting by modifying array variables defined near the top of the script, as shown below.

Broaden or Focus Discovery Scan

The following are arrays that can be modified depending on your reporting needs.

  • The $FilterArray is a list of accounts that are ignored during the discovery scan
  • The $FilterSQLBuiltinAccounts is the list of built in SQL Account to ignore
  • The $SQLPermissions is a list of SQL permissions to look for when scanning SQL
  • The $SQLRoles is a list of SQL roles to look for when scanning. Any SQL users that are members of these roles will be captured

“By adding or removing elements of these arrays, you can broaden or focus your discovery scan.”

Let’s Continue the Conversation

I set out to develop a flexible scanning script that can provide actionable data on privileged accounts in your environment. However, I am sure there are scenarios, configurations, and use cases that I missed.

I look forward to feedback and any requests for additional functionality. Do you have a suggestion? Please leave it in the comments below and we will continue the conversation.


Aman Motazedian
Senior Consultant
Critical Design Associates

LinkedIn Profile

Optimizing Windows 10 Upgrades with Ivanti Endpoint Manager (EPM)


In a recent customer engagement, the client had requested to upgrade Windows 10 workstations within their environment using Ivanti Endpoint Manager (EPM.)

Ivanti has a recommended method to upgrade Windows 10 workstations to newer versions through their service pack definitions.

The service pack definitions are found in the Patch and Compliance tool and can be used to determine if an endpoint can receive the upgraded version of Windows. The service pack definition defines an ISO for the deployment, which cannot be downloaded via the Patch and Compliance tool.

The ISO must be downloaded separately and renamed to match what is configured in the definition. There are both pros and cons to using the recommended method:

ISO Method


  • Easy to deploy
  • Simple configuration


  • Space requirements (2x ISO size)
  • Large performance impact
  • Poor end-user awareness

When deploying any patch or distribution package, it is important to do so consistently each time to achieve expected results.

For this reason, I developed a Software Distribution method that would offer versatility and consistency with any Windows 10 upgrade. There are pros and cons to this method as well:

Software Distribution Method


  • Fewer space requirements (1x ISO size)
  • Full end-user awareness
  • No performance impact


  • More involved configuration
  • Leaves machine unusable for the duration of the deployment

Deploying Windows 10 Upgrades via Patch and Compliance

Ivanti’s recommended method for upgrading Windows 10 is fairly straightforward for the setup and deployment.

After the ISO is named according to what is configured in the definition file, all that is left to do is deploy it to targeted endpoints.

The Patch and Compliance deployment, after scheduling the repair and starting the task, is as follows:

  1. Copy the ISO to the machine (download ISO here)
  2. Mount the ISO and extract the contents
  3. Unmount the ISO and start the upgrade process with the now local files

As previously mentioned, Ivanti’s recommended method for deployment has some cons.

First, it is required to have twice the disk space on the endpoint for storing the ISO and the extracted contents; that can easily amount to 8GB or more.

Once the installation starts, a large performance impact will be seen as the upgrade will start using most of the machine’s resources.

Lastly, there is poor end-user awareness as to what is actually happening. EPM does have the capability to provide prompts to the end user with the correct agent settings; however, when using those settings there is still no indication of the progress of the deployment.

Deploying Windows 10 Upgrades via Software Distribution

Ivanti’s Windows 10 upgrade method using Patch and Compliance works, but in this case, the customer needed something that was more user friendly and did not have any impact on performance.

This is how the Software Distribution method ensued. The Software Distribution method makes use of two custom batch files.

The first batch file used in the deployment, in this case, named GetUserName.bat, is used to simply get the username of the currently logged-in user if there is one; the username will be output into a temporary text file called Username.txt.

By default, when creating a distribution package, it will run under the SYSTEM account.

This particular package, however, will run under the current user account; this is important for the next batch file in the process. The contents of the GetUserName.bat file can be seen below.

REM -- If C:\Temp doesn't exist, create it and output the current user to Username.txt
REM -- Since the task is running under the current users context, a file will only get
REM -- created if there is a user logged in

if not exist C:\Temp (
mkdir C:\Temp
echo %username% > C:\Temp\Username.txt
) else (
echo %username% > C:\Temp\Username.txt

The second batch file, which will be named Windows10Upgrade.bat, will use the Username.txt output from the previous batch file if it exists.

If the Username.txt file exists, a scheduled task will be created to execute setup.exe that gets copied to the clients.

Setup.exe is the main executable in a Windows ISO that installs and configures the OS with the parameters you define.

The scheduled task will be created to run in the current user’s context with the highest privileges and will execute one minute from the time it is created.

Running the task with the highest privileges is a requirement, otherwise, the scheduled task will fail. The reason a scheduled task is created is to allow the user to see the GUI operation of the upgrade; if setup.exe was executed under the SYSTEM context, the currently logged in user would not see anything.

If there is no Username.txt file, setup.exe will just run under the SYSTEM context as that is the default for the distribution package. The contents of the Windows10Upgrade.bat file can be seen below.

REM -- Set the 'name' variable to whatever is in the text file, if it exists
REM -- This text file only gets created if there is a user currently logged in

set /p name=<C:\Temp\Username.txt

REM -- Get the time in 24 hour format, add one minute, and assign it to the 'hhmm' variable

set hh=%time:~0,2%
set mm=%time:~3,2%
set /A mm=%mm%+1
if %mm% GTR 59 set /A mm=%mm%-60 && set /A hh=%hh%+1
set P=00%mm%
if %mm% LSS 10 set mm=%P:~-2%
if %hh% == 24 set hh=00
if "%hh:~0,1%" == " " set hh=0%hh:~1,1%
set hhmm=%hh%:%mm%

REM -- If the Username.txt exists, that means a user is logged in, so create a scheduled task
REM -- Set the scheduled task to run with the highest privileges and under the currently logged in user
REM -- This will ensure an update prompt is seen by the user during the upgrade
REM -- Otherwise, just run setup.exe as SYSTEM since no user is logged in and Username.txt does not exist

if exist C:\Temp\Username.txt (
schtasks /create /s %computername% /tn "Windows Upgrade" /sc once /tr "%cd%\Setup.exe /Auto Upgrade /Telemetry Disable /ShowOOBE none /DynamicUpdate disable" /st %hhmm% /rl highest /ru %userdomain%\%name%
del C:\Temp\Username.txt
) else (
Setup.exe /Auto Upgrade /Telemetry Disable /ShowOOBE none /DynamicUpdate disable

While the batch files, along with the ISO itself, are the main components of this deployment method, below is a list of items and configurations needed for this deployment method:

  • Windows 10 ISO (Extracted to a folder)
  • GetUserName.bat (In the same folder as the Extracted ISO)
  • Windows10Upgrade.bat (In the same folder as the Extracted ISO)
  • IIS MIME type for Default Website
    • Type: application/octet
    • Extension: .

This method allows for a seamless, quick, and efficient deployment that will provide the end-users with a good experience if logged in during the deployment.

If they are logged in, they will have full insight into what is happening. The general process for the entire deployment is as follows:

  • The task starts and either begins the download on the client or starts executing the batch files if already downloaded
    • GetUserName.bat runs and outputs a Username.txt file to C:\Temp that contains the username of the currently logged-in user if there is one. A file does not get created if there is no user logged in.
    • Next, Windows10Upgrade.bat will run and determine if there is a Username.txt file
      • If there is a Username.txt file, a scheduled task will be created for the current user, obtained from the Username.txt file
      • If there is no Username.txt file, setup.exe will run under the SYSTEM context as is the default for the package
    • The machine will transition to a blue screen showing the progress of the installation after about 30-45 seconds and will make the computer unusable for approximately 45min-1.5h; time can also vary depending on hardware capabilities

As you can see, the process is fairly straight forward and if anything gets created, such as the Username.txt file and scheduled task, it will be cleaned up.

To make this process more user friendly, one can also pair this entire deployment with notification messages or deferment timers to provide more control to the end-user.

These are a few examples of the flexibility that EPM offers. Below is a short video of the deployment and demonstration of how it works and is setup.

Ivanti Endpoint Manager (EPM) Demo & Deployment Video

In Conclusion

Thank you for reading and please feel free to reach out if you have questions, comments, or concerns about the information presented in this article.

Zach Thurmond
IT Consultant
Critical Design Associates

LinkedIn Profile

Using PowerShell to Deploy Ivanti UWM Agents

The Ivanti Management Center PowerShell Module

The Ivanti Management Center provides a simple interface to deploy Ivanti UWM agents and configurations.

When installed, it exposes web services that are used by the Ivanti Management Center console to perform various functions.

I began developing functions to manipulate the Ivanti web services while on a project where I needed to automate the process of moving and polling machines.

After working with various functions, I assembled what I needed and created a module that works intuitively within PowerShell.

With this module administrators can automate certain management tasks that would ordinarily have to be performed through the UWM Management Center console.

A few examples of tasks that can be automated:

  • Moving machines between deployment groups
  • Installing the CCA
  • Polling machines
  • Removing the machines from the database

We will review the functions in the module and a simple script that allows users to pull machine information from the Management Center console.

There are two scripts that come with this module:

The IvantiManagementCenterModule.psm1 script is the module which contains all functions.

This is a basic template for accessing the module as shown below.

$PathToManagementCenterModule = "."

If(-not(Test-Path -Path "$PathToManagementCenterModule\IvantiManagementCenterModule.psm1")) {
    Write-Host "Unable to find the IvantiManagementCenterModule.psm1 module file, quitting."

Import-Module "$PathToManagementCenterModule\IvantiManagementCenterModule.psm1" -ErrorAction Stop

Connect-MCServer -ManagementServerName "uwm01.lab.local" -Port 80


Inside MCSCript.ps1 we define the variable:
$PathToManagementCenterModule = "."

The script can be modified to change the path containing the module. This is helpful if you paln on keeping it centrally on a workstation or server.

EX: $PathToManagementCenterModule = "C:\users\adminuser\documents\powershellstuff"

The MCScript will then load the module.

Let’s Get Started

First we call the Connect-MCServer function. This function is a prerequisite for all the functions in the module. Calling any other function without calling this one will cause the script to fail.

My lab management server is UWM01 and is configured to communicate with agents through port 80.

Connect-MCServer -ManagementServerName "uwm01.lab.local" -Port 80

After that we call the Get-MCMachine function.


This function returns an object or collection of objects that are the records for the machine in the Ivanti Management Center server.

You can then pipe this collection into the built-in PowerShell cmdlets Select-Object or Format-List to generate a simple report.

Additional Functions

Update-MCMachineList – Refreshes internal arrays that contain the machine list sent back by the Ivanti Management Server.

Get-MCDeploymentGroup – Returns a group or collection of groups in the Ivanti Management Center.

Move-MCMachine – Moves a machine or a collection of machines in the Ivanti Management Center.

Start-MCInstallCCA – Calls the Ivanti Client Communication Agent install function on a target machine.

Start-MCPollMachine – Starts a client poll on a target

Remove-MCMachine – Removes a client from the Ivanti Management Server. This function is designed to only delete one machine at a time. It does not work with wildcards.

A Few Aspects to Consider

Once the module is loaded, you can use Get-Help with the above functions to get more detailed information including examples.

You can also inspect the comments in the IvantiManagementCenterModule.psm1 file to get this information.

Additionally, most of these functions have been designed to work with PowerShell pipelines.

Real World Scenario

In my example I have two machines. Each machine is a member of a different deployment group. I also have a server and is a member of another deployment group.

Using the script, I acquire a list of machines that match these workstations and poll only the machines that start with “Win10”.

Get-MCMachine -Machine "Win10*" | Start-MCPollMachine

In the client access log, you’ll notice a custom message:

In Conclusion

I hope this script will help my fellow Ivanti admins with machine cleanups and periodic CCA pushes.

I also look forward to any new use cases, custom scripts, and suggestions for improvement.


Aman Motazedian
Senior Consultant
Critical Design Associates

LinkedIn Profile

Using PowerShell and Ivanti UWM API for Machine Polling

I was working on a project where we built a complex Environment Manager config. It made sense to have this config start doing its magic on the workstation during the SCCM build Task sequence, but we didn’t want to have to maintain a config package in SCCM.

I decided to search around to find out how to force a poll at the time of install for the Ivanti Client Communication Agent during the SCCM task sequence. Forcing a poll ensures that the EM Config is downloaded to the endpoint after establishing communication with the management server.

Unfortunately, this was not as straight forward as it looked, and doing it manually through the management center console was not an option.

Ivanti provides a document titled “AppSense Management Center v10.0 Web Services API Guide” which is the latest version I could find in their Knowledge Base. This document lays out what services and functions are available through a set of APIs designed for this type of solution.

An additional resource I used was a blog article on Ivanti’s web site:  

This article showed me how to perform a Machine move and provided a template for how to load the API objects using libraries that are installed with the console.

The following PowerShell snippet is an example of calling the WebServices API:

While the blog article explains how to find machines using the WebServices API, it doesn’t provide much information on how to execute a poll.

I discovered that a method for executing a poll involves a process by creating “instructions” and executing them:

Notice the parameter “Initiating Script Client Poll”. This will show up in the console when the action executes.
You also need to make sure that there are no existing instructions. The console automatically takes existing instructions into account, so you’ll need to make sure to delete any existing instructions before adding a new one.

And then it’s a matter of performing an “activate” function which will run the loaded instruction as shown below:

If you want a simple PowerShell script to poll a machine in your Ivanti Management Center, use my script below!

Make sure to run the script on a computer with the Management Center Console installed. Info-wise, you just need the name of your Management Server, the Port that’s configured to receive Web Service requests, and the name of the Machine that you want to poll.

An easy way to get this info is to see how you’re connecting to your management server with the MC Console.

Your script call should look something like this:

When the script is run, you’ll see this message in the console for the machine:

There are a lot of these great little functions hidden away in the Ivanti Management Server Web Services, so check in again soon to see the other scripts we’ve come up with.


	This script will run a poll on a workstation in the Ivanti Management Center
    This script will run a poll on a workstation in the Ivanti Management Center
.PARAMETER ManagementServerName
    The name of the Ivanti Management Center Server
	Default is 80. Can also be set to 443
	Machine Name
    .\Poll-MCMachine.ps1 -ManagementServerName "" -Port 80 -Name "Win10-2"


Param (

If($Port = 80) {
    $Protocol = "http"
}Else {
    $Protocol = "https"

$ManagementServerUrl = "$($Protocol)://$($ManagementServerName):$($Port)/ManagementServer"

If(Test-Path "${Env:ProgramFiles}\AppSense\Management Center\Console\ManagementConsole.WebServices.dll"){
    Add-Type -Path "${Env:ProgramFiles}\AppSense\Management Center\Console\ManagementConsole.WebServices.dll"

$ConnectionCredentials = $([System.Net.CredentialCache]::DefaultCredentials).GetCredential($ManagementServerUrl, "Basic")

[ManagementConsole.WebServices]::Connect($ManagementServerUrl, $ConnectionCredentials)

$MachinesWebService = [ManagementConsole.WebServices]::Machines
$DeploymentWebService = [ManagementConsole.WebServices]::Deployment

$TargetMachineObject = $MachinesWebService.FindMachines('%').Machines | Where-Object {$_.NetBiosName -eq $Name}
$TargetMachineKey =  $($TargetMachineObject | Select-Object MachineKey).MachineKey

$DeploymentWebService.GetDeploymentInstructionsFromDiscoveredMachineKey($TargetMachineKey).Instructions|Foreach-Object {$DeploymentWebService.DeleteInstructions($_.InstructionKey,$Null)}

$PollActionGuid = [guid]::newguid()

$DeploymentWebService.CreateInstructions($PollActionGuid,129,$Null,"DeployNowPlugin.dll",$TargetMachineKey,"Initiating Script Client Poll")|Out-Null


Aman Motazedian
Senior Consultant
Critical Design Associates

LinkedIn Profile

Securing an Existing ADFS Environment with Okta MFA

Since the introduction of Active Directory Federation Services (ADFS) in 2015, companies have been widely adopting the idea of using this technology to leverage claims-based authentication…

How Ivanti Development Broke My Start Menu

There was a post on the Ivanti forums that I started reviewing in October ( This post was about the Edge icon on the taskbar reappearing each time.

From my past experience, this was an easy fix, you needed to add the “StartMenuInit” value as a managed item in personalization. The “StartMenuInit” value acts much like “Active Setup” and runs at first logon to customize the users profile by adding the browser (based on your OS) to the start menu as well as the taskbar.

It also adds Windows Media Player or Server Manager shortcuts depending on your OS. For the customer in this forum post the fix was easy, capture “StartMenuInit” to prevent this from happening at every logon. The customer responded that this recommendation broke the start menu.

I’ve never used the XML method mentioned in the thread above to capture the start menu. Historically, personalization worked fine, using my baseline templates and the built-in functionality… so managing the start menu via PowerShell didn’t make sense to me. “XML Method Reference”: James Rankin first talked about this method on his blog over 3 years ago.

I decided to give the “XML method” a try and found out that it is also controlled by “StartMenuInit” value and is designed to run once per user. This being the case, you can capture “StartMenuInit” and prevent IE or Edge from re-pinning over and over or you can personalize your start menu via the XML method but not both.

Critical Design is hiring ITSM Consultants with Ivanti Experience. Learn more at our career opportunities page.

During this testing, I tried reverting back to my “old tried and true” templates that have always worked. Basically, my template is an out of the box configuration with “StartMenuInit” and the “UserSignedIn” values added. What I found was that on the second logon the start menu was completely broken. I was able to reproduce these results on every recent build of Windows 10 (1607, 1703, 1709). I was “stumped”… why is this issue is occurring all of the sudden?

Come to find out this is a new undocumented “feature” in FR3. This new functionality handles the start menu using the XML method that isn’t documented in any release note that I could find.

This little-hidden gem was found in the out of box templates on my personalization server. See the image below:

When the layoutmodification.xml file is included it breaks the functionality in my template. Since I cannot update the out of box settings I had to create a new custom setting and replace it.

Now I had my start menu working again on Win10 1607 and properly managing the taskbar personalization by capturing “StartMenuInit”.

I was fired up until I started testing this fix on other Win10 builds. On Windows 10 1709 the implementation with FR3 was rather simple. In 1709 Microsoft stopped using the “TileDataLayer” and completely replaced it with the “CloudStore” registry key.

After some success with Windows 10 1709 and the updated Windows Setting Group I moved on to testing Windows 10 1703. This turned out to be a “mess”. I began to suspect that Ivanti development must be doing something in the code with 1703 and the TileDataLayer that does not make sense to me.

Much like the new XML method, that I mentioned earlier, it isn’t documented in the release notes.
When testing Windows 10 1703, At logoff, the copy of the TileDataLayer folder fails. Not only does it fail with some completely weird reason but the path is completely wrong and is referencing my temp folder, as shown in the highlighted output below:


After witnessing these results the issue is becoming apparent. In my opinion it appears that FR3 has had some major overhauls, which are causing a lot of issues. I decided to test FR2 on the exact same machine. FR2 was able to copy the entire folder without any issues. This led me to the conclusion that the issue cannot be the endpoint OS but the version of Environment Manager that is not allowing the “TileDataLayer” folder to be copied out on 1703.

So rollback to FR2? Not exactly…. See there is a known issue in FR2 with the “CloudStore” key. This article written in Ivanti’s own words proves that all that was needed was the “CloudStore” key.

The issue in the article DOC-48236 has been resolved in FR3. While FR3 fixes one (or many) issue(s) it appears to also unintentionally broke some features that worked before. I cannot rollout FR3 due to the “TileDataLayer issue” in Win10 1703 and the workaround in the article is inconsistent due to it using the desktop created trigger.

It seems to me that if the issue with the CloudStore key was resolved in FR3, which it has, and development didn’t add changes with the “XML Method” and “TileDataLayer” functionality we would be in good shape. The start menu and taskbar functionality would be working if the “out of the box” templates were modified to use the proper includes (referenced above).

At the present time I am being told that this issue would need to be addressed as a feature request. Since we know the issue exists and have at least one possible solution to fix the issue, I need some support from the community to get this feature request prioritized.

If you would like to help get this issue resolved please vote on this request here:

Stay tuned for updates!

Landon Winburn
Principal Architect
Critical Design Associates