├── .gitignore ├── Active Directory ├── GPO │ ├── GPO-BackupAndRestore.ps1 │ ├── GPO-CompareReports.ps1 │ └── GPO-ToolSet.ps1 └── User │ ├── ChangeUserPasswords.ps1 │ ├── RandomDomainUserBulkCreate.ps1 │ ├── UserBulkCreate.ps1 │ └── sample_aduser.csv ├── Azure ├── AzureUploadFile.ps1 ├── DeployTemplate.ps1 ├── Function_TK_AzStorageAccountName.ps1 ├── TK_CreateVPN.ps1 ├── VerifyReachability.ps1 ├── Windows Virtual Desktop │ ├── TK_CopyVHDToBlob.ps1 │ ├── TK_RemoveWVDHostPool.ps1 │ ├── WVDPreparation.config.ini │ └── WVDPreparation.ps1 └── installChoco.ps1 ├── CVE-2021-1675 ├── FolderProperties.png ├── RunningScript.png ├── TK_PrintNightMare.ps1 └── readme.md ├── Citrix ├── CitrixCloud │ ├── CitrixCloudAutomation.ps1 │ └── Install_RemotePoshSDK.ps1 ├── FAS │ ├── CleanUpFASCerts_v1.0.ps1 │ └── FASConfig.ps1 ├── SessionRecording │ └── GenRandomQMID.ps1 ├── Sharefile │ └── DeleteDisabledSFUser.ps1 └── XenDesktop │ ├── CVAD Database Migration.md │ ├── CVAD-Site-Database-Role-assignment-01.png │ ├── CVAD-Site-Database-Role-assignment-02.png │ ├── InstallHPLJ2800PSDriver.ps1 │ ├── InstallHPLJ2800PSDriver_signed.ps1 │ ├── TrustLicenseServerCertificate.ps1 │ └── XenDesktop7MoveDatabase.ps1 ├── DHCP └── DHCPReservations.ps1 ├── Function Library ├── Function_Convert-WindowsImage.ps1 ├── Function_MW-CreateProfileFolder.ps1 ├── Function_MW-ShowUEVPKGXRegistry.ps1 ├── Function_StartCountdown.ps1 ├── Function_TK_AzStorageAccountName.ps1 ├── Function_TK_CleanupDirectory.ps1 ├── Function_TK_CompressDirectory.ps1 ├── Function_TK_Confirm-DomainAdmin.ps1 ├── Function_TK_CopyAzureVHDToAzureBlob.ps1 ├── Function_TK_CreateDirectory.ps1 ├── Function_TK_CreateFolderFromCSV.ps1 ├── Function_TK_DeleteDirectory.ps1 ├── Function_TK_DeleteFile.ps1 ├── Function_TK_Get-CurrentWeek.ps1 ├── Function_TK_IsAdmin.ps1 ├── Function_TK_LoadModule.ps1 ├── Function_TK_ReadFromINI.ps1 ├── Function_TK_RemoveWVDHostPool.ps1 ├── Function_TK_SendMail.ps1 ├── Function_TK_WriteLog.ps1 ├── Function_TK_WriteToEventLog.ps1 ├── Function_TK_check-even-odd.ps1 ├── ModifyProxySettings.ps1 └── _TemplateForYourOwnFunctions.ps1 ├── Github ├── TK_DownloadFilesFromGithubRepo.ps1 └── TK_Invoke-Gist.ps1 ├── LICENSE ├── LoginAM ├── AM-Copy-XenServerVMTemplate.ps1 ├── AM-JoinXenServerVMsToDomain.ps1 ├── AMDocGen_Anton.ps1 ├── AMPreparation.ps1 ├── AddComputerToCollection.ps1 ├── AllowSQLFirewallRule.ps1 ├── Copy-XenServerVMTemplate.ps1 ├── CopyCertfilesToNetScaler.ps1 ├── CreateMasterDevice.ps1 ├── CreatePVSvDisk.ps1 ├── CreateStoresOnStorefront_v3.ps1 ├── DisableCheckCertificate.ps1 ├── FSLogix_EnableProfileDisk.ps1 ├── FirewallRule-Inbound_SQL.ps1 ├── GET_AM_Inventory.ps1 ├── GetHostnameWithMACAddressFromDHCP.ps1 ├── GetXenVMNameLabelbyMAC_new.ps1 ├── GetXenVMNameLabelbyMAC_signed.ps1 ├── InstallXSTools.ps1 ├── InstallXenServerPSSnapIn.ps1 ├── OnlineVerification.ps1 ├── OnlineVerificationSmall.ps1 ├── PVSCreateOrJoinV10.ps1 ├── PrepareAM.ps1 ├── RegisterGatewayInStorefront.ps1 ├── RegisterPVS-McliPSSnapIn.ps1 ├── TrustCertificate.ps1 ├── TrustXMLPort.ps1 └── VDIOptimizationV111.ps1 ├── LoginVSI └── SFLauncher.ps1 ├── Monitoring └── QAReport_Final.ps1 ├── NetScaler └── ConfigureNetScalerNITRO-v1.ps1 ├── Parallels └── parallels_desktop_tools.sh ├── README.md ├── URL shortener └── longurl.ps1 ├── User Profiles ├── CleanUpUserProfile.ps1 ├── Get-FolderSizes.ps1 ├── TK_CreateTestUserFromCSV.ps1 ├── TK_CreateUserFolderFromCSV.ps1 ├── TK_ReadFromINI.ps1 └── testuser.csv ├── Windows ├── InstallVcRedist.ps1 ├── List-ProcessesExtended.ps1 ├── Update-PolicyDefinitions.ps1 └── WindowsUpdate │ ├── README.md │ ├── images │ ├── windows-updates1.png │ ├── windows-updates2.png │ └── windows-updates3.png │ └── windows-updates.ps1 ├── WorkingWithFiles └── TK_Copy-WithProgress.ps1 ├── _config.yml └── terraform ├── Install_PS_Core.ps1 ├── Install_Preparation_OpenSSH.ps1 └── optimize-powershell-assemblies.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | *.old 2 | .DS_Store 3 | *.txt 4 | -------------------------------------------------------------------------------- /Active Directory/GPO/GPO-BackupAndRestore.ps1: -------------------------------------------------------------------------------- 1 | <<<<<<< HEAD 2 | <# 3 | .SYNOPSIS 4 | GPO-BackupAndRestore.ps1 5 | .DESCRIPTION 6 | Lightweight Script for Ex- and Importing GPO's for e.g. GPO migration 7 | .PARAMETER Mode 8 | Export 9 | Import 10 | .EXAMPLE 11 | GPO-BackupAndRestore.ps1 -Mode Export 12 | GPO-BackupAndRestore.ps1 -Mode Import 13 | .LINK 14 | https://github.com/thomaskrampe/PowerShell 15 | .NOTES 16 | Author : Thomas Krampe | t.krampe@loginconsultants.de 17 | Version : 1.0 18 | Creation date : 26.07.2018 | v0.1 | Initial script 19 | : 30.07.2018 | v1.0 | Release to GitHub 20 | Last change : 02.08.2018 | v1.1 | Provide Domain informations 21 | #> 22 | 23 | Param( 24 | [Parameter(Mandatory=$True)] 25 | [ValidateSet("Export", "Import")] 26 | [string]$Mode 27 | ) 28 | 29 | # Change the variables to your own needs 30 | import-module grouppolicy 31 | $ExportFolder="c:\_GPO-EXPORT\" 32 | $Importfolder="c:\_GPO-EXPORT\" 33 | 34 | # For importing the GPO's to a new domain you can specify either a prefix or a suffix 35 | $Prefix="New_" 36 | $Suffix="_001" 37 | 38 | # Domaininformation 39 | $QDomain = "ad1.local" 40 | $QDomainC = "dc01"+$QDomain 41 | $TDomain = "ad2.local" 42 | $TDOmainC = "dc01"+$TDomain 43 | 44 | 45 | function Export-GPOs { 46 | $GPO=Get-GPO –All 47 | foreach ($Entry in $GPO) { 48 | $Path=$ExportFolder+$entry.Displayname 49 | New-Item -ItemType directory -Path $Path 50 | Backup-GPO -Guid $Entry.id -Path $Path -Domain $QDomain -Server $QDomainC 51 | } 52 | } 53 | 54 | function Import-GPOs { 55 | $Folder=Get-childItem -Path $Importfolder -Exclude *.ps1 56 | foreach ($Entry in $Folder) { 57 | $Name=$Prefix+$Entry.Name+$Suffix 58 | $Path=$Importfolder+$entry.Name 59 | $ID=Get-ChildItem -Path $Path 60 | New-GPO -Name $Name -Domain $TDomain -Server $TDomainC 61 | Import-GPO -TargetName $Name -Path $Path -BackupId $ID.Name .$TDomain -Server $TDomainC 62 | } 63 | } 64 | 65 | Clear-Host 66 | 67 | switch ($Mode){ 68 | "Export" {Export-GPOs; break} 69 | "Import" {Import-GPOs; break} 70 | } 71 | exit 0 72 | ======= 73 | <# 74 | .SYNOPSIS 75 | GPO-BackupAndRestore.ps1 76 | 77 | .DESCRIPTION 78 | Lightweight Script for Ex- and Importing GPO's for e.g. GPO migration 79 | 80 | .PARAMETER Mode 81 | Export 82 | Import 83 | 84 | .EXAMPLE 85 | GPO-BackupAndRestore.ps1 -Mode Export 86 | GPO-BackupAndRestore.ps1 -Mode Import 87 | 88 | .LINK 89 | 90 | 91 | .NOTES 92 | Author : Thomas Krampe | t.krampe@loginconsultants.de 93 | Version : 1.0 94 | Creation date : 26.07.2018 | v0.1 | Initial script 95 | : 30.07.2018 | v1.0 | Release to GitHub 96 | : 02.08.2018 | v1.1 | Provide Domain informations 97 | Last change : 13.08.2018 | v1.2 | Customizations 98 | 99 | IMPORTANT NOTICE 100 | ---------------- 101 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 102 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 103 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 104 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 105 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 106 | OF SUCH DAMAGES IN ADVANCE. 107 | 108 | #> 109 | 110 | 111 | 112 | Param( 113 | [Parameter(Mandatory=$True)] 114 | [ValidateSet("Export", "Import")] 115 | [string]$Mode 116 | ) 117 | 118 | # Change the variables to your own need 119 | import-module grouppolicy 120 | $ExportFolder="c:\_GPO-EXPORT\" # Export GPO Objects to ... 121 | $Importfolder="c:\_GPO-EXPORT\" # Import GPO Objects from ... 122 | 123 | # For importing the GPO's to a new domain you can specify either a prefix or a suffix 124 | $Prefix="" 125 | $Suffix="" 126 | 127 | # Domaininformation 128 | $QDomain = "sourcedomain.local" # Source Domain 129 | $QDomainC = "sourcedc."+$QDomain # Source Domain Controller 130 | $TDomain = "targetdomain.local" # Target Domain 131 | $TDOmainC = "targetdc."+$TDomain # Target Domain Controller 132 | 133 | 134 | function Export-GPOs { 135 | $GPO=Get-GPO -All 136 | foreach ($Entry in $GPO) { 137 | $Path=$ExportFolder+$entry.Displayname 138 | New-Item -ItemType directory -Path $Path 139 | Backup-GPO -Guid $Entry.id -Path $Path -Domain $QDomain -Server $QDomainC 140 | } 141 | } 142 | 143 | function Import-GPOs { 144 | $Folder=Get-childItem -Path $Importfolder -Exclude *.ps1 145 | foreach ($Entry in $Folder) { 146 | $Name=$Prefix+$Entry.Name+$Suffix 147 | $Path=$Importfolder+$entry.Name 148 | $ID=Get-ChildItem -Path $Path 149 | New-GPO -Name $Name -Domain $TDomain -Server $TDomainC 150 | Import-GPO -TargetName $Name -Path $Path -BackupId $ID.Name .$TDomain -Server $TDomainC 151 | } 152 | } 153 | 154 | cls 155 | 156 | switch ($Mode){ 157 | "Export" {Export-GPOs; break} 158 | "Import" {Import-GPOs; break} 159 | } 160 | exit 0 161 | 162 | >>>>>>> 4bd8c05cf14a5710b13b8420d01cb64f08ef60cb 163 | -------------------------------------------------------------------------------- /Active Directory/GPO/GPO-CompareReports.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Create GPO XML Reports and compare them 4 | 5 | .DESCRIPTION 6 | 7 | .PARAMETER Domain 8 | Domain FQDN 9 | 10 | .PARAMETER DC 11 | Hostname of the Domain Controller 12 | 13 | .PARAMETER GPONames 14 | GPO names seperated by comma 15 | 16 | .PARAMETER Folder 17 | Target folder for Reports 18 | 19 | .PARAMETER User / Computer 20 | User or Computer part of the GPO 21 | 22 | .EXAMPLE 23 | GPO-CompraeReports.ps1 -Domain "domain.local" -DC "domaincontroller" -GPONames "Policy1,Policy2" -Folder "C:\TEMP" -Computer 24 | 25 | or with pre-filled values 26 | 27 | GPO-CompareReports.ps1 -User | GPO-CompareReports.ps1 -computer 28 | 29 | .LINK 30 | 31 | .NOTES 32 | Author : Thomas Krampe | t.krampe@loginconsultants.de 33 | Version : 1.0 34 | Creation date : 14.08.2018 | v1.0 | Initial script 35 | Last change : | | 36 | 37 | IMPORTANT NOTICE 38 | ---------------- 39 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 40 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 41 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 42 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 43 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 44 | OF SUCH DAMAGES IN ADVANCE. 45 | 46 | #> 47 | 48 | # Script parameters 49 | Param( 50 | [string]$Domain = "domain.local", 51 | [string]$DC = "domaincontroller", 52 | [string]$GPONames = "GPO1,GPO2", 53 | [string]$Folder = "C:\_GPO_COMPARE", 54 | [switch]$User, 55 | [switch]$Computer 56 | ) 57 | 58 | # Functions 59 | Function GPOReport 60 | { 61 | Param( 62 | [string[]]$GPONames, 63 | [string]$Domain, 64 | [string]$DC, 65 | [string]$Folder 66 | ) 67 | 68 | $GPOReport = $null 69 | 70 | ForEach($GPOName in $GPONames) 71 | { 72 | $Path = Join-Path -Path $Folder -ChildPath "$GPOName.xml" 73 | (Get-GPO -Name $GPOName -Domain $Domain -Server $DC).GenerateReportToFile("xml",$Path) 74 | [array]$GPOReport + $Path 75 | } 76 | Return $GPOReport 77 | } 78 | 79 | Function GPOCompare 80 | { 81 | Param( 82 | [string[]]$GPOReport,$User, $Computer 83 | ) 84 | 85 | [xml]$xml1 = Get-Content -Path $GpoReport[0] 86 | [xml]$xml2 = Get-Content -Path $GpoReport[1] 87 | 88 | $GPOComputerNodes1 = $xml1.GPO.Computer.ExtensionData.Extension.ChildNodes | Select-Object name, state 89 | $GPOComputerNodes2 = $xml2.GPO.Computer.ExtensionData.Extension.ChildNodes | Select-Object name, state 90 | $GPOUserNodes1 = $xml1.GPO.User.ExtensionData.Extension.ChildNodes | Select-Object name, state 91 | $GPOUserNodes2 = $xml2.GPO.User.ExtensionData.Extension.ChildNodes | Select-Object name, state 92 | 93 | if ($computer){ 94 | Try { 95 | Write-Host "Comparing Computer GPO's $($GpoReport[0]) with $($GpoReport[1]) `r`n" 96 | Compare-Object -ReferenceObject $GPOComputerNodes1 -DifferenceObject $GPOComputerNodes2 -IncludeEqual -Property name 97 | } 98 | 99 | Catch [System.Exception] { 100 | If ($GPOComputerNodes1) { 101 | Write-Host "Computer GPO $($GpoReport[0]) settings `r`f" 102 | Write-Host $GPOComputerNodes1 103 | } 104 | else { 105 | Write-Host "Computer GPO $($GpoReport[0]) not set" -ForegroundColor Yellow 106 | Write-Host $GPOComputerNodes2 107 | } 108 | 109 | If ($GPOComputerNodes2) { 110 | Write-Host "Computer GPO $($GpoReport[1]) settings `r`f" 111 | } 112 | else { 113 | Write-Host "Computer GPO $($GpoReport[1]) not set" -ForegroundColor Yellow 114 | } 115 | } 116 | } 117 | 118 | if ($user){ 119 | Try { 120 | Write-Host "Comparing Computer GPO's $($GpoReport[0]) with $($GpoReport[1]) `r`n" 121 | Compare-Object -ReferenceObject $GPOComputerNodes1 -DifferenceObject $GPOComputerNodes2 -IncludeEqual -Property name 122 | } 123 | 124 | Catch [System.Exception] { 125 | If ($GPOUserNodes1) { 126 | Write-Host "User GPO $($GpoReport[0]) settings `r`f" 127 | Write-Host $GPOUserNodes1 128 | } 129 | else { 130 | Write-Host "User GPO $($GpoReport[0]) not set" -ForegroundColor Yellow 131 | } 132 | 133 | If ($GPOUserNodes2) { 134 | Write-Host "User GPO $($GpoReport[1]) settings `r`f" 135 | Write-Host $GPOUserNodes2 136 | } 137 | else { 138 | Write-Host "User GPO $($GpoReport[1]) not set" -ForegroundColor Yellow 139 | } 140 | } 141 | } 142 | } 143 | 144 | # Main script 145 | If (-not ($user -or $computer)) {Write-Host "Please specify either -user or -computer when running this script." -ForegroundColor Yellow; exit} 146 | 147 | Write-Verbose "Importing Module Group Policy" 148 | Import-Module GroupPolicy 149 | 150 | $GPOReport = GPOReport -GPONames $GPONames.split(",") -DC $DC -Domain $Domain -Folder $Folder 151 | GPOCompare -GPOReport $GPOReport -User $User -Computer $Computer 152 | 153 | Exit -------------------------------------------------------------------------------- /Active Directory/User/ChangeUserPasswords.ps1: -------------------------------------------------------------------------------- 1 | # Import ActiveDirectory module 2 | Import-module ActiveDirectory 3 | 4 | # Grab list of users from a text file. 5 | $ListOfUsers = Get-Content C:\Temp\userlist.txt 6 | foreach ($user in $ListOfUsers) { 7 | 8 | #Generate a 15-character random password. 9 | $Password = -join ((48..57) + (65..90) + (97..122) + 36 + 33 | Get-Random -Count 15 | ForEach-Object { [char]$_ }) 10 | 11 | #Convert the password to secure string. 12 | $NewPwd = ConvertTo-SecureString $Password -AsPlainText -Force 13 | 14 | #Assign the new password to the user. 15 | Set-ADAccountPassword $user -NewPassword $NewPwd -Reset 16 | 17 | #Force user to change password at next logon. 18 | # Set-ADUser -Identity $user -ChangePasswordAtLogon $true 19 | 20 | #Display userid and new password on the console. 21 | Write-Host $user, $Password 22 | } 23 | -------------------------------------------------------------------------------- /Active Directory/User/sample_aduser.csv: -------------------------------------------------------------------------------- 1 | lastname,firstname 2 | Biedermann,Sven 3 | Blume,Olaf 4 | Bremer,Thomas 5 | Schmidt,Martin 6 | -------------------------------------------------------------------------------- /Azure/AzureUploadFile.ps1: -------------------------------------------------------------------------------- 1 | # Upload Files to Azure Storage Container 2 | Function TK_UploadFilesToAzure { 3 | Param ( 4 | [Parameter(Mandatory)] 5 | [string]$StorageAccountName, 6 | [Parameter(Mandatory)] 7 | [string]$StorageAccountKey, 8 | [Parameter(Mandatory)] 9 | [string]$file 10 | ) 11 | 12 | # Login to Azure RM 13 | Login-AzureRMAccount 14 | 15 | # Prepare Variables 16 | $StorageContext = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey 17 | $StorageContainer = Get-AzureStorageContainer -Context $StorageContext 18 | 19 | # Upload File 20 | Set-AzureStorageBlobContent -File $file -Container $StorageContainer.name -BlobType "Block" -Context $StorageContext -Verbose 21 | 22 | } 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Azure/DeployTemplate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Deploys a template to Azure 4 | 5 | .DESCRIPTION 6 | Deploys an Azure Resource Manager template 7 | #> 8 | 9 | param ( 10 | [Parameter(Mandatory)] 11 | #The subscription id where the template will be deployed. 12 | [string]$SubscriptionId, 13 | 14 | [Parameter(Mandatory)] 15 | #The resource group where the template will be deployed. Can be the name of an existing or a new resource group. 16 | [string]$ResourceGroupName, 17 | 18 | #Optional, a resource group location. If specified, will try to create a new resource group in this location. If not specified, assumes resource group is existing. 19 | [string]$ResourceGroupLocation, 20 | 21 | #The deployment name. 22 | [Parameter(Mandatory)] 23 | [string]$DeploymentName, 24 | 25 | #Path to the template file. Defaults to template.json. 26 | [string]$TemplateFilePath = "azuredeploy.json", 27 | 28 | #Path to the parameters file. Defaults to parameters.json. If file is not found, will prompt for parameter values based on template. 29 | [string]$ParametersFilePath = "azuredeploy.parameters.json" 30 | ) 31 | 32 | $ErrorActionPreference = "Stop" 33 | 34 | # Login to Azure and select subscription 35 | Write-Output "Logging in" 36 | Login-AzureRmAccount 37 | Write-Output "Selecting subscription '$SubscriptionId'" 38 | Select-AzureRmSubscription -SubscriptionID $SubscriptionId 39 | 40 | # Create or check for existing resource group 41 | $resourceGroup = Get-AzureRmResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue 42 | if ( -not $ResourceGroup ) { 43 | Write-Output "Could not find resource group '$ResourceGroupName' - will create it" 44 | if ( -not $ResourceGroupLocation ) { 45 | $ResourceGroupLocation = Read-Host -Prompt 'Enter location for resource group' 46 | } 47 | Write-Output "Creating resource group '$ResourceGroupName' in location '$ResourceGroupLocation'" 48 | New-AzureRmResourceGroup -Name $resourceGroupName -Location $resourceGroupLocation 49 | } 50 | else { 51 | Write-Output "Using existing resource group '$ResourceGroupName'" 52 | } 53 | 54 | # Start the deployment 55 | Write-Output "Starting deployment" 56 | if ( Test-Path $ParametersFilePath ) { 57 | New-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName -TemplateFile $TemplateFilePath -TemplateParameterFile $ParametersFilePath 58 | } 59 | else { 60 | New-AzureRmResourceGroupDeployment -ResourceGroupName $ResourceGroupName -TemplateFile $TemplateFilePath 61 | } -------------------------------------------------------------------------------- /Azure/Function_TK_AzStorageAccountName.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Function TK_AzStorageAccountName { 5 | <# 6 | .SYNOPSIS 7 | TK_AzStorageAccountName 8 | .DESCRIPTION 9 | Create a unique storage account name for aAzure 10 | .PARAMETER StrToHash 11 | String for the Hash eg. your-company-name 12 | .PARAMETER CharsToUse 13 | Character to use 14 | .EXAMPLE 15 | TK_AzStorageAccountName -StrToHash "Login-Consultants" -CharsToUse 12 (max. 64) 16 | .NOTES 17 | Author : Thomas Krampe | t.krampe@loginconsultants.de 18 | Version : 1.0 19 | Creation date : 13.03.2020 | v0.1 | Initial script 20 | Last change : 13.03.2020 | v1.0 | Release 21 | 22 | IMPORTANT NOTICE 23 | ---------------- 24 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 25 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 26 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 27 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 28 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 29 | OF SUCH DAMAGES IN ADVANCE. 30 | #> 31 | [CmdletBinding()] 32 | Param( 33 | [Parameter(Mandatory=$true, Position = 0)][String]$StrToHash, 34 | [Parameter(Mandatory=$true, Position = 1)][Int]$CharsToUse 35 | ) 36 | 37 | begin { 38 | 39 | } 40 | 41 | process { 42 | $stringAsStream = [System.IO.MemoryStream]::new() 43 | $writer = [System.IO.StreamWriter]::new($stringAsStream) 44 | $writer.write($StrToHash) 45 | $writer.Flush() 46 | $stringAsStream.Position = 0 47 | [string]$strHash = Get-FileHash -InputStream $stringAsStream | Select-Object Hash 48 | 49 | if ([Int]$CharsToUse -gt 64) { 50 | [Int]$CharsToUse = 64 51 | } 52 | 53 | Write-Host $strHash.Substring(7,[Int]$CharsToUse).ToLower() 54 | } 55 | 56 | end { 57 | 58 | } 59 | } #EndFunction TK_AzStorageAccountName 60 | 61 | # Example function call 62 | TK_AzStorageAccountName -StrToHash "Login-Consultants" -CharsToUse 12 -------------------------------------------------------------------------------- /Azure/VerifyReachability.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS This script verifies that a machine in the vNet has access to the internet and the domain speficied by the user is reachable and the credentials are correct. 3 | 4 | .PARAMETER DomainName 5 | The domain name to verify 6 | 7 | .PARAMETER ServiceAccountName 8 | The user account that has access to the domain 9 | 10 | .PARAMETER ServiceAccountPassword 11 | The password for the service account user 12 | 13 | .EXAMPLE 14 | VerifyReachability.ps1 -DomainName 'radhe.local' -ServiceAccountName 'skyway' -ServiceAccountPassword 'citrix' 15 | #> 16 | 17 | param( 18 | [Parameter(Mandatory=$true)] 19 | [string] $DomainName, 20 | [Parameter(Mandatory=$true)] 21 | [string] $ServiceAccountName, 22 | [Parameter(Mandatory=$true)] 23 | [string] $ServiceAccountPassword 24 | ) 25 | 26 | Add-Type -TypeDefinition " 27 | public enum ReachabilityStatus 28 | { 29 | Success, 30 | ErrorNoInternetConnection, 31 | ErrorDomainNotReachable, 32 | ErrorIncorrectDomainCredentials 33 | } 34 | " 35 | 36 | function IamOnline { 37 | <# 38 | .SYNOPSIS 39 | Function/tool to detect if the computer has Internet access 40 | 41 | .DESCRIPTION 42 | Function/tool to detect if the computer has Internet access 43 | 44 | .EXAMPLE 45 | if (IamOnline) { "I'm online" } else { "I'm offline" } 46 | If any of the input URLs retuns a status code, 47 | it's considered online and function returns a positive result 48 | 49 | .OUTPUTS 50 | A number ranging from zero to the count of URLs entered 51 | 52 | .LINK 53 | https://superwidgets.wordpress.com/category/powershell/ 54 | 55 | .NOTES 56 | Function by Sam Boutros 57 | v1.0 - 12/19/2014 58 | 59 | #> 60 | 61 | $urls = @('https://citrix.com','https://microsoft.com','https://google.com') 62 | $success = 0 63 | Foreach($uri in $urls) { 64 | try { 65 | $response = Invoke-WebRequest -Uri $uri -UseBasicParsing -ErrorAction Stop 66 | if ($response.StatusCode) { $success++ } 67 | } catch {} 68 | } 69 | if ($success -eq 0) 70 | { 71 | return $false 72 | } 73 | return $true 74 | } 75 | 76 | function Test-ADCredentials { 77 | Param($username, $password, $domain) 78 | 79 | Add-Type -AssemblyName System.DirectoryServices.AccountManagement 80 | $ct = [System.DirectoryServices.AccountManagement.ContextType]::Domain 81 | $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext($ct, $domain) 82 | $isValid = $pc.ValidateCredentials($username, $password) 83 | return $isValid 84 | } 85 | 86 | function HandleDomainError { 87 | Param ( 88 | [int]$currentCount, 89 | [int]$maxCount 90 | ) 91 | if ($currentCount -ge $maxCount) 92 | { 93 | $errorCode = [ReachabilityStatus]::ErrorDomainNotReachable 94 | throw "CTX ERROR CODE:[$errorCode]: $_" 95 | } 96 | Start-Sleep -Seconds 60 97 | } 98 | 99 | [Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null 100 | 101 | $isOnline = IamOnline 102 | if (!($isOnline)) 103 | { 104 | $errorCode = [ReachabilityStatus]::ErrorNoInternetConnection 105 | throw "CTX ERROR CODE:[$errorCode]: Machines created in the specified vNet do not have internet connection. Please check DNS settings." 106 | } 107 | 108 | $retryAttempt = 0 109 | $maxRetryAttempt = 3 110 | while($true) 111 | { 112 | try 113 | { 114 | $retryAttempt++ 115 | $decodedPassword = [System.Web.HttpUtility]::UrlDecode($ServiceAccountPassword) 116 | $decodedDomain = [System.Web.HttpUtility]::UrlDecode($DomainName) 117 | $decodedAccountName = [System.Web.HttpUtility]::UrlDecode($ServiceAccountName) 118 | 119 | if ($decodedAccountName.Contains("\")) 120 | { 121 | $decodedAccountName = $decodedAccountName.Split("\")[1]; 122 | } 123 | 124 | $isValidCredentials = Test-ADCredentials $decodedAccountName $decodedPassword $decodedDomain 125 | 126 | if ($isValidCredentials -ne $true) 127 | { 128 | $errorCode = [ReachabilityStatus]::ErrorIncorrectDomainCredentials 129 | throw "CTX ERROR CODE:[$errorCode]: $_" 130 | } 131 | break; 132 | } catch { 133 | if ($Error[0] -ne $null -and $Error[0].Exception.Message.Contains("ErrorIncorrectDomainCredentials")) 134 | { 135 | $errorCode = [ReachabilityStatus]::ErrorIncorrectDomainCredentials 136 | throw $_ 137 | } 138 | else 139 | { 140 | HandleDomainError $retryAttempt $maxRetryAttempt 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /Azure/Windows Virtual Desktop/TK_CopyVHDToBlob.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CopyVHDToBlob { 2 | <# 3 | .SYNOPSIS 4 | Copy / Download a managed Azure Disk to Azure Storage account 5 | .DESCRIPTION 6 | Copy / Download a managed Azure Disk to Azure Storage account 7 | .PARAMETER SubscriptionID 8 | Azure Subscription ID eg. 11111111-2222-3333-4444-555555555555 9 | .PARAMETER ResourceGroupName 10 | The name of the ResourceGroup where the disk is stored eg. my-resources 11 | .PARAMETER ManagedDiskName 12 | The Name of the managed disk eg. test01_OsDisk_1_729ca8fexxxxxx849c2a8d89d21119db 13 | .PARAMETER DestStorageAccName 14 | The Name of the destination storage account eg. mystorage 15 | .PARAMETER DestStorageAccKey 16 | The access key for that storage account eg. 17 | .PARAMETER StorageContainerName 18 | The Name of the destination container in that storage account eg. myimages 19 | .PARAMETER VHDFileName 20 | Name of the VHD file eg. myimage.vhd 21 | .EXAMPLE 22 | TK_CopyVHDToBlob -SubscriptionID xxxx -ResourceGroupName "my-resources"" -ManagedDiskName "test01_=OsDisk_1_xxx" -DestStorageAccName "mystorage" -DestStorageAccKey "abcxxxx==" -StorageContainerName "myimages" -VHDFileName "myimage.vhd" 23 | .NOTES 24 | Author : Thomas Krampe | t.krampe@loginconsultants.de 25 | Version : 1.0 26 | Creation date : 23.08.2019 | v0.1 | Initial script 27 | Last change : 23.08.2019 | v1.0 | Release 28 | 29 | IMPORTANT NOTICE 30 | ---------------- 31 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 32 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 33 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 34 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 35 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 36 | OF SUCH DAMAGES IN ADVANCE. 37 | #> 38 | 39 | [CmdletBinding()] 40 | Param( 41 | [Parameter(Mandatory = $true, Position = 0)][String]$SubscriptionID, 42 | [Parameter(Mandatory = $true, Position = 1)][String]$ResourceGroupName, 43 | [Parameter(Mandatory = $true, Position = 2)][String]$ManagedDiskName, 44 | [Parameter(Mandatory = $true, Position = 3)][String]$DestStorageAccName, 45 | [Parameter(Mandatory = $true, Position = 4)][String]$DestStorageAccKey, 46 | [Parameter(Mandatory = $true, Position = 5)][String]$StorageContainerName, 47 | [Parameter(Mandatory = $true, Position = 6)][String]$VHDFileName 48 | ) 49 | 50 | begin { 51 | Connect-AzAccount 52 | } 53 | 54 | process { 55 | Select-AzSubscription -SubscriptionId $SubscriptionID 56 | $sas = Grant-AzDiskAccess -ResourceGroupName $ResourceGroupName -DiskName $ManagedDiskName -DurationInSecond 3600 -Access Read 57 | 58 | $destContext = New-AzStorageContext –StorageAccountName $DestStorageAccName -StorageAccountKey $DestStorageAccKey 59 | $blobcopy = Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $StorageContainerName -DestContext $destContext -DestBlob $VHDFileName 60 | 61 | while (($blobCopy | Get-AzStorageBlobCopyState).Status -eq "Pending") { 62 | Start-Sleep -s 30 63 | $blobCopy | Get-AzStorageBlobCopyState 64 | } 65 | } 66 | 67 | end { 68 | 69 | } 70 | } #EndFunction TK_CopyVHDToBlob 71 | 72 | # Usage Example 73 | $HLSubscriptionID = "11111111-2222-3333-4444-555555555555" 74 | $HLResourceGroupName = "myresources" 75 | $HLManagedDiskName = "test01_OsDisk_1_xxxxxxxxxxxxxxxdb" 76 | $HLDestStorageAccName = "mystorage" 77 | $HLDestStorageAccKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==" 78 | $HLStorageContainerName = "myimages" 79 | $HLVHDFileName = "myimage.vhd" 80 | 81 | # Function Call 82 | TK_CopyVHDToBlob -SubscriptionID $HLSubscriptionID -ResourceGroupName $HLResourceGroupName -ManagedDiskName $HLManagedDiskName -DestStorageAccName $HLDestStorageAccName -DestStorageAccKey $HLDestStorageAccKey -StorageContainerName $HLStorageContainerName -VHDFileName $HLVHDFileName 83 | -------------------------------------------------------------------------------- /Azure/Windows Virtual Desktop/TK_RemoveWVDHostPool.ps1: -------------------------------------------------------------------------------- 1 | Function TK_RemoveWVDHostPool { 2 | <# 3 | .SYNOPSIS 4 | TK_RemoveWVDHostPool 5 | .DESCRIPTION 6 | Delete a Windows Virtual Desktop RDS Host Pool in Azure 7 | .PARAMETER TenantName 8 | The Name of the WVD Tenant (you can get this with the Get-RdsTenant cmdlet) 9 | .PARAMETER HostPoolName 10 | The Name of the host pool (you can get this with the Get-RdsHostPool -TenantName xxx cmdlet) 11 | .EXAMPLE 12 | TK_RemoveWVDHostPool -TenantName MyTenant -HostPoolName MyHostPool 13 | This call remove the Application Group as well as the session host server associated to the Host Pool and finally the hpst pool itself. 14 | .NOTES 15 | Author : Thomas Krampe | t.krampe@loginconsultants.de 16 | Version : 1.0 17 | Creation date : 15.08.2019 | v0.1 | Initial script 18 | Last change : 15.08.2019 | v1.0 | Release 19 | 20 | IMPORTANT NOTICE 21 | ---------------- 22 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 23 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 24 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 25 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 26 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 27 | OF SUCH DAMAGES IN ADVANCE. 28 | #> 29 | 30 | [CmdletBinding()] 31 | Param( 32 | [Parameter(Mandatory = $true, Position = 0)][String]$TenantName, 33 | [Parameter(Mandatory = $true, Position = 1)][String]$HostPoolName 34 | ) 35 | 36 | begin { 37 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 38 | Write-Verbose "START FUNCTION - $FunctionName" 39 | 40 | [string]$ModuleName = "Microsoft.RDInfra.RDPowerShell" 41 | 42 | # If module is already imported there is nothing to do. 43 | if (Get-Module | Where-Object { $_.Name -eq $ModuleName }) { 44 | Write-Verbose "Module $ModuleName is already imported." 45 | } 46 | else { 47 | 48 | # If module is not imported, but available on disk then import 49 | if (Get-Module -ListAvailable | Where-Object { $_.Name -eq $ModuleName }) { 50 | Import-Module $ModuleName -Verbose 51 | } 52 | else { 53 | 54 | # If module is not imported, not available on disk, but is in online gallery then install and import 55 | if (Find-Module -Name $ModuleName | Where-Object { $_.Name -eq $ModuleName }) { 56 | Install-Module -Name $ModuleName -Verbose 57 | Import-Module $ModuleName -Verbose 58 | } 59 | else { 60 | 61 | # If module is still not available then abort with exit code 1 62 | Write-Warning "Module $ModuleName not imported, not local available and not in online gallery, exiting." 63 | EXIT 1 64 | } 65 | } 66 | } 67 | 68 | # Login to the Windows Virtual Desktop Tenant 69 | Add-RdsAccount -DeploymentUrl "https://rdbroker.wvd.microsoft.com" 70 | } 71 | 72 | process { 73 | # Do some pre-checks 74 | [string]$TenantCheck = (Get-RdsTenant).TenantName 75 | 76 | If ($TenantName -ne $TenantCheck) { 77 | Write-Error "Tenant name mismatch. Please verify the tenant name and try again." 78 | Exit 1 79 | } 80 | 81 | [string]$HostPoolCheck = (Get-RdsHostPool -TenantName $TenantName).HostPoolName 82 | 83 | If ($HostPoolName -ne $HostPoolCheck) { 84 | Write-Error "Host pool name mismatch. Please verify the host pool name and try again." 85 | Exit 1 86 | } 87 | 88 | # Remove Application Group associated to the Host Pool 89 | Get-RdsAppGroup -TenantName $TenantName -HostPoolName $HostPoolName | Remove-RdsAppGroup 90 | # Remove Session Host servers associated to the Host Pool 91 | Get-RdsSessionHost -TenantName $TenantName -HostPoolName $HostPoolName | Remove-RdsSessionHost 92 | # Remove the Host Pool 93 | Get-RdsHostPool -TenantName $TenantName -HostPoolName $HostPoolName | Remove-RdsHostPool 94 | } 95 | 96 | end { 97 | 98 | } 99 | } #EndFunction TK_RemoveWVDHostPool 100 | 101 | 102 | -------------------------------------------------------------------------------- /Azure/Windows Virtual Desktop/WVDPreparation.config.ini: -------------------------------------------------------------------------------- 1 | [BaseConfig] 2 | LogDir=C:\_logs 3 | 4 | [Control] 5 | CreateResourceGroup=1 6 | 7 | [Azure] 8 | ResourceGroupName=rg-test 9 | RGLocation=West Europe 10 | 11 | [AzureNetwork] 12 | VNetName=vnet-test 13 | VNetPrefix=10.1.0.0/16 14 | FrontSNName=FrontEnd 15 | FrontSNPrefix=10.1.1.0/24 16 | 17 | -------------------------------------------------------------------------------- /Azure/installChoco.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Install Chocolatey with Custom Script Extension 4 | 5 | .DESCRIPTION 6 | Install Chocolatey with CustomeScript Extension and applications via Chocolatey (eg. Google Chrome) 7 | 8 | .LINK 9 | https://github.com/thomaskrampe/CitrixCloud/tree/master/XenApp%20Essentials/CustomScriptExtension 10 | 11 | .NOTES 12 | Author : Thomas Krampe | t.krampe@loginconsultants.de 13 | Version : 1.0 14 | Creation date : 22.01.2018 | v0.1 | Initial script 15 | Last change : 22.01.2018 | v1.0 | Release it to GitHub 16 | #> 17 | 18 | # Install Chocolatey 19 | iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')) 20 | 21 | # Enable global confirmation 22 | choco feature enable -n allowGlobalConfirmation 23 | 24 | # Install Google Chrome via Chocolatey 25 | choco install googlechrome 26 | -------------------------------------------------------------------------------- /CVE-2021-1675/FolderProperties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/CVE-2021-1675/FolderProperties.png -------------------------------------------------------------------------------- /CVE-2021-1675/RunningScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/CVE-2021-1675/RunningScript.png -------------------------------------------------------------------------------- /CVE-2021-1675/TK_PrintNightMare.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Workaround for PrintNightmare CVE-2021-34527 4 | .DESCRIPTION 5 | Use an ACL to prevent malicious DLLs to be introduced by the print spooler 6 | .PARAMETER mode 7 | secure or unsecure C:\Windows\System32\spool\drivers 8 | .PARAMETER serverlist 9 | Path and filename to the server list text file (one server per line) 10 | eg. C:\temp\serverlist.txt 11 | .EXAMPLE 12 | TK_PrintNightMare.ps1 -mode secure -ServerList "C:\temp\serverlist.txt" 13 | TK_PrintNightMare.ps1 -mode unsecure "C:\temp\serverlist.txt" 14 | .LINK 15 | https://github.com/thomaskrampe/ 16 | 17 | .NOTES 18 | Author : Thomas Krampe | t.krampe@loginconsultants.de 19 | Version : 0.1 20 | Creation date : 01.07.2021 | v0.1 | Initial script 21 | : 02.07.2021 | v1.0 | Release to GitHub 22 | Last change : 02.07.2021 | v1.1 | add run on remote machines (Thanks C.Wallner) 23 | #> 24 | 25 | Param( 26 | [Parameter(Mandatory=$True)][ValidateSet("secure", "unsecure", "check")][string]$Mode, 27 | [Parameter(Mandatory=$True)][string]$ServerList 28 | ) 29 | 30 | $FileExists = Test-Path $ServerList 31 | 32 | If ($FileExists -eq $False) { 33 | Write-Host "Server List file doesn't exist. Please provide a valid server list file." -ForegroundColor "Red" 34 | Exit 9 35 | } 36 | 37 | 38 | $Servers = @(get-content -Path $ServerList) 39 | 40 | switch ($Mode){ 41 | "secure" { 42 | ForEach ($Server in $Servers) { 43 | If(!(Test-Connection -Cn $Server -BufferSize 16 -Count 1 -ea 0 -quiet)){ 44 | Write-Host "$Server offline, skipping." -ForegroundColor "Magenta" 45 | continue 46 | } else { 47 | Write-Host "Activate PrintNightmare workaround on $Server" -ForegroundColor "Green" 48 | Invoke-Command -Computername $Server -ScriptBlock { 49 | $Path = "C:\Windows\System32\spool\drivers" 50 | $Acl = Get-Acl $Path 51 | # The Hard way 52 | $dRule = New-Object System.Security.AccessControl.FileSystemAccessRule("System", "Modify", "ContainerInherit, ObjectInherit", "None", "Deny") 53 | # The Soft way not sure if it's enough 54 | # $dRule = New-Object System.Security.AccessControl.FileSystemAccessRule("System", "Write", "ContainerInherit, ObjectInherit", "None", "Deny") 55 | $Acl.AddAccessRule($dRule) 56 | Set-Acl $Path $Acl 57 | } 58 | } 59 | } 60 | break 61 | } 62 | "unsecure" { 63 | ForEach ($Server in $Servers) { 64 | If(!(Test-Connection -Cn $Server -BufferSize 16 -Count 1 -ea 0 -quiet)){ 65 | Write-Host "$Server offline, skipping." -ForegroundColor "Magenta" 66 | continue 67 | } else { 68 | Write-Host "Deactivate PrintNightmare workaround on $Server" -ForegroundColor "Green" 69 | Invoke-Command -Computername $Server -ScriptBlock { 70 | $Path = "C:\Windows\System32\spool\drivers" 71 | $Acl = Get-Acl $Path 72 | # The Hard way 73 | $aRule = New-Object System.Security.AccessControl.FileSystemAccessRule("System", "Modify", "ContainerInherit, ObjectInherit", "None", "Deny") 74 | # The Soft way not sure if it's enough 75 | # $aRule = New-Object System.Security.AccessControl.FileSystemAccessRule("System", "Write", "ContainerInherit, ObjectInherit", "None", "Deny") 76 | $Acl.RemoveAccessRule($aRule) 77 | Set-Acl $Path $Acl 78 | } 79 | } 80 | } 81 | break 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /CVE-2021-1675/readme.md: -------------------------------------------------------------------------------- 1 | # CVE-2021-1675 aka Print Nightmare Workaround 2 | 3 | Just provide a text file with all your servers and run this script to prevent SYSTEM for adding malicious DLL's in your spool\drivers directory. For more informations and PoC of the attack visit [https://github.com/thomasgeens/CVE-2021-1675](https://github.com/thomasgeens/CVE-2021-1675). 4 | 5 | Run 6 | `TK_PrintNightMare.ps1 -mode secure -Serverlist "C:\PathToYour\serverlist.txt"` 7 | 8 | to secure your Print Spooler, or 9 | 10 | `TK_PrintNightMare.ps1 -mode unsecure -Serverlist "C:\PathToYour\serverlist.txt"` 11 | 12 | to change it back to normal/unsecure 13 | 14 | ![Folder Properties](./FolderProperties.png) 15 | 16 | ![Running Script](./RunningScript.png) 17 | 18 | That's it, but keep in mind that's only a workaround until a patch is available - watch this space [(https://msrc.microsoft.com/update-guide/vulnerability](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-1675). 19 | -------------------------------------------------------------------------------- /Citrix/CitrixCloud/Install_RemotePoshSDK.ps1: -------------------------------------------------------------------------------- 1 | # PowerShell Wrapper for MDT, Standalone and Chocolatey Installation - (C)2015 xenappblog.com 2 | # Example 1: Start-Process "XenDesktopServerSetup.exe" -ArgumentList $unattendedArgs -Wait -Passthru 3 | # Example 2 Powershell: Start-Process powershell.exe -ExecutionPolicy bypass -file $Destination 4 | # Example 3 EXE (Always use ' '): 5 | # $UnattendedArgs='/qn' 6 | # (Start-Process "$PackageName.$InstallerType" $UnattendedArgs -Wait -Passthru).ExitCode 7 | # Example 4 MSI (Always use " "): 8 | # $UnattendedArgs = "/i $PackageName.$InstallerType ALLUSERS=1 /qn /liewa $LogApp" 9 | # (Start-Process msiexec.exe -ArgumentList $UnattendedArgs -Wait -Passthru).ExitCode 10 | 11 | Clear-Host 12 | Write-Verbose "Setting Arguments" -Verbose 13 | $StartDTM = (Get-Date) 14 | 15 | $Vendor = "Citrix" 16 | $Product = "Virtual Apps and Desktops Remote PowerShell SDK" 17 | $Version = "7.19.0.26" 18 | $PackageName = "CitrixPoshSdk" 19 | $InstallerType = "exe" 20 | $Source = "$PackageName" + "." + "$InstallerType" 21 | $LogPS = "${env:SystemRoot}" + "\Temp\$Vendor $Product $Version PS Wrapper.log" 22 | $LogApp = "${env:SystemRoot}" + "\Temp\$PackageName.log" 23 | $Destination = "${env:ChocoRepository}" + "\$Vendor\$Product\$Version\$packageName.$installerType" 24 | $UnattendedArgs='/q' 25 | $url = "https://download.apps.cloud.com/CitrixPoshSdk.exe" 26 | $ProgressPreference = 'SilentlyContinue' 27 | 28 | Start-Transcript $LogPS 29 | 30 | if( -Not (Test-Path -Path $Version ) ) 31 | { 32 | New-Item -ItemType directory -Path $Version 33 | } 34 | 35 | CD $Version 36 | 37 | Write-Verbose "Downloading $Vendor $Product $Version" -Verbose 38 | If (!(Test-Path -Path $Source)) { 39 | Invoke-WebRequest -Uri $url -OutFile $Source 40 | } 41 | Else { 42 | Write-Verbose "File exists. Skipping Download." -Verbose 43 | } 44 | 45 | Write-Verbose "Starting Installation of $Vendor $Product $Version" -Verbose 46 | (Start-Process "$PackageName.$InstallerType" $UnattendedArgs -Wait -Passthru).ExitCode 47 | 48 | Write-Verbose "Customization" -Verbose 49 | 50 | Write-Verbose "Stop logging" -Verbose 51 | $EndDTM = (Get-Date) 52 | Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalSeconds) Seconds" -Verbose 53 | Write-Verbose "Elapsed Time: $(($EndDTM-$StartDTM).TotalMinutes) Minutes" -Verbose 54 | Stop-Transcript 55 | -------------------------------------------------------------------------------- /Citrix/FAS/FASConfig.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | FASConfig.ps1 4 | 5 | .DESCRIPTION 6 | Lightweight Script for Enable, Disable or Audit Storefront Stores for FAS 7 | 8 | .PARAMETER Mode 9 | Enable 10 | Disable 11 | Audit 12 | 13 | .EXAMPLE 14 | 15 | FASConfig.ps1 -Mode Enable 16 | FASConfig.ps1 -Mode Disable 17 | FASConfig.ps1 -Mode Audit 18 | 19 | .LINK 20 | https://github.com/thomaskrampe/PowerShell/blob/master/Citrix/FAS/FASConfig.ps1 21 | 22 | .NOTES 23 | Author : Thomas Krampe | thomas.krampe@myctx.net 24 | Version : 1.0 25 | Creation date : 12.09.2018 | v0.1 | Initial script 26 | Last change : 14.09.2018 | v1.0 | Release to Github 27 | 28 | IMPORTANT NOTICE 29 | ---------------- 30 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 31 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 32 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 33 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 34 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 35 | OF SUCH DAMAGES IN ADVANCE. 36 | 37 | #> 38 | 39 | # Script parameter 40 | Param( 41 | [Parameter(Mandatory=$True)][ValidateSet("Enable", "Disable", "Audit")][string]$Mode 42 | ) 43 | 44 | # Define global Error handling 45 | $global:ErrorActionPreference = "Stop" 46 | if($verbose){ $global:VerbosePreference = "Continue" } 47 | 48 | # ------------------------------------------------------------------------------------------------- 49 | # FUNCTIONS (don't change anything here) 50 | # ------------------------------------------------------------------------------------------------- 51 | 52 | function TK_AuditFAS { 53 | begin { 54 | } 55 | 56 | process { 57 | $SFSTores = Get-STFStoreService 58 | Foreach ($SFStore in $SFSTores) { 59 | $StoreVirtualPath = $SFStore.VirtualPath 60 | $Store = Get-STFStoreService -VirtualPath $StoreVirtualPath 61 | $Auth = Get-STFAuthenticationService -StoreService $Store 62 | 63 | $FASAudit = Get-STFStoreLaunchOptions -StoreService $Store 64 | 65 | If ($FASAudit.VdaLogonDataProviderName -eq "FASLogonDataProvider") { 66 | Write-Host "FAS ist auf dem Store $($SFStore.VirtualPath) aktiviert." -ForegroundColor Green 67 | } 68 | else { 69 | Write-Host "FAS ist nicht auf dem Store $($SFStore.VirtualPath) aktiviert." -ForegroundColor Red 70 | } 71 | } 72 | } 73 | 74 | end { 75 | } 76 | 77 | } 78 | 79 | function TK_EnableFAS { 80 | begin { 81 | } 82 | 83 | process { 84 | $SFSTores = Get-STFStoreService 85 | Foreach ($SFStore in $SFSTores) { 86 | # Better Exclusion as a later improvement, for now just a simple if then 87 | If ( $SFStore.VirtualPath -eq "/Citrix/Store" -or $SFStore.VirtualPath -eq "/Citrix/Intern") { 88 | Write-Host "Store $($SFStore.VirtualPath) is excluded." -ForegroundColor Red 89 | } Else { 90 | Write-Host "Configuring $($SFStore.VirtualPath) for FAS authentication." -ForegroundColor Yellow 91 | 92 | $StoreVirtualPath = $SFStore.VirtualPath 93 | $Store = Get-STFStoreService -VirtualPath $StoreVirtualPath 94 | $Auth = Get-STFAuthenticationService -StoreService $Store 95 | 96 | Set-STFClaimsFactoryNames -AuthenticationService $Auth -ClaimsFactoryName "FASClaimsFactory" 97 | Set-STFStoreLaunchOptions -StoreService $Store -VdaLogonDataProvider "FASLogonDataProvider" 98 | Write-Host "All done with $StoreVirtualPath." -ForegroundColor Green 99 | } 100 | } 101 | } 102 | 103 | end { 104 | } 105 | 106 | } 107 | 108 | function TK_DisableFAS { 109 | begin { 110 | } 111 | 112 | process { 113 | $SFSTores = Get-STFStoreService 114 | Foreach ($SFStore in $SFSTores) { 115 | Write-Host "Configuring $($SFStore.VirtualPath) for standard authentication (Disable FAS)." -ForegroundColor Yellow 116 | 117 | $StoreVirtualPath = $SFStore.VirtualPath 118 | $Store = Get-STFStoreService -VirtualPath $StoreVirtualPath 119 | $Auth = Get-STFAuthenticationService -StoreService $Store 120 | 121 | Set-STFClaimsFactoryNames -AuthenticationService $Auth -ClaimsFactoryName "standardClaimsFactory" 122 | Set-STFStoreLaunchOptions -StoreService $Store -VdaLogonDataProvider "" 123 | Write-Host "FAS on Store $StoreVirtualPath disabled." -ForegroundColor Green 124 | } 125 | } 126 | 127 | end { 128 | } 129 | 130 | } 131 | 132 | # ------------------------------------------------------------------------------------------------- 133 | # MAIN SECTION 134 | # ------------------------------------------------------------------------------------------------- 135 | 136 | # Disable File Security 137 | $env:SEE_MASK_NOZONECHECKS = 1 138 | 139 | Clear-Host 140 | 141 | Write-Host "Starting script in $mode mode.`n`r" -ForegroundColor Yellow 142 | 143 | # Import PowerShell Module 144 | Get-Module "Citrix.Storefront.*" -ListAvailable | Import-Module 145 | 146 | 147 | switch ($Mode){ 148 | "Enable" {TK_EnableFAS; break} 149 | "Disable" {TK_DisableFAS; break} 150 | "Audit" {TK_AuditFAS; break} 151 | 152 | } 153 | 154 | 155 | -------------------------------------------------------------------------------- /Citrix/SessionRecording/GenRandomQMID.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Generate Random QMID for Citrix Session Recording Agent on PVS or MCS images 4 | 5 | .DESCRIPTION 6 | When Machine Creation Services (MCS) or Provisioning Services (PVS) creates multiple VDAs with 7 | the configured master image and Microsoft Message Queuing (MSMQ) installed, those VDAs can have 8 | the same QMId under certain conditions. 9 | 10 | Ensure that the execution policy is set to RemoteSigned or Unrestricted in PowerShell. 11 | Set-ExecutionPolicy RemoteSigned 12 | 13 | Create a scheduled task, set the trigger as on system startup, and run with the SYSTEM account on 14 | the PVS or MCS master image machine. Add the command as a startup task. 15 | 16 | eg. powershell.exe -file C:\GenRandomQMID.ps1 17 | 18 | .NOTES 19 | Author : Thomas Krampe | t.krampe@loginconsultants.de 20 | Version : 1.0 21 | Creation date : 06.08.2018 | v0.1 | Initial script for Athora 22 | 23 | 24 | NOTICE 25 | THIS SCRIPT IS PROVIDED “AS IS” WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 26 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 27 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED HEREIN, 28 | NOR FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM THE FURNISHING, 29 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 30 | OF SUCH DAMAGES IN ADVANCE. 31 | #> 32 | 33 | # Remove old QMId from registry and set SysPrep flag for MSMQ 34 | Remove-Itemproperty -Path HKLM:Software\Microsoft\MSMQ\Parameters\MachineCache -Name QMId -Force 35 | Set-ItemProperty -Path HKLM:Software\Microsoft\MSMQ\Parameters -Name "SysPrep" -Type DWord -Value 1 36 | 37 | # Get dependent services 38 | $depServices = Get-Service -name MSMQ -dependentservices | Select -Property Name 39 | 40 | # Restart MSMQ to get a new QMId 41 | Restart-Service -force MSMQ 42 | 43 | # Start dependent services 44 | if ($depServices -ne $null) { 45 | foreach ($depService in $depServices) { 46 | $startMode = Get-WmiObject win32_service -filter "NAME = '$($depService.Name)'" | Select -Property StartMode 47 | if ($startMode.StartMode -eq "Auto") { 48 | Start-Service $depService.Name 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Citrix/Sharefile/DeleteDisabledSFUser.ps1: -------------------------------------------------------------------------------- 1 | # Get all disabled users and delete them 2 | 3 | Add-PSSnapIn ShareFile 4 | 5 | Function FindDisabledUsers { 6 | $UserType = "employee" 7 | $client = Get-SfClient -Name "c:\tmp\Sharefile\sfclient.sfps" 8 | $entity = ""; 9 | switch ($UserType.ToLower()){ 10 | "employee"{ 11 | $entity = 'Accounts/Employees'; 12 | } 13 | "client" { 14 | $entity = 'Accounts/Clients'; 15 | } 16 | } 17 | 18 | # Pull all of the Account Employees or Clients 19 | $sfUsers = Send-SfRequest -Client $client -Entity $entity 20 | 21 | $fileOutput = @() 22 | 23 | # Loop through each of the Employees or Clients returned from inital call 24 | foreach($sfUserId in $sfUsers){ 25 | #Get full user information including security 26 | $sfUser = Send-SfRequest -Client $client -Entity Users -Id $sfUserId.Id -Expand Security 27 | 28 | #Output to Console Emails of disabled users 29 | Write-Host $sfUser.Email 30 | 31 | # check to see if security parameter IsDisabled is true 32 | switch ($sfUser.Security.IsDisabled ) { 33 | "True" { 34 | $fileOutput += New-Object PSObject -Property @{'UserId'=$sfUserId.Id;'FullName'=$sfUser.FullName;'Email'=$sfUser.Email} 35 | } 36 | } 37 | } 38 | 39 | #Output CSV file with all disabled user information 40 | $fileOutput | Export-Csv ("C:\tmp\Sharefile\" + $UserType + ".csv") -Force -NoTypeInformation 41 | } 42 | 43 | Function DeleteUsers { 44 | # $UserType = "employee" 45 | $client = Get-SfClient -Name "c:\tmp\Sharefile\sfclient.sfps" 46 | $sfUserObjects = Import-Csv ("C:\tmp\Sharefile\employee.csv") 47 | 48 | foreach($sfUser in $sfUserObjects){ 49 | Send-SfRequest -Client $client -Method Delete -Entity Users -Id $sfUser.UserId -Parameters @{"completely" = "true"} 50 | } 51 | 52 | } 53 | 54 | 55 | # Create an authentication file 56 | New-SfClient -Name "c:\tmp\Sharefile\sfclient.sfps" 57 | # Get-SfClient -Name "c:\tmp\Sharefile\sfclient.sfps" 58 | 59 | FindDisabledUsers; 60 | 61 | # DeleteUsers; -------------------------------------------------------------------------------- /Citrix/XenDesktop/CVAD Database Migration.md: -------------------------------------------------------------------------------- 1 | # CVAD Database Migration 2 | ## Preparations 3 | 4 | Following steps should be performed just before the Citrix Database migration procedure begins: 5 | 6 | 1\. Take a snapshot of Delivery Controller virtual machines. This will help us revert to previous state if anything goes wrong while establishing connections with the new database server. 7 | 8 | 2\. Enable maintenance mode on all VDA machines in Citrix Studio. Once primary delivery controller is disconnected from databases, all VDAs will re-register themselves and new connections will be handled with/by newly elected broker. 9 | 10 | 3\. Make sure that all active sessions are logged off. 11 | 12 | 4\. Back up the databases on the original SQL server. 13 | * Site DB – Stores the running Site configuration, plus the current session state and connection information. 14 | * Configuration Logging DB – Stores information about Site configuration changes and administrative activities. 15 | * Monitoring DB – Stores data used by Director, such as session and connection information. 16 | 17 | 5\. Restore Database on the "new" database server. 18 | 19 | 6\. Under User Mapping, select the database and assign below roles to Delivery Controller computer accounts: 20 | 21 | ``` 22 | Citrix Site Database – ADIdentitySchema_ROLE 23 | Citrix Site Database – Analytics_ROLE # for 7.8 and newer 24 | Citrix Site Database – AppLibrarySchema_ROLE # for 7.8 and newer 25 | Citrix Site Database – chr_Broker 26 | Citrix Site Database – chr_Controller 27 | Citrix Site Database – ConfigLoggingSiteSchema_ROLE 28 | Citrix Site Database – ConfigurationSchema_ROLE 29 | Citrix Site Database – DAS_ROLE 30 | Citrix Site Database – DesktopUpdateManagerSchema_ROLE 31 | Citrix Site Database – EnvTestServiceSchema_ROLE 32 | Citrix Site Database – HostingUnitServiceSchema_ROLE 33 | Citrix Site Database – Monitor_ROLE 34 | Citrix Site Database – OrchestrationSchema_ROLE # for 7.11 and newer 35 | Citrix Site Database – public 36 | Citrix Site Database – StorefrontSchema_ROLE # for 7.8 and newer 37 | Citrix Site Database – TrustSchema_ROLE # for 7.11 and newer 38 | Citrix Site Monitoring Database – Monitor_ROLE 39 | Citrix Site Monitoring Database – public 40 | Citrix Site Configuration Logging Database – ConfigLoggingSchema_ROLE 41 | Citrix Site Configuration Logging Database – public 42 | ``` 43 | ![][1] 44 | 45 | ## Migration 46 | 47 | In this part of Citrix Database Migration process, we will migrate Citrix XenDesktop or Citrix Virtual Apps and Desktops Databases. 48 | 49 | 1\. Confirm that Citrix Studio is not opened on any Delivery Controller. If Studio is published, ensure that there is no active session of that. 50 | 51 | 2\. Login to Primary Citrix Delivery Controller, open PowerShell as an Administrator and execute following commands to see the existing database connection strings. 52 | 53 | ```language-powershell 54 | asnp citrix* 55 | Get-ConfigDBConnection 56 | Get-AcctDBConnection 57 | Get-AnalyticsDBConnection # for 7.6 and newer 58 | Get-AppLibDBConnection # for 7.8 and newer 59 | Get-OrchDBConnection # for 7.11 and newer 60 | Get-TrustDBConnection # for 7.11 and newer 61 | Get-HypDBConnection 62 | Get-ProvDBConnection 63 | Get-BrokerDBConnection 64 | Get-EnvTestDBConnection 65 | Get-SfDBConnection 66 | Get-MonitorDBConnection 67 | Get-MonitorDBConnection -DataStore Monitor 68 | Get-LogDBConnection 69 | Get-LogDBConnection -DataStore Logging 70 | Get-AdminDBConnection 71 | ``` 72 | 73 | ![][2] 74 | 75 | 3\. Run the migration script from [GitHub][3]. Make sure that you change the old and the new database server\instance names in the script. 76 | 77 | ## Database testing 78 | Sometimes it make sense to try if the new database is available and accessable. In that case you can use a PowerShell function like the following example function. 79 | 80 | ```language-powershell 81 | function Test-SqlConnection { 82 | param( 83 | [Parameter(Mandatory)] 84 | [string]$ServerName, 85 | 86 | [Parameter(Mandatory)] 87 | [string]$DatabaseName, 88 | 89 | [Parameter(Mandatory)] 90 | [pscredential]$Credential 91 | ) 92 | 93 | $ErrorActionPreference = 'Stop' 94 | 95 | try { 96 | $userName = $Credential.UserName 97 | $password = $Credential.GetNetworkCredential().Password 98 | $connectionString = 'Data Source={0};database={1};User ID={2};Password={3}' -f $ServerName,$DatabaseName,$userName,$password 99 | $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $ConnectionString 100 | $sqlConnection.Open() 101 | 102 | ## This will run if the Open() method does not throw an exception 103 | write-host "Database connection to $Servername and Database $DatabaseName successful." -ForegroundColor Green 104 | } catch { 105 | write-host "Database connection to $Servername and Database $DatabaseName NOT successful." -ForegroundColor Red 106 | } finally { 107 | ## Close the connection when we're done 108 | $sqlConnection.Close() 109 | } 110 | } 111 | 112 | Test-SqlConnection -ServerName 'serverhostname' -DatabaseName 'DbName' -Credential (Get-Credential) 113 | 114 | ``` 115 | 116 | 117 | 118 | [1]: CVAD-Site-Database-Role-assignment-01.png 119 | [2]: CVAD-Site-Database-Role-assignment-02.png 120 | [3]: https://github.com/thomaskrampe/PowerShell/blob/master/Citrix/XenDesktop/XenDesktop7MoveDatabase.ps1 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /Citrix/XenDesktop/CVAD-Site-Database-Role-assignment-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/Citrix/XenDesktop/CVAD-Site-Database-Role-assignment-01.png -------------------------------------------------------------------------------- /Citrix/XenDesktop/CVAD-Site-Database-Role-assignment-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/Citrix/XenDesktop/CVAD-Site-Database-Role-assignment-02.png -------------------------------------------------------------------------------- /Citrix/XenDesktop/InstallHPLJ2800PSDriver.ps1: -------------------------------------------------------------------------------- 1 | #################################################################################################### 2 | # 3 | # Script to Install HP LaserJet 2800 Series PS Driver 4 | # 5 | # Author: Thomas Krampe - t.krampe@loginconsultants.de 6 | # Date: 05.11.2018 7 | # Notes: Citrix KB http://support.citrix.com/article/CTX140208 8 | # Driver Source https://www.catalog.update.microsoft.com/Search.aspx?q=HP%20LaserJet%202800 9 | # 10 | ##################################################################################################### 11 | 12 | If (-not (Test-Path C:\Driver\HPLJ2800Series -PathType Container)) { 13 | New-Item C:\Driver\HPLJ2800Series -ItemType directory 14 | } 15 | 16 | 17 | $url = "http://download.windowsupdate.com/msdownload/update/driver/drvs/2011/07/4753_fc148f3df197a4c5cf20bd6a8b337b444037655f.cab" 18 | $output = "C:\Driver\4753_fc148f3df197a4c5cf20bd6a8b337b444037655f.cab" 19 | $start_time = Get-Date 20 | 21 | Invoke-WebRequest -Uri $url -OutFile $output 22 | Write-Output "Time taken: $((Get-Date).Subtract($start_time).Seconds) second(s)" 23 | 24 | Set-Location -Path C:\Driver 25 | & expand.exe 4753_fc148f3df197a4c5cf20bd6a8b337b444037655f.cab -F:* C:\Driver\HPLJ2800Series 26 | 27 | Write-Host "Folder found - Install HP 2800 Series PS Driver" 28 | & pnputil.exe -a "C:\Driver\HPLJ2800Series\prnhp002.inf" 29 | Write-Host "Add Driver to local PrintServer." 30 | Add-PrinterDriver -Name "HP Color LaserJet 2800 Series PS" 31 | Write-Host "Clean-up" 32 | Set-Location -Path $PSScriptRoot 33 | Remove-Item –path C:\Driver -Recurse 34 | Write-Host "All done!" 35 | 36 | -------------------------------------------------------------------------------- /Citrix/XenDesktop/TrustLicenseServerCertificate.ps1: -------------------------------------------------------------------------------- 1 | # Sets the License Server certificate as trusted 2 | # Thomas Krampe 3 | 4 | Add-pssnapin citrix* 5 | 6 | # Change IP-address 7 | $LicenseServerAddress = "192.168.1.12" 8 | 9 | $licenseServerQueryAddress = "https://" + $LicenseServerAddress + ":8083/" 10 | 11 | $cert = Get-LicCertificate -AdminAddress $licenseServerQueryAddress 12 | Set-ConfigSiteMetadata -Name "CertificateHash" -Value $cert.certhash -------------------------------------------------------------------------------- /DHCP/DHCPReservations.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Export or Import DHCP reservations 4 | 5 | .DESCRIPTION 6 | Export or Import DHCP reservations 7 | 8 | .PARAMETER Mode 9 | Export or Import 10 | 11 | .PARAMETER DataPath 12 | Path to the file (eg. c:\temp) 13 | 14 | .EXAMPLE 15 | .\DHCPReservations.ps1 -Mode Export -DataPath "C:\temp" -Verbose 16 | 17 | .LINK 18 | https://github.com/thomaskrampe/Citrix-PowerShell-Scripts 19 | 20 | .NOTES 21 | Author : Thomas Krampe | t.krampe@loginconsultants.de 22 | Version : 1.0 23 | Creation date : 12.02.2018 | v0.1 | Initial script 24 | Last change : 12.02.2018 | v1.0 | Release to GitHub 25 | 26 | .TODO 27 | Create Scope Part 28 | https://docs.microsoft.com/en-us/powershell/module/dhcpserver/add-dhcpserverv4scope?view=win10-ps 29 | #> 30 | 31 | Param ( 32 | [Parameter(Mandatory=$true)] [string]$Mode, 33 | [Parameter(Mandatory=$true)] [string]$DataPath 34 | ) 35 | 36 | 37 | # Export DHCP reservations to CSV file 38 | function ExportDHCP { 39 | Param ( 40 | [string]$DataPath 41 | ) 42 | write-Verbose "Creating output file $DataPath\$($env:COMPUTERNAME)-Reservations.csv" 43 | Get-DHCPServerV4Scope | ForEach {Get-DHCPServerv4Lease -ScopeID $_.ScopeID | where {$_.AddressState -like '*Reservation'}} | Select-Object ScopeId,IPAddress,HostName,ClientID | Export-Csv "$DataPath\$($env:COMPUTERNAME)-Reservations.csv" -NoTypeInformation 44 | } 45 | 46 | 47 | # Import DHCP reservations from CSV file 48 | function ImportDHCP { 49 | Param ( 50 | [string]$DataPath 51 | ) 52 | if (Test-Path "$DataPath\$($env:COMPUTERNAME)-Reservations.csv" ) { 53 | $ResList = import-csv -Path "$DataPath\$($env:COMPUTERNAME)-Reservations.csv" -Delimiter "," 54 | } 55 | Else {write-error "File not exists"; exit} 56 | try { 57 | foreach( $r in $reslist ) 58 | { 59 | if ( $r.ClientID -eq $null -Or $r.ClientID -eq "ClientID" ) { continue } 60 | $DHCPScopeID = $r.ScopeId 61 | $DHCPMacAddress = $r.ClientID 62 | $DHCPIPAddress = $r.IPAddress 63 | $DHCPHostname = $r.HostName 64 | 65 | Write-Verbose "Importing: $DHCPScopeID, $DHCPIPAddress, $DHCPHostname, $DHCPMacAddress" 66 | Add-DhcpServerv4Reservation -ScopeId $DHCPScopeID -IPAddress $DHCPIPAddress -Name $DHCPHostname -ClientId $DHCPMacAddress -Type Dhcp 67 | } 68 | } 69 | catch { 70 | $Reason = $_ 71 | Write-AMInfo "Service start failed. Error message: `'$Reason`'" 72 | } 73 | } 74 | 75 | 76 | switch ($Mode) { 77 | Export {ExportDHCP -DataPath $DataPath} 78 | Import {ImportDHCP -DataPath $DataPath} 79 | default {throw "No Mode selected"} 80 | } 81 | 82 | 83 | -------------------------------------------------------------------------------- /Function Library/Function_MW-CreateProfileFolder.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION MW-CreateProfileFolder { 2 | <# 3 | THis function creates a root folder for Roaming Profiles with the appropriate file permissions 4 | You need to define the admin group name that can access the folder, 5 | if no Admingroup Parameter is defined the local Admin group is used 6 | 7 | Example: 8 | 9 | MW-CreateProfileFolder -folder C:\Profiles 10 | will create the folder, set the appropriate folder permissions on C:\Profiles with the local admin account 11 | and will share it as Profiles$ 12 | #> 13 | 14 | Param ($folder, 15 | $adminGroup) 16 | 17 | if ($adminGroup -eq $null){ 18 | Write-host "no admin group defined, using builtin group" 19 | $objSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544") 20 | $adminGroup = ( $objSID.Translate([System.Security.Principal.NTAccount]) ).Value 21 | } 22 | 23 | # Create folder if not existent 24 | IF (!(Test-path $folder)) {MD $folder} 25 | 26 | $DefaultAccessGroup = "authenticated users" 27 | 28 | #share folder 29 | $Sharename = "$($folder.split("\")[-1])" + "`$" 30 | Write-host "trying to create a share with the name $Sharename" 31 | if (Get-SmbShare $sharename -ea SilentlyContinue){ 32 | write-host "share is already existent, will not create it" 33 | } ELSE { 34 | New-SmbShare -Path $folder -Name $sharename -FullAccess $DefaultAccessGroup 35 | } 36 | 37 | 38 | # remove inheritence 39 | $acl = Get-Acl $Folder 40 | $acl.SetAccessRuleProtection($true,$true) 41 | $acl |Set-Acl 42 | 43 | # remove all rights 44 | $acl = Get-Acl $Folder 45 | $acl.Access | % {$acl.purgeaccessrules($_.IdentityReference)} 46 | # add new acl 47 | $rule = New-Object System.Security.AccessControl.FileSystemAccessRule $adminGroup ,"Fullcontrol", "ContainerInherit,ObjectInherit", "None","Allow" 48 | $acl.AddAccessRule($rule) 49 | $rule = New-Object System.Security.AccessControl.FileSystemAccessRule "SYSTEM","Fullcontrol", "ContainerInherit,ObjectInherit", "None","Allow" 50 | $acl.AddAccessRule($rule) 51 | $rule = New-Object System.Security.AccessControl.FileSystemAccessRule "Creator Owner","Fullcontrol", "ContainerInherit,ObjectInherit", "InheritOnly","Allow" 52 | $acl.AddAccessRule($rule) 53 | $rule = New-Object System.Security.AccessControl.FileSystemAccessRule $DefaultAccessGroup,"AppendData, ReadAndExecute", "None", "None","Allow" 54 | $acl.AddAccessRule($rule) 55 | $acl | set-acl 56 | 57 | 58 | } #EndFUNCTION MW-CreateProfileFolder -------------------------------------------------------------------------------- /Function Library/Function_MW-ShowUEVPKGXRegistry.ps1: -------------------------------------------------------------------------------- 1 | FUNCTION MW-ShowUEVPKGXRegistry { 2 | <# 3 | This functions shows the actual registry values in a PKGX file (UEV) 4 | The parameter is the path to the PKGX file 5 | Example 6 | 7 | MW-ShowPKGXRegistry "C:\UEV\Join\SettingsPackages\MicrosoftWordpad6\MicrosoftWordpad6.pkgx" 8 | #> 9 | 10 | 11 | Param ($PKGXFile) 12 | $stream = Export-UevPackage $PKGXFile 13 | $data = $stream.split("`n") 14 | $matches = $null 15 | foreach ($line in $data){ 16 | if ($line -match 'HKCU(.*)" Action="(.*)">(.*)<'){ 17 | Write-host "REgkey: $($matches[1]) `t`t $($matches[3])" 18 | 19 | } 20 | } 21 | 22 | 23 | } #EndFUNCTION MW-ShowUEVPKGXRegistry -------------------------------------------------------------------------------- /Function Library/Function_StartCountdown.ps1: -------------------------------------------------------------------------------- 1 | Function Start-Countdown { 2 | <# 3 | .SYNOPSIS 4 | Provide a graphical countdown if you need to pause a script for a period of time 5 | .PARAMETER Seconds 6 | Time, in seconds, that the function will pause 7 | .PARAMETER Messge 8 | Message you want displayed while waiting 9 | .EXAMPLE 10 | Start-Countdown -Seconds 30 -Message Please wait while Active Directory replicates data... 11 | .NOTES 12 | Author: Martin Pugh 13 | Twitter: @thesurlyadm1n 14 | Spiceworks: Martin9700 15 | Blog: www.thesurlyadmin.com 16 | 17 | Changelog: 18 | 2.0 New release uses Write-Progress for graphical display while couting 19 | down. 20 | 1.0 Initial Release 21 | .LINK 22 | http://community.spiceworks.com/scripts/show/1712-start-countdown 23 | #> 24 | 25 | Param( 26 | [Int32]$Seconds = 10, 27 | [string]$Message = "Pausing for 10 seconds..." 28 | ) 29 | ForEach ($Count in (1..$Seconds)) 30 | { Write-Progress -Id 1 -Activity $Message -Status "Waiting for $Seconds seconds, $($Seconds - $Count) left" -PercentComplete (($Count / $Seconds) * 100) 31 | Start-Sleep -Seconds 1 32 | } 33 | Write-Progress -Id 1 -Activity $Message -Status "Completed" -PercentComplete 100 -Completed 34 | } #End Function Start-Countdown -------------------------------------------------------------------------------- /Function Library/Function_TK_AzStorageAccountName.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Function TK_AzStorageAccountName { 5 | <# 6 | .SYNOPSIS 7 | TK_AzStorageAccountName 8 | .DESCRIPTION 9 | Create a unique storage account name for aAzure 10 | .PARAMETER StrToHash 11 | String for the Hash eg. your-company-name 12 | .PARAMETER CharsToUse 13 | Character to use 14 | .EXAMPLE 15 | TK_AzStorageAccountName -StrToHash "Login-Consultants" -CharsToUse 12 (max. 64) 16 | .NOTES 17 | Author : Thomas Krampe | t.krampe@loginconsultants.de 18 | Version : 1.0 19 | Creation date : 13.03.2020 | v0.1 | Initial script 20 | Last change : 13.03.2020 | v1.0 | Release 21 | 22 | IMPORTANT NOTICE 23 | ---------------- 24 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 25 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 26 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 27 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 28 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 29 | OF SUCH DAMAGES IN ADVANCE. 30 | #> 31 | [CmdletBinding()] 32 | Param( 33 | [Parameter(Mandatory=$true, Position = 0)][String]$StrToHash, 34 | [Parameter(Mandatory=$true, Position = 1)][Int]$CharsToUse 35 | ) 36 | 37 | begin { 38 | 39 | } 40 | 41 | process { 42 | $stringAsStream = [System.IO.MemoryStream]::new() 43 | $writer = [System.IO.StreamWriter]::new($stringAsStream) 44 | $writer.write($StrToHash) 45 | $writer.Flush() 46 | $stringAsStream.Position = 0 47 | [string]$strHash = Get-FileHash -InputStream $stringAsStream | Select-Object Hash 48 | 49 | if ([Int]$CharsToUse -gt 64) { 50 | [Int]$CharsToUse = 64 51 | } 52 | 53 | Write-Host $strHash.Substring(7,[Int]$CharsToUse).ToLower() 54 | } 55 | 56 | end { 57 | 58 | } 59 | } #EndFunction TK_AzStorageAccountName 60 | 61 | # Example function call 62 | TK_AzStorageAccountName -StrToHash "Login-Consultants" -CharsToUse 12 -------------------------------------------------------------------------------- /Function Library/Function_TK_CleanupDirectory.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CleanupDirectory { 2 | <# 3 | .SYNOPSIS 4 | TK_CleanupDirectory 5 | .DESCRIPTION 6 | Delete all files and subfolders in one specific directory, but do not delete the main folder itself 7 | .PARAMETER Directory 8 | This parameter contains the full path to the directory that needs to cleaned (for example 'C:\Temp') 9 | .EXAMPLE 10 | TK_CleanupDirectory -Directory "C:\Temp" 11 | Deletes all files and subfolders in the directory 'C:\Temp' 12 | .NOTES 13 | Author : Thomas Krampe | t.krampe@loginconsultants.de 14 | Version : 1.0 15 | Creation date : 15.05.2017 | v0.1 | Initial script 16 | Last change : 15.05.2018 | v1.0 | Release 17 | 18 | IMPORTANT NOTICE 19 | ---------------- 20 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 21 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 22 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 23 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 24 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGES IN ADVANCE. 26 | #> 27 | 28 | [CmdletBinding()] 29 | Param( 30 | [Parameter(Mandatory=$true, Position = 0)][String]$Directory 31 | ) 32 | 33 | begin { 34 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 35 | Write-Verbose "START FUNCTION - $FunctionName" 36 | } 37 | 38 | process { 39 | if ( Test-Path $Directory ) { 40 | try { 41 | Remove-Item "$Directory\*.*" -force -recurse | Out-Null 42 | Remove-Item "$Directory\*" -force -recurse | Out-Null 43 | Write-Verbose "Successfully deleted all files and subfolders in the directory $Directory" 44 | } catch { 45 | Write-Verbose "An error occurred trying to delete files and subfolders in the directory $Directory (exit code: $($Error[0]))!" 46 | Exit 1 47 | } 48 | } else { 49 | Write-Verbose "The directory $Directory does not exist." 50 | } 51 | } 52 | 53 | end { 54 | Write-Verbose "END FUNCTION - $FunctionName" 55 | } 56 | } #EndFunction TK_CleanupDirectory -------------------------------------------------------------------------------- /Function Library/Function_TK_CompressDirectory.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CompressDirectory { 2 | <# 3 | .SYNOPSIS 4 | TK_CompressDirectory 5 | .DESCRIPTION 6 | Execute the process compress.exe 7 | .PARAMETER Directory 8 | his parameter contains the full path to the directory that needs to be compressed (for example C:\temp) 9 | .EXAMPLE 10 | TK_CompressDirectory -Directory "C:\temp" 11 | Compacts the directory 'C:\temp' 12 | .NOTES 13 | Author : Thomas Krampe | t.krampe@loginconsultants.de 14 | Version : 1.0 15 | Creation date : 26.07.2017 | v0.1 | Initial script 16 | Last change : 26.07.2018 | v1.0 | Release 17 | 18 | IMPORTANT NOTICE 19 | ---------------- 20 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 21 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 22 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 23 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 24 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGES IN ADVANCE. 26 | #> 27 | [CmdletBinding()] 28 | Param( 29 | [Parameter(Mandatory=$true, Position = 0)][String]$Directory 30 | ) 31 | 32 | begin { 33 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 34 | Write-Verbose "START FUNCTION - $FunctionName" $LogFile 35 | } 36 | 37 | process { 38 | Write-Verbose "Compress files in the directory $Directory" $LogFile 39 | if ( Test-Path $Directory ) { 40 | try { 41 | $params = " /C /S /I /Q /F $($Directory)\*" 42 | start-process "$WinDir\System32\compact.exe" $params -WindowStyle Hidden -Wait 43 | Write-Verbose "Successfully compressed all files in the directory $Directory" 44 | } catch { 45 | Write-Verbose "An error occurred trying to compress the files in the directory $Directory (exit code: $($Error[0]))!" 46 | Exit 1 47 | } 48 | } else { 49 | Write-verbose "The directory $Directory does not exist. Nothing to do" 50 | } 51 | } 52 | 53 | end { 54 | Write-Verbose "END FUNCTION - $FunctionName" 55 | } 56 | } #EndFunction TK_CompressDirectory -------------------------------------------------------------------------------- /Function Library/Function_TK_Confirm-DomainAdmin.ps1: -------------------------------------------------------------------------------- 1 | function TK_Confirm-DomainAdmin { 2 | <# 3 | .SYNOPSIS 4 | Confirm Domain Admin 5 | .DESCRIPTION 6 | Check if user is domain admin 7 | .PARAMETER UserName 8 | user to check, if not given current user is used 9 | .EXAMPLE 10 | TK_Confirm-DomainAdmin -UserName Thomas 11 | Check if "Thomas" is domain admin 12 | .EXAMPLE 13 | TK_Confirm-DomainAdmin 14 | Check if current user is domain admin 15 | #> 16 | 17 | [cmdletbinding()] 18 | param ( 19 | $UserName = $env:USERNAME 20 | ) 21 | begin { 22 | $domainadmins = (Get-ADGroupMember 'domain admins').samaccountname 23 | } 24 | process { 25 | foreach ($user in $UserName) { 26 | if ($user -in $domainadmins) { 27 | Write-Verbose "$User is a member of the domain admins group" 28 | $domainadmin = $true 29 | } 30 | else { 31 | Write-Verbose "$User is not a member of the domain admins group" 32 | $domainadmin = $false 33 | } 34 | 35 | [pscustomobject]@{ 36 | User = $user 37 | DomainAdmin = $domainadmin 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Function Library/Function_TK_CopyAzureVHDToAzureBlob.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CopyVHDToBlob { 2 | <# 3 | .SYNOPSIS 4 | Copy / Download a managed Azure Disk to Azure Storage account 5 | .DESCRIPTION 6 | Copy / Download a managed Azure Disk to Azure Storage account 7 | .PARAMETER SubscriptionID 8 | Azure Subscription ID eg. 11111111-2222-3333-4444-555555555555 9 | .PARAMETER ResourceGroupName 10 | The name of the ResourceGroup where the disk is stored eg. my-resources 11 | .PARAMETER ManagedDiskName 12 | The Name of the managed disk eg. test01_OsDisk_1_729ca8fexxxxxx849c2a8d89d21119db 13 | .PARAMETER DestStorageAccName 14 | The Name of the destination storage account eg. mystorage 15 | .PARAMETER DestStorageAccKey 16 | The access key for that storage account eg. 17 | .PARAMETER StorageContainerName 18 | The Name of the destination container in that storage account eg. myimages 19 | .PARAMETER VHDFileName 20 | Name of the VHD file eg. myimage.vhd 21 | .EXAMPLE 22 | TK_CopyVHDToBlob -SubscriptionID xxxx -ResourceGroupName "my-resources"" -ManagedDiskName "test01_=OsDisk_1_xxx" -DestStorageAccName "mystorage" -DestStorageAccKey "abcxxxx==" -StorageContainerName "myimages" -VHDFileName "myimage.vhd" 23 | .NOTES 24 | Author : Thomas Krampe | t.krampe@loginconsultants.de 25 | Version : 1.0 26 | Creation date : 23.08.2019 | v0.1 | Initial script 27 | Last change : 23.08.2019 | v1.0 | Release 28 | 29 | IMPORTANT NOTICE 30 | ---------------- 31 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 32 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 33 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 34 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 35 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 36 | OF SUCH DAMAGES IN ADVANCE. 37 | #> 38 | 39 | [CmdletBinding()] 40 | Param( 41 | [Parameter(Mandatory = $true, Position = 0)][String]$SubscriptionID, 42 | [Parameter(Mandatory = $true, Position = 1)][String]$ResourceGroupName, 43 | [Parameter(Mandatory = $true, Position = 2)][String]$ManagedDiskName, 44 | [Parameter(Mandatory = $true, Position = 3)][String]$DestStorageAccName, 45 | [Parameter(Mandatory = $true, Position = 4)][String]$DestStorageAccKey, 46 | [Parameter(Mandatory = $true, Position = 5)][String]$StorageContainerName, 47 | [Parameter(Mandatory = $true, Position = 6)][String]$VHDFileName 48 | ) 49 | 50 | begin { 51 | Connect-AzAccount 52 | } 53 | 54 | process { 55 | Select-AzSubscription -SubscriptionId $SubscriptionID 56 | $sas = Grant-AzDiskAccess -ResourceGroupName $ResourceGroupName -DiskName $ManagedDiskName -DurationInSecond 3600 -Access Read 57 | 58 | $destContext = New-AzStorageContext –StorageAccountName $DestStorageAccName -StorageAccountKey $DestStorageAccKey 59 | $blobcopy = Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $StorageContainerName -DestContext $destContext -DestBlob $VHDFileName 60 | 61 | while (($blobCopy | Get-AzStorageBlobCopyState).Status -eq "Pending") { 62 | Start-Sleep -s 30 63 | $blobCopy | Get-AzStorageBlobCopyState 64 | } 65 | } 66 | 67 | end { 68 | 69 | } 70 | } #EndFunction TK_CopyVHDToBlob 71 | 72 | # Usage Example 73 | $HLSubscriptionID = "11111111-2222-3333-4444-555555555555" 74 | $HLResourceGroupName = "myresources" 75 | $HLManagedDiskName = "test01_OsDisk_1_xxxxxxxxxxxxxxxdb" 76 | $HLDestStorageAccName = "mystorage" 77 | $HLDestStorageAccKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==" 78 | $HLStorageContainerName = "myimages" 79 | $HLVHDFileName = "myimage.vhd" 80 | 81 | # Function Call 82 | TK_CopyVHDToBlob -SubscriptionID $HLSubscriptionID -ResourceGroupName $HLResourceGroupName -ManagedDiskName $HLManagedDiskName -DestStorageAccName $HLDestStorageAccName -DestStorageAccKey $HLDestStorageAccKey -StorageContainerName $HLStorageContainerName -VHDFileName $HLVHDFileName -------------------------------------------------------------------------------- /Function Library/Function_TK_CreateDirectory.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CreateDirectory { 2 | <# 3 | .SYNOPSIS 4 | TK_CreateDirectory 5 | .DESCRIPTION 6 | Create a new directory 7 | .PARAMETER Directory 8 | This parameter contains the name of the new directory including the full path (for example C:\Temp\MyNewFolder). 9 | .EXAMPLE 10 | TK_CreateDirectory -Directory "C:\Temp\MyNewFolder" 11 | Creates the new directory "C:\Temp\MyNewFolder" 12 | .NOTES 13 | Author : Thomas Krampe | t.krampe@loginconsultants.de 14 | Version : 1.0 15 | Creation date : 26.07.2018 | v0.1 | Initial script 16 | Last change : 26.07.2018 | v1.0 | Release 17 | 18 | IMPORTANT NOTICE 19 | ---------------- 20 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 21 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 22 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 23 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 24 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGES IN ADVANCE. 26 | #> 27 | 28 | [CmdletBinding()] 29 | Param( 30 | [Parameter(Mandatory=$true, Position = 0)][String]$Directory 31 | ) 32 | 33 | begin { 34 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 35 | Write-Verbose "START FUNCTION - $FunctionName" 36 | } 37 | 38 | process { 39 | Write-verbose "Create directory $Directory" 40 | if ( Test-Path $Directory ) { 41 | Write-Verbose "The directory $Directory already exists." 42 | } else { 43 | try { 44 | New-Item -ItemType Directory -Path $Directory -force | Out-Null 45 | Write-Verbose "Successfully created the directory $Directory." 46 | } catch { 47 | Write-Error "An error occurred trying to create the directory $Directory (exit code: $($Error[0]))!" 48 | Exit 1 49 | } 50 | } 51 | } 52 | 53 | end { 54 | Write-Verbose "END FUNCTION - $FunctionName" 55 | } 56 | } #EndFunction TK_CreateDirectory -------------------------------------------------------------------------------- /Function Library/Function_TK_CreateFolderFromCSV.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CreateFolderFromCSV { 2 | <# 3 | .SYNOPSIS 4 | TK_CreateFolderFromCSV 5 | .DESCRIPTION 6 | Create user folders from CSV file 7 | 8 | Example CSV 9 | user,password,realname 10 | homer,Password!,Homer Simpson 11 | bart,Password!,Bart Simpson 12 | .PARAMETER CSVFile 13 | Full path to the CSV file eg. C:\Temp\userlist.csv 14 | .PARAMETER TargetPath 15 | Root path for folder creation eg. C:\Users 16 | .EXAMPLE 17 | TK_CreateFolderFromCSV -CSVFile "C:\Temp\userlist.csv" - TargetPath "C:\Users" 18 | .LINK 19 | https://github.com/thomaskrampe/PowerShell/blob/master/User%20Profiles/TK_CreateUserFolderFromCSV.ps1 20 | .NOTES 21 | Author : Thomas Krampe | thomas.krampe@myctx.net 22 | Version : 1.0 23 | Creation date : 21.02.2019 | v0.1 | Initial script 24 | Last change : 21.02.2019 | v1.0 | Add script documentation 25 | 26 | IMPORTANT NOTICE 27 | ---------------- 28 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 29 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 30 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 31 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 32 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 33 | OF SUCH DAMAGES IN ADVANCE. 34 | 35 | #> 36 | 37 | [CmdletBinding()] 38 | Param( 39 | [Parameter(Mandatory=$true)][String]$CSVFile, 40 | [Parameter(Mandatory=$true)][String]$TargetPath 41 | ) 42 | 43 | begin { 44 | } 45 | 46 | process { 47 | $CSVSource = Import-CSV -Path $CSVFile -Delimiter "," 48 | 49 | foreach ($CSVObject in $CSVSource) { 50 | $CreateFolder = $TargetPath + "\" + $($CSVObject.User) 51 | Write-Verbose "Creating folder $CreateFolder." 52 | New-Item -ItemType directory -Path $CreateFolder | Out-Null 53 | if ( $(Try { Test-Path $CreateFolder.trim() } Catch { $false }) ) { 54 | Write-Verbose "Folder $CreateFolder created successful." 55 | } 56 | Else { 57 | Write-Error "Creating folder $CreateFolder failed." -targetobject $_ -Category WriteError -RecommendedAction "Maybe missing permissions." 58 | } 59 | } 60 | } 61 | 62 | end { 63 | } 64 | } #EndFunction TK_CreateFolderFromCSV 65 | -------------------------------------------------------------------------------- /Function Library/Function_TK_DeleteDirectory.ps1: -------------------------------------------------------------------------------- 1 | Function TK_DeleteDirectory { 2 | <# 3 | .SYNOPSIS 4 | TK_DeleteDirectory 5 | .DESCRIPTION 6 | Delete a directory 7 | .PARAMETER Directory 8 | This parameter contains the full path to the directory which needs to be deleted (for example C:\Temp\MyFolder). 9 | .EXAMPLE 10 | TK_DeleteDirectory -Directory "C:\Temp\MyFolder" 11 | Deletes the directory "C:\Temp\MyFolder" 12 | .NOTES 13 | Author : Thomas Krampe | t.krampe@loginconsultants.de 14 | Version : 1.0 15 | Creation date : 26.07.2018 | v0.1 | Initial script 16 | Last change : 26.07.2018 | v1.0 | Release 17 | 18 | IMPORTANT NOTICE 19 | ---------------- 20 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 21 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 22 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 23 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 24 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGES IN ADVANCE. 26 | #> 27 | 28 | [CmdletBinding()] 29 | Param( 30 | [Parameter(Mandatory=$true, Position = 0)][String]$Directory 31 | ) 32 | 33 | begin { 34 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 35 | Write-Verbose "START FUNCTION - $FunctionName" 36 | } 37 | 38 | process { 39 | Write-Verbose "Delete directory $Directory" 40 | if ( Test-Path $Directory ) { 41 | try { 42 | Remove-Item $Directory -force -recurse | Out-Null 43 | Write-Verbose "Successfully deleted the directory $Directory" 44 | } catch { 45 | Write-Error "An error occurred trying to delete the directory $Directory (exit code: $($Error[0]))!" 46 | Exit 1 47 | } 48 | } else { 49 | Write-Verbose "The directory $Directory does not exist. Nothing to do" 50 | } 51 | } 52 | 53 | end { 54 | Write-Verbose "END FUNCTION - $FunctionName" 55 | } 56 | } #EndFunction TK_DeleteDirectory -------------------------------------------------------------------------------- /Function Library/Function_TK_DeleteFile.ps1: -------------------------------------------------------------------------------- 1 | Function TK_DeleteFile { 2 | <# 3 | .SYNOPSIS 4 | TK_DeleteFile 5 | .DESCRIPTION 6 | Delete files 7 | .PARAMETER File 8 | This parameter contains the full path to the file that needs to be deleted (for example C:\Temp\MyFile.txt). 9 | .EXAMPLE 10 | TK_DeleteFile -File "C:\Temp\*.txt" 11 | Deletes all files in the directory "C:\Temp" that have the file extension *.txt. *.txt. Files stored within subfolders of 'C:\Temp' are NOT deleted 12 | .NOTES 13 | Author : Thomas Krampe | t.krampe@loginconsultants.de 14 | Version : 1.0 15 | Creation date : 26.07.2018 | v0.1 | Initial script 16 | Last change : 26.07.2018 | v1.0 | Release 17 | 18 | IMPORTANT NOTICE 19 | ---------------- 20 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 21 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 22 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 23 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 24 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGES IN ADVANCE. 26 | #> 27 | 28 | [CmdletBinding()] 29 | Param( 30 | [Parameter(Mandatory=$true, Position = 0)][String]$File 31 | ) 32 | 33 | begin { 34 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 35 | Write-Verbose "START FUNCTION - $FunctionName" 36 | } 37 | 38 | process { 39 | Write-Verbose "Delete the file '$File'" 40 | if ( Test-Path $File ) { 41 | try { 42 | Remove-Item "$File" | Out-Null 43 | Write-Verbose "Successfully deleted the file '$File'" 44 | } catch { 45 | Write-Error "An error occurred trying to delete the file '$File' (exit code: $($Error[0]))!" 46 | Exit 1 47 | } 48 | } else { 49 | Write-Verbose "The file '$File' does not exist. Nothing to do" 50 | } 51 | } 52 | 53 | end { 54 | Write-Verbose "END FUNCTION - $FunctionName" 55 | } 56 | } #EndFunction TK_DeleteFile -------------------------------------------------------------------------------- /Function Library/Function_TK_Get-CurrentWeek.ps1: -------------------------------------------------------------------------------- 1 | function TK_Get-CurrentWeek { 2 | <# 3 | .SYNOPSIS 4 | Get current calendar week 5 | 6 | .DESCRIPTION 7 | Get current calendar week 8 | 9 | .EXAMPLE 10 | $CurrentWeek = TK_Get-CurrentWeek 11 | 12 | .NOTES 13 | Author : Thomas Krampe | t.krampe@loginconsultants.de 14 | Version : 1.0 15 | Creation date : 26.07.2018 | v0.1 | Initial script 16 | Last change : 07.09.2018 | v1.0 | Create the script header 17 | 18 | 19 | IMPORTANT NOTICE 20 | ---------------- 21 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 22 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 23 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 24 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 25 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 26 | OF SUCH DAMAGES IN ADVANCE. 27 | 28 | .RETURN 29 | Current week number 30 | #> 31 | 32 | $CurrentWeek = [System.Globalization.DateTimeFormatInfo]::CurrentInfo.Calendar.GetWeekOfYear([datetime]::Now,0,0) 33 | 34 | Return $CurrentWeek 35 | } #Endfunction TK_Get-CurrentWeek -------------------------------------------------------------------------------- /Function Library/Function_TK_IsAdmin.ps1: -------------------------------------------------------------------------------- 1 | function TK_IsAdmin { 2 | <# 3 | .SYNOPSIS 4 | TK_IsAdmin 5 | .DESCRIPTION 6 | Check if the user running this script has admin permissions 7 | .EXAMPLE 8 | TK_IsAdmin 9 | .RETURN 10 | $True or $False 11 | .NOTES 12 | Author : Thomas Krampe | t.krampe@loginconsultants.de 13 | Version : 1.1 14 | Creation date : 26.07.2018 | v0.1 | Initial script 15 | Last change : 26.07.2018 | v1.1 | Release 16 | 17 | IMPORTANT NOTICE 18 | ---------------- 19 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 20 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 21 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 22 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 23 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 24 | OF SUCH DAMAGES IN ADVANCE. 25 | #> 26 | 27 | begin { 28 | } 29 | 30 | process { 31 | ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") 32 | } 33 | 34 | end { 35 | } 36 | 37 | } #Endfunction TK_IsAdmin -------------------------------------------------------------------------------- /Function Library/Function_TK_LoadModule.ps1: -------------------------------------------------------------------------------- 1 | Function TK_LoadModule { 2 | <# 3 | .SYNOPSIS 4 | TK_LoadModule 5 | .DESCRIPTION 6 | Import a Powershell module from disk, if not present install from powershell gallery. 7 | .PARAMETER ModuleName 8 | The name of the PowerShell module 9 | .EXAMPLE 10 | TK_LoadModule -ModuleName AzureAD 11 | Import module if possible. Otherwise try to install from local or, if not available local, from PowerShell Gallery 12 | .NOTES 13 | Author : Thomas Krampe | t.krampe@loginconsultants.de 14 | Version : 1.0 15 | Creation date : 05.08.2019 | v0.1 | Initial script 16 | Last change : 06.08.2019 | v1.0 | Release 17 | 18 | IMPORTANT NOTICE 19 | ---------------- 20 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 21 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 22 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 23 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 24 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 25 | OF SUCH DAMAGES IN ADVANCE. 26 | #> 27 | 28 | [CmdletBinding()] 29 | 30 | Param( 31 | [Parameter(Mandatory = $true, Position = 0)][String]$ModuleName 32 | ) 33 | 34 | begin { 35 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 36 | Write-Verbose "START FUNCTION - $FunctionName" 37 | } 38 | 39 | process { 40 | # If module is already imported there is nothing to do. 41 | if (Get-Module | Where-Object { $_.Name -eq $ModuleName }) { 42 | Write-Verbose "Module $ModuleName is already imported." 43 | } 44 | else { 45 | 46 | # If module is not imported, but available on disk then import 47 | if (Get-Module -ListAvailable | Where-Object { $_.Name -eq $ModuleName }) { 48 | Import-Module $ModuleName -Verbose 49 | } 50 | else { 51 | 52 | # If module is not imported, not available on disk, but is in online gallery then install and import 53 | if (Find-Module -Name $ModuleName | Where-Object { $_.Name -eq $ModuleName }) { 54 | Install-Module -Name $ModuleName -Force -Verbose -Scope CurrentUser 55 | Import-Module $ModuleName -Verbose 56 | } 57 | else { 58 | 59 | # If module is still not available then abort with exit code 1 60 | Write-Warning "Module $ModuleName not imported, not local available and not in online gallery, exiting." 61 | EXIT 1 62 | } 63 | } 64 | } 65 | } 66 | 67 | end { 68 | Write-Verbose "END FUNCTION - $FunctionName" 69 | } 70 | } #EndFunction TK_LoadModule -------------------------------------------------------------------------------- /Function Library/Function_TK_ReadFromINI.ps1: -------------------------------------------------------------------------------- 1 | Function TK_ReadFromINI { 2 | <# 3 | .SYNOPSIS 4 | TK_ReadFromINI 5 | .DESCRIPTION 6 | Get values from INI file 7 | 8 | Example INI 9 | ----------- 10 | [owner] 11 | name=Thomas Krampe 12 | organization=MyCTX 13 | 14 | [informations] 15 | hostname=sqlserver 16 | ipaddress=192.168.1.2 17 | 18 | .PARAMETER filePath 19 | Full path to the INI file eg. C:\Temp\server.ini 20 | .EXAMPLE 21 | $INIValues = TK_ReadFromINI -filePath "C:\Temp\server.ini" 22 | 23 | You can then access values like this: 24 | $Server = $INIValues.informations.server 25 | $Organization = $INIValues.owner.organization 26 | 27 | .LINK 28 | https://github.com/thomaskrampe/PowerShell/blob/master/User%20Profiles/TK_ReadFromINI.ps1 29 | .NOTES 30 | Author : Thomas Krampe | thomas.krampe@myctx.net 31 | Version : 1.0 32 | Creation date : 21.02.2019 | v0.1 | Initial script 33 | Last change : 21.02.2019 | v1.0 | Add script documentation 34 | 35 | IMPORTANT NOTICE 36 | ---------------- 37 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 38 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 39 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 40 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 41 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 42 | OF SUCH DAMAGES IN ADVANCE. 43 | 44 | #> 45 | 46 | [CmdletBinding()] 47 | 48 | Param( 49 | [Parameter(Mandatory=$true)][String]$filePath 50 | ) 51 | 52 | begin { 53 | } 54 | 55 | process { 56 | 57 | $anonymous = "NoSection" 58 | $ini = @{} 59 | switch -regex -file $filePath 60 | { 61 | "^\[(.+)\]$" # Section 62 | { 63 | $section = $matches[1] 64 | $ini[$section] = @{} 65 | $CommentCount = 0 66 | } 67 | 68 | "^(;.*)$" # Comment 69 | { 70 | if (!($section)) { 71 | $section = $anonymous 72 | $ini[$section] = @{} 73 | } 74 | $value = $matches[1] 75 | $CommentCount = $CommentCount + 1 76 | $name = "Comment" + $CommentCount 77 | $ini[$section][$name] = $value 78 | } 79 | 80 | "(.+?)\s*=\s*(.*)" # Key 81 | { 82 | if (!($section)) { 83 | $section = $anonymous 84 | $ini[$section] = @{} 85 | } 86 | $name,$value = $matches[1..2] 87 | $ini[$section][$name] = $value 88 | } 89 | } 90 | return $ini 91 | 92 | } 93 | 94 | end { 95 | } 96 | } #EndFunction TK_ReadFromINI -------------------------------------------------------------------------------- /Function Library/Function_TK_RemoveWVDHostPool.ps1: -------------------------------------------------------------------------------- 1 | Function TK_RemoveWVDHostPool { 2 | <# 3 | .SYNOPSIS 4 | TK_RemoveWVDHostPool 5 | .DESCRIPTION 6 | Delete a Windows Virtual Desktop RDS Host Pool in Azure 7 | .PARAMETER TenantName 8 | The Name of the WVD Tenant (you can get this with the Get-RdsTenant cmdlet) 9 | .PARAMETER HostPoolName 10 | The Name of the host pool (you can get this with the Get-RdsHostPool -TenantName xxx cmdlet) 11 | .EXAMPLE 12 | TK_RemoveWVDHostPool -TenantName MyTenant -HostPoolName MyHostPool 13 | This call remove the Application Group as well as the session host server associated to the Host Pool and finally the hpst pool itself. 14 | .NOTES 15 | Author : Thomas Krampe | t.krampe@loginconsultants.de 16 | Version : 1.0 17 | Creation date : 15.08.2019 | v0.1 | Initial script 18 | Last change : 15.08.2019 | v1.0 | Release 19 | 20 | IMPORTANT NOTICE 21 | ---------------- 22 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 23 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 24 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 25 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 26 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 27 | OF SUCH DAMAGES IN ADVANCE. 28 | #> 29 | 30 | [CmdletBinding()] 31 | Param( 32 | [Parameter(Mandatory = $true, Position = 0)][String]$TenantName, 33 | [Parameter(Mandatory = $true, Position = 1)][String]$HostPoolName 34 | ) 35 | 36 | begin { 37 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 38 | Write-Verbose "START FUNCTION - $FunctionName" 39 | 40 | [string]$ModuleName = "Microsoft.RDInfra.RDPowerShell" 41 | 42 | # If module is already imported there is nothing to do. 43 | if (Get-Module | Where-Object { $_.Name -eq $ModuleName }) { 44 | Write-Verbose "Module $ModuleName is already imported." 45 | } 46 | else { 47 | 48 | # If module is not imported, but available on disk then import 49 | if (Get-Module -ListAvailable | Where-Object { $_.Name -eq $ModuleName }) { 50 | Import-Module $ModuleName -Verbose 51 | } 52 | else { 53 | 54 | # If module is not imported, not available on disk, but is in online gallery then install and import 55 | if (Find-Module -Name $ModuleName | Where-Object { $_.Name -eq $ModuleName }) { 56 | Install-Module -Name $ModuleName -Verbose 57 | Import-Module $ModuleName -Verbose 58 | } 59 | else { 60 | 61 | # If module is still not available then abort with exit code 1 62 | Write-Warning "Module $ModuleName not imported, not local available and not in online gallery, exiting." 63 | EXIT 1 64 | } 65 | } 66 | } 67 | 68 | # Login to the Windows Virtual Desktop Tenant 69 | Add-RdsAccount -DeploymentUrl "https://rdbroker.wvd.microsoft.com" 70 | } 71 | 72 | process { 73 | # Do some pre-checks 74 | [string]$TenantCheck = (Get-RdsTenant).TenantName 75 | 76 | If ($TenantName -ne $TenantCheck) { 77 | Write-Error "Tenant name mismatch. Please verify the tenant name and try again." 78 | Exit 1 79 | } 80 | 81 | [string]$HostPoolCheck = (Get-RdsHostPool -TenantName $TenantName).HostPoolName 82 | 83 | If ($HostPoolName -ne $HostPoolCheck) { 84 | Write-Error "Host pool name mismatch. Please verify the host pool name and try again." 85 | Exit 1 86 | } 87 | 88 | # Remove Application Group associated to the Host Pool 89 | Get-RdsAppGroup -TenantName $TenantName -HostPoolName $HostPoolName | Remove-RdsAppGroup 90 | # Remove Session Host servers associated to the Host Pool 91 | Get-RdsSessionHost -TenantName $TenantName -HostPoolName $HostPoolName | Remove-RdsSessionHost 92 | # Remove the Host Pool 93 | Get-RdsHostPool -TenantName $TenantName -HostPoolName $HostPoolName | Remove-RdsHostPool 94 | } 95 | 96 | end { 97 | 98 | } 99 | } #EndFunction TK_RemoveWVDHostPool 100 | 101 | 102 | -------------------------------------------------------------------------------- /Function Library/Function_TK_SendMail.ps1: -------------------------------------------------------------------------------- 1 | Function TK_SendMail { 2 | <# 3 | .SYNOPSIS 4 | TK_SendMail 5 | .DESCRIPTION 6 | Send an e-mail to one or more recipients. 7 | .PARAMETER Sender 8 | This parameter contains the e-mail address of the sender (e.g. mymail@mydomain.com). 9 | .PARAMETER Recipients 10 | This parameter contains the e-mail address or addresses of the recipients (e.g. "@mycompany.com" or "@mycompany.com", "@mycompany.com") 11 | .PARAMETER Subject 12 | This parameter contains the subject of the e-mail 13 | .PARAMETER Text 14 | This parameter contains the body of the e-mail 15 | .PARAMETER SMTPServer 16 | This parameter contains the name or the IP-address of the SMTP server (e.g. 'smtp.mycompany.com') 17 | .EXAMPLE 18 | TK_SendMail -Sender "me@mycompany.com" -Recipients "someone@mycompany.com" -Subject "Something important" -Text "This is the text for the e-mail" -SMTPServer "smtp.mycompany.com" 19 | Sends an e-mail to one recipient 20 | .EXAMPLE 21 | TK_SendMail -Sender "me@mycompany.com" -Recipients "someone@mycompany.com","someoneelse@mycompany.com" -Subject "Something important" -Text "This is the text for the e-mail" -SMTPServer "smtp.mycompany.com" 22 | Sends an e-mail to two recipients 23 | .NOTES 24 | Author : Thomas Krampe | t.krampe@loginconsultants.de 25 | Version : 1.0 26 | Creation date : 26.07.2018 | v0.1 | Initial script 27 | Last change : 26.07.2018 | v1.0 | Release 28 | 29 | IMPORTANT NOTICE 30 | ---------------- 31 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 32 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 33 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 34 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 35 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 36 | OF SUCH DAMAGES IN ADVANCE. 37 | #> 38 | 39 | [CmdletBinding()] 40 | Param( 41 | [Parameter(Mandatory=$true, Position = 0)][String]$Sender, 42 | [Parameter(Mandatory=$true, Position = 1)][String[]]$Recipients, 43 | [Parameter(Mandatory=$true, Position = 2)][String]$Subject, 44 | [Parameter(Mandatory=$true, Position = 3)][String]$Text, 45 | [Parameter(Mandatory=$true, Position = 4)][String]$SMTPServer 46 | ) 47 | 48 | begin { 49 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 50 | Write-Verbose "START FUNCTION - $FunctionName" 51 | } 52 | 53 | process { 54 | try { 55 | Send-MailMessage -From $Sender -to $Recipients -subject $Subject -body $Text -smtpServer $SMTPServer -BodyAsHtml 56 | Write-Verbose "E-mail successfully sent." 57 | Exit 0 58 | } catch { 59 | Write-Error "An error occurred trying to send the e-mail (exit code: $($Error[0]))!" 60 | Exit 1 61 | } 62 | } 63 | 64 | end { 65 | Write-Verbose "END FUNCTION - $FunctionName" 66 | } 67 | } #EndFunction TK_SendMail -------------------------------------------------------------------------------- /Function Library/Function_TK_WriteLog.ps1: -------------------------------------------------------------------------------- 1 | function TK_WriteLog { 2 | <# 3 | .SYNOPSIS 4 | Write text to log file 5 | .DESCRIPTION 6 | Write text to this script's log file 7 | .PARAMETER InformationType 8 | This parameter contains the information type prefix. Possible prefixes and information types are: 9 | I = Information 10 | S = Success 11 | W = Warning 12 | E = Error 13 | - = No status 14 | .PARAMETER Text 15 | This parameter contains the text (the line) you want to write to the log file. If text in the parameter is omitted, an empty line is written. 16 | .PARAMETER LogFile 17 | This parameter contains the full path, the file name and file extension to the log file (e.g. C:\Logs\MyApps\MylogFile.log) 18 | .EXAMPLE 19 | TK_WriteLog -$InformationType "I" -Text "Copy files to C:\Temp" -LogFile "C:\Logs\MylogFile.log" 20 | Writes a line containing information to the log file 21 | .EXAMPLE 22 | TK_WriteLog -$InformationType "E" -Text "An error occurred trying to copy files to C:\Temp (error: $($Error[0]))" -LogFile "C:\Logs\MylogFile.log" 23 | Writes a line containing error information to the log file 24 | .EXAMPLE 25 | TK_WriteLog -$InformationType "-" -Text "" -LogFile "C:\Logs\MylogFile.log" 26 | Writes an empty line to the log file 27 | .NOTES 28 | Author : Thomas Krampe | t.krampe@loginconsultants.de 29 | Version : 1.0 30 | Creation date : 26.07.2018 | v0.1 | Initial script 31 | Last change : 07.09.2018 | v1.0 | Fix some minor typos 32 | 33 | IMPORTANT NOTICE 34 | ---------------- 35 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 36 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 37 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 38 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 39 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 40 | OF SUCH DAMAGES IN ADVANCE. 41 | #> 42 | 43 | [CmdletBinding()] 44 | Param( 45 | [Parameter(Mandatory=$true, Position = 0)][ValidateSet("I","S","W","E","-",IgnoreCase = $True)][String]$InformationType, 46 | [Parameter(Mandatory=$true, Position = 1)][AllowEmptyString()][String]$Text, 47 | [Parameter(Mandatory=$true, Position = 2)][AllowEmptyString()][String]$LogFile 48 | ) 49 | 50 | begin { 51 | } 52 | 53 | process { 54 | $DateTime = (Get-Date -format dd-MM-yyyy) + " " + (Get-Date -format HH:mm:ss) 55 | 56 | if ( $Text -eq "" ) { 57 | Add-Content $LogFile -value ("") 58 | } Else { 59 | Add-Content $LogFile -value ($DateTime + " " + $InformationType.ToUpper() + " - " + $Text) 60 | } 61 | } 62 | 63 | end { 64 | } 65 | 66 | 67 | } #EndFunction TK_WriteLog 68 | 69 | #region Log handling 70 | # ------------------------------------------------------------------------------------------------- 71 | # Log handling 72 | # To use the function above in your own script, make sure that you prepare your log file directory. 73 | # ------------------------------------------------------------------------------------------------- 74 | $LogDir = "C:\_Logs" 75 | $ScriptName = "CitrixCloudAutomation" 76 | $DateTime = Get-Date -uformat "%Y-%m-%d_%H-%M" 77 | $LogFileName = "$ScriptName"+"$DateTime.log" 78 | $LogFile = Join-path $LogDir $LogFileName 79 | 80 | # Create the log directory if it does not exist 81 | if (!(Test-Path $LogDir)) { New-Item -Path $LogDir -ItemType directory | Out-Null } 82 | 83 | # Create new log file (overwrite existing one) 84 | New-Item $LogFile -ItemType "file" -force | Out-Null 85 | #endregion 86 | 87 | -------------------------------------------------------------------------------- /Function Library/Function_TK_WriteToEventLog.ps1: -------------------------------------------------------------------------------- 1 | Function TK_WriteToEventLog { 2 | <# 3 | .SYNOPSIS 4 | TK_WriteToEventLog 5 | .DESCRIPTION 6 | Write an entry into the Windows event log. New event logs as well as new event sources are automatically created. 7 | .PARAMETER EventLog 8 | This parameter contains the name of the event log the entry should be written to (e.g. Application, Security, System or a custom one) 9 | .PARAMETER Source 10 | This parameter contains the source (e.g. 'MyScript') 11 | .PARAMETER EventID 12 | This parameter contains the event ID number (e.g. 3000) 13 | .PARAMETER Type 14 | This parameter contains the type of message. Possible values are: Information | Warning | Error 15 | .PARAMETER Message 16 | This parameter contains the event log description explaining the issue 17 | .EXAMPLE 18 | TK_WriteToEventLog -EventLog "System" -Source "MyScript" -EventID "3000" -Type "Error" -Message "An error occurred" 19 | Write an error message to the System event log with the source 'MyScript' and event ID 3000. The unknown source 'MyScript' is automatically created 20 | .EXAMPLE 21 | TK_WriteToEventLog -EventLog "Application" -Source "Something" -EventID "250" -Type "Information" -Message "Information: action completed successfully" 22 | Write an information message to the Application event log with the source 'Something' and event ID 250. The unknown source 'Something' is automatically created 23 | .EXAMPLE 24 | TK_WriteToEventLog -EventLog "MyNewEventLog" -Source "MyScript" -EventID "1000" -Type "Warning" -Message "Warning. There seems to be an issue" 25 | Write an warning message to the event log called 'MyNewEventLog' with the source 'MyScript' and event ID 1000. The unknown event log 'MyNewEventLog' and source 'MyScript' are automatically created 26 | .NOTES 27 | Author : Thomas Krampe | t.krampe@loginconsultants.de 28 | Version : 1.0 29 | Creation date : 26.07.2018 | v0.1 | Initial script 30 | Last change : 26.07.2018 | v1.0 | Release 31 | 32 | IMPORTANT NOTICE 33 | ---------------- 34 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 35 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 36 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 37 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 38 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 39 | OF SUCH DAMAGES IN ADVANCE. 40 | #> 41 | 42 | [CmdletBinding()] 43 | Param( 44 | [parameter(mandatory=$True)] 45 | [ValidateNotNullorEmpty()] 46 | [String]$EventLog, 47 | [parameter(mandatory=$True)] 48 | [ValidateNotNullorEmpty()] 49 | [String]$Source, 50 | [parameter(mandatory=$True)] 51 | [Int]$EventID, 52 | [parameter(mandatory=$True)] 53 | [ValidateNotNullorEmpty()] 54 | [String]$Type, 55 | [parameter(mandatory=$True)] 56 | [ValidateNotNullorEmpty()] 57 | [String]$Message 58 | ) 59 | 60 | begin { 61 | [string]$FunctionName = $PSCmdlet.MyInvocation.MyCommand.Name 62 | Write-Verbose "START FUNCTION - $FunctionName" 63 | } 64 | 65 | process { 66 | # Check if the event log exist. If not, create it. 67 | Write-Verbose "Check if the event log $EventLog exists. If not, create it" 68 | if ( !( [System.Diagnostics.EventLog]::Exists( $EventLog ) ) ) { 69 | Write-Verbose "The event log '$EventLog' does not exist." 70 | try { 71 | New-EventLog -LogName $EventLog -Source $EventLog 72 | Write-Verbose "The event log '$EventLog' was created successfully" 73 | } catch { 74 | Write-Verbose "An error occurred trying to create the event log '$EventLog' (error: $($Error[0]))!" 75 | 76 | } 77 | } else { 78 | Write-Verbose "The event log '$EventLog' already exists." 79 | } 80 | 81 | # Check if the event source exist. If not, create it. 82 | Write-Verbose "Check if the event source '$Source' exists. If not, create it." 83 | if ( !( [System.Diagnostics.EventLog]::SourceExists( $Source ) ) ) { 84 | Write-Verbose "The event source '$Source' does not exist." 85 | try { 86 | [System.Diagnostics.EventLog]::CreateEventSource( $Source, $EventLog ) 87 | Write-Verbose "The event source '$Source' was created successfully." 88 | } catch { 89 | Write-Verbose "An error occurred trying to create the event source '$Source' (error: $($Error[0]))!" 90 | } 91 | } else { 92 | Write-verbose "The event source '$Source' already exists." 93 | } 94 | 95 | # Write the event log entry 96 | Write-Verbose "Write the event log entry." 97 | try { 98 | Write-EventLog -LogName $EventLog -Source $Source -eventID $EventID -EntryType $Type -message $Message 99 | Write-Verbose "The event log entry was written successfully." 100 | } catch { 101 | Write-Verbose "An error occurred trying to write the event log entry (error: $($Error[0]))!" 102 | } 103 | } 104 | 105 | end { 106 | Write-Verbose "END FUNCTION - $FunctionName" 107 | } 108 | } #EndFunction TK_WriteToEventLog -------------------------------------------------------------------------------- /Function Library/Function_TK_check-even-odd.ps1: -------------------------------------------------------------------------------- 1 | Function TK_check-even-odd ($num) {[bool]!($num%2)} 2 | 3 | # Example script using the function above 4 | $Computers = "LAB5003XA01", "LAB5003XA02", "LAB5003XA03", "LAB5003XA04", "LAB5003XA05" 5 | 6 | foreach ($computer in $computers) { 7 | if ($computer -like "LAB5003XA*") { 8 | [int]$ComputerNum = $computer.Substring($computer.Length - 2) 9 | 10 | if((TK_check-even-odd $computerNum) -eq $true) { 11 | #even hostname ending 12 | "Do something for even computer: {0}" -f $computer 13 | } 14 | else { 15 | #odd hostname ending 16 | "Do something for odd computer: {0}" -f $computer 17 | } 18 | } 19 | else { 20 | "Computer does not meet naming standards: {0}" -f $computer 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Function Library/ModifyProxySettings.ps1: -------------------------------------------------------------------------------- 1 | #requires -runasadministrator 2 | 3 | <# 4 | .Synopsis 5 | Modify proxy settings for the current user. 6 | 7 | .DESCRIPTION 8 | Modify proxy settings for the current user modifying the windows registry. 9 | 10 | .EXAMPLE 11 | Get the proxy settings for the current user 12 | 13 | PS D:\> get-proxy 14 | ProxyServer ProxyEnable 15 | ----------- ----------- 16 | 0 17 | 18 | .EXAMPLE 19 | Set the proxy server for the current user. Test the address and if the TCP Port is open before applying the settings. 20 | proxy squid.server.com 3128 21 | set-proxy -server "yourproxy.server.com" -port 3128 22 | 23 | .EXAMPLE 24 | Remove the current proxy settings for the user. 25 | 26 | .NOTES 27 | Author Paolo Frigo, https://www.scriptinglibrary.com 28 | #> 29 | 30 | function Get-Proxy (){ 31 | Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' | Select-Object ProxyServer, ProxyEnable 32 | } 33 | 34 | function Set-Proxy { 35 | [CmdletBinding()] 36 | [Alias('proxy')] 37 | [OutputType([string])] 38 | Param 39 | ( 40 | # server address 41 | [Parameter(Mandatory = $true, 42 | ValueFromPipelineByPropertyName = $true, 43 | Position = 0)] 44 | $server, 45 | # port number 46 | [Parameter(Mandatory = $true, 47 | ValueFromPipelineByPropertyName = $true, 48 | Position = 1)] 49 | $port 50 | ) 51 | #Test if the TCP Port on the server is open before applying the settings 52 | If ((Test-NetConnection -ComputerName $server -Port $port).TcpTestSucceeded) { 53 | Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyServer -Value "$($server):$($port)" 54 | Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyEnable -Value 1 55 | Get-Proxy #Show the configuration 56 | } 57 | Else { 58 | Write-Error -Message "The proxy address is not valid: $($server):$($port)" 59 | } 60 | } 61 | 62 | function Remove-Proxy (){ 63 | Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyServer -Value "" 64 | Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyEnable -Value 0 65 | } 66 | 67 | -------------------------------------------------------------------------------- /Function Library/_TemplateForYourOwnFunctions.ps1: -------------------------------------------------------------------------------- 1 | Function ShortURL { 2 | <# 3 | .SYNOPSIS 4 | Name of the Function 5 | .DESCRIPTION 6 | Short Function description 7 | .PARAMETER Param1 8 | Parameter description 9 | .PARAMETER Param2 10 | Parameter ... description 11 | .EXAMPLE 12 | Usage example 13 | .NOTES 14 | Author : Name | E-Mail 15 | Version : 1.0 16 | Creation date : 31.12.2018 | v0.1 | Initial script 17 | Last change : 31.12.2018 | v1.0 | Release 18 | 19 | IMPORTANT NOTICE 20 | ---------------- 21 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 22 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 23 | LOGIN CONSULTANTS, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 24 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 25 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF LOGIN CONSULTANTS HAS BEEN ADVISED OF THE POSSIBILITY 26 | OF SUCH DAMAGES IN ADVANCE. 27 | #> 28 | 29 | [CmdletBinding()] 30 | Param( 31 | [Parameter(Mandatory=$true, Position = 0)][String]$longurl 32 | ) 33 | 34 | begin { 35 | 36 | } 37 | 38 | process { 39 | 40 | $url ="http://t13k.de/yourls-api.php?signature=9695dd257c&action=shorturl&format=simple&url=$longurl" 41 | $request = Invoke-WebRequest $url 42 | $request.Content 43 | } 44 | 45 | end { 46 | 47 | } 48 | } #EndFunction ShortURL 49 | 50 | ShortURL "https://www.example.com" -------------------------------------------------------------------------------- /Github/TK_DownloadFilesFromGithubRepo.ps1: -------------------------------------------------------------------------------- 1 | function TK_DownloadFilesFromRepo { 2 | <# 3 | .SYNOPSIS 4 | TK_DownloadFilesFromRepo 5 | .DESCRIPTION 6 | Download a file from a public github repository 7 | .PARAMETER Owner 8 | The owner of the reporitory 9 | .PARAMETER Repository 10 | The Repository name 11 | .PARAMETER Path 12 | The Path to the file you would like to download 13 | .PARAMETER DestinationPath 14 | The destionation for storing the file 15 | .EXAMPLE 16 | on macOS 17 | TK_DownloadFilesFromRepo -Owner thomaskrampe -Repository PowerShell -Path /WorkingWithFiles/TK_Copy-WithProgress.ps1 -DestinationPath \Users\thomas 18 | on Windows 19 | TK_DownloadFilesFromRepo -Owner thomaskrampe -Repository PowerShell -Path /WorkingWithFiles/TK_Copy-WithProgress.ps1 -DestinationPath C:\\Users\thomas 20 | .LINK 21 | https://github.com/thomaskrampe/PowerShell/blob/master/WorkingWithFiles/TK_DownloadFilesFromGithubRepo.ps1 22 | .NOTES 23 | Author : Thomas Krampe | thomas.krampe@myctx.net 24 | Version : 1.0 25 | Creation date : 21.02.2021 | v0.1 | Initial script 26 | Last change : 20.03.2021 | v1.0 | Add script documentation 27 | 28 | IMPORTANT NOTICE 29 | ---------------- 30 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 31 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 32 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 33 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 34 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 35 | OF SUCH DAMAGES IN ADVANCE. 36 | 37 | #> 38 | 39 | Param( 40 | [string]$Owner, 41 | [string]$Repository, 42 | [string]$Path, 43 | [string]$DestinationPath 44 | ) 45 | 46 | $baseUri = "https://api.github.com/" 47 | $args = "repos/$Owner/$Repository/contents/$Path" 48 | $wr = Invoke-WebRequest -Uri $($baseuri+$args) 49 | $objects = $wr.Content | ConvertFrom-Json 50 | $files = $objects | Where-Object {$_.type -eq "file"} | Select-Object -exp download_url 51 | $directories = $objects | Where-Object {$_.type -eq "dir"} 52 | 53 | $directories | ForEach-Object { 54 | DownloadFilesFromRepo -Owner $Owner -Repository $Repository -Path $_.path -DestinationPath $($DestinationPath+$_.name) 55 | } 56 | 57 | 58 | if (-not (Test-Path $DestinationPath)) { 59 | # Destination path does not exist, let's create it 60 | try { 61 | New-Item -Path $DestinationPath -ItemType Directory -ErrorAction Stop 62 | } catch { 63 | throw "Could not create path '$DestinationPath'!" 64 | } 65 | } 66 | 67 | foreach ($file in $files) { 68 | $fileDestination = Join-Path $DestinationPath (Split-Path $file -Leaf) 69 | try { 70 | Invoke-WebRequest -Uri $file -OutFile $fileDestination -ErrorAction Stop -Verbose 71 | "Grabbed '$($file)' to '$fileDestination'" 72 | } catch { 73 | throw "Unable to download '$($file.path)'" 74 | } 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /Github/TK_Invoke-Gist.ps1: -------------------------------------------------------------------------------- 1 | function TK_Invoke-Gist { 2 | <# 3 | .SYNOPSIS 4 | TK_Invoke-Gist 5 | .DESCRIPTION 6 | Execute a gist from a public github gist 7 | .PARAMETER Identity 8 | The identity of the gist eg. 5087431135c9aa650952a349910e6acf 9 | .PARAMETER Arguments 10 | Arguments for the gist if any 11 | .EXAMPLE 12 | TK_Invoke-Gist -Identity 5087431135c9aa650952a349910e6acf 13 | .LINK 14 | https://github.com/thomaskrampe/PowerShell/blob/master/WorkingWithFiles/TK_Invoke-Gist.ps1 15 | .NOTES 16 | Author : Thomas Krampe | thomas.krampe@myctx.net 17 | Version : 1.0 18 | Creation date : 21.02.2021 | v0.1 | Initial script 19 | Last change : 20.03.2021 | v1.0 | Add script documentation 20 | 21 | IMPORTANT NOTICE 22 | ---------------- 23 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 24 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 25 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 26 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 27 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 28 | OF SUCH DAMAGES IN ADVANCE. 29 | 30 | #> 31 | 32 | Param( 33 | [String] 34 | $Identity, 35 | 36 | [String] 37 | $Arguments 38 | ) 39 | 40 | $gistBase = "https://api.github.com/gists/" 41 | 42 | if ( ($Identity.Length -eq 32) -and ($Identity -match '[A-Za-z0-9]*') ) { 43 | # We got a gist ID 44 | $gistUrl = $gistBase + $Identity 45 | # Use TLS 1.2 46 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 47 | $pageContents = Invoke-WebRequest -Uri $gistUrl 48 | 49 | $gist = $pageContents.Content | ConvertFrom-Json 50 | 51 | } 52 | else { 53 | # Not a gist ID, try the full URL (this is very bad, I am sorry) 54 | $GistId = $Identity.TrimEnd("/").Split("/")[-1] 55 | $gistUrl = $gistBase + $GistId 56 | $pageContents = Invoke-WebRequest -Uri $gistUrl 57 | $gist = $pageContents.Content | ConvertFrom-Json 58 | } 59 | 60 | Write-Verbose "Invoking gist from $gistUrl" 61 | Write-Verbose "Gist by $($gist.owner.login)" 62 | Write-Verbose "Created at $($gist.created_at), last modified at $($gist.updated_at)" 63 | 64 | <# 65 | Write-Host "Invoking gist from $gistUrl" 66 | Write-Host "Gist by $($gist.owner.login)" 67 | Write-Host "Created at $($gist.created_at), last modified at $($gist.updated_at)" 68 | Write-Host "Gist-Files $($gist.files)" 69 | #> 70 | 71 | # Get the filenames and sort them alphabetically 72 | $files = $gist.files | Get-Member | Where-Object { $_.MemberType -eq "NoteProperty" } | Select-Object -ExpandProperty Name | Sort-Object 73 | 74 | 75 | 76 | foreach ($file in $files) { 77 | $file = $gist.files.$file 78 | Write-Verbose "Invoking file $($file.filename)" 79 | # Write-Host "Invoking file $($file.filename)" 80 | if ($file.language -ne "PowerShell") { 81 | Write-Warning "The file $($file.filename) is not marked as being of the PowerShell language." 82 | } 83 | 84 | Invoke-Expression -Command $file.Content 85 | } 86 | } 87 | 88 | 89 | TK_Invoke-Gist -Identity 5087431135c9aa650952a349910e6acf 90 | -------------------------------------------------------------------------------- /LoginAM/AM-Copy-XenServerVMTemplate.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Creates new XenServer VM's from an existing Template. 4 | .DESCRIPTION 5 | Creates new XenServer VM's by cloning an existing Template. This script is only for running within 6 | an Automation Machine environemnt 7 | Requires XenServer 7.0 SDK's PowerShell Module. 8 | .PARAMETER VMNames 9 | Names of new VMs to be created - AM Variables %vmname1%, %vmname2%, %vmname3%, %vmname4% 10 | .PARAMETER SourceTemplateName 11 | Name of the Template to be used. - AMVariable %SourceTemplateName% 12 | .PARAMETER XenServerHost 13 | The XenServer Pool Master to connect to. AM Variable %XenServerHost% 14 | .PARAMETER UserName 15 | Username for XenServer host.- AM Variable %XSCredentials% 16 | .PARAMETER Password 17 | Password for XenServer host. - AM Variable %XSCredentials% 18 | .NOTES 19 | Thomas Krampe - t.krampe@loginconsultants.de 20 | Version 1.0 21 | #> 22 | 23 | 24 | Param( 25 | [string[]]$VMNames = @($env:vmname1,$env:vmname2,$env:vmname3,$env:vmname4), 26 | [string]$SourceTemplateName = $env:SourceTemplateName, 27 | [string]$XenServerHost = $env:XenServerHost, 28 | [string]$UserName = $env:XSCredentials.Split(";")[0], 29 | [string]$Password = $env:XSCredentials.Split(";")[1] 30 | ) 31 | 32 | 33 | # Need this to ensure non-terminating error halt script 34 | $ErrorActionPreference = "Stop" 35 | 36 | # Import XenServerPSModule 37 | Import-Module XenServerPSModule 38 | 39 | if (Get-Module XenServerPSModule | ? {$_.Name -eq "XenServerPSModule"}) { 40 | 41 | try { 42 | # Connect to the XenServer pool master 43 | Write-Verbose "$($MyInvocation.MyCommand): Connecting to XenServer host: $XenServerHost" 44 | $session = Connect-XenServer -Server $XenServerHost -UserName $UserName -Password $Password -NoWarnCertificates -SetDefaultSession -PassThru 45 | 46 | if ($session) { 47 | try { 48 | $params = @{ 49 | Async = $true 50 | PassThru = $true 51 | } 52 | # Get the source VM or Template 53 | $sourceTemplate = Get-XenVM -Name $SourceTemplateName 54 | $params.Add("VM",$sourceTemplate) 55 | 56 | # Decide if we’re doing a clone or copy (i.e. thin vs. thick provision) 57 | Write-Verbose "$($MyInvocation.MyCommand): CLONE MODE" 58 | $params.Add("XenAction","Clone") 59 | 60 | # Schedule the creation of the VMs 61 | $xenTasks = @() 62 | foreach ($VMName in $VMNames) { 63 | Write-Verbose "$($MyInvocation.MyCommand): Scheduling creation of VM '$VMName' from Template '$SourceTemplateName'" 64 | $xenTasks += Invoke-XenVM -NewName $VMName @params 65 | } 66 | # Wait for the creation to finish 67 | Write-Verbose "$($MyInvocation.MyCommand): Waiting for clone to finish..." 68 | foreach ($xenTask in $xenTasks) { 69 | $xenTask | Wait-XenTask -ShowProgress 70 | } 71 | # If we started with templates, then we need to provision VMs from the copies/clones and wait for the provisioning to finish 72 | $xenTasks = @() 73 | foreach ($VMName in $VMNames) { 74 | Write-Verbose "$($MyInvocation.MyCommand): Provisioning VM '$VMName'" 75 | $xenTasks += Invoke-XenVM -Name $VMName -XenAction Provision -Async -PassThru 76 | Write-Verbose "$($MyInvocation.MyCommand): Waiting for provisioning to finish..." 77 | foreach ($xenTask in $xenTasks) { 78 | $xenTask | Wait-XenTask -ShowProgress 79 | } 80 | } 81 | # If we want to start the VMs, then get each VM and schedule a power on 82 | foreach ($VMName in $VMNames) { 83 | $VM = Get-XenVM -Name $VMName 84 | Write-Verbose "$($MyInvocation.MyCommand): Scheduling power on of VM '$VMName'" 85 | Invoke-XenVM -VM $VM -XenAction Start -Async 86 | } 87 | 88 | } 89 | finally { 90 | # Disconnect from XenServer pool master 91 | Write-Verbose "$($MyInvocation.MyCommand): Disconnecting from XenServer host" 92 | Disconnect-XenServer -Session $session 93 | } 94 | } 95 | } 96 | finally { 97 | # Finishing 98 | Write-Verbose "$($MyInvocation.MyCommand): VM creation finished" 99 | 100 | } 101 | } else { 102 | throw "XenServerPSModule not found." 103 | } 104 | 105 | -------------------------------------------------------------------------------- /LoginAM/AMDocGen_Anton.ps1: -------------------------------------------------------------------------------- 1 | cls 2 | 3 | $am_path = "D:\AM" 4 | $env_id = "adede9f1-924b-4096-9d56-7310cc4bc924" 5 | $csv_path = "C:\temp\report.cvs" 6 | 7 | # Loading AM Module 8 | $module = "$am_path\$env_id\bin\modules\admin\Automation Machine.psm1" 9 | 10 | If (Test-path $module){ 11 | Import-module $module -Verbose 12 | } 13 | else 14 | { 15 | Write-host "Module $module cannot be found" 16 | } 17 | 18 | #Get data 19 | $am_cols = Get-AMCollection | Sort-Object Name 20 | 21 | # Declare an array to collect our result objects 22 | $resultsarray =@() 23 | 24 | # For every collection do this loop 25 | ForEach ($am_col in $am_cols) { 26 | # Create a new custom object to hold our result. 27 | $tmpObject = new-object PSObject 28 | 29 | # Add our data to $contactObject as attributes using the Add-Member commandlet 30 | $tmpObject | Add-Member -MemberType NoteProperty -Name "Name" -Value $am_col.Name 31 | $tmpObject | Add-Member -MemberType NoteProperty -Name "Version" -Value $am_col.Version.VersionNumber 32 | $tmpObject | Add-Member -MemberType NoteProperty -Name "Layers" -Value $(($am_col.Layers.Layer.Name | Out-String) -replace "`n","," -replace "`r","") 33 | $tmpObject | Add-Member -MemberType NoteProperty -Name "Packages" -Value $(($am_col.Layers.Layer.Packages.Package.Name | Out-String) -replace "`n","," -replace "`r","") 34 | 35 | # Save the current $tmpObjectby appending it to $resultsArray ( += means append a new element to ‘me’) 36 | $resultsarray += $tmpObject 37 | } 38 | 39 | $resultsarray | Export-csv $csv_path -NoTypeInformation -Delimiter ";" 40 | -------------------------------------------------------------------------------- /LoginAM/AMPreparation.ps1: -------------------------------------------------------------------------------- 1 | # Prepare AM Server 2 | New-NetFirewallRule -Name Allow_ICMPv4 -DisplayName "Allow ICMPv4" -Protocol ICMPv4 -Enable True -Profile Any -Action Allow 3 | Enable-WSManCredSSP -Role Server -Force 4 | Enable-WSManCredSSP -Role Client -DelegateComputer * 5 | -------------------------------------------------------------------------------- /LoginAM/AddComputerToCollection.ps1: -------------------------------------------------------------------------------- 1 | # Load special AM module 2 | $lines = get-childitem -path "E:\Automation Machine" -exclude dtap,"environment manager",00000000-0000-0000-0000-000000000001,media,Logging,Monitoring -directory 3 | $TMP_EnvironmentID = $lines.Name 4 | 5 | $module = "E:\Automation Machine\$TMP_EnvironmentID\bin\modules\admin\Automation Machine.psm1" 6 | Import-module $module 7 | 8 | $Import_Servers = Get-content E:\server.txt 9 | Foreach ($TMP_SValue in $Import_Servers) { 10 | If ($tmp_SValue -ne ""){New-AMComputer -Name $TMP_SValue.split(";")[0] -Collection $TMP_SValue.split(";")[1] } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /LoginAM/AllowSQLFirewallRule.ps1: -------------------------------------------------------------------------------- 1 | New-NetFirewallRule -DisplayName “Allow Inbound SQL” -Direction Inbound -RemoteAddress LocalSubnet -protocol tcp -LocalPort 1433 -Action Allow -------------------------------------------------------------------------------- /LoginAM/CopyCertfilesToNetScaler.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Copy certificate files to an existing NetScaler. 4 | .DESCRIPTION 5 | Copy certificate files to an existing NetScaler. 6 | .NOTES 7 | Thomas Krampe - t.krampe@loginconsultants.de 8 | Version 1.0 9 | #> 10 | 11 | $ErrorActionPreference = "Stop" 12 | 13 | # Check if Windows Management Framework 5 is installed (https://www.microsoft.com/en-us/download/details.aspx?id=50395) 14 | If ($PSVersionTable.PSVersion.Major -ne 5) { 15 | Write-Warning -Message "Windows Management Framework 5 not installed. Please install WMF 5 before proceed - https://www.microsoft.com/en-us/download/details.aspx?id=50395" 16 | exit 17 | } 18 | 19 | # Install SSH Module 20 | Install-Module PoSH-SSH 21 | 22 | # Prepare Variables 23 | $SourcePath = $env:am_workfolder 24 | $NSCertFileName = $env:NSCertFile 25 | $NSCertFileKeyName = $env:NSCertKey 26 | $NSCertFilePath = "$SourcePath\$NSCertFileName" 27 | $NSCertKeyPath = "$SourcePath\$NSCertFileKeyName" 28 | $NSHostIP = $env:NSHostName.Slit("/")[2] 29 | $NSUserName = $env:NSUser.Split(";")[0] 30 | $NSUserPass = $env:NSUser.Split(";")[1] 31 | $NSSecureStringPwd = ConvertTo-SecureString $NSUserPass -asplaintext -force 32 | $NSCred = new-object management.automation.pscredential $NSUserName,$NSSecureStringPwd 33 | 34 | # Copy Certificate files with SCP to the NetScaler 35 | try { 36 | 37 | Set-SCPFile -ComputerName $NSHostIP -Credential $NSCred -LocalFile $NSCertFilePath -RemotePath "/nsconfig/ssl/" -AcceptKey $True 38 | Set-SCPFile -ComputerName $NSHostIP -Credential $NSCred -LocalFile $NSCertKeyPath -RemotePath "/nsconfig/ssl/" -AcceptKey $True 39 | 40 | Remove-Item $NSCertFilePath -Force 41 | Remove-Item $NSCertKeyPath -Force 42 | } 43 | catch { 44 | 45 | $ErrorMessage = $_.Exception.Message 46 | $FailedItem = $_.Exception.ItemName 47 | Write-Host "File copy failed. $ErrorMessage $FailedItem" 48 | 49 | } 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /LoginAM/CreateMasterDevice.ps1: -------------------------------------------------------------------------------- 1 | # =========================================================================================================== 2 | # 3 | # Title: Create Citrix PVS Master Target Device 4 | # Author: Thomas Krampe - t.krampe@loginconsultants.com 5 | # 6 | # Created: 10.05.2014 7 | # 8 | # Version: 1.0.0 9 | # 10 | # Purpose: This script will create a Master Target Device and a initial empty vDisk on a Citrix 11 | # Provisioning Server 7.1. This script is for the use with Automation Machine only. 12 | # 13 | # Requirements: Administrative Privileges, Registry backup (Just in case) and of course commonsense ;) 14 | # After running that script you should restart the system !!!! 15 | # 16 | # THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, 17 | # INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR 18 | # NON-INFRINGEMENT. THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS 19 | # OR OMISSIONS CONTAINED HEREIN, NOR FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER 20 | # DAMAGES RESULTING FROM THE FURNISHING, PERFORMANCE, OR USE OF THIS SCRIPT, EVEN 21 | # IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES IN ADVANCE. 22 | # 23 | # License: Creative Commons CC BY-NC-SA 4.0 24 | # http://creativecommons.org/licenses/by-nc-sa/4.0/ 25 | # 26 | # =========================================================================================================== 27 | 28 | $ErrorActionPreference = 'SilentlyContinue' 29 | 30 | #Prepare Powershel Environment 31 | Set-ExecutionPolicy -ExecutionPolicy Bypass -Force 32 | Add-PSSnapIn mclipssnapin 33 | 34 | # Define Variables 35 | $PVS_Site = (Get-Item env:pvs_site).Value 36 | $PVS_Store = (Get-Item env:pvs_store).Value 37 | $PVS_Collection = (Get-Item env:pvs_collection).Value 38 | $PVS_vDiskName = (Get-Item env:pvs_vdiskname).Value 39 | $PVS_vDiskSize = (Get-Item env:pvs_vdisksize).Value 40 | $PVS_vDiskBlocksize = (Get-Item env:pvs_vdiskblocksize).Value 41 | $MD_HostName = (Get-Item env:md_hostname).Value 42 | $MD_MACAddr = (Get-Item env:md_macaddr).Value 43 | 44 | #Create vDisk 45 | Mcli-RunWithReturn CreateDisk -p name="$PVS_vDiskName",size="$PVS_vDiskSize",storename="$PVS_Store",SiteName="$PVS_Site",servername="$env:computername",type="1",vhdBlockSize="$PVS_vDiskBlocksize" 46 | 47 | #Add new Master Target Device to a collection 48 | Mcli-Add Device -r deviceName="$MD_HostName",collectionName="$PVS_Collection",siteName="$PVS_Site",deviceMac="$MD_MACAddr",bootFrom="2",logLevel="2" 49 | 50 | # Set advanced options to the Master Device (eg. Description and Type=1 Test) 51 | Mcli-Set Device -p deviceName="$MD_HostName" -r description="Master Device",type="1" 52 | 53 | # Assign the vDisk to the Master Device 54 | $vDiskArray = Mcli-Get DiskLocator -p diskLocatorName="$PVS_vDiskName", siteName="$PVS_Site", storeName="$PVS_Store" -f diskLocatorId 55 | $vDiskUUID = $vDiskArray[4] 56 | $vDiskUUID = $vDiskUUID.substring($vDiskUUID.length - 36, 36) 57 | 58 | Mcli-Run AssignDiskLocator -p diskLocatorId="$vDiskUUID",deviceName="$MD_HostName" 59 | 60 | -------------------------------------------------------------------------------- /LoginAM/CreatePVSvDisk.ps1: -------------------------------------------------------------------------------- 1 | # =========================================================================================================== 2 | # 3 | # Title: Create Citrix PVS Server vDisk 4 | # Author: Thomas Krampe - t.krampe@loginconsultants.com 5 | # 6 | # Created: 10.05.2014 7 | # 8 | # Version: 1.0.0 9 | # 10 | # Purpose: The following script will prepare a Citrix Provisioning Server 7.1 for the 11 | # with Automation Machine. 12 | # 13 | # Requirements: Administrative Privileges, Registry backup (Just in case) and of course commonsense ;) 14 | # After running that script you should restart the system !!!! 15 | # 16 | # THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, 17 | # INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR 18 | # NON-INFRINGEMENT. THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS 19 | # OR OMISSIONS CONTAINED HEREIN, NOR FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER 20 | # DAMAGES RESULTING FROM THE FURNISHING, PERFORMANCE, OR USE OF THIS SCRIPT, EVEN 21 | # IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES IN ADVANCE. 22 | # 23 | # License: Creative Commons CC BY-NC-SA 4.0 24 | # http://creativecommons.org/licenses/by-nc-sa/4.0/ 25 | # 26 | # =========================================================================================================== 27 | 28 | $ErrorActionPreference = 'SilentlyContinue' 29 | 30 | #Prepare Powershel Environment 31 | Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force 32 | Add-PSSnapIn mclipssnapin 33 | 34 | # Define Variables 35 | $PVS_Site = (Get-Item env:pvs_site).Value 36 | $PVS_Store = (Get-Item env:pvs_store).Value 37 | $PVS_vDiskName = (Get-Item env:pvs_vdiskname).Value 38 | $PVS_vDiskSize = (Get-Item env:pvs_vdisksize).Value 39 | $PVS_vDiskBlocksize = (Get-Item env:pvs_vdiskblocksize).Value 40 | 41 | #Create vDisk 42 | Mcli-RunWithReturn CreateDisk -p name="$PVS_vDiskName",size="$PVS_vDiskSize",storename="$PVS_Store",SiteName="$PVS_Site",servername="$env:computername",type="1",vhdBlockSize="$PVS_vDiskBlocksize" 43 | 44 | -------------------------------------------------------------------------------- /LoginAM/DisableCheckCertificate.ps1: -------------------------------------------------------------------------------- 1 | # Disable check publisher's certificate revocation (to speed up console start-up) 2 | #================================================================================ 3 | 4 | set-ItemProperty -path "REGISTRY::\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing\" -name State -value 146944 -------------------------------------------------------------------------------- /LoginAM/FSLogix_EnableProfileDisk.ps1: -------------------------------------------------------------------------------- 1 | # =========================================================================================================== 2 | # 3 | # Title: Windows 8 and Server 2012 VDI Optimization Script 4 | # Author: Thomas Krampe - t.krampe@loginconsultants.com 5 | # 6 | # Created: 18.06.2015 7 | # 8 | # Version: 1.0 9 | # 10 | # Requirements: Administrative Privileges, Registry backup (Just in case) and of course commonsense ;) 11 | # After running that script you should restart the system !!!! 12 | # 13 | # THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, 14 | # INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR 15 | # NON-INFRINGEMENT. THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS 16 | # OR OMISSIONS CONTAINED HEREIN, NOR FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER 17 | # DAMAGES RESULTING FROM THE FURNISHING, PERFORMANCE, OR USE OF THIS SCRIPT, EVEN 18 | # IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES IN ADVANCE. 19 | # 20 | # License: Creative Commons CC BY-NC-SA 4.0 21 | # http://creativecommons.org/licenses/by-nc-sa/4.0/ 22 | # 23 | # Help: ItemType Description DataType 24 | # String A string REG_SZ 25 | # ExpandString A string with environment variables REG_EXPAND_SZ 26 | # that are resolved when invoked 27 | # Binary Binary values REG_BINARY 28 | # DWord Numeric values REG_DWORD 29 | # MultiString Text of several lines REG_MULTI_SZ 30 | # QWord 64-bit Numeric values REG_QWORD 31 | # 32 | # =========================================================================================================== 33 | 34 | # =================================================== 35 | # Variables 36 | # =================================================== 37 | 38 | $ErrorActionPreference = 'SilentlyContinue' 39 | $OSName = (Get-WmiObject Win32_OperatingSystem).Caption 40 | $AMEnvName = (Get-Item env:am_env_name).Value 41 | 42 | # =================================================== 43 | # Package Settings for Automation Machine 44 | # Get Automation Machine today 45 | # http://www.getautomationmachine.com/en/download 46 | # =================================================== 47 | 48 | If($AMEnvName) { 49 | $FSLogix_VHDLocation = (Get-Item env:FSLogix_VHDLocation).Value 50 | $FSLogix_SizeInMBs = (Get-Item env:FSLogix_SizeInMBs).Value 51 | $FSLogix_VolumeType = (Get-Item env:FSLogix_VolumeType).Value 52 | $FSLogix_VHDXSectorSize = (Get-Item env:FSLogix_VHDXSectorSize).Value 53 | $FSLogix_IsDynamic = (Get-Item env:FSLogix_IsDynamic).Value 54 | } 55 | 56 | # =================================================== 57 | # Create neccessary registry keys 58 | # =================================================== 59 | 60 | New-Item -Path 'HKLM:\SOFTWARE\FSLogix' -Name Profiles 61 | Set-ItemProperty -Name VHDLocation -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Type MultiString -Value $FSLogix_VHDLocation 62 | Set-ItemProperty -Name VolumeType -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Type String -Value $FSLogix_VolumeType 63 | Set-ItemProperty -Name SizeInMBs -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Type DWord -Value $FSLogix_SizeInMBs 64 | Set-ItemProperty -Name VHDXSectorSize -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Type DWord -Value $FSLogix_VHDXSectorSize 65 | 66 | If ($FSLogix_IsDynamic -eq $true) { 67 | Set-ItemProperty -Name IsDynamic -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Type DWord -Value 1 68 | } 69 | Else { 70 | Set-ItemProperty -Name IsDynamic -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Type DWord -Value 0 71 | } 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /LoginAM/FirewallRule-Inbound_SQL.ps1: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------- 2 | # Script: FirewallRule-Inbound_SQL.ps1 3 | # Author: Thomas Krampe 4 | # Date: 01/22/2015 5 | # Keywords: Security,Firewall, MS-SQL 6 | # ----------------------------------------------------------------- 7 | 8 | Import-Module NetSecurity 9 | New-NetFirewallRule -DisplayName "Allow TCP 1433 Inbound"-Description "Created by Automation Machine" -Direction Inbound -RemoteAddress LocalSubnet -Action Allow -EdgeTraversalPolicy Allow -Protocol TCP -LocalPort 1433 -------------------------------------------------------------------------------- /LoginAM/GET_AM_Inventory.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/LoginAM/GET_AM_Inventory.ps1 -------------------------------------------------------------------------------- /LoginAM/GetHostnameWithMACAddressFromDHCP.ps1: -------------------------------------------------------------------------------- 1 |  2 | 3 | # User credentials for the XenServer 4 | $XSHost = "192.168.1.101" 5 | $XSUser = "xs-readonly" 6 | $XSPassword = "Password01!" 7 | 8 | # User credentials for the Target Server 9 | $TargetUser = "Administrator" 10 | $TargetPassword = "Password01!" 11 | 12 | 13 | # Domain user credentials for the DHCP server 14 | $strUsername = "Administrator" 15 | $strDomain = "myctxlab" 16 | $strUserDomain = $strDomain + "\" + $strUsername 17 | $SecureStringPwd = convertto-securestring "!Man0n2502!" -asplaintext -force 18 | $DomainController = "prod-dc-01" 19 | 20 | 21 | # Functions 22 | Function get_xen_vm_by_mac([STRING]$MACfilter) 23 | { 24 | # Import XenServerPSModule 25 | Import-Module XenServerPSModule 26 | 27 | # Verify that module is available 28 | If (Get-Module XenServerPSModule | ? {$_.Name -eq "XenServerPSModule"}) { 29 | $XSSession = Connect-XenServer -Server $XSHost -UserName $XSUser -Password $XSPassword -NoWarnCertificates -SetDefaultSession -PassThru 30 | $vif = get-xenVIF | ? { $_.MAC -match $MACFilter} 31 |   If ($vif) {$oref = $vif.opaque_ref} 32 |   If ($oref) {$vif_vm = Get-XenVIFProperty -Ref $oref -XenProperty VM} 33 | If ($vif_vm) { 34 |   Return $vif_vm.name_label 35 |   } 36 |   Else { 37 |   Write-Host = "No Xen VM found which owns the MAC $MACFilter on XenServer $XSHost" 38 | Return $false 39 | } 40 | Disconnect-XenServer -Session $XSSession 41 | } 42 | Else { 43 | Write-Warning "FATAL ERROR - XenServerPSModule not available." 44 | Exit 99 45 | } 46 | } 47 | 48 | # Create the powershell credential object 49 | $Cred = new-object management.automation.pscredential $strUserDomain,$SecureStringPwd 50 | 51 | # Create the Powershell session 52 | $Session = New-PSSession –Computername $DomainController -Credential $Cred 53 | 54 | # Collect MAC addresses from DHCP server 55 | $MacAddresses = Invoke-Command -Session $Session -ScriptBlock {Get-DhcpServerv4Lease -ScopeId "192.168.1.0" | ? { $_.Hostname -match "WIN-" } | Select-Object ClientId,IPAddress,HostName} 56 | Remove-PSSession $Session 57 | 58 | # Get current name-label from virtual machines on XenServer 59 | ForEach ($MACAddress in $MacAddresses) { 60 | $MACReplaced = $MACAddress.ClientID -Replace "-",":" 61 | $DHCPIPAddress = $MACAddress.IPAddress 62 | $DHCPHostName = $MACAddress.HostName 63 | $VMCheck = get_xen_vm_by_mac $MACReplaced 64 | 65 | If ($VMCheck) { 66 | 67 | Write-Host "DEBUG: The VM $VMCheck is running on this Hypervisor with IP address $DHCPIPAddress and hostname $DHCPHostName." 68 | 69 | # Create local credentials for target access 70 | $TargetUserDomain = $VMCheck + "\" + $TargetUser 71 | $TargetSecureStringPwd = ConvertTo-SecureString $TargetPassword -asplaintext -force 72 | $CredTarget = new-object management.automation.pscredential $TargetUserDomain,$TargetSecureStringPwd 73 | 74 | # Rename the Computer, join Domain and restart after 75 | $pos = $DHCPHostName.IndexOf(".") 76 | $DHCPHostName = $DHCPHostName.Substring(0, $pos) 77 | write-host "LOG: Renamimg $DHCPHostName - new host name: $VMCheck" 78 | Rename-Computer -ComputerName $DHCPHostName -NewName $VMCheck -LocalCredential $CredTarget -Force -PassThru 79 | 80 | write-host "LOG: Adding $VMCheck to domain $strDomain" 81 | # Add-Computer -NewName $VMCheck -DomainName $strDomain -Credential $Cred -OUPath "OU=Deployment,DC=myctx,DC=lab" -Force 82 | Add-Computer -Credential $Cred -DomainName $strDomain -ComputerName $DHCPHostName -Force -LocalCredential $CredTarget -NewName $VMCheck -Options JoinWithNewName -OUPath '"OU=Deployment,DC=myctx,DC=lab' -PassThru 83 | Restart-Computer -ComputerName $DHCPHostName -Credential $Cred -Force 84 | 85 | } 86 | Else { 87 | 88 | Write-Host "DEBUG: The VM $VMCheck is not running on this Hypervisor." 89 | # Falls bereits eine andere WIN-* VM existiert, die nicht auf dem XenServer läuft. 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /LoginAM/GetXenVMNameLabelbyMAC_new.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Get XenServer VM name label from an existing VM by using the MAC-address. 4 | .DESCRIPTION 5 | Get XenServer VM name label from an existing VM by using the MAC-address. 6 | Requires XenServer 6.5 SDK's PowerShell Module. 7 | .PARAMETER XenServerHost 8 | The XenServer Pool Master to connect to. 9 | .PARAMETER UserName 10 | Username for XenServer host. 11 | .PARAMETER Password 12 | Password for XenServer host. 13 | .EXAMPLE 14 | GetXenVMNameLabelbyMAC.ps1 -XenServerHost "1.2.3.4" -UserName "root" -Password "p4ssw0rd" -Windowshost "localhost" 15 | 16 | Description 17 | ----------- 18 | Get the Name-Label value from a virtual machine on the XenServer host based on the Mac address collected from the Windows host. 19 | If the WindowsHost parameter is empty, localhost will be used. 20 | 21 | .NOTES 22 | Thomas Krampe - t.krampe@loginconsultants.de 23 | Version 1.0 24 | #> 25 | 26 | Param ( 27 | [Parameter(Mandatory=$true)] [string]$XenServerHost, 28 | [Parameter(Mandatory=$true)] [string]$UserName, 29 | [Parameter(Mandatory=$true)] [string]$Password, 30 | [Parameter(Mandatory=$false)] [string]$WindowsHost 31 | ) 32 | 33 | # Functions 34 | Function get_xen_vm_by_mac([STRING]$MACfilter) 35 | { 36 | $strSession = Connect-XenServer -Server $XenServerHost -UserName $UserName -Password $Password -NoWarnCertificates -SetDefaultSession -PassThru 37 | $vif = get-xenVIF | ? { $_.MAC -match $MACFilter} 38 |   If ($vif) {$oref = $vif.opaque_ref} 39 |   If ($oref) {$vif_vm = Get-XenVIFProperty -Ref $oref -XenProperty VM} 40 |   If ($vif_vm) 41 |   { 42 |   43 | 'The VM with MAC: ' + $MACfilter + ' has the Name-Label: ' +$vif_vm.name_label + ' on XenServer ' + $XenServerHost 44 | 45 |   } 46 |   Else 47 |   { 48 |   "No Xen VM found which owns the MAC $MACFilter" 49 | } 50 | Disconnect-XenServer -Session $strSession 51 | } 52 | 53 | 54 | # Get adapter information for each network adapter on a given machine. 55 | # Get the machine name or IP 56 | If (!$WindowsHost) { 57 | $WindowsHost = "localhost" 58 | } 59 | 60 | 61 | 62 | #pull in namespace and filter by which adapters have an IP address enabled 63 | $colItems = Get-WmiObject -Class "Win32_NetworkAdapterConfiguration" -ComputerName $WindowsHost -Filter "IpEnabled = TRUE" 64 | 65 | #iterate and display 66 | ForEach ($objItem in $colItems) { 67 | # write-host 68 | # write-host $objItem.Description 69 | # write-host "MAC Address: " $objItem.MacAddress 70 | # write-host "IP Address: " $objItem.IpAddress 71 | # write-host 72 | # write-host $objItem.MacAddress 73 | 74 | } 75 | 76 | $result = get_xen_vm_by_mac $objItem.MacAddress 77 | Write-Host "$($MyInvocation.MyCommand): " $result 78 | -------------------------------------------------------------------------------- /LoginAM/InstallXSTools.ps1: -------------------------------------------------------------------------------- 1 | &"%SystemRoot%\System32\msiexec.exe /i %AM_Workfolder%\1e8e2bea-d205-4da4-b5cd-93f1819dafbd\1\installwizard.msi /quiet /norestart" -------------------------------------------------------------------------------- /LoginAM/InstallXenServerPSSnapIn.ps1: -------------------------------------------------------------------------------- 1 | # =============================================================================================================== 2 | # 3 | # Title: XenServer PSSnapin Register 4 | # Author: Thomas Krampe - t.krampe@loginconsultants.com 5 | # 6 | # Version: 1.0 7 | # 8 | # Created: 15.09.2014 9 | # 10 | # Special thanks to : To the Automation Machine Team 11 | # 12 | # Purpose: The following script will register the XS PSSnapIn DLL and add the 13 | # PSSnapIn to PowerShell. 14 | # 15 | # Requirements: nothing 16 | # 17 | # =============================================================================================================== 18 | 19 | $ErrorActionPreference = 'SilentlyContinue' 20 | $Path =(Get-Item 'env:ProgramFiles(x86)').Value + "\Citrix\XenServerPSSnapIn\XenServerPSSnapIn.dll" 21 | 22 | If (Test-Path $Path) { 23 | 24 | # Register DLL 25 | & "$env:SystemRoot\Microsoft.NET\Framework64\v2.0.50727\InstallUtil.exe" "$Path" 26 | 27 | # Add XenServerPSSnapIn to local PS 28 | Add-PSSnapIn XenServerPSSnapIn 29 | 30 | $IsInstalled = Get-PSSnapin -registered 31 | 32 | If ($IsInstalled){ 33 | Write-Host "XenServerPSSnapIn successful registered." 34 | } 35 | Else { 36 | Write-Host "XenServerPSSnapIn NOT registered. Installation failed." 37 | } 38 | } 39 | Else { 40 | Write-Host "XenServerPSSnapIn not installed!" 41 | 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /LoginAM/OnlineVerification.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Online Verification Script. 4 | .DESCRIPTION 5 | Online Verification Script that runs after the computer has completed it's LoginAM maintenance reboot. 6 | This script check several Citrix services on a english server os machine with installed Citrix VDA. 7 | .NOTES 8 | Author : Thomas Krampe | t.krampe@loginconsultants.de 9 | Version : 1.0 10 | Creation date : 26.10.2016 | v0.1 | Initial script 11 | Last change : 02.03.2017 | v1.0 | Add additional Citrix Service checks 12 | #> 13 | 14 | # Prepare 15 | $Return = $true 16 | Import-Module AMClient 17 | Write-AMInfo "Starting Verification." 18 | 19 | try 20 | { 21 | # <----- Place your additional code for more checks within this 'try' block -----> 22 | 23 | # Check the main VDA broker service 24 | $BrokerOnline = Get-Service -Name "BrokerAgent" 25 | If ($BrokerOnline.Status -eq "Running") { 26 | Write-AMInfo "$($BrokerOnline.DisplayName) ist running" 27 | 28 | # Check the other services (only if Broker Service is running) 29 | $CitrixServices = Get-Service -Name Citrix* 30 | 31 | foreach ($CitrixService in $CitrixServices) { 32 | If ($CitrixService.Status -eq "Running") { 33 | Write-AMInfo "$($CitrixService.DisplayName) is running." 34 | } 35 | Else { 36 | Write-AMInfo "$($CitrixService.DisplayName) isn't running." 37 | 38 | # If an additional service is in stopped state, we try to start the service first. 39 | try { 40 | Write-AMInfo "Try to start $($CitrixService.DisplayName)." 41 | Start-Service -DisplayName $($CitrixService.DisplayName) 42 | Start-Sleep -Seconds 30 43 | $SvcStarted = Get-Service -DisplayName $($CitrixService.DisplayName) 44 | If ($SvcStarted.Status -eq "Running") { 45 | Write-AMInfo "Service $($CitrixService.DisplayName) succesful started." 46 | } 47 | Else { 48 | Write-AMInfo "Could not start $($CitrixService.DisplayName)." 49 | $Return = $false 50 | Break 51 | } 52 | } 53 | catch { 54 | $Reason = $_ 55 | Write-AMInfo "Service start failed. Error message: `'$Reason`'" 56 | $Return = $false 57 | } 58 | } 59 | } 60 | } 61 | Else { 62 | Write-AMInfo "$($BrokerOnline.DisplayName) isn't running." 63 | $Return = $false 64 | } 65 | 66 | } 67 | 68 | catch 69 | { 70 | $Reason = $_ 71 | $Return = $false 72 | Write-AMInfo "Something went wrong. Error message: `'$Reason`'" 73 | } 74 | 75 | switch ($Return) 76 | { 77 | $false 78 | { 79 | # <----- Place your additional code here (only runs in case of an error)-----> 80 | Write-AMError "Verification script failed." 81 | 82 | } 83 | $true 84 | { 85 | # <----- Place your additional code here (runs if no errors have occured)-----> 86 | Write-AMInfo "Verification script succesful completed." 87 | } 88 | } 89 | 90 | Return $Return -------------------------------------------------------------------------------- /LoginAM/OnlineVerificationSmall.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Online Verification Script. 4 | .DESCRIPTION 5 | Online Verification Script that runs after the computer has completed it's LoginAM maintenance reboot. 6 | This script check several Citrix services on a english server os machine with installed Citrix VDA. 7 | .NOTES 8 | Author : Thomas Krampe | t.krampe@loginconsultants.de 9 | Version : 1.0 10 | Creation date : 26.10.2016 | v0.1 | Initial script 11 | Last change : 02.03.2017 | v1.0 | Add additional Citrix Service checks 12 | #> 13 | 14 | # Prepare 15 | $Return = $true 16 | Import-Module AMClient 17 | Write-AMInfo "Starting Verification." 18 | 19 | try 20 | { 21 | # <----- Place your additional code for more checks within this 'try' block -----> 22 | 23 | # Check the main VDA broker service 24 | $BrokerOnline = Get-Service -Name "BrokerAgent" 25 | If ($BrokerOnline.Status -eq "Running") { 26 | Write-AMInfo "$($BrokerOnline.DisplayName) ist running" 27 | 28 | # Check the other services (only if Broker Service is running) 29 | $CitrixServices = Get-Service -Name Citrix* 30 | 31 | } 32 | Else { 33 | Write-AMInfo "$($BrokerOnline.DisplayName) isn't running." 34 | $Return = $false 35 | } 36 | 37 | } 38 | 39 | catch 40 | { 41 | $Reason = $_ 42 | $Return = $false 43 | Write-AMInfo "Something went wrong. Error message: `'$Reason`'" 44 | } 45 | 46 | switch ($Return) 47 | { 48 | $false 49 | { 50 | # <----- Place your additional code here (only runs in case of an error)-----> 51 | Write-AMError "Verification script failed." 52 | 53 | } 54 | $true 55 | { 56 | # <----- Place your additional code here (runs if no errors have occured)-----> 57 | Write-AMInfo "Verification script succesful completed." 58 | } 59 | } 60 | 61 | Return $Return -------------------------------------------------------------------------------- /LoginAM/PVSCreateOrJoinV10.ps1: -------------------------------------------------------------------------------- 1 | # =============================================================================================================== 2 | # 3 | # Title: PVS Create or Join Farm Script 4 | # Author: Thomas Krampe - t.krampe@loginconsultants.com 5 | # 6 | # Version: 1.0 7 | # 8 | # Created: 25.06.2014 9 | # 10 | # Special thanks to : To the Automation Machine Team 11 | # 12 | # Purpose: The following script will check if a given PVS database already 13 | # exists on a MS-SQL Server. If not it will set a variable to "Create" 14 | # otherwise it will set the variable to "Join". 15 | # 16 | # Requirements: nothing 17 | # 18 | # =============================================================================================================== 19 | 20 | # Check if PVS DB exists 21 | 22 | try 23 | { 24 | $conn = New-Object System.Data.SQLClient.SQLConnection("Server=$env:pvs_db_server;Database=$env:pvs_db;Trusted_Connection=True") 25 | 26 | $cmd = New-Object System.Data.SQLClient.SQLCommand("SELECT COUNT(farmId) FROM dbo.Farm",$conn) 27 | $conn.Open() 28 | $Table_Num = $cmd.ExecuteScalar() 29 | 30 | If ($Table_Num -eq 0) 31 | { 32 | $env:JoinOrCreate = "Create" 33 | } 34 | Else 35 | { 36 | $env:JoinOrCreate = "Join" 37 | } 38 | 39 | } 40 | Catch [System.Data.SqlClient.SqlException] 41 | { 42 | $env:JoinOrCreate = "Create" 43 | } 44 | Catch 45 | { 46 | throw $_ 47 | } 48 | Write-Host "Join or create mode:$env:JoinOrCreate" -------------------------------------------------------------------------------- /LoginAM/PrepareAM.ps1: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------ 2 | # Prepare and initialize new Machine for AM deployment 3 | # 4 | # Thomas Krampe - t.krampe@loginconsultants.com 5 | # (c) 2015 Login Consultants Germany GmbH 6 | # ------------------------------------------------------ 7 | 8 | # Variables 9 | $AMShare = "\\lab-am-01\am$\ea7a74ea-8059-4878-907a-964c7e745cea" 10 | 11 | # Enable Remote Admin in Windows Firewall 12 | netsh firewall set service type=REMOTEADMIN mode=ENABLE 13 | 14 | #Allow ICMPv4 in Windows Firewall 15 | New-NetFirewallRule -Name Allow_ICMPv4 -DisplayName "Allow ICMPv4" -Protocol ICMPv4 -Enable True -Profile Any -Action Allow 16 | 17 | # Set Execution Policy 18 | Set-ExecutionPolicy Bypass 19 | 20 | # Enable CredSSP for PS remoting 21 | Enable-WSManCredSSP -Role Server -Force 22 | Enable-WSManCredSSP -Role Client -DelegateComputer * -Force 23 | 24 | # Make sure Remote Registry Service is running 25 | Get-Service RemoteRegistry | where {$_.status -eq "Stopped"} | start-service -PassThru 26 | 27 | # Initialize AM 28 | If (Test-Path $AMShare) { 29 | & $AMShare\Initialize-AM.ps1 30 | } 31 | Else { 32 | Write-Host "Someting went wrong! Environment not available." 33 | } 34 | 35 | -------------------------------------------------------------------------------- /LoginAM/RegisterGatewayInStorefront.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Register NetScaler Gateway in Storefront. 4 | .DESCRIPTION 5 | Register NetScaler Gateway in Storefront via Powershell remoting. This script should run on the Automation Machine itself. 6 | .PARAMETER StoreVirtualPath (Mandatory) 7 | The Path to the Storefront Store (eg. /Citrix/Store). 8 | .PARAMETER GatewayURL (Mandatory) 9 | The external URL of the NetScaler Gateway vServer (starting with https://). 10 | For AM deployments use $env:NSGWFQDN 11 | .PARAMETER GatewayCallbackURL (Mandatory) 12 | Callback URL normally the same like the GatewayURL. 13 | For AM deployments use $env:NSGWFQDN 14 | .PARAMETER GatewaySTAUrls (Mandatory) 15 | The URL of the STA server, normally the DDC. 16 | For AM deployments use $env:NSGWSTA 17 | .PARAMETER GatewaySubnetIP 18 | SNIP or MIP address (10.0) or VIP address (10.5 >) for the Gateway. 19 | For AM deployments use $env:NSGWVIP 20 | .PARAMETER GatewayName (Mandatory) 21 | NetScaler name in Storefront. 22 | For AM deployments use $env:NSGWName 23 | .PARAMETER SFServerIP (Mandatory) 24 | IP address of the Storefront Server 25 | For AM deployments use $env:NSSFServerIP 26 | .NOTES 27 | Thomas Krampe - t.krampe@loginconsultants.de 28 | Version 1.0 29 | #> 30 | 31 | Param( 32 | [string]$StoreVirtualPath = "/Citrix/Store", 33 | [Uri]$GatewayUrl = "https://", 34 | [Uri]$GatewayCallbackUrl = "https://", 35 | [Uri[]]$GatewaySTAUrls = "https://", 36 | [string]$GatewaySubnetIP = "", 37 | [string]$GatewayName = "", 38 | [string]$SFServerIP = "" 39 | ) 40 | 41 | Set-StrictMode -Version 2.0 42 | 43 | if ($env:NSDCBindDN) { 44 | $DomainUserName = $env:NSDCBindDN.Split(";")[0] 45 | $DomainSecureStringPwd = ConvertTo-SecureString $env:NSDCBindDN.Split(";")[1] -asplaintext -force 46 | } 47 | else { 48 | $NSDCBinDN = Get-Credential 49 | $DomainUserName = $credential.getNetworkCredential().username 50 | $DomainSecureStringPwd = ConvertTo-SecureString $credential.getNetworkCredential().password -asplaintext -force 51 | } 52 | 53 | # Create the powershell credential object 54 | $Cred = new-object management.automation.pscredential $DomainUserName,$DomainSecureStringPwd 55 | 56 | # Create the Powershell session 57 | $Session = New-PSSession –Computername $SFServerIP -Credential $Cred 58 | 59 | # Any failure is a terminating failure. 60 | $ErrorActionPreference = 'Stop' 61 | $ReportErrorShowStackTrace = $true 62 | $ReportErrorShowInnerException = $true 63 | 64 | Invoke-Command -Session $Session -argumentlist $StoreVirtualPath,$GatewayUrl,$GatewayCallbackUrl,$GatewaySTAUrls,$GatewaySubnetIP,$GatewayName -ScriptBlock { 65 | 66 | # Import StoreFront modules. Required for versions of PowerShell earlier than 3.0 that do not support autoloading 67 | Import-Module Citrix.StoreFront 68 | Import-Module Citrix.StoreFront.Stores 69 | Import-Module Citrix.StoreFront.Roaming 70 | 71 | # Determine the Authentication and Receiver sites based on the Store 72 | $store = Get-STFStoreService -VirtualPath $args[0] 73 | $authentication = Get-STFAuthenticationService -StoreService $store 74 | $receiverForWeb = Get-STFWebReceiverService -StoreService $store 75 | 76 | # Enables CitrixAGBasic on the Citrix Receiver for Web service required for remote access using NetScaler Gateway. 77 | $receiverMethods = Get-STFWebReceiverAuthenticationMethodsAvailable | Where-Object { $_ -match "Explicit" -or $_ -match "CitrixAG" } 78 | 79 | # Enable CitrixAGBasic in Receiver for Web (required for remote access) 80 | Set-STFWebReceiverService $receiverForWeb 81 | 82 | # Enables CitrixAGBasic on the authentication service. This is required for remote access. 83 | $citrixAGBasic = Get-STFAuthenticationProtocolsAvailable | Where-Object { $_ -match "CitrixAGBasic" } 84 | 85 | # Enable CitrixAGBasic in the Authentication service (required for remote access) 86 | Enable-STFAuthenticationServiceProtocol -AuthenticationService $authentication -Name $citrixAGBasic 87 | 88 | # Add a new Gateway used to access the new store remotely 89 | Add-STFRoamingGateway -Name $args[5] -LogonType Domain -Version Version10_0_69_4 -GatewayUrl $args[1] -CallbackUrl $args[2] -SecureTicketAuthorityUrls $args[3] 90 | 91 | # Get the new Gateway from the configuration (Add-STFRoamingGateway will return the new Gateway if -PassThru is supplied as a parameter) 92 | $gateway = Get-STFRoamingGateway -Name $args[5] 93 | 94 | # If the gateway subnet was provided then set it on the gateway object 95 | if($args[4]) 96 | 97 | { 98 | 99 | Set-STFRoamingGateway -Gateway $gateway -SubnetIPAddress $args[4] 100 | 101 | } 102 | 103 | # Register the Gateway with the new Store 104 | Register-STFStoreGateway -Gateway $gateway -StoreService $store -DefaultGateway 105 | 106 | 107 | } 108 | 109 | Remove-PSSession $Session -------------------------------------------------------------------------------- /LoginAM/RegisterPVS-McliPSSnapIn.ps1: -------------------------------------------------------------------------------- 1 | # Register McliPSSnapIn 2 | $Path =(Get-Item 'env:ProgramFiles').Value + "\Citrix\Provisioning Services Console\McliPSSnapIn.dll" 3 | & "$env:SystemRoot\Microsoft.NET\Framework64\v2.0.50727\installutil.exe" “$Path” 4 | write-host "McliPSSnapIn registered." 5 | 6 | # Import PSSnapIn 7 | add-PSSnapIn mclipssnapin 8 | 9 | # Sometimes the SOAP Service stop working. Just check this and restart the service if neccessary 10 | If ((gsv soapserver).Status -ne "Running") { 11 | Restart-Service soapserver 12 | Write-Host "soapservcer restartet!" 13 | } 14 | Else { 15 | Write-Host "soapserver is running." 16 | } -------------------------------------------------------------------------------- /LoginAM/TrustCertificate.ps1: -------------------------------------------------------------------------------- 1 | # sets the certificate as trusted - otherwise publishing will not work automatically 2 | 3 | 4 | Add-pssnapin citrix* 5 | $PackageID = "d5bd0606-0d55-4cc0-ba7a-a55b29907adc" 6 | $CollectionId = (Get-AMCollection -Current).Id 7 | 8 | 9 | $LicenseServerAddress = (Get-AMVariable -Id "4972ddd8-5ae0-472d-84f7-f21059b3fcb0" -ComponentId $PackageID -CollectionId $CollectionID).Value | Expand-AMEnvironmentVariables 10 | 11 | $licenseServerQueryAddress = "https://" + $LicenseServerAddress + ":8083/" 12 | 13 | $cert = Get-LicCertificate -AdminAddress $licenseServerQueryAddress 14 | Set-ConfigSiteMetadata -Name "CertificateHash" -Value $cert.certhash -------------------------------------------------------------------------------- /LoginAM/TrustXMLPort.ps1: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------- 2 | # 3 | # Trust Broker XML Port 4 | # 5 | # 2015 Thomas Krampe - t.krampeloginconsultants.com 6 | # Login Consultants Germany GmbH 7 | # 8 | # ---------------------------------------------------- 9 | 10 | Set-ExecutionPolicy Bypass 11 | Import-Module citrix.* 12 | Add-PSSnapin citrix.* 13 | 14 | Write-Host "Set XML Port Trust" 15 | Set-BrokerSite -TrustRequestsSentToTheXmlServicePort $True -------------------------------------------------------------------------------- /Parallels/parallels_desktop_tools.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Patch Parallels Desktop Tool installation on CentOS or Alma Linux 3 | 4 | if [[ ! -d "/run/media/$(whoami)/Parallels Tools" ]]; then 5 | echo "Please mount parallels tools disk before install" 6 | exit 7 | fi 8 | 9 | echo "Copy install files to /tmp/parallels_fixed" 10 | cp -rf "/run/media/$(whoami)/Parallels Tools" /tmp/parallels_fixed 11 | chmod -R 755 /tmp/parallels_fixed 12 | cd /tmp/parallels_fixed/kmods 13 | echo "Unpack prl_mod.tar.gz" 14 | tar -xzf prl_mod.tar.gz 15 | rm prl_mod.tar.gz 16 | echo "Patch prl_fs/SharedFolders/Guest/Linux/prl_fs/super.c" 17 | sed '1i\#include ' -i prl_fs/SharedFolders/Guest/Linux/prl_fs/super.c 18 | echo "Repack prl_mod.tar.gz" 19 | tar -zcvf prl_mod.tar.gz . dkms.conf Makefile.kmods > /dev/null 20 | cd /tmp/parallels_fixed 21 | echo "Start install" 22 | sudo ./install 23 | echo "Remove /tmp/parallels_fixed" 24 | rm -rf /tmp/parallels_fixed 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Welcome to GitHub Pages 2 | 3 | You can use the [editor on GitHub](https://github.com/thomaskrampe/PowerShell/edit/master/README.md) to maintain and preview the content for your website in Markdown files. 4 | 5 | Whenever you commit to this repository, GitHub Pages will run [Jekyll](https://jekyllrb.com/) to rebuild the pages in your site, from the content in your Markdown files. 6 | 7 | ### Markdown 8 | 9 | Markdown is a lightweight and easy-to-use syntax for styling your writing. It includes conventions for 10 | 11 | ```markdown 12 | Syntax highlighted code block 13 | 14 | # Header 1 15 | ## Header 2 16 | ### Header 3 17 | 18 | - Bulleted 19 | - List 20 | 21 | 1. Numbered 22 | 2. List 23 | 24 | **Bold** and _Italic_ and `Code` text 25 | 26 | [Link](url) and ![Image](src) 27 | ``` 28 | 29 | For more details see [GitHub Flavored Markdown](https://guides.github.com/features/mastering-markdown/). 30 | 31 | ### Jekyll Themes 32 | 33 | Your Pages site will use the layout and styles from the Jekyll theme you have selected in your [repository settings](https://github.com/thomaskrampe/PowerShell/settings). The name of this theme is saved in the Jekyll `_config.yml` configuration file. 34 | 35 | ### Support or Contact 36 | 37 | Having trouble with Pages? Check out our [documentation](https://help.github.com/categories/github-pages-basics/) or [contact support](https://github.com/contact) and we’ll help you sort it out. 38 | -------------------------------------------------------------------------------- /URL shortener/longurl.ps1: -------------------------------------------------------------------------------- 1 | Function ShortURL { 2 | <# 3 | .SYNOPSIS 4 | ShortURL 5 | .DESCRIPTION 6 | Shorten a long URL with my own YOURLS instance and put the result in the clipboard 7 | .PARAMETER longURL 8 | The log URL 9 | .EXAMPLE 10 | ShortURL "https://www.example.com" 11 | .NOTES 12 | Author : Name | E-Mail 13 | Version : 1.0 14 | Creation date : 18.04.2021 | v0.1 | Initial script 15 | Last change : 18.04.2021 | v1.0 | Release 16 | 17 | IMPORTANT NOTICE 18 | ---------------- 19 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 20 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 21 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 22 | HEREIN, NOT FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 23 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 24 | OF SUCH DAMAGES IN ADVANCE. 25 | #> 26 | 27 | [CmdletBinding()] 28 | Param( 29 | [Parameter(Mandatory=$true, Position = 0)][String]$longurl 30 | ) 31 | 32 | begin { 33 | 34 | Set-Variable Signature -Option ReadOnly -Value 9695dd257c 35 | 36 | } 37 | 38 | process { 39 | 40 | $url ="http://t13k.de/yourls-api.php?signature=$Signature&action=shorturl&format=simple&url=$longurl" 41 | $request = Invoke-WebRequest $url 42 | $shorturl = $request.Content 43 | Set-Clipboard -Value $shorturl 44 | } 45 | 46 | end { 47 | 48 | } 49 | } #EndFunction ShortURL 50 | 51 | ShortURL "https://www.test.com" 52 | # SIG # Begin signature block 53 | # MIIIWwYJKoZIhvcNAQcCoIIITDCCCEgCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB 54 | # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR 55 | # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUH2wFszO6oK8wY3yKN10IG7rd 56 | # uAWgggW1MIIFsTCCBJmgAwIBAgITRQAAAAgrN2P01EvyBwAAAAAACDANBgkqhkiG 57 | # 9w0BAQsFADBYMRMwEQYKCZImiZPyLGQBGRYDbmV0MRUwEwYKCZImiZPyLGQBGRYF 58 | # bXljdHgxEjAQBgoJkiaJk/IsZAEZFgJhZDEWMBQGA1UEAxMNUFJELVBEQy0wMS1D 59 | # QTAeFw0yMTA1MDkyMDQwMDVaFw0yMjA1MDkyMDQwMDVaMGgxEzARBgoJkiaJk/Is 60 | # ZAEZFgNuZXQxFTATBgoJkiaJk/IsZAEZFgVteWN0eDESMBAGCgmSJomT8ixkARkW 61 | # AmFkMQ4wDAYDVQQDEwVVc2VyczEWMBQGA1UEAxMNQWRtaW5pc3RyYXRvcjCCASIw 62 | # DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANdukhCGSP4sOAK+/jFFL7FkaWBq 63 | # 1SvhMZCGEiH4dW5uVRd3GQQ0qbZjtqDb0UgPrdVpqwN5AwfFf4ZAPWPRwnV0Xzmd 64 | # wC5ldfe67Kun3ap4HdFyEn+enliC1dvHh+V3ni+JrkuQgMNbSZVHlVUm9x3dbFOs 65 | # bU5Uh5QX7XzN/IUSHWaTDhGHV5DuPyC3LDdyx/PqpasQ3l6LyWT03o/iZs9K59Pl 66 | # fajRK706WdAWSJG3PtcXFIISculMTvAwhEh13zcTwkyQhBn6TwX5Rkt0VJTVszuJ 67 | # ljY+x16riv6PX/sP1cwHuaGaqZkfIOkA0dfNQqRZGV3o+RpXaQL02fUeTWcCAwEA 68 | # AaOCAmIwggJeMCUGCSsGAQQBgjcUAgQYHhYAQwBvAGQAZQBTAGkAZwBuAGkAbgBn 69 | # MBMGA1UdJQQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQU 70 | # Axagk/BjWCsjdP1cAW3UXqofzpgwHwYDVR0jBBgwFoAUHOPAVbD46aGl7SbNYy5k 71 | # tBfKB7EwgdIGA1UdHwSByjCBxzCBxKCBwaCBvoaBu2xkYXA6Ly8vQ049UFJELVBE 72 | # Qy0wMS1DQSxDTj1wcmQtcGRjLTAxLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBT 73 | # ZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWFkLERDPW15 74 | # Y3R4LERDPW5ldD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0 75 | # Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwgcMGCCsGAQUFBwEBBIG2MIGzMIGw 76 | # BggrBgEFBQcwAoaBo2xkYXA6Ly8vQ049UFJELVBEQy0wMS1DQSxDTj1BSUEsQ049 77 | # UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJh 78 | # dGlvbixEQz1hZCxEQz1teWN0eCxEQz1uZXQ/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29i 79 | # amVjdENsYXNzPWNlcnRpZmljYXRpb25BdXRob3JpdHkwNQYDVR0RBC4wLKAqBgor 80 | # BgEEAYI3FAIDoBwMGkFkbWluaXN0cmF0b3JAYWQubXljdHgubmV0MA0GCSqGSIb3 81 | # DQEBCwUAA4IBAQACX6w0Ajzts5YQUn96ScF/DF9Jr7+8dln+yOAjvisTrJ5RxVne 82 | # AwwkUTtx30qWWdWW6xJRDcrSB7GdxS71ujnXsHQu2bJfKwWAPssrKXGFEKlgUHvh 83 | # gdip+BoyQ1+5hX5Z6xP3Y8CRh+XvtrRJhbseQAVilqU8Hpv4OMw/s/RHDRrTNzgV 84 | # SzjZ9B84faoHlFznvuRyvqrK9ieiHTz5TCwEq9X/gVkDZmMlbroy5gkpMn2/WxVG 85 | # N+j3SqmbwQPFbPLv5mBWhcnTnWPEkA+I7Cuch4vewE6oVc0+uq9wnlVuXJNNYA4n 86 | # /xzFof7mXYiWpoPMt3389dMrFqv6KgZdH2o/MYICEDCCAgwCAQEwbzBYMRMwEQYK 87 | # CZImiZPyLGQBGRYDbmV0MRUwEwYKCZImiZPyLGQBGRYFbXljdHgxEjAQBgoJkiaJ 88 | # k/IsZAEZFgJhZDEWMBQGA1UEAxMNUFJELVBEQy0wMS1DQQITRQAAAAgrN2P01Evy 89 | # BwAAAAAACDAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZ 90 | # BgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYB 91 | # BAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUiAxuWfn5jZjpA/cEnMf8F6wklGQwDQYJ 92 | # KoZIhvcNAQEBBQAEggEAaf4Ahv93g0KkNo38hdBOc1PTkwoKGxZCLfSNp2lzw+Ap 93 | # OPSvOkTW4O9i9nVKKjDbFPP5Q+UyBrMoEhs9cGOaoKxqiFIftkh6WcUUBZAPMKR/ 94 | # KXn6mWWiTViVrkoNpGhC8go6RUhroheGVJ/28HU0xMRh1SPLEOwOrPEnX3X91NGW 95 | # 4Xh4aATMW5AGCaWRE+gMW9VC5KazSGUy2rhChg/O9xyEQTrBY+kGZ9mTYyDaBwq3 96 | # wV7lSlUiVSFb2YWElTGIuqNtS/cc+MxHufqexYZY4F/0KiMfQ04tyCPwcJ1nHxVF 97 | # z/OFzJJGSnVup+Yno8ZAAvoYYk4Ibgi0jNQYuE+VJw== 98 | # SIG # End signature block 99 | -------------------------------------------------------------------------------- /User Profiles/CleanUpUserProfile.ps1: -------------------------------------------------------------------------------- 1 | function remove-itembyage { 2 | <# 3 | .SYNOPSIS 4 | remove items from folders recursively. 5 | 6 | .DESCRIPTION 7 | this function removes items older than a specified age from the target folder 8 | 9 | .PARAMETER Days 10 | Specifies the ammount of days since the file was last written to you wish to filter on. 11 | 12 | .PARAMETER Path 13 | Specifies the path to the folder you wish to search recursively. 14 | 15 | .PARAMETER Silent 16 | Instructs the function not to return any output. 17 | 18 | .EXAMPLE 19 | PS C:\> remove-itembyage -days 0 -path $recent 20 | 21 | This command searches the $recent directory, for any files, then deletes them. 22 | 23 | .EXAMPLE 24 | PS C:\> remove-itembyage -days 5 -path $recent 25 | 26 | This command searches the $recent directory, for files older than 5 days, then deletes them. 27 | 28 | .EXAMPLE 29 | PS C:\> remove-itembyage -days 10 -path $appdata -typefilter "txt,log" 30 | 31 | This command searches the $cookies directory, for files older than 10 days and end with txt or log extensions, then deletes them. 32 | 33 | .EXAMPLE 34 | PS C:\> remove-itembyage -days 10 -path $cookies -typefilter "txt,log" -silent 35 | 36 | This command searches the $cookies directory, for files older than 10 days and end with txt or log extensions, then deletes them without a report. 37 | 38 | .NOTES 39 | http://stealthpuppy.com/user-virtualization/profile-clean-up-script-powershell-edition/ for support information. 40 | 41 | .LINK 42 | http://stealthpuppy.com/user-virtualization/profile-clean-up-script-powershell-edition/ 43 | #> 44 | 45 | [cmdletbinding(SupportsShouldProcess=$True)] 46 | 47 | param( 48 | [Parameter(Mandatory=$true, Position=0,HelpMessage="Number of days to filter by, E.G. ""14""")] 49 | [int]$days, 50 | [Parameter(Mandatory=$true, Position=1,HelpMessage="Path to files you wish to delete")] 51 | [string]$path, 52 | [string]$typefilter, 53 | [switch]$silent 54 | ) 55 | 56 | #check for silent switch 57 | if ($silent){$ea="Silentlycontinue"} 58 | Else {$ea="Continue"} 59 | 60 | #check for typefilter, creates an array if specified. 61 | if (!($typefilter)){$filter="*"} 62 | Else{$filter=foreach ($item in $typefilter.split(",")){$item.insert(0,"*.")}} 63 | 64 | if (test-path $path){ 65 | $now=get-date 66 | $datefilter=$now.adddays(-$days) 67 | foreach ($file in get-childitem "$path\*" -recurse -force -include $filter | where {$_.PSIsContainer -eq $false -and $_.lastwritetime -le $datefilter -and $_.name -ne "desktop.ini"}){ 68 | if (!($silent)){write-host "Deleting: $($file.fullname)"} 69 | remove-item -literalPath $file.fullname -force -ea $ea 70 | } #end for 71 | } #end if 72 | 73 | Else{ 74 | if (!($silent)){write-warning "the path specified does not exist! ($path)"} 75 | } #end else 76 | } #end function 77 | 78 | #Get KnownFolder Paths 79 | $appdata=$env:appdata 80 | $Cookies=(new-object -com shell.application).namespace(289).Self.Path 81 | $History=(new-object -com shell.application).namespace(34).Self.Path 82 | $recent=(new-object -com shell.application).namespace(8).Self.Path 83 | $profile=$env:userprofile 84 | 85 | #commands 86 | remove-itembyage -days 0 -path $appdata -typefilter "txt,log" -silent -whatif 87 | remove-itembyage -days 90 -path $cookies -silent -whatif 88 | remove-itembyage -days 14 -path $recent -silent -whatif 89 | remove-itembyage -days 21 -path $history -silent -whatif 90 | remove-itembyage -days 14 -path "$appdata\Microsoft\office\Recent" -silent -whatif 91 | -------------------------------------------------------------------------------- /User Profiles/TK_CreateTestUserFromCSV.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CreateTestUserFromCSV { 2 | <# 3 | .SYNOPSIS 4 | TK_CreatTestUserFromCSV 5 | .DESCRIPTION 6 | Create test user from CSV file 7 | 8 | Example CSV 9 | user,password,realname 10 | homer,Password!,Homer Simpson 11 | bart,Password!,Bart Simpson 12 | 13 | .PARAMETER CSVFile 14 | Full path to the CSV file eg. testuser.csv 15 | .PARAMETER TargetPath 16 | Root path for folder creation eg. C:\Users 17 | .PARAMETER LogFile 18 | This parameter contains the full path, the file name and file extension to the log file (e.g. C:\Logs\MyApps\MylogFile.log) 19 | .EXAMPLE 20 | TK_CreateFolderFromCSV -CSVFile "testuser.csv" - TargetPath "C:\Users" 21 | .LINK 22 | https://github.com/thomaskrampe/PowerShell/blob/master/User%20Profiles/TK_CreateUserFolderFromCSV.ps1 23 | .NOTES 24 | Author : Thomas Krampe | thomas.krampe@myctx.net 25 | Version : 1.0 26 | Creation date : 13.03.2019 | v0.1 | Initial script 27 | Last change : 21.02.2019 | v1.0 | Add script documentation 28 | 29 | IMPORTANT NOTICE 30 | ---------------- 31 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 32 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 33 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 34 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 35 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 36 | OF SUCH DAMAGES IN ADVANCE. 37 | 38 | #> 39 | 40 | [CmdletBinding()] 41 | Param( 42 | [Parameter(Mandatory=$true)][String]$CSVFile, 43 | [Parameter(Mandatory=$true)][String]$BaseOU, 44 | [Parameter(Mandatory=$true)][String]$Domain, 45 | [Parameter(Mandatory=$true)][String]$UserGroup 46 | ) 47 | 48 | begin { 49 | 50 | # Check if Module ActiveDirectory is available and loaded 51 | if (Get-Module -ListAvailable -Name "ActiveDirectory") { 52 | Write-Verbose "Module Active Directory exists." 53 | if (!(Get-Module "ActiveDirectory")) { 54 | Write-Verboset "Module ActiveDirectory is not loaded." 55 | Import-Module ActiveDirectory 56 | } 57 | } 58 | Else { 59 | Write-Verbose "Module ActiveDirectory not available or not installed." 60 | Exit 1 61 | } 62 | } 63 | 64 | process { 65 | # Create Active Directory Group Object 66 | if (!(Get-ADGroup -Filter {Name -eq $UserGroup} )) { 67 | Write-Verbose "Active Directory group object doesn't exist" 68 | New-ADGroup -Name $UserGroup -SamAccountName $UserGroup -GroupCategory Security -GroupScope Global -DisplayName $UserGroup -Path "CN=Users,$BaseOU" -Description "Script created group" 69 | } 70 | Else { 71 | Write-Verbose "AD Group already exist. Exit script" 72 | Exit 1 73 | } 74 | 75 | # Verify if CSV file in script directory exist 76 | $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition 77 | if (!(Test-Path -Path $scriptPath + "\" + $CSVFile)) { 78 | Write-Verbose "CSV file not available. Exit script." 79 | Exit 1 80 | } 81 | 82 | $CSVSource = Import-CSV -Path $scriptPath + "\" + $CSVFile -Delimiter "," 83 | 84 | foreach ($CSVObject in $CSVSource) { 85 | $UPName = $($CSVObject.user) + "@" + $Domain 86 | 87 | Write-Verbose "Creating user $($CSVObject.realname)." 88 | New-ADUser -Name $($CSVObject.user) -SamAccountName $($CSVObject.user) -UserPrincipalName $UPName -PasswordNeverExpires $true -OtherAttributes @{'mail'="chewdavid@fabrikam.com"} 89 | 90 | New-Item -ItemType directory -Path $CreateFolder | Out-Null 91 | if ( $(Try { Test-Path $CreateFolder.trim() } Catch { $false }) ) { 92 | Write-Verbose "Folder $CreateFolder created successful." 93 | } 94 | Else { 95 | Write-Error "Creating folder $CreateFolder failed." -targetobject $_ -Category WriteError -RecommendedAction "Maybe missing permissions." 96 | } 97 | } 98 | } 99 | 100 | end { 101 | } 102 | } -------------------------------------------------------------------------------- /User Profiles/TK_CreateUserFolderFromCSV.ps1: -------------------------------------------------------------------------------- 1 | Function TK_CreateFolderFromCSV { 2 | <# 3 | .SYNOPSIS 4 | TK_CreateFolderFromCSV 5 | .DESCRIPTION 6 | Create user folders from CSV file 7 | 8 | Example CSV 9 | user,password,realname 10 | homer,Password!,Homer Simpson 11 | bart,Password!,Bart Simpson 12 | .PARAMETER CSVFile 13 | Full path to the CSV file eg. C:\Temp\userlist.csv 14 | .PARAMETER TargetPath 15 | Root path for folder creation eg. C:\Users 16 | .PARAMETER LogFile 17 | This parameter contains the full path, the file name and file extension to the log file (e.g. C:\Logs\MyApps\MylogFile.log) 18 | .EXAMPLE 19 | TK_CreateFolderFromCSV -CSVFile "C:\Temp\userlist.csv" - TargetPath "C:\Users" 20 | .LINK 21 | https://github.com/thomaskrampe/PowerShell/blob/master/User%20Profiles/TK_CreateUserFolderFromCSV.ps1 22 | .NOTES 23 | Author : Thomas Krampe | thomas.krampe@myctx.net 24 | Version : 1.0 25 | Creation date : 21.02.2019 | v0.1 | Initial script 26 | Last change : 21.02.2019 | v1.0 | Add script documentation 27 | 28 | IMPORTANT NOTICE 29 | ---------------- 30 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 31 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 32 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 33 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 34 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 35 | OF SUCH DAMAGES IN ADVANCE. 36 | 37 | #> 38 | 39 | [CmdletBinding()] 40 | Param( 41 | [Parameter(Mandatory=$true)][String]$CSVFile, 42 | [Parameter(Mandatory=$true)][String]$TargetPath 43 | ) 44 | 45 | begin { 46 | } 47 | 48 | process { 49 | $CSVSource = Import-CSV -Path $CSVFile -Delimiter "," 50 | 51 | foreach ($CSVObject in $CSVSource) { 52 | $CreateFolder = $TargetPath + "\" + $($CSVObject.User) 53 | Write-Verbose "Creating folder $CreateFolder." 54 | New-Item -ItemType directory -Path $CreateFolder | Out-Null 55 | if ( $(Try { Test-Path $CreateFolder.trim() } Catch { $false }) ) { 56 | Write-Verbose "Folder $CreateFolder created successful." 57 | } 58 | Else { 59 | Write-Error "Creating folder $CreateFolder failed." -targetobject $_ -Category WriteError -RecommendedAction "Maybe missing permissions." 60 | } 61 | } 62 | } 63 | 64 | end { 65 | } 66 | } -------------------------------------------------------------------------------- /User Profiles/TK_ReadFromINI.ps1: -------------------------------------------------------------------------------- 1 | Function TK_ReadFromINI { 2 | <# 3 | .SYNOPSIS 4 | TK_ReadFromINI 5 | .DESCRIPTION 6 | Get values from INI file 7 | 8 | Example INI 9 | ----------- 10 | [owner] 11 | name=Thomas Krampe 12 | organization=MyCTX 13 | 14 | [informations] 15 | hostname=sqlserver 16 | ipaddress=192.168.1.2 17 | 18 | .PARAMETER filePath 19 | Full path to the INI file eg. C:\Temp\server.ini 20 | .EXAMPLE 21 | $INIValues = TK_ReadFromINI -filePath "C:\Temp\server.ini" 22 | 23 | You can then access values like this: 24 | $Server = $INIValues.informations.server 25 | $Organization = $INIValues.owner.organization 26 | 27 | .LINK 28 | https://github.com/thomaskrampe/PowerShell/blob/master/User%20Profiles/TK_ReadFromINI.ps1 29 | .NOTES 30 | Author : Thomas Krampe | thomas.krampe@myctx.net 31 | Version : 1.0 32 | Creation date : 21.02.2019 | v0.1 | Initial script 33 | Last change : 21.02.2019 | v1.0 | Add script documentation 34 | 35 | IMPORTANT NOTICE 36 | ---------------- 37 | THIS SCRIPT IS PROVIDED "AS IS" WITHOUT WARANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 38 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 39 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED 40 | HEREIN, NOT FOR DIRECT, INCIDENTIAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM FURNISHING, 41 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 42 | OF SUCH DAMAGES IN ADVANCE. 43 | 44 | #> 45 | 46 | [CmdletBinding()] 47 | 48 | Param( 49 | [Parameter(Mandatory=$true)][String]$filePath 50 | ) 51 | 52 | begin { 53 | } 54 | 55 | process { 56 | 57 | $anonymous = "NoSection" 58 | $ini = @{} 59 | switch -regex -file $filePath 60 | { 61 | "^\[(.+)\]$" # Section 62 | { 63 | $section = $matches[1] 64 | $ini[$section] = @{} 65 | $CommentCount = 0 66 | } 67 | 68 | "^(;.*)$" # Comment 69 | { 70 | if (!($section)) { 71 | $section = $anonymous 72 | $ini[$section] = @{} 73 | } 74 | $value = $matches[1] 75 | $CommentCount = $CommentCount + 1 76 | $name = "Comment" + $CommentCount 77 | $ini[$section][$name] = $value 78 | } 79 | 80 | "(.+?)\s*=\s*(.*)" # Key 81 | { 82 | if (!($section)) { 83 | $section = $anonymous 84 | $ini[$section] = @{} 85 | } 86 | $name,$value = $matches[1..2] 87 | $ini[$section][$name] = $value 88 | } 89 | } 90 | return $ini 91 | 92 | } 93 | 94 | end { 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /User Profiles/testuser.csv: -------------------------------------------------------------------------------- 1 | user,password,realname 2 | bart,Password!,Bart Simpson 3 | homer,Password!,Homer Simpson 4 | barney,Password!,Barney Gumble 5 | -------------------------------------------------------------------------------- /Windows/InstallVcRedist.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # Install all the Visual C Redistributables silently 3 | # 4 | 5 | # Install prerequisites 6 | Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force 7 | 8 | # Install and Import PowerShell Module 9 | Install-Module VcRedist -AllowClobber -Force 10 | Import-Module VcRedist 11 | 12 | # Create target path if not present 13 | $Path = "C:\Temp\VcRedist" 14 | if (!(Test-Path $Path)) 15 | { 16 | New-Item -itemType Directory -Path C:\Temp\ -Name VcRedist 17 | } 18 | 19 | # Download redistributables 20 | $VcList = Get-VcList | Get-VcRedist -Path "C:\Temp\VcRedist" 21 | 22 | # Install redistributables 23 | $VcList | Install-VcRedist -Path C:\Temp\VcRedist 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Windows/List-ProcessesExtended.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | List-ProcessesExtended.ps1 4 | 5 | .DESCRIPTION 6 | List processes with their dependent services 7 | 8 | .EXAMPLE 9 | List-ProcessesExtended.ps1 10 | 11 | .NOTES 12 | Author : Thomas Krampe | thomas@myctx.net 13 | Version : 1.0 14 | Creation date : 07.01.2023 | v0.1 | Initial script 15 | Last change : 07.01.2023 | v1.0 | Release it to GitHub 16 | 17 | NOTICE 18 | THIS SCRIPT IS PROVIDED “AS IS” WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 19 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 20 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED HEREIN, 21 | NOR FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM THE FURNISHING, 22 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 23 | OF SUCH DAMAGES IN ADVANCE. 24 | #> 25 | 26 | $gps = Get-Process 27 | $procIDs = gcim -Class Win32_Service 28 | foreach ($prs in $gps) { 29 | "Process: $($prs.ProcessName)" 30 | $x = $procIDs | ? {$_.ProcessId -eq $prs.Id} 31 | foreach ($dps in $x) { 32 | write-host " Dependent service: $($dps.Name)" -ForegroundColor Green 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Windows/WindowsUpdate/README.md: -------------------------------------------------------------------------------- 1 | # Install Windows Updates 2 | 3 | This script update your windows server based on a simple txt file with name "servers.txt" (one machine per line). This file should be saved in the script directory. 4 | 5 | If a reboot is required after installing updates, the target machine will be restarted automatically via 'Restart-Computer' CMDlet. If don't like this just add the -NoRestart parameter. 6 | 7 | If you don't have a hashed password in a local file, use -NoLocalPW to be prompted for credentials. 8 | 9 | ## Why sequential and not parallel? 10 | 11 | You are right, a sequential run needs a lot of time but I want to make sure that the servers are up and running before continuing. You can control the reboot in the servers.txt for instance. Just start with your first domain controller for example and have your second domain controller in line 3, 4 or 5. This gives dc1 enough time to reboot before starting with dc2. But if you don't like my way of thinking, re-write my script to your needs. 12 | 13 | ## Screenshots 14 | 15 | Download Updates 16 | ![Downloading updates](images/windows-updates2.png) 17 | 18 | Installing Updates 19 | ![Installing updates](images/windows-updates1.png) 20 | 21 | Update finished 22 | ![Update finished](images/windows-updates3.png) 23 | -------------------------------------------------------------------------------- /Windows/WindowsUpdate/images/windows-updates1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/Windows/WindowsUpdate/images/windows-updates1.png -------------------------------------------------------------------------------- /Windows/WindowsUpdate/images/windows-updates2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/Windows/WindowsUpdate/images/windows-updates2.png -------------------------------------------------------------------------------- /Windows/WindowsUpdate/images/windows-updates3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomaskrampe/PowerShell/85e17d1b06a331db140f072637d37ddfce0d8974/Windows/WindowsUpdate/images/windows-updates3.png -------------------------------------------------------------------------------- /Windows/WindowsUpdate/windows-updates.ps1: -------------------------------------------------------------------------------- 1 | #Requires -RunAsAdministrator 2 | #Requires -Version 5.1 3 | 4 | <# 5 | .SYNOPSIS 6 | Install Windows Updates 7 | 8 | .DESCRIPTION 9 | Install Windows Updates using a server list 10 | 11 | .EXAMPLE 12 | Output: 13 | ----------------------------------------------------------------------------------------------------------------------- 14 | PS C:\Temp> C:\Temp\windows-updates.ps1 15 | Starting Windows Updates on server1.demo.local 16 | Windows Malicious Software Removal Tool x64 - v5.98 (KB890830) 17 | 2022-02 Cumulative Update Preview for .NET Framework 3.5, 4.7.2 and 4.8 for Windows Server 2019 for x64 (KB5011267) 18 | Security Intelligence Update for Microsoft Defender Antivirus - KB2267602 (Version 1.359.1358.0) 19 | 2022-02 Cumulative Update for Windows Server 2019 (1809) for x64-based Systems (KB5010351) 20 | 21 | Installing 4 updates. 22 | True 23 | Reboot required on server1.demo.local 24 | ----------------------------------------------------------------------------------------------------------------------- 25 | 26 | .PARAMETER NoRestart 27 | Suppress restart 28 | 29 | .PARAMETER LocalPW 30 | Ask for credentials (don't use saved credentials in a password file) 31 | 32 | .LINK 33 | https://github.com/thomaskrampe/PowerShell/tree/master/Windows/WindowsUpdate 34 | 35 | .NOTES 36 | Author : Thomas Krampe | t.krampe@loginconsultants.de 37 | Version : 1.3 38 | Creation date : 04.03.2022 | v0.1 | Initial script 39 | 05.03.2022 | v1.0 | first release 40 | 06.03.2022 | v1.1 | Add NoRestart parameter 41 | 07.03.2022 | v1.2 | Add NoLocalPassword parameter, Add Path Variables 42 | Last change : 10.03.2022 | v1.3 | Remove some typos 43 | 44 | NOTICE 45 | THIS SCRIPT IS PROVIDED “AS IS” WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 46 | ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. 47 | THOMAS KRAMPE, SHALL NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED HEREIN, 48 | NOR FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES RESULTING FROM THE FURNISHING, 49 | PERFORMANCE, OR USE OF THIS SCRIPT, EVEN IF THOMAS KRAMPE HAS BEEN ADVISED OF THE POSSIBILITY 50 | OF SUCH DAMAGES IN ADVANCE. 51 | #> 52 | 53 | param 54 | ( 55 | # Turn automatic reboot off and prevent saved password file 56 | [Parameter()][Switch]$NoRestart, 57 | [Parameter()][switch]$NoLocalPW 58 | ) 59 | 60 | # Change your path and file name here 61 | $ServersListPath = "" 62 | $PasswordFilePath = "" 63 | 64 | if (-not($ServersListPath)) { 65 | $ServersListPath = "$PSSCriptRoot\servers.txt" 66 | } 67 | 68 | if (-not($PasswordFilePath)) { 69 | $PasswordFilePath = "$PSScriptRoot\password.txt" 70 | } 71 | 72 | # Read servers.txt content 73 | If (-not(Test-Path -Path $ServersListPath -PathType Leaf )) { 74 | Write-Host "Servers file doesn't exist, exit script." -ForegroundColor Red 75 | exit 1 76 | } else { 77 | $servers = Get-Content $ServersListPath 78 | } 79 | 80 | # Authentication 81 | if ($NoLocalPW) { 82 | $Credential = Get-Credential 83 | } else { 84 | $HexPass = Get-Content $PasswordFilePath 85 | $Credential = New-Object -TypeName PSCredential -ArgumentList "administrator@demo.local", ($HexPass | ConvertTo-SecureString) 86 | } 87 | 88 | # Start the main loop 89 | ForEach ($server in $servers) { 90 | 91 | # Get available updates for target server 92 | write-host "Starting Windows Updates on $server" 93 | 94 | try { 95 | $up = Invoke-Command -ComputerName $server -ScriptBlock {Start-WUScan -SearchCriteria "Type='Software' AND IsInstalled=0"} -Credential $Credential 96 | } 97 | catch { 98 | throw $_.Exception.Message 99 | } 100 | 101 | if ($up) { 102 | # Installing updates on target server 103 | $upc = $up.count 104 | write-host "Found $upc update(s)." -ForegroundColor Green 105 | 106 | for ($num = 0 ; $num -le $upc ; $num++){ 107 | write-host " "$up[$num].Title 108 | } 109 | 110 | $cs = New-CimSession -ComputerName $server -Credential $Credential 111 | Install-WUUpdates -Updates $up -CimSession $cs 112 | 113 | $rb = Invoke-Command -ComputerName $server -ScriptBlock {Get-WUIsPendingReboot} -Credential $Credential 114 | 115 | if ($rb -eq $true) { 116 | write-host "Reboot required on $server." -ForegroundColor Yellow 117 | 118 | # Reboot server 119 | if (-not($NoRestart)) { 120 | write-host "Restart initiated on $server." -ForegroundColor Yellow 121 | Restart-Computer -ComputerName $server -Credential $Credential -force 122 | } else { 123 | write-host "Automatic restart prevented with -NoRestart switch. Please restart the targets manually." -ForegroundColor Red 124 | } 125 | } 126 | else { 127 | write-host "No reboot required on $server" -ForegroundColor Green 128 | } 129 | } 130 | else { 131 | write-host "No Updates available for $server" -ForegroundColor Green 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /WorkingWithFiles/TK_Copy-WithProgress.ps1: -------------------------------------------------------------------------------- 1 | function Copy-WithProgress { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter(Mandatory = $true)] 5 | [string] $Source 6 | , [Parameter(Mandatory = $true)] 7 | [string] $Destination 8 | , [int] $Gap = 200 9 | , [int] $ReportGap = 2000 10 | ) 11 | # Author: https://stackoverflow.com/users/189198/trevor-sullivan 12 | 13 | # Define regular expression that will gather number of bytes copied 14 | $RegexBytes = '(?<=\s+)\d+(?=\s+)'; 15 | 16 | #region Robocopy params 17 | # MIR = Mirror mode 18 | # NP = Don't show progress percentage in log 19 | # NC = Don't log file classes (existing, new file, etc.) 20 | # BYTES = Show file sizes in bytes 21 | # NJH = Do not display robocopy job header (JH) 22 | # NJS = Do not display robocopy job summary (JS) 23 | # TEE = Display log in stdout AND in target log file 24 | $CommonRobocopyParams = '/MIR /NP /NDL /NC /BYTES /NJH /NJS'; 25 | #endregion Robocopy params 26 | 27 | #region Robocopy Staging 28 | Write-Verbose -Message 'Analyzing robocopy job ...'; 29 | $StagingLogPath = '{0}\temp\{1} robocopy staging.log' -f $env:windir, (Get-Date -Format 'yyyy-MM-dd HH-mm-ss'); 30 | 31 | $StagingArgumentList = '"{0}" "{1}" /LOG:"{2}" /L {3}' -f $Source, $Destination, $StagingLogPath, $CommonRobocopyParams; 32 | Write-Verbose -Message ('Staging arguments: {0}' -f $StagingArgumentList); 33 | Start-Process -Wait -FilePath robocopy.exe -ArgumentList $StagingArgumentList -NoNewWindow; 34 | # Get the total number of files that will be copied 35 | $StagingContent = Get-Content -Path $StagingLogPath; 36 | $TotalFileCount = $StagingContent.Count - 1; 37 | 38 | # Get the total number of bytes to be copied 39 | [RegEx]::Matches(($StagingContent -join "`n"), $RegexBytes) | % { $BytesTotal = 0; } { $BytesTotal += $_.Value; }; 40 | Write-Verbose -Message ('Total bytes to be copied: {0}' -f $BytesTotal); 41 | #endregion Robocopy Staging 42 | 43 | #region Start Robocopy 44 | # Begin the robocopy process 45 | $RobocopyLogPath = '{0}\temp\{1} robocopy.log' -f $env:windir, (Get-Date -Format 'yyyy-MM-dd HH-mm-ss'); 46 | $ArgumentList = '"{0}" "{1}" /LOG:"{2}" /ipg:{3} {4}' -f $Source, $Destination, $RobocopyLogPath, $Gap, $CommonRobocopyParams; 47 | Write-Verbose -Message ('Beginning the robocopy process with arguments: {0}' -f $ArgumentList); 48 | $Robocopy = Start-Process -FilePath robocopy.exe -ArgumentList $ArgumentList -Verbose -PassThru -NoNewWindow; 49 | Start-Sleep -Milliseconds 100; 50 | #endregion Start Robocopy 51 | 52 | #region Progress bar loop 53 | while (!$Robocopy.HasExited) { 54 | Start-Sleep -Milliseconds $ReportGap; 55 | $BytesCopied = 0; 56 | $LogContent = Get-Content -Path $RobocopyLogPath; 57 | $BytesCopied = [Regex]::Matches($LogContent, $RegexBytes) | ForEach-Object -Process { $BytesCopied += $_.Value; } -End { $BytesCopied; }; 58 | $CopiedFileCount = $LogContent.Count - 1; 59 | Write-Verbose -Message ('Bytes copied: {0}' -f $BytesCopied); 60 | Write-Verbose -Message ('Files copied: {0}' -f $LogContent.Count); 61 | $Percentage = 0; 62 | if ($BytesCopied -gt 0) { 63 | $Percentage = (($BytesCopied/$BytesTotal)*100) 64 | } 65 | Write-Progress -Activity Robocopy -Status ("Copied {0} of {1} files; Copied {2} of {3} bytes" -f $CopiedFileCount, $TotalFileCount, $BytesCopied, $BytesTotal) -PercentComplete $Percentage 66 | } 67 | #endregion Progress loop 68 | 69 | #region Function output 70 | [PSCustomObject]@{ 71 | BytesCopied = $BytesCopied; 72 | FilesCopied = $CopiedFileCount; 73 | }; 74 | #endregion Function output 75 | } 76 | 77 | # 1. TESTING: Generate a random, unique source directory, with some test files in it 78 | $TestSource = '{0}\{1}' -f $env:temp, [Guid]::NewGuid().ToString(); 79 | $null = mkdir -Path $TestSource; 80 | # 1a. TESTING: Create some test source files 81 | 1..20 | % -Process { Set-Content -Path $TestSource\$_.txt -Value ('A'*(Get-Random -Minimum 10 -Maximum 2100)); }; 82 | 83 | # 2. TESTING: Create a random, unique target directory 84 | $TestTarget = '{0}\{1}' -f $env:temp, [Guid]::NewGuid().ToString(); 85 | $null = mkdir -Path $TestTarget; 86 | 87 | # 3. Call the Copy-WithProgress function 88 | Copy-WithProgress -Source $TestSource -Destination $TestTarget -Verbose; 89 | 90 | # 4. Add some new files to the source directory 91 | 21..40 | % -Process { Set-Content -Path $TestSource\$_.txt -Value ('A'*(Get-Random -Minimum 950 -Maximum 1400)); }; 92 | 93 | # 5. Call the Copy-WithProgress function (again) 94 | Copy-WithProgress -Source $TestSource -Destination $TestTarget -Verbose; -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /terraform/Install_PS_Core.ps1: -------------------------------------------------------------------------------- 1 | # Install Powershell Core 2 | 3 | # Install Chocolatey 4 | Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | Invoke-Expression 5 | 6 | # Install PowerShell core 7.1.3 7 | & C:\ProgramData\chocolatey\choco.exe install powershell-core --version=7.1.3 -y 8 | 9 | # Install nano 10 | & C:\ProgramData\chocolatey\choco.exe install nano -y 11 | 12 | Start-Sleep -Seconds 120 13 | 14 | # Update PATH variable 15 | $env:Path = "C:\Program Files\PowerShell\7;C:\ProgramData\chocolatey;" + $env:Path 16 | 17 | # Set pwsh-core as default ssh shell 18 | # Set-ItemProperty -Path "HKLM:\Software\OpenSSH" -Name "DefaultShell" -Value "C:\Program Files\PowerShell\7\pwsh.exe" 19 | ######################################################################################################################### 20 | # Why I don't do this? 21 | # If we use choco to install additional software we can't upgrade powershell-core from powershell-core 22 | # in that case it's better to switch to build in PowerShell, upgrade the package and execute pwsh again. 23 | ######################################################################################################################### 24 | 25 | # Create an AllUsersCurrentHost profile 26 | if (!(Test-Path -Path $PROFILE.AllUsersAllHosts)) { 27 | New-Item -ItemType File -Path $PSHOME\profile.ps1 -Force 28 | Add-Content -Path $PSHOME\Profile.ps1 -Value 'function Prompt { "PS [" + $env:COMPUTERNAME + "] " + (Get-Location) + "> " }' 29 | } 30 | 31 | # Set service start type 32 | Set-Service -Name ssh-agent -StartupType 'Automatic' 33 | Set-Service -Name sshd -StartupType 'Automatic' 34 | 35 | # Restart services 36 | Restart-Service sshd 37 | Restart-Service ssh-agent 38 | -------------------------------------------------------------------------------- /terraform/Install_Preparation_OpenSSH.ps1: -------------------------------------------------------------------------------- 1 | Import-Module -Name 'NetSecurity' 2 | 3 | # Setup windows update service to manual 4 | $wuauserv = Get-WmiObject Win32_Service -Filter "Name = 'wuauserv'" 5 | $wuauserv_starttype = $wuauserv.StartMode 6 | Set-Service wuauserv -StartupType Manual 7 | 8 | # Install OpenSSH Server 9 | Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 10 | 11 | # Install OpenSSH Client 12 | # Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 13 | 14 | # Set service start type 15 | Set-Service -Name ssh-agent -StartupType 'Automatic' 16 | Set-Service -Name sshd -StartupType 'Automatic' 17 | 18 | # Start services 19 | Start-Service ssh-agent 20 | Start-Service sshd 21 | 22 | # Setup windows update service to original 23 | Set-Service wuauserv -StartupType $wuauserv_starttype 24 | 25 | # Configure Powershell as default ssh shell 26 | New-ItemProperty -Path "HKLM:\Software\OpenSSH" -Name "DefaultShell" -Value "$Env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force 27 | 28 | # Restart the service 29 | Restart-Service sshd 30 | 31 | # Configure SSH public key 32 | $content = @" 33 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDTtDthK1ChMH22xFIMMH1oPL2/ZMW+Bb1t1IU1rXu+Zy+JLmT/pblVBUR0ZGi7lcCCHaVe7iDiLD07LXWTjsj481cARSh8POsy5BRUp3oBDycUygmHMBswbCWj3pnlvCC7P6c3wVLT2VF5c/3Bt907lwp6jMSq6v27j12cTjZm3FX3I/nGC0hRR9ovdXJRnuWHb7Dd/wgFXk75zydFKFmfZ/K5b7lhX1qHp0k7eh3bGKsRB4LwZG7ShcEBdL6/uZjB9JQlt6E4OJ94s50ihE+kB07yBu3HbrXs8VA6ulAJjTjpgWCWeT/BFcsLEOdGh6ong3kHsaC/B/dbBsvy1KtFzHAJZlge4kj7GWiaoAQT/oyAH7NC5ZL/e4iWFCV/1R5RraVo0bGSQD8imuyNBcfbQM8saPfx0Frlbc21PCM0ut7jN6c+FWkf4MxXMJsnce0R5+JOcdew5WwF4FUCqdO5EVPL5KPs6u4tTIi3cmI2Da7y7QuBSGSFcG6kcTBIMw0= cloud@lic-ans-1 34 | "@ 35 | 36 | # Write public key to file 37 | $content | Set-Content -Path "$Env:ProgramData\ssh\administrators_authorized_keys" 38 | 39 | # Set acl on administrators_authorized_keys 40 | $admins = ([System.Security.Principal.SecurityIdentifier]'S-1-5-32-544').Translate( [System.Security.Principal.NTAccount]).Value 41 | $acl = Get-Acl $Env:ProgramData\ssh\administrators_authorized_keys 42 | $acl.SetAccessRuleProtection($true, $false) 43 | $administratorsRule = New-Object system.security.accesscontrol.filesystemaccessrule($admins,"FullControl","Allow") 44 | $systemRule = New-Object system.security.accesscontrol.filesystemaccessrule("SYSTEM","FullControl","Allow") 45 | $acl.SetAccessRule($administratorsRule) 46 | $acl.SetAccessRule($systemRule) 47 | $acl | Set-Acl 48 | 49 | # Open Windows Firewall for SSH traffic inbound 50 | New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 51 | 52 | -------------------------------------------------------------------------------- /terraform/optimize-powershell-assemblies.ps1: -------------------------------------------------------------------------------- 1 | function Optimize-PowershellAssemblies { 2 | # NGEN powershell assembly, improves startup time of powershell by 10x 3 | $old_path = $env:path 4 | try { 5 | $env:path = [Runtime.InteropServices.RuntimeEnvironment]::GetRuntimeDirectory() 6 | [AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object { 7 | if (! $_.location) {continue} 8 | $Name = Split-Path $_.location -leaf 9 | if ($Name.startswith("Microsoft.PowerShell.")) { 10 | Write-Progress -Activity "Native Image Installation" -Status "$name" 11 | ngen install $_.location | ForEach-Object {"`t$_"} 12 | } 13 | } 14 | } finally { 15 | $env:path = $old_path 16 | } 17 | } 18 | 19 | Optimize-PowershellAssemblies --------------------------------------------------------------------------------