Jere's Techblog

Create Discord Bot

I way toying arround with Discord and Python because I wanted to record the messages and reactions of users.
Therefore I wrote a bot with the library discord.py My first attempts with Python…or let’s say a try and error session….

But in the end I was able toget the reactions and log messages.

below some good references and instructions and an example of my discord bot

Prerequisits:

Installation of Python 3.5<

Python Discord API – https://github.com/Rapptz/discord.py

py -3 -m pip install -U discord.py

Python await – https://pypi.org/project/await/

pip install await

Python async – https://pypi.org/project/async/

pip install async

References:

Documentation

https://discordapp.com/developers/docs/intro

https://discordpy.readthedocs.io/en/latest/discord.html

https://discordpy.readthedocs.io/

Tutorial

https://realpython.com/how-to-make-a-discord-bot-python/

My own Bot

import discord
from discord.ext import commands

client = commands.Bot(command_prefix='.')

@client.event
async def on_ready():
   #a = discord.utils.get(client.get_all_members(),name="Test-User", discriminator="9635").id  #GetUserID
    print('Bot is ready.')


"""  crawl message
@client.event
async def on_message(message):
    if str(message.author) == 'Test-user#111':
         print(f'{message.content} RECEIVED!.')
    else:
        print(f'{message.content} wrong User!.')
"""

#get reaction an log it on another channel crawl message with some condition as an example
@client.event
async def on_reaction_add(reaction, user):
    channel = client.get_channel(6637461198)
    print(f'{reaction}')
    if str(reaction.message.author.id) == '579155970803':
        if str(user.id) != '57915597803':
            await channel.send('[{0.display_name}] -  {0} has reacted with {1.emoji}!; ID = {1.message.id} '.format(user, reaction))
client.run(' some API-DiscordServer String here ')
Continue reading...

Get size of Citrix UPM Profile

With these few lines you get an evaluation of your profile sizes and the AppData, if you have redirectet this to a share.
The script is designed to check multiple shares. You only have to adjust the array “$ProfileFolders” and if necessary the variable “$folder1, $folder2”

#by J.Kühnis 18.12.2019
$ProfileFolders = @(
"\\TSProfileShare1\profile$",
"\\TSProfileShare2\profile$"
)

$infos = @()

Foreach ($folder in $ProfileFolders){
Write-Host $folder

Get-ChildItem $folder | ? { $_.Name -notmatch ".V2" } | % {
    
    Write-Host ($folder + "\" + $_.Name + "\ts\v3\prd\AppData")
   
    $folder1 = $folder + "\" + $_.Name + "\ts\v3\prd\AppData"
    $folder2 = $folder + "\" + $_.Name + "\ts\v3\prd\upm\UPM_Profile"
    IF (Test-Path $folder2) {
        $a = ((gci -Recurse $folder1 -Force | measure Length -s).sum / 1Gb)
        $b = ((gci -Recurse $folder2 -Force | measure Length -s).sum / 1Gb)
        $c = "{0:N3} GB" -f ($a + $b)
        $output = $_.Name + "," +  $c + "," + $folder
        Write-Host $output
        $infos += $output
        Clear-Variable a,b,c,output
    }
    Clear-Variable folder1, folder2
}
}

$infos | ogv
Continue reading...

Compare ActiveDirectory ACL

Here are some examples and a good description of the ActiveDirectory ACL:

https://blogs.technet.microsoft.com/ashleymcglone/2013/03/25/active-directory-ou-permissions-report-free-powershell-script-download/

Script example to compare ActiveDirectory OU ACL ( Security Groups )

by J.Kühnis 25.11.2019

Import-Module ActiveDirectory


$OU1 = Get-ACl -Path 'AD:\OU=Sales,OU=UserAccounts,DC=FABRIKAM,DC=COM' |  Select-Object -ExpandProperty Access | select IdentityReference

$OU2 = Get-ACl -Path 'AD:\OU=Marketing,OU=UserAccounts,DC=FABRIKAM,DC=COM' |  Select-Object -ExpandProperty Access | select IdentityReference

Compare-Object $OU1 $OU2 -IncludeEqual
Continue reading...

Function Count Ad-GroupMember

#by J.Kühnis 12.11.2019
Function Count-ADGroupMember {
    
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string]$GroupName
    )


    #Get Data From AD-Group
    $groupname
    $groupdsn = (Get-ADGroup $groupname).DistinguishedName
    $group = [adsi]"LDAP://$groupdsn" 
    $groupmemebrs = $group.psbase.invoke("Members") | ForEach-Object { $_.GetType().InvokeMember("SamAccountName", 'GetProperty', $null, $_, $null) }
    $ADGroupMemberCount = $groupmemebrs.count
    return $ADGroupMemberCount
}

