├── .gitignore ├── Network └── disable-NetBios.ps1 ├── ActiveDirectory ├── Configure-AD.ps1 ├── get-CVE20201472Events.ps1 ├── Get-LAPSAuditReport.ps1 ├── install-AD.ps1 ├── install-DC.ps1 ├── move-FSMO.ps1 ├── execute-RemoteScriptWithLAPS.ps1 ├── Get-ADPermissionsReport.ps1 ├── Reset-DSRM.ps1 ├── Locate-46xx.ps1 ├── Locate-ADLockout.ps1 ├── get-adinfo.ps1 └── Repair-DFSR.ps1 ├── Dokumente └── Zertifizierungsstellen mit Windows Server 2012R2.pdf ├── Linux-Files ├── allow_github.squid ├── allow_vscode.squid ├── allow_psgallery.squid └── allow_windowsupdate.squid ├── .github ├── workflows │ └── gernerate-docs.yml ├── FUNDING.yml └── copilot-instructions.md ├── Intune ├── Readme.md ├── create-package.ps1 └── get-AutopilotLogs.ps1 ├── BitLocker ├── Start-Bitlocker.ps1 ├── List-BitLockerrecoveryKeys.ps1 └── Update-BitLockerRecovery.ps1 ├── Azure ├── Install-AzModule.ps1 └── Install-AzCopy.ps1 ├── WSUS ├── Reset-WSUSClient.cmd └── start-WsusServerSync.ps1 ├── GPO ├── get-GPOreport.ps1 ├── invoke-GPupdateDomain.ps1 ├── Check-LocalGroupPolicy.ps1 └── get-GPOBackup.ps1 ├── install-greenshot.ps1 ├── generate-hosts.ps1 ├── User ├── Get-LastLogonOU.ps1 └── create-user.ps1 ├── Windows ├── set-cert4rdp.ps1 └── Remove-AzureArc.ps1 ├── README.md ├── Set-Network.ps1 ├── send-files.ps1 ├── Exchange ├── Set-Ex2013Vdir.ps1 └── Set-MaintananceMode.ps1 ├── Get-WindowsSid.ps1 ├── Set-WinRelease.ps1 └── New-DokuwikiAnimal.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | hosts 2 | -------------------------------------------------------------------------------- /Network/disable-NetBios.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfrastructureHeroes/Scipts/HEAD/Network/disable-NetBios.ps1 -------------------------------------------------------------------------------- /ActiveDirectory/Configure-AD.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfrastructureHeroes/Scipts/HEAD/ActiveDirectory/Configure-AD.ps1 -------------------------------------------------------------------------------- /Dokumente/Zertifizierungsstellen mit Windows Server 2012R2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfrastructureHeroes/Scipts/HEAD/Dokumente/Zertifizierungsstellen mit Windows Server 2012R2.pdf -------------------------------------------------------------------------------- /Linux-Files/allow_github.squid: -------------------------------------------------------------------------------- 1 | # GitHub URL list for squid ACL (Fabian Niesen - InfrastrukturHelden.de) 2 | # add to squid.conf: 3 | # acl github dstdomain "/etc/squid/allow_github.squid" 4 | # http_access allow github 5 | 6 | .github.com 7 | -------------------------------------------------------------------------------- /.github/workflows/gernerate-docs.yml: -------------------------------------------------------------------------------- 1 | name: generate docs 2 | on: 3 | [push] 4 | jobs: 5 | docs: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout 9 | uses: actions/checkout@main 10 | - name: Generate docs 11 | uses: Microsoft/ps-docs@main 12 | -------------------------------------------------------------------------------- /Linux-Files/allow_vscode.squid: -------------------------------------------------------------------------------- 1 | # Visual Studio Code URL list for squid ACL (Fabian Niesen - InfrastrukturHelden.de) 2 | # add to squid.conf: 3 | # acl vscode dstdomain "/etc/squid/allow_vscode.squid" 4 | # http_access allow vscode 5 | 6 | # extension gallery 7 | marketplace.visualstudio.com 8 | .vsassets.io 9 | 10 | -------------------------------------------------------------------------------- /Intune/Readme.md: -------------------------------------------------------------------------------- 1 | # Microsoft Intune Scripts 2 | 3 | ## get-AutopilotLogs.ps1 4 | Script to gather some Logs and Information for troubleshoot failed Autopilot Pre-Provisionings. Best to be run fro USB thumbdrive. 5 | 6 | ## create-package.ps1 7 | Create Intunewin Files from Sourcefolders. Install Commands must be located in install.cmd 8 | 9 | Check https://github.com/InfrastructureHeroes/Intune-Apps for a more complete solution 10 | -------------------------------------------------------------------------------- /Linux-Files/allow_psgallery.squid: -------------------------------------------------------------------------------- 1 | # NuGet URL list for squid ACL (Fabian Niesen - InfrastrukturHelden.de) 2 | # based upon https://learn.microsoft.com/en-us/powershell/gallery/getting-started?view=powershellget-2.x 3 | # add to squid.conf: 4 | # acl psgallery dstdomain "/etc/squid/allow_psgallery.squid" 5 | # http_access allow psgallery 6 | 7 | go.microsoft.com 8 | onegetcdn.azureedge.net 9 | psg-prod-centralus.azureedge.net 10 | psg-prod-eastus.azureedge.net 11 | az818661.vo.msecnd.net 12 | # For Website 13 | devopsgallerystorage.blob.core.windows.net 14 | *.powershellgallery.com 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: InfrastructureHeroes 4 | patreon: infrastrukturhelden 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: fabian_niesen 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /BitLocker/Start-Bitlocker.ps1: -------------------------------------------------------------------------------- 1 | $Pin = ConvertTo-SecureString "123456" -AsPlainText -Force 2 | Add-BitlockerKeyProtector -MountPoint $env:SystemDrive -RecoveryPasswordProtector 3 | $BLV = Get-BitLockerVolume -MountPoint "C:" Backup-BitLockerKeyProtector -MountPoint "C:" -KeyProtectorId $BLV.KeyProtector[0].KeyProtectorId 4 | Enable-BitLocker -MountPoint C: -TpmAndPinProtector -Pin $Pin -SkipHardwareTest -UsedSpaceOnly 5 | While ((Get-BitLockerVolume -MountPoint $env:SystemDrive).VolumeStatus -eq "EncryptionInProgress") { 6 | $encPercent = (Get-BitLockerVolume -MountPoint $env:SystemDrive).EncryptionPercentage 7 | Write-Progress -Activity "Encrypting $env:SystemDrive" -PercentComplete $encPercent -Status "$encPercent% complete" 8 | sleep -m 1000 9 | } 10 | Write-Progress -Activity "Encrypting $env:SystemDrive" -Status "Done" -Completed 11 | -------------------------------------------------------------------------------- /Linux-Files/allow_windowsupdate.squid: -------------------------------------------------------------------------------- 1 | # Windows Update URL list for squid ACL (Fabian Niesen - InfrastrukturHelden.de) 2 | # based upon https://learn.microsoft.com/de-de/security-updates/WindowsUpdateServices/18127640 and https://learn.microsoft.com/en-us/windows-server/administration/windows-server-update-services/deploy/2-configure-wsus#211-connection-from-the-wsus-server-to-the-internet 3 | # add to squid.conf: 4 | # acl windowsupdate dstdomain "/etc/squid/allow_windowsupdate.squid" 5 | # http_access allow windowsupdate 6 | 7 | 8 | definitionupdates.microsoft.com 9 | .windowsupdate.microsoft.com 10 | .update.microsoft.com 11 | .windowsupdate.com 12 | download.microsoft.com 13 | wustat.windows.com 14 | ntservicepack.microsoft.com 15 | go.microsoft.com 16 | .delivery.mp.microsoft.com 17 | download.visualstudio.microsoft.com 18 | www.microsoft.com 19 | 20 | -------------------------------------------------------------------------------- /BitLocker/List-BitLockerrecoveryKeys.ps1: -------------------------------------------------------------------------------- 1 | $computers = get-adobject -Filter * | Where-Object {$_.ObjectClass -eq "msFVE-RecoveryInformation"} 2 | 3 | $key = (read-host -Prompt "Enter starting portion of recovery key ID").ToUpper() 4 | $records = $computers | where {$_.DistinguishedName -like "*{$key*"} 5 | foreach ($rec in $records) { 6 | $computer = get-adcomputer -identity ($records.DistinguishedName.Split(",")[1]).split("=")[1] 7 | $recoveryPass = Get-ADObject -Filter {objectclass -eq 'msFVE-RecoveryInformation'} -SearchBase $computer.DistinguishedName -Properties 'msFVE-RecoveryPassword' | where {$_.DistinguishedName -like "*$key*"} 8 | [pscustomobject][ordered]@{ 9 | Computer = $computer 10 | 'Recovery Key ID' = $rec.Name.Split("{")[1].split("}")[0] 11 | 'Recovery Password' = $recoveryPass.'msFVE-RecoveryPassword' 12 | } | Format-List 13 | } -------------------------------------------------------------------------------- /Azure/Install-AzModule.ps1: -------------------------------------------------------------------------------- 1 | Write-Verbose "Check for Admin" 2 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) 3 | { 4 | $arguments = "& '" + $myinvocation.mycommand.definition + "'" 5 | Start-Process powershell -Verb runAs -ArgumentList $arguments 6 | Break 7 | } 8 | If (!(Get-PackageProvider NuGet -ErrorAction SilentlyContinue).count -ge 1 ) { Install-PackageProvider -Name NuGet -Force -Confirm:$false } ELSE { Write-Output "NuGet Provider already configured"} 9 | If (!(get-module PowerShellGet -ErrorAction SilentlyContinue).count -ge 1 ) { Install-Module PowerShellGet -Force -Confirm:$false } ELSE { Write-Output "PowershellGet already installed"} 10 | If (!(get-command Connect-AzAccount -ErrorAction SilentlyContinue).count -ge 1 ) { Install-Module Az -Force -Confirm:$false } ELSE { Write-Output "Az Module already installed"} -------------------------------------------------------------------------------- /ActiveDirectory/get-CVE20201472Events.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Checks all Domain Controller for Event ID 5827-5829 in the System Eventlog 4 | 5 | .DESCRIPTION 6 | Checks all Domain Controller for Event ID 5827-5829 in the System Eventlog. This are the Event for connections witch will be blockt startin 9 Feb. 2021 due CVE-2020-1472. 7 | 8 | .EXAMPLE 9 | C:\PS> get-CVE20201472Events.ps1 10 | 11 | .NOTES 12 | Author : Fabian Niesen (www.fabian-niesen.de) 13 | Filename : get-CVE20201472Events.ps1 14 | Requires : PowerShell Version 3.0 15 | Version : 1.0 16 | History : 1.0 FN 17.01.2021 initial version 17 | 18 | 19 | .LINK 20 | https://www.infrastrukturhelden.de/?p=14850 21 | #> 22 | 23 | Param() 24 | 25 | $ErrorActionPreference = "Stop" 26 | 27 | try { Import-Module activedirectory } catch { Write-Warning "ActiveDirectory Module ist missing. Please install first"; break } 28 | $DCs = Get-ADDomainController -Filter { OperatingSystemVersion -like "*" } 29 | Write-Output "Found $($DCs.count) Domain Controllers in Active Directory" 30 | Write-Progress -activity "Query Eventlogs" -Status "starting" -PercentComplete "0" -Id 1 31 | [int]$i = "0" 32 | ForEach ($DC in $DCs) 33 | { 34 | $i++ 35 | Write-Progress -activity "Query Eventlogs" -Status "$($DC.HostName)" -PercentComplete ((($i / $DCs.count)*100)-5) -Id 1 36 | Write-Output $DC.HostName 37 | Get-EventLog -ComputerName $DC.HostName -LogName "System" | Where-Object { $_.EventID -eq 5829 -or $_.EventID -eq 5827 -or $_.EventID -eq 5828 } | select -First 10 38 | } -------------------------------------------------------------------------------- /ActiveDirectory/Get-LAPSAuditReport.ps1: -------------------------------------------------------------------------------- 1 | #@{Name="Title";Expression={[string]$_.Title}},@{Name="KB Article";Expression={[string]::join(' | ',$_.KnowledgebaseArticles[0])}}, 2 | 3 | $Events = (Get-WinEvent -FilterHashtable @{ LogName='Security'; Id='4662'; StartTime=$((Get-Date).AddHours(-1)) } | Where-Object { $_.Message -like "*f3531ec6-6330-4f8e-8d39-7a671fbac605*" } ) 4 | 5 | $Results = @() 6 | ForEach ($Event in $Events) { 7 | [XML]$XMLEvent = $Event.ToXml() 8 | # $Event.TimeCreated 9 | # $(($XMLEvent.Event.EventData.Data | ? { $_.Name -like "SubjectUserName"}).'#text') 10 | $(($XMLEvent.Event.EventData.Data | ? { $_.Name -like "SubjectUserName"}).'#text') 11 | $Results += [PSCustomObject]@{ 12 | 'TimeCreated' = $Event.TimeCreated 13 | 'SubjectUserName' = $(($XMLEvent.Event.EventData.Data | ? { $_.Name -like "SubjectUserName"}).'#text') 14 | 'MachineName' = $Event.MachineName 15 | 'KeywordsDisplayNames' = $Event.KeywordsDisplayNames 16 | 'Computer' = $XMLEvent.Event.System.Computer 17 | } 18 | } 19 | $Results | ft -AutoSize 20 | 21 | <# .Event.EventData.data 22 | 23 | Name #text 24 | ---- ----- 25 | SubjectUserSid S-1-5-18 26 | SubjectUserName DC01$ 27 | SubjectDomainName lapsifh 28 | SubjectLogonId 0x1e78212 29 | ObjectServer DS 30 | ObjectType %{bf967a86-0de6-11d0-a285-00aa003049e2} 31 | ObjectName %{c9064d61-1d2b-46f0-b9ca-b4d5b35249c7} 32 | OperationType Object Access 33 | HandleId 0x0 34 | AccessList %%7688... 35 | AccessMask 0x100 36 | Properties %%7688... 37 | AdditionalInfo - 38 | AdditionalInfo2 39 | #> -------------------------------------------------------------------------------- /Azure/Install-AzCopy.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Download and install the actual version of AzCopy for the executing User 4 | 5 | .DESCRIPTION 6 | Download and install the actual version of AzCopy for the executing User 7 | 8 | .EXAMPLE 9 | C:\PS> Install-AzCopy.ps1 10 | 11 | .EXAMPLE 12 | C:\PS> Install-AzCopy.ps1 -targetfolder'C:\Program Files' 13 | 14 | 15 | .PARAMETER targetfolder 16 | Path to install AzCopy. Default is UserProfile 17 | 18 | .NOTES 19 | Author : Fabian Niesen (www.fabian-niesen.de) 20 | Filename : Install-AzCopy.ps1 21 | Requires : PowerShell Version 3.0 22 | Version : 1.0 23 | History : 1.0 FN 05.08.2022 initial version 24 | 25 | .LINK 26 | https://github.com/InfrastructureHeroes/Scipts 27 | #> 28 | 29 | Param( 30 | [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$true)] 31 | [String]$targetfolder = $env:USERPROFILE 32 | ) 33 | 34 | #Internal parameters 35 | $zipfile = $targetfolder + "\AzCopy.zip" 36 | $azfolder = $targetfolder + "\AzCopy" 37 | #Download AzCopy to Profile 38 | Invoke-WebRequest -Uri "https://aka.ms/downloadazcopy-v10-windows" -OutFile $zipfile -UseBasicParsing 39 | 40 | #Expand Archive and remove ZIP 41 | Expand-Archive $zipfile $azfolder -Force 42 | Remove-Item $zipfile -Force 43 | #Move exe from Subfolder, but leave subfolder for Version lookup 44 | Get-ChildItem $($azfolder +"\*\azcopy.exe") | Move-Item -Destination $azfolder -Force 45 | #Set Path for the user 46 | $userenvpath = [System.Environment]::GetEnvironmentVariable("Path", "User") 47 | IF ($userenvpath.contains($azfolder)) { Write-Output "Path already set" } Else { [System.Environment]::SetEnvironmentVariable("PATH", $userenv + ";"+$azfolder , "User") } -------------------------------------------------------------------------------- /Intune/create-package.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Create Intunewin Files from Sourcefolders 4 | 5 | .DESCRIPTION 6 | Create Intunewin Files from Sourcefolders. Install Commands must be located in install.cmd 7 | 8 | .EXAMPLE 9 | create-package.ps1 -workpath "path to Install" -ContentPrepTool "Path to ContentPrepTool Executable file" 10 | 11 | .PARAMETER workpath 12 | Workfolder for Win32 app packaging. Source files must be in subfolder "Source\Application Name". Output will be in "Output" 13 | 14 | .PARAMETER ContentPrepTool 15 | Path to ContentPrepTool Executable file 16 | 17 | .NOTES 18 | Author : Fabian Niesen 19 | Filename : create-package.ps1 20 | Requires : PowerShell Version 3.0 21 | Version : 1.0 22 | History : 1.0.0 FN 19.04.2021 initial version 23 | 24 | .LINK 25 | https://github.com/FabianNiesen/Infrastrukturhelden.de 26 | #> 27 | 28 | Param( 29 | [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$False)] 30 | [String]$workpath = "C:\Users\fabian_niesen\OneDrive - Dell Technologies\Documents\_Install", 31 | [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$False)] 32 | [String]$ContentPrepTool ="C:\Users\fabian_niesen\OneDrive - Dell Technologies\Documents\GitHub\Microsoft-Win32-Content-Prep-Tool\IntuneWinAppUtil.exe" 33 | ) 34 | $date = get-date -format yyyyMMdd-HHmm 35 | Write-Progress -activity "Preparing Workdir: $workdir" -Status "starting" -PercentComplete "0" -Id 1 36 | [int]$i = "0" 37 | $Sources = (Get-ChildItem -Path $($workpath+"\Source")).Name 38 | foreach ($Source in $Sources) 39 | { 40 | $i++ 41 | Write-Progress -activity "Processing Sources" -Status "$($Source)" -PercentComplete (($i / $Sources.count)*100) -Id 1 42 | Write-Verbose $Source 43 | $c = $workpath+"\Source\"+$Source 44 | $s = $workpath+"\Source\"+$Source+"\install.cmd" 45 | $o = $workpath+"\Output\"+$date+"\"+$Source 46 | Write-Verbose "Starte ContentPrep" 47 | & $ContentPrepTool -c $c -s $s -o $o -q 48 | Write-Verbose "ContentPrep abgeschlossen" 49 | } 50 | -------------------------------------------------------------------------------- /ActiveDirectory/install-AD.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | 4 | .DESCRIPTION 5 | 6 | .EXAMPLE 7 | 8 | .INPUTS 9 | Keine. 10 | .OUTPUTS 11 | Keine. 12 | .NOTES 13 | Author : Fabian Niesen 14 | Filename : 15 | Requires : PowerShell Version 2.0 16 | 17 | Version : 0.1 18 | History : 0.1 FN 26.111.2015 initial version 19 | 20 | .LINK 21 | 22 | #> 23 | # Variable declaration 24 | $DOM ="" 25 | $NETBIOS ="" 26 | $SMADMIPW ="" 27 | 28 | # End of declaration - do not edit below this Point! 29 | 30 | $ErrorActionPreference = "Stop" 31 | $before = Get-Date 32 | $date = get-date -format yyyyMMdd-HHmm 33 | $ErrorLog =$BackupPath+$date+"-error.log" 34 | $WarningLog =$BackupPath+$date+"-warning.log" 35 | 36 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) 37 | { 38 |     Write-Warning "You need Admin Permissions to run this script!"| Out-file $ErrorLog -Append 39 | break    40 | } 41 | 42 | Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools Import-Module ADDSDeployment Install-ADDSForest ` 43 | -CreateDnsDelegation:$false ` 44 | -DatabasePath "C:\Windows\NTDS" ` 45 | -DomainMode "Win2012R2" ` 46 | -DomainName $DOM ` 47 | -DomainNetbiosName $NETBIOS ` 48 | -ForestMode "Win2012R2" ` 49 | -InstallDns:$true ` 50 | -LogPath "C:\Windows\NTDS" ` 51 | -NoRebootOnCompletion:$false ` 52 | -SysvolPath "C:\Windows\SYSVOL" ` 53 | -Force:$true ` 54 | -SafeModeAdministratorPassword (ConvertTo-SecureString $SMADMIPW -AsPlainText -Force) 55 | 56 | 57 | 58 | 59 | $after = Get-Date 60 | 61 | $time = $after - $before 62 | $buildTime = "`nBuild finished in "; 63 | if ($time.Minutes -gt 0) 64 | { 65 | $buildTime += "{0} minute(s) " -f $time.Minutes; 66 | } 67 | 68 | $buildTime += "{0} second(s)" -f $time.Seconds; 69 | Write-host "$buildTime" -------------------------------------------------------------------------------- /ActiveDirectory/install-DC.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | 4 | .DESCRIPTION 5 | 6 | .EXAMPLE 7 | 8 | .INPUTS 9 | Keine. 10 | .OUTPUTS 11 | Keine. 12 | .NOTES 13 | Author : Fabian Niesen 14 | Filename : 15 | Requires : PowerShell Version 2.0 16 | 17 | Version : 0.1 18 | History : 0.1 FN 26.111.2015 initial version 19 | 20 | .LINK 21 | 22 | #> 23 | 24 | Param( 25 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 26 | [String]$DOM ="demo.infrastrukturhelden.de", 27 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 28 | [String]$NETBIOS ="DEMO", 29 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 30 | [String]$SMADMINPW ="Chang3M3!" 31 | ) 32 | 33 | 34 | # End of declaration - do not edit below this Point! 35 | 36 | $ErrorActionPreference = "Stop" 37 | $before = Get-Date 38 | $date = get-date -format yyyyMMdd-HHmm 39 | $ErrorLog =$BackupPath+$date+"-error.log" 40 | $WarningLog =$BackupPath+$date+"-warning.log" 41 | 42 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) 43 | { 44 | Write-Warning "You need Admin Permissions to run this script!"| Out-file $ErrorLog -Append 45 | break 46 | } 47 | 48 | Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools 49 | Import-Module ADDSDeployment 50 | Install-ADDSForest -CreateDnsDelegation:$false -DatabasePath "C:\Windows\NTDS" -DomainMode "Win2012R2" -DomainName $DOM -DomainNetbiosName $NETBIOS -ForestMode "Win2012R2" -InstallDns:$true -LogPath "C:\Windows\NTDS" -NoRebootOnCompletion:$false -SysvolPath "C:\Windows\SYSVOL" -Force:$true -SafeModeAdministratorPassword (ConvertTo-SecureString $SMADMINPW -AsPlainText -Force) 51 | 52 | $after = Get-Date 53 | 54 | $time = $after - $before 55 | $buildTime = "`nBuild finished in "; 56 | if ($time.Minutes -gt 0) 57 | { 58 | $buildTime += "{0} minute(s) " -f $time.Minutes; 59 | } 60 | 61 | $buildTime += "{0} second(s)" -f $time.Seconds; 62 | Write-host "$buildTime" -------------------------------------------------------------------------------- /WSUS/Reset-WSUSClient.cmd: -------------------------------------------------------------------------------- 1 | @Echo off 2 | Echo ===WSUS Client reset by Fabian Niesen - www.infratrukturhelden.de === 3 | Echo Stopping BITS 4 | net stop bits 5 | ECHO =Stopping Windows Update Service= 6 | net stop wuauserv 7 | timeout /t 30 /nobreak 8 | Echo =de-register wuaueng.dll= 9 | %windir%\system32\regsvr32.exe /s /u wuaueng.dll 10 | echo =Deleting AU cache...= 11 | del /f /s /q %windir%\SoftwareDistribution\*.* 12 | del /f /s /q %windir%\windowsupdate.log 13 | echo =Registering DLLs...= 14 | %windir%\system32\regsvr32.exe /s %windir%\system32\wuaueng.dll 15 | %windir%\system32\regsvr32.exe /s %windir%\system32\MSXML.DLL 16 | %windir%\system32\regsvr32.exe /s %windir%\system32\MSXML2.DLL 17 | %windir%\system32\regsvr32.exe /s %windir%\system32\MSXML3.DLL 18 | %windir%\system32\regsvr32.exe /s %windir%\system32\wups2.dll 19 | %windir%\system32\regsvr32.exe /s %windir%\system32\wuaueng1.dll 20 | %windir%\system32\regsvr32.exe /s %windir%\system32\wuaueng.dll 21 | %windir%\system32\regsvr32.exe /s %windir%\system32\wuapi.dll 22 | %windir%\system32\regsvr32.exe /s %windir%\system32\atl.dll 23 | %windir%\system32\regsvr32.exe /s %windir%\system32\jscript.dll 24 | %windir%\system32\regsvr32.exe /s %windir%\system32\softpub.dll 25 | %windir%\system32\regsvr32.exe /s %windir%\system32\wuapi.dll 26 | %windir%\system32\regsvr32.exe /s %windir%\system32\wuaueng1.dll 27 | %windir%\system32\regsvr32.exe /s %windir%\system32\wucltui.dll 28 | %windir%\system32\regsvr32.exe /s %windir%\system32\wups.dll 29 | %windir%\system32\regsvr32.exe /s %windir%\system32\wuweb.dll 30 | ECHO =Cleaning registry...= 31 | reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /v AccountDomainSid /f 32 | reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /v PingID /f 33 | reg delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /v SusClientId /f 34 | reg Delete HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate /v SusClientIDValidation /f 35 | Echo =Starting BITS= 36 | net start bits 37 | ECHO =Starting Windows Update Services= 38 | net start wuauserv 39 | Timeout /t 30 /nobreak 40 | ECHO =Reset Authorisation and Detect now= 41 | wuauclt.exe /resetauthorization /detectnow 42 | usoclient StartScan 43 | Echo =Done...= 44 | -------------------------------------------------------------------------------- /GPO/get-GPOreport.ps1: -------------------------------------------------------------------------------- 1 | ## Code sniplet from the path - not sure if its work... 2 | $ErrorActionPreference = "Stop" 3 | 4 | 5 | $GPOitem = New-Object psobject 6 | $GPOitem | Add-Member -MemberType NoteProperty -Name 'Policy' -Value $null 7 | $GPOitem | Add-Member -MemberType NoteProperty -Name 'LinkPath' -Value $null 8 | $GPOitem | Add-Member -MemberType NoteProperty -Name 'LinkEnabled' -Value $null 9 | $GPOitem | Add-Member -MemberType NoteProperty -Name 'LinkNoOverride' -Value $null 10 | $result = @{} 11 | try 12 | { 13 | Import-Module grouppolicy 14 | } 15 | catch 16 | { 17 | Write-Warning "GroupPolicy Module ist missing. Please install first" | Out-file $ErrorLog -Append 18 | break 19 | } 20 | $CSV = "\\UNC\Dokumentation\Intern\_Microsoft\GPOReport.CSV" 21 | "Policy, LinkPath, LinkEnabled, LinkNoOverride" | Out-file $CSV -Force 22 | 23 | $GPOS = get-GPO -all 24 | Write-host "Found $($GPOS.count) GPO" 25 | FOREACH ( $GPO in $GPOS) 26 | { 27 | [XML]$GPOv = Get-GPOReport -Name $GPO.DisplayName -ReportType XML 28 | #$GPOv.GPO | Write-Verbose 29 | $m = $GPOv.GPO.LinksTo.count 30 | Write-verbose "$m Links found $($GPO.DisplayName)" 31 | IF ($GPOv.GPO.LinksTo.count -gt 0) 32 | { 33 | 34 | Foreach ($link in $GPOv.GPO.LinksTo) 35 | { 36 | 37 | $GPOitem.Policy= $GPO.DisplayName 38 | $GPOitem.LinkPath= $link.SOMPath 39 | $GPOitem.LinkEnabled= $link.Enabled 40 | $GPOitem.LinkNoOverride= $link.NoOverride 41 | $GPOReport += , $GPOitem 42 | "$($GPO.DisplayName),$($link.SOMPath),$($link.Enabled),$($link.NoOverride)" | Out-file $CSV -Append 43 | } 44 | } 45 | ELSEIF ($GPOv.GPO.LinksTo.count -ne "0") 46 | { 47 | Write-Verbose "Count ne 0" 48 | 49 | $GPOitem.Policy= $GPO.DisplayName 50 | $GPOitem.LinkPath= $GPOv.GPO.LinksTo.SOMPath 51 | $GPOitem.LinkEnabled= $GPOv.GPO.LinksTo.Enabled 52 | $GPOitem.LinkNoOverride= $GPOv.GPO.LinksTo.NoOverride 53 | $GPOReport += , $GPOitem 54 | "$($GPO.DisplayName),$($link.SOMPath),$($link.Enabled),$($link.NoOverride)" | Out-file $CSV -Append 55 | } 56 | ELSE 57 | { 58 | Write-Warning "No Link found $($GPO.DisplayName) $m" 59 | $GPOitem.Policy= $GPO.DisplayName 60 | $GPOReport += , $GPOitem 61 | "$($GPO.DisplayName),,," | Out-file $CSV -Append 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /ActiveDirectory/move-FSMO.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 2.0 2 | #requires -modules activedirectory 3 | 4 | <# 5 | .SYNOPSIS 6 | Move FSMO roles to a new DC 7 | .DESCRIPTION 8 | This script moves FSMO roles to a new single DC. 9 | For more information check https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/fsmo-placement-and-optimization-on-ad-dcs 10 | .EXAMPLE 11 | move-FSMO.ps1 -Server DC -Forest -Domain 12 | .NOTES 13 | Author : Fabian Niesen 14 | Filename : move-FSMO.ps1 15 | Requires : PowerShell Version 2.0 16 | 17 | Version : 0.1 18 | History : 0.1 FN 10.02.2022 initial version 19 | 20 | .LINK 21 | https://gallery.technet.microsoft.com/Gesamtstruktur-Informations-63719eec 22 | #> 23 | [CmdLetBinding()] 24 | param( 25 | [Parameter(Mandatory = $false, Position = 1, ValueFromPipelineByPropertyName = $true, 26 | ValueFromPipeline = $True, 27 | HelpMessage = 'Specify Target Server' 28 | )][Alias("Target")] 29 | [string]$Server, 30 | [switch]$Forest, 31 | [switch]$Domain, 32 | [switch]$All, 33 | [switch]$whatIf 34 | ) 35 | Function list-FSMO { 36 | # List actual owner 37 | $forestdata = Get-ADForest 38 | $domaindata = Get-ADDomain 39 | $FSMO = @(@{DomainNamingMaster = $forestdata.DomainNamingMaster; SchemaMaster = $forestdata.SchemaMaster; InfrastructureMaster = $domaindata.InfrastructureMaster; PDCEmulator = $domaindata.PDCEmulator ; RIDMaster = $domaindata.RIDMaster}) 40 | $FSMO | ft 41 | } 42 | 43 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) 44 | { 45 | $arguments = "& '" + $myinvocation.mycommand.definition + "'" 46 | Start-Process powershell -Verb runAs -ArgumentList $arguments 47 | Break 48 | } 49 | 50 | list-FSMO 51 | If ($all) 52 | { 53 | $Forest = $true 54 | $Domain = $true 55 | } 56 | If ($whatIf) 57 | { 58 | If ($Forest) { Write-Output "This would be executed: Move-ADDirectoryServerOperationMasterRole -Identity $Server -OperationMasterRole DomainNamingMaster,SchemaMaster" } 59 | If ($Domain) { Write-Output "This would be executed: Move-ADDirectoryServerOperationMasterRole -Identity $Server -OperationMasterRole RIDMaster,InfrastructureMaster,PDCEmulator" } 60 | 61 | } 62 | ELSE 63 | { 64 | If ($Forest) { Move-ADDirectoryServerOperationMasterRole -Identity $Server -OperationMasterRole DomainNamingMaster,SchemaMaster -Confirm:$false } 65 | If ($Domain) { Move-ADDirectoryServerOperationMasterRole -Identity $Server -OperationMasterRole RIDMaster,InfrastructureMaster,PDCEmulator -Confirm:$false } 66 | } 67 | list-FSMO 68 | -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | # KI-Agent Anweisungen für Infra-Scripts 2 | 3 | Dieses Repository enthält eine Sammlung von PowerShell-Skripten für die Windows-Infrastrukturverwaltung. Hier sind die wichtigsten Informationen für KI-Agenten: 4 | 5 | ## Projektstruktur 6 | 7 | - Skripte sind nach Funktionsbereichen in Ordnern organisiert (z.B. `ActiveDirectory/`, `BitLocker/`, `WSUS/`) 8 | - Jeder Ordner enthält spezialisierte Skripte für den jeweiligen Bereich 9 | - Hauptverzeichnis enthält allgemeine Verwaltungsskripte 10 | 11 | ## Konventionen 12 | 13 | ### Skript-Reife 14 | - Skripte mit Versionierung im Header sind ausgereifter und besser getestet 15 | - Beispiel aus `GPO/get-GPOBackup.ps1`: Version wird als "V1.58" im Header angegeben 16 | 17 | ### Namenskonventionen 18 | - Verb-Substantiv Benennungsschema (PowerShell-Standard) 19 | - Präfixe zeigen Hauptfunktion: 20 | - `get-` für Abfragen 21 | - `set-` für Konfigurationen 22 | - `install-` für Installationen 23 | - `update-` für Aktualisierungen 24 | 25 | ### Fehlerbehandlung 26 | - PowerShell ErrorAction und Try-Catch Blöcke werden verwendet 27 | - Kritische Operationen haben Sicherheitsabfragen 28 | 29 | ## Hauptkomponenten 30 | 31 | ### Active Directory Management 32 | - Primäre Skripte in `ActiveDirectory/` 33 | - Kernfunktionen: DC-Installation, LAPS-Management, AD-Berechtigungen 34 | - Integration mit Windows-Ereignisprotokollen 35 | 36 | ### BitLocker Verwaltung 37 | - Zentrale Funktionen in `BitLocker/` 38 | - Fokus auf Wiederherstellungsschlüssel-Management und AD-Integration 39 | 40 | ### Gruppenrichtlinien (GPO) 41 | - Backup und Reporting in `GPO/` 42 | - Domänenweite Aktualisierungen 43 | - HTML-Berichterstellung für Dokumentation 44 | 45 | ### Benutzerverwaltung 46 | - Integration mit Microsoft 365 47 | - Automatisierte Benutzerbereitstellung 48 | - Audit und Reporting-Funktionen 49 | 50 | ## Entwicklungs-Workflow 51 | 52 | ### Testing 53 | - Skripte sollten in einer Testumgebung validiert werden 54 | - Parameter `-WhatIf` und `-Confirm` für sensitive Operationen verwenden 55 | 56 | ### Best Practices 57 | - Dokumentiere Änderungen im Skript-Header 58 | - Füge Kommentare für komplexe Operationen hinzu 59 | - Verwende standardisierte PowerShell-Parameter 60 | 61 | ## Wichtige Hinweise 62 | 63 | - Alle Skripte sind "Verwendung auf eigene Gefahr" 64 | - Einige Exchange-Skripte werden nicht mehr aktiv gepflegt 65 | - Bei Microsoft 365-Integration müssen entsprechende Berechtigungen vorhanden sein 66 | 67 | ## Beispiele 68 | 69 | ### GPO-Backup erstellen: 70 | ```powershell 71 | # Erstellt Backup und HTML-Report in timestamp-basiertem Unterordner 72 | .\get-GPOBackup.ps1 73 | ``` 74 | 75 | ### BitLocker-Wiederherstellungsschlüssel aktualisieren: 76 | ```powershell 77 | # Lädt fehlende BitLocker-Informationen ins AD hoch 78 | .\Update-BitLockerRecovery.ps1 79 | ``` -------------------------------------------------------------------------------- /install-greenshot.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Install ZIP-Version of GreenShot and create StartMenu entry 4 | 5 | .DESCRIPTION 6 | Install ZIP-Version of GreenShot and create StartMenu entry. This can be used to avoid the open Webpage in the Installer. 7 | The installer also open the Website if it is used with /Verysilent. 8 | This Skript was created for Unattened installation with MDT. 9 | 10 | .EXAMPLE 11 | C:\PS> install-greenshot.ps1 12 | 13 | .NOTES 14 | Author : Fabian Niesen (www.fabian-niesen.de) 15 | Filename : install-greenshot.ps1 16 | Requires : PowerShell Version 3.0 17 | License : The MIT License (MIT) 18 | Copyright (c) 2022-2025 Fabian Niesen 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 20 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 21 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 24 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 25 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 26 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 27 | connection with the software or the use or other dealings in the Software. 28 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 29 | The author assumes no responsibility for any damage or data loss caused by this script. 30 | Test thoroughly in a controlled environment before deploying to production. 31 | Version : 1.1 32 | History : 1.1 FN 03.12.2025 Change License to MIT, housekeeping Header 33 | 1.0 FN 08/07/2019 initial version 34 | 35 | .LINK 36 | https://www.infrastrukturhelden.de 37 | #> 38 | Expand-Archive -Force C:\Programme\Greenshot\Greenshot-NO-INSTALLER-1.2.10.6-RELEASE.zip C:\Programme\Greenshot 39 | Remove-Item C:\Programme\Greenshot\Greenshot-NO-INSTALLER-1.2.10.6-RELEASE.zip 40 | $WshShell = New-Object -comObject WScript.Shell 41 | $Shortcut = $WshShell.CreateShortcut("C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Greenshot.lnk") 42 | $Shortcut.TargetPath = "C:\Programme\Greenshot\Greenshot.exe" 43 | $Shortcut.Save() -------------------------------------------------------------------------------- /generate-hosts.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Generates a hosts file based on Active Directory 4 | .DESCRIPTION 5 | Generates a hosts file based on Active Directory 6 | .EXAMPLE 7 | C:\PS> Generate-Hosts.ps1 8 | 9 | .EXAMPLE 10 | C:\PS> Generate-Hosts.ps1 -export C:\Temp\hosts 11 | 12 | .PARAMETER export 13 | File path to export the final hosts file 14 | 15 | .NOTES 16 | Author : Fabian Niesen (www.fabian-niesen.de) 17 | Filename : Generate-Hosts.ps1 18 | Requires : PowerShell Version 3.0 19 | Version : 1.1 20 | History : 1.1 FN 03.12.2025 Change License to MIT, housekeeping Header 21 | 1.0 FN 28.09.2022 first official 22 | License : The MIT License (MIT) 23 | Copyright (c) 2022-2025 Fabian Niesen 24 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 25 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 26 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 27 | furnished to do so, subject to the following conditions: 28 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 29 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 30 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 31 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 32 | connection with the software or the use or other dealings in the Software. 33 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 34 | The author assumes no responsibility for any damage or data loss caused by this script. 35 | Test thoroughly in a controlled environment before deploying to production. 36 | 37 | .LINK 38 | https://github.com/InfrastructureHeroes/Scipts 39 | #> 40 | 41 | Param( 42 | $export = ".\hosts" 43 | ) 44 | $scriptversion = "1.1" 45 | Write-Output "Generate-Hosts.ps1 Version $scriptversion " 46 | import-module activedirectory 47 | IF ( Test-Path $export ) { Remove-Item $export -Force -Confirm:$false | out-null } 48 | $Computers = Get-ADComputer -filter "Enabled -eq 'true'" -Properties IPv4Address | Where-Object { $null -ne $_.IPv4Address } 49 | ForEach ($Computer in $Computers) 50 | { 51 | "$($Computer.IPv4Address) $($Computer.Name) $($Computer.DNSHostName)" | Out-File -FilePath $export -Append -Force 52 | } 53 | Get-Content $export -------------------------------------------------------------------------------- /ActiveDirectory/execute-RemoteScriptWithLAPS.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 4.0 2 | #requires -modules activedirectory 3 | #Requires -RunAsAdministrator 4 | <# 5 | .SYNOPSIS 6 | Execute a remote script with Local Admin account and Microsoft LAPS 7 | 8 | .DESCRIPTION 9 | Execute a remote script with Local Admin account and Microsoft LAPS 10 | 11 | .EXAMPLE 12 | C:\PS> execute-RemoteScriptWirhLAPS.ps1 13 | 14 | .EXAMPLE 15 | C:\PS> execute-RemoteScriptWirhLAPS.ps1 16 | 17 | .PARAMETER computer 18 | Computer to be used as remote target 19 | 20 | .PARAMETER ScriptBlock 21 | ScriptBlock to be executed remotely 22 | 23 | .PARAMETER admin 24 | Name of the Administrative account handled with LAPS 25 | 26 | .NOTES 27 | Author : Fabian Niesen (www.infrastrukturhelden.de) 28 | Filename : execute-RemoteScriptWirhLAPS 29 | Requires : PowerShell Version 4.0 30 | Version : 1.1 31 | History : 1.1 FN 08.09.2022 updated version, translated to english 32 | 1.0.0 FN 04.06.2019 initial version 33 | 34 | .LINK 35 | https://www.infrastrukturhelden.de/microsoft-infrastruktur/active-directory/powershell-skripte-mit-local-administrator-password-solution-laps-nutzen-und-auditieren/ 36 | #> 37 | 38 | Param( 39 | [Parameter(Mandatory=$true)][string]$computer, #Computer to which the connection is established 40 | [string]$ScriptBlock, 41 | [string]$admin = "Administrator" 42 | ) 43 | #Imports the required module 44 | Import-Module AdmPwd.PS 45 | #User account that is protected with LAPS 46 | $username = "$computer\$admin" 47 | #The readout works only from a shell with administrative rights and an authorized user! 48 | $password = (Get-AdmPwdPassword -ComputerName $computer).Password 49 | IF ( $($password).count -gt 0 ) { 50 | Write-Output "Password was found" 51 | $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username,$($password | ConvertTo-SecureString -asPlainText -Force) 52 | #Create the credentials 53 | $FQDN= $computer + "."+ $(Get-ADDomain).DNSRoot 54 | #To avoid a certificate error the FQDN must be used to establish the connection 55 | IF ($ScriptBlock -ne "") 56 | { 57 | Invoke-Command -ComputerName $FQDN -ScriptBlock { $ScriptBlock } -credential $cred -UseSSL 58 | } 59 | Else 60 | { 61 | Write-Output "No ScriptBlock specified, start demo mode" 62 | Invoke-Command -ComputerName $FQDN -ScriptBlock { Get-ChildItem C:\ } -credential $cred -UseSSL 63 | } 64 | Write-Output "Reset Password timer" 65 | Reset-AdmPwdPassword -ComputerName $computer 66 | #Reset the LAPS password 67 | Write-Output "Give AD replication a few seconds" 68 | Start-Sleep -Seconds 30 69 | #A little patience for local AD replication 70 | Write-Output "Invoke GPupdate on $computer, this may need some minutes to take effect" 71 | Invoke-GPUpdate -Computer $computer -Target Computer -Force 72 | #Run GPUdate to set a new password. This will take a few minutes. 73 | } 74 | else { 75 | Write-Warning "No LAPS Password found" 76 | } -------------------------------------------------------------------------------- /ActiveDirectory/Get-ADPermissionsReport.ps1: -------------------------------------------------------------------------------- 1 | ##requires -version 5.1 2 | ##requires -modules activedirectory 3 | 4 | <# 5 | .SYNOPSIS 6 | Get CSV Report about all Permisions in Active Directory 7 | .DESCRIPTION 8 | Get CSV Report about all Permisions in Active Directory 9 | .PARAMETER showresult 10 | Shows permissions as Shell output - not recommended 11 | .PARAMETER Export 12 | Activate CSV Export 13 | .PARAMETER Exportpath 14 | Path to CSV file for Export, default: "C:\Temp\$(Get-Date -Format "yyyyMMdd-HHmm")-ADPermissionReport.csv" 15 | .EXAMPLE 16 | Shows permissions as Shell output - not recommended 17 | get-ADPermisionReport.ps1 -showresult 18 | .EXAMPLE 19 | Export report as CSV to c:\temp\ifhpermissionreport.csv 20 | get-ADPermisionReport.ps1 -export -ExportFile c:\temp\ifhpermissionreport.csv 21 | .INPUTS 22 | Keine. 23 | .OUTPUTS 24 | Keine. 25 | .NOTES 26 | Author : Fabian Niesen 27 | Filename : get-ADPermisionReport.ps1 28 | Requires : PowerShell Version 5.1 29 | 30 | Version : 0.2 31 | History : 0.2 FN 28.04.2024 Add Parameters 32 | 0.1 FN 27.04.2024 initial version 33 | 34 | .LINK 35 | https://www.infrastrukturhelden.de 36 | #> 37 | [CmdletBinding(DefaultParameterSetName='showresult')] 38 | Param( 39 | [Parameter(ParameterSetName = "export" ,Mandatory=$false)] 40 | [Parameter(ParameterSetName = "showresult" ,Mandatory=$false)] 41 | [switch]$export, 42 | [Parameter(ParameterSetName = "export" ,Mandatory=$true)] 43 | [string]$ExportFile = "C:\Temp\$(Get-Date -Format "yyyyMMdd-HHmm")-ADPermissionReport.csv", 44 | [Parameter(ParameterSetName = "export" ,Mandatory=$false)] 45 | [Parameter(ParameterSetName = "showresult" ,Mandatory=$false)] 46 | [switch]$showresult 47 | ) 48 | # Array for report. 49 | $report = @() 50 | $schemaIDGUID = @{} 51 | # ignore duplicate errors if any # 52 | $ErrorActionPreference = 'SilentlyContinue' 53 | Get-ADObject -SearchBase (Get-ADRootDSE).schemaNamingContext -LDAPFilter '(schemaIDGUID=*)' -Properties name, schemaIDGUID | ForEach-Object {$schemaIDGUID.add([System.GUID]$_.schemaIDGUID,$_.name)} 54 | Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).configurationNamingContext)" -LDAPFilter '(objectClass=controlAccessRight)' -Properties name, rightsGUID | ForEach-Object {$schemaIDGUID.add([System.GUID]$_.rightsGUID,$_.name)} 55 | $ErrorActionPreference = 'Continue' 56 | $OUs = (Get-ADOrganizationalUnit -filter *).DistinguishedName 57 | $i = 0 58 | foreach($OU in $OUs){ 59 | $i++ 60 | Write-Progress -activity "Query Permissions, please wait." -Status "$i of $($OUs.count): $($OU)" -PercentComplete (($i / $OUs.count)*100) -Id 1 61 | $report += Get-Acl -Path "AD:\$OU" | Select-Object -ExpandProperty Access | Select-Object @{name='organizationalunit';expression={$OU}}, @{name='objectTypeName';expression={if ($_.objectType.ToString() -eq '00000000-0000-0000-0000-000000000000') {'All'} Else {$schemaIDGUID.Item($_.objectType)}}}, @{name='inheritedObjectTypeName';expression={$schemaIDGUID.Item($_.inheritedObjectType)}}, * 62 | } 63 | Write-Progress -activity "Query Permissions, please wait." -Completed -Id 1 64 | IF ($showresult) { $report | Format-Table -AutoSize } 65 | IF ($export) { $report | Export-Csv -Path "$ExportFile" -NoTypeInformation -Force -Delimiter ";"} -------------------------------------------------------------------------------- /User/Get-LastLogonOU.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Scan OU for all users an provide LastLogon for AD and Exchange 4 | .DESCRIPTION 5 | Scan OU for all users an provide LastLogon for AD and Exchange 6 | .EXAMPLE 7 | Get-LastlogonOU.ps1 -OU "OU=Users,DC=Domain,DC=tld" -Export "C:\Export.csv" 8 | .INPUTS 9 | OU: Target OU for scanning 10 | Export: Exportpath for CSV File 11 | .OUTPUTS 12 | Keine. 13 | .NOTES 14 | Author : Fabian Niesen 15 | Requires : PowerShell Version 2.0 16 | License : The MIT License (MIT) 17 | Copyright (c) 2022-2025 Fabian Niesen 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 19 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 20 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 23 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 24 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 25 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 26 | connection with the software or the use or other dealings in the Software. 27 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 28 | The author assumes no responsibility for any damage or data loss caused by this script. 29 | Test thoroughly in a controlled environment before deploying to production. 30 | Version : 0.2 FN 03.12.2025 Changed License to MIT, housekeeping Header 31 | History : 0.1 FN 11.10.2016 initial version 32 | 33 | .LINK 34 | 35 | #> 36 | 37 | [CmdletBinding()] 38 | 39 | Param( 40 | [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$False)] 41 | [String]$OU="OU=Benutzer-Extern,OU=Bonn,DC=steep,DC=loc", 42 | [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$False)] 43 | [String]$Export="c:\export.csv" 44 | ) 45 | $schriptversion = "0.2" 46 | Write-Output "Get-LastLogonOU.ps1 Version $scriptversion " 47 | $ErrorActionPreference = "SilentlyContinue" 48 | import-module activedirectory 49 | $CSV = @() 50 | Write-Verbose "Ersteller Userliste" 51 | Get-ADUser -SearchBase $OU -filter * -ResultSetSize 5000 -Properties SamAccountName,displayName,lastLogonTimestamp | Sort-Object lastLogonTimestamp |Select-Object SamAccountName,DisplayName,Enabled,@{Name="lastLogonAD"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp).ToString('dd.MM.yyyy hh:mm')}} | export-csv $Export -Delimiter ";" -NoTypeInformation -Encoding UTF8 52 | Write-Verbose "Importiere Userliste" 53 | $CSV = Import-CSV -Path $Export -Delimiter ";" 54 | $CSV | Add-Member -MemberType NoteProperty -Name 'ExchangeLastLogon' -Value $null 55 | Write-Verbose "Starte Exchange Abfrage" 56 | ForEach ($Entry in $CSV) 57 | { 58 | $SamAccountName = $Entry.SamAccountName 59 | Write-Verbose "SamAccountName: $SamAccountName " 60 | Try 61 | { 62 | $Entry.ExchangeLastLogon = $(Get-MailboxStatistics $SamAccountName -ErrorAction Stop).LastLogonTime 63 | } 64 | catch 65 | { 66 | $Entry.ExchangeLastLogon = "no Mailbox" 67 | } 68 | } 69 | $CSV | Export-Csv $Export -NoTypeInformation -Delimiter ";" -Encoding UTF8 -------------------------------------------------------------------------------- /ActiveDirectory/Reset-DSRM.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 3.0 2 | #requires -modules activedirectory 3 | #Requires -RunAsAdministrator 4 | <# 5 | .SYNOPSIS 6 | Reset the Directory Services Restore Mode (DSRM) password on a Domain Controller in an Active Directory Domain. 7 | .DESCRIPTION 8 | Reset the Directory Services Restore Mode (DSRM) password on a Domain Controller in an Active Directory Domain. 9 | .EXAMPLE 10 | Reset-DSRM.ps1 11 | .INPUTS 12 | Keine. 13 | .OUTPUTS 14 | Keine. 15 | .PARAMETER 16 | .NOTES 17 | Author : Fabian Niesen 18 | Filename : 19 | Requires : PowerShell Version 3.0 20 | License : GNU General Public License v3 (GPLv3) 21 | (c) 2015-2025 Fabian Niesen, www.infrastrukturhelden.de 22 | This script is licensed under the GNU General Public License v3 (GPLv3), except for 3rd party code (e.g. Function Get-GPPolicyKey). 23 | You can redistribute it and/or modify it under the terms of the GPLv3 as published by the Free Software Foundation. 24 | This script is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 26 | See https://www.gnu.org/licenses/gpl-3.0.html for the full license text. 27 | Version : 0.3 28 | History : 29 | 0.3 FN 25.10.2025 Change License to GPLv3 30 | 0.2 FN 31.08.2022 Add some autodetection, Change Logging 31 | 0.1 FN 26.11.2015 initial version 32 | 33 | 34 | .LINK 35 | https://github.com/InfrastructureHeroes/Scipts/ 36 | 37 | .COPYRIGHT 38 | Copyright (c) Fabian Niesen if not stated otherwise. All rights reserved. Licensed under the MIT license. 39 | 40 | #> 41 | [CmdletBinding(DefaultParameterSetName = 'AllDC')] 42 | Param( 43 | [Parameter(Mandatory=$true, 44 | ParameterSetName = 'AllDC', 45 | HelpMessage = 'Reset DSRM on all DCs in Domain')] 46 | [switch]$AllDC, 47 | [Parameter(Mandatory=$true, 48 | ParameterSetName = 'OnlyOne', 49 | HelpMessage = 'Reset DSRM on a single DC')] 50 | [switch]$Server, 51 | [Parameter(Mandatory=$false, 52 | HelpMessage = 'RandomPassword?')] 53 | [switch]$RandomPW, 54 | [Parameter(Mandatory=$false, 55 | HelpMessage = 'Username for Sync Account')] 56 | [string]$Username, 57 | [Parameter(Mandatory=$false, 58 | HelpMessage = 'Password')] 59 | [string]$PW, 60 | [Parameter(Mandatory=$false, 61 | ParameterSetName = 'OnlyOne', 62 | HelpMessage = 'Servername')] 63 | [string]$ServerName, 64 | [string]$logPath = "C:\Windows\System32\LogFiles\" 65 | ) 66 | $ErrorActionPreference = "Stop" 67 | IF (RandomPW) { 68 | $TokenSet = @{ 69 | U = [Char[]]'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 70 | L = [Char[]]'abcdefghijklmnopqrstuvwxyz' 71 | N = [Char[]]'0123456789' 72 | S = [Char[]]'(~!@#$%^&*_-+=\(){}[]:;<>,.?/)' 73 | } 74 | $Upper = Get-Random -Count 10 -InputObject $TokenSet.U 75 | $Lower = Get-Random -Count 10 -InputObject $TokenSet.L 76 | $Number = Get-Random -Count 7 -InputObject $TokenSet.N 77 | $Special = Get-Random -Count 7 -InputObject $TokenSet.S 78 | $StringSet = $Upper + $Lower + $Number + $Special 79 | 80 | [String]$PW = (Get-Random -Count 30 -InputObject $StringSet) -join '' 81 | } 82 | Write-Host "Please note this Password someware Safe: $PW" 83 | Write-Warning "Be Aware, you need to enter the Password during the execution twice. This can not be automated. Sorry." 84 | #TODO Check User and Create is 85 | 86 | #TODO Set Password 87 | 88 | 89 | If ( $OnlyOne ) { 90 | Try {Test-Connection $ServerName} 91 | catch { Throw "Server $ServerName not reachable!"} 92 | $ntdsutil = ntdsutil "set dsrm password" "reset password on server NULL" q q 93 | } elseif ( $AllDC) { 94 | Write-Host "Not Implemented now" 95 | <# Action when this condition is true #> 96 | } else { 97 | Throw "Please check Script Parameters with get-Help .\Reset-DSRM.PS1" 98 | } -------------------------------------------------------------------------------- /ActiveDirectory/Locate-46xx.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 2.0 2 | #requires -modules activedirectory 3 | 4 | 5 | <# 6 | .SYNOPSIS 7 | Locate user Lockouts in Active Directory 8 | .DESCRIPTION 9 | Query all DC and Locate user Lockouts in Active Directory within the last 24h. As default the result is shown as Grid-View, but CSV Export is possible. 10 | A lunchtime project... 11 | .EXAMPLE 12 | .\LocateADLockout-v2.ps1 -filter "bn" -CSVOUT $true -Gridview $false -CSVpath 13 | .INPUTS 14 | -filter only DC's with this pattern in the Hostname 15 | -Gridview Output as GridView 16 | -CSVOUT Export as CSV 17 | -CSVpath Exportpath for CSV 18 | .OUTPUTS 19 | Keine. 20 | .NOTES 21 | Author : Fabian Niesen 22 | Filename : Locate-ADLockout.ps1 23 | Requires : PowerShell Version 2.0 24 | 25 | Version : 1.0 26 | History : 1.0 27 | 28 | .LINK 29 | https://www.infrastrukturhelden.de 30 | #> 31 | 32 | Param( 33 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 34 | [String]$filter ="*", 35 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 36 | [String]$Gridview =$true, 37 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 38 | [String]$CSVOUT = $false, 39 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 40 | [String]$CSVpath = "changeme" 41 | ) 42 | 43 | $LogOuts = @() 44 | 45 | 46 | #@{label=''}, @{label=''},@{label=''}, @{label=''}, @{label=''} 47 | $DCs = Get-ADDomainController -Filter { HostName -like "$filter" } 48 | ForEach ($DC in $DCs) 49 | { 50 | Write-Output "Starte Remote PowerShell Session und Suche nach EventID 4625 zu:" $DC.HostName 51 | $temp = Invoke-Command -ComputerName $DC.HostName -ScriptBlock { Get-EventLog -LogName "Security" -After (Get-Date).AddDays(-1) | Where-Object { $_.EventID -match '4625'} } 52 | ForEach ($t in $temp) 53 | { 54 | IF ($t.ReplacementStrings[7] -like "0xc0000234") { $Staus = "Kontosperrung"} ELSEIF ($t.ReplacementStrings[7] -like "0xc000006d") { $Staus = "Anmelden"} 55 | $Log = New-Object -TypeName psobject 56 | $Log | Add-Member -MemberType NoteProperty -Name EventID -Value $t.EventID 57 | $Log | Add-Member -MemberType NoteProperty -Name TimeGenerated -Value $t.TimeGenerated 58 | $Log | Add-Member -MemberType NoteProperty -Name DC -Value $t.ReplacementStrings[4] 59 | $Log | Add-Member -MemberType NoteProperty -Name Benutzer -Value $($t.ReplacementStrings[6] +"\" +$t.ReplacementStrings[5]) 60 | $Log | Add-Member -MemberType NoteProperty -Name Quelle -Value $Staus 61 | $Log | Add-Member -MemberType NoteProperty -Name LoginID -Value $Null 62 | $Log | Add-Member -MemberType NoteProperty -Name IP -Value $t.ReplacementStrings[19] 63 | $Log | Add-Member -MemberType NoteProperty -Name EventServer -Value $DC.HostName 64 | $LogOuts += $Log 65 | } 66 | 67 | Write-Output "Starte Remote PowerShell Session und Suche nach EventID 4776 zu: "$DC.HostName 68 | $temp = Invoke-Command -ComputerName $DC.HostName -ScriptBlock { Get-EventLog -LogName "Security" -After (Get-Date).AddDays(-1) | Where-Object { $_.EventID -match '4776'} } 69 | ForEach ($t in $temp) 70 | { 71 | $Log = New-Object -TypeName psobject 72 | $Log | Add-Member -MemberType NoteProperty -Name EventID -Value $t.EventID 73 | $Log | Add-Member -MemberType NoteProperty -Name TimeGenerated -Value $t.TimeGenerated 74 | $Log | Add-Member -MemberType NoteProperty -Name DC -Value $t.ReplacementStrings[2] 75 | $Log | Add-Member -MemberType NoteProperty -Name Benutzer -Value $t.ReplacementStrings[1] 76 | $Log | Add-Member -MemberType NoteProperty -Name EventServer -Value $DC.HostName 77 | $LogOuts += $Log 78 | } 79 | 80 | } 81 | 82 | IF ($Gridview -eq $true) { $LogOuts | Out-GridView -Title "EventID's 4625 and 4776 on all/filterd DCs" } 83 | IF ($CSVOUT -eq $true) 84 | { 85 | IF ($CSVpath -like "changeme") 86 | { 87 | Write-Verbose "No Path found" 88 | $CSVpath = Read-Host -Prompt "Bitte geben Sie einen Dateinamen inklusive Pfad an" 89 | } 90 | $LogOuts | Export-Csv -Path $CSVpath -Delimiter ";" -NoTypeInformation 91 | } 92 | 93 | 94 | -------------------------------------------------------------------------------- /Windows/set-cert4rdp.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 5.0 2 | #Requires -RunAsAdministrator 3 | 4 | <# 5 | .SYNOPSIS 6 | Set RDP Certificate based on issuing CA. 7 | .DESCRIPTION 8 | Set RDP Certificate based on issuing CA. Works only if only one Certificate from the Issuing CA is installed. 9 | .EXAMPLE 10 | .\set-cert4rdp.ps1 -caName "Issuing CA" 11 | Set the Cert from the Issuing CA. 12 | 13 | .PARAMETER caName 14 | Name of issung CA 15 | 16 | .NOTES 17 | Author : Fabian Niesen 18 | Filename : .\set-cert4rdp.ps1 19 | Requires : PowerShell Version 5.0 20 | License : The MIT License (MIT) 21 | Copyright (c) 2022-2025 Fabian Niesen 22 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 23 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 24 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 25 | furnished to do so, subject to the following conditions: 26 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 27 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 28 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 29 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 30 | connection with the software or the use or other dealings in the Software. 31 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 32 | The author assumes no responsibility for any damage or data loss caused by this script. 33 | Test thoroughly in a controlled environment before deploying to production. 34 | 35 | Version : 0.2 FN 03.12.2025 Changed License to MIT, housekeeping Header 36 | History : 0.1 FN 24.09.2024 Initial version. 37 | .LINK 38 | https://github.com/InfrastructureHeroes/Scipts/tree/master/Windows 39 | #> 40 | [cmdletbinding()] 41 | Param( 42 | [string]$caName = "" 43 | ) 44 | $scriptversion = "0.2" 45 | Write-Output "set-cert4rdp.ps1 Version $scriptversion " 46 | # Path to the RDP SSL configuration in the registry 47 | $rdpRegPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" 48 | 49 | # Open certificate store (local computer) 50 | $certs = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Issuer -like "*$caName*" } 51 | 52 | if ($certs -and $certs.Count -eq 1) { 53 | # If exactly one certificate was found 54 | $cert = $certs[0] 55 | $thumbprint = $($cert.Thumbprint -replace '\s+', '') 56 | # Add thumbprint in the registry for RDP SSL certificate 57 | Set-ItemProperty -Path $rdpRegPath -Name "SSLCertificateSHA1Hash" -Value ([byte[]]($thumbprint -split '(?<=\G.{2})(?!$)' | ForEach-Object { "0x$_" })) 58 | Write-Output "The thumbprint $thumbprint was successfully entered in the registry." 59 | $cert = Get-ChildItem -Path "Cert:\LocalMachine\My" | Where-Object { $_.Thumbprint -eq $thumbprint } 60 | $keyPath = $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName 61 | $keyPath = "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\" + $keyPath 62 | # Set permissions for NETWORK SERVICE 63 | $acl = Get-Acl -Path $keyPath 64 | $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule("NETWORK SERVICE", "Read", "Allow") 65 | $acl.SetAccessRule($accessRule) 66 | Set-Acl -Path $keyPath -AclObject $acl 67 | Write-Output "Private key permissions have been updated for certificates with thumbprint $thumbprint." 68 | } elseif ($certs.Count -gt 1) { 69 | Write-Output "Several certificates from the CA $caName were found. Please check the certificates." 70 | } else { 71 | Write-Output "No certificate found from the CA $caName." 72 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Infrastrukturhelden.de - English version below 2 | Powershell Skriptsammlung von Fabian Niesen [InfrastrukturHelden.de](https://www.infrastrukturhelden.de). Für alle Scripte gilt: 3 | **Verwendung auf eigene Gefahr und ohne Gewährleistungsansprüche!** 4 | Die Skripte die über einen Header mit Versionierung verfügen, sind meistens ausgereifter. Andere sind teilweise auch nur praktische Codeschnipsel, die ich so besser im Zugriff habe. 5 | Ihr sucht die [Life-Cycle Diagramme](https://github.com/FabianNiesen/InfrastrukturHelden-LifeCycle-diagrams), dann seit Ihr hier leider falsch. 6 | 7 | ## Skripte in der Übersicht 8 | 9 | ### BitLocker 10 | * List-BitLockerrecoveryKeys.ps1 - *Listet alle BitLocker Wiederherstellungsschlüssel im AD auf* 11 | * Update-BitLockerRecovery.ps1 - *Upload BitLocker recovery information to Active Directory, if they not already exist.* 12 | * Start-Bitlocker.ps1 - *Startet die BitLocker Verschlüsselung mit einer definierten PIN* 13 | 14 | ### Exchange 15 | Verschiedene Skripte auf meiner Exchange-Berater Zeit. Nicht mehr gepflegt! 16 | 17 | ### GPO - Gruppenrichtlinien 18 | * get-GPOBackup.ps1 - *Creates backup of the GPO with according html Reports. The script creates a subfolder based upon an actual timestamp. - V1.58* 19 | * invoke-GPupdateDomain.ps1 - *Führt remote ein GPUPDATE für einzelne Computer, OUs oder die ganze Domäne aus* 20 | 21 | ### User - Benutzermanagement 22 | * create-user.ps1 - *Legt einen neuen Benutzer an. Inklusive Microsoft365 Lizenzzuweisung und einer Begrüßungsmail. Passender Artikel: [Benutzer einfachen anlegen mit PowerShell](https://www.infrastrukturhelden.de/microsoft-infrastruktur/active-directory/benutzer-einfachen-anlegen-mit-powershell/)* 23 | * Get-LastLogonOU.ps1 - *zeigt das letzte LogOn für alle Nutzer in einer OU an. Sowohl AD als auch Exchange.* 24 | 25 | ### WSUS - Windows Server Update Service 26 | * decline-WSUSUpdatesTypes.ps1 - *Decline several Update Types in Windows Server Update Services (WSUS)* 27 | * Reset-WSUSClient.cmd - *Setzt diverse Einstellungen auf dem Client zurück. Löst die meisten aller Client Probleme* 28 | * start-WsusServerSync.ps1 - *Startet eine WSUS Syncronisierung über alle Server und schickt eine Email als Abschluss.* 29 | 30 | ### Sonstige 31 | * get-adinfo.ps1 - *Erstellt einen AD Report mit Nützlichen Funktionen wie Liste der DCs und die Versionen des Schemas und eventueller Erweiterungen.* 32 | 33 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Z8Z8FB6VH) 34 | # English version 35 | Powershell script collection by Fabian Niesen [InfrastrukturHelden.de](https://www.infrastrukturhelden.de). The following applies to all scripts: 36 | **Use at your own risk and without any guarantee!** 37 | The scripts that have a header with versioning are usually more mature. Others are sometimes just practical code snippets that I can access better this way. 38 | 39 | ## Scripts in the overview 40 | 41 | ### BitLocker 42 | * List-BitLockerrecoveryKeys.ps1 - *Lists all BitLocker recovery keys in AD*. 43 | * Update-BitLockerRecovery.ps1 - *Upload BitLocker recovery information to Active Directory, if they do not already exist.* 44 | * Start-Bitlocker.ps1 - *Starts BitLocker encryption with a defined PIN*. 45 | 46 | ### Exchange 47 | Scripts from the time where I was Exchange consultant - no longer maintained 48 | 49 | ### GPO - Group Policy 50 | * get-GPOBackup.ps1 - *Creates backup of the GPO with according html reports. The script creates a subfolder based upon an actual timestamp. - V1.58* 51 | * invoke-GPupdateDomain.ps1 - *Remotely executes a GPUPDATE for individual computers, OUs or the entire domain.* 52 | 53 | ### User - User management 54 | * create-user.ps1 - *Creates a new user. Includes Microsoft365 licence assignment and a welcome email. Related Article: [Creating Users Easily with PowerShell](https://www.infrastrukturhelden.de/microsoft-infrastruktur/active-directory/benutzer-einfachen-anlegen-mit-powershell/)* 55 | * Get-LastLogonOU.ps1 - *displays the last logon for all users in an OU. Both AD and Exchange.* 56 | 57 | ### WSUS - Windows Server Update Service 58 | * decline-WSUSUpdatesTypes.ps1 - *Decline several Update Types in Windows Server Update Services (WSUS)*. 59 | * Reset-WSUSClient.cmd - *Resets several settings on the client. Solves most of the client problems*. 60 | * start-WsusServerSync.ps1 - *Starts a WSUS sync across all servers and sends an email as a completion.* 61 | 62 | ### Other 63 | * get-adinfo.ps1 - *Creates an AD report with useful functions like list of DCs and the versions of the schema and any extensions.* 64 | -------------------------------------------------------------------------------- /Set-Network.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 4.0 2 | #Requires -RunAsAdministrator 3 | <# 4 | .SYNOPSIS 5 | Modify often needed Networkkonfiguration like set DNSDomainName, disable NetBios over TCP/IP or disable IPv6. 6 | 7 | .DESCRIPTION 8 | Modify often needed Networkkonfiguration like set DNSDomainName, disable NetBios over TCP/IP or disable IPv6 based on MS KB929852 9 | 10 | .EXAMPLE 11 | C:\PS> Set-Network.ps1 12 | 13 | .EXAMPLE 14 | C:\PS> Set-Network.ps1 15 | 16 | .PARAMETER DNSDomain 17 | String of the DNSDomain. If used, the DNSDomain will changed and a DNS re-register is triggert. 18 | 19 | .PARAMETER DisableNetbios 20 | Diable NetBios over TCP/IP on all enabled network interfaces 21 | 22 | .PARAMETER DisableIPv6Interfaces 23 | Disable IPv6 on all interfaces and change the prefference to IPv4. Set DisabledComponents to 0x32 24 | 25 | 26 | .COPYRIGHT 27 | Copyright (c) 2022 Fabian Niesen. All rights reserved. Licensed under the MIT license. 28 | 29 | .NOTES 30 | Author : Fabian Niesen (Infrastrukturhelden.de) 31 | Filename : Set-Network.ps1 32 | Requires : PowerShell Version 4.0 33 | License : The MIT License (MIT) 34 | Copyright (c) 2022-2025 Fabian Niesen 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 36 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 37 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 38 | furnished to do so, subject to the following conditions: 39 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 40 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 41 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 42 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 43 | connection with the software or the use or other dealings in the Software. 44 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 45 | The author assumes no responsibility for any damage or data loss caused by this script. 46 | Test thoroughly in a controlled environment before deploying to production. 47 | Version : 1.2 48 | History : 1.2 FN 03.12.2025 Change License to MIT, housekeeping Header 49 | 1.1 FN 11.10.2022 Add Set MTU 50 | 1.0 FN 04.10.2022 extracted from other script for idependent use 51 | 52 | .LINK 53 | https://github.com/InfrastructureHeroes/Scipts 54 | #> 55 | 56 | param ( 57 | [string]$DNSDomain, 58 | [switch]$DisableNetbios, 59 | [switch]$DisableIPv6Interfaces, 60 | [int]$MTU = 0 61 | 62 | ) 63 | $scriptversion = "1.2" 64 | Write-Output "Set-Network.ps1 Version $scriptversion " 65 | Write-Verbose "DNSDomain: $DNSDomain - DisableNetbios: $DisableNetbios - DisableIPv6Interfaces: $DisableIPv6Interfaces" 66 | Write-Verbose "Scan for Networkinterfaces" 67 | $networkConfig = Get-WmiObject Win32_NetworkAdapterConfiguration -filter "ipenabled = 'true'" 68 | Foreach ( $nc in $networkConfig ) 69 | { 70 | $NIPI = Get-NetIPInterface -InterfaceIndex $($nc.InterfaceIndex) -AddressFamily IPv4 71 | IF ( $DNSDomain -ne "") 72 | { 73 | Write-Verbose "Set DNSDomain" 74 | $nc.SetDnsDomain($DNSDomain) 75 | Write-Verbose "Set Dynamic DNS Registration" 76 | $nc.SetDynamicDNSRegistration($true,$true) 77 | ipconfig /registerdns 78 | } 79 | IF ($DisableNetbios) 80 | { 81 | Write-Verbose "Disable NetBios over TCPIP" 82 | $nc.SetTcpipNetbios(2) 83 | } 84 | if ($DisableIPv6Interfaces) 85 | { 86 | Write-Verbose "Disable IPv6 on Interfaces and prefer IPv4 over IPv6 (Based on Microsoft KB929852)" 87 | reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters" /v DisabledComponents /t REG_DWORD /d 0x32 /f 88 | } 89 | if ($MTU -ne 0 ) 90 | { 91 | Write-Verbose "Set MTU to $MTU is activeatd" 92 | $localMTU = $NIPI.NlMtu 93 | If ( $localMTU -ne $MTU ) 94 | { 95 | Set-NetIPInterface -InterfaceIndex $($nc.InterfaceIndex) -NlMtuBytes $MTU -PolicyStore ActiveStore -Confirm:$false 96 | Set-NetIPInterface -InterfaceIndex $($nc.InterfaceIndex) -NlMtuBytes $MTU -PolicyStore PersistentStore -Confirm:$false 97 | #test einbauen 98 | } 99 | 100 | } 101 | } -------------------------------------------------------------------------------- /send-files.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Small Power Shell script to send files from a directory via mail. 4 | 5 | .DESCRIPTION 6 | Small Power Shell script to send files from a directory via mail and move them into an archive. Each mail contain only a single file. There is a filter for the file type. 7 | This script is designed to be executed as scheduled task. 8 | 9 | .EXAMPLE 10 | send-files.ps1 -sourcepath "C:\User\Fabian\Scaned-PDF" -archivepath "$sourcepath\Archive" -filetype "*.pdf" -SmtpServer mail.infrastrukturhelden.de -From Script@infrastrukturhelden.de -To john.doe@infrastrukturhelden.de 11 | 12 | .PARAMETER sourcepath 13 | Path where to look for files. Subfolders will not be used! 14 | 15 | .PARAMETER archivepath 16 | Path where file will moved after sending 17 | 18 | .PARAMETER filetype 19 | Filter for file types 20 | 21 | .PARAMETER SmtpServer 22 | SmtpServer witch is uses to send the mail 23 | 24 | .PARAMETER From 25 | Mail From 26 | 27 | .PARAMETER To 28 | Mail To 29 | 30 | .PARAMETER Subject 31 | Subject of the Mail 32 | 33 | .PARAMETER SmtpAuth 34 | Switch if SMTP needs authentication 35 | 36 | .PARAMETER smtppw 37 | Password for SMTP User. Only need with SmtpAuth. 38 | 39 | .PARAMETER smtpuser 40 | SMTP Username. Only need with SmtpAuth. 41 | 42 | .PARAMETER SmtpPort 43 | Portnumber for SMTP if non Standard 44 | 45 | .PARAMETER Body 46 | Mail body, no HTML. 47 | 48 | .NOTES 49 | Author : Fabian Niesen 50 | Filename : send-files.ps1 51 | Requires : PowerShell Version 3.0 52 | License : The MIT License (MIT) 53 | Copyright (c) 2022-2025 Fabian Niesen 54 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 55 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 56 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 57 | furnished to do so, subject to the following conditions: 58 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 59 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 60 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 61 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 62 | connection with the software or the use or other dealings in the Software. 63 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 64 | The author assumes no responsibility for any damage or data loss caused by this script. 65 | Test thoroughly in a controlled environment before deploying to production. 66 | Version : 1.3 67 | History : 68 | 1.3 FN 03.12.2025 Change License to MIT, housekeeping Header 69 | 1.2 FN 25.10.2025 Change License to GPLv3 70 | 1.1 FN 27.08.2022 Add SMTP Port (for #4) 71 | 1.0 FN initial version 72 | 73 | .LINK 74 | https://www.infrastrukturhelden.de/?p=13527 75 | #> 76 | [cmdletbinding()] 77 | Param( 78 | [Parameter(Position=1)] 79 | [string]$sourcepath, 80 | [Parameter(Position=2)] 81 | [string]$archivepath, 82 | [Parameter(Position=3)] 83 | [string]$filetype="*.pdf", 84 | [Parameter(Position=10)] 85 | [string]$SmtpServer, 86 | [Parameter(Position=17)] 87 | [string]$From, 88 | [Parameter(Position=18)] 89 | [string]$To, 90 | [Parameter(Position=19)] 91 | [string]$Subject = "PDF Report: ", 92 | [Parameter(Position=22)] 93 | [switch]$SmtpAuth, 94 | [Parameter(Position=23)] 95 | [string]$smtppw, 96 | [Parameter(Position=24)] 97 | [string]$smtpuser, 98 | [Parameter(Position=25)] 99 | [int]$SmtpPort, 100 | [Parameter(Position=28)] 101 | [string]$Body = "Please see attachment." 102 | ) 103 | $schriptversion = "1.3" 104 | Write-Output "send-files.ps1 Version $scriptversion " 105 | IF ($SmtpAuth) { 106 | Write-Debug "Using SMTP Auth" 107 | $password = ConvertTo-SecureString $smtppw -AsPlainText -Force 108 | $cred = New-Object System.Management.Automation.PSCredential ($smtpuser, $password) 109 | } 110 | IF ($SmtpPort) { $SmtpClient.Port = $SmtpPort } 111 | $sources = Get-ChildItem $sourcepath -Filter $filetype -Depth 0 112 | 113 | ForEach ( $source in $sources) 114 | { 115 | $file = $source.FullName 116 | $SubjectM = $Subject + $source.Name 117 | Write-Debug $file 118 | Write-Debug "Send-MailMessage" 119 | IF ($SmtpAuth) { Send-MailMessage -To $To -From $From -Subject $SubjectM -SmtpServer $SmtpServer -Attachments $file -Credential $cred -UseSsl } 120 | ELSE { Send-MailMessage -To $To -From $From -Subject $SubjectM -SmtpServer $SmtpServer -Attachments $file -UseSsl } 121 | Write-Debug "Move File" 122 | Move-Item -Path $file -Destination $archivepath 123 | } -------------------------------------------------------------------------------- /GPO/invoke-GPupdateDomain.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Execute Invoke-GPupdate for all computers in an OU. 4 | 5 | .DESCRIPTION 6 | Execute Invoke-GPupdate for all computers in an OU with parameters. To speed up the process in larger domains will be a Test-Connection performed before the Invoke-GPupdate. 7 | 8 | .EXAMPLE 9 | C:\PS> invoke-GPupdateDomain.ps1 10 | 11 | .EXAMPLE 12 | C:\PS> invoke-GPupdateDomain.ps1 -SearchBase "OU=Devices,DC=Your,DC=Domain" 13 | 14 | .EXAMPLE 15 | C:\PS> invoke-GPupdateDomain.ps1 -Force 16 | 17 | .EXAMPLE 18 | C:\PS> invoke-GPupdateDomain.ps1 -AsJob 19 | 20 | .EXAMPLE 21 | C:\PS> invoke-GPupdateDomain.ps1 -Computer 22 | 23 | .PARAMETER SearchBase 24 | DN for the AD structure to search for Computers 25 | 26 | .PARAMETER ResultPageSize 27 | Limits the ammout of searched Computer to 1000 in default. Use this parameter to increase if nessessary 28 | 29 | .PARAMETER force 30 | Perform a invoke-gpupdate -Force 31 | 32 | .PARAMETER asjob 33 | Perform a invoke-gpupdate -asjob 34 | 35 | .PARAMETER user 36 | Perform a invoke-gpupdate -target user 37 | 38 | .PARAMETER computer 39 | Perform a invoke-gpupdate -target computer 40 | 41 | .NOTES 42 | Author : Fabian Niesen (infrastrukturhelden.de) 43 | Filename : invoke-GPupdateDomain.ps1 44 | Requires : PowerShell Version 3.0 45 | License : The MIT License (MIT) 46 | Copyright (c) 2022-2025 Fabian Niesen 47 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 48 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 49 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 50 | furnished to do so, subject to the following conditions: 51 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 52 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 53 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 54 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 55 | connection with the software or the use or other dealings in the Software. 56 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 57 | The author assumes no responsibility for any damage or data loss caused by this script. 58 | Test thoroughly in a controlled environment before deploying to production. 59 | Version : 1.1 60 | History : 1.1 FN 03.12.2025 Changed License to MIT, housekeeping Header 61 | 1.0 FN 10/12/2018 initial version 62 | 63 | .LINK 64 | https://www.infrastrukturhelden.de 65 | #> 66 | Param( 67 | [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$False)] 68 | [String]$Searchbase="", 69 | [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$False)] 70 | [int]$ResultPageSize="1000", 71 | [switch]$force, 72 | [switch]$asjob, 73 | [switch]$User, 74 | [switch]$Computer 75 | ) 76 | $scriptversion = "1.1" 77 | Write-Output "invoke-GPupdateDomain.ps1 Version $scriptversion " 78 | $ErrorActionPreference = "Stop" 79 | [int]$Suc = 0 80 | $Command = "Invoke-GPupdate " 81 | IF ($force -eq $true) { $Command += "-Force "; Write-Output "Enable Force Mode"} 82 | IF ($asjob -eq $true) { $Command += "-AsJob "; Write-Output "Enable AsJob"} 83 | IF ($User -eq $true -and $Computer -eq $true) {Write-Verbose "There is no need for User and Computer"} 84 | ElseIF ($User -eq $true) { $Command += "-Target User "; Write-Output "Only invoke User Policy"} 85 | ElseIF ($Computer -eq $true) { $Command += "-Target Computer "; Write-Output "Only invoke Computer Policy"} 86 | ELse {Write-Verbose "Run with no Target Scope for GPupdate"} 87 | Write-Verbose "Invoke Command will be: $Command" 88 | Write-Verbose "=== Import AD Module ===" 89 | try 90 | { 91 | Import-Module activedirectory 92 | } 93 | catch 94 | { 95 | Write-Warning "ActiveDirectory Module ist missing. Please install first" 96 | #"GroupPolicy Module ist missing. Please install first" | Out-file $ErrorLog -Append 97 | break 98 | } 99 | 100 | IF ( $Searchbase -eq "") { Write-Verbose "Query Domain DN for Searchbase"; $Searchbase = $(Get-ADDomain).DistinguishedName } 101 | Write-Verbose "Searchbase: $Searchbase" 102 | 103 | $Computers = $(Get-ADComputer -SearchBase $Searchbase -filter {(Enabled -eq $True)} -ResultPageSize $ResultPageSize ).Name 104 | $CompCount = $($Computers.count) 105 | Write-Output "Found $CompCount Computer at $Searchbase" 106 | Write-Progress -activity "Trigger GPupdate" -Status "starting" -PercentComplete "0" -Id 1 107 | [int]$i = "0" 108 | FOREACH ( $Comp in $Computers) 109 | { 110 | $i++ 111 | $Try = $true 112 | Write-Progress -activity "Trigger GPupdate" -Status "Active on $Compr" -PercentComplete (($i / $CompCount)*100) -Id 1 113 | Write-Verbose "Test-Connection $Comp" 114 | Try { Test-Connection $Comp -Count 1 -Delay 1 |Out-Null } catch { Write-Warning "Computer $Comp is not reachable."; $Try = $false } 115 | IF ($Try -eq $true) 116 | { 117 | Write-Verbose "Invoke-GPUpdate on $Comp" 118 | $TryGP = $true 119 | Try { $($Command+$Comp) | Out-Null } catch { Write-Warning "Invoke-GPupdate war not successful on $Comp"; $TryGP = $false } 120 | IF ($TryGP -eq $true) {Write-Host -ForegroundColor Green "Invoke-GPupdate on $Comp was successful" ; $Suc++} 121 | 122 | } 123 | } 124 | Write-Verbose "Done" 125 | IF ($asjob -eq $true) {Write-Output "Script was Started in Job mode. There might be still running Jobs" ; Get-Job | FT -AutoSize} 126 | Write-Output "$Suc of $CompCount Computers triggered for GPupdate successful" -------------------------------------------------------------------------------- /Exchange/Set-Ex2013Vdir.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | 4 | .DESCRIPTION 5 | 6 | .EXAMPLE 7 | 8 | .INPUTS 9 | Keine. 10 | .OUTPUTS 11 | Keine. 12 | .NOTES 13 | Author : Fabian Niesen 14 | Filename : set-ex2013vdir.ps1 15 | Requires : PowerShell Version 3.0 16 | 17 | Version : 0.1 18 | History : 19 | .LINK 20 | 21 | #> 22 | 23 | Param( 24 | [Parameter(Mandatory=$false, ValueFromPipeline=$False)] 25 | [String]$InternalHost=$null, 26 | [Parameter(Mandatory=$false, ValueFromPipeline=$False)] 27 | [String]$ExternalHost=$null 28 | 29 | ) 30 | $before = Get-Date 31 | Set-AdServerSettings -ViewEntireForest $true 32 | 33 | Write-Host "Found the following Exchange Server" 34 | Get-ExchangeServer | ft Name,Site,ServerRole,Edition,AdminDisplayVersion -AutoSize 35 | 36 | IF (!($InternalHost -like "$null")) 37 | { 38 | IF (!($ExternalHost -like "$null")) 39 | { 40 | Write-Host "Set Internalhost $InternalHost and Externalhost $ExternalHost" 41 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-WebservicesVirtualDirectory | Set-WebservicesVirtualDirectory -InternalURL https://$InternalHost/EWS/Exchange.asmx -ExternalURL https://$ExternalHost/EWS/Exchange.asmx 42 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-OwaVirtualDirectory | Set-OwaVirtualDirectory -InternalURL https://$InternalHost/owa -ExternalURL https://$ExternalHost/owa 43 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-ecpVirtualDirectory | Set-ecpVirtualDirectory -InternalURL https://$InternalHost/ecp -ExternalURL https://$ExternalHost/ecp 44 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-ActiveSyncVirtualDirectory | Set-ActiveSyncVirtualDirectory -InternalURL https://$InternalHost/Microsoft-Server-ActiveSync -ExternalURL https://$ExternalHost/Microsoft-Server-ActiveSync 45 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-OABVirtualDirectory | Set-OABVirtualDirectory -InternalUrl https://$InternalHost/OAB -ExternalURL https://$ExternalHost/OAB 46 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| get-mapivirtualdirectory | Set-MapiVirtualDirectory -InternalUrl https://$InternalHost/mapi -ExternalURL https://$ExternalHost/mapi 47 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Set-ClientAccessServer -AutodiscoverServiceInternalUri https://$InternalHost/Autodiscover/Autodiscover.xml 48 | get-OutlookAnywhere | Set-OutlookAnywhere -InternalHostname $InternalHost -ExternalHostName $ExternalHost -InternalClientAuthenticationMethod ntlm -InternalClientsRequireSsl:$True -ExternalClientAuthenticationMethod NTLM -ExternalClientsRequireSsl:$True 49 | } 50 | ELSE 51 | { 52 | Write-Host "Set Internalhost $InternalHost" 53 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-WebservicesVirtualDirectory | Set-WebservicesVirtualDirectory -InternalURL https://$InternalHost/EWS/Exchange.asmx -externalurl $null 54 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-OwaVirtualDirectory | Set-OwaVirtualDirectory -InternalURL https://$InternalHost/owa -externalurl $null 55 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-ecpVirtualDirectory | Set-ecpVirtualDirectory -InternalURL https://$InternalHost/ecp -externalurl $null 56 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-ActiveSyncVirtualDirectory | Set-ActiveSyncVirtualDirectory -InternalURL https://$InternalHost/Microsoft-Server-ActiveSync -externalurl $null 57 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Get-OABVirtualDirectory | Set-OABVirtualDirectory -InternalUrl https://$InternalHost/OAB -externalurl $null 58 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| get-mapivirtualdirectory | Set-MapiVirtualDirectory -InternalUrl https://$InternalHost/mapi -externalurl $null 59 | Get-ExchangeServer | ? { $_.ServerRole -like "*ClientAccess*" }| Set-ClientAccessServer -AutodiscoverServiceInternalUri https://$InternalHost/Autodiscover/Autodiscover.xml 60 | get-OutlookAnywhere | Set-OutlookAnywhere -InternalHostname $InternalHost -InternalClientAuthenticationMethod ntlm -InternalClientsRequireSsl:$True 61 | }} 62 | ELSE 63 | { 64 | Write-Warning "InternalHost not set, no changes made" 65 | } 66 | Write-Host "Actual Exchange settings" 67 | Write-host "========================" 68 | Write-Host "Autodiscover Uri" 69 | get-exchangeserver | ? { $_.ServerRole -like "*ClientAccess*" }| get-ClientAccessServer | ft Name,AutodiscoverServiceInternalUri,AutoDiscoverSiteScope -AutoSize 70 | Write-Host "OwaVirtualDirectory" 71 | get-exchangeserver | ? { $_.ServerRole -like "*ClientAccess*" }| Get-OwaVirtualDirectory | ft ServerName,Name,ExternalUrl,InternalUrl -AutoSize 72 | Write-Host "EcpVirtualDirectory" 73 | get-exchangeserver | ? { $_.ServerRole -like "*ClientAccess*" }| Get-EcpVirtualDirectory | ft Server,Name,ExternalUrl,InternalUrl,AdminEnabled -AutoSize 74 | Write-Host "OABVirtualDirectory" 75 | get-exchangeserver | ? { $_.ServerRole -like "*ClientAccess*" }| Get-OABVirtualDirectory | ft Server,Name,ExternalUrl,InternalUrl -AutoSize 76 | Write-Host "ActiveSyncVirtualDirectory" 77 | get-exchangeserver | ? { $_.ServerRole -like "*ClientAccess*" }| Get-ActiveSyncVirtualDirectory | ft Server,Name,ExternalUrl,InternalUrl -AutoSize 78 | Write-Host "mapiVirtualDirectory" 79 | get-exchangeserver | ? { $_.ServerRole -like "*ClientAccess*" }| Get-mapiVirtualDirectory | ft Server,Name,ExternalUrl,InternalUrl -AutoSize 80 | Write-Host "WebservicesVirtualDirectory" 81 | get-exchangeserver | ? { $_.ServerRole -like "*ClientAccess*" }| Get-WebservicesVirtualDirectory | ft Server,Name,ExternalUrl,InternalUrl -AutoSize 82 | Write-Host "OutlookAnywhere" 83 | get-exchangeserver | Get-outlookAnywhere | ft Name,ExternalHostname,InternalHostname -AutoSize 84 | 85 | $after = Get-Date 86 | 87 | $time = $after - $before 88 | $buildTime = "`nBuild finished in "; 89 | if ($time.Minutes -gt 0) 90 | { 91 | $buildTime += "{0} minute(s) " -f $time.Minutes; 92 | } 93 | 94 | $buildTime += "{0} second(s)" -f $time.Seconds; 95 | Write-host $buildTime -------------------------------------------------------------------------------- /Get-WindowsSid.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 5.1 2 | 3 | <# 4 | .SYNOPSIS 5 | Utilize PSGetSid by Mark Russinovich (Sysinternals) to gather the Windows SID from all online Computer within the Active Directory. 6 | 7 | .DESCRIPTION 8 | Utilize PSGetSid by Mark Russinovich (Sysinternals) to gather the Windows SID from all online Computer within the Active Directory. It also gather some Additional information from the Active Directory. 9 | Download and extract PSGetSid from PSTools: https://download.sysinternals.com/files/PSTools.zip 10 | For more details about duplicated SID check Marks article: https://learn.microsoft.com/en-us/archive/blogs/markrussinovich/the-machine-sid-duplication-myth-and-why-sysprep-matters 11 | 12 | .PARAMETER PSGetSid 13 | Path to PsGetsid64.exe including filename 14 | 15 | .PARAMETER CSV 16 | Export report as CSV 17 | 18 | .EXAMPLE 19 | C:\PS> Get-WindowsSid.ps1 20 | 21 | .NOTES 22 | Author : Fabian Niesen (www.fabian-niesen.de) 23 | Filename : Get-WindowsSid.ps1 24 | Requires : PowerShell Version 5.1, PsGetSid from Sysinternals 25 | LastModBy : Fabian Niesen 26 | License : The MIT License (MIT) 27 | Copyright (c) 2022-2025 Fabian Niesen 28 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 29 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 30 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 31 | furnished to do so, subject to the following conditions: 32 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 33 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 34 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 35 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 36 | connection with the software or the use or other dealings in the Software. 37 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 38 | The author assumes no responsibility for any damage or data loss caused by this script. 39 | Test thoroughly in a controlled environment before deploying to production. 40 | 41 | Version : 1.2 42 | History : 43 | 1.2 FN 03.12.2025 Change License to MIT, housekeeping Header 44 | 1.1 FN 25.10.2025 Change License to GPLv3 45 | 1.0 FN 24.09.2022 first official 46 | 47 | .LINK 48 | https://github.com/InfrastructureHeroes/Scipts 49 | https://www.infrastructureheroes.org/microsoft-infrastructure/microsoft-windows/the-windows-sid-and-an-old-problem/ 50 | https://www.infrastrukturhelden.de/microsoft-infrastruktur/microsoft-windows/die-windows-sid-und-ein-altes-problem/ 51 | #> 52 | 53 | Param( 54 | [String]$PSGetSid = ".\PsGetsid64.exe", 55 | [switch]$CSV 56 | ) 57 | 58 | #ToDo: Test for local PsGetsid64.exe, ask for Path or Download 59 | #ToDo: Add Parameter for CSV Export 60 | #ToDo: Test for PSGetSid exists 61 | $ErrorActionPreference = "SilentlyContinue" 62 | Set-Location $PSScriptRoot 63 | $ScriptName = $myInvocation.MyCommand.Name 64 | $ScriptName = $ScriptName.Substring(0, $scriptName.Length - 4) 65 | $LogName = (Get-Date -UFormat "%Y%m%d-%H%M") + "-" + $scriptName + "_" + $ENV:COMPUTERNAME +".log" 66 | Start-Transcript -Path "$PSScriptRoot\$LogName" -Append 67 | 68 | try { 69 | Get-ItemProperty -Path "REGISTRY::HKEY_CURRENT_USER\Software\Sysinternals\PsGetSid" -ErrorAction Stop | Select-Object -ExpandProperty "EulaAccepted" -ErrorAction Stop | Out-Null 70 | } 71 | catch { 72 | Write-Verbose "no EULA" 73 | $accepteula = Read-Host "Do you Accept the EULA? (Y/N)" 74 | IF ( $accepteula -match "y" -or $accepteula -match "z") 75 | { & $PSGetSid -accepteula } 76 | ELSE { Break } 77 | } 78 | $Computers = Get-ADComputer -Filter "Enabled -eq 'true'" -Properties name,LastLogonDate,OperatingSystem,OperatingSystemVersion,whenChanged,DNSHostName | Sort-Object | Select-Object name,LastLogonDate,OperatingSystem,OperatingSystemVersion,whenChanged,DNSHostName 79 | $Computers | Add-Member -MemberType NoteProperty -Name 'SID' -Value $null 80 | $Computers | Add-Member -MemberType NoteProperty -Name 'Online' -Value $null 81 | $SIDs = @() 82 | $SIDs | Add-Member -MemberType NoteProperty -Name 'Online' -Value $null 83 | $SIDs | Add-Member -MemberType NoteProperty -Name 'SID' -Value $null 84 | Write-Progress -activity "Processing PSsid" -Status "starting" -PercentComplete "0" -Id 1 85 | [int]$i = 0 86 | [int]$j = $($Computers).count 87 | ForEach ($Computer in $Computers) 88 | { 89 | Write-Progress -activity "Processing PSsid - $i of $j" -Status "$($Computer.name)" -PercentComplete (($i / $j *100)) -Id 1 -ErrorAction SilentlyContinue 90 | $i++ 91 | [bool]$Computer.Online = [bool]$(Test-Connection $($Computer.DNSHostName) -Count 3 -ErrorAction SilentlyContinue) 92 | IF ( $($Computer.Online) -eq $true) 93 | { 94 | Write-Verbose "$($Computer.DNSHostName) - Starte PSSID" 95 | $pssid = (& $PSGetSid \\$($Computer.name) -nobanner) | Select-String -Pattern "S-1-5-21-" 96 | $Computer.SID = $pssid 97 | } ELSEIF ( $($Computer.Online) -eq $false) { 98 | Write-Verbose "$($Computer.DNSHostName) - System Offline" 99 | } Else { Write-host "WTF $($Computer.DNSHostName)" } 100 | Write-Verbose "Value: $Computer" 101 | $SIDs += $Computer 102 | } 103 | $SIDs | Format-Table -Property name,Online,SID,LastLogonDate,OperatingSystem,OperatingSystemVersion,whenChanged -AutoSize 104 | IF ( $CSV) 105 | { 106 | $csvpath = "$PSScriptRoot\"+(Get-Date -UFormat "%Y%m%d-%H%M")+"-SID.csv" 107 | Write-Output "CSV file generated - $csvpath" 108 | $SIDs | Export-Csv -Path $csvpath -Force -Delimiter ";" -NoTypeInformation 109 | } -------------------------------------------------------------------------------- /GPO/Check-LocalGroupPolicy.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 4.0 2 | #Requires -RunAsAdministrator 3 | <# 4 | .SYNOPSIS 5 | Check local EventLog for signes of issues with Local GPO and fixed them if needed. 6 | .DESCRIPTION 7 | Check local EventLog for signes of issues with Local GPO and fixed them if needed. Malformed local GPO prevent GPO processing. This mean changes in GPOs will not be processed by this client. The script needs to be run with Administrative permissions. 8 | .EXAMPLE 9 | Check-LocalGroupPolicy.ps1 10 | 11 | .NOTES 12 | Author : Fabian Niesen 13 | Filename : Check-LocalGroupPolicy.ps1 14 | Requires : PowerShell Version 4.0 15 | License : The MIT License (MIT) 16 | Copyright (c) 2022-2025 Fabian Niesen 17 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 18 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 19 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 22 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 23 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 24 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 25 | connection with the software or the use or other dealings in the Software. 26 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 27 | The author assumes no responsibility for any damage or data loss caused by this script. 28 | Test thoroughly in a controlled environment before deploying to production. 29 | Version : 0.4 30 | History : 0.4 03.12.2025 FN Changed License to MIT, housekeeping Header 31 | 0.3 23.12.2022 FN Some Cleanup and Housekeeping 32 | 0.2 08.03.2021 FN Found in personal archive and published to GitHub 33 | 0.1 FN 2016 Initial version. 34 | .LINK 35 | https://github.com/InfrastructureHeroes/Scipts/blob/master/GPO/Check-LocalGroupPolicy.ps1 36 | #> 37 | [cmdletbinding()] 38 | Param( 39 | [Parameter(Mandatory=$false, Position=2, ValueFromPipeline=$False)] 40 | [bool]$needfix = $false, 41 | [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$False)] 42 | $logpath = "C:\Windows\System32\LogFiles\" 43 | ) 44 | $scriptversion = "0.4" 45 | Write-Output "Check-LocalGroupPolicy.ps1 Version $scriptversion " 46 | $ScriptName = $myInvocation.MyCommand.Name 47 | $ScriptName = $ScriptName.Substring(0, $ScriptName.Length - 4) 48 | $LogName = $ScriptName + "_" + $env:computername + "_" + (Get-Date -UFormat "%Y%m%d") + ".log" 49 | $logfile = $logpath + $LogName 50 | "$(get-date -format yyyyMMdd-HHmm) Starting $ScriptName" | Out-File $logfile -Append 51 | # Function to start a CLI application and return the exit code - This could maybe also be done with Invoke-GPUpdate today, but I have no malformed device to test. 52 | # Based upon https://powersheller.wordpress.com/2011/03/29/powershell-re-creating-the-local-group-policy-database-file/ 53 | Function Start-CliApplication { 54 | param ( [string]$application, [string]$arguments ) 55 | # Build Startinfo and set options according to parameters 56 | $startInfo = new-object System.Diagnostics.ProcessStartInfo 57 | $startInfo.FileName = $application 58 | $startInfo.Arguments = $arguments 59 | $startInfo.WindowStyle = "Hidden" 60 | $startInfo.CreateNoWindow = $true 61 | $startInfo.UseShellExecute = $false 62 | # Start the process 63 | $process = [System.Diagnostics.Process]::Start($startinfo) 64 | 65 | # Wait until the process finished 66 | Do { 67 | If( -not $process.HasExited ) { 68 | $process.Refresh() 69 | } 70 | } While( -not $process.WaitForExit(1000) ) 71 | 72 | # Output the exitcode 73 | Write-Output $process.exitcode 74 | } 75 | 76 | "$(get-date -format yyyyMMdd-HHmm) Processing Eventlog" | Out-File $logfile -Append 77 | 78 | $eventGpoProcessingFailed = Get-EventLog System -Newest 500 | where { $_.eventID -eq "1096" } 79 | 80 | IF ( $eventGpoProcessingFailed -ne $null) 81 | { 82 | "$(get-date -format yyyyMMdd-HHmm) Found EventID 1096"| Out-File $logfile -Append 83 | $FilePath = $($eventGpoProcessingFailed[0] | select -ExpandProperty ReplacementStrings)[8] 84 | "$(get-date -format yyyyMMdd-HHmm) Find corupted local GPO: $FilePath" | Out-File $logfile -Append 85 | "$(get-date -format yyyyMMdd-HHmm) Set NeedFix"| Out-File $logfile -Append 86 | $needfix = $true 87 | } 88 | 89 | IF ( $needfix -eq $true) 90 | { 91 | "$(get-date -format yyyyMMdd-HHmm) Fix required, Try to delete File: $FilePath"| Out-File $logfile -Append 92 | Remove-Item -LiteralPath $FilePath -Force 93 | "$(get-date -format yyyyMMdd-HHmm) Test if file is deleted"| Out-File $logfile -Append 94 | IF ( !(Test-Path $FilePath)) 95 | { 96 | "$(get-date -format yyyyMMdd-HHmm) File removed, starting GPUPDATE"| Out-File $logfile -Append 97 | Start-Sleep -Seconds 5 98 | $gpupdateResult = Start-CliApplication "gpupdate" "/force" 99 | If ($gpUpdateResult -eq 0) 100 | { 101 | "$(get-date -format yyyyMMdd-HHmm) Group Policy Update Successful"| Out-File $logfile -Append 102 | } 103 | Else 104 | { 105 | "$(get-date -format yyyyMMdd-HHmm) Group Policy Update Failed"| Out-File $logfile -Append 106 | break 107 | } 108 | } 109 | ELSE 110 | { 111 | "$(get-date -format yyyyMMdd-HHmm) Can not remove $FilePath, please check"| Out-File $logfile -Append 112 | break 113 | } 114 | } 115 | ELSE {"$(get-date -format yyyyMMdd-HHmm) Noting to do"| Out-File $logfile -Append } 116 | -------------------------------------------------------------------------------- /Set-WinRelease.ps1: -------------------------------------------------------------------------------- 1 | #Requires -RunAsAdministrator 2 | 3 | <# 4 | .SYNOPSIS 5 | Set Registry key to stay at a specific Windows 10 Release 6 | 7 | .DESCRIPTION 8 | Set Registry key to set a max Windows 10 Release version for Windows update automatic feature upgrade. This script does not force a downgrade. 9 | Use it on your own risk. 10 | 11 | .EXAMPLE 12 | C:\PS> set-WinRelease.ps1 13 | 14 | .EXAMPLE 15 | C:\PS> set-WinRelease.ps1 -ver 1909 16 | 17 | .PARAMETER ver 18 | Set Windows Release to this version 19 | 20 | .NOTES 21 | Author : Fabian Niesen (www.infrastrukturhelden.de) 22 | Filename : set-WinRelease.ps1 23 | Requires : PowerShell Version 3.0 24 | License : The MIT License (MIT) 25 | Copyright (c) 2022-2025 Fabian Niesen 26 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 27 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 28 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 29 | furnished to do so, subject to the following conditions: 30 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 31 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 32 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 33 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 34 | connection with the software or the use or other dealings in the Software. 35 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 36 | The author assumes no responsibility for any damage or data loss caused by this script. 37 | Test thoroughly in a controlled environment before deploying to production. 38 | Version : 1.1 39 | History : 1.1 FN 30.05.2024 Added 23H2 and 24H2, MIT License, housekeeping Header 40 | 1.0 FN 30.11.2021 initial version 41 | 42 | .LINK 43 | https://github.com/InfrastructureHeroes/Scipts 44 | #> 45 | 46 | Param( 47 | [Parameter(Mandatory=$true)][ValidateSet("1909","2004","20H2","21H1","21H2","22H2","23H2","24H2")] [string]$ver 48 | ) 49 | $scriptversion = "1.1" 50 | Write-Output "Set-WinRelease.ps1 Version $scriptversion " 51 | $ErrorActionPreference = "Stop" 52 | $RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Update" 53 | $RegName = "TargetReleaseVersion" 54 | $RegValue = "1" 55 | $ProductName = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ProductName).ProductName 56 | If ( $ProductName -Like "Windows 10 Pro") { $Edition = "Pro"} 57 | elseif ( $ProductName -like "Windows 10 Enterprise") { $Edition = "Ent"} 58 | else { $Edition = "Other" } 59 | 60 | Try { $Version = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ReleaseID -ErrorAction Stop).ReleaseID } 61 | Catch { $Version = "N/A" } 62 | Write-Output "Found $ProductName" 63 | if ($ver -eq $null) { Write-Output "No Windows Release selected, please start again with the release of choice." ; Break } 64 | If (-NOT (Test-Path $RegPath)) { New-Item -Path $RegPath -Force | Out-Null } 65 | New-ItemProperty -Path $RegPath -Name $RegName -Value $RegValue -PropertyType DWORD -Force 66 | $RegName = "TargetReleaseVersionInfo" 67 | $date = Get-Date 68 | Switch ( $ver ) 69 | { 70 | "21H2" 71 | { 72 | New-ItemProperty -Path $RegPath -Name $RegName -Value "21H2" -PropertyType String -Force 73 | If ( $Edition -like "Pro") { $sdate = get-date -Year "2023" -Month "06" -Day "13" ; If ($date -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" } } 74 | ElseIf ( $Edition -like "Ent") { $sdate = get-date -Year "2024" -Month "06" -Day "11" ; If ($(get-date) -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" } } 75 | } 76 | "21H1" 77 | { 78 | New-ItemProperty -Path $RegPath -Name $RegName -Value "21H1" -PropertyType String -Force 79 | $sdate = get-date -Year "2022" -Month "12" -Day "13" 80 | If ($( get-date) -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" } 81 | } 82 | "20H2" 83 | { 84 | New-ItemProperty -Path $RegPath -Name $RegName -Value "20H2" -PropertyType String -Force 85 | If ( $Edition -like "Pro") {$sdate = get-date -Year "2022" -Month "05" -Day "10" ; If ($( get-date) -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" } } 86 | ElseIf ( $Edition -like "Ent") { $sdate = get-date -Year "2023" -Month "05" -Day "09" ; If ($(get-date) -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" } } 87 | } 88 | "2004" 89 | { 90 | New-ItemProperty -Path $RegPath -Name $RegName -Value "2004" -PropertyType String -Force 91 | $sdate = get-date -Year "2021" -Month "12" -Day "14" 92 | If ($( get-date) -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" } 93 | } 94 | "1909" 95 | { 96 | New-ItemProperty -Path $RegPath -Name $RegName -Value "1909" -PropertyType String -Force 97 | If ( $Edition -like "Pro") { $sdate = get-date -Year "2021" -Month "05" -Day "10" ; If ($( get-date) -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" }} 98 | ElseIf ( $Edition -like "Ent") { $sdate = get-date -Year "2022" -Month "05" -Day "11" ; If ($(get-date) -gt $sdate) { Write-Warning "$ProductName $Version is not longer supported anymore!!"} ELSE { $left = $($sdate - $date).Days ; Write-Output "You have $left days support left till EOL for $ProductName $ver" }} 99 | } 100 | Default { Write-Warning "No valid Value entered. Please use 21H2, 21H1, 2004 or 1909" } 101 | } 102 | -------------------------------------------------------------------------------- /User/create-user.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Code sample to create a new AD User with Office 365 integration. 4 | 5 | .DESCRIPTION 6 | Code sample to create a new AD User with Office 365 integration. This needs to be customized to the target environment. 7 | 8 | .NOTES 9 | Author : Fabian Niesen (infrastrukturhelden.de) 10 | Filename : create-user.ps1 11 | Requires : PowerShell Version 3.0 12 | 13 | Version : 0.3 14 | History : 0.3 FN 03.12.2025 Changed License to MIT, housekeeping Header 15 | 0.2 FN 27.08.2022 Add SmtpPort due #4, fixed some encoding and Typos - Not testest, since my test env is down - Any problems, open an issue at https://github.com/InfrastructureHeroes/Scipts 16 | 0.1 FN 22.01.2019 initial draft 17 | License : The MIT License (MIT) 18 | Copyright (c) 2022-2025 Fabian Niesen 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 20 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 21 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 24 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 25 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 26 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 27 | connection with the software or the use or other dealings in the Software. 28 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 29 | The author assumes no responsibility for any damage or data loss caused by this script. 30 | Test thoroughly in a controlled environment before deploying to production. 31 | .LINK 32 | https://www.infrastrukturhelden.de/microsoft-infrastruktur/active-directory/benutzer-einfachen-anlegen-mit-powershell/ 33 | https://github.com/InfrastructureHeroes/Scipts/blob/master/User/create-user.ps1 34 | #> 35 | 36 | [cmdletbinding()] 37 | Param( 38 | [string] $OU="OU=Benutzer,DC=ADG,DC=local", 39 | [string] $Vorname="", 40 | [string] $Nachname="", 41 | [string] $Password="Pa$$w0rd!1", 42 | [string] $Username=$Vorname+"."+$Nachname , 43 | [string] $Email="demo.held@niesenf.onmicrosoft.com", 44 | [string] $UPN="demo.held@adg.local", 45 | [switch] $PWwechsel, 46 | [switch] $Aktiviert, 47 | [DateTime] $Ablaufdatum, #-AccountExpirationDate #! Umsetzen 48 | [switch] $O365, 49 | [string] $ADCServer="", 50 | [String] $O365Loc="", 51 | [String] $O365Lic="SPE_E5", #Office365 E3 Development = DEVELOPERPACK, Microsoft365 E5 = SPE_E5, WDATP = WIN_DEF_ATP 52 | [string] $DC="", 53 | [string] $Abt="", 54 | [string] $SmtpServer, 55 | [string] $From, 56 | [string] $To, 57 | [switch] $TLS, 58 | [switch] $SmtpAuth, 59 | [string] $smtppw = "", 60 | [string] $smtpuser = "", 61 | [int] $SmtpPort ="" 62 | ) 63 | $scriptversion = "0.3" 64 | Write-Output "create-user.ps1 Version $scriptversion " 65 | [String] $WelcomeSub = "Willkommen bei Infrastrukturhelden.de" 66 | [String] $WelcomeBody = "Hallo $Vorname" + ',
hier schreiben wir dir noch eine nette Begrüssung
Besuche uns auf Infrastrukturhelden.de' 67 | 68 | Function SendEmailStatus($From, $To, $Subject, $SmtpServer, $BodyAsHtml, $Body) 69 | { 70 | $SmtpMessage = New-Object System.Net.Mail.MailMessage $From, $To, $Subject, $Body 71 | $SmtpMessage.IsBodyHTML = $BodyAsHtml 72 | $SmtpClient = New-Object System.Net.Mail.SmtpClient $SmtpServer 73 | IF ($TLS) { $SmtpClient.EnableSsl = $true } 74 | IF ($SmtpAuth) { $SmtpClient.Credentials = New-Object System.Net.NetworkCredential($smtpuser, $smtppw) } 75 | IF ($SmtpPort) { $SmtpClient.Port = $SmtpPort } 76 | $SmtpClient.Send($SmtpMessage) 77 | If($? -eq $False){Write-Warning "$($Error[0].Exception.Message) | $($Error[0].Exception.GetBaseException().Message)"} 78 | $SmtpMessage.Dispose() 79 | Remove-Variable SmtpClient 80 | Remove-Variable SmtpMessage 81 | } 82 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) 83 | { 84 | $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell"; 85 | $newProcess.Arguments = $myInvocation.MyCommand.Definition; 86 | $newProcess.Verb = "runas"; 87 | break 88 | } 89 | if(@(get-module | where-object {$_.Name -eq "ActiveDirectory"} ).count -eq 0) {import-module ActiveDirectory} 90 | Import-Module ActiveDirectory 91 | IF ($DC -eq "") { $DC = $(Get-ADDomainController).HostName ; Write-Verbose "Kein DC angegeben, nutze $DC" } 92 | IF ( $O365 ) { Try { Connect-AzureAD } catch { Write-Verbose "Installiere AzureAD Modul" ; Install-Module -Name AzureAD -Force ; Connect-AzureAD } } 93 | $SecPass = $Password | ConvertTo-SecureString -AsPlainText -Force 94 | #Zeichenlimit für SAM Account 95 | Write-Verbose "Lege Benutzer an" 96 | New-ADUser -Name $Username -GivenName $Vorname -Surname $Nachname -Path $OU -AccountPassword $SecPass -DisplayName $($Vorname+" "+$Nachname) -EmailAddress $Email -UserPrincipalName $UPN -OtherAttributes @{proxyAddresses=$("SMPT:"+$Email)} -Server $DC 97 | Start-Sleep -Seconds 10 98 | IF ( $PWwechsel ) { Set-ADUser -Identity $Username -ChangePasswordAtLogon $true -Server $DC } ELSE { Set-ADUser -Identity $Username -ChangePasswordAtLogon $false -Server $DC } 99 | IF ( $Aktiviert ) { Set-ADUser -Identity $Username -Enabled $true -Server $DC ; Write-Verbose "Aktiviere $Username" } 100 | IF ( $Abt -eq "" ) { Write-verbose "Keine Abteilung ausgewählt" } Else { Add-ADGroupMember -Identity $Abt -Members $Username } 101 | IF ( $O365 ) { 102 | Write-Verbose "Starte AAD Sync" 103 | Invoke-Command -ComputerName $ADCServer -ScriptBlock { Start-ADSyncSyncCycle -PolicyType Delta } 104 | while ( $(try {Get-AzureADUser -ObjectId $Email} catch {}).count -lt 1) { start-sleep -Seconds 10 ; Write-Verbose "Wait for user appear online"} 105 | #Lizenzzuweisen 106 | Set-AzureADUser -ObjectId $Email -UsageLocation "DE" 107 | $license = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense 108 | $licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses 109 | $license.SkuId = (Get-AzureADSubscribedSku | Where-Object -Property SkuPartNumber -Value $O365Lic -EQ).SkuID 110 | $licenses.AddLicenses = $license 111 | Set-AzureADUserLicense -ObjectId $Email -AssignedLicenses $licenses 112 | Write-Verbose "Assigned Licenses: $($(Get-AzureADUserLicenseDetail -ObjectId $Email ).SkuPartNumber)" 113 | } 114 | # Willkommensemail 115 | SendEmailStatus -From $From -To $Email -Subject $WelcomeSub -SmtpServer $SmtpServer -BodyAsHtml $True -Body $WelcomeBody -------------------------------------------------------------------------------- /Windows/Remove-AzureArc.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 5.1 2 | 3 | <# 4 | .SYNOPSIS 5 | Remove Azure Arc Setup if installed. Reboot will happend automaticaly. 6 | 7 | .DESCRIPTION 8 | Remove Azure Arc Setup if installed. Reboot will happend automaticaly. 9 | 10 | .EXAMPLE 11 | Remove-AzureArc.ps1 12 | 13 | .NOTES 14 | Author : Fabian Niesen 15 | Filename : Remove-AzureArc.ps1 16 | Requires : PowerShell Version 5.1 17 | License : The MIT License (MIT) 18 | Copyright (c) 2024-2025 Fabian Niesen 19 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 20 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 21 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 24 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 25 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 26 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 27 | connection with the software or the use or other dealings in the Software. 28 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 29 | The author assumes no responsibility for any damage or data loss caused by this script. 30 | Test thoroughly in a controlled environment before deploying to production. 31 | Version : 1.1 FN 03.12.2025 Changed License to MIT, housekeeping Header 32 | History : FN 06.03.2024 Initiale Version 33 | .LINK 34 | https://github.com/InfrastructureHeroes/Scipts 35 | #> 36 | 37 | #REGION Functions 38 | Function Get-PendingRebootStatus { 39 | <# 40 | .Synopsis 41 | This will check to see if a server or computer has a reboot pending. 42 | For updated help and examples refer to -Online version. 43 | 44 | .NOTES 45 | Name: Get-PendingRebootStatus 46 | Author: theSysadminChannel, Fabian Niesen 47 | Version: 1.2 FN 48 | DateCreated: 2018-Jun-6 49 | DateModified: 2023-Jan-20 50 | 51 | .LINK 52 | https://thesysadminchannel.com/remotely-check-pending-reboot-status-powershell 53 | 54 | 55 | .PARAMETER ComputerName 56 | By default it will check the local computer. 57 | 58 | .EXAMPLE 59 | Get-PendingRebootStatus -ComputerName PAC-DC01, PAC-WIN1001 60 | 61 | Description: 62 | Check the computers PAC-DC01 and PAC-WIN1001 if there are any pending reboots. 63 | #> 64 | 65 | [CmdletBinding()] 66 | Param () 67 | 68 | BEGIN {} 69 | 70 | PROCESS { 71 | Try { 72 | $Computer = $env:COMPUTERNAME 73 | $PendingReboot = $false 74 | $HKLM = [UInt32] "0x80000002" 75 | $WMI_Reg = [WMIClass] "\\$Computer\root\default:StdRegProv" 76 | if ($WMI_Reg) { 77 | if (($WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")).sNames -contains 'RebootPending') {$PendingReboot = $true ; Write-output "Component Based Servicing: RebootPending"} 78 | if (($WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")).sNames -contains 'RebootRequired') {$PendingReboot = $true ; Write-output "WindowsUpdate: RebootRequired"} 79 | if (($WMI_Reg.EnumKey($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager")).sNames -contains 'PendingFileRenameOperations') {$PendingReboot = $true ; Write-output "Session Manager: PendingFileRenameOperations"} 80 | if (($WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update")).sNames -contains 'PostRebootReporting') {$PendingReboot = $true ; Write-output "WindowsUpdate: PostRebootReporting"} 81 | if (($WMI_Reg.EnumKey($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager")).sNames -contains 'PendingFileRenameOperations2') {$PendingReboot = $true ; Write-output "Session Manager: PendingFileRenameOperations2"} 82 | if (($WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")).sNames -contains 'RebootInProgress') {$PendingReboot = $true ; Write-output "Component Based Servicing: RebootInProgress"} 83 | if (($WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")).sNames -contains 'PackagesPending') {$PendingReboot = $true ; Write-output "Component Based Servicing: PackagesPending"} 84 | if (($WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\ServerManager")).sNames -contains 'CurrentRebootAttempts') {$PendingReboot = $true ; Write-output "ServerManager: CurrentRebootAttempts"} 85 | if (($WMI_Reg.EnumKey($HKLM,"SYSTEM\CurrentControlSet\Services\Netlogon")).sNames -contains 'JoinDomain') {$PendingReboot = $true ; Write-output "Netlogon: JoinDomain"} 86 | #Checking for SCCM namespace 87 | $SCCM_Namespace = Get-WmiObject -Namespace ROOT\CCM\ClientSDK -List -ComputerName $Computer -ErrorAction Ignore 88 | if ($SCCM_Namespace) { 89 | if (([WmiClass]"\\$Computer\ROOT\CCM\ClientSDK:CCM_ClientUtilities").DetermineIfRebootPending().RebootPending -eq $true) {$PendingReboot = $true ; Write-output "SCCM: RebootPending"} 90 | } 91 | } 92 | } catch { 93 | Write-Error $_.Exception.Message 94 | } finally { 95 | #Clearing Variables 96 | $null = $WMI_Reg 97 | $null = $SCCM_Namespace 98 | IF ($PendingReboot) { $reboot = $true } 99 | } 100 | } 101 | 102 | END { Return $PendingReboot } 103 | } 104 | #ENDREGION Functions 105 | $scriptversion = "1.1" 106 | Write-Output "Remove-AzureArc.ps1 Version $scriptversion " 107 | $AzureArc = $( (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue ).UBR -ge 2031) 108 | IF ( -not $AzureArc) 109 | { Write-Output "Patchlevel is not high enough for Azure Arc - No action required " } 110 | Else { 111 | # Get-WindowsFeature -Name AzureArcSetup 112 | IF ( (get-WindowsFeature -Name AzureArcSetup).InstallState -like "Installed" ) {Write-Warning "AzureArc is Installed - Remove Feature Restart required" ; Uninstall-WindowsFeature -Name AzureArcSetup -Restart:$false -confirm:$false } 113 | ELSE { Write-Output "Windows Arc is not installed"} 114 | IF ( Get-PendingRebootStatus ) { 115 | Write-Warning "Reboot required - Will reboot in 60 sec. Use >Shutdown.exe /a< to abort." 116 | shutdown.exe /t 60 /r /c "Reboot required" /d p:2:4 117 | } 118 | } -------------------------------------------------------------------------------- /BitLocker/Update-BitLockerRecovery.ps1: -------------------------------------------------------------------------------- 1 | 2 | <#PSScriptInfo 3 | 4 | .VERSION 1.0.1 5 | 6 | .GUID 3c0736ab-4777-4b58-ae0f-80b4e89b64a2 7 | 8 | .AUTHOR Fabian Niesen 9 | 10 | .COMPANYNAME InfrastrukturHelden.de | Fabian Niesen Online Services 11 | 12 | .COPYRIGHT 13 | 14 | .TAGS BitLocker PowerShell Update ActiveDirectory RecoveryKeys 15 | 16 | .LICENSEURI 17 | 18 | .PROJECTURI https://www.infrastrukturhelden.de/microsoft-infrastruktur/active-directory/bitlocker-wiederherstellungs-keys-nachtraglich-im-ad-sichern/ 19 | 20 | .ICONURI 21 | 22 | .EXTERNALMODULEDEPENDENCIES 23 | 24 | .REQUIREDSCRIPTS 25 | 26 | .EXTERNALSCRIPTDEPENDENCIES 27 | 28 | .RELEASENOTES 29 | 30 | 31 | #> 32 | 33 | 34 | 35 | <# 36 | .SYNOPSIS 37 | Upload BitLocker recovery information to Active Directory, if they not already exist. 38 | 39 | .DESCRIPTION 40 | Upload BitLocker recovery information to Active Directory, if they not already exist. 41 | WARNING: While the manage-bde Output is localized, this will only work on English and German Windows 10 devices. 42 | 43 | .EXAMPLE 44 | C:\PS> Update-BitLockerRecovery.ps1 45 | 46 | .EXAMPLE 47 | C:\PS> Update-BitLockerRecovery.ps1 -locale "de-DE" 48 | 49 | .PARAMETER locale 50 | Language code of the OS, if not set the script will use "GET-WinSystemLocale" for autodetection 51 | 52 | .PARAMETER procstate 53 | String to determin the protection state based on the localized output of "manage-bde -status" 54 | 55 | .PARAMETER procstatepat 56 | Pattern to determin the if the protection state based on the localized output of "manage-bde -status" is enabled 57 | 58 | .PARAMETER adcheck 59 | Check Active Directory and shows the key. Require Active Directory PowerShell module installed and Domain Admin permissions 60 | 61 | .NOTES 62 | Author : Fabian Niesen (infrastrukturhelden.de) 63 | Filename : Update-BitLockerRecovery.ps1 64 | Requires : PowerShell Version 3.0 65 | License : The MIT License (MIT) 66 | Copyright (c) 2022-2025 Fabian Niesen 67 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 68 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 69 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 70 | furnished to do so, subject to the following conditions: 71 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 72 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 73 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 74 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 75 | connection with the software or the use or other dealings in the Software. 76 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 77 | The author assumes no responsibility for any damage or data loss caused by this script. 78 | Test thoroughly in a controlled environment before deploying to production. 79 | Version : 1.2 80 | History : 1.2 FN 03.12.2025 Changed License to MIT, housekeeping Header 81 | 1.1 FN 09.12.2021 Change Locale setting after feedback from Jonas. Thanks 82 | 1.0 FN 01/22/2021 initial version 83 | 84 | .LINK 85 | https://www.infrastrukturhelden.de/microsoft-infrastruktur/active-directory/bitlocker-wiederherstellungs-keys-nachtraglich-im-ad-sichern/ 86 | #> 87 | Param( 88 | [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$False)] 89 | [String]$procstate="", 90 | [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$False)] 91 | [String]$procstatepat="", 92 | [Parameter(Mandatory=$false, Position=2, ValueFromPipeline=$false)] 93 | [string]$locale = $((Get-UICulture).Name), 94 | [switch]$adcheck 95 | ) 96 | $scriptversion = "1.2" 97 | Write-Output "Update-BitLockerRecovery.ps1 Version $scriptversion " 98 | $ErrorActionPreference = "Stop" 99 | If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) 100 | { 101 | $arguments = "& '" + $myinvocation.mycommand.definition + "'" 102 | Start-Process powershell -Verb runAs -ArgumentList $arguments 103 | Break 104 | } 105 | switch($locale){ 106 | "de-DE" {$procstate = "Schutzstatus" ; $procstatepat = "*Der Schutz ist aktiviert*" ; Write-Verbose "Locale set to de-DE"} 107 | "en-EN" {$procstate = "Protection" ; $procstatepat = "*Protection On*" ; Write-Verbose "Locale set to en-EN"} 108 | Default {IF ($procstate -eq "" -or $procstatepat-eq "") { Write-Error -Message "Locale not prefinied in script! Please use parameter procstate and procstatepat. Please execute >Get-Help .\Update-BitLockerRecovery.ps1 -Detailed<" -Category NotImplemented }} 109 | } 110 | 111 | Try { New-Item -Path HKLM:\SOFTWARE\Policies\Microsoft -Name FVE } Catch {Write-Warning "Registry path already exists"} 112 | Set-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSRecovery -Value 1 -Type DWord -Force; 113 | Set-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSManageDRA -Value 1 -Type DWord -Force; 114 | Set-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSRequireActiveDirectoryBackup -Value 0 -Type DWord -Force; 115 | Set-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSActiveDirectoryInfoToStore -Value 1 -Type DWord -Force; 116 | Set-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSActiveDirectoryBackup -Value 1 -Type DWord -Force; 117 | Set-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSHideRecoveryPage -Value 0 -Type DWord -Force 118 | Get-PSDrive -PSProvider FileSystem | Where-Object { !($_.DisplayRoot -ilike "\\*") } | ForEach-Object { 119 | $root = $_.Root # Fetch the drive letter or mount point 120 | if ($root -ilike "*\") { $root = $root.substring(0, $root.length - 1) } # Remove trailing backslash 121 | [string] $status = (manage-bde -status $root) | Select-String -Pattern $procstate 122 | Write-verbose "Status: $status" 123 | if ($status -ilike $procstatepat) { 124 | [string] $id = (manage-bde -protectors -get $root -Type recoverypassword) | Select-String -Pattern ID 125 | $id = $id.Replace("ID: ", "").Trim() 126 | Write-verbose "ID: $id" 127 | manage-bde -protectors -adbackup $root -id $id 128 | Start-Sleep -Seconds 10 129 | } 130 | } 131 | Remove-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSRecovery -Force; 132 | Remove-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSManageDRA -Force; 133 | Remove-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSRequireActiveDirectoryBackup -Force; 134 | Remove-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSActiveDirectoryInfoToStore -Force; 135 | Remove-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSActiveDirectoryBackup -Force; 136 | Remove-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\FVE -Name OSHideRecoveryPage -Force 137 | Write-Verbose "Setting back GPO Settings" 138 | GPupdate.exe /Target:Computer /Force 139 | if ($adcheck -eq $false ) { 140 | try 141 | { 142 | Import-Module ActiveDirectory 143 | } 144 | catch 145 | { 146 | Write-Warning "ActiveDirectory Module ist missing. Please install for local check" 147 | break 148 | } 149 | Write-Output "Wait 30 sec to process and AD sync" 150 | Start-Sleep -Seconds 30 151 | $recoveryPass = Get-ADObject -Filter {objectclass -eq 'msFVE-RecoveryInformation'} -SearchBase $($env:COMPUTERNAME).DistinguishedName -Properties 'msFVE-RecoveryPassword' | Where-Object {$_.DistinguishedName -like "*$id*"} 152 | Write-Output "Stored Recovery Password in AD: $recoveryPass " 153 | } 154 | 155 | -------------------------------------------------------------------------------- /ActiveDirectory/Locate-ADLockout.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 2.0 2 | #requires -modules activedirectory 3 | 4 | 5 | <# 6 | .SYNOPSIS 7 | Locate user Lockouts in Active Directory 8 | .DESCRIPTION 9 | Query all DC and Locate user Lockouts in Active Directory within the last 24h. As default the result is shown as Grid-View, but CSV Export is possible. 10 | A lunchtime project... 11 | .EXAMPLE 12 | .\LocateADLockout-v2.ps1 -filter "bn" -CSVOUT $true -Gridview $false -CSVpath 13 | .INPUTS 14 | -RunAs For future use 15 | -filter only DC's with this pattern in the Hostname 16 | -Gridview Output as GridView 17 | -CSVOUT Export as CSV 18 | -CSVpath Exportpath for CSV 19 | .OUTPUTS 20 | Keine. 21 | .NOTES 22 | Author : Fabian Niesen 23 | Filename : Locate-ADLockout.ps1 24 | Requires : PowerShell Version 2.0 25 | 26 | Version : 1.0 27 | History : 1.0 28 | 29 | .LINK 30 | https://www.infrastrukturhelden.de 31 | #> 32 | 33 | Param( 34 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 35 | [String]$RunAs = $false, 36 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 37 | [String]$filter ="*", 38 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 39 | [String]$Gridview =$true, 40 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 41 | [String]$CSVOUT = $false, 42 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 43 | [String]$CSVpath = "changeme" 44 | ) 45 | 46 | $LogOuts = @() 47 | 48 | 49 | #@{label=''}, @{label=''},@{label=''}, @{label=''}, @{label=''} 50 | $DCs = Get-ADDomainController -Filter { HostName -like "$filter" } 51 | ForEach ($DC in $DCs) 52 | { 53 | Write-Output "Starte Remote PowerShell Session zu: "$DC.HostName 54 | $temp = Invoke-Command -ComputerName $DC.HostName -ScriptBlock { Get-EventLog -LogName "Security" -After (Get-Date).AddDays(-1) | Where-Object { $_.EventID -match '4740' -or $_.EventID -match '644'} } 55 | ForEach ($t in $temp) 56 | { 57 | $Log = New-Object -TypeName psobject 58 | $Log | Add-Member -MemberType NoteProperty -Name TimeGenerated -Value $t.TimeGenerated 59 | $Log | Add-Member -MemberType NoteProperty -Name DC -Value $t.ReplacementStrings[4] 60 | $Log | Add-Member -MemberType NoteProperty -Name Benutzer -Value $t.ReplacementStrings[0] 61 | $Log | Add-Member -MemberType NoteProperty -Name Quelle -Value $t.ReplacementStrings[1] 62 | $Log | Add-Member -MemberType NoteProperty -Name LoginID -Value $t.ReplacementStrings[6] 63 | $LogOuts += $Log 64 | } 65 | } 66 | 67 | IF ($Gridview -eq $true) { $LogOuts | Out-GridView -Title "Account Lockouts" } 68 | IF ($CSVOUT -eq $true) 69 | { 70 | IF ($CSVpath -like "changeme") 71 | { 72 | Write-Verbose "No Path found" 73 | $CSVpath = Read-Host -Prompt "Bitte geben Sie einen Dateinamen inklusive Pfad an" 74 | } 75 | $LogOuts | Export-Csv -Path $CSVpath -Delimiter ";" -NoTypeInformation 76 | } 77 | 78 | <# If I have to much time left... 79 | ### Runas Auswertung der Aufgabenplanung pro User und System 80 | IF ($RunAs -eq $true) 81 | { 82 | $SchedService.Connect($ComputerName) 83 | $TaskFolder = $SchedService.GetFolder("") 84 | $RootTasks = $TaskFolder.GetTasks("") 85 | Foreach ($Task in $RootTasks) 86 | { 87 | Switch ($Task.State) 88 | { 89 | 0 {$Status = "Unknown"} 90 | 1 {$Status = "Disabled"} 91 | 3 {$Status = "Ready"} 92 | 4 {$Status = "Running"} 93 | }#End Switch ($Task.State) 94 | $Xml = $Task.Xml 95 | #The code below parses the Xml String Data for the "RunAs User" that is returned from the Schedule.Service COM Object 96 | [String]$RunUser = $Xml[(($Xml.LastIndexOf(""))+8)..(($Xml.LastIndexOf(""))-1)] 97 | $RunUser = $RunUser.Replace(" ","").ToUpper() 98 | $Result = New-Object PSObject -Property @{ 99 | ServerName=$ComputerName 100 | TaskName=$Task.Name 101 | RunAs=$RunUser 102 | LastRunTime=$Task.LastRunTime 103 | NextRunTime=$Task.NextRunTime 104 | }#End $Result = New-Object 105 | $Result = $Result | Select-Object Servername, TaskName, RunAs, LastRunTime, NextRunTime 106 | 107 | #> 108 | 109 | # SIG # Begin signature block 110 | # MIINhAYJKoZIhvcNAQcCoIINdTCCDXECAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB 111 | # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR 112 | # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUY5VekahfDkMzynRQdVSHw6kI 113 | # pG2gggrDMIIE1zCCA7+gAwIBAgIQQqUulpP/t+xNJTeKzXz8XzANBgkqhkiG9w0B 114 | # AQsFADB1MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEpMCcG 115 | # A1UECxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIzAhBgNVBAMT 116 | # GlN0YXJ0Q29tIENsYXNzIDMgT2JqZWN0IENBMB4XDTE2MDcyMDA4MjM0MFoXDTE5 117 | # MDcyMDA4MjM0MFowZDELMAkGA1UEBhMCREUxHDAaBgNVBAgME05vcmRyaGVpbi1X 118 | # ZXN0ZmFsZW4xDTALBgNVBAcMBEJvbm4xEzARBgNVBAoMCnN0ZWVwIEdtYkgxEzAR 119 | # BgNVBAMMCnN0ZWVwIEdtYkgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB 120 | # AQDEym9W07bauIxBdWBD29HJRWbPEZXE7y/slfD1z2Ldf5dNcbhBN++AcFmmitfD 121 | # 9wC4qa6Masw2bcILUqyxY0kTb1zUpV5RPJ389e2mzvsgaQyIsqB+tIUHxdhiyRzc 122 | # i9yFmNybCErwEzNueU37BAxpc21OYn44IExSfP26qsKlEi1KxukHv+pWZbLfZpCt 123 | # T/WE+lZxNTxzjDezk9c0m5wQ+HSShcFUwViBf/h2Ov+05ZhH7j1RjvUSmLSyx0cs 124 | # JL8jaMszouYlRPHnbghD3UD500TjlkT+sstf6JqInGyNYcfa0bsFwbuoKz3SndH1 125 | # RGQ/b4riT5GW0wOljsRtpglBAgMBAAGjggFyMIIBbjAOBgNVHQ8BAf8EBAMCB4Aw 126 | # EwYDVR0lBAwwCgYIKwYBBQUHAwMwCQYDVR0TBAIwADAdBgNVHQ4EFgQUEPS1SOLL 127 | # CkfWuYxHbJz2dHucaNowbQYIKwYBBQUHAQEEYTBfMCQGCCsGAQUFBzABhhhodHRw 128 | # Oi8vb2NzcC5zdGFydHNzbC5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly9haWEuc3Rh 129 | # cnRzc2wuY29tL2NlcnRzL3NjYS5jb2RlMy5jcnQwNgYDVR0fBC8wLTAroCmgJ4Yl 130 | # aHR0cDovL2NybC5zdGFydHNzbC5jb20vc2NhLWNvZGUzLmNybDAjBgNVHRIEHDAa 131 | # hhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wUQYDVR0gBEowSDAIBgZngQwBBAEw 132 | # PAYLKwYBBAGBtTcBAgUwLTArBggrBgEFBQcCARYfaHR0cHM6Ly93d3cuc3RhcnRz 133 | # c2wuY29tL3BvbGljeTANBgkqhkiG9w0BAQsFAAOCAQEAAmEyPAwytipNaWO1N/gf 134 | # c/dMMbf4nKGaIIYSTaguZwdgVwbWEegJ7b51i8kB1+nI3qg+Ez89kmT/Ano4Ot+V 135 | # 7IOx8Hvpfqy1eXKOl2oHVXqEzoZJV/nNf+TFJRk5PKORS8lJIEss9slS79bw4ejI 136 | # LaowcfgHLwmP9yeL3M860edWB+yL00VOVUnYM/Jb2SkCvd1buLUVUluMz1tZdh+s 137 | # B/sGcf2I0sxS8mCbPFuIGJ2LBq859W8MDM4BO1i4tQnLKi5i/VlbVelUtaMTbndS 138 | # WbRn3828k5QnajErzR2C2cAI6Lya8TsKTKKz1I2etM7gPy16II/ygR5q6KoON9n1 139 | # mjCCBeQwggPMoAMCAQICEHgiQ6FT3ygKH/rhXNAoTIYwDQYJKoZIhvcNAQELBQAw 140 | # fTELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT 141 | # IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxKTAnBgNVBAMTIFN0 142 | # YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTE1MTIxNjAxMDAwNVoX 143 | # DTMwMTIxNjAxMDAwNVowdTELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29t 144 | # IEx0ZC4xKTAnBgNVBAsTIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 145 | # MSMwIQYDVQQDExpTdGFydENvbSBDbGFzcyAzIE9iamVjdCBDQTCCASIwDQYJKoZI 146 | # hvcNAQEBBQADggEPADCCAQoCggEBANhsJTYUZFx5zWGYAp8FlVG8yEBmyldXMpNl 147 | # oFW7wnrfr/7lVSgyZ+ZjL8LvZcDB5nftTaSlvd5MCOJW9WlMICRksLS/2vo5b/Bs 148 | # OjIs5A9j8FSt0far4mtE0dlu5mQ3+6hbn2tgjW+m6aksqDymsAIAAW/NFKCsyrDl 149 | # qNOaujXkfmdpbe0keZqKfDDw7DoHZygP9e6KaDn0pcuheiYNa+T+cqlrV8Tw3sZm 150 | # zPyxv/itSCiR3G+yo9LKDZwVFfRj/tpAJhFAodHEw9Swna2FRYlpA1TZg93QSEDe 151 | # u6HjTR9AJPHA4I4SRhsIL5LuGWVhuxT1hX2pLmKSL2mPACV3etcCAwEAAaOCAWYw 152 | # ggFiMA4GA1UdDwEB/wQEAwIBBjAfBgNVHSUEGDAWBggrBgEFBQcDAwYKKwYBBAGC 153 | # Nz0BATASBgNVHRMBAf8ECDAGAQH/AgEAMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6 154 | # Ly9jcmwuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDBmBggrBgEFBQcBAQRaMFgwJAYI 155 | # KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbTAwBggrBgEFBQcwAoYk 156 | # aHR0cDovL2FpYS5zdGFydHNzbC5jb20vY2VydHMvY2EuY3J0MB0GA1UdDgQWBBRm 157 | # ep7NnHOGammgrvqMuxiPCOzVBDAfBgNVHSMEGDAWgBROC+8apEBbpRdphzDKNGhD 158 | # 0EGu8jA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cDovL3d3 159 | # dy5zdGFydHNzbC5jb20vcG9saWN5MA0GCSqGSIb3DQEBCwUAA4ICAQALH3fwpLbm 160 | # kgX1R/F0c6VgGrehmK66gJnxuJbU+iPpymMFgggAr5TMITlT1VGYaAHA4PZTvlgR 161 | # mL3ZrhHnn+/TI03MZyt4XluVm0qju0w0R+EpeUZHycXTKK51G8Jjvfn9u1GnsgKT 162 | # QFNeep1p+f40LvQai2wLQgCJ4ScvqIUK5+2FJvS4yNOugZejNyw45duXUyWukBah 163 | # G2fQFcW6yZuvjHHh7qfAi2Dyv1w6FeJeHNP/tPhYdQK6bRKDM//EDFyXY/+xEWaB 164 | # REDDI8D2HJVvJ8p0AIZQatPNBiF7AdiPSZVBYwhXBr9n7NwOrFkqARvHmecrdQ1h 165 | # IwSMUtIuvHtRUJKin6J4dJWDnvO3llnKrhHYnpu4SgzC6Dk2KGbppnbaxP8x4rJd 166 | # jWkkiltYfYuv0oy8UjEPHZAvlqhGmnc2q5kvVc0NtXgD5IipE8xybXrI9nd5uErP 167 | # hR4eSvguRy5aNusuF//bdcB9lGhMM3V2QyLRgABXh34TwfBVSvLrnwThqC06t66n 168 | # iXyxqA/98iad8PdAHfSkyRBMMNxk0LVSETfJ/FtVJr6JvWPfQgRxek+L8s6sw/bb 169 | # 4Jr6LnCCQjaChoDFrn0CevRgDsodMJbbFPToTJk8sgOOK1D3mWOAhLL1G765DD80 170 | # ytzX/aOOXA5wfpQTTzIb/6SPXHX1nKRYyTGCAiswggInAgEBMIGJMHUxCzAJBgNV 171 | # BAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSkwJwYDVQQLEyBTdGFydENv 172 | # bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEjMCEGA1UEAxMaU3RhcnRDb20gQ2xh 173 | # c3MgMyBPYmplY3QgQ0ECEEKlLpaT/7fsTSU3is18/F8wCQYFKw4DAhoFAKB4MBgG 174 | # CisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC 175 | # AQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYE 176 | # FP8IdNLO8hTUzYNJpRoTG5P7aAtJMA0GCSqGSIb3DQEBAQUABIIBAGtwmWDP5UfK 177 | # KVx9Gz7hb8iWerlkk87ADhtIyFJs8LtBM5eSHCTmzTn3BEv5TsAIqCb692w70i1d 178 | # c812ehjpZbR6hvumMtBG+YgggqbxuaMzrppBJbMKZ/L3dWQY4LNpvEU+O+Vv0fhc 179 | # +abVe7sJXuUjGzgQYpiMkWyWUVQvh/gOJo4ytCvwfdP1D6PUPabvVsWd0Xzzh37U 180 | # 4jGaYTDg45DoO/Wa812j/+abYwqCAZuwkN0P++n+QTBBZQR47d6vFwTymiGEPiLB 181 | # hAraXkOw7e/BCmORydk3asLmHc0OVJmKqiedKpuSgy8wfScVH5nz3Y1ugSeHTuQ9 182 | # v8QIjIQpH/0= 183 | # SIG # End signature block 184 | -------------------------------------------------------------------------------- /WSUS/start-WsusServerSync.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | $WsusServer = ([system.net.dns]::GetHostByName('localhost')).hostname, 3 | [switch]$Recursive, 4 | [bool]$TrialRun = $false, 5 | [int]$SleepTime = 60, 6 | [string]$SmtpServer = "email.server.local", 7 | [string]$From = "Wsus@domain.local", 8 | [string]$To = "admin@domain.local", 9 | [string]$Subject = "WSUS Server Synchronization.", 10 | [switch]$EmailLog 11 | ) 12 | Begin 13 | { $script:CurrentErrorActionPreference = $ErrorActionPreference 14 | $script:Output = @() 15 | $script:ProcessedServers = @() 16 | $WsusAssembly = [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") 17 | If($WsusAssembly -eq $Null) 18 | { throw "Loading Microsoft.UpdateServices.Administration failed. Are you running this on a machine with the WSUS 3.0 SP2 Administration Console installed? http://technet.microsoft.com/en-us/library/dd939875(v=ws.10).aspx"} 19 | 20 | $ErrorActionPreference = "SilentlyContinue" 21 | If($EmailLog) 22 | { If($Recursive) 23 | { $Table = @{Name="Parent Wsus Server";expression={$_.ParentWsusServer}},@{Name="Wsus Server";expression={$_.WsusServer}},@{Name="Port Number";expression={$_.PortNumber}},@{Name="Using SSL";expression={$_.UsingSSL}},@{Name="Version";expression={$_.Version}},@{Name="Start";expression={$_.Start}},@{Name="Finish";expression={$_.Finish}} 24 | } 25 | Else 26 | { $Table = @{Name="Wsus Server";expression={$_.WsusServer}},@{Name="Port Number";expression={$_.PortNumber}},@{Name="Using SSL";expression={$_.UsingSSL}},@{Name="Version";expression={$_.Version}},@{Name="Start";expression={$_.Start}},@{Name="Finish";expression={$_.Finish}} 27 | } 28 | If($TrialRun -eq $False) 29 | { $Table += @{Name="Categories";expression={$_.Categories}},@{Name="Updates";expression={$_.Updates}},@{Name="Approvals";expression={$_.Approvals}},@{Name="LastSyncResult";expression={$_.LastSyncResult}} 30 | } 31 | $Style = "" 35 | Function SendEmailStatus($From, $To, $Subject, $SmtpServer, $BodyAsHtml, $Body) 36 | { $SmtpMessage = New-Object System.Net.Mail.MailMessage $From, $To, $Subject, $Body 37 | $SmtpMessage.IsBodyHTML = $BodyAsHtml 38 | $SmtpClient = New-Object System.Net.Mail.SmtpClient $SmtpServer 39 | $SmtpClient.Send($SmtpMessage) 40 | If($? -eq $False){Write-Warning "$($Error[0].Exception.Message) | $($Error[0].Exception.GetBaseException().Message)"} 41 | $SmtpMessage.Dispose() 42 | rv SmtpClient 43 | rv SmtpMessage 44 | } 45 | } 46 | 47 | function Get-HKLMValue 48 | { Param( 49 | [string]$computername=".", 50 | [string]$key = "SOFTWARE\Microsoft\Update Services\Server\Setup", 51 | [string]$value, 52 | [switch]$REG_SZ, 53 | [switch]$REG_DWORD 54 | ) 55 | $HKLM = 2147483650 56 | $reg = [wmiclass]"\\$computername\root\default:StdRegprov" 57 | If($REG_SZ) 58 | { $Result = $reg.GetStringValue($HKLM,$key,$value) 59 | If($Result.ReturnValue -eq 0){$Result.sValue} 60 | } 61 | If($REG_DWORD) 62 | { $Result = $reg.GetDwordValue($HKLM,$key,$value) 63 | If($Result.ReturnValue -eq 0){$Result.uValue} 64 | } 65 | } 66 | 67 | function Start-Pause 68 | { Param( 69 | [int]$SleepTime = 10, 70 | [int]$ID = 1, 71 | [int]$ParentID, 72 | [string]$Activity = "Just taking a quick breather after all that activity..." 73 | ) 74 | for($x = 1 ; $x -le $SleepTime; $x++) 75 | { If(!$ParentID) 76 | { Write-progress -Activity $Activity -Status "Seconds Remaining: $($SleepTime-$x)" -PercentComplete ($x/$SleepTime*100) -ID $ID} 77 | Else 78 | { Write-progress -Activity $Activity -Status "Seconds Remaining: $($SleepTime-$x)" -PercentComplete ($x/$SleepTime*100) -ID $ID -ParentId $ParentID} 79 | Sleep 1 80 | } 81 | Write-progress -Activity $Activity -Status "Done sleeping..." -Completed -ID $ID 82 | } 83 | 84 | Function Sync-WsusServer 85 | { Param( 86 | $WsusServer, 87 | $ParentWsusServer 88 | ) 89 | Write-Progress -Activity "Processing server: $WsusServer" -Status "Started at $((get-date).DateTime)" -ID 2 -ParentID 1 90 | Write-Progress -Activity "Retrieving PortNumber value from the registry via StdRegprov ..." -Status "Started at $((get-date).DateTime)" -ID 3 -ParentID 2 91 | $PortNumber = Get-HKLMValue -Computername $WsusServer -value PortNumber -REG_DWORD 92 | Write-Progress -Activity "Retrieving UsingSSL value from the registry via StdRegprov ..." -Status "Started at $((get-date).DateTime)" -ID 3 -ParentID 2 93 | $UsingSSL = If((Get-HKLMValue -Computername $WsusServer -value UsingSSL -REG_DWORD) -eq 1){$True}Else{$False} 94 | If($UsingSSL) 95 | { Write-Progress -Activity "Retrieving ServerCertificateName value from the registry via StdRegprov ..." -Status "Started at $((get-date).DateTime)" -ID 3 -ParentID 2 96 | $ServerCertificateName = Get-HKLMValue -Computername $WsusServer -value ServerCertificateName -REG_SZ 97 | If($ServerCertificateName){$WsusServer = $ServerCertificateName} 98 | } 99 | If($script:ProcessedServers -Contains $WsusServer) 100 | { Write-Warning "$WsusServer appears to have already been processed. You may have a circular loop in your hierarchy."} 101 | Else 102 | { $script:ProcessedServers += $WsusServer 103 | $Object = New-Object psobject 104 | If($Recursive) 105 | { If(!$ParentWsusServer){$ParentWsusServer = "--"} 106 | $Object | Add-Member NoteProperty ParentWsusServer $ParentWsusServer 107 | } 108 | $Object | Add-Member NoteProperty WsusServer $WsusServer -PassThru | Add-Member NoteProperty PortNumber $PortNumber -PassThru | 109 | Add-Member NoteProperty UsingSSL $UsingSSL -PassThru | Add-Member NoteProperty Version "" -PassThru | 110 | Add-Member NoteProperty Start (get-date).DateTime -PassThru | Add-Member NoteProperty Finish "" 111 | If($TrialRun -eq $False) 112 | { $Object | Add-Member NoteProperty Categories "--" -PassThru | 113 | Add-Member NoteProperty Updates "--" -PassThru | 114 | Add-Member NoteProperty Approvals "--" -PassThru | 115 | Add-Member NoteProperty LastSyncResult "" 116 | } 117 | Write-Progress -Activity "Connecting to UpdateServices AdminProxy..." -Status "Started at $((get-date).DateTime)" -ID 3 -ParentID 2 118 | $WsusServerAdminProxy = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusServer,$UsingSSL,$PortNumber) 119 | If ($? -eq $False) 120 | { $Object.Version = $Error[0] 121 | Write-Warning "Failed to connect to $WsusServer $($Error[0])" 122 | $Object.Finish = (get-date).DateTime 123 | $Object 124 | If($EmailLog){$script:Output += $Object} 125 | } 126 | Else 127 | { $Object.Version = $WsusServerAdminProxy.Version 128 | If($TrialRun -eq $False) 129 | { Write-Progress -Activity "Connecting to the Subscription..." -Status "Started at $((get-date).DateTime)" -ID 3 -ParentID 2 130 | $Subscription = $WsusServerAdminProxy.GetSubscription(); 131 | Write-Progress -Activity "Calling StartSynchronization on $WsusServer" -Status "Started at $((get-date).DateTime)" -ID 3 -ParentID 2 132 | $Subscription.StartSynchronization() 133 | $SynchronizationProgress = $Subscription.GetSynchronizationProgress() 134 | While ($SynchronizationProgress.Phase.ToString() -eq "NotProcessing") 135 | { Start-Sleep -Milliseconds 100 136 | $SynchronizationProgress = $Subscription.GetSynchronizationProgress() 137 | } 138 | While ($SynchronizationProgress.Phase.ToString() -ne "NotProcessing") 139 | { If($SynchronizationProgress.Phase.ToString() -eq "Categories") 140 | {$Object.Categories = $SynchronizationProgress.TotalItems} 141 | If($SynchronizationProgress.Phase.ToString() -eq "Updates") 142 | { $Object.Updates = $SynchronizationProgress.TotalItems} 143 | If($SynchronizationProgress.Phase.ToString() -eq "Approvals") 144 | {$Object.Approvals = $SynchronizationProgress.TotalItems} 145 | Write-Progress -Activity "Synchronization Phase: $($SynchronizationProgress.Phase.ToString())" -Status "$($SynchronizationProgress.ProcessedItems) of $($SynchronizationProgress.TotalItems) items done..." -PercentComplete ($SynchronizationProgress.ProcessedItems*100/($SynchronizationProgress.TotalItems)) -ID 4 -ParentId 3 146 | $SynchronizationProgress = $Subscription.GetSynchronizationProgress() 147 | } 148 | $Object.LastSyncResult = $Subscription.GetLastSynchronizationInfo().Result 149 | Write-Progress -Activity "Synchronization Phase: $($SynchronizationProgress.Phase.ToString())" -Status "Complete." -ID 4 -ParentId 3 -Completed 150 | } 151 | $Object.Finish = (get-date).DateTime 152 | $Object 153 | If($EmailLog){$script:Output += $Object} 154 | If($Recursive -And $TrialRun -eq $False){Start-Pause -Activity "Processed $($script:ProcessedServers.Count) server(s). The script is pausing for $SleepTime seconds starting at $((get-date).DateTime)." -SleepTime $SleepTime -ID 3 -ParentID 2} 155 | If($Recursive) 156 | { Write-Progress -Activity "Retrieving Downstream Servers on $WsusServer..." -Status "Started at $((get-date).DateTime)" -ID 3 -ParentID 2 157 | $WsusDownstreamServers = $WsusServerAdminProxy.GetDownstreamServers() 158 | If($WsusDownstreamServers){$WsusDownstreamServers | %{Sync-WsusServer -WsusServer $_.FullDomainName -ParentWsusServer $WsusServer}} 159 | } 160 | } 161 | } 162 | } 163 | Write-Progress -Activity "WSUS Server Synchronization." -Status "Started at $((get-date).DateTime)" -ID 1 164 | } 165 | Process 166 | { If($WsusServer) 167 | { ForEach($Server in $WsusServer){Sync-WsusServer $Server} 168 | } 169 | Else 170 | { Sync-WsusServer $_ 171 | } 172 | } 173 | End 174 | { If($EmailLog){SendEmailStatus -From $From -To $To -Subject $Subject -SmtpServer $SmtpServer -BodyAsHtml $True -Body ($Output | Select $Table | ConvertTo-HTML -head $Style)} 175 | $ErrorActionPreference = $script:CurrentErrorActionPreference 176 | } -------------------------------------------------------------------------------- /Intune/get-AutopilotLogs.ps1: -------------------------------------------------------------------------------- 1 | #Requires -RunAsAdministrator 2 | <# 3 | .SYNOPSIS 4 | Gather Informations & Logs for Autopilot Pre-Provisioning process. 5 | 6 | .DESCRIPTION 7 | Gather Informations & Logs for Autopilot Pre-Provisioning process. It creates a folder in the locaion where it was started from, usually a USB Thumdrive. 8 | 9 | .EXAMPLE 10 | C:\PS> get-AutopilotLogs.ps1 11 | 12 | .NOTES 13 | Author : Fabian Niesen (www.fabian-niesen.de) 14 | Filename : get-AutopilotLogs.ps1 15 | Requires : PowerShell Version 4.0 16 | Version : 1.0.2 17 | History : 1.0.2 FN 26.08.2022 Add ToDo list, changed LogName 18 | 1.0.1 FN 25.08.2022 Buxfixes 19 | 1.0.0 FN 21.08.2022 initial version 20 | 21 | .ToDo 22 | - Integrate Networkchecks 23 | - Integrate TPM check 24 | - Gather MDM Policies from Registry 25 | 26 | .LINK 27 | https://github.com/InfrastructureHeroes/Scipts/ 28 | 29 | .COPYRIGHT 30 | Copyright (c) Fabian Niesen if not stated otherwise. All rights reserved. Licensed under the MIT license. 31 | 32 | #> 33 | $ErrorActionPreference = "SilentlyContinue" 34 | $script:BuildVer = "1.0.2" 35 | $script:ProgramFiles = $env:ProgramFiles 36 | $script:ParentFolder = $PSScriptRoot | Split-Path -Parent 37 | $script:ScriptName = $myInvocation.MyCommand.Name 38 | $script:ScriptName = $scriptName.Substring(0, $scriptName.Length - 4) 39 | $serial = $(Get-WmiObject Win32_bios).Serialnumber 40 | $Device = Get-CimInstance -ClassName Win32_ComputerSystem 41 | $LogName = (Get-Date -UFormat "%Y%m%d-%H%M")+ "_" + $serial 42 | $Logpath = $PSScriptRoot + "\" + $LogName 43 | $LogFile = $Logpath +"\" + $script:ScriptName + ".log" 44 | $ntpserver = "ptbtime1.ptb.de,ptbtime2.ptb.de,time.windows.com,time.nist.gov" 45 | #################################################### 46 | #region Logfiles 47 | <# 48 | .COPYRIGHT for this region 49 | Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. 50 | See LICENSE in the project https://github.com/gregnottage/IntuneScripts for license information. 51 | 52 | .Notes 53 | Removed EventLog Handling and smaller changes by Fabian Niesen 54 | #> 55 | Function Start-Log { 56 | param ( 57 | [string]$FilePath, 58 | 59 | [Parameter(HelpMessage = 'Deletes existing file if used with the -DeleteExistingFile switch')] 60 | [switch]$DeleteExistingFile 61 | ) 62 | 63 | Try { 64 | If (!(Test-Path $FilePath)) { 65 | ## Create the log file 66 | New-Item $FilePath -Type File -Force | Out-Null 67 | } 68 | 69 | If ($DeleteExistingFile) { 70 | Remove-Item $FilePath -Force 71 | } 72 | 73 | ## Set the global variable to be used as the FilePath for all subsequent Write-Log 74 | ## calls in this session 75 | $script:ScriptLogFilePath = $FilePath 76 | } 77 | Catch { 78 | Write-Error $_.Exception.Message 79 | } 80 | } 81 | 82 | #################################################### 83 | 84 | Function Write-Log { 85 | #Write-Log -Message 'warning' -LogLevel 2 86 | #Write-Log -Message 'Error' -LogLevel 3 87 | param ( 88 | [Parameter(Mandatory = $true)] 89 | [string]$Message, 90 | 91 | [Parameter()] 92 | [ValidateSet(1, 2, 3)] 93 | [int]$LogLevel = 1, 94 | 95 | [Parameter(HelpMessage = 'Outputs message to Event Log,when used with -WriteEventLog')] 96 | [switch]$WriteEventLog 97 | ) 98 | Write-Host $Message 99 | $TimeGenerated = "$(Get-Date -Format HH:mm:ss).$((Get-Date).Millisecond)+000" 100 | $Line = '' 101 | $LineFormat = $Message, $TimeGenerated, (Get-Date -Format MM-dd-yyyy), "$($MyInvocation.ScriptName | Split-Path -Leaf):$($MyInvocation.ScriptLineNumber)", $LogLevel 102 | $Line = $Line -f $LineFormat 103 | Add-Content -Value $Line -Path $ScriptLogFilePath 104 | } 105 | #endregion Logfiles 106 | #################################################### 107 | 108 | ### Check for Admin rights 109 | if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 110 | { 111 | $arguments = "& '" +$myinvocation.mycommand.definition + "'" 112 | Start-Process powershell -Verb runAs -ArgumentList $arguments 113 | Break 114 | } 115 | ### 116 | If (-not (Test-Path $Logpath)) 117 | { 118 | New-Item -Path $Logpath -ItemType Directory -Force | Out-Null 119 | } 120 | Start-Log -FilePath $LogFile -DeleteExistingFile 121 | Write-Log -Message "All files will be stored here: $Logpath" 122 | Write-Log -Message "Start get-AutopilotLogs Version $script:BuildVer" 123 | Write-Log -Message "Device Serial : $serial" 124 | Write-Log -Message "Devicename : $($Device.Name)" 125 | Write-Log -Message "Device Manufacturer : $($Device.Manufacturer)" 126 | Write-Log -Message "Device Model : $($Device.Model)" 127 | Write-Log -Message "Device ChassisSKUNumber: $($Device.ChassisSKUNumber)" 128 | Write-Log -Message "Device PowerSupplyState: $($Device.PowerSupplyState)" 129 | 130 | If (Test-Path "C:\Windows\system32\w32tm.exe" ) { $w32tm = "C:\Windows\system32\w32tm.exe"} Else { $w32tm = "w32tm.exe" } 131 | Start-Process -FilePath $w32tm -ArgumentList " /monitor /computers:$ntpserver " -NoNewWindow -Wait -RedirectStandardOutput $($Logpath+"\ntp-raw.txt") 132 | $TimeDiff = Get-Content $($Logpath+"\ntp-raw.txt") | ForEach-Object { $_.trim() } | Where-Object { $_ -ne ""} 133 | $TimeDiff = $TimeDiff.Where({ $_ -like "*$($ntpserver.split(",")[0])*"},'SkipUntil') | Select-Object -First 20 134 | $TimeTab = @( 135 | [PSCustomObject]@{Server = $($TimeDiff[0].split("[")[0]); Offset = $($TimeDiff[2].Split(":")[1].trim().split(" ")[0]); RefID = $($TimeDiff[3].Split(" ")[1]+$TimeDiff[3].Split(" ")[2]) ; Stratum = $($TimeDiff[4].Split(" ")[1])} 136 | [PSCustomObject]@{Server = $($TimeDiff[5].split("[")[0]); Offset = $($TimeDiff[7].Split(":")[1].trim().split(" ")[0]); RefID = $($TimeDiff[8].Split(" ")[1]+$TimeDiff[8].Split(" ")[2]) ; Stratum = $($TimeDiff[9].Split(" ")[1])} 137 | [PSCustomObject]@{Server = $($TimeDiff[10].split("[")[0]); Offset = $($TimeDiff[12].Split(":")[1].trim().split(" ")[0]); RefID = $($TimeDiff[13].Split(" ")[1]+$TimeDiff[13].Split(" ")[2]) ; Stratum = $($TimeDiff[14].Split(" ")[1])} 138 | [PSCustomObject]@{Server = $($TimeDiff[15].split("[")[0]); Offset = $($TimeDiff[17].Split(":")[1].trim().split(" ")[0]); RefID = $($TimeDiff[18].Split(" ")[1]+$TimeDiff[18].Split(" ")[2]) ; Stratum = $($TimeDiff[19].Split(" ")[1])} 139 | ) 140 | $TimeData = $($TimeTab | ConvertTo-Csv -NoTypeInformation ) 141 | $TimeTab | export-csv -Path $($Logpath+"\ntp.txt") -force -NoTypeInformation 142 | Write-Log -Message "Time informations `n$TimeData" 143 | 144 | 145 | # Copy PowerShell Framework for Intune 146 | Write-Log -Message "Checking for Logfiles from PowerShell Framework for Intune based upon https://github.com/gregnottage/IntuneScripts" 147 | IF (Test-Path -Path "$($env:LOCALAPPDATA)\Microsoft\IntuneApps") 148 | { 149 | Write-Log -Message "Found Logs in $($env:LOCALAPPDATA)\Microsoft\IntuneApps" 150 | Copy-Item -Path "$($env:LOCALAPPDATA)\Microsoft\IntuneApps" -Destination $Logpath -Recurse -Force 151 | } 152 | IF (Test-Path -Path "$($env:ProgramData)\Microsoft\IntuneApps") 153 | { 154 | Write-Log -Message "Found Logs in $($env:ProgramData)\Microsoft\IntuneApps" 155 | Copy-Item -Path "$($env:ProgramData)\Microsoft\IntuneApps" -Destination $Logpath -Recurse -Force 156 | } 157 | 158 | # Copy AppDeploymentToolkit Logs 159 | Write-Log -Message "Checking for Logfiles from PSAppDeploymentToolkit" 160 | IF (Test-Path -Path "$env:WINDIR\Logs\Software") 161 | { 162 | Write-Log -Message "Found Logs in $envWinDir\Logs\Software" 163 | Copy-Item -Path "$env:WINDIR\Logs\Software" -Destination $Logpath -Recurse -Force 164 | } 165 | 166 | # MDMDiagnostics 167 | [string]$DiagArea = $(Get-ChildItem HKLM:\SOFTWARE\Microsoft\MdmDiagnostics\Area).PSChildName 168 | $DiagArea = $DiagArea.replace(' ',';') 169 | Write-Log -Message "Start MDMDiagnostics - $DiagArea" 170 | Start-Process -FilePath "C:\windows\system32\MdmDiagnosticsTool.exe" -ArgumentList "-area $DiagArea -cab $logpath\$LogName.cab" -NoNewWindow -Wait -PassThru 171 | 172 | # Gater additional Informations 173 | Write-Log -Message "Get installed Software" 174 | get-wmiobject Win32_Product | Sort-Object -Property Name, IdentifyingNumber | Export-Csv -Path $($Logpath+"\Win32_Product.csv") -force -NoTypeInformation 175 | Write-log -Message "Get-DeliveryOptimizationStatus" 176 | Get-DeliveryOptimizationStatus | Export-Csv -Path $($Logpath+"\DO-Status.csv") -force -NoTypeInformation 177 | 178 | Write-Log -Message "Export System Eventlog" 179 | $evtldate = [math]::Round((New-TimeSpan -Start $($(Get-Date).AddDays(-10)) -End (Get-Date)).TotalMilliseconds ) 180 | #Start-Process -FilePath wevtutil -ArgumentList " epl Application test.evtx /q:$("*[System[TimeCreated[timediff(@SystemTime) <= $evtldate]]]")" -NoNewWindow -Wait -PassThru 181 | wevtutil epl System $logpath\system.evtx /q:$("*[System[TimeCreated[timediff(@SystemTime) <= $evtldate]]]") 182 | Write-Log -Message "Export Application Eventlog" 183 | wevtutil epl Application $logpath\Application.evtx /q:$("*[System[TimeCreated[timediff(@SystemTime) <= $evtldate]]]") 184 | Write-Log -Message "Export Service list" 185 | Get-WmiObject -Class Win32_Service | Export-csv -Path $($Logpath+"\Services.csv") -force -NoTypeInformation 186 | Write-Log -Message "Get installed Software Uninstall information" 187 | Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Sort-Object InstallDate | Export-csv -Path $($Logpath+"\Uninstall.csv") -force -NoTypeInformation 188 | Write-Log -Message "Get Driver versions" 189 | Get-WmiObject Win32_PnPSignedDriver| Select-Object devicename, driverversion, driverdate | Sort-Object devicename | Export-csv -Path $($Logpath+"\Driver.csv") -force -NoTypeInformation 190 | Write-Log -Message "Get installe AppX Packages" 191 | Get-AppxPackage -AllUsers | Export-csv -Path $($Logpath+"\AppX.csv") -force -NoTypeInformation 192 | Write-Log -Message "Get Packages" 193 | Get-Package | Sort-Object ProviderName | Export-csv -Path $($Logpath+"\Packages.csv") -force -NoTypeInformation 194 | Write-Log -Message "Get Windows Packages" 195 | Get-WindowsPackage -Online | Export-csv -Path $($Logpath+"\WinPackages.csv") -force -NoTypeInformation 196 | Write-Log -Message "Get Provisioning Packages" 197 | Get-ProvisioningPackage -AllInstalledPackages | Export-csv -Path $($Logpath+"\ProvisioningPackage.csv") -force -NoTypeInformation 198 | Write-Log -Message "get-AutopilotLogs is completed" -------------------------------------------------------------------------------- /Exchange/Set-MaintananceMode.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Setting Exchange 2013 DAG to Maintenence mode 4 | .DESCRIPTION 5 | Setting Exchange 2013 DAG to Maintenence mode 6 | .EXAMPLE 7 | 8 | .INPUTS 9 | Mode: start | stop 10 | Source: (Optional, otherwise will autodetect) 11 | Target: (Optional, otherwise will autodetect) 12 | DAG: (Optional, otherwise will autodetect) 13 | TARGETSITE: (Optional, otherwise will autodetect) 14 | .OUTPUTS 15 | Keine. 16 | .NOTES 17 | Author : Fabian Niesen 18 | Filename : set-MaintananceMode.ps1 19 | Requires : PowerShell Version 3.0 20 | 21 | Version : 0.2 22 | History : 23 | .LINK 24 | 25 | #> 26 | <# Known issues / Fix List 27 | Auto redistibution for active databases did not work at this version 28 | Autodetection for MODE ist not implemented 29 | 30 | #> 31 | [cmdletbinding()] 32 | Param( 33 | [Parameter(Mandatory=$false, ValueFromPipeline=$False)] 34 | [ValidateNotNullOrEmpty()] 35 | [ValidateSet("start","stop")] 36 | [String]$Mode=$null, 37 | 38 | [Parameter(Mandatory=$false, ValueFromPipeline=$False)] 39 | [String]$Source=$env:COMPUTERNAME, 40 | 41 | [Parameter(Mandatory=$false, ValueFromPipeline=$False)] 42 | [String]$target=$null, 43 | 44 | [Parameter(Mandatory=$false, ValueFromPipeline=$False)] 45 | [String]$targetsite=$null, 46 | 47 | [Parameter(Mandatory=$false, ValueFromPipeline=$False)] 48 | [String]$dag=$null 49 | ) 50 | 51 | function checkqueue() 52 | { 53 | $MessageCount = Get-Queue -Server $Source | ?{($_.Identity -notlike "*\Poison") -and ($_.Identity -notlike "*\Shadow\*")} | Select MessageCount 54 | $i = 0 55 | foreach ( $count in $MessageCount) 56 | { 57 | $i +=$count.MessageCount 58 | } 59 | IF ($i -ne 0 ) 60 | { 61 | Write-Output "Still $i messages in the queque, please wait. Recheck in 30 seconds." 62 | Start-Sleep -Seconds 30 63 | checkqueue 64 | } 65 | ELSE 66 | { 67 | Write-Output "All queues empty" 68 | } 69 | } 70 | 71 | Function Load-ExchangeModule { 72 | Write-Verbose 'Loading Exchange PowerShell module' 73 | If( -not ( Get-Command Connect-ExchangeServer -ErrorAction SilentlyContinue)) { 74 | $SetupPath= (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\ExchangeServer\v15\Setup -Name MsiInstallPath -ErrorAction SilentlyContinue).MsiInstallPath 75 | If( $SetupPath -and (Test-Path "$SetupPath\bin\RemoteExchange.ps1" )) { 76 | . "$SetupPath\bin\RemoteExchange.ps1" | Out-Null 77 | Try { 78 | Connect-ExchangeServer $($env:COMPUTERNAME+"."+$env:USERDNSDOMAIN) 79 | } 80 | Catch { 81 | Write-Warning 'Problem loading Exchange module' 82 | } 83 | } 84 | Else { 85 | Write-Warning "Can't determine installation path to load Exchange module" 86 | } 87 | } 88 | Else { 89 | Write-Warning 'Exchange module already loaded' 90 | } 91 | } 92 | 93 | ### Proof for administrative permissions (UAC) 94 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) 95 | { 96 |     Write-Error "This script needs to be run as administrator!!!"    97 | break 98 | } 99 | 100 | ### insert Exchange connection! 101 | #Try { Import-Module ActiveDirectory -ErrorAction Stop } Catch { Write-Warning "ActiveDirectory Powershell Module not found!" } 102 | Load-ExchangeModule 103 | 104 | Set-ADServerSettings -ViewEntireForest $true 105 | Write-Verbose "Analyzing $Source" 106 | IF ($dag -like $null) { $dag = $(Get-DatabaseAvailabilityGroup).Name } ELSE { Write-Verbose "DAG preseted with $dag" } 107 | Write-Verbose "DAG >$dag< is selected" 108 | $DagMember = $(Get-DatabaseAvailabilityGroup $dag -status).Servers.Name 109 | $exchangeServers = $DagMember | Get-ExchangeServer | Select Identity,Fqdn,IsClientAccessServer,IsMailboxServer,IsHubTransportServer,IsFrontendTransportServer,ServerRole,Site,AdminDisplayVersion 110 | Write-Verbose "Found the following Exchnage Servers within the DAG: $($exchangeServers.Identity)" 111 | $exchangeServerSource = Get-ExchangeServer -Identity $Source | Select Identity,Fqdn,IsClientAccessServer,IsMailboxServer,IsHubTransportServer,IsFrontendTransportServer,ServerRole,Site,AdminDisplayVersion 112 | Write-Verbose "Source Server is $($exchangeServerSource.Fqdn)" 113 | IF ($targetsite -ne $null) { $site = $targetsite } ELSE {$site = $exchangeServerSource.Site.Name} 114 | $PAM = $(Get-DatabaseAvailabilityGroup $dag -status ).PrimaryActiveManager.Name 115 | Write-Verbose "Found PAM: $PAM" 116 | 117 | ### Insert AutoDetection for Maintenance 118 | 119 | IF ($Mode -eq "start") 120 | { 121 | ### Find proper target 122 | IF ($target -like $null) 123 | { 124 | Write-Verbose "No Target provided, starting autodiscovery" 125 | 126 | [array]$alt = $exchangeServers | ? {($_.Site.Name -match $Site) -and ($_.IsMailboxServer -match $true) -and ($_.Identity -notmatch $Source) } 127 | IF ( $alt.count -ge 1) 128 | { 129 | Write-Output "Found $($alt.count) Exchange Mailbox server within the same site" 130 | $target = $alt[0].Fqdn 131 | Write-Output "Choose $target as target" 132 | } 133 | Else 134 | { 135 | Write-Warning "No other Mailbox Server found within the same site! Choose from a other site!" 136 | Write-Warning "To avoid, cancel within 10 seconds and Please specify Target or Targetsite" 137 | Start-Sleep -Seconds 10 138 | [array]$alt = $exchangeServers | ? {($_.IsMailboxServer -match $true) -and ($_.Identity -notmatch $Source) } 139 | Write-Output "Found $($alt.count) Exchange Mailbox server within other sites" 140 | $target = $alt[0].Fqdn 141 | Write-Output "Choose $target as target" 142 | } 143 | } 144 | 145 | ### Disable HubTransport 146 | Write-Verbose "Disable HubTransport" 147 | Set-ServerComponentState $Source -Component HubTransport -State Draining -Requester Maintenance 148 | Write-Verbose "Redirecting Messages" 149 | Redirect-Message -Server $Source -Target $target -Confirm:$false 150 | 151 | ### Check and move PAM 152 | IF ( $PAM -match $Source) 153 | { 154 | Write-Output "PAM is running on the Source server, move it to: $target" 155 | Move-ClusterGroup -Cluster $dag -name "Cluster group" -node:$target 156 | Start-Sleep -Seconds 10 157 | $PAM = $(Get-DatabaseAvailabilityGroup $dag -status ).PrimaryActiveManager.Name 158 | IF ( $PAM -match $Source) 159 | { 160 | Write-Warning "PAM still on the Source Server please check" 161 | break 162 | } 163 | ELSE 164 | { 165 | Write-Output "Successfully moved the PAM to $PAM" 166 | } 167 | } 168 | Invoke-Command -ComputerName $Source -ArgumentList $Source {Suspend-ClusterNode $args[0]} 169 | ### Check and move active Databases 170 | Write-Verbose "Check and move active Databases" 171 | Try { Get-MailboxDatabaseCopyStatus -Server $Source -Active -ErrorAction stop } Catch { $ADB = "No Active" } 172 | IF ($ADB -like "No Active") 173 | { 174 | Write-Output "No active Database found" 175 | } 176 | ELSE 177 | { 178 | [array]$ADBs = Get-MailboxDatabaseCopyStatus -Server $Source -Active | Select DatabaseName,Status,ActiveDatabaseCopy 179 | IF ($ADBs.Count -ge 1) 180 | { 181 | Foreach ($ADB in $ADBs) 182 | { 183 | Write-Verbose "Move Database $ADB to $target" 184 | Move-ActiveMailboxDatabase $ADB -ActivateOnServer $target 185 | } 186 | } 187 | } 188 | Set-MailboxServer $Source -DatabaseCopyActivationDisabledAndMoveNow $true 189 | Set-MailboxServer $Source -DatabaseCopyAutoActivationPolicy Blocked 190 | Write-Verbose "Checking queues" 191 | checkqueue 192 | Set-ServerComponentState $Source -Component ServerWideOffline -State Inactive -Requester Maintenance 193 | IF (Invoke-Command -ComputerName $Source {Restart-Service MSExchangeTransport | Out-Null}) 194 | { 195 | Write-Verbose "Successfully restarted MSExchangeTransport service" 196 | } 197 | ELSE 198 | { 199 | Write-Warning "Restart of MSExchangeTransport service failed" 200 | } 201 | IF ($Source.IsClientAccessServer -match $true ) 202 | { 203 | Write-Verbose "CAS detected" 204 | IF (Invoke-Command -ComputerName $Source {Restart-Service MSExchangeFrontEndTransport | Out-Null}) 205 | { 206 | Write-Verbose "Successfully restarted MSExchangeFrontEndTransport service" 207 | } 208 | ELSE 209 | { 210 | Write-Warning "Restart of MSExchangeFrontEndTransport service failed" 211 | } 212 | } 213 | Write-Output "Server $source is now in maintenance mode, please proceed" 214 | 215 | } 216 | ELSEIF ($Mode -eq "stop") 217 | { 218 | Set-ServerComponentState $Source -Component ServerWideOffline -State Active -Requester Maintenance 219 | Invoke-Command -ComputerName $Source -ArgumentList $Source {Resume-ClusterNode $args[0]} 220 | Set-MailboxServer $Source -DatabaseCopyActivationDisabledAndMoveNow $false 221 | Set-MailboxServer $Source -DatabaseCopyAutoActivationPolicy Unrestricted 222 | Set-ServerComponentState $Source -Component HubTransport -State Active -Requester Maintenance 223 | IF (Invoke-Command -ComputerName $Source {Restart-Service MSExchangeTransport | Out-Null}) 224 | { 225 | Write-Verbose "Successfully restarted MSExchangeTransport service" 226 | } 227 | ELSE 228 | { 229 | Write-Warning "Restart of MSExchangeTransport service failed" 230 | } 231 | IF ($Source.IsClientAccessServer -match $true ) 232 | { 233 | Write-Verbose "CAS detected" 234 | IF (Invoke-Command -ComputerName $Source {Restart-Service MSExchangeFrontEndTransport | Out-Null}) 235 | { 236 | Write-Verbose "Successfully restarted MSExchangeFrontEndTransport service" 237 | } 238 | ELSE 239 | { 240 | Write-Warning "Restart of MSExchangeFrontEndTransport service failed" 241 | } 242 | } 243 | Start-Sleep -Seconds 30 244 | Get-HealthReport $Source | ? { $_:alertvalue -ne "healthy"} 245 | Get-ServerComponentState $Source | ft Component,State -AutoSize 246 | ### Find Databases for Activation and move them 247 | <# Benötigt credentials um als Admin zu laufen 248 | Write-Verbose "Starting relocating active Mailbox database copies" 249 | Invoke-Command -ComputerName $Source -Authentication Credssp -Credential $cred -ScriptBlock { c: ; cd "\Program Files\Microsoft\Exchange Server\V15\Scripts" ; .\RedistributeActiveDatabases.ps1 -BalanceDbsByActivationPreference -DAG $args[0] -LogEvents } -ArgumentList "$dag" 250 | #> 251 | } 252 | ELSE 253 | { 254 | Write-Warning "No Mode selected" 255 | } -------------------------------------------------------------------------------- /ActiveDirectory/get-adinfo.ps1: -------------------------------------------------------------------------------- 1 | ##requires -version 2.0 2 | ##requires -modules activedirectory 3 | 4 | <# 5 | .SYNOPSIS 6 | Get basic information upon the Active Directory Forrest 7 | .DESCRIPTION 8 | Get basic information upon the Active Directory Forrest, like the cration date of the domains, a list off all DC and a Report the Schema versions (AD, Exchange, Lync and SCCM). 9 | Based upon an TechNet article from "The Scripting guys". Thanks also to Shawn Johnson, Paul Wetter, SteveLarson for providing SCCM extension and more schema versions. 10 | http://blogs.technet.com/b/heyscriptingguy/archive/2012/01/05/how-to-find-active-directory-schema-update-history-by-using-powershell.aspx 11 | Require the ActiveDirectory PowerShell Module, no admin permisions needed. 12 | .EXAMPLE 13 | get-adinfo 14 | .INPUTS 15 | Keine. 16 | .OUTPUTS 17 | Keine. 18 | .NOTES 19 | Author : Fabian Niesen 20 | Filename : get-adinfo.ps1 21 | Requires : PowerShell Version 2.0 22 | 23 | Version : 0.5 24 | History : 0.5 FN 19.02.2021 25 | 0.4 FN 15.07.2020 Update Schemas, integrate LAPS detection 26 | 0.3 FN 21.07.2016 Add Windows Server 2016, Exchange multiple CU and 2016, some SystemCenter and Sign Script 27 | 0.2 FN 10.03.2015 Add SCCM R2 CU1-4 and SCCM CU5 28 | 0.1 FN 18.02.2015 initial version 29 | 30 | .LINK 31 | https://gallery.technet.microsoft.com/Gesamtstruktur-Informations-63719eec 32 | #> 33 | 34 | [cmdletbinding()] 35 | Param( 36 | $logfile="C:\Temp\log.txt" 37 | ) 38 | 39 | <# 40 | Param( 41 | [Parameter(Mandatory=$false, ValueFromPipeline=$True)] 42 | [switch]$Verbose = $false 43 | ) 44 | 45 | $oldverbose = $VerbosePreference 46 | IF ($Verbose -eq $True) 47 | { 48 | $VerbosePreference = "Continue" 49 | } 50 | #> 51 | "Get-ADInfo.ps1 by Fabian Niesen" | Out-file -FilePath $logfile | Write-Output 52 | get-date -format yyyyMMdd-HHmm | Tee-Object -FilePath $logfile -Append | Write-Output 53 | 54 | 55 | $ErrorActionPreference = "SilentlyContinue" 56 | $before = Get-Date 57 | Try 58 | { 59 | Import-Module ActiveDirectory 60 | } 61 | catch 62 | { 63 | Write-Warning "PowerShell module for Active Directory not found!" 64 | break 65 | } 66 | 67 | # Forrest creation 68 | "Creation date of the domains" | Tee-Object -FilePath $logfile -Append | Write-Output 69 | "============================" | Tee-Object -FilePath $logfile -Append | Write-Output 70 | $Doms = Get-ADObject -SearchBase (Get-ADForest).PartitionsContainer -LDAPFilter "(&(objectClass=crossRef)(systemFlags=3))" -Property dnsRoot, nETBIOSName, whenCreated |Sort-Object whenCreated 71 | $Doms | Format-Table dnsRoot, NETBIOSName, whenCreated -AutoSize 72 | 73 | # Fuctional Levels 74 | "Funtional Level and FSMO roles" | Tee-Object -FilePath $logfile -Append | Write-Output 75 | "==============================" | Tee-Object -FilePath $logfile -Append | Write-Output 76 | Get-ADForest | fl Name,ForestMode,SchemaMaster,DomainNamingMaster 77 | $Doms.Netbiosname | Get-ADDomain | FL Name,NetBiosName,DNSRoot,DomainMode,PDCEmulator,RIDMaster,InfrastructureMaster 78 | 79 | # List DCs 80 | "List of all domain controllers" | Tee-Object -FilePath $logfile -Append | Write-Output 81 | "==============================" | Tee-Object -FilePath $logfile -Append | Write-Output 82 | try 83 | { 84 | $Forest = [system.directoryservices.activedirectory.Forest]::GetCurrentForest() 85 | } 86 | catch 87 | { 88 | "Cannot connect to current forest." 89 | } 90 | $Forest.domains | ForEach-Object {$_.DomainControllers} | FT Name,OSVersion,SiteName -AutoSize -GroupBy Domain 91 | 92 | # User Objects normal & Password age180+ 93 | 94 | 95 | 96 | # Computer Objects normal & Password age180+ 97 | 98 | 99 | 100 | # SchemaVersionen 101 | 102 | $SchemaVersions = @() 103 | 104 | $SchemaHashAD = @{ 105 | 13="Windows 2000 Server"; 106 | 30="Windows Server 2003"; 107 | 31="Windows Server 2003 R2"; 108 | 44="Windows Server 2008"; 109 | 47="Windows Server 2008 R2"; 110 | 51="!!! Windows Server 8 Developer Preview !!!"; 111 | 52="!!! Windows Server 8 BETA !!!"; 112 | 56="Windows Server 2012"; 113 | 69="Windows Server 2012 R2"; 114 | 72="!!! Windows Server vNext Technical Preview (Build 9841) !!!"; 115 | 87="Windows Server 2016"; 116 | 88="Windows Server 2019"; 117 | } 118 | 119 | Write-Verbose "Starting AD Schema" 120 | $SchemaPartition = (Get-ADRootDSE).NamingContexts | Where-Object {$_ -like "*Schema*"} 121 | $SchemaVersionAD = (Get-ADObject $SchemaPartition -Property objectVersion).objectVersion 122 | write-verbose "SchemaVersionAD: $SchemaVersionAD" 123 | $SchemaVersions += 1 | Select-Object @{name="Product";expression={"AD"}}, @{name="Schema";expression={$SchemaVersionAD}}, @{name="Version";expression={$SchemaHashAD.Item($SchemaVersionAD)}} 124 | 125 | #------------------------------------------------------------------------------ 126 | 127 | $SchemaHashExchange = @{ 128 | 0="No Exchange Schema extension installed"; 129 | 4397="Exchange Server 2000 RTM"; 130 | 4406="Exchange Server 2000 SP3"; 131 | 6870="Exchange Server 2003 RTM or SP2"; 132 | 6936="Exchange Server 2003 SP3"; 133 | 10628="Exchange Server 2007 RTM"; 134 | 10637="Exchange Server 2007 RTM"; 135 | 11116="Exchange 2007 SP1"; 136 | 14622="Exchange 2007 SP2 or Exchange 2010 RTM"; 137 | 14625="Exchange 2007 SP3"; 138 | 14726="Exchange 2010 SP1"; 139 | 14732="Exchange 2010 SP2"; 140 | 14734="Exchange 2010 SP3"; 141 | 15137="Exchange 2013 RTM"; 142 | 15254="Exchange 2013 CU1"; 143 | 15281="Exchange 2013 CU2"; 144 | 15283="Exchange 2013 CU3"; 145 | 15292="Exchange 2013 SP1/CU4"; 146 | 15300="Exchange 2013 CU5"; 147 | 15303="Exchange 2013 CU6"; 148 | 15312="Exchange 2013 CU7 - CU23"; 149 | 15317="Exchange 2016 RTM / Preview"; 150 | 15323="Exchange 2016 CU1"; 151 | 15325="Exchange 2016 CU2"; 152 | 15326="Exchange 2016 CU3 - CU5"; 153 | 15330="Exchange 2016 CU6"; 154 | 15332="Exchange 2016 CU7 - CU18 or Exchange 2019 Preview"; 155 | 15333="Exchange 2016 CU19"; 156 | 17000="Exchange 2019 RTM/CU1"; 157 | 17001="Exchange 2019 CU2-CU7"; 158 | 17002="Exchange 2019 CU8"; 159 | } 160 | 161 | Write-Verbose "Starting Exchange Schema" 162 | $SchemaPathExchange = "CN=ms-Exch-Schema-Version-Pt,$SchemaPartition" 163 | If (Test-Path "AD:$SchemaPathExchange") { 164 | Write-Verbose "Exchange Schema found" 165 | $SchemaVersionExchange = (Get-ADObject $SchemaPathExchange -Property rangeUpper).rangeUpper 166 | Write-Verbose "SchemaVersionExchange: $SchemaVersionExchange" 167 | } Else { 168 | $SchemaVersionExchange = 0 169 | } 170 | 171 | $SchemaVersions += 1 | Select-Object @{name="Product";expression={"Exchange"}}, @{name="Schema";expression={$SchemaVersionExchange}}, @{name="Version";expression={$SchemaHashExchange.Item($SchemaVersionExchange)}} 172 | 173 | #------------------------------------------------------------------------------ 174 | 175 | $SchemaHashLync = @{ 176 | 0="No Lync / OCS / S4B Schema extension installed"; 177 | 1006="LCS 2005"; 178 | 1007="OCS 2007 R1"; 179 | 1008="OCS 2007 R2"; 180 | 1100="Lync Server 2010"; 181 | 1150="Lync Server 2013 / Skype 4 Business 2015" 182 | } 183 | 184 | Write-Verbose "Starting Lync / Skype4Business Schema" 185 | $SchemaPathLync = "CN=ms-RTC-SIP-SchemaVersion,$SchemaPartition" 186 | If (Test-Path "AD:$SchemaPathLync") { 187 | Write-Verbose "Lync found" 188 | $SchemaVersionLync = (Get-ADObject $SchemaPathLync -Property rangeUpper).rangeUpper 189 | Write-Verbose "SchemaVersionLync: $SchemaVersionLync" 190 | } Else { 191 | $SchemaVersionLync = 0 192 | } 193 | 194 | $SchemaVersions += 1 | Select-Object @{name="Product";expression={"Lync"}}, @{name="Schema";expression={$SchemaVersionLync}}, @{name="Version";expression={$SchemaHashLync.Item($SchemaVersionLync)}} 195 | 196 | $SchemaHashSCCM = @{ 197 | 0="No SCCM Schema extension installed"; 198 | "4.00.5135.0000"="SCCM 2007 Beta 1"; 199 | "4.00.5931.0000"="SCCM 2007 RTM"; 200 | "4.00.6221.1000"="SCCM 2007 SP1/R2"; 201 | "4.00.6221.1193"="SCCM 2007 SP1 (KB977203)"; 202 | "4.00.6487.2000"="SCCM 2007 SP2"; 203 | "4.00.6487.2111"="SCCM 2007 SP2 (KB977203)"; 204 | "4.00.6487.2157"="SCCM 2007 R3"; 205 | "4.00.6487.2207"="SCCM 2007 SP2 (KB2750782)"; 206 | "5.00.7561.0000"="SCCM 2012 Beta 2"; 207 | "5.00.7678.0000"="SCCM 2012 RC1"; 208 | "5.00.7703.0000"="SCCM 2012 RC2"; 209 | "5.00.7711.0000"="SCCM 2012 RTM"; 210 | "5.00.7711.0200"="SCCM 2012 CU1"; 211 | "5.00.7711.0301"="SCCM 2012 CU2"; 212 | "5.00.7782.1000"="SCCM 2012 SP1 Beta"; 213 | "5.00.7804.1000"="SCCM 2012 SP1"; 214 | "5.00.7804.1202"="SCCM 2012 SP1 CU1"; 215 | "5.00.7804.1300"="SCCM 2012 SP1 CU2"; 216 | "5.00.7804.1400"="SCCM 2012 SP1 CU3"; 217 | "5.00.7804.1500"="SCCM 2012 SP1 CU4"; 218 | "5.00.7804.1600"="SCCM 2012 SP1 CU5"; 219 | "5.00.7958.1000"="SCCM 2012 R2"; 220 | "5.00.7958.1203"="SCCM 2012 R2 CU1"; 221 | "5.00.7958.1303"="SCCM 2012 R2 CU2"; 222 | "5.00.7958.1401"="SCCM 2012 R2 CU3"; 223 | "5.00.7958.1501"="SCCM 2012 R2 CU4"; 224 | "5.00.7958.1604"="SCCM 2012 R2 CU5"; 225 | "5.00.8239.1000"="SCCM 2012 R2 SP1"; 226 | "5.00.8239.1203"="SCCM 2012 R2 SP1 CU1"; 227 | "5.00.8239.1301"="SCCM 2012 R2 SP1 CU2"; 228 | "5.00.8239.1403"="SCCM 2012 R2 SP1 CU3"; 229 | "5.0.8325.1000"="SCCM Current Branch 1511"; 230 | "5.0.8355.1000"="SCCM Current Branch 1602"; 231 | "5.0.8239.1501" = "SCCM 2012 R2 SP1 - CU4"; 232 | "5.00.8355.1306" = "SCCM 1602 - UR1"; 233 | "5.00.8412.1007" = "SCCM 1606"; 234 | "5.00.8412.1307" = "SCCM 1606 - UR1"; 235 | "5.0.8458.1000" = "SCCM 1610"; 236 | "5.0.8458.1001" = "SCCM 1610"; 237 | "5.0.8458.1002" = "SCCM 1610"; 238 | "5.0.8458.1003" = "SCCM 1610"; 239 | "5.0.8458.1004" = "SCCM 1610"; 240 | "5.0.8458.1005" = "SCCM 1610"; 241 | "5.0.8458.1006" = "SCCM 1610 - Update 1, FW (KB3209501)"; 242 | "5.0.8458.1007" = "SCCM 1610 - Update 1, FW (KB3209501)"; 243 | "5.0.8458.1008" = "SCCM 1610 - Update 1, FW (KB3209501)"; 244 | "5.0.8458.1009" = "SCCM 1610 - IU (KB3214042)"; 245 | "5.0.8458.1520" = "SCCM 1610 - UR (KB4010155)"; 246 | "5.0.8498.1007" = "SCCM 1702"; 247 | "5.00.8498.1711" = "SCCM 1702- UR1 (KB4019926)"; 248 | "5.00.8540.1000" = "SCCM 1706"; 249 | "5.00.8540.1005" = "SCCM 1706 - Update 1, FW (KB4039380)"; 250 | "5.00.8540.1007" = "SCCM 1706 - Update 2, FW(KB4036267)"; 251 | "5.0.8540.1611" = "SCCM 1706 - UR1 (KB4042949)"; 252 | "5.00.8577.1000" = "SCCM 1710"; 253 | "5.0.8577.1108" = "SCCM 1710 UR1 (KB4057517)"; 254 | "5.0.8577.1115" = "SCCM 1710 UR2 (KB4086143)"; 255 | "5.00.8634.1007" = "SCCM 1802"; 256 | "5.0.8634.1813" = "SCCM 1802 UR (KB4163547)"; 257 | "5.00.8692.1003" = "SCCM 1806"; 258 | "5.00.8740.1003" = "SCCM 1810"; 259 | "5.00.8790.1005" = "SCCM 1902"; 260 | "5.00.8853.1006" = "SCCM 1906"; 261 | "5.00.8913.1006" = "SCCM 1910"; 262 | "5.00.8968.1000" = "SCCM 2002"; 263 | "5.00.9012.1000" = "SCCM 2006"; 264 | "5.00.9040.1000" = "SCCM 2010"; 265 | "5.00.9040.1019" = "SCCM 2010 (KB4594177)"; 266 | } 267 | 268 | Write-Verbose "Starting SCCM Schema" 269 | $SchemaPathSCCM = "CN=System Management," + (Get-ADDomain).SystemsContainer 270 | if (Test-Path "AD:$SchemaPathSCCM") { 271 | Write-Verbose "Found SCCM Schema" 272 | $SCCMData = Get-ADObject -SearchBase ("CN=System Management," + (Get-ADDomain).SystemsContainer) -LDAPFilter "(&(objectClass=mSSMSManagementPoint))" -Property mSSMSCapabilities,mSSMSMPName 273 | Write-Verbose "SCCMData: $SCCMData" 274 | $SCCMxml = [XML]$SCCMdata.mSSMSCapabilities 275 | Write-Verbose "SCCMxml: $SCCMxml" 276 | $SchemaVersionSCCM = $SCCMxml.ClientOperationalSettings.Version 277 | Write-Verbose "SchemaVersionSCCM: $SchemaVersionSCCM" 278 | IF ( $SchemaVersionSCCM -eq $null) { Write-Warning "Ops, SCCM Schema found but could not figure out" ; Write-Warning "You found a known bug, whitch I could not fix till know. Any Idears or suggestion will be welcome: mail@fabian-niesen.de" } 279 | }Else{ 280 | Write-Verbose "No SCCM Schema found" 281 | $SchemaVersionSCCM = 0 282 | } 283 | 284 | Write-Verbose "Add SCCM Version to Schemaextension List" 285 | $SchemaVersions += 1 | Select-Object @{name="Product";expression={"SCCM"}}, @{name="Schema";expression={$SchemaVersionSCCM}}, @{name="Version";expression={$SchemaHashSCCM.Item($SchemaVersionSCCM)}} 286 | 287 | "Known current schema version of products" | Tee-Object -FilePath $logfile -Append | Write-Output 288 | "========================================" | Tee-Object -FilePath $logfile -Append | Write-Output 289 | $SchemaVersions | Format-Table * -AutoSize | Tee-Object -FilePath $logfile -Append | Write-Output 290 | IF ((Get-ADObject -Filter 'Name -like "ms-Mcs-AdmPwd"' -SearchBase $Schemapath -Properties Name)) { "Schema is LAPS ready" | Tee-Object -FilePath $logfile -Append | Write-Output } Else { "Schema is NOT LAPS ready" | Tee-Object -FilePath $logfile -Append | Write-Output } 291 | 292 | 293 | $after = Get-Date 294 | 295 | $time = $after - $before 296 | $buildTime = "`nBuild finished in "; 297 | if ($time.Minutes -gt 0) 298 | { 299 | $buildTime += "{0} minute(s) " -f $time.Minutes; 300 | } 301 | 302 | $buildTime += "{0} second(s)" -f $time.Seconds; 303 | "$buildTime" 304 | $VerbosePreference = $oldverbose 305 | $logfile | Write-Host -------------------------------------------------------------------------------- /ActiveDirectory/Repair-DFSR.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 5.0 2 | #Requires -Modules ActiveDirectory,dfsr 3 | #Requires -RunAsAdministrator 4 | 5 | <# 6 | .SYNOPSIS 7 | Repairs all DFS-R Replications configured on the Domain Controllers, including SysVol. 8 | .DESCRIPTION 9 | Repairs all DFS-R Replications configured on the Domain Controllers, including SysVol. 10 | Limitations: The script is only tested for other DFS-R replication groups, then SYSVOL, if they also located on all DC. 11 | FireWall Requirements: DFS Replication, DFS Namespace, WinRM, Remote EventLog, RemotePowerShell 12 | .EXAMPLE 13 | .\Repair-DFSR.ps1 -Authoritative -refernceDC DC01 14 | Executes an Authorative sync from DC01 15 | 16 | .EXAMPLE 17 | .\Repair-DFSR.ps1 -Authoritative 18 | Executes an Authorative sync from PDC emulator 19 | 20 | .EXAMPLE 21 | .\Repair-DFSR.ps1 22 | Stops and Restart the DFSR replication 23 | 24 | .PARAMETER Authoritative, 25 | Replication will be Authorative 26 | 27 | .PARAMETER referenceServer 28 | referenceServer for replication. Required for Authorative. If not defined PDC is used, if reachable. 29 | 30 | .NOTES 31 | Author : Fabian Niesen 32 | Filename : Repair-DFSR.ps1 33 | Requires : PowerShell Version 5.0 34 | 35 | Version : 0.1 FN 04.04.2023 Initial Version 36 | History : 0.1 FN 04.04.2023 Initial version. 37 | .LINK 38 | https://learn.microsoft.com/en-us/troubleshoot/windows-server/group-policy/force-authoritative-non-authoritative-synchronization 39 | #> 40 | Param( 41 | [Parameter(ParameterSetName = "TargetReplicationGroup")][string]$TargetReplicationGroup, #To be implemented 42 | [Parameter(ParameterSetName = "all")][Switch]$all, 43 | [Parameter(ParameterSetName = "list")][Switch]$list, 44 | [switch]$Authoritative, 45 | [String]$referenceServer 46 | ) 47 | #region Functions 48 | Function Start-Log { 49 | <# 50 | .COPYRIGHT 51 | Original Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. 52 | Additional Copyright for changes (c) 2022 Fabian Niesen. All rights reserved. Licensed under the MIT license. 53 | #> 54 | param ( 55 | [string]$FilePath , 56 | [string]$scriptName = "", 57 | [Parameter(HelpMessage = 'Deletes existing file if used with the -DeleteExistingFile switch')] 58 | [switch]$DeleteExistingFile 59 | ) 60 | IF ($FilePath -like "") 61 | { 62 | Try 63 | { 64 | $global:logPath = $(Split-Path -Parent $(Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription\" -Name "OutputDirectory" -ErrorAction Stop).OutputDirectory) + "\SecureAD" 65 | "Test $Transscripttarget $(Get-Date) from $env:COMPUTERNAME" | Out-File -FilePath $global:logPath\test.log -Append -ErrorAction Stop 66 | Write-Output "Variable Targetfolder not provided - Used Autodetection: $logPath" 67 | } 68 | CATCH 69 | { 70 | Write-Warning -Message "LogPath not found in Registry. Fall back to local log path." 71 | IF ( (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) ) { $global:logPath = "C:\Windows\System32\LogFiles\SecureAD" } else { $global:logPath = $HOME + "\LogFiles\SecureAD" } 72 | } 73 | If (!(Test-Path $logPath)) { New-Item $logPath -Type Directory -Force | Out-Null } 74 | IF ( $scriptName -like "" ) 75 | { 76 | $global:scriptName = $myInvocation.MyCommand.Name 77 | $global:scriptName = $ScriptName.Substring(0, $scriptName.Length - 4) 78 | } 79 | $global:LogName = $scriptName + "_" + (Get-Date -UFormat "%Y%m%d") +"_" + $Env:COMPUTERNAME 80 | $global:logFile = "$logPath\$LogName.log" 81 | #$global:logFile = "C:\Windows\System32\LogFiles\SecureAD\" + $(($myInvocation.MyCommand.Name).Substring(0, $($myInvocation.MyCommand.Name).Length - 4) + "_" + (Get-Date -UFormat "%Y%m%d"))+".log" 82 | Write-Output "No logfile provided - Use $logFile" 83 | $FilePath = $logFile 84 | } 85 | Try { 86 | If ($DeleteExistingFile) { Remove-Item $FilePath -Force } 87 | If (!(Test-Path $FilePath)) { New-Item $FilePath -Type File -Force | Out-Null } 88 | } 89 | Catch { 90 | Write-Error $_.Exception.Message 91 | } 92 | } 93 | #################################################### 94 | Function Write-Log { 95 | <# 96 | .COPYRIGHT 97 | Original Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. 98 | Additional Copyright for changes (c) 2022 Fabian Niesen. All rights reserved. Licensed under the MIT license. 99 | #> 100 | #Write-Log -Message 'warning' -LogLevel 2 101 | #Write-Log -Message 'Error' -LogLevel 3 102 | param ( 103 | [Parameter(Mandatory = $true)] 104 | [string]$Message, 105 | 106 | [Parameter()] 107 | [ValidateSet(1, 2, 3)] 108 | [int]$LogLevel = 1 109 | ) 110 | IF ( ! ($logFile)) { Write-Warning "Start-Log was missing - starting now with Autodetection" ; Start-Log ; } 111 | If ($LogLevel -eq 1) {Write-Host $Message } else { Write-Warning $Message } 112 | $TimeGenerated = "$(Get-Date -Format HH:mm:ss).$((Get-Date).Millisecond)+000" 113 | $Line = '' 114 | $Execname = TRY { ($MyInvocation.ScriptName | Split-Path -Leaf -ErrorAction stop)} catch { "NoScript" } 115 | $LineFormat = $Message, $TimeGenerated, (Get-Date -Format MM-dd-yyyy), "$($Execname):$($MyInvocation.ScriptLineNumber)", $LogLevel 116 | $Line = $Line -f $LineFormat 117 | $Line | Out-File -FilePath $global:logFile -Append 118 | 119 | } 120 | #################################################### 121 | function IsNull($objectToCheck) { 122 | <# 123 | .COPYRIGHT 124 | Original Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. 125 | #> 126 | if ($objectToCheck -eq $null) { return $true } 127 | if ($objectToCheck -is [String] -and $objectToCheck -eq [String]::Empty) { return $true } 128 | if ($objectToCheck -is [DBNull] -or $objectToCheck -is [System.Management.Automation.Language.NullString]) { return $true } 129 | return $false 130 | } 131 | #################################################### 132 | Function start-wait { 133 | <# 134 | .COPYRIGHT 135 | Copyright (c) 2022 Fabian Niesen. All rights reserved. Licensed under the MIT license. 136 | #> 137 | 138 | param ( 139 | [Parameter(Mandatory = $true)][int]$seconds, 140 | [string]$Comment ="Something magic is happend in the background" 141 | ) 142 | Begin { 143 | Write-Verbose -Message "$($MyInvocation.InvocationName) function..." 144 | Write-Log -Message $Comment 145 | } 146 | Process { 147 | For ($i=1; $i -le $seconds; $i++) 148 | { 149 | Write-Progress -Activity "Please Wait - $Comment - $i of $seconds seconds" -Status "$([Math]::round($i / $seconds*100 , 2))% Complete:" -PercentComplete (($i / $seconds)*100) -id 25 150 | Start-Sleep -Seconds 1 151 | } 152 | } 153 | End { Write-Verbose "Returning..." } 154 | } 155 | #################################################### 156 | #endregion functions 157 | #region init 158 | $ScriptVersion = "0.1" 159 | $script:ParentFolder = $PSScriptRoot | Split-Path -Parent 160 | $global:ScriptName = $myInvocation.MyCommand.Name 161 | $global:ScriptName = $ScriptName.Substring(0, $scriptName.Length - 4) 162 | $global:scriptsource = $myInvocation.MyCommand.Source 163 | $global:scriptparam = $MyInvocation.BoundParameters 164 | Write-Verbose "RefenceDC: $referenceServer - Authoritative: $Authoritative" 165 | Start-log -ScriptName $ScriptName 166 | Write-Log -Message "Start $ScriptName $ScriptVersion - Executed on $($Env:COMPUTERNAME)" 167 | #endregion init 168 | Set-Location $PSScriptRoot 169 | Start-Transcript -Path "$logPath\$LogName-Transcript.log" -Append 170 | If ($list) { 171 | Get-DfsReplicationGroup -IncludeSysvol 172 | Write-Host "Please us the Identyfier" 173 | Break 174 | } 175 | IF ($null -ne $TargetReplicationGroup){ 176 | 177 | } 178 | 179 | $DC=(Get-ADDomainController -Filter {OperationMasterRoles -like "PDC*"}).Hostname 180 | IF ( IsNull($referenceServer) ) { $referenceServer = $DC } Else { $referenceServer = (Get-ADComputer -Identity $referenceServer).DNSHostName } 181 | [String]$LDAPDOM = (Get-ADDomain).DistinguishedName 182 | $DFSServers = Get-ADDomain | Select-Object -ExpandProperty ReplicaDirectoryServers 183 | #region Sort Server 184 | [String[]]$SortServer = $DFSServers | Where-Object { $_ -like "$referenceServer"} 185 | ForEach ( $DFSServer in $($DFSServers | Where-Object { $_ -ne "$referenceServer"})) { $SortServer += $DFSServer } 186 | $DFSServers = $SortServer 187 | Write-Log -message "Server precedence: $($DFSServers -join(', '))" 188 | #endregion Sort Server 189 | Write-Log -message "Detected $($DFSServers.count) Replication Server" 190 | 191 | ForEach ( $DFSServer in $DFSServers ) 192 | { 193 | Write-Debug "$DFSServer" 194 | $DFSServerDN = (Get-ADComputer -Identity $($DFSServer.Split(".")[0])).DistinguishedName 195 | IF ( $all ) { [string[]]$ReplicationGroups = Get-ChildItem "AD:\CN=DFSR-LocalSettings,$DFSServerDN" } 196 | IF ( $TargetReplicationGroup) { [string[]]$ReplicationGroups = "$TargetReplicationGroup" } 197 | #IF ($null -ne $TargetReplicationGroup) { } 198 | ForEach ( $ReplicationGroup in $ReplicationGroups) 199 | { 200 | $ReplicationGroupName =$((($ReplicationGroup -split ',')[0]).Replace('CN=','')) 201 | Write-Log -Message "Modify Replication Group $ReplicationGroupName" 202 | $DfsrSettingsObject = Get-ADObject $((Get-ChildItem "AD:\$($ReplicationGroup)").DistinguishedName) -Properties "msDFSR-Enabled","msDFSR-Options" -Server $DC 203 | If ( $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { $DfsrSettingsObject | format-List } 204 | IF ( $Authoritative -and $DFSServer -like $referenceServer ) { $DfsrSettingsObject.'msDFSR-options' = 1 } 205 | $DfsrSettingsObject.'msDFSR-Enabled' = $False 206 | Set-ADObject -Instance $DfsrSettingsObject -Server $DC 207 | start-wait -Comment "Waiting for AD" -seconds 5 208 | $DfsrSettingsObject = Get-ADObject $((Get-ChildItem "AD:\$($ReplicationGroup)").DistinguishedName) -Properties "msDFSR-Enabled","msDFSR-Options" -Server $DC 209 | Write-Log -message "DFSR settings for $ReplicationGroupName are - msDFSR-Enabled: $($DfsrSettingsObject.'msDFSR-Enabled') msDFSR-options: $($DfsrSettingsObject.'msDFSR-options') " 210 | } 211 | Write-Log -Message "Start remote AD replication on $DFSServer" 212 | Try { Invoke-Command -ComputerName $DFSServer -ScriptBlock {Start-Process repadmin -ArgumentList "/syncall /APed" -NoNewWindow -Wait} -ErrorAction Stop } 213 | Catch { Write-log -message "$($_.Exception.Message)" -logLevel 3 ; Continue } 214 | start-wait -Comment "Waiting for AD" -seconds 5 215 | Update-DfsrConfigurationFromAD -ComputerName $DFSServer -Verbose 216 | Write-Log -Message "Stop DFS-R Service on $DFSServer" 217 | Try { Invoke-Command -ComputerName $DFSServer -ScriptBlock { Stop-Service -Name dfsr } -ErrorAction Stop } 218 | Catch { Write-log -message "$($_.Exception.Message)" -logLevel 3 ; Continue } 219 | } 220 | Write-Log -Message "DFS-R Disabled" 221 | Write-Host "========================================================" 222 | Write-Log -Message "Enable DFS-R" 223 | ForEach ( $DFSServer in $DFSServers ) 224 | { 225 | $DFSServerDN = (Get-ADComputer -Identity $($DFSServer.Split(".")[0])).DistinguishedName 226 | $ReplicationGroups = Get-ChildItem "AD:\CN=DFSR-LocalSettings,$DFSServerDN" 227 | Write-Debug "Round 2 - $DFSServer" 228 | Write-Log -Message "Start DFS-R Service on $DFSServer" 229 | Try { Invoke-Command -ComputerName $DFSServer -ScriptBlock { Start-Service -Name dfsr } -ErrorAction Stop } 230 | Catch { Write-log -message "$($_.Exception.Message)" -logLevel 3 ; Continue } 231 | do { 232 | Start-Wait -comment "Wait for DFS-R to settle" -seconds 10 233 | If ( $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) {(Get-EventLog -LogName "DFS Replication" -ComputerName $DFSServer -InstanceId 1073745938 -Newest 10 -After ((Get-Date).AddMinutes(-10)))} 234 | } Until ( (Get-EventLog -LogName "DFS Replication" -ComputerName $DFSServer -InstanceId 1073745938 -After ((Get-Date).AddMinutes(-10))).Count -ge 1 ) 235 | ForEach ( $ReplicationGroup in $ReplicationGroups) 236 | { 237 | $ReplicationGroupName =$((($ReplicationGroup -split ',')[0]).Replace('CN=','')) 238 | Write-Log -Message "Modify Replication Group $ReplicationGroupName" 239 | $DfsrSettingsObject = Get-ADObject $((Get-ChildItem "AD:\$($ReplicationGroup)").DistinguishedName) -Properties "msDFSR-Enabled","msDFSR-Options" -Server $DC 240 | If ( $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { $DfsrSettingsObject | format-List } 241 | $DfsrSettingsObject.'msDFSR-Enabled' = $True 242 | Set-ADObject -Instance $DfsrSettingsObject -Server $DC 243 | start-wait -Comment "Waiting for AD" -seconds 5 244 | $DfsrSettingsObject = Get-ADObject $((Get-ChildItem "AD:\$($ReplicationGroup)").DistinguishedName) -Properties "msDFSR-Enabled","msDFSR-Options" -Server $DC 245 | Write-Log -message "DFSR settings for $ReplicationGroupName are - msDFSR-Enabled: $($DfsrSettingsObject.'msDFSR-Enabled') msDFSR-options: $($DfsrSettingsObject.'msDFSR-options') " 246 | } 247 | Write-Log -Message "Start remote AD replication on $DFSServer" 248 | Try { Invoke-Command -ComputerName $DFSServer -ScriptBlock {Start-Process repadmin -ArgumentList "/syncall /APed" -NoNewWindow -Wait} -ErrorAction Stop } 249 | Catch { Write-log -message "$($_.Exception.Message)" -logLevel 3 ; Continue } 250 | start-wait -Comment "Waiting for AD" -seconds 5 251 | Update-DfsrConfigurationFromAD -ComputerName $DFSServer -Verbose 252 | IF ( $DFSServer -eq $referenceServer) 253 | { 254 | do { 255 | Start-Wait -comment "Wait for DFS-R to settle" -seconds 10 256 | } Until ( (Get-EventLog -LogName "DFS Replication" -ComputerName $referenceServer -InstanceId 1073746426 -Newest 3 -After (Get-Date).AddMinutes(-10)).Count -ge 1 ) 257 | } 258 | } 259 | Write-Log -Message "DFS-R Repair Completed - Synchronisation may take a while" -------------------------------------------------------------------------------- /New-DokuwikiAnimal.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Legt Dokuwiki Animals an. 4 | .DESCRIPTION 5 | Legt Dokuwiki Animals an. Inklusive AD-Gruppen, ACL, Konfig, NTFS Rechte, .... 6 | .EXAMPLE 7 | New-DokuwikiAnimal.ps1 -Animal IT 8 | .INPUTS 9 | Animal 10 | .OUTPUTS 11 | Keine. 12 | .NOTES 13 | Author : Fabian Niesen 14 | Filename : New-DokuwikiAnimal.ps1 15 | Requires : PowerShell Version 3.0 16 | License : The MIT License (MIT) 17 | Copyright (c) 2022-2025 Fabian Niesen 18 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 19 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 20 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 23 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 24 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 25 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 26 | connection with the software or the use or other dealings in the Software. 27 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 28 | The author assumes no responsibility for any damage or data loss caused by this script. 29 | Test thoroughly in a controlled environment before deploying to production. 30 | Version : 0.1 31 | History : 0.1 Los geht es 32 | .LINK 33 | http://wiki.domain.tld/ 34 | 35 | Offene Punkte / Knowing Bugs 36 | 37 | #> 38 | [cmdletbinding()] 39 | Param( 40 | [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$False)] 41 | [String]$Animal="!notset!" 42 | ) 43 | 44 | clear-host 45 | 46 | $wwwroot ="C:\inetpub\wwwroot" 47 | $farmpath = $wwwroot+"\wiki" 48 | $GroupOU = "OU=Wiki,OU=Gruppen,DC=domain,DC=tld" 49 | $wikiadmins = "RG-WEB-Wiki-Admins" 50 | $GroupPreFix = "RG-WEB-Wiki-" 51 | $ErrorActionPreference = "Stop" 52 | $before = Get-Date 53 | $date = get-date -format yyyyMMdd-HHmm 54 | 55 | ### Proof for administrative permissions (UAC) 56 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) 57 | { 58 | Write-Warning "Not run as administrator! You failed ;)" 59 | break 60 | } 61 | 62 | Write-Host "Lade ActiveDirectory Module" 63 | try 64 | { 65 | Import-Module ActiveDirectory 66 | } 67 | catch 68 | { 69 | Write-Warning "ActiveDirectory Module ist missing. Please install first" 70 | break 71 | } 72 | 73 | If ($Animal -eq "!notset!") { 74 | Write-Host "" 75 | $Animal = $( Read-Host "Bitte geben Sie den Namen des neuen Wiki ein (Ohne den Begriff 'Wiki')" ) 76 | Write-Host "" 77 | } 78 | 79 | #Check Sonderzeichen und Leerzeichen !!!!!!!!!!! 80 | $cleananimal = $($Animal -replace " ","").ToLower() 81 | 82 | $animalpath = $farmpath+"\"+$cleananimal 83 | 84 | Write-Host "Wiki wird eingerichtet unter $animalpath" 85 | Write-Host "" 86 | Write-verbose "Lege Verzeichnis an" 87 | IF (Test-Path $animalpath) {Write-Warning "Das Verzeichnis $animalpath existiert bereits"} 88 | ELSE 89 | { new-item -Path $animalpath -ItemType directory| Out-Null } 90 | 91 | Write-Host "Lege die AD-Gruppen mit dem Prefix $($GroupPreFix+$Animal) in der OU $GroupOU" 92 | #Anlegen der AD-Gruppen 93 | $GroupRead = $GroupPreFix+$Animal+"-Lesen" 94 | $GroupEditor = $GroupPreFix+$Animal+"-Editor" 95 | $GroupManager = $GroupPreFix+$Animal+"-Manager" 96 | $GroupAdmins = $GroupPreFix+$Animal+"-Admins" 97 | 98 | try { New-ADGroup -Name $GroupRead -SamAccountName $GroupRead -GroupCategory Security -GroupScope Global -DisplayName $GroupRead -Path $GroupOU -Description "Leserechte für das Wiki $Animal"} 99 | catch {Write-Warning "Die Gruppe $GroupRead existiert bereits"} 100 | try { New-ADGroup -Name $GroupEditor -SamAccountName $GroupEditor -GroupCategory Security -GroupScope Global -DisplayName $GroupEditor -Path $GroupOU -Description "Editorrechte für das Wiki $Animal"} 101 | catch {Write-Warning "Die Gruppe $GroupEditor existiert bereits"} 102 | try { New-ADGroup -Name $GroupManager -SamAccountName $GroupManager -GroupCategory Security -GroupScope Global -DisplayName $GroupManager -Path $GroupOU -Description "Managementrechte für das Wiki $Animal"} 103 | catch {Write-Warning "Die Gruppe $GroupManager existiert bereits"} 104 | try { New-ADGroup -Name $GroupAdmins -SamAccountName $GroupAdmins -GroupCategory Security -GroupScope Global -DisplayName $GroupAdmins -Path $GroupOU -Description "Adminrechte für das Wiki $Animal"} 105 | catch {Write-Warning "Die Gruppe $GroupAdmins existiert bereits"} 106 | 107 | Write-Host "Füge die Wiki-Admins zu den Admins hinzu hinzu, befülle die Lesegruppe mit Editoren, Manager und Admins." 108 | try { Add-ADGroupMember $GroupAdmins $wikiadmins} 109 | catch {Write-Warning "$wikiadmins sind bereits in $GroupAdmins enthalten"} 110 | try { Add-ADGroupMember $GroupRead $GroupEditor,$GroupManager,$GroupAdmins} 111 | catch {Write-Warning "Die Editoren, Manager und Admins haben bereits Leserechte"} 112 | try { Add-ADGroupMember "RG-WEB-Wiki-Benutzer" $GroupRead} 113 | catch {Write-Warning "Die Gruppe $GroupRead ist bereits in der Gruppe RG-WEB-Wiki-Benutzer enthalten"} 114 | Write-Host "" 115 | 116 | Write-Verbose "Setzte NTFS Rechte" 117 | #Setzen der NTFS Rechte 118 | $inherit = [system.security.accesscontrol.InheritanceFlags]"ContainerInherit, ObjectInherit" 119 | $propagation = [system.security.accesscontrol.PropagationFlags]"InheritOnly" 120 | $modify = [System.Security.AccessControl.FileSystemRights]"Read, Write, Modify, ExecuteFile" 121 | $read = [System.Security.AccessControl.FileSystemRights]"ReadAndExecute" 122 | 123 | ### ==== For Schleife für NTFS Einfügen ==== ### 124 | ### Schleife umbauen nach verzeichnissen statt Gruppen, wäre schneller !! 125 | ### Setzt eigentlich noch zuviele Rechte!!!! 126 | 127 | $groups = @($GroupRead,$GroupEditor,$GroupManager,$GroupAdmins) 128 | #foreach ($group in $groups) 129 | #{ 130 | $group = $GroupRead 131 | Write-Host "Setzte NTFS Rechte für $group" 132 | ##NTFS für WWWROOT 133 | $Acl = Get-ACL -Path $wwwroot 134 | Write-Debug "$($acl | FL)" 135 | $Ar = New-Object system.security.accesscontrol.filesystemaccessrule($GroupRead,$read,"None","None","Allow") 136 | Write-Debug "$($Ar | FL)" 137 | $Acl.AddAccessRule($Ar) 138 | Write-Debug "$($acl | FL)" 139 | Write-Verbose "Set-ACL lesen WWWroot" 140 | Set-Acl -Path $wwwroot -AclObject $Acl 141 | 142 | Write-Verbose "NTFS für Farm" 143 | $Acl = Get-ACL -Path $farmpath 144 | $Ar = New-Object system.security.accesscontrol.filesystemaccessrule($GroupRead,$read,"None","None","Allow") 145 | $Acl.AddAccessRule($Ar) 146 | Set-Acl $farmpath $Acl 147 | 148 | ##NTFS für Farmer 149 | $Acl = Get-ACL -Path $($wwwroot+"\dokuwiki") 150 | $Ar = New-Object system.security.accesscontrol.filesystemaccessrule($GroupRead,$modify,$inherit, $propagation, "Allow") 151 | $Acl.AddAccessRule($Ar) 152 | Set-Acl $($wwwroot+"\dokuwiki") $Acl 153 | 154 | ##NTFS Für Animal 155 | $Acl = Get-ACL -Path $animalpath 156 | $Ar = New-Object system.security.accesscontrol.filesystemaccessrule($GroupRead,$modify,$inherit, $propagation, "Allow") 157 | $Acl.AddAccessRule($Ar) 158 | Set-Acl $animalpath $Acl 159 | 160 | 161 | #} 162 | ### ==== Ende der Schleife für NTFS ==== ### 163 | 164 | #Anlegen des Animal 165 | Write-Host "" 166 | Write-Host "Erzeuge das Child Wiki" 167 | 168 | new-item -Path $($animalpath+"\data\") -ItemType directory| Out-Null 169 | new-item -Path $($animalpath+"\conf\") -ItemType directory| Out-Null 170 | 171 | Write-Verbose "Setzte NTFS für Animal Conf" 172 | $Acl = Get-ACL -Path $($animalpath+"\conf") 173 | $Ar = New-Object system.security.accesscontrol.filesystemaccessrule($GroupAdmins,$modify,$inherit, $propagation, "Allow") 174 | $Acl.AddAccessRule($Ar) 175 | Set-Acl $($animalpath+"\conf") $Acl 176 | 177 | $verz = @("attic","cache","index","locks","media","media_attic","media_meta","meta","pages","tmp") 178 | foreach ($ver in $verz) { 179 | new-item -Path $($animalpath+"\data\"+$ver) -ItemType directory | Out-Null 180 | } 181 | $conffiles = @("local.php","local.protected.php","acl.auth.php","users.auth.php","plugins.local.php") 182 | foreach ($conffile in $conffiles) { 183 | new-item -Path $($animalpath+"\conf\"+$conffile) -ItemType File| Out-Null 184 | } 185 | Copy-Item -Path $($wwwroot+"\dokuwiki\data\pages\wiki") -Destination $($animalpath+"\data\pages\") -Recurse 186 | Copy-Item -Path $($wwwroot+"\dokuwiki\data\pages\playground") -Destination $($animalpath+"\data\pages\") -Recurse 187 | Copy-Item -Path $($wwwroot+"\dokuwiki\data\meta\wiki") -Destination $($animalpath+"\data\meta\") -Recurse 188 | Copy-Item -Path $($wwwroot+"\dokuwiki\data\media\wiki\logo.png") -Destination $($animalpath+"\data\media\") 189 | 190 | ### Writing 191 | $lc = $animalpath+"\conf\local.protected.php" 192 | Write-Host "Befülle die Konfiguration $lc" 193 | "" | Out-File $aclc -Append 239 | "# Don't modify the lines above" | Out-File $aclc -Append 240 | "# Access Control Lists" | Out-File $aclc -Append 241 | "* @$($GroupAdmins -replace '-','%2d') 16" | Out-File $aclc -Append 242 | "* @$($GroupManager -replace '-','%2d') 16" | Out-File $aclc -Append 243 | "* @$($GroupEditor -replace '-','%2d') 8" | Out-File $aclc -Append 244 | "* @$($GroupRead -replace '-','%2d') 1" | Out-File $aclc -Append 245 | $file_content = Get-Content "$aclc"; 246 | [System.IO.File]::WriteAllLines("$aclc", $file_content); 247 | 248 | ## Startseite 249 | $startpage = $animalpath+"\data\pages\start.txt" 250 | Write-Host "Befülle die Startseite" 251 | "====== Willkommen im $Animal Wiki ======" |Out-File $startpage -Append 252 | "===== Wichtiger Hinweis zur Nutzung der Wikis =====" |Out-File $startpage -Append 253 | "Jede Änderung an einer Seite wird Protokolliert und ist eindeutig einer Person mit Zeitstempel zuordenbar. Bitte bedenken Sie dies beim Ändern oder hinzufügen von Inhalten, dass Ihre Kollegen dies sehen können. Den Zeitpunkt und Autor der letzten Änderung finden Sie unten Rechts. \\ \\ Sollte dies nicht gewünscht sein, empfehlen wir eine Zentrale Instanz zum ändern der Beträge, zum Beispiel ein Sekretariat. Eine Abschaltung dieser Funktion ist aus technischen Gründen nicht möglich." |Out-File $startpage -Append 254 | "==== Handhabung des DokuWiki ====" |Out-File $startpage -Append 255 | " * [[wiki:syntax|DokuWiki Syntax]]" |Out-File $startpage -Append 256 | " * [[playground:playground|Spielplatz zum üben]]" |Out-File $startpage -Append 257 | 258 | $file_content = Get-Content "$startpage" 259 | [System.IO.File]::WriteAllLines("$startpage", $file_content) 260 | 261 | ##Setzten des NTFS Owner 262 | 263 | <# $owner = New-Object System.Security.Principal.NTAccount("steep\$GroupAdmins") 264 | Write-Host "Setze den NTFS Owner für $animalpath auf $owner" 265 | $Acl = $(get-Item $animalpath).GetAccessControl() 266 | $Acl.SetOwner($owner) 267 | set-acl -aclobject $Acl -path $animalpath 268 | 269 | #Ownervererbung geht noch nicht !!!!!! 270 | #> 271 | 272 | ## Anwender Infos 273 | Write-Host "" 274 | Write-Host "=============================================================================" 275 | Write-Host "" 276 | Write-Host "Das $Animal Wiki ist nun unter http://wiki.domain.tld/$cleananimal/ erreichbar" 277 | Write-Host "Für die Berechtigung bitte Gruppen verwenden, und keine Benutzer in die Gruppen $GroupEditor und $GroupRead " 278 | Write-Host "Die Gruppen mit Leserechten fügen Sie bitte der Gruppe $GroupRead hinzu" 279 | Write-Host "Die Gruppen mit Editierechten fügen Sie bitte der Gruppe $GroupEditor hinzu" 280 | Write-Host "Die Gruppen mit Managementrechten fügen Sie bitte der Gruppe $GroupManager hinzu" 281 | #Write-Host "Die Gruppen mit Adminrechten fügen Sie bitte der Gruppe $GroupAdmins hinzu, dies ist nur im Ausnahmefall zulässig." -------------------------------------------------------------------------------- /GPO/get-GPOBackup.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Creates backup of the GPO with according html Reports. The script creates a subfolder based upon an actual timestamp. 4 | 5 | .DESCRIPTION 6 | PowerShell script to periodically back up the Group Policy and documentation of version using HTML reports. Ideal as a scheduled task to perform regular backups of the GPO. Each backup creates a new subfolder with a time stamp. 7 | The script does not require Administrative privileges. If the script runs with Administrative privileges, it will write status information to the event log. 8 | Based opon the german blog article contained in the link. Get the actual Script version from Microsoft TechNet: http://bit.ly/gpobackup 9 | If you like this script, please rate it in the TechNet Gallery. 10 | 11 | .EXAMPLE 12 | C:\PS> get-GPOBackup.ps1 13 | 14 | .EXAMPLE 15 | C:\PS> get-GPOBackup.ps1 -BackupPath C:\GPOBACKUP -KeepDate 90 16 | 17 | .EXAMPLE 18 | C:\PS> get-GPOBackup.ps1 -BackupPath C:\GPOBACKUP -KeepDate 90 -Verbose 19 | 20 | .PARAMETER BackupPath 21 | Path to Backup. 22 | 23 | .PARAMETER KeepDate 24 | Amount of days to keep the old versions. 25 | 26 | .PARAMETER characters 27 | Characters to be replaced in GPO names with an "_". 28 | 29 | .PARAMETER PolicyDefinition 30 | Switch to enable Backup of PolicyDefinition Files 31 | 32 | .PARAMETER testerror 33 | Switch to force an Error for testing 34 | 35 | .PARAMETER testwarning 36 | Switch to force an Warrning for testing 37 | 38 | .PARAMETER testerrorwarning 39 | Switch to force an Error with Warrning for testing 40 | 41 | .NOTES 42 | Author : Fabian Niesen (infrastrukturhelden.de) 43 | Filename : get-GPOBackup.ps1 44 | Requires : PowerShell Version 4.0 45 | Version : 1.8 46 | License : The MIT License (MIT) 47 | Copyright (c) 2022-2025 Fabian Niesen 48 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 49 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, 50 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 51 | furnished to do so, subject to the following conditions: 52 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 53 | The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties 54 | of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be 55 | liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in 56 | connection with the software or the use or other dealings in the Software. 57 | Disclaimer : This script is provided "as is" without warranty. Use at your own risk. 58 | The author assumes no responsibility for any damage or data loss caused by this script. 59 | Test thoroughly in a controlled environment before deploying to production. 60 | History : 1.0.0 FN 27/07/14 initial version 61 | 1.1.0 FN 25/08/14 Change script to handle new GUID on GPO backup 62 | 1.1.1 FN 03/09/14 Fix Targetpath for secured enviorment 63 | 1.2 FN 20/01/15 move download to TechNet, translation to english, 64 | implement Eventlog if Run as Admin 65 | 1.3 FN 09/02/15 Change Name to get-GPOBackup, Change Path to parameter 66 | instead Config, Implementing KeepDate, Implementing Error-Logging 67 | 1.4 FN 25/02/15 Tracking runtime, fixes in documentation 68 | 1.55 FN 11/08/17 Add some Debug Options. Filtering GPO Names for unwanted Characters 69 | 1.56 FN 04/03/18 Fix Eventlog handling. Add additional Eventlog posibilities, 70 | for this I change and add EventIDs. Some fixes with the get-Help output 71 | 1.57 FN 06/02/19 Added "/" to Escape Chars 72 | 1.58 FN 12/03/19 Added Central Store Backup 73 | 1.59 FN 11/08/21 Added '"' to Escape Chars 74 | 1.60 FN 13.10.22 Added PowerShell Creation for easier GPO export and import - only works with GPO Settings stored in Regestry Keys under HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER Everthing under Software and System! 75 | 1.61 FN 26.01.23 Small Improvements for Module loading 76 | 1.7 FN 25.10.2025 Change License to GPLv3, except for 3rdparty code (e.g Function Get-GPPolicyKey) 77 | 1.8 FN 03.12.2025 Changed License to MIT, housekeeping Header 78 | 79 | .LINK 80 | https://www.infrastrukturhelden.de/microsoft-infrastruktur/active-directory/gruppenrichtlinien-richtig-sichern-und-dokumentieren.html 81 | #> 82 | 83 | Param( 84 | [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$False)] 85 | [String]$BackupPath="C:\Temp\GPOBackup", 86 | [Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$False)] 87 | [Int]$KeepDate="93", 88 | [Parameter(Mandatory=$false, Position=2, ValueFromPipeline=$false)] 89 | [string]$characters = '. $%&!?#*:;\><|/"', 90 | [switch]$PolicyDefinitions, 91 | [switch]$PowerShellExport, 92 | [switch]$testerror, 93 | [switch]$testwarning, 94 | [switch]$testerrorwarning 95 | ) 96 | #region Functions 97 | ######################## 98 | # Function found at: https://sdmsoftware.com/group-policy-videos/find-all-registry-settings-managed-in-a-gpo/ 99 | function Get-GPPolicyKey 100 | { 101 | param( 102 | [string]$gpoName, 103 | [string]$key 104 | ) 105 | $ErrorActionPreference = "Stop" 106 | Write-Verbose "GPO: $gpoName - Key: $key" 107 | $hive = Get-GPRegistryValue -Name $gpoName -Key $key 108 | ForEach ($item in $hive) 109 | { 110 | Write-Verbose "Item: $($item.FullKeyPath)" 111 | if ($item.ValueName -ne $null) { [array]$result += $item } 112 | else { Get-GPPolicyKey -Key $item.FullKeyPath -gpoName $gpoName } 113 | } 114 | return $result 115 | } 116 | 117 | #endregion Functions 118 | 119 | #Verknüfungsorte mit speichern 120 | $scriptversion = "1.8" 121 | Write-Output "Get-GPOBackup.ps1 Version $scriptversion " 122 | $ErrorActionPreference = "Stop" 123 | $GPList = @() 124 | $regex = "[$([regex]::Escape($characters))]" 125 | #[Array]$GPList = $null 126 | 127 | $before = Get-Date 128 | 129 | IF ($BackupPath.EndsWith("\") -like "False") { $BackupPath =$BackupPath+"\" } 130 | IF (!(Test-Path $BackupPath)) { new-item -Path $BackupPath -ItemType directory } 131 | 132 | $date = get-date -format yyyyMMdd-HHmm 133 | $ErrorLog =$BackupPath+$date+"-error.log" 134 | $InfoLog =$BackupPath+$date+"-info.log" 135 | $WarningLog =$BackupPath+$date+"-warning.log" 136 | $Report = $BackupPath+$date+"-Report.csv" 137 | Write-Verbose "Import Grouppolicy module" 138 | IF ( (Get-WindowsFeature -Name GPMC).InstallState -notlike "Installed" ) {Write-Warning "Missing Windows Feature GPMC - start Installation" ; Install-WindowsFeature -Name GPMC} 139 | IF ( (Get-WindowsFeature -Name RSAT-AD-PowerShell).InstallState -notlike "Installed" ) {Write-Warning "Missing Windows Feature RSAT-AD-PowerShell - start Installation" ; Install-WindowsFeature -Name RSAT-AD-PowerShell} 140 | IF ( (Get-WindowsFeature -Name GPMC).InstallState -notlike "Installed" ) {Write-Error -Message "GPMC missing - Installation Failed" ; Break } 141 | IF ( (Get-WindowsFeature -Name RSAT-AD-PowerShell).InstallState -notlike "Installed" ) {Write-Error -Message "RSAT-AD-PowerShell missing - Installation Failed" ; Break } 142 | 143 | Write-Verbose "Check if backup path is default" 144 | IF ($BackupPath -eq "c:\temp\GPOBackup\") 145 | { 146 | Write-Warning "No BackupPath provided, use C:\TEMP\GPOBackup. To provide a Backuppath use >Get-GPOBackup -BackupPath<" 147 | "BackupPath not set, use default"| Out-file $WarningLog -Append 148 | $Wait = $True 149 | } 150 | 151 | 152 | IF ($KeepDate -eq "93") 153 | { 154 | Write-Warning "No KeepDate provided, delete Backups older than 93 days. To provide a an other timeperiod use >Get-GPOBackup -KeepDate<" 155 | "KeepDate not set, use default"| Out-file $WarningLog -Append 156 | $Wait = $True 157 | } 158 | 159 | IF ($Wait -eq $True) { Start-Sleep -s 10 } 160 | Write-Verbose "Start housekeeping, deleting old backups" 161 | 162 | try 163 | { 164 | Write-Host "Start deleting Backups older than $KeepDate days" 165 | Get-ChildItem $BackupPath | Where-Object {$_.PSIsContainer -and $_.LastWriteTime -le (Get-Date).AddDays(-$KeepDate)} | ForEach-Object {Remove-Item $_.Fullname -Recurse -Force } 166 | } 167 | catch 168 | { 169 | $Error.Item($Error.Count - 1) | Format-List * -Force | Out-file $ErrorLog -Append 170 | "Deletion of old backups failed" | Out-file $ErrorLog -Append 171 | Write-Warning "Deletion of old backups failed" 172 | } 173 | 174 | 175 | $BackupPath =$BackupPath+$date 176 | IF (!(Test-Path $BackupPath)) { New-Item -Path $BackupPath -ItemType directory | out-null } 177 | ELSE 178 | { 179 | "Backup already exist. Script started twice or you use a time machine!" | Out-file $ErrorLog -Append 180 | Write-Warning "Backup already exist. Script started twice or you use a time machine!" 181 | break 182 | } 183 | 184 | ### Processing PolicyDefinitions 185 | If ($PolicyDefinitions -eq $true) { 186 | Write-Verbose "Start policyDefinition Backup" 187 | $DomDNS = $(Get-ADDomain).DNSroot 188 | IF (Test-Path "C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions") { Write-Verbose "Found Local SYSVOL Central Store" ; $PolDef = "C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions" } 189 | elseif (Test-Path "\\$DomDNS\SYSVOL\$DomDNS\Policies\PolicyDefinitions") { $PolDef = "\\$DomDNS\SYSVOL\$DomDNS\Policies\PolicyDefinitions" } 190 | Else {Write-Warning "No Central Store Found. Central Store is needed for this feature, otherwise it is useless. Please Check"; "No Central Store Found. Backup failed"| Out-file $ErrorLog -Append ; Break} 191 | Write-Verbose "Found Central Store: $PolDef" 192 | Add-Type -assembly "system.io.compression.filesystem" 193 | $PDZip = $($BackupPath+"\PolicyDefinition.zip") 194 | If (Test-Path "$PDZip") {Write-Warning "Something went wrong, Target already exist. Timetravel?"} 195 | Else { 196 | [io.compression.zipfile]::CreateFromDirectory($PolDef,$PDZip) 197 | } 198 | } 199 | 200 | ### Processing GPO 201 | Write-Verbose "Query GPOs" 202 | $GPOS = get-GPO -all 203 | Write-Verbose "Start processing GPO" 204 | Write-Progress -activity "Processing GPO" -Status "starting" -PercentComplete "0" -Id 1 205 | [int]$i = "0" 206 | FOREACH ( $GPO in $GPOS) 207 | { 208 | $i++ 209 | Write-Progress -activity "Processing GPO" -Status "$($GPO.DisplayName)" -PercentComplete (($i / $GPOS.count)*100) -Id 1 210 | $GPOname = $($GPO.DisplayName).Trim() 211 | $GPOname = $GPOname -replace $regex,"_" 212 | IF (!($($GPO.DisplayName) -eq $GPOname)) 213 | { 214 | Write-Verbose "Filtered GPO Name >$($GPO.DisplayName)< to: >$GPOname<" 215 | "Filtered GPO Name >$($GPO.DisplayName)< to: >$GPOname<" | Out-File $InfoLog -Append 216 | } 217 | $bpath = $BackupPath+"\"+$GPOname 218 | New-Item -Path $bpath -ItemType directory | Out-Null 219 | Write-Verbose "Starting backup $($GPO.DisplayName)" 220 | try 221 | { 222 | $gptemp = Backup-Gpo -Name $($GPO.DisplayName) -Path $bpath 223 | $GPitem = New-Object -TypeName psobject 224 | $GPitem | Add-Member -MemberType NoteProperty -Name DisplayName -Value $gptemp.DisplayName 225 | $GPitem | Add-Member -MemberType NoteProperty -Name GpoId -Value $gptemp.GpoId 226 | $GPitem | Add-Member -MemberType NoteProperty -Name Id -Value $gptemp.Id 227 | $GPitem | Add-Member -MemberType NoteProperty -Name BackupDirectory -Value $gptemp.BackupDirectory 228 | $GPitem | Add-Member -MemberType NoteProperty -Name CreationTime -Value $gptemp.CreationTime 229 | $GPitem | Add-Member -MemberType NoteProperty -Name DomainName -Value $gptemp.DomainName 230 | $GPitem | Add-Member -MemberType NoteProperty -Name Comment -Value $gptemp.Comment 231 | $GPList += $GPitem 232 | } 233 | catch 234 | { 235 | $Error.Item($Error.Count - 1) | Format-List * -Force | Out-file $ErrorLog -Append 236 | Write-Warning "$($GPO.DisplayName) backup failed" 237 | "$($GPO.DisplayName) Backup failed"| Out-file $ErrorLog -Append 238 | } 239 | Write-Verbose "Starting HTML report $($GPO.DisplayName)" 240 | try 241 | { 242 | Get-GPOReport $($GPO.DisplayName) -ReportType HTML -Path "$bpath\$GPOname.html" 243 | } 244 | catch 245 | { 246 | $Error.Item($Error.Count - 1) | Format-List * -Force | Out-file $ErrorLog -Append 247 | Write-Warning "$($GPO.DisplayName) HTML report failed" 248 | "$($GPO.DisplayName) HTML report failed"| Out-file $ErrorLog -Append 249 | } 250 | IF ( $PowerShellExport ) 251 | { 252 | Write-Verbose "Start PowerShell script creation" 253 | $exportcsv = $bpath + "\" + $GPOname + "-PS.csv" 254 | $exportps = $bpath + "\" + $GPOname + ".ps1" 255 | Write-Verbose "ExportCSV: $exportcsv - ExportPS: $exportps" 256 | try { $settings = Get-GPPolicyKey -key "HKEY_LOCAL_MACHINE\Software" -gpoName $($GPO.DisplayName) -ErrorAction Stop } 257 | catch 258 | { 259 | Write-Host "No Policy under HKEY_LOCAL_MACHINE\Software" 260 | } 261 | try { $settings += Get-GPPolicyKey -key "HKEY_LOCAL_MACHINE\System" -gpoName $($GPO.DisplayName) -ErrorAction Stop } 262 | catch 263 | { 264 | Write-Host "No Policy under HKEY_LOCAL_MACHINE\System" 265 | } 266 | try { $settings += Get-GPPolicyKey -key "HKEY_CURRENT_USER\Software" -gpoName $($GPO.DisplayName) -ErrorAction Stop } 267 | catch 268 | { 269 | Write-Host "No Policy under HKEY_CURRENT_USER\Software" 270 | } 271 | try { $settings += Get-GPPolicyKey -key "HKEY_CURRENT_USER\System" -gpoName $($GPO.DisplayName) -ErrorAction Stop } 272 | catch 273 | { 274 | Write-Host "No Policy under HKEY_CURRENT_USER\System" 275 | } 276 | $settings = $settings.Where({ $null -ne $_ }) 277 | Write-Verbose "Export CSV" 278 | $settings | Export-Csv -NoTypeInformation -Path $exportcsv -Force -Confirm:$false -Delimiter ";" 279 | Write-Progress -activity "Processing GPO $GPOname - $i of $j" -Status "Create PowerShell import script" -PercentComplete (($i / $GPOS.count)*100) -Id 1 -ErrorAction SilentlyContinue 280 | Write-Progress -activity "Create PowerShell import script" -Status "starting" -PercentComplete "0" -Id 2 -ParentId 1 281 | Write-Verbose "Found $(($settings).count)" 282 | [int]$i2 = 0 283 | [int]$j2 = $($settings).count 284 | ForEach ($setting in $settings) 285 | { 286 | $i2++ 287 | Write-Progress -activity "Create PowerShell import script - $i2 of $j2" -Status $($setting.ValueName) -PercentComplete (($i2 / $j2 *100)) -Id 2 -ParentId 1 -ErrorAction SilentlyContinue 288 | "Set-GPRegistryValue -Key " + $($setting.FullKeyPath) + " -Name '"+ $GPOname +"' -Type "+ $($setting.Type) + " -Value "+ $($setting.Value)+ " -ValueName " + $($setting.ValueName) | out-file -FilePath $exportps -Append 289 | } 290 | } 291 | } 292 | 293 | $GPList | Export-Csv $Report -NoTypeInformation -Delimiter ";" 294 | Write-Output "Creating a report about all handled GPO. Please check $Report" 295 | 296 | ###Prepare Errorhandling Output 297 | $EHMessage = @() 298 | IF ((Test-Path $ErrorLog) -and (Test-Path $WarningLog)) 299 | { 300 | IF ($EHID -eq $null) { $EHID = "301" } 301 | $EHCategory = "Error" 302 | $EHMessage += "Backup completed with Errors and Warnings. Targetpath: $BackupPath" 303 | $EHMessage += "--- ERRORLOG $ErrorLog ---" 304 | $EHMessage += Get-Content $ErrorLog 305 | $EHMessage += "--- WARNINGLOG $WarningLog ---" 306 | $EHMessage += Get-Content $WarningLog 307 | 308 | } 309 | ELSEIF (Test-Path $ErrorLog) 310 | { 311 | IF ($EHID -eq $null) { $EHID = "300" } 312 | $EHCategory = "Error" 313 | $EHMessage += "Backup completed with Errors. Targetpath: $BackupPath" 314 | $EHMessage += "--- ERRORLOG $ErrorLog ---" 315 | $EHMessage += Get-Content $ErrorLog 316 | } 317 | ELSeIF (Test-Path $WarningLog) 318 | { 319 | IF ($EHID -eq $null) { $EHID = "200" } 320 | $EHCategory = "Warning" 321 | $EHMessage += "Backup completed with Warnings. Targetpath: $BackupPath" 322 | $EHMessage += "--- WARNINGLOG $WarningLog ---" 323 | $EHMessage += Get-Content $WarningLog 324 | } 325 | ELSEIF (Test-Path $InfoLog) 326 | { 327 | IF ($EHID -eq $null) { $EHID = "101" } 328 | $EHCategory = "Information" 329 | $EHMessage += "Backup completed only with Informations. Targetpath: $BackupPath" 330 | $EHMessage += "--- INFOLOG $InfoLog ---" 331 | $EHMessage += Get-Content $InfoLog 332 | } 333 | ELSE 334 | { 335 | IF ($EHID -eq $null) { $EHID = "100" } 336 | $EHCategory = "Information" 337 | $EHMessage += "Backup completed. Targetpath: $BackupPath" 338 | } 339 | 340 | IF ($testerrorwarning -eq $true) { $EHID = "301" ; $EHCategory = "Error" ; $EHMessage += "Test Error with Warnings" } 341 | ELSEIF ($testerror -eq $true) { $EHID = "300" ; $EHCategory = "Error" ; $EHMessage += "Test Error" } 342 | ELSEIF ($testwarning -eq $true) { $EHID = "200" ; $EHCategory = "Warning" ; $EHMessage += "Test Warning" } 343 | $Message = $EHMessage | Out-String 344 | IF ($EHCategory -like "Error" -or $EHCategory -like "Warning") { Write-Warning $Message } 345 | ELSE { Write-output $Message } 346 | 347 | 348 | Write-Verbose "Check Admin privilages for creation of the EventLog entries" 349 | ### Proof for administrative permissions (UAC) and start EventLog Handling 350 | If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( [Security.Principal.WindowsBuiltInRole] "Administrator")) 351 | { 352 | Write-Warning "Not run as administrator, eventlog handling will be disabled." 353 | } ELSE { 354 | $skipeventlog = $false 355 | Try 356 | { 357 | Write-verbose "Check for Eventlog source" 358 | ( Get-EventLog -LogName Application -Source "GPObackup").count -ge 0 | Out-Null 359 | } 360 | Catch 361 | { 362 | Write-Verbose "Eventlog Source >GPObackup< not found. Try to create" 363 | "Eventlog Source >GPObackup< not found. Try to create" | Out-File $InfoLog -Append 364 | Try 365 | { 366 | New-EventLog -LogName Application -Source "GPObackup" 367 | } 368 | catch 369 | { 370 | write-warning "Creating EventLog category failed, cancel eventlog handling" 371 | "Creating EventLog category failed, cancel eventlog handling"| Out-file $ErrorLog -Append 372 | $skipeventlog = $true 373 | } 374 | } 375 | IF ( $skipeventlog -eq $false) 376 | { 377 | write-eventlog -logname Application -source "GPObackup" -EventId $EHID -EntryType $EHCategory -Message $Message 378 | Write-verbose "Eventlog entry written." 379 | ### Add for verbose 380 | IF ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { Get-EventLog -LogName Application -Source "GPObackup" -Newest 1 | Format-List } 381 | } 382 | } 383 | 384 | $after = Get-Date 385 | 386 | $time = $after - $before 387 | $buildTime = "`nBuild finished in "; 388 | if ($time.Minutes -gt 0) 389 | { 390 | $buildTime += "{0} minute(s) " -f $time.Minutes; 391 | } 392 | 393 | $buildTime += "{0} second(s)" -f $time.Seconds; 394 | Write-verbose $buildTime 395 | Write-verbose "Done. Have a nice day!" 396 | --------------------------------------------------------------------------------