Jere's Techblog

Query big ADObject / Containers

The Powershell AD-Modules have certain restrictions when it comes to querying large objects, this can be bypassed by ADSI Query.

Here an example how to read them and how to iterate on users of a group:

#by J.Kühnis 13.03.2019
#example ADSI Query Powershell
$BigGroup = "someADGroupName"
$ADGroup1 = "someADGroup1"
$ADGroup2 = "someADGroup2"

$groupname = $BigGroup
$groupdsn = (Get-ADGroup $groupname).DistinguishedName
$group =[adsi]”LDAP://$groupdsn” 
$groupmemebrs = $group.psbase.invoke("Members") | % {$_.GetType().InvokeMember("SamAccountName",'GetProperty',$null,$_,$null)}

$groupmemebrs | foreach {
    $usradgroups = GET-ADUser -Identity $_ –Properties MemberOf | Select-Object -ExpandProperty MemberOf | Get-ADGroup -Properties name | Select-Object name
    IF ($ -notContains $ADGroup1 -and $ -notContains $ADGroup2) {

        #User is not a Member of ADGroup1 & ADGroup2

          #User is MemberOf ADGroup1 & ADGroup2

Here also an example using a Class to just specify the object the way you like:

#by J.Kühnis 09.10.2019
#Set variables
$ADGROUP = "someAdGrp"

# Load AD-Module
IF (!(Get-Module -Name ActiveDirectory)) {
    Import-Module -Name ActiveDirectory
    IF (!(Get-Module -Name ActiveDirectory)) {
    start-sleep 10
    Write-Warning "No AD-Module Found"

$groupname = $ADGROUP
$groupdsn = (Get-ADGroup $groupname).DistinguishedName
$group =[adsi]”LDAP://$groupdsn” 
$groupmemebrs = $group.psbase.invoke("Members") | % {$_.GetType().InvokeMember("SamAccountName",'GetProperty',$null,$_,$null)}

class User{

$Userlist = @()
$groupmemebrs | ForEach-Object {
    $usrATTR = GET-ADUser -Identity $_ –Properties Name,SamAccountName,UserPrincipalName,mail,extensionAttribute9, extensionAttribute7
    $User = [User]::new()
    $User.Name = $usrATTR.Name
    $User.SamAccountName = $usrATTR.SamAccountName
    $User.UserPrincipalName = $usrATTR.UserPrincipalName
    $User.Mail = $usrATTR.Mail
    $User.extensionAttribute1 = $usrATTR.extensionAttribute1
    $User.extensionAttribute2 = $usrATTR.extensionAttribute2

    $Userlist += $User
$Userlist | format-table
Continue reading...

Copy-Items with folder Structure and Filter in a Foreach-Parallel Workflow

#J.Kühnis 08.03.2019
$Sourcefolder= "\\localhost\C$\Temp\1"
$Targetfolder= "C:\Temp2\1"

$query = Get-ChildItem $Sourcefolder -Recurse | Where-Object {$_.LastWriteTime -gt [datetime]::Now.AddDays(-1)}

workflow CopyJob {
    param (
Foreach($item in $query){
    $dest = $Targetfolder + $item.FullName.SubString($Sourcefolder.Length)
    #Write-Host $dest -ForegroundColor Yellow
    Copy-Item $item.FullName -Destination $dest -Force

CopyJob -query $query -Sourcefolder $Sourcefolder -Targetfolder $Targetfolder
Continue reading...

Invoke Command on Specified MachineCatalog and DeliveryGroup

The nice thing about Powershell and the modules/API to other technologies is that you can do simple queries and have a big effect.

The following example starts a service for specified machines in a Citrix 7.x environment.

#by J.Kühnis 06.03.2019
Add-PSSnapin *
$machines = (Get-BrokerMachine * -AdminAddress |
 where-object {($_.CatalogName -match "someMC*") -and ($_.DesktopGroupName -eq "someDG")}).DNSName

Foreach ($machine in $Machines)
 {Write-Host $machine -ForegroundColor Yellow
 invoke-command -ComputerName $machine -ScriptBlock {get-service -name cpsvc | Start-Service} }

Continue reading...

Reset User Profile FatClients

Just run the Script and have some fun while deleting local/remote Userprofiles 🙂

The parameters Username and ComputerName are mandatory.

The parameter -wildcard:$true allows to delete multiple profiles. For example all users with the profile name “John*“.

#by J.Kühnis 
#Code Elements of
#Run with elevated rights
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent( ) )
if ( -not ($currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator ) ) )
    Write-Host "This script must be executed in admin mode." -ForegroundColor Yellow
    Write-Error "This script must be executed in admin mode." -ErrorAction Stop

Function Reset-LocalUserProfile {

        [Parameter(Mandatory = $true)][string]$Username,
        [Parameter(Mandatory = $true)][string]$ComputerName,
        [switch]$IncludeSpecialUsers = $False,
        [switch]$Force = $True,

    IF ($Username -match '\*'){
            Write-Warning "wildcard enabled, deletion for multiple users enabled"

            Write-Warning "Username must be unique without wildcard '*'. If you like to use wildcard, please use '-Widlcard `$true' parameter. "

    $profileFounds = 0

    #Region Functions

    Function Test-PSRemoting {
            [Parameter(Position = 0, Mandatory, HelpMessage = "Enter a computername", ValueFromPipeline)]
            [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty
        Begin {
            Write-Host -Message "Starting $($MyInvocation.Mycommand)"  
        } #begin
        Process {
            Write-Host -Message "Testing $computername"
            Try {
                $r = Test-WSMan -ComputerName $Computername -Credential $Credential -Authentication Default -ErrorAction Stop
            Catch {
                Write-Host $_.Exception.Message
        } #Process
        End {
            Write-Host -Message "Ending $($MyInvocation.Mycommand)"
        } #end
    } #close function

    #Check IF WinRM is OK

    IF (!(Test-PSRemoting -Computername $ComputerName)) {    
        Write-Host -Message "PS Remoting Error, can't reach Connect with WinRM"

    Try {
        $profiles = Get-WmiObject -Class Win32_UserProfile -Computer $ComputerName -Filter "Special = '$IncludeSpecialUsers'" -EnableAllPrivileges
    Catch {            
        Write-Warning "Failed to retreive user profiles on $ComputerName"

    ForEach ($profile in $profiles) {
        try {
            $sid = New-Object System.Security.Principal.SecurityIdentifier($profile.SID)               
            $account = $sid.Translate([System.Security.Principal.NTAccount])    
            $accountName = $account.value.split("\")[1]
            $profilePath = $profile.LocalPath
            $loaded = $profile.Loaded
            $special = $profile.Special
        catch {
        If ($accountName.ToLower() -Eq $UserName.ToLower() -Or ($UserName.Contains("*") -And $accountName.ToLower() -Like $UserName.ToLower())) {
            #If ($ExcludeUserName -ne [string]::Empty -And -Not $ExcludeUserName.Contains("*") -And ($accountName.ToLower() -eq $ExcludeUserName.ToLower())) {Continue}
            #If ($ExcludeUserName -ne [string]::Empty -And $ExcludeUserName.Contains("*") -And ($accountName.ToLower() -Like $ExcludeUserName.ToLower())) {Continue}

            $profileFounds ++

            If ($profileFounds -gt 1) {Write-Host "`n"}
            Write-Host "Start deleting profile ""$account"" on computer ""$ComputerName"" ..." -ForegroundColor Green
            Write-Host "Account SID: $sid"
            Write-Host "Special system service user: $special"
            Write-Host "Profile Path: $profilePath"
            Write-Host "Loaded : $loaded"
            If ($loaded) {
                Write-Warning "Cannot delete profile because is in use"

            If ($Force -Or $PSCmdlet.ShouldProcess($account)) {
                Try {
                    Write-Host "Profile deleted successfully" -ForegroundColor Green        
                Catch {            
                    Write-Host "Error during delete the profile. Maybe the user with you executed the script has no rights or the script was not started with admin rights." -ForegroundColor Red

    If ($profileFounds -eq 0) {
        Write-Warning "No profiles found on $ComputerName with Name $UserName"
Write-Host '########## START SCRIPT ##########' -ForegroundColor yellow

Continue reading...

Get Data from Bluecat DNS Server with REST API

Here is an example how you can use the REST API on the BluecatDNSServer to query data via the workflow interface (alternatively you could use its API directly).
I am sure that you can use this concept for other web interfaces.

The script is a translation of a CURL request. It shows how to query the token and use this “BASIC Token” for further queries.

#BY J.Kühnis
#Invoke Webrequest/RestMethod to get IP Adress & Mac-Adress from Bluecat API
#translation of CURL Commands

#   CURL sample
#curl -k https://URL/rest_login -X POST -H "Content-Type: application/json" --data "{\"username\":\"your USERNAME\",\"password\":\"your USERNAME\"}"
#GET Request:
#curl -k https://URL/get_ip_infos/get_ip_infos_endpoint -X GET -H "auth: Basic ****SOME TOKEN****" -H "Content-Type: application/json" --data "{\"host\":\"SERVERNAME\"}"
#  "ip": "some ip",
#  "mac": "some mac"

#Trust SelfSigned SSL/TLS Channel
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

#Generate Web Token (Basic Token)
Function Get-WebTokenBasic{

    [Parameter(Mandatory = $true)][string]$Username,
    [Parameter(Mandatory = $true)][string]$Password

$json=ConvertTo-Json (@{"username"="$Username";"password"="$Password";})
$token = (Invoke-WebRequest -Uri "https://URL/rest_login"  -Body $json -ContentType "application/json" -Method POST).content | Out-String | ConvertFrom-Json

$token = $token.access_token
$global:headers = @{auth="Basic $token"}


#Get IP or Mac from Servername
Function Get-DNSBluecatValues{
    [Parameter(Mandatory = $true)][string]$ServerName

$json4= (@{"host"="$servername";}) | ConvertTo-Json

    $result = Invoke-WebRequest -Uri "https://URL/get_ip_infos/get_ip_infos_endpoint" -Headers $headers -Body $json4 -Method Post -ContentType "application/json"
    $global:result = $result | ConvertFrom-Json
    return $global:result
    $ErrorMessage = $_.Exception.Message
    $FailedItem = $_.Exception.ItemName
    Write-Warning "Failed Authentication or Webrequest"

Continue reading...

MCLI Module error after Citrix PVS Update 7.13 to 7.18

After Updating Citrix PVS Server i got an Issue with my PVS Scripts.
I couldn’t load the Powershell modules anymore.

Of course I have properly registered the DLL of the PVS Snapin. I executed the following command as admin in the CMD:

"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe" "c:\program files\citrix\provisioning services console\Citrix.PVS.snapin.dll"

I got this Error:

PS C:\Temp> Add-PSSnapin *

Add-PSSnapin : Cannot load Windows PowerShell snap-in McliPSSnapIn because of the following error: The Windows PowerShell snap-in module C:\Program Files\Citrix\Provisioning Services

Console\McliPSSnapIn.dll does not have the required Windows PowerShell snap-in strong name McliPSSnapIn, Version=, Culture=neutral, PublicKeyToken=null.


The support article describes some symptomps but the Solution didn’t work.

In my case I had to manually change certain registry keys.


You Can also Copy this into a .REG File and run on the PVS Server (Ensure the Versionnumber is equal to your PVS Version):

Windows Registry Editor Version 5.00

"Vendor"="Citrix Systems, Inc."
"Description"="This is a PowerShell snap-in that includes the Mcli-Add, Mcli-Delete, Mcli-Get, Mcli-Help, Mcli-Info, Mcli-Run, Mcli-RunWithReturn, Mcli-Set and Mcli-SetList cmdlets."
"ApplicationBase"="C:\\Program Files\\Citrix\\Provisioning Services Console"
"ModuleName"="C:\\Program Files\\Citrix\\Provisioning Services Console\\McliPSSnapIn.dll"
"AssemblyName"="McliPSSnapIn, Version=, Culture=neutral, PublicKeyToken=null"

Continue reading...

Delete Citrix Worker from Studio and vCenter

With this script one or more servers can be deleted from the Citrix DeliveryController (Citrix Studio) and from the ESXi/vCenter.

To use The Script some variables and values need to be adjusted like the name of the Citrix DeliveryController and vCenter.
Vmware (PowerCLI) and Citrix (SDK) powershellmodules need to be installed.

This only works if the VM name is identical to the Worker Server DNS name. If this is the case, the following string can be deleted in the script [-replace “.FQDN.address”,””]

In my case, the name of the VM is only the “hostname” of the machine and not the DNSname. So the script removes the FQDN name, in order to use the script successfully, this must also be adjusted.

Import-Module *
Add-PSSnapin *

$DeliveryController = "someBrokerDNSName"
Connect-viserver "some vCenter"

Get-BrokerMachine -DNSName anySevernames* -AdminAddress $DeliveryController |  %{
    #Delete & Remove From Citrix Studio
    Remove-BrokerMachine $_ -DesktopGroup $_.DesktopGroupName
    Remove-BrokerMachine $_ -Force

    #Delete Permanently from vCenter
    remove-vm ($_.DNSName -replace ".FQDN.Adress","") -DeletePermanently -Confirm:$false

    write-host $_.DNSName -ForegroundColor Green  #Write ServerName

Continue reading...

Useful WordPress Plugins

I’m a big WordPress fan!
The community is huge, it has lots of plugins and it is very user friendly.
Compared to a CMS like Typo3, simple end users can manage WordPress very easily and create posts, as well as customize pages.

This post shows some of my favorite addins and explains their function:

WPTouch – Responsive Mobile Theme;easy to manage

Simple Login Screen Customizer –the name says it all

Secret Content – hide content from non logged in visitors

Post Expirator – The Post Expirator plugin allows the user to set expiration dates for both posts and pages.

NextGEN Gallery – The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 24 million downloads.

Members – Members is a plugin that extends your control over your blog. It’s a user, role, and capability editor plugin that was created to make WordPress a more powerful CMS.

Contact Form 7  & Advanced Contact form 7 DB – A solid contact form plugin and extension that exports the database in formats such as CSV, Excel, etc.

Continue reading...