example:

Count-ADGroupMember -GroupName AnyGroupNameHere
Continue reading...

PowerCLI: Create VM Engine

Here is an example of how to make automated VM’s with PowerCLI. You can customize the vLAN, DiskType, etc.

If you reuse the Script below, I would recommend to look at the parameters and adapt them to your environment, e.g. network/storage config like the vLan,ESXI Hosts or the adapter type you are using its VMWare.

example:

Create-CustomVirtualMachine -Hostname 'MyServer' -NumCPU 6 -DiskSize 80 -RAMinGB 12 -OS Srv2016

Ensure you are using this script with PowerCLI or with the PowerCLI Module / Assemblys.

The script can also be saved and imported as a module (.psm1).

Import-Module "Path:\to\your\module\share\Create-VM_onFreeDatastore.psm1" -Verbose

Script to create VMs on Hypervisor with enough free ressources

#by J.Kühnis 06.11.2019
    $VmHostArray = @()

    Class VMHost {
        [string]$Name
        [string]$State
        [string]$Parent
        [Array]$DatastoreIdList
        [int]$MemoryTotalGB
        [int]$MemoryUsageGB
        [int]$FreetoUseMemory
        [int]$ReservedVMmemory
        [String]$VMCreationState
        [String]$VMCacheDiskState
        [String]$ESXiHost
        [String]$PVSCollectionState
        [String]$CTXStudioState
        [String]$CTXMaintState
    }

Function Get-VMHostVirtualMachineVMs {
 
    [CmdletBinding()]
    Param(
        #[Parameter(Mandatory=$true)][string[]]$ServerName
        [Parameter(Mandatory = $true)][String] $VMhost,
        [bool]$ExtendedProperties
    )
      
    IF ($ExtendedProperties -eq $true) {
        IF ($global:VMhostsVM = (Get-VMHost -Name $VMhost | Get-VM | select MemoryGB, VMHost, Name)) {
            return $global:VMhostsVM
        }
                
    }
    Else {
        IF ($global:VMhostsVM = ((Get-VMHost -Name $VMhost | Get-VM).Name | sort)) {
            return $global:VMhostsVM
        }
    }
    return $false
}
Function Get-vmHostDataStore {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [String[]]$DatastoreIDList
    )
    $global:DatastoreID = (get-datastore -Id $DatastoreIDList)           
    return  $global:DatastoreID
    
}
  
