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”
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:
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 …
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
The following print screen shows the parameters of the Windows Update Standalone Installer.
local installation
As far as I know, the patch cannot be installed with native powershell, means we have to address the wusa.exe in powershell. Of course Powershell is a nice way to automate the whole process.
In the following example, the patch is copied from a UNC share and installed locally.
I was not able to run wusa.exe remotely, any tests with workflows, Remotepowershell (Invoke-Command CMDLeet) failed. Even triggering a localy copied batch file caused problems. The wusa.exe process was executed with the correct parameters but aborted after a few seconds. Even with an Invoke-Command and the parameter -Wait it didn’t work.
Probably it’s because you intervene in the system and perform an unauthorized action.
With the PSExec.exe it is possible to start the process remotely.
The principle is very simple, you have to copy the patch to the appropriate target computer. Then PSExec starts a remote process on the target computer and executes the wusa.exe with the corresponding parameters. The wusae.exe must point to the path where the patch was copied.
#16.05.2019 by JKU
$Hotfix = 'kb-12345.msu'
$HostName = 'F.Q.D.N'
$DestinationPath = "\\$Hostname\c$\Temp\"
Copy-Item C:\temp\$Hotfix -Destination $DestinationPath
#Start Process with PSExec.exe
& C:\Temp\PsExec.exe -accepteula -s \\$HostName wusa C:\Temp\$Hotfix /quiet /norestart
And so you can distribute a patch for multiple computers with a simple iteration.
It is especially useful if you have to work with a driveletter in the code or if the share has to be mapped in the Scirpt and has to be removed at the end of the script.
Eclipse Java EE IDE for Web Developers – Version: Oxygen.1a Release (4.7.1a)
Eclipse Java EE IDE for Web Developers – Version: 2019-03 (4.11.0)
Basics
There is a nice detailed blog article which describes how to install the Eclipse plugins. The description is for Linux, it works exactly the same on Windows. The syntax is shown with an example and it is explained how to get to the repository information.
The plugins cannot be installed in parallel mode, at least this didn’t work for me.
Prerequisits will not be automaticly installed.
The automated solution:
First you have to manually try out the commands to get the order and dependencies/prerequsits right.
The loop in the script will sequentially process the installations…if a plugin installation takes more than 5min the Eclipse process will stop and the next plugin will be installed.
Don’t forget ro Run Powershell in elevated mode.
#09.04.2019 by J.Kühnis installation Eclipse Plugins
#Install Eclipse Addons from Web-repository
[array]$InstallArguments = @(
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository https://tools.hana.ondemand.com/oxygen/ -installIU com.sap.it.ide.adapter.sdk.feature.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository http://download.eclipse.org/releases/oxygen -installIU org.eclipse.jgit.http.apache.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository https://tools.hana.ondemand.com/oxygen/ -installIU com.sap.it.commons.command.http.apacheclient'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository https://tools.hana.ondemand.com/oxygen/ -installIU com.sap.it.op.cockpit.ui.feature.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository https://tools.hana.ondemand.com/oxygen/ -installIU com.sap.core.tools.eclipse.help.feature.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository http://download.eclipse.org/releases/oxygen -installIU org.eclipse.libra.facet'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository http://download.eclipse.org/releases/oxygen -installIU org.eclipse.libra.facet.feature.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository http://download.eclipse.org/releases/oxygen -installIU org.eclipse.jpt.jpadiagrameditor.feature.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository https://tools.hana.ondemand.com/oxygen/ -installIU com.sap.core.tools.eclipse.server.feature.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository https://tools.hana.ondemand.com/oxygen/ -installIU com.sap.jvm.profiling.feature.group'
'&"C:\Program Files\eclipse\jee-latest-released\eclipse\eclipse.exe" -application org.eclipse.equinox.p2.director -repository https://tools.hana.ondemand.com/oxygen/ -installIU com.sap.idm.dev-ui-feature.feature.group'
)
Foreach($argument in $InstallArguments){
#Install Addins
Write-Host $argument -ForegroundColor Yellow
$argument | Invoke-Expression
Start-Sleep 5
#Check if Service is Running and wait | Exit after 300Seconds
[int]$counter = 0
Do {
$ProcessesFound = get-process -Name *eclipse*
If (($ProcessesFound) -and ($counter -le "30")) {
Start-Sleep 10
$counter++
Write-Host "Still running: $($ProcessesFound) $counter"
}Else{
IF ($counter -gt "30"){
Write-Host "Try to kill running Process while Process is taking more than 5 Minutes" -ForegroundColor DarkYellow -BackgroundColor Black
}Else{
Write-Host "Process ended by installer" -ForegroundColor Green
}
Get-Process *eclipse* | Stop-Process -Force
}
} Until (!$ProcessesFound)
Clear-Variable -Name counter -Scope Global
Start-Sleep 2
}