Function Create-VMEngine {
    
    
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string]$VMName,
        [string]$EsxiHost,
        [string]$Datastore,
        [int]$NumCPUCore,
        [int]$MemoryGB,
        [int]$DiskSize,
        $Vlan,
        $HDFormat,
        [int]$TotalCPU,
        $OS
    )

    write-host "Hypervisor Parameters:" $VMName $EsxiHost $Datastore $MemoryGB $Vlan
    write-host (get-date -f HH:mm:ss)"Start VM Creation $VmName, please wait..."
    If (Get-VM *$VMName*) {
        Write-Host "VM $VMName already exists!!!, Skip this Hostname." -ForegroundColor RED -BackgroundColor Black
        break
    }

    IF ($OS -eq 'Win10') {
        New-VM -Name $VmName -ResourcePool $EsxiHost -Datastore $Datastore -NumCPU $NumCPUCore -MemoryGB $MemoryGB -NetworkName $Vlan -GuestID windows9_64Guest -DiskGB $DiskSize -DiskStorageFormat $HDFormat
    }
    Else {
        New-VM -Name $VmName -ResourcePool $EsxiHost -Datastore $Datastore -NumCPU $NumCPUCore -MemoryGB $MemoryGB -NetworkName $Vlan -GuestID windows9Server64Guest -DiskGB $DiskSize -DiskStorageFormat $HDFormat
    }

    # Set SCSI Controller
    Get-ScsiController -VM $VmName | Set-ScsiController -Type VirtualLsiLogicSAS >$NULL -WarningAction SilentlyContinue
    Write-host "Configure VM $VMName"
       
    # Configure vCPU & Core
    $VmName = Get-VM -name $VmName
    set-vm -vm $VmName -numcpu $TotalCpu -Confirm:$false >$NULL

    # Configure MAC-Address and Adapter Type
    $vm = Get-VM -Name $vmName
    $nic = Get-NetworkAdapter -VM $vm
    $global:spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $devSpec = New-Object VMware.Vim.VirtualDeviceConfigSpec
    $devSpec.Device = $nic.ExtensionData
    $devSpec.operation = "edit"
    $spec.DeviceChange += $devSpec
    $vm.ExtensionData.ReconfigVM($spec)
    Set-NetworkAdapter -NetworkAdapter $nic -Type Vmxnet3 -Confirm:$false >$NULL

    $spec = New-Object VMware.Vim.VirtualMachineConfigSpec
    $spec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::bios
    try {
        $VmName.ExtensionData.ReconfigVM($spec)
    }
    catch {
    }


    #special Parameters
    New-AdvancedSetting -Entity $vm -Name ethernet0.pciSlotNumber -Value 192 -Confirm:$false -Force:$true >$NULL -WarningAction SilentlyContinue
    Write-host "VM Config finished"
    write-host (get-date -f HH:mm:ss)"VM Creation $VmName finished!" -ForegroundColor "Green"

}


Function Create-CustomVirtualMachine {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][string]$Hostname,
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][ValidateRange(1, 16)][int]$NumCPU,
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][ValidateRange(1, 250)][int]$DiskSize,
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][ValidateRange(1, 32)][int]$RAMinGB,
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][ValidateSet('Win10', 'Srv2016')][string]$OS
    )

    Write-host "------------------------"`n"| Start VmWare Section |"`n"------------------------"  -ForegroundColor WHITE
    
    (get-vmhost HYPERVISORFQDN1.f.q.d.n, HYPERVISORFQDN2.f.q.d.n | select Name, State, Parent, DatastoreIdList, MemoryTotalGB, MemoryUsageGB) | % {
        #$FreetoUseMemory = ("{0:N0}" -f $_.MemoryTotalGB) - ("{0:N0}" -f $_.MemoryUsageGB)
        $myhost = New-Object VMhost -Property @{Name = $_.Name; State = $_.State; Parent = $_.Parent; DatastoreIdList = $_.DatastoreIdList; MemoryTotalGB = $_.MemoryTotalGB; MemoryUsageGB = $_.MemoryUsageGB; }
        $VmHostArray += $myhost
    }
    
    Foreach ($VmWareHost in $VmHostArray) {
        $VmWareHost.ReservedVMmemory = ((Get-VMHostVirtualMachineVMs $VmWareHost.Name -ExtendedProperties $true).MemoryGB | Measure-Object -sum).sum
        $VmWareHost.FreetoUseMemory = ("{0:N0}" -f $VmWareHost.MemoryTotalGB) - ("{0:N0}" -f $VmWareHost.ReservedVMmemory);
    }

    $VmHostArray = $VmHostArray | Sort-Object -Property FreetoUseMemory -Descending
    

    #Check RAM Space on ESXI Host with 10GB reserves on Host
    IF (($VmHostArray[0].FreetoUseMemory - 10) -ge ($RAM)) {
        #Check if Disk has 10GB Free Storage
        IF (get-vmHostDataStore -DatastoreIDList $VmHostArray[0].DatastoreIdList) {
            $specVMDatastore = (get-vmHostDataStore -DatastoreIDList $VmHostArray[0].DatastoreIdList | Sort-Object -Property FreeSpaceGB -Descending)
            [int]$a = ("{0:N0}" -f $specVMDatastore[0].FreeSpaceGB).Replace("'", "")
            
            IF ($a -ge ($DiskSize + 10) ) {
                $specVMDatastore = $specVMDatastore[0].Name
    
                #StagingParameters
            
                $VMName = $Hostname
                $EsxiHost = $VmHostArray[0].Name
                $Datastore = $specVMDatastore
                [int]$NumCPUCore = 1
                $Vlan = 'Some_VlanName'
                $HDFormat = "Thin"
                [int]$TotalCPU = $NumCPU

                # Create VM on Host
                Create-VMEngine -VMName $VMName -EsxiHost $EsxiHost -Datastore $Datastore -MemoryGB $RAMinGB -Vlan $Vlan -NumCPUCore $NumCPUCore -HDFormat $HDFormat -TotalCPU $TotalCPU -DiskSize $DiskSize -OS $OS
                Write-host "----------------------"`n"| End VmWare Section |"`n"----------------------"  -ForegroundColor WHITE
            
            }
            Else {
                Write-host $Hostname "| not enough storage on ESXI Host! Action stopped." -ForegroundColor Yellow -BackgroundColor Black
            }
            
        }
        Else {
            Write-host $Hostname "| No Datastore found. Action stopped" -ForegroundColor Yellow -BackgroundColor Black
            
        }
    }
    Else {
        Write-Host $Hostname "| not enough on ESXI Host. Action stopped" -ForegroundColor Yellow -BackgroundColor Black

    }
}
Continue reading...

Jobs on PowerShell

Certain processes can take a long time. As an example, if you want to search a specific event log trough several servers.
To counteract this, Powershell has introduced “Jobs, Workflows and Foreach-Parallel”. It should be well estimated what you can use where best. Personally, I like to rely on jobs when it comes to remote querying / remote invocation.

There is a sensational blogpost by Harry Eagles bout the topic:

https://blogs.technet.microsoft.com/uktechnet/2016/06/20/parallel-processing-with-powershell/

I would like to show a small example of how I use Jobs to read out Eventlogs about several machines. In the example, it is only checked if the corresponding log exists or was written in the last 45 minutes. For 128 servers I needed 30 minutes with this parallel Task. I killed the sequential script after 6 hours …

#by J.Kühnis
$Servers = @(
"serverHostname1"
"serverHostname2"
"serverHostname3"
)

Remove-Job *
$outputArray = @()

Foreach ($Server in $Servers){

Start-Job -Name $Server -ArgumentList $Server{
    param($servername)
    IF(Get-EventLog -LogName System -InstanceId '12306' -After (Get-Date).AddMinutes(-45) -ComputerName $servername -ErrorAction Ignore){
    
    Write-Output"$servername  true"
    }Else{
    Write-Output "$servername  false"
    
    }
} 

}

While (Get-Job -State "Running") {
    Clear-Host
    write-host "Jobs Running"  (Get-Job).count
    Start-Sleep 2
}
Clear-Host
Get-Job
write-host "Jobs completed, getting output"

Get-Job | ForEach-Object {
    $a = Receive-Job $_.Id
    $a
    $outputArray += $a
  
}

#Use the variable $outputArray to get or export the Outputdata
Continue reading...

Join Azure VM into AD and install SCCM Client

Enclosed a script to join the Azure machine into AD and install the SCCM client. This is useful if you want to populate a native Azure VM that was not installed with SCCM. To make the AD-join a service user was assigned in the script, certainly not the most beautiful variant but this can be encrypted by a compiled EXE. This can be done with the following tool: https://gallery.technet.microsoft.com/scriptcenter/PS2EXE-GUI-Convert-e7cb69d5

Of course, network access to the AD and SCCM server must be available.

#by Jeremias Kühnis
#02.10.2019

### Vars Section ###
$SCCM_Server = "SCCMPrimary.f.q.d.n"
$site_code = "Your Site Code -like S01"
$SCCM_MPServer = "ManagementPoint.f.q.d.n"
$LocalSource_Path = "$env:SystemDrive\temp\"
$SCCM_ClientInstaller = "$LocalSource_Path" + "Client\ccmsetup.exe"
$SCCM_Repo = "\\$SCCM_Server\SMS_***YOURSITECODE***\Client"
$time = ([datetime]::now).tostring("dd_MM_yyyy_HH-mm-ss")
$ScriptFilename = Split-Path $MyInvocation.MyCommand.Definition -leaf
$LogfileName = $LocalSource_Path + 'Azure-SCCMInstaller' + '__' + $time + '.log'
$fqdn = 'someFQDN'
$JoinADUser = $fqdn + '\ServiceAccountjoinAD'
$JoinADUserPw = 'ServiceAccountPW'
$ADOU_NewAzuewDevice = "OU=Germany,DC=contoso,DC=com"



### External Functions ###
#by   https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0 


function Write-Log { 
    [CmdletBinding()] 
    Param 
    ( 
        [Parameter(Mandatory = $true, 
            ValueFromPipelineByPropertyName = $true)] 
        [ValidateNotNullOrEmpty()] 
        [Alias("LogContent")] 
        [string]$Message, 
 
        [Parameter(Mandatory = $false)] 
        [Alias('LogPath')] 
        [string]$Path = 'C:\Logs\PowerShellLog.log', 
         
        [Parameter(Mandatory = $false)] 
        [ValidateSet("Error", "Warn", "Info")] 
        [string]$Level = "Info", 
         
        [Parameter(Mandatory = $false)] 
        [switch]$NoClobber 
    ) 
 
    Begin { 
        # Set VerbosePreference to Continue so that verbose messages are displayed. 
        $VerbosePreference = 'Continue' 
    } 
    Process { 
         
        # If the file already exists and NoClobber was specified, do not write to the log. 
        if ((Test-Path $Path) -AND $NoClobber) { 
            Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name." 
            Return 
        } 
 
        # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path. 
        elseif (!(Test-Path $Path)) { 
            Write-Verbose "Creating $Path." 
            $NewLogFile = New-Item $Path -Force -ItemType File 
        } 
 
        else { 
            # Nothing to see here yet. 
        } 
 
        # Format Date for our Log File 
        $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" 
 
        # Write message to error, warning, or verbose pipeline and specify $LevelText 
        switch ($Level) { 
            'Error' { 
                Write-Error $Message 
                $LevelText = 'ERROR:' 
            } 
            'Warn' { 
                Write-Warning $Message 
                $LevelText = 'WARNING:' 
            } 
            'Info' { 
                Write-Verbose $Message 
                $LevelText = 'INFO:' 
            } 
        } 
         
        # Write log entry to $Path 
        "$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append 
    } 
    End { 
    } 
}

### own Functions ###

function Mount-SCCMShare {
    $DriveName = 'SCCMRepo'
    If (!(Get-PSDrive -name $DriveName -ErrorAction SilentlyContinue)) {
        try {
            New-PSDrive -name $DriveName -PSProvider "FileSystem" -Root  $SCCM_Repo -Credential $credential -Scope Script
        }
        catch {
            Write-Log -Path $LogfileName -Level Error -Message "Can not Mount SCCM Share $SCCM_Repo"
            Exit
        }

    
    }
}

Function SCCMClientInstaller {

    ###########################################################################
    ##          SCCM Client Health check and Troubleshooting Script					
    ##          Author: Lokesh Agarwal
    ##          Date: 23-08-2017
    ##	        Input:- SCCM Client path, MP Address, Site Code
    ##	     Edited: Jeremias Kühnis 27.09.2019 -> Added/Modifying some Code and add some Log Warning
    ###########################################################################




    ############################### Main Code ####################################
    $machinename = hostname


    ############################### Check if WMI is working #######################
    if ((Get-WmiObject -Namespace root\ccm -Class SMS_Client -ErrorAction SilentlyContinue) -and (Get-WmiObject -Namespace root\ccm -Class SMS_Client -ErrorAction SilentlyContinue)) {
        Write-Log -Path $LogfileName -Level Info -Message "WMI is OK"
        $WMI_Status = "Working"
    }
    else {
        Write-Log -Path $LogfileName -Level Warn -Message "Try to Repair WMI"
        Stop-Service -Force winmgmt -ErrorAction SilentlyContinue
        cd  C:\Windows\System32\Wbem\
        Remove-item C:\Windows\System32\Wbem\Repository.old -Recurse -Force -ErrorAction SilentlyContinue -Confirm:$false
        rename-Item Repository Repository.old -ErrorAction SilentlyContinue -Confirm:$false
        Start-Service winmgmt 
    }

    ############################# Check if SCCM Client is installed ##################
    If (Get-Service -Name CcmExec -ErrorAction SilentlyContinue) {
        $Client_Status = "Yes"
        Write-Log -Path $LogfileName -Level Info -Message "SCCM Status OK, Client is installed"
	
        ########### Check if services are running ################################
        $CcmExec_Status = Get-Service -Name CcmExec | % { $_.status }
        $BITS_Status = Get-Service -Name BITS | % { $_.status }
        $wuauserv_Status = Get-Service -Name wuauserv | % { $_.status }
        $Winmgmt_Status = Get-Service -Name Winmgmt | % { $_.status }
        $RRegistry_Status = Get-Service -Name RemoteRegistry | % { $_.status }


        if ($CcmExec_Status -eq "Stopped") {
            Write-Log -Path $LogfileName -Level Warn -message "Try to start Service $CcmExec_Status"
            Get-Service -Name CcmExec | Start-Service
        }

        if ($BITS_Status -eq "Stopped") {
            Write-Log -Path $LogfileName -Level Warn -message "Try to start Service $BITS_Status"
            Get-Service -Name BITS | Start-Service
        }

        if ($wuauserv_Status -eq "Stopped") {
            Write-Log -Path $LogfileName -Level Warn -message "Try to start Service $wuauserv_Status"
            Get-Service -Name wuauserv | Start-Service
        }

        if ($Winmgmt_Status -eq "Stopped") {
            Write-Log -Path $LogfileName -Level Warn -message "Try to start Service $Winmgmt_Status"
            Get-Service -Name Winmgmt | Start-Service
        }

	
	
        $MachinePolicyRetrievalEvaluation = "{00000000-0000-0000-0000-000000000021}"
        $SoftwareUpdatesScan = "{00000000-0000-0000-0000-000000000113}"
        $SoftwareUpdatesDeployment = "{00000000-0000-0000-0000-000000000108}"

        #################### check if Scan cycles are working ###################
        $machine_status = Invoke-WmiMethod -Namespace root\ccm -Class sms_client -Name TriggerSchedule $MachinePolicyRetrievalEvaluation
        $software_status = Invoke-WmiMethod -Namespace root\ccm -Class sms_client -Name TriggerSchedule $SoftwareUpdatesScan
        $softwaredeploy_Status = Invoke-WmiMethod -Namespace root\ccm -Class sms_client -Name TriggerSchedule $SoftwareUpdatesDeployment

        if ($machine_status -and $software_status -and $softwaredeploy_Status) {
            $machine_Rstatus = "Successful"
            Write-Log -Path $LogfileName -Level Info -message "Scan cycles are working $machine_Rstatus"
        }
        else {
            $SMSCli = [wmiclass] "root\ccm:sms_client"
            Write-Log -Path $LogfileName -Level Warn -message "Scan cycles are not working, try to repair SMSCLI-Client"
            $repair = $SMSCli.RepairClient()
            
        }

    }
    else {
        ############## Install SCCM Client ###############################
        Write-Log -Path $LogfileName -Level Info -message "Missing SCCM Client, try to start installation"
        &$SCCM_ClientInstaller /mp:$SCCM_MPServer /logon SMSSITECODE=$site_code
        Start-Sleep 5
        DO {
            $ProcessesFound = (Get-Process -name ccmsetup -ErrorAction SilentlyContinue)
            If (($ProcessesFound) -and ($counter -le "90")) {
                Start-Sleep 10
                $counter++
                Write-Host "Still running: $($ProcessesFound)  $counter"
            }
            Else {
                IF ($counter -gt "90") {
                    Write-Log -Path $LogfileName -Level Error -message "Not OK: Try to kill running Process while InstallationProcess is taking more than 15 Minutes"
                    Get-Process ccmsetup | Stop-Process -Force
                    Exit
                }
                Else {
                    Write-Log -Path $LogfileName -Level Info -message "OK:Process ended by SCCM installer."
                }
            }
        } Until (!$ProcessesFound)

    }

    ####################################################################################################
}

function New-folder {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true)][string]$folderpath
    )

    If (!(Test-path $folderpath)) {
        New-Item $folderpath -ItemType Directory
    }
}   

function VerifyPrerequisits {
    #Check Powershell Version
    $psversion = $PSVersionTable.PSVersion.Major
    IF ($psversion -ge "5") {
        Write-Log -Path $LogfileName -Level Info -Message "Powershell Version is OK – $psversion"
    }
    Else {
        Write-Log -Path $LogfileName -Level Error -Message "Missing PowerShell or installed Version is to low  – $psversion "
        $Errorcouonter = "1"
    }
    
    #Check .Net FrameWork Version
    $DotNetVersion = (Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\' | Get-ItemPropertyValue -Name Version)
    IF (Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\' | Get-ItemPropertyValue -Name Release | Foreach-Object { $_ -ge 461814 }) {
        Write-Log -Path $LogfileName -Level Info -Message ".NetVersion ist OK – $DotNetVersion"
    }
    else {
        Write-Log -Path $LogfileName -Level Error -Message "Missing .NetFramework or installed Version is to low  – $DotNetVersion "
        $Errorcouonter = "1"
    }

    #Verify SourcePath
    IF (!(Test-Path $SCCM_Repo) ) {
        Write-Log -Path $LogfileName -Level Error -Message "Can not find SCCM installer Path: $SCCM_Repo"
        $Errorcouonter = "1"
    }

    ##Last Part
    If ($Errorcouonter -eq "1") {
        Write-Log -Path $LogfileName -Level Warn -Message "Installation is not performed because the checked prerequisites are Wrong/Missing. See further up in the log."
        exit
    }
    Else {
        Write-Log -Path $LogfileName -Level Info -Message "Prerequisits are Okay, try to lead trough installation"
    }


}

Function Remove-InstallerLocation {
    $removepaths = @(
        "$LocalSource_Path\Client"
    )
    foreach ($ToDelPath in $removepaths) {
        Remove-Item $ToDelPath -Recurse -Force -ErrorAction SilentlyContinue
    }
}

###################
### Main Script ###
###################
$password = $JoinADUserPw | ConvertTo-SecureString -asPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($JoinADUser, $password)

### Create C:\Temp Folder, if not Exists for logs ###
New-folder -folderpath $LocalSource_Path


### Join AD-Section ###
#Need to Add credentials and start Job for OU path
$Error.Clear()
Try {
    Add-Computer -DomainName $fqdn -Credential $credential -OUPath $ADOU_NewAzuewDevice -Force -ErrorAction Stop
    
    
}
catch [System.Net.WebException], [System.Exception] {
    Write-Log -Path $LogfileName -Level Error -Message "Failed @ Ad-join Part...maybe ADAccount already exists."
    Write-Log -Path $LogfileName -Level Error -Message $Error
    Exit
}

Mount-SCCMShare
VerifyPrerequisits


### Install SCCM-Client Section ###
Write-Log -Path $LogfileName -Level Info -message "Start-SCCM Repair/ Install Process..."
Copy-Item $SCCM_Repo -Recurse -Destination $LocalSource_Path -Force
SCCMClientInstaller
Write-Log -Path $LogfileName -Level Info -message "End Section: 'Start-SCCM Repair/ Install Process...'"
Write-Log -Path $LogfileName -Level Info -message "Finished all Jobs, if there are any Problems Check if Computer is joined in AD and Check the Execution Policy. Also Check de Install status of SCCM Client."
Write-Log -Path $LogfileName -Level Info -message "Try to clean Up local install Files"
Start-Sleep 3
Remove-InstallerLocation
Write-Log -Path $LogfileName -Level Info -message "Successfully finish..."

#reboot while AD-Join
shutdown -r -f -t 60
Continue reading...