├── Packer ├── .gitignore ├── README.md ├── Setup │ ├── vmtools.cmd │ ├── Enable-WinRM.ps1 │ └── autounattend.xml ├── Scripts │ ├── Invoke-SystemUpdate.ps1 │ ├── Set-TimeZone.ps1 │ ├── Install-Chocolatey.ps1 │ ├── Install-BoxStarter.ps1 │ ├── Set-ChocolateySettings.ps1 │ ├── Invoke-Cleanup.ps1 │ └── Invoke-SystemCleanup.ps1 ├── ConfigurationFiles │ └── server-2016.json └── Invoke-TemplateBuild.ps1 ├── Plex ├── 4k_logo.jpg ├── readme.md └── plexfunctions.psm1 ├── Security ├── README.MD ├── Test-SecurityHardening.ps1 ├── Tests │ └── security.tests.ps1 └── Get-TLSSetting.ps1 ├── .gitignore ├── WindowsUpdates ├── Update-OSDModule.ps1 ├── Install-PSWindowsUpdate.ps1 ├── Get-PendingWindowsUpdate.ps1 ├── Install-WinUpdatesDependencies.ps1 └── Install-AllTheUpdates.ps1 ├── IntuneDevices ├── Get-AllMsolDevices.ps1 ├── Get-AADRegistered.ps1 ├── Get-HybridAADJoinDevicesPending.ps1 ├── Get-AllAADDevices.ps1 ├── Get-NonHybridAADJoinDevices.ps1 ├── Get-HybridAADJoinDevices.ps1 └── Get-DsRegStatus.ps1 ├── README.md ├── Transmission ├── automation.ps1 └── transmission.ps1 ├── Exchange ├── Get-LargeMailboxes.ps1 ├── Get-X500Errors.ps1 ├── Get-MigrationStats.ps1 └── Get-AutoForwards.ps1 ├── Utilities ├── Publish-ToRepo.ps1 ├── Get-DotNetCoreVersion.ps1 ├── Update-AllModules.ps1 ├── Get-LocalAdmins.ps1 ├── Get-PortProcess.ps1 ├── Test-ConnectionASync.ps1 ├── Get-InstalledSoftware.ps1 └── Get-PortCertificate.ps1 ├── Active Directory ├── Get-AllDCs.ps1 ├── Get-ADServers.ps1 ├── Get-2016Servers.ps1 ├── Get-2008R2Servers.ps1 ├── Get-2012R2Servers.ps1 ├── Get-LDAPSigning.ps1 ├── Get-RecentlyBuiltServers.ps1 └── Convert-SidtoUsername.ps1 ├── Get-PercentChange.ps1 ├── Windows ├── Get-PowerShellVersion.ps1 ├── Get-RecentlyLoggedOnUsers.ps1 ├── Get-W10OS.ps1 ├── Install-DotNet35.ps1 ├── Get-GroupMembership.ps1 ├── Get-DotNetFrameworkVersion.ps1 ├── Update-2016ISO.ps1 ├── Get-FileSharePermissions.ps1 └── Install-VCRuntime.ps1 ├── Jenkins └── Submit-JenkinsJob.ps1 ├── GitHub └── Update-GitWebhook.ps1 ├── Solarwinds └── Invoke-SolarwindsQuery.ps1 ├── VMware ├── Install-VMwareTools.ps1 └── Build-VM.ps1 ├── MigrationWiz ├── Set-MigWizToken.ps1 ├── Submit-MigWizPreStage.ps1 ├── Get-MigWizMailboxError.ps1 ├── Get-MigWizStats.ps1 ├── New-MigWizProject.ps1 └── Add-MigWizProject.ps1 ├── Search-RedditPatchTuesday.ps1 ├── RingCentral └── Get-RingCentralStatus.ps1 ├── Samanage ├── New-Ticket.ps1 ├── Get-Hardware.ps1 └── Remove-OldComputers.ps1 ├── JIRA └── scratchpad.ps1 ├── ConvertTo-Markdown.ps1 ├── Office └── Install-OfficeUpdates.ps1 └── TLS └── TLS.ps1 /Packer/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Packer/README.md: -------------------------------------------------------------------------------- 1 | # Packer 2 | Repository for Packer Files 3 | -------------------------------------------------------------------------------- /Plex/4k_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jwmoss/powershell_scripts/HEAD/Plex/4k_logo.jpg -------------------------------------------------------------------------------- /Packer/Setup/vmtools.cmd: -------------------------------------------------------------------------------- 1 | @rem Silent mode, basic UI, no reboot 2 | e:\setup64 /s /v "/qb REBOOT=R" -------------------------------------------------------------------------------- /Packer/Scripts/Invoke-SystemUpdate.ps1: -------------------------------------------------------------------------------- 1 | Install-WindowsUpdate -getUpdatesFromMS -acceptEula -SuppressReboots -------------------------------------------------------------------------------- /Packer/Scripts/Set-TimeZone.ps1: -------------------------------------------------------------------------------- 1 | Write-Output "Setting the timezone to EST" 2 | 3 | Set-TimeZone -Name "Eastern Standard Time" -------------------------------------------------------------------------------- /Security/README.MD: -------------------------------------------------------------------------------- 1 | # Links 2 | 3 | * [Setting Perfect Secrecy and TLS 1.2 Windows](https://www.hass.de/content/setup-microsoft-windows-or-iis-ssl-perfect-forward-secrecy-and-tls-12) -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | FinnHubTokens.json 2 | dailystonk.ps1 3 | stockresearch.ps1 4 | /Plex/scratchpad.ps1 5 | /Transmission/token.txt 6 | /Transmission/url.txt 7 | .vscode 8 | Transmission/scratchpad.ps1 -------------------------------------------------------------------------------- /WindowsUpdates/Update-OSDModule.ps1: -------------------------------------------------------------------------------- 1 | function Update-OSDModule { 2 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 3 | Uninstall-Module -Name OSDSUS -AllVersions -Force 4 | Install-Module -Name OSDSUS -Force 5 | } -------------------------------------------------------------------------------- /Packer/Scripts/Install-Chocolatey.ps1: -------------------------------------------------------------------------------- 1 | # Installs Chocolatey 2 | Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) 3 | # Forces an exit 0 due to the chocolatey installer. If chocolatey fails to install as expected, this will fail on the first choco install function. 4 | Exit 0 -------------------------------------------------------------------------------- /IntuneDevices/Get-AllMsolDevices.ps1: -------------------------------------------------------------------------------- 1 | function Get-AllMsolDevices { 2 | [CmdletBinding()] 3 | param ( 4 | 5 | ) 6 | 7 | begin { 8 | 9 | } 10 | 11 | process { 12 | Get-MsolDevice -All -IncludeSystemManagedDevices | Where-Object {$PSItem.DeviceOsType -match "Windows"} 13 | } 14 | 15 | end { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /IntuneDevices/Get-AADRegistered.ps1: -------------------------------------------------------------------------------- 1 | function Get-AADRegistered { 2 | [CmdletBinding()] 3 | param ( 4 | [PSObject] 5 | $Devices 6 | ) 7 | 8 | begin { 9 | 10 | } 11 | 12 | process { 13 | $Devices | 14 | Where-Object {$PSItem.DeviceTrustType -eq "Workplace Joined"} 15 | } 16 | 17 | end { 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /IntuneDevices/Get-HybridAADJoinDevicesPending.ps1: -------------------------------------------------------------------------------- 1 | function Get-HybridAADJoinDevicesPending { 2 | [CmdletBinding()] 3 | param ( 4 | [PSObject] 5 | $Devices 6 | ) 7 | 8 | begin { 9 | 10 | } 11 | 12 | process { 13 | $Devices | 14 | Where-Object {($null -eq $_.DeviceTrustType)} 15 | } 16 | 17 | end { 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /IntuneDevices/Get-AllAADDevices.ps1: -------------------------------------------------------------------------------- 1 | function Get-AllAADDevices { 2 | [CmdletBinding()] 3 | param ( 4 | 5 | ) 6 | 7 | begin { 8 | Get-AzureADDevice -All $true | 9 | Where-Object {$PSItem.deviceOSType -match "Windows"} | 10 | Select-object * 11 | } 12 | 13 | process { 14 | 15 | } 16 | 17 | end { 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IntuneDevices/Get-NonHybridAADJoinDevices.ps1: -------------------------------------------------------------------------------- 1 | function Get-NonHybridAADJoinDevices { 2 | [CmdletBinding()] 3 | param ( 4 | [PSObject] 5 | $Devices 6 | ) 7 | 8 | begin { 9 | 10 | } 11 | 12 | process { 13 | $Devices | 14 | Where-Object {$PSItem.DeviceTrustType -ne "Domain Joined"} 15 | } 16 | 17 | end { 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /Security/Test-SecurityHardening.ps1: -------------------------------------------------------------------------------- 1 | function Test-SecurityHardening { 2 | [CmdletBinding()] 3 | param ( 4 | [switch] 5 | $Passthru 6 | ) 7 | 8 | process { 9 | if ($Passthru) { 10 | Invoke-Pester -Script "$PSScriptRoot\Tests\security.tests.ps1" -PassThru 11 | } 12 | else { 13 | Invoke-Pester -Script "$PSScriptRoot\Tests\security.tests.ps1" 14 | } 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Powershell Scripts 2 | 3 | This repository hosts powershell scripts that I've developed in the last few years. 4 | 5 | ## Getting Started 6 | 7 | The easiest way to get started using these scripts is to clone the repository to your local machine. 8 | 9 | ```bash 10 | git clone https://github.com/jwmoss/powershell_scripts.git 11 | ``` 12 | 13 | ## Contact me 14 | 15 | * Email: jwmoss88@gmail.com 16 | 17 | Pull requests welcome! 18 | -------------------------------------------------------------------------------- /IntuneDevices/Get-HybridAADJoinDevices.ps1: -------------------------------------------------------------------------------- 1 | function Get-HybridAADJoinDevices { 2 | [CmdletBinding()] 3 | param ( 4 | [PSObject] 5 | $Devices 6 | ) 7 | 8 | begin { 9 | 10 | } 11 | 12 | process { 13 | $Devices | 14 | Where-Object {($_.DeviceTrustType -eq 'Domain Joined') -and (([string]($_.AlternativeSecurityIds)).StartsWith("X509:"))} 15 | } 16 | 17 | end { 18 | 19 | } 20 | } -------------------------------------------------------------------------------- /Transmission/automation.ps1: -------------------------------------------------------------------------------- 1 | . (Join-Path -Path ($ENV:HOME) -ChildPath "powershell_scripts" -AdditionalChildPath "Transmission", "transmission.ps1") 2 | 3 | $token = get-content (Join-Path -Path ($ENV:HOME) -ChildPath "powershell_scripts" -AdditionalChildPath "Transmission", "token.txt") 4 | $securePwd = ConvertTo-SecureString $token -AsPlainText -Force 5 | $credential = New-Object System.Management.Automation.PSCredential ("jwmoss", $securePwd) 6 | 7 | Get-Torrent -Credential $Credential -------------------------------------------------------------------------------- /Exchange/Get-LargeMailboxes.ps1: -------------------------------------------------------------------------------- 1 | function Get-LargeMailboxes { 2 | $Mailboxes = Get-Mailbox -ResultSize Unlimited | Get-MailboxStatistics 3 | foreach ($mailbox in $Mailboxes) { 4 | [pscustomobject]@{ 5 | Displayname = $mailbox.DisplayName 6 | TotalItemSizeinMB = [math]::Round(($mailbox.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",", "") / 1MB), 0) 7 | ItemCount = $mailbox.itemCount 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /Utilities/Publish-ToRepo.ps1: -------------------------------------------------------------------------------- 1 | function Publish-ToRepo { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $Psd1Path, 6 | 7 | [string] 8 | $RepositoryName, 9 | 10 | [string] 11 | $Token 12 | ) 13 | 14 | $splat = @{ 15 | Name = $Psd1Path 16 | Repository = $RepositoryName 17 | Verbose = $true 18 | NugetAPIKey = $Token 19 | } 20 | 21 | Publish-Module @splat 22 | 23 | } -------------------------------------------------------------------------------- /Active Directory/Get-AllDCs.ps1: -------------------------------------------------------------------------------- 1 | 2 | Function Get-AllDCs { 3 | Get-ADDomainController -filter * | Select-Object Name, Operatingsystem, Domain, Site | ForEach-Object { 4 | $ipaddress = resolve-dnsname $_.Name -ErrorAction SilentlyContinue 5 | [PSCustomObject]@{ 6 | Name = $_.Name 7 | IP = $ipaddress.IPAddress 8 | OS = $_.OperatingSystem 9 | Domain = $_.Domain 10 | Site = $_.Site 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Get-PercentChange.ps1: -------------------------------------------------------------------------------- 1 | function Get-PercentChange { 2 | [Alias("gpc")] 3 | [CmdletBinding()] 4 | param ( 5 | [string] 6 | $Begin = 6.92, 7 | 8 | [string] 9 | $End = 8.60, 10 | 11 | [string] 12 | $Investment = 725.10 13 | ) 14 | 15 | [PSCustomObject]@{ 16 | Percentage = [int32](($End - $Begin) / $Begin * 100) 17 | Profit = (([int32](($End - $Begin) / $Begin * 100)) / 100) * $Investment 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Windows/Get-PowerShellVersion.ps1: -------------------------------------------------------------------------------- 1 | function Get-PowerShellVersion { 2 | [CmdletBinding()] 3 | param ( 4 | [string[]] 5 | $ComputerName 6 | ) 7 | 8 | begin { 9 | $Session = New-PSSession -ComputerName $ComputerName 10 | } 11 | 12 | process { 13 | Invoke-Command -Session $Session -ScriptBlock { 14 | $PSVersionTable.PSVersion 15 | } 16 | } 17 | 18 | end { 19 | Get-PSSession | Remove-PSSession 20 | } 21 | } -------------------------------------------------------------------------------- /Packer/Scripts/Install-BoxStarter.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs Boxstarter from their website 4 | .NOTES 5 | Performs an installation of the most recent stable version of Boxstarter. 6 | #> 7 | 8 | $PackageName = "boxstarter" 9 | 10 | Try { 11 | . { Invoke-WebRequest -UseBasicParsing https://boxstarter.org/bootstrapper.ps1 } | Invoke-Expression; get-boxstarter -Force 12 | } 13 | Catch { 14 | Write-Host "Fatal erorr installing package $PackageName. Exiting." 15 | Exit 1 16 | } -------------------------------------------------------------------------------- /Active Directory/Get-ADServers.ps1: -------------------------------------------------------------------------------- 1 | function Get-ADServers { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $Domain 6 | ) 7 | 8 | Get-ADComputer -Filter { OperatingSystem -like "*Windows Server*" } -Properties OperatingSystem -Server $domain | ForEach-Object { 9 | [pscustomobject]@{ 10 | DNS = $_.DNSHostName 11 | OS = $_.OperatingSystem 12 | OU = ([regex]::match($_.distinguishedName, '(?=OU)(.*\n?)(?<=.)').Value) 13 | } 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /Utilities/Get-DotNetCoreVersion.ps1: -------------------------------------------------------------------------------- 1 | function Get-DotNetCoreVersion { 2 | [CmdletBinding()] 3 | param ( 4 | [String[]] 5 | $ComputerName = $ENV:ComputerName 6 | ) 7 | 8 | process { 9 | Invoke-Command -ComputerName $ComputerName -ScriptBlock { 10 | $d = dotnet --info 11 | [PSCustomobject]@{ 12 | ComputerName = $ENV:COMPUTERNAME 13 | DotNetVersion = $d[2].Trim() 14 | AspNetCore = $d[9].Trim() 15 | Netcore = $d[10].Trim() 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Jenkins/Submit-JenkinsJob.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module Jenkins 2 | function Submit-JenkinsJob { 3 | [CmdletBinding()] 4 | param ( 5 | [pscredential] 6 | $Credential, 7 | 8 | [string] 9 | $Username, 10 | 11 | [string] 12 | $JenkinsURL, 13 | 14 | [string] 15 | $Folder, 16 | 17 | [string] 18 | $Name 19 | ) 20 | $job = @{ 21 | URI = $JenkinsURL 22 | Credential = $Credential 23 | Folder = $Folder 24 | Name = $Name 25 | Verbose = $True 26 | } 27 | 28 | Invoke-JenkinsJob @job 29 | } -------------------------------------------------------------------------------- /Exchange/Get-X500Errors.ps1: -------------------------------------------------------------------------------- 1 | function Get-X500Error { 2 | <# 3 | .SYNOPSIS 4 | Get's all mailboxes with X500 errors. 5 | .EXAMPLE 6 | PS C:\> Get-X500Errors 7 | .NOTES 8 | Opens a powershell remoting session to the exchange server, searches message tracking for IMCEAEX errors. 9 | #> 10 | 11 | $servers = (Get-TransportServer).Name 12 | 13 | foreach ($server in $servers) { 14 | Invoke-Command -scriptblock { Get-MessageTrackinglog -EventID FAIL -Start (Get-Date).AddDays(-7) -ResultSize Unlimited -Server $server | Where-Object { $psitem.Recipients -match "^IMCEAEX*" } } -ArgumentList $server 15 | } 16 | } -------------------------------------------------------------------------------- /Packer/Scripts/Set-ChocolateySettings.ps1: -------------------------------------------------------------------------------- 1 | Try 2 | { 3 | # Set Default Chocolatey Settings 4 | 5 | # Set global confirmation 6 | choco feature enable -n allowGlobalConfirmation 7 | 8 | # Allow empty checksums for HTTPS 9 | choco feature enable -n allowemptychecksumsecure 10 | 11 | # Disable package exit codes 12 | choco feature disable -n usePackageExitCodes 13 | 14 | # Disable animated download progress bar 15 | choco feature disable -n showDownloadProgress 16 | 17 | } 18 | Catch 19 | { 20 | Write-Host "Error occurred. Exiting." 21 | Write-Host $_.Exception | format-list -force 22 | Exit 1 23 | } 24 | -------------------------------------------------------------------------------- /Windows/Get-RecentlyLoggedOnUsers.ps1: -------------------------------------------------------------------------------- 1 | Function Get-RecentlyLoggedOnUsers { 2 | [cmdletbinding()] 3 | param ( 4 | [parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] 5 | [string[]] 6 | $ComputerName 7 | ) 8 | 9 | $output = Invoke-Command -ComputerName $computername -ScriptBlock { 10 | get-ChildItem -Path "C:\Users\*\AppData\Local\Microsoft\Windows\UsrClass.dat" -Force | Select-Object @{Label = "User"; Expression = {($_.directory).tostring().split("\")[2]}}, LastWriteTime 11 | } 12 | 13 | $output | Sort-Object LastWriteTime -Descending 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Active Directory/Get-2016Servers.ps1: -------------------------------------------------------------------------------- 1 | function Get-2016Servers { 2 | [cmdletbinding()] 3 | Param ( 4 | [string] 5 | $Domain 6 | ) 7 | 8 | $filter = 'OperatingSystem -like "{0}"' -f "*2016*" 9 | 10 | $properties = @( 11 | 'Name', 12 | 'Enabled', 13 | 'PasswordLastSet', 14 | 'DNSHostName', 15 | 'Description', 16 | 'CanonicalName', 17 | 'OperatingSystem', 18 | 'ManagedBy' 19 | ) 20 | 21 | $ADComputerSplat = @{ 22 | Filter = $filter 23 | Properties = $properties 24 | Server = $domain 25 | } 26 | 27 | Get-ADComputer @ADComputerSplat 28 | 29 | } -------------------------------------------------------------------------------- /Utilities/Update-AllModules.ps1: -------------------------------------------------------------------------------- 1 | function Update-AllModules { 2 | Get-Module -ListAvailable | 3 | Where-Object { $_.Path -like "C:\Program Files\WindowsPowerShell\Modules*" } | 4 | ForEach-Object { 5 | $currentVersion = [Version] $_.Version 6 | $newVersion = [Version] (Find-Module -Name $_.Name -Repository "PSGallery").Version 7 | if ($newVersion -gt $currentVersion) { 8 | Write-Host -Object "Updating $_ Module from $currentVersion to $newVersion" 9 | Update-Module -Name $_.Name -RequiredVersion $newVersion -Force 10 | Uninstall-Module -Name $_.Name -RequiredVersion $currentVersion -Force 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /Active Directory/Get-2008R2Servers.ps1: -------------------------------------------------------------------------------- 1 | function Get-2008R2Servers { 2 | [cmdletbinding()] 3 | Param ( 4 | [string] 5 | $Domain 6 | ) 7 | 8 | $filter = 'OperatingSystem -like "{0}"' -f "*2008*" 9 | 10 | $properties = @( 11 | 'Name', 12 | 'Enabled', 13 | 'PasswordLastSet', 14 | 'DNSHostName', 15 | 'Description', 16 | 'CanonicalName', 17 | 'OperatingSystem', 18 | 'ManagedBy' 19 | ) 20 | 21 | $ADComputerSplat = @{ 22 | Filter = $filter 23 | Properties = $properties 24 | Server = $domain 25 | } 26 | 27 | Get-ADComputer @ADComputerSplat 28 | 29 | } -------------------------------------------------------------------------------- /Active Directory/Get-2012R2Servers.ps1: -------------------------------------------------------------------------------- 1 | function Get-2012R2Servers { 2 | [cmdletbinding()] 3 | Param ( 4 | [string] 5 | $Domain 6 | ) 7 | 8 | $filter = 'OperatingSystem -like "{0}"' -f "*2012*" 9 | 10 | $properties = @( 11 | 'Name', 12 | 'Enabled', 13 | 'PasswordLastSet', 14 | 'DNSHostName', 15 | 'Description', 16 | 'CanonicalName', 17 | 'OperatingSystem', 18 | 'ManagedBy' 19 | ) 20 | 21 | $ADComputerSplat = @{ 22 | Filter = $filter 23 | Properties = $properties 24 | Server = $domain 25 | } 26 | 27 | Get-ADComputer @ADComputerSplat 28 | 29 | } -------------------------------------------------------------------------------- /Active Directory/Get-LDAPSigning.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module PSWinReporting 2 | function Get-LDAPSigning { 3 | [CmdletBinding()] 4 | param ( 5 | 6 | ) 7 | 8 | (Find-Events -Report LdapBindingsDetails,LdapBindingsSummary -DatesRange Last7days -DetectDC).LdapBindingsDetails | ForEach-Object { 9 | $user = ($_."Account Name" -split "\\")[1] 10 | $ADuser = Get-ADUser -Identity $user -Properties * 11 | [pscustomobject]@{ 12 | User = $user 13 | Description = $ADuser.Description 14 | Manager = $ADUser.manager 15 | Action = $_.Action 16 | DomainController = $_."Domain Controller" 17 | } 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /Active Directory/Get-RecentlyBuiltServers.ps1: -------------------------------------------------------------------------------- 1 | function Get-RecentlyBuiltServers { 2 | [cmdletbinding()] 3 | Param ( 4 | [string] 5 | $Domain 6 | ) 7 | 8 | $When = ((Get-Date).AddDays(-31)).Date 9 | 10 | $filter = { whenCreated -ge $When -and OperatingSystem -like "*Server*" } 11 | 12 | $adproperties = @( 13 | 'PasswordLastSet', 14 | 'Description', 15 | 'WhenCreated', 16 | 'OperatingSystem', 17 | 'Managedby' 18 | ) 19 | 20 | $ComputerSplat = @{ 21 | Filter = $filter 22 | Properties = $adproperties 23 | Server = $domain 24 | } 25 | 26 | Get-ADComputer @ComputerSplat 27 | 28 | } -------------------------------------------------------------------------------- /Packer/Scripts/Invoke-Cleanup.ps1: -------------------------------------------------------------------------------- 1 | # JetBrains Packer plugin seems to be leaving remnant tasks in Task Scheduler. Check for tasks and delete any that start with the name Packer. 2 | $PackerTasks = get-scheduledtask -TaskName Packer* 3 | if ($PackerTasks) { 4 | try { 5 | Write-Output "One or more Packer tasks found in Task Scheduler." 6 | Write-Output "Deleting the following task(s): $($PackerTasks.taskname)" 7 | $PackerTasks | unregister-scheduledtask -confirm:$false -ErrorAction Stop 8 | } 9 | catch { 10 | Write-Output "Error occurred when the cleanup.ps1 script attempted to unregister remnant Packer* tasks. Please investigate." 11 | } 12 | } 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /IntuneDevices/Get-DsRegStatus.ps1: -------------------------------------------------------------------------------- 1 | function Get-DsRegStatus { 2 | <# 3 | .Synopsis 4 | Returns the output of dsregcmd /status as a PSObject. 5 | 6 | .Description 7 | Returns the output of dsregcmd /status as a PSObject. All returned values are accessible by their property name. 8 | 9 | .Example 10 | # Displays a full output of dsregcmd / status. 11 | Get-DsRegStatus 12 | #> 13 | $dsregcmd = dsregcmd /status 14 | $o = New-Object -TypeName PSObject 15 | $dsregcmd | Select-String -Pattern " *[A-z]+ : [A-z]+ *" | ForEach-Object { 16 | Add-Member -InputObject $o -MemberType NoteProperty -Name (([String]$_).Trim() -split " : ")[0] -Value (([String]$_).Trim() -split " : ")[1] 17 | } 18 | return $o 19 | } -------------------------------------------------------------------------------- /Utilities/Get-LocalAdmins.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module PoshRSJob 2 | function Get-LocalAdmins { 3 | 4 | [CmdletBinding()] 5 | param ( 6 | [Parameter()] 7 | [string[]] 8 | $ComputerName 9 | ) 10 | 11 | Start-RSJob -InputObject $computername -Throttle "20" -ScriptBlock { 12 | Invoke-Command -ComputerName $_ -ScriptBlock { 13 | $members = net localgroup administrators | where {$_ -AND $_ -notmatch "command completed successfully"} | select -skip 4 14 | New-Object PSObject -Property @{ 15 | Computername = $env:COMPUTERNAME 16 | Group = "Administrators" 17 | Members = $members 18 | } 19 | } 20 | } | Wait-RSJob -ShowProgress -Timeout 60 | Receive-RSJob 21 | } -------------------------------------------------------------------------------- /GitHub/Update-GitWebhook.ps1: -------------------------------------------------------------------------------- 1 | function Update-GitWebhook { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $WebhookURL, 6 | 7 | [string] 8 | $Token, 9 | 10 | [string] 11 | $NewWebhookURL 12 | ) 13 | 14 | begin { 15 | $headers = @{ 16 | "Accept" = "application/vnd.github.v3+json" 17 | "Authorization" = "token $token" 18 | } 19 | } 20 | 21 | process { 22 | ## create the new one 23 | $body = @{ 24 | config = @{ 25 | url = $NewWebhookURL 26 | } 27 | } 28 | 29 | Invoke-RestMethod -Uri $WebhookURL -Body ($body | ConvertTo-Json) -Method Patch -Headers $headers 30 | } 31 | 32 | end { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /WindowsUpdates/Install-PSWindowsUpdate.ps1: -------------------------------------------------------------------------------- 1 | function Install-PSWindowsupdate { 2 | [CmdletBinding()] 3 | param ( 4 | [string[]] 5 | $Computername 6 | ) 7 | 8 | begin { 9 | 10 | } 11 | 12 | process { 13 | Invoke-Command -ComputerName $Computername -ScriptBlock { 14 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 15 | if (-not (Get-Module PSWindowsUpdate)) { 16 | Get-PackageProvider -Name Nuget -ForceBootstrap | Out-Null 17 | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted 18 | Set-ExecutionPolicy Unrestricted 19 | Install-Module -Name PSWindowsUpdate 20 | } 21 | } 22 | } 23 | 24 | end { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Solarwinds/Invoke-SolarwindsQuery.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-SolarWindsQuery { 2 | [CmdletBinding()] 3 | param ( 4 | [hashtable] 5 | $Body = @{query = "SELECT Caption, IPAddress FROM Orion.Nodes" }, 6 | 7 | [PSCredential] 8 | $Credential, 9 | 10 | [string] 11 | $URL 12 | ) 13 | 14 | $Headers = @{ 15 | "Content-Type" = "application/json" 16 | } 17 | 18 | $splat = @{ 19 | uri = "$($URL):17778/Solarwinds/InformationService/v3/Json/Query" 20 | ContentType = "application/json" 21 | Credential = $Credential 22 | Body = $Body | ConvertTo-Json 23 | Headers = $Headers 24 | Authentication = "Basic" 25 | Method = "POST" 26 | } 27 | 28 | ((Invoke-WebRequest @splat).Content | ConvertFrom-Json).results 29 | } -------------------------------------------------------------------------------- /Windows/Get-W10OS.ps1: -------------------------------------------------------------------------------- 1 | function Get-W10OS { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter( 5 | ValueFromPipeline, 6 | ValueFromPipelineByPropertyName 7 | )] 8 | [string] 9 | $ID 10 | ) 11 | 12 | begin { 13 | 14 | } 15 | 16 | process { 17 | Switch -WildCard ($ID) { 18 | '*19042*' { "20H2" } 19 | '*19041*' { "2004" } 20 | '*18363*' { "1909" } 21 | '*18362*' { "1903" } 22 | '*17763*' { "1809" } 23 | '*17134*' { "1803" } 24 | '*16299*' { "1709" } 25 | '*15063*' { "1703" } 26 | '*14393*' { "1607" } 27 | '*10586*' { "1511" } 28 | Default { "Failed" } 29 | } # End of Switch 30 | } 31 | 32 | end { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /VMware/Install-VMwareTools.ps1: -------------------------------------------------------------------------------- 1 | function Install-VMwareTools { 2 | [CmdletBinding()] 3 | param ( 4 | [string[]] 5 | $ComputerName = $ENV:COMPUTERNAME 6 | ) 7 | 8 | Invoke-Command -ComputerName $ComputerName -ScriptBlock { 9 | 10 | $ErrorActionPreference = 'Stop' 11 | $url64 = 'https://packages.vmware.com/tools/releases/11.2.0/windows/x64/VMware-tools-11.2.0-16938113-x86_64.exe' 12 | 13 | $packageArgs = @{ 14 | url64bit = $url64 15 | validExitCodes = @(0) 16 | silentArgs = '/S /v /qn REBOOT=R' 17 | softwareName = 'VMware Tools' 18 | } 19 | 20 | Invoke-WebRequest -Uri $url64 -OutFile "$env:TEMP\vmwaretools.exe" 21 | 22 | Start-Process -FilePath "$env:TEMP\vmwaretools.exe" -ArgumentList $packageArgs.silentArgs -Wait -NoNewWindow 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Exchange/Get-MigrationStats.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MigrationStats { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $MWName, 6 | 7 | [string] 8 | $UPN 9 | ) 10 | 11 | ## Select just what we want from $results 12 | $PropertyArray = @( 13 | "Displayname", 14 | "Status", 15 | "StatusDetail", 16 | "SourceServer", 17 | "BatchName", 18 | "OverallDuration", 19 | "TotalMailboxSize", 20 | "BytesTransferred", 21 | "PercentComplete" 22 | ) 23 | 24 | Connect-ExchangeOnline -UserPrincipalName $UPN -ShowProgress $true 25 | 26 | ## List Mailbox Move Requests that are not completed 27 | Get-Moverequest | Where-Object { $psitem.Status -notmatch "completed" } | Get-MoveRequestStatistics | Select-Object -Property $PropertyArray 28 | 29 | Get-PSSession | Remove-PSSession 30 | } 31 | -------------------------------------------------------------------------------- /Exchange/Get-AutoForwards.ps1: -------------------------------------------------------------------------------- 1 | function Get-AutoForwards { 2 | [CmdletBinding()] 3 | param ( 4 | 5 | ) 6 | 7 | $UserForwards = Get-Mailbox -Filter { ForwardingAddress -like "*" } | Select-Object * 8 | 9 | foreach ($user in $UserForwards) { 10 | $contactinfo = Get-Recipient -Identity $User.ForwardingAddress | Select-Object * 11 | if ($contactinfo.RecipientType -eq "UserMailbox") { 12 | [PSCustomObject]@{ 13 | PrimarySMTPAddress = $user.PrimarySMTPAddress 14 | PrimarySMTPAddressMailboxSource = $domain 15 | ForwardingEmailAddress = $contactinfo.PrimarySMTPAddress 16 | ForwardingEmailDomain = ($contactinfo.PrimarySMTPAddress -split '@')[1] 17 | ForwardingEmailRecipientType = $contactinfo.RecipientType 18 | ForwardingEmailAddressName = $contactinfo.Name 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MigrationWiz/Set-MigWizToken.ps1: -------------------------------------------------------------------------------- 1 | function Set-MigWizToken { 2 | 3 | <# 4 | .SYNOPSIS 5 | Short description 6 | .DESCRIPTION 7 | Long description 8 | .EXAMPLE 9 | PS C:\> 10 | Explanation of what the example does 11 | .INPUTS 12 | Inputs (if any) 13 | .OUTPUTS 14 | Output (if any) 15 | .NOTES 16 | I'm lazy and storing the token in the global scope. 17 | #> 18 | 19 | [CmdletBinding()] 20 | param ( 21 | [ValidateNotNull()] 22 | [System.Management.Automation.PSCredential] 23 | [System.Management.Automation.Credential()] 24 | $Credential 25 | ) 26 | 27 | process { 28 | Write-Verbose "Setting up session to Migration Wiz" 29 | $rightnow = (Get-Date).ToUniversalTime() 30 | if (($null -eq $global:mwticket) -and ($global:mwticket.ExpirationDate -lt $rightnow)) { 31 | $global:mwticket = Get-MW_Ticket -Credentials $Credential 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Packer/Setup/Enable-WinRM.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | # Enable WinRM service 4 | winrm quickconfig -quiet 5 | winrm set winrm/config/service '@{AllowUnencrypted="true"}' 6 | winrm set winrm/config/service/auth '@{Basic="true"}' 7 | winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="2048"}' 8 | winrm set winrm/config/winrs '@{MaxConcurrentUsers="100"}' 9 | winrm set winrm/config/winrs '@{MaxProcessesPerShell="0"}' 10 | winrm set winrm/config/winrs '@{MaxShellsPerUser="0"}' 11 | winrm set winrm/config '@{MaxTimeoutms="7200000"}' 12 | winrm set winrm/config/service/auth '@{CredSSP="true"}' 13 | winrm set winrm/config/client '@{TrustedHosts="*"}' 14 | 15 | # Allow WinRM 16 | netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow 17 | 18 | # Reset auto logon count 19 | # https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-autologon-logoncount#logoncount-known-issue 20 | Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' -Name AutoLogonCount -Value 0 -------------------------------------------------------------------------------- /WindowsUpdates/Get-PendingWindowsUpdate.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module Invoke-CommandAs,PSWindowsupdate 2 | Function Get-PendingWindowsUpdate { 3 | [CmdletBinding()] 4 | param ( 5 | [string[]] 6 | $Computername, 7 | 8 | [switch] 9 | $Online 10 | ) 11 | 12 | $Session = New-PSSession -ComputerName $Computername 13 | 14 | if ($Online) { 15 | Write-host "Checking for windows updates online" -ForegroundColor Cyan 16 | Invoke-CommandAs -Session $Session -Scriptblock { 17 | Import-Module PSWindowsupdate 18 | (Get-WUList -MicrosoftUpdate -Verbose).ForEach({$_ | Select-Object KB,ComputerName,Title}) 19 | } -AsSystem 20 | } 21 | else { 22 | Write-host "Checking for windows updates using WSUS" -ForegroundColor Cyan 23 | Invoke-CommandAs -Session $Session -Scriptblock { 24 | Import-Module PSWindowsupdate 25 | (Get-WUList -Verbose).ForEach({$_ | Select-Object KB,ComputerName,Title}) 26 | } -AsSystem 27 | } 28 | 29 | Get-PSSession | Remove-PSSession 30 | } -------------------------------------------------------------------------------- /Utilities/Get-PortProcess.ps1: -------------------------------------------------------------------------------- 1 | function Get-PortProcess { 2 | [CmdletBinding()] 3 | param ( 4 | [string[]] 5 | $Computername, 6 | 7 | [string] 8 | $Port 9 | ) 10 | 11 | Begin { 12 | $Session = New-PSSession -ComputerName $Computername 13 | } 14 | Process { 15 | Invoke-Command -Session $Session -ScriptBlock { 16 | Get-Process -Id (Get-NetTCPConnection -LocalPort $using:port).OwningProcess | ForEach-Object { 17 | [pscustomobject]@{ 18 | Name = $_.Name 19 | Path = $_.Path 20 | SHA256 = Get-FileHash -Path $_.Path | Select-Object -ExpandProperty Hash 21 | Port = $using:port 22 | Company = $_.Company 23 | ProductVersion = $_.ProductVersion 24 | Product = $_.Product 25 | Computer = $env:COMPUTERNAME 26 | } 27 | } 28 | } 29 | } 30 | End { 31 | 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /Search-RedditPatchTuesday.ps1: -------------------------------------------------------------------------------- 1 | Function Search-RedditPatchTuesday { 2 | ## Found this on Reddit, saving it for future use. Forgot where it was originally posted :( 3 | 4 | # Get a list of posts from reddit.com/r/sysadmin front page 5 | $posts = Invoke-RestMethod 'https://www.reddit.com/r/sysadmin/.json' 6 | 7 | # Get the URL for the patch tuesday megathread 8 | $megathread = $posts.data.children.data.Where{$_.title -like '*Patch Tuesday Megathread*'} 9 | $megathreadUrl = $megathread.Url 10 | 11 | # Get the comments of the megathread 12 | $comments = Invoke-RestMethod "$megathreadUrl.json" 13 | 14 | # Iterate through the comments, match any KB#######. Case insensitive, there can be any single character between KB and the numbers. 15 | $comments.data.children.data.ForEach{ 16 | $match = ([regex]'(?i)kb\d{7}|(?i)kb.\d{7}').Matches($_.body); 17 | if ($match.Value) { 18 | # Return a custom object with the data we want to see 19 | [PSCustomObject] @{ 20 | UpVotes = $_.ups 21 | KB = $match.Value -join ', ' 22 | Body = $_.body 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /RingCentral/Get-RingCentralStatus.ps1: -------------------------------------------------------------------------------- 1 | Function Get-RingCentralStatus { 2 | 3 | <# 4 | .SYNOPSIS 5 | Retrives Ring Central status from their website 6 | .DESCRIPTION 7 | Long description 8 | .EXAMPLE 9 | PS C:\> Get-RingCentralStatus -ShowOutput 10 | Gets the status and outputs a message 11 | .INPUTS 12 | Inputs (if any) 13 | .OUTPUTS 14 | Output (if any) 15 | .NOTES 16 | General notes 17 | #> 18 | 19 | [CmdletBinding()] 20 | param ( 21 | [Parameter()] 22 | [switch] 23 | $ShowOutput 24 | ) 25 | 26 | Begin { 27 | 28 | $URL = "https://status.ringcentral.com/status.json" 29 | } 30 | Process { 31 | $RingCentralServices = Invoke-RestMethod -Method Get -Uri $URL 32 | 33 | $RingCentral = $RingCentralServices | Where-Object {$psitem.region -eq "Americas" -and $psitem.Service -match "Calling|Meetings"} 34 | 35 | } 36 | End { 37 | if ($PSBoundParameters.ContainsKey('ShowOutput')) { 38 | foreach ($monitor in $RingCentral) { 39 | Write-Output "$($monitor.Service) - $($monitor.level)" 40 | } 41 | } 42 | else { 43 | $RingCentral 44 | } 45 | 46 | } 47 | } -------------------------------------------------------------------------------- /Active Directory/Convert-SidtoUsername.ps1: -------------------------------------------------------------------------------- 1 | 2 | Function Convert-SIDToUsername { 3 | <# 4 | .SYNOPSIS 5 | This cmdlet takes in SID and translate them to Domain UserID. 6 | .DESCRIPTION 7 | This cmdlet takes in SID and translate them to Domain UserID. 8 | .NOTES 9 | Author: Teng Yang 10 | .PARAMETER SIDs 11 | String object variable that takes in one SID or a group of many SID 12 | .EXAMPLE 13 | Convert-SIDToUsername -SIDs 'S-1-5-21-296299305-573448302-1760960739-35799' 14 | Convert-SIDToUsername -SIDs '$GroupOfSID' 15 | #> 16 | 17 | [CmdletBinding()] 18 | param ( 19 | [Parameter(Mandatory = $True)] 20 | [string[]] 21 | $SIDs 22 | ) 23 | 24 | Foreach ($SID in $SIDs) { 25 | Try { 26 | $SID = [System.Security.Principal.SecurityIdentifier]$SID 27 | $userID = $SID.Translate([System.Security.Principal.NTAccount]) 28 | $list = Select-Object -InputObject "" Name, SID 29 | $list.Name = $userID.value 30 | $list.SID = $SID.value 31 | $list 32 | } 33 | Catch { 34 | Write-Warning ("Unable to translate SID: $SID.") 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Windows/Install-DotNet35.ps1: -------------------------------------------------------------------------------- 1 | function Install-dotnet35 { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $ComputerName, 6 | 7 | [string] 8 | $ISOPATH, 9 | 10 | [string] 11 | $ISOName 12 | ) 13 | 14 | process { 15 | 16 | $copysplat = @{ 17 | Path = $ISOPATH 18 | Destination = "\\$computername\c$" 19 | Force = $true 20 | } 21 | 22 | Copy-Item @copysplat -Verbose 23 | 24 | ## Install .NET 3.5 25 | Invoke-Command -ComputerName $Computername -ScriptBlock { 26 | try { 27 | $Mountiso = Mount-DiskImage -ImagePath "C:\$ISOName" -ErrorAction Stop -PassThru 28 | } 29 | catch { 30 | Write-Warning "Unable to mount" 31 | return 32 | } 33 | 34 | $volume = (Get-Volume -DiskImage $Mountiso).DriveLettter 35 | 36 | Install-WindowsFeature -Name Net-Framework-Core -Source "$volume`:\sources\sxs" 37 | 38 | Dismount-DiskImage $Mountiso.ImagePath 39 | 40 | Get-ChildItem -Path "C:\$ISONAME" | Remove-Item -Force 41 | } 42 | 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /Plex/readme.md: -------------------------------------------------------------------------------- 1 | # Setting 4K Movie Posters 2 | 3 | ## Requirements 4 | 5 | * PowerShell 7 6 | * Windows: [chocolatey package](https://chocolatey.org/packages/powershell-core) 7 | * macOS: [homebrew](https://formulae.brew.sh/cask/powershell) 8 | * Source: [source](https://github.com/PowerShell/PowerShell/releases/tag/v7.0.3) 9 | * A 4K plex library 10 | * Tested with Plex Movie Scanner 11 | * Tested with Plex Movie Agent 12 | * The Movie Database v3 API 13 | * Magick version 7.0.10-25 or newer 14 | * Windows: [chocolatey package](https://chocolatey.org/packages/imagemagick) 15 | * macOS: [homebrew](https://formulae.brew.sh/formula/imagemagick) 16 | * Source: [imagemagick](https://imagemagick.org/script/download.php) 17 | 18 | * To use, clone this repository and import the .psm1 19 | 20 | ```PowerShell 21 | 22 | Import-Module /path/to/plexfunctions.psm1 23 | 24 | $splat = @{ 25 | "PlexToken" = "plextoken" 26 | "TMDBToken" = "tmdbtoken" 27 | "4KLogoPath" = "./4k_logo.jpg" 28 | "PosterPath" = "/path/to/posterpath" 29 | "PlexURL" = "https://plexurl:port" 30 | "4KLibraryName" = "Name of 4K Movie Library" 31 | "SkipSSL" = $true ## if you have an un-trusted SSL certificate 32 | } 33 | 34 | Set-4KMoviePoster @splat 35 | 36 | ``` 37 | -------------------------------------------------------------------------------- /Samanage/New-Ticket.ps1: -------------------------------------------------------------------------------- 1 | function New-Ticket { 2 | [CmdletBinding()] 3 | param ( 4 | [string]$api, 5 | [string]$ticketname, 6 | [string]$assignedto 7 | ) 8 | 9 | begin { 10 | ## Connect to Samanage 11 | $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" 12 | $headers.Add("Accept", 'application/vnd.samanage.v2.1+json') 13 | $headers.Add("X-Samanage-Authorization", "Bearer $api") 14 | $method = "Post" 15 | $contenttype = "application/json" 16 | $uri = "https://api.samanage.com/incidents.json" 17 | 18 | $json = @" 19 | { 20 | "incident": { 21 | "name": "$ticketname", 22 | "assignee": { 23 | "email": "$assignedto" 24 | }, 25 | "priority": "CRITICAL", 26 | "description": "This is a test ticket.", 27 | "requester": { 28 | "email": "manager@blah.com" 29 | }, 30 | "add_to_tag_list": "tag1" 31 | } 32 | } 33 | "@ 34 | } 35 | 36 | process { 37 | $vars = @{ 38 | URI = $uri 39 | Headers = $headers 40 | ContentType = $contenttype 41 | Method = $method 42 | Body = $json 43 | } 44 | Invoke-WebRequest @vars 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /WindowsUpdates/Install-WinUpdatesDependencies.ps1: -------------------------------------------------------------------------------- 1 | function Install-WinUpdatesDependencies { 2 | [CmdletBinding()] 3 | param ( 4 | [string[]] 5 | $Computername 6 | ) 7 | 8 | Begin { 9 | 10 | $Session = New-PSSession -ComputerName $COMPUTERNAME 11 | 12 | $nugetpath = "\\path\to\nuget\NuGet" 13 | 14 | Invoke-Command -Session $session -ScriptBlock { 15 | New-Item -Name "NuGet" -ItemType Directory -Path "C:\Program Files\PackageManagement\ProviderAssemblies" 16 | } 17 | 18 | Copy-Item $nugetpath -Destination "C:\Program Files\PackageManagement\ProviderAssemblies" -ToSession $session -Recurse -Force 19 | 20 | } 21 | 22 | Process { 23 | 24 | Invoke-Command -Session $session -Scriptblock { 25 | $PSSplat = @{ 26 | Name = "nugetreponame" 27 | SourceLocation = "https://nugetrepo/repository/powershell-modules/" 28 | InstallationPolicy = "Trusted" 29 | } 30 | 31 | Register-PSRepository @PSSplat 32 | 33 | Install-Module -Name "PSWindowsUpdate", "Invoke-CommandAs" -Repository "nugetreponame" 34 | } 35 | 36 | } 37 | 38 | End { 39 | 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /JIRA/scratchpad.ps1: -------------------------------------------------------------------------------- 1 | ## Connect to JIRA 2 | Set-JiraConfigServer -Server "server" 3 | 4 | ## Store email and token 5 | $email = "user@domain.com" 6 | $token = "xxxxx" 7 | 8 | ## Convert to PSCredential 9 | $SecurePassword = $token | ConvertTo-SecureString -AsPlainText -Force 10 | $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $email, $SecurePassword 11 | 12 | ## Open a JIRA session 13 | New-JiraSession -Credential $Cred 14 | 15 | ## Get a JIRA issue by the name INCOL-1234 16 | Get-JiraIssue -Key "INCOL-1234" 17 | 18 | ## List custom properties and fields required by new jira story 19 | Get-JiraIssueCreateMetadata -Project "INCOL" -IssueType Task 20 | 21 | ## Get all stories in INCOL that are to-do and created more than 6 weeks ago 22 | $filter = 'project = INCOL AND issuetype = Story AND status = "To Do" AND created >= -6w' 23 | 24 | ## Get JIRA issue based on the above query 25 | Get-JiraIssue -Query $filter 26 | 27 | Foreach ($server in $eolservers) { 28 | #Write-Host "Decommission/Upgrade $($server.name)" 29 | $params = @{ 30 | Project = "INCOL" 31 | IssueType = "Story" 32 | Summary = "Summary of the JIRA story" 33 | Fields = @{ 34 | customfield_10025 = "Jonathan Moss" ## Reporter 35 | } 36 | Description = "This is a description of the JIRA story" 37 | } 38 | 39 | New-JiraIssue @params 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Transmission/transmission.ps1: -------------------------------------------------------------------------------- 1 | function Get-Torrent { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $URL = (get-content (Join-Path -Path ($ENV:HOME) -ChildPath "powershell_scripts" -AdditionalChildPath "Transmission", "url.txt")), 6 | 7 | [PSCredential] 8 | $Credential, 9 | 10 | [switch] 11 | $All 12 | ) 13 | 14 | $headers = @{ 15 | #'X-Transmission-Session-Id' = $sessionHeader 16 | } 17 | 18 | Invoke-WebRequest $url -Headers $headers -errorvariable a -Credential $credential -AllowUnencryptedAuthentication -warningaction SilentlyContinue 19 | 20 | $sessionHeader = ($a.Message -split "\.").split(" ")[-1] 21 | 22 | $headers = @{ 23 | 'X-Transmission-Session-Id' = $sessionHeader 24 | } 25 | 26 | $body = @{ 27 | arguments = @{ 28 | fields = @( 29 | "id", 30 | "uploadRatio", 31 | "downloadDir", 32 | "name" 33 | "addedDate", 34 | "status", 35 | "trackers", 36 | "trackerstats", 37 | "seedRatioLimit", 38 | "creator" 39 | ) 40 | } 41 | method = "torrent-get" 42 | } 43 | 44 | $splat = @{ 45 | Method = "POST" 46 | URI = $url 47 | Headers = $headers 48 | Credential = $credential 49 | Body = $body | convertto-json 50 | } 51 | 52 | (Invoke-RestMethod @splat -AllowUnencryptedAuthentication).arguments.torrents 53 | } 54 | -------------------------------------------------------------------------------- /Windows/Get-GroupMembership.ps1: -------------------------------------------------------------------------------- 1 | function Get-GroupMembership { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter (Mandatory = $true)] 5 | [string]$Server, 6 | [string]$GroupName, 7 | [bool]$Recursive 8 | ) 9 | 10 | if (!($script:Out)) { $script:Out = @() } 11 | 12 | $Members = (get-adgroup -server $Server $GroupName -Properties Members).members | ForEach-Object { get-adobject $_ -server $Server -Properties DisplayName, Name, SAMAccountName | Select @{e = { $_.SAMAccountName }; l = "Username" }, Name, ObjectClass, DisplayName } 13 | foreach ($Member in $Members) { 14 | 15 | if ($Recursive) { 16 | if ($Member.objectClass -eq "group") { 17 | $RecursiveResults = Get-GroupMembership -GroupName $Member.Name -Server $Server -Recursive $true 18 | $script:Out += $RecursiveResults 19 | } 20 | 21 | else { $script:Out += $Member } 22 | } 23 | 24 | if ($Member.ObjectClass -eq "foreignSecurityPrincipal") { 25 | $FSPUsername = (New-Object System.Security.Principal.SecurityIdentifier($Member.Name)).Translate([System.Security.Principal.NTAccount]) 26 | $script:Out += New-Object psobject -Property @{ 27 | Username = $FSPUsername 28 | ObjectClass = $Member.ObjectClass 29 | DisplayName = "" 30 | } 31 | } 32 | 33 | else { $script:Out += $Member } 34 | } 35 | 36 | $script:Out | Select-Object -Unique * | Sort-Object objectclass, username 37 | 38 | $script:Out = $null 39 | 40 | } -------------------------------------------------------------------------------- /MigrationWiz/Submit-MigWizPreStage.ps1: -------------------------------------------------------------------------------- 1 | Function Submit-MigWizPreStage { 2 | 3 | <# 4 | .SYNOPSIS 5 | Submits a project for pre-staging. 6 | .DESCRIPTION 7 | Long description 8 | .EXAMPLE 9 | PS C:\> Submit-MigWizPreStage -Name "ProjectName" 10 | Starts pre-staging the migrationwiz project name called ProjectName 11 | .INPUTS 12 | Inputs (if any) 13 | .OUTPUTS 14 | Output (if any) 15 | .NOTES 16 | General notes 17 | #> 18 | 19 | [CmdletBinding()] 20 | Param( 21 | [parameter(Mandatory = $true)] 22 | [ValidateNotNullOrEmpty()] 23 | $Name 24 | ) 25 | 26 | Process { 27 | 28 | Try { 29 | $MWproject = Get-MW_MailboxConnector -Ticket $global:mwticket -Name $name -ErrorAction Stop 30 | $items = Get-MW_Mailbox -ticket $global:mwticket -FilterBy_Guid_ConnectorId $MWproject.Id -ErrorAction Stop 31 | foreach ($item in $items) { 32 | $PreStageSplat = @{ 33 | Ticket = $global:mwticket 34 | MailboxID = $item.Id 35 | Type = "Full" 36 | ConnectorID = $MWproject.Id 37 | UserID = $global:mwticket.UserID 38 | ItemType = "Mail" 39 | ItemEndDate = ((Get-Date).AddDays(-1)) 40 | ErrorAction = "Stop" 41 | } 42 | $null = Add-MW_MailboxMigration @PreStageSplat 43 | Write-Verbose "Successfully started MigrationWiz Prestage for $($item.exportemailaddress)!" 44 | } 45 | } 46 | Catch { 47 | Write-Error "Could not start pre-stage batch migration $name. Start manually!" 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Windows/Get-DotNetFrameworkVersion.ps1: -------------------------------------------------------------------------------- 1 | function Get-DotNetFrameworkVersion { 2 | [CmdletBinding()] 3 | param( 4 | [string[]]$Computer 5 | ) 6 | 7 | $scriptblock = { 8 | $NetRegKey = Get-Childitem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' 9 | $Release = $NetRegKey.GetValue("Release") 10 | Switch ($Release) { 11 | 378389 { $NetFrameworkVersion = "4.5" } 12 | 378675 { $NetFrameworkVersion = "4.5.1" } 13 | 378758 { $NetFrameworkVersion = "4.5.1" } 14 | 379893 { $NetFrameworkVersion = "4.5.2" } 15 | 393295 { $NetFrameworkVersion = "4.6" } 16 | 393297 { $NetFrameworkVersion = "4.6" } 17 | 394254 { $NetFrameworkVersion = "4.6.1" } 18 | 394271 { $NetFrameworkVersion = "4.6.1" } 19 | 394802 { $NetFrameworkVersion = "4.6.2" } 20 | 394806 { $NetFrameworkVersion = "4.6.2" } 21 | 460798 { $NetFrameworkVersion = "4.7" } 22 | 460805 { $NetFrameworkVersion = "4.7" } 23 | 461308 { $NetFrameworkVersion = "4.7.1" } 24 | 461310 { $NetFrameworkVersion = "4.7.1" } 25 | 461808 { $NetFrameworkVersion = "4.7.2" } 26 | 461814 { $NetFrameworkVersion = "4.7.2" } 27 | 528049 { $NetFrameworkVersion = "4.8" } 28 | Default { $NetFrameworkVersion = "Net Framework 4.5 or later is not installed." } 29 | } 30 | [PSCustomObject]@{ 31 | Computername = $env:COMPUTERNAME 32 | NETFrameworkVersion = $NetFrameworkVersion 33 | } 34 | } 35 | 36 | if ($Computer -eq "localhost") { 37 | . $scriptblock 38 | } 39 | else { 40 | $Session = New-PSSession $Computer 41 | Invoke-Command -Session $Session -ScriptBlock $scriptblock 42 | } 43 | } -------------------------------------------------------------------------------- /Windows/Update-2016ISO.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module OSDBuilder 2 | function Update-2016ISO { 3 | 4 | [CmdletBinding()] 5 | param ( 6 | [Parameter()] 7 | [string] 8 | $ISOPath 9 | ) 10 | 11 | ## Initialise OSDBuilder and check some config ## 12 | Get-OSDBuilder -SetHome C:\OSDBuilder 13 | Get-OSDBuilder -CreatePaths 14 | 15 | if(-not (Test-Path -Path "C:\WindowsISOCache")){ 16 | New-Item -Path "C:\" -ItemType Directory -Name WindowsISOCache 17 | } 18 | 19 | ## Mount the reference image 20 | Mount-DiskImage -ImagePath $ISOPath -Verbose 21 | 22 | ## Import the media, update it and run a OSBuild for each index ## 23 | Import-OSMedia -ImageIndex 4 -Update -SkipGrid 24 | 25 | ## Eject the reference image ## 26 | Dismount-DiskImage -ImagePath $ISOPath -Verbose 27 | 28 | ## Copy the new ISOs to a different folder and rename with version. ## 29 | $folders = Get-ChildItem -Path "C:\OSDBuilder\OSBuilds" 30 | 31 | foreach ($item in $folders) { 32 | 33 | ## Create ISOs ## 34 | New-OSBMediaISO -FullName $item.FullName 35 | 36 | ## Get the ISO and work out name ## 37 | $iso = Get-ChildItem -Path "C:\OSDBuilder\OSBuilds\$($item.Name)\ISO" 38 | 39 | if (-not (Test-Path -Path "C:\WindowsISOCache\$($item.Name).iso")) { 40 | 41 | ## Copy the ISO over if its not already there ## 42 | Write-Host "## INFO ## ISO for this version not found, copying to the cache" 43 | Copy-Item -Path $iso.FullName -Destination "C:\WindowsISOCache\$($item.Name).iso" -Verbose 44 | 45 | } 46 | else { 47 | 48 | ## Do nothing if it exists ## 49 | Write-Host "## INFO ## ISO already exists in the cache. Skipping...." 50 | 51 | } 52 | 53 | } 54 | } -------------------------------------------------------------------------------- /Samanage/Get-Hardware.ps1: -------------------------------------------------------------------------------- 1 | function Get-Hardware { 2 | 3 | <# 4 | .SYNOPSIS 5 | Connects to Samanage API and outputs hardware information 6 | .DESCRIPTION 7 | In order to get an accurate view of hardware stored in Samanage, this script will loop through each page via the JSON 8 | API call and output information regarding the models stored in Samanage. 9 | .NOTES 10 | Version: 1.0 11 | Author: Jonathan Moss 12 | Creation Date: 12/14/18 13 | Purpose/Change: More 14 | Requires Powershell Core 15 | .EXAMPLE 16 | .\Get-Hardware.ps1 17 | #> 18 | 19 | #Requires -Version 6.0 20 | 21 | [CmdletBinding()] 22 | param ( 23 | [string]$api 24 | ) 25 | 26 | ## Define variables. Fill in the API key in line 21 after Bearer 27 | $apiRoot = "https://api.samanage.com" 28 | $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" 29 | $headers.Add("Accept", 'application/vnd.samanage.v2.1+json') 30 | $headers.Add("X-Samanage-Authorization", "Bearer $api") 31 | $contentType = "application/json" 32 | $data = Invoke-WebRequest -Uri "$apiRoot/hardwares.json" -Header $headers -ContentType $contentType -Method Get 33 | 34 | $hardware = @() 35 | 36 | ## Gets the last page of the JSON output since Samanage limits their pages to 100 rows 37 | $lastpage = $($data.RelationLink.Values | ForEach-Object { $_.Values} | Select-Object -Last 1) -replace '(.*)=' 38 | 39 | ## Loops through pages 1 through whatever the last page is and retrives the JSON information for hardware 40 | (1..($lastpage)) | ForEach-Object { 41 | $hardware += Invoke-RestMethod -Uri "$apiRoot/hardwares.json?page=$_" -Header $headers -ContentType $contentType -Method Get 42 | } 43 | 44 | ## Takes the full JSON output and selects certain information 45 | $hardware 46 | } 47 | -------------------------------------------------------------------------------- /WindowsUpdates/Install-AllTheUpdates.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module Invoke-CommandAs,PSWindowsupdate 2 | function Install-AllTheUpdates { 3 | [CmdletBinding()] 4 | param ( 5 | [string[]] 6 | $Computername, 7 | 8 | [string] 9 | $TitleExclusion, 10 | 11 | [switch] 12 | $Reboot, 13 | 14 | [switch] 15 | $FromWSUS 16 | ) 17 | 18 | Begin { 19 | $Session = New-PSSession -ComputerName $Computername 20 | } 21 | 22 | Process { 23 | 24 | if ($TitleExclusion -and $reboot) { 25 | Write-host "Installing Windows Updates on $computername using Microsoft Update, excluding $TitleExclusion and rebooting" -ForegroundColor Cyan 26 | Invoke-CommandAs -Session $Session -Scriptblock { 27 | Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -Verbose -NotTitle $using:TitleExclusion -AutoReboot 28 | } -AsSystem 29 | } 30 | 31 | if ($Reboot) { 32 | Write-host "Installing Windows Updates on $computername using Microsoft Update and rebooting" -ForegroundColor Cyan 33 | Invoke-CommandAs -Session $Session -Scriptblock { 34 | Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -Verbose -AutoReboot 35 | } -AsSystem 36 | } 37 | 38 | if ($Reboot -and $FromWSUS) { 39 | Write-host "Installing Windows Updates on $computername using WSUS and rebooting" -ForegroundColor Cyan 40 | Invoke-CommandAs -Session $Session -Scriptblock { 41 | Install-WindowsUpdate -AcceptAll -Verbose -AutoReboot 42 | } -AsSystem 43 | } 44 | 45 | if (-not ($Reboot -or $FromWSUS -or $TitleExclusion)) { 46 | Write-host "Installing Windows Updates on $computername using Microsoft update" -ForegroundColor Cyan 47 | Invoke-CommandAs -Session $Session -Scriptblock { 48 | Install-WindowsUpdate -MicrosoftUpdate -AcceptAll -Verbose 49 | } -AsSystem 50 | } 51 | 52 | } 53 | 54 | End { 55 | 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /ConvertTo-Markdown.ps1: -------------------------------------------------------------------------------- 1 | Function ConvertTo-Markdown { 2 | 3 | <# 4 | .SYNOPSIS 5 | https://gist.github.com/mac2000/86150ab43cfffc5d0eef 6 | .DESCRIPTION 7 | Long description 8 | .EXAMPLE 9 | PS C:\> 10 | Explanation of what the example does 11 | .INPUTS 12 | Inputs (if any) 13 | .OUTPUTS 14 | Output (if any) 15 | .NOTES 16 | General notes 17 | #> 18 | 19 | [CmdletBinding()] 20 | [OutputType([string])] 21 | Param ( 22 | [Parameter( 23 | Mandatory = $true, 24 | Position = 0, 25 | ValueFromPipeline = $true 26 | )] 27 | [PSObject[]]$collection 28 | ) 29 | 30 | Begin { 31 | $items = @() 32 | $columns = @{} 33 | } 34 | 35 | Process { 36 | ForEach ($item in $collection) { 37 | $items += $item 38 | 39 | $item.PSObject.Properties | ForEach-Object { 40 | if ($null -ne $_.Value ) { 41 | if (-not $columns.ContainsKey($_.Name) -or $columns[$_.Name] -lt $_.Value.ToString().Length) { 42 | $columns[$_.Name] = $_.Value.ToString().Length 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | End { 50 | ForEach ($key in $($columns.Keys)) { 51 | $columns[$key] = [Math]::Max($columns[$key], $key.Length) 52 | } 53 | 54 | $header = @() 55 | ForEach ($key in $columns.Keys) { 56 | $header += ('{0,-' + $columns[$key] + '}') -f $key 57 | } 58 | $header -join ' | ' 59 | 60 | $separator = @() 61 | ForEach ($key in $columns.Keys) { 62 | $separator += '-' * $columns[$key] 63 | } 64 | $separator -join ' | ' 65 | 66 | ForEach ($item in $items) { 67 | $values = @() 68 | ForEach ($key in $columns.Keys) { 69 | $values += ('{0,-' + $columns[$key] + '}') -f $item.($key) 70 | } 71 | $values -join ' | ' 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /MigrationWiz/Get-MigWizMailboxError.ps1: -------------------------------------------------------------------------------- 1 | function Get-MigWizMailboxError { 2 | 3 | <# 4 | .SYNOPSIS 5 | Check for any mailbox errors for a migrationwiz project. 6 | .DESCRIPTION 7 | Long description 8 | .EXAMPLE 9 | PS C:\> Get-MigWizMailboxError -Name "ProjectName" 10 | Retrieves mailbox errors (if there are any) for migrationwiz project called "Projectname" 11 | .INPUTS 12 | Inputs (if any) 13 | .OUTPUTS 14 | Output (if any) 15 | .NOTES 16 | General notes 17 | #> 18 | 19 | [CmdletBinding()] 20 | Param( 21 | [parameter(Mandatory = $true)] 22 | [ValidateNotNullOrEmpty()] 23 | $Name 24 | ) 25 | 26 | Process { 27 | $MWproject = Get-MW_MailboxConnector -Ticket $global:mwticket -Name $name -ErrorAction Stop 28 | $items = Get-MW_Mailbox -ticket $global:mwticket -FilterBy_Guid_ConnectorId $MWproject.Id -ErrorAction Stop 29 | Foreach ($mailbox in $items) { 30 | $migrationerrors = Get-MW_MailboxError -Ticket $global:mwticket -MailboxId $mailbox.id 31 | if ($MigrationErrors) { 32 | @($migrationerrors).ForEach( { 33 | [PSCustomObject]@{ 34 | Mailbox = $mailbox.ExportEmailAddress 35 | HasErrors = "Yes" 36 | ContainerName = $migrationerrors.ContainerName[0] 37 | ItemSubject = $migrationerrors.ItemSubject[0] 38 | Message = $migrationerrors.Message[0] 39 | CreateDate = $migrationerrors.CreateDate[0] 40 | } 41 | } 42 | ) 43 | } 44 | else { 45 | [PSCustomObject]@{ 46 | Mailbox = $mailbox.ExportEmailAddress 47 | HasErrors = "No" 48 | ContainerName = $null 49 | ItemSubject = $null 50 | Message = $null 51 | CreateDate = $null 52 | } 53 | } 54 | } 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /Security/Tests/security.tests.ps1: -------------------------------------------------------------------------------- 1 | #requires -Modules Pester 2 | Describe "TLS and SSL Checks" { 3 | 4 | BeforeAll { 5 | $tlsstuff = Get-TLSSetting -ComputerName $ComputerName 6 | } 7 | 8 | Context "SSL and TLS Checks" { 9 | 10 | foreach ($item in $tlsstuff) { 11 | It "SSL v2 Client $($item.Computer)" { 12 | $item.SSL2ClientEnabled | Should -Be $False 13 | } 14 | } 15 | 16 | foreach ($item in $tlsstuff) { 17 | It "SSL v2 Server $($item.Computer)" { 18 | $item.SSL2ServerEnabled | Should -Be $False 19 | } 20 | } 21 | 22 | foreach ($item in $tlsstuff) { 23 | It "SSL v3 Server $($item.Computer)" { 24 | $item.SSL3ServerEnabled | Should -Be $False 25 | } 26 | } 27 | 28 | foreach ($item in $tlsstuff) { 29 | It "SSL v3 Client $($item.Computer)" { 30 | $item.SSL3ClientEnabled | Should -Be $False 31 | } 32 | } 33 | 34 | foreach ($item in $tlsstuff) { 35 | It "DiffieHellman MinBitKeyLength $($item.Computer)" { 36 | $item.DiffieHellmanMinBitLength | Should -Be 2048 37 | } 38 | } 39 | 40 | foreach ($item in $tlsstuff) { 41 | It "DiffieHellman Enabled $($item.Computer)" { 42 | $item.DiffieHellmanEnabled | Should -Be $true 43 | } 44 | } 45 | 46 | foreach ($item in $tlsstuff) { 47 | It "RC4 128/128 $($item.Computer)" { 48 | $item.'RC4 128/128' | Should -be $False 49 | } 50 | } 51 | 52 | foreach ($item in $tlsstuff) { 53 | It "RC4 56/128 $($item.Computer)" { 54 | $item.'RC4 56/128' | Should -be $False 55 | } 56 | } 57 | 58 | foreach ($item in $tlsstuff) { 59 | It "RC4 40/128 $($item.Computer)" { 60 | $item.'RC4 40/128' | Should -be $False 61 | } 62 | } 63 | 64 | foreach ($item in $tlsstuff) { 65 | It "TripleDES 168 $($item.Computer)" { 66 | $item.TripleDES168 | Should -be $False 67 | } 68 | } 69 | 70 | } 71 | } -------------------------------------------------------------------------------- /Windows/Get-FileSharePermissions.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module NTFSAccess 2 | Function Get-FileSharePermissions { 3 | Param ( 4 | [String] 5 | $Path, 6 | 7 | [string] 8 | $Domain 9 | ) 10 | $rights = Get-NTFSAccess -Path $path 11 | 12 | foreach ($permission in $rights) { 13 | if ($permission.Account.Accountname -match $Domain -and $null -ne $permission.Account.Accountname) { 14 | $Group = Get-ADObject -Filter ("objectSid -eq '{0}'" -f $permission.Account.Sid) 15 | $users = Get-GroupMembership -GroupName $group.Name -Server $Domain 16 | foreach ($person in $users) { 17 | if ($person.objectClass -eq "foreignSecurityPrincipal") { 18 | 19 | if ($person.Username -match $Domain) { 20 | $user = $person.Username 21 | } 22 | 23 | if ($permission.accessrights -eq "Modify, Synchronize") { 24 | $accessrights = "Write" 25 | } 26 | if ($permission.accessrights -eq "ReadandExecute, Synchronize") { 27 | $accessrights = "Read" 28 | } 29 | 30 | [PSCustomObject]@{ 31 | User = $user 32 | Path = $permission.Fullname 33 | Rights = $accessrights 34 | IsInherited = $permission.IsInherited 35 | ADGroup = $permission.Account.Accountname 36 | } 37 | } 38 | else { 39 | if ($permission.accessrights -eq "Modify, Synchronize") { 40 | $accessrights = "Write" 41 | } 42 | if ($permission.accessrights -eq "ReadandExecute, Synchronize") { 43 | $accessrights = "Read" 44 | } 45 | 46 | [PSCustomObject]@{ 47 | User = $person.Name 48 | Path = $permission.Fullname 49 | Rights = $accessrights 50 | IsInherited = $permission.IsInherited 51 | ADGroup = $permission.Account.Accountname 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Samanage/Remove-OldComputers.ps1: -------------------------------------------------------------------------------- 1 | function Remove-OldComputers { 2 | 3 | <# 4 | .SYNOPSIS 5 | Removes computers from Samanage that haven't been online in 2 months. 6 | .EXAMPLE 7 | PS C:\> Remove-OldComputers -api xxx 8 | Returns list of all old computers 9 | PS C:\> Remove-OldComputers -api xxx -delete 10 | Deletes computers from Samanage that haven't been online in 2 months. 11 | #> 12 | 13 | [CmdletBinding()] 14 | param ( 15 | [Parameter(Mandatory = $true)] 16 | [string]$api, 17 | [switch]$delete 18 | ) 19 | 20 | begin { 21 | ## Connect to Samanage 22 | $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" 23 | $headers.Add("Accept", 'application/vnd.samanage.v2.1+json') 24 | $headers.Add("X-Samanage-Authorization", "Bearer $api") 25 | $contenttype = "application/json" 26 | $uri = "https://api.samanage.com/hardwares.json" 27 | $data = Invoke-WebRequest -Uri $Uri -Header $headers -ContentType $contentType -Method Get 28 | 29 | ## Get last page 30 | $lastpage = $data.headers.'X-Total-Pages' 31 | 32 | (1..($lastpage)) | ForEach-Object { 33 | $splat = @{ 34 | Uri = "$uri?page=$_" 35 | Header = $headers 36 | ContentType = $contentType 37 | Method = "Get" 38 | } 39 | $hardware += Invoke-RestMethod @splat 40 | } 41 | $inventory = ForEach ($item in $hardware) { 42 | [PScustomobject]@{ 43 | ComputerName = $item.name 44 | Model = $item.Model 45 | LastUpdated = [datetime](Get-Date $($item.Updated_at) -Format "MM/dd/yyyy") 46 | UserName = $item.UserName 47 | OS_Version = $item.operating_system_version 48 | ComputerID = $item.id 49 | } 50 | } 51 | $old_computers = $inventory | Where-Object {$PSItem.LastUpdated -lt (Get-Date).AddMonths(-2)} 52 | } 53 | 54 | process { 55 | if ($Delete) { 56 | ## Delete old computers 57 | foreach ($id in $old_computers.ComputerID) { 58 | $deletesplat = @{ 59 | URI = "$apiRoot/hardwares/$id.json" 60 | Headers = $headers 61 | ContentType = $contenttype 62 | Method = "Delete" 63 | } 64 | Invoke-WebRequest @deletesplat 65 | } 66 | } 67 | else { 68 | return $old_computers 69 | } 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /MigrationWiz/Get-MigWizStats.ps1: -------------------------------------------------------------------------------- 1 | Function Get-MigWizStats { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $MWName, 6 | 7 | [string] 8 | $UPN 9 | ) 10 | 11 | if (-not (Test-Path 'C:\Program Files (x86)\BitTitan\BitTitan PowerShell\BitTitanPowerShell.dll')) { 12 | throw "BitTitan Powershell module not installed. Please see https://www.bittitan.com/doc/powershell.html for more info" 13 | } 14 | 15 | Connect-ExchangeOnline -UserPrincipalName $UPN -ShowProgress $true 16 | 17 | ## List Mailbox Move Requests that are not completed 18 | $Results = Get-Moverequest | Where-Object { $psitem.Status -notmatch "completed" } | Get-MoveRequestStatistics | Select-Object * 19 | 20 | ## Select just what we want from $results 21 | $PropertyArray = @( 22 | "Displayname", 23 | "Status", 24 | "StatusDetail", 25 | "SourceServer", 26 | "BatchName", 27 | "OverallDuration", 28 | "TotalMailboxSize", 29 | "BytesTransferred", 30 | "PercentComplete" 31 | ) 32 | 33 | $Results | Select-Object -Property $PropertyArray 34 | 35 | # Get Move Request status for Migration batch 36 | $Name = $MWName 37 | ## Get MigWiz Project 38 | $MWproject = Get-MW_MailboxConnector -Ticket $global:mwticket -Name $name -ErrorAction SilentlyContinue 39 | ## Get the status/stats of it 40 | $currentmigration = Get-MW_MailboxMigration -Ticket $Global:mwticket -ConnectorId $MWproject.id 41 | ## Get all of the mailboxes in the project 42 | $Mailboxes = Get-MW_Mailbox -ConnectorId $MWproject.id -Ticket $global:mwticket -RetrieveAll 43 | 44 | ## Build PS Object Listing Email, ID, and Project ID 45 | foreach ($mwmailbox in $Mailboxes) { 46 | ## Get migration status for each mailbox 47 | $migrationstatus = $currentmigration | Where-Object { $psitem.MailboxID -eq $mwmailbox.ID } 48 | 49 | if (($migrationstatus | Measure-Object).Count -gt 1) { 50 | $latestresult = $migrationstatus | Sort-Object -Property "StartDate" -Descending | Select-Object -First 1 51 | [PSCustomObject]@{ 52 | EmailAddress = $mwmailbox.exportemailaddress 53 | ID = $mwmailbox.ID 54 | ConnectorID = $mwmailbox.ConnectorID 55 | Status = $latestresult.Status 56 | } 57 | } 58 | else { 59 | [PSCustomObject]@{ 60 | EmailAddress = $mwmailbox.exportemailaddress 61 | ID = $mwmailbox.ID 62 | ConnectorID = $mwmailbox.ConnectorID 63 | Status = $migrationstatus.Status 64 | } 65 | } 66 | } 67 | 68 | Get-PSSession | Remove-PSSession 69 | } 70 | -------------------------------------------------------------------------------- /MigrationWiz/New-MigWizProject.ps1: -------------------------------------------------------------------------------- 1 | function New-MigWizProject { 2 | 3 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] 4 | param ( 5 | [string]$ProjectName 6 | ) 7 | 8 | Begin { 9 | if (-not $PSBoundParameters.ContainsKey('Confirm')) { 10 | $ConfirmPreference = $PSCmdlet.SessionState.PSVariable.GetValue('ConfirmPreference') 11 | } 12 | if (-not $PSBoundParameters.ContainsKey('WhatIf')) { 13 | $WhatIfPreference = $PSCmdlet.SessionState.PSVariable.GetValue('WhatIfPreference') 14 | } 15 | 16 | $btcreds = Import-Clixml "$ENV:LOCALAPPDATA\O365Migration\MWCred.xml" 17 | 18 | $btticket = Get-BT_Ticket -Credentials $btcreds -ServiceType BitTitan 19 | 20 | $customer = Get-BT_Customer -Ticket $btticket -CompanyName "CompanyName" 21 | 22 | $importEndpoint = Get-BT_Endpoint -Ticket $btticket -Name "TenantName O365" 23 | $exportEndpoint = Get-BT_Endpoint -Ticket $btticket -Name "On-PremSourceName" 24 | 25 | $importConfiguration = New-Object -TypeName MigrationProxy.WebApi.ExchangeConfiguration -Property @{ 26 | "UseAdministrativeCredentials" = $true; 27 | "ExchangeItemType" = "Mail"; 28 | } 29 | 30 | $exportConfiguration = New-Object -TypeName MigrationProxy.WebApi.ExchangeConfiguration -Property @{ 31 | "UseAdministrativeCredentials" = $true; 32 | "ExchangeItemType" = "Mail"; 33 | } 34 | 35 | [string]$advancedoptions = 'UseEwsImportImpersonation=1', 'Tags=IpLockDown!' 36 | 37 | $connectorsplat = @{ 38 | Ticket = $Global:mwticket 39 | ProjectType = "Mailbox" 40 | ExportType = "ExchangeServer" 41 | ImportType = "ExchangeOnline2" 42 | Name = $ProjectName 43 | UserId = $Global:mwticket.UserId 44 | SelectedExportEndpointID = $exportEndpoint.Id 45 | SelectedImportEndpointID = $importEndpoint.Id 46 | ImportConfiguration = $importConfiguration 47 | ExportConfiguration = $exportConfiguration 48 | OrganizationId = $customer.OrganizationId 49 | AdvancedOptions = $advancedoptions 50 | Tags = "IpLockDown!" 51 | Flags = "LogFailedItemSubjects" 52 | PurgePeriod = "180" 53 | MaxLicensesToConsume = "1" 54 | MaximumItemFailures = "1000" 55 | } 56 | } 57 | 58 | Process { 59 | if ($PSCmdlet.ShouldProcess("New migration wiz project?")) { 60 | # Create the project 61 | Add-MW_MailboxConnector @connectorsplat 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Windows/Install-VCRuntime.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module VcRedist 2 | function Install-VCRuntime { 3 | [CmdletBinding()] 4 | param ( 5 | [string] 6 | $ComputerName, 7 | 8 | [Parameter(Mandatory)] 9 | [ValidateSet( 10 | "2008", 11 | "2010", 12 | "2012", 13 | "2013", 14 | "2019" 15 | )] 16 | [string] 17 | $Version, 18 | 19 | [Parameter(Mandatory)] 20 | [ValidateSet( 21 | "x64", 22 | "x86" 23 | )] 24 | [string] 25 | $OSType, 26 | 27 | [switch] 28 | $Local 29 | ) 30 | 31 | $nugetpath = "\\path\to\nuget" 32 | 33 | $session = New-PSSession -ComputerName $ComputerName 34 | 35 | Invoke-Command -Session $session -ScriptBlock { 36 | New-Item -Name "NuGet" -ItemType Directory -Path "C:\Program Files\PackageManagement\ProviderAssemblies" -ErrorAction SilentlyContinue 37 | } 38 | 39 | Copy-Item $nugetpath -Destination "C:\Program Files\PackageManagement\ProviderAssemblies" -ToSession $session -Recurse -Force 40 | 41 | if ($Local) { 42 | 43 | Copy-Item "C:\Program Files\WindowsPowerShell\Modules\VcRedist" -ToSession $session -Destination "C:\Program Files\WindowsPowerShell\Modules" -Recurse -Force 44 | 45 | Copy-Item "C:\Temp\VcRedist" -ToSession $session -Destination "C:\" -Recurse -Force 46 | 47 | Invoke-Command -Session $session -Scriptblock { 48 | ## store them to a variable 49 | $VcList = Get-VcList -Release $using:version -Architecture $using:OSType 50 | 51 | ## Install it from the local path 52 | Install-VcRedist -Path C:\VcRedist -VcList $VcList 53 | } 54 | } 55 | else { 56 | 57 | Invoke-Command -Session $session -Scriptblock { 58 | 59 | ## Set TLS to TLS 1.2 60 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 61 | 62 | ## trust the psgallery 63 | Set-PSRepository -Name PSGallery -InstallationPolicy Trusted 64 | 65 | ## Install VcRedist module from powershell gallery 66 | Install-Module -Name VcRedist -Repository "PSGallery" 67 | 68 | Import-Module VcRedist -Force 69 | 70 | ## store them locally 71 | New-Item C:\Temp\VcRedist -ItemType Directory -Force 72 | 73 | ## save them to c:\temp 74 | Get-VcList -Release $using:version -Architecture $using:OSType | Save-VcRedist -Path C:\Temp\VcRedist 75 | 76 | ## store them to a variable 77 | $VcList = Get-VcList -Release $using:version -Architecture $using:OSType 78 | 79 | ## Install it from the local path 80 | Install-VcRedist -Path C:\Temp\VcRedist -VcList $VcList 81 | 82 | ## Uninstall the module 83 | Uninstall-Module VcRedist -Force 84 | } 85 | } 86 | 87 | 88 | } -------------------------------------------------------------------------------- /Packer/ConfigurationFiles/server-2016.json: -------------------------------------------------------------------------------- 1 | { 2 | "builders": [ 3 | { 4 | "type": "vsphere-iso", 5 | "vcenter_server": "vCenter.fqdn.com", 6 | "username": "domain\\user", 7 | "password": "{{ user `password` }}", 8 | "insecure_connection": "true", 9 | "vm_version": 13, 10 | "vm_name": "Template_Win2016_Std_64bit_Prod", 11 | "guest_os_type": "windows9Server64Guest", 12 | "communicator": "winrm", 13 | "cluster": "cluster1", 14 | "datacenter": "datacenter1", 15 | "host": "esxihost.fqdn.com", 16 | "datastore": "datastore1", 17 | "network": "Virtual Switch 1", 18 | "winrm_username": "admin", 19 | "winrm_password": "{{ user `winrm_password` }}", 20 | "winrm_port": 5985, 21 | "CPUs": 2, 22 | "RAM": 4096, 23 | "convert_to_template": "true", 24 | "CPU_limit": -1, 25 | "boot_order": "disk,cdrom", 26 | "RAM_reserve_all": true, 27 | "disk_controller_type": "pvscsi", 28 | "disk_size": 71680, 29 | "disk_thin_provisioned": true, 30 | "network_card": "vmxnet3", 31 | "iso_paths": [ 32 | "[datastore1] ISO/14393.0.161119-1705.RS1_REFRESH_SERVER_EVAL_X64FRE_EN-US.ISO", 33 | "[datastore1] ISO/Windows.iso" 34 | ], 35 | "floppy_files": [ 36 | "./Setup/" 37 | ], 38 | "floppy_img_path": "[datastore1] ISO/pvscsi-Windows8.flp" 39 | } 40 | ], 41 | "provisioners": [ 42 | { 43 | "type": "powershell", 44 | "elevated_user": "admin", 45 | "elevated_password": "{{ user `winrm_password` }}", 46 | "scripts": [ 47 | "./Scripts/Install-Chocolatey.ps1", 48 | "./Scripts/Set-ChocolateySettings.ps1", 49 | "./Scripts/Install-Boxstarter.ps1" 50 | 51 | ] 52 | }, 53 | { 54 | "type": "windows-restart", 55 | "restart_timeout": "15m" 56 | }, 57 | { 58 | "type": "powershell", 59 | "elevated_user": "admin", 60 | "elevated_password": "{{ user `winrm_password` }}", 61 | "scripts": [ 62 | "./Scripts/Invoke-SystemUpdate.ps1" 63 | ] 64 | }, 65 | { 66 | "type": "windows-restart", 67 | "restart_timeout": "30m" 68 | }, 69 | { 70 | "type": "powershell", 71 | "elevated_user": "admin", 72 | "elevated_password": "{{ user `winrm_password` }}", 73 | "scripts": [ 74 | "./Scripts/Invoke-SystemUpdate.ps1", 75 | "./Scripts/Set-TimeZone.ps1", 76 | "./Scripts/Invoke-SystemCleanup.ps1" 77 | ] 78 | }, 79 | { 80 | "type": "windows-restart", 81 | "restart_timeout": "45m" 82 | } 83 | ] 84 | } -------------------------------------------------------------------------------- /Packer/Scripts/Invoke-SystemCleanup.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Performs cleanup of aesthetic artifacts on the system. 4 | 5 | #> 6 | 7 | # Remove icon files from the desktop. 8 | Try { 9 | Write-Host "Cleaning up icon files." 10 | Remove-Item "$Env:SystemDrive\Users\admin\Desktop\*" -Force -Recurse 11 | Remove-Item "$Env:SystemDrive\Users\Public\Desktop\*" -Force -Recurse 12 | } 13 | Catch { 14 | Write-Error "Could not delete desktop icon files as part of the cleanup script. Exiting." 15 | Write-Host $_.Exception | format-list -force 16 | Exit 1 17 | } 18 | 19 | # Remove Run Key Persistence 20 | Try { 21 | Write-Host "Cleaning up registry keys." 22 | Remove-ItemProperty 'HKLM:\SOFTWARE\Wow6432node\Microsoft\Windows\CurrentVersion\Run' -Name * -Force 23 | Remove-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' -Name * -Force 24 | Remove-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run' -Name * -Force 25 | } 26 | Catch { 27 | Write-Error "Could not remove run keys as part of the cleanup script. Exiting." 28 | Write-Host $_.Exception | format-list -force 29 | Exit 1 30 | } 31 | 32 | # Remove Chocolatey and its settings/dependencies 33 | Try { 34 | Write-Host "Removing Chocolatey and all packages from image." 35 | Remove-Item -Recurse -Force "$env:ChocolateyInstall" 36 | [System.Text.RegularExpressions.Regex]::Replace([Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment').GetValue('PATH', '', [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames).ToString(), [System.Text.RegularExpressions.Regex]::Escape("$env:ChocolateyInstall\bin") + '(?>;)?', '', [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) | % {[System.Environment]::SetEnvironmentVariable('PATH', $_, 'User')} 37 | [System.Text.RegularExpressions.Regex]::Replace([Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment\').GetValue('PATH', '', [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames).ToString(), [System.Text.RegularExpressions.Regex]::Escape("$env:ChocolateyInstall\bin") + '(?>;)?', '', [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) | % {[System.Environment]::SetEnvironmentVariable('PATH', $_, 'Machine')} 38 | } 39 | Catch { 40 | Write-Error "Could not remove Choclatey as part of the cleanup script. Exiting." 41 | Write-Host $_.Exception | format-list -force 42 | Exit 1 43 | } 44 | 45 | try { 46 | if ($env:ChocolateyBinRoot -ne '' -and $env:ChocolateyBinRoot -ne $null) { Remove-Item -Recurse -Force "$env:ChocolateyBinRoot" -WhatIf } 47 | if ($env:ChocolateyToolsRoot -ne '' -and $env:ChocolateyToolsRoot -ne $null) { Remove-Item -Recurse -Force "$env:ChocolateyToolsRoot" -WhatIf } 48 | [System.Environment]::SetEnvironmentVariable("ChocolateyBinRoot", $null, 'User') 49 | [System.Environment]::SetEnvironmentVariable("ChocolateyToolsLocation", $null, 'User') 50 | } 51 | catch { 52 | Write-Error "Could not remove Choclatey as part of the cleanup script. Exiting." 53 | Write-Host $_.Exception | format-list -force 54 | Exit 1 55 | } 56 | 57 | 58 | # Delete Packer Directory 59 | Try { 60 | Remove-Item -Path "$Env:SystemDrive\packer\" -Recurse -Force | Out-Null 61 | } 62 | Catch { 63 | Write-Error "Could not clean up packer folder. Exiting." 64 | Write-Host $_.Exception | format-list -force 65 | Exit 1 66 | } -------------------------------------------------------------------------------- /Packer/Invoke-TemplateBuild.ps1: -------------------------------------------------------------------------------- 1 | function Invoke-TemplateBuild { 2 | param ( 3 | [Parameter(Mandatory = $true)] 4 | [string]$vCenterServer, 5 | [Parameter(Mandatory = $true)] 6 | [string]$TemplateFolder, 7 | [Parameter(Mandatory = $true)] 8 | [string]$TemplateName, 9 | [Parameter(Mandatory = $true)] 10 | [string]$ConfigurationFile 11 | ) 12 | 13 | <# 14 | .SYNOPSIS 15 | Executes Packer Template Build against a vCenter. This script is designed to run from Jenkins. 16 | .EXAMPLE 17 | PS C:\> Invoke-TemplateBuild.ps1 -vCenter vcenter.fqdn.com -TemplateFolder TemplateFolder -TemplateName Win2016 -ConfigurationFile Server2016.json 18 | Executes packer.exe, connects to a vCenter and moves the template to the correct folder. 19 | .NOTES 20 | v1.0.0 - 7/9/18 - Jonathan Moss 21 | v1.0.1 - 7/11/18 - Remove existing template prior to deploying new one 22 | v1.0.2 - 10/22/18 - Added parameters to support targetting multiple vCenters 23 | #> 24 | 25 | Import-Module VMware.PowerCLI | Out-Null 26 | 27 | ## Define Jenkins parameters and pass through credentials stored in Jenkins using Credentials Binding plugin. 28 | $SecurePassword = $env:vCenterPassword | ConvertTo-SecureString -AsPlainText -Force 29 | $vCenterCred = New-Object System.Management.Automation.PSCredential -ArgumentList $env:vCenterAdmin, $SecurePassword 30 | 31 | Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false 32 | 33 | ## Connect to vCenter with stored credentials 34 | try { 35 | Connect-VIServer -Server $vCenterServer -Protocol https -Credential $vCenterCred -ErrorAction Stop 36 | Write-Output "Successfully connected to $vcenterServer! Continuing.." 37 | } 38 | catch { 39 | Write-Output "Could not connect to $vcenterserver" 40 | Write-Host $_.Exception.Message 41 | Write-Host $_.Exception.ItemName 42 | } 43 | 44 | try { 45 | $VMTemplate = Get-Template -Name $TemplateName -ErrorAction STOP 46 | if ($VMTemplate) { 47 | try { 48 | Remove-Template -Template $VMTemplate -Confirm:$false -ErrorAction STOP 49 | } 50 | catch { 51 | ## If template is found, yet can't be removed, exit the script. 52 | Write-Output "Could not delete, skipping..." 53 | Write-Output "Manually delete $VMTemplate from $vcenterServer" 54 | Break 55 | } 56 | } 57 | } 58 | catch { 59 | Write-Host "No template found! Continuing.." 60 | Write-Host $_.Exception.Message 61 | Write-Host $_.Exception.ItemName 62 | } 63 | 64 | $params = @{ 65 | FilePath = "$ENV:WORKSPACE\Binaries\packer.exe" 66 | ArgumentList = "build -var `"password=$($env:vCenterPassword)`" -var `"winrm_password=$($env:LocalAdminPassword)`" `"$($ENV:WORKSPACE)\ConfigurationFiles\$ConfigurationFile`"" 67 | WorkingDirectory = "$ENV:WORKSPACE\Packer" 68 | } 69 | 70 | Start-Process @params -NoNewWindow -Wait 71 | 72 | ## Get existing folder where templates are stored 73 | 74 | $TemplateFolder = Get-Folder -Name $TemplateFolder 75 | 76 | ## Move template that was created from script to the destination template folder 77 | $a = Get-Template -Name $TemplateName 78 | $b = Get-Folder -Name $TemplateFolder 79 | Get-Template $a | Move-Template -Destination $b 80 | 81 | ## Disconnect from vCenter 82 | Disconnect-VIServer $vCenterServer -Confirm:$False 83 | } -------------------------------------------------------------------------------- /Utilities/Test-ConnectionASync.ps1: -------------------------------------------------------------------------------- 1 | Function Test-ConnectionAsync { 2 | <# 3 | .SYNOPSIS 4 | Performs a ping test asynchronously 5 | 6 | .DESCRIPTION 7 | Performs a ping test asynchronously 8 | 9 | .PARAMETER Computername 10 | List of computers to test connection 11 | 12 | .PARAMETER Timeout 13 | Timeout in milliseconds 14 | 15 | .PARAMETER TimeToLive 16 | Sets a time to live on ping request 17 | 18 | .PARAMETER Fragment 19 | Tells whether to fragment the request 20 | 21 | .PARAMETER Buffer 22 | Supply a byte buffer in request 23 | 24 | .NOTES 25 | Name: Test-ConnectionAsync 26 | Author: Boe Prox 27 | Version History: 28 | 1.0 //Boe Prox - 12/24/2015 29 | - Initial result 30 | 31 | .OUTPUT 32 | Net.AsyncPingResult 33 | 34 | .EXAMPLE 35 | Test-ConnectionAsync -Computername server1,server2,server3 36 | 37 | Computername Result 38 | ------------ ------ 39 | Server1 Success 40 | Server2 TimedOut 41 | Server3 No such host is known 42 | 43 | Description 44 | ----------- 45 | Performs asynchronous ping test against listed systems. 46 | #> 47 | #Requires -Version 3.0 48 | [OutputType('Net.AsyncPingResult')] 49 | [cmdletbinding()] 50 | Param ( 51 | [parameter(ValueFromPipeline = $True)] 52 | [string[]]$Computername, 53 | [parameter()] 54 | [int32]$Timeout = 100, 55 | [parameter()] 56 | [Alias('Ttl')] 57 | [int32]$TimeToLive = 128, 58 | [parameter()] 59 | [switch]$Fragment, 60 | [parameter()] 61 | [byte[]]$Buffer 62 | ) 63 | Begin { 64 | 65 | If (-NOT $PSBoundParameters.ContainsKey('Buffer')) { 66 | $Buffer = 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 67 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69 68 | } 69 | $PingOptions = New-Object System.Net.NetworkInformation.PingOptions 70 | $PingOptions.Ttl = $TimeToLive 71 | If (-NOT $PSBoundParameters.ContainsKey('Fragment')) { 72 | $Fragment = $False 73 | } 74 | $PingOptions.DontFragment = $Fragment 75 | $Computerlist = New-Object System.Collections.ArrayList 76 | If ($PSBoundParameters.ContainsKey('Computername')) { 77 | [void]$Computerlist.AddRange($Computername) 78 | } 79 | Else { 80 | $IsPipeline = $True 81 | } 82 | } 83 | Process { 84 | If ($IsPipeline) { 85 | [void]$Computerlist.Add($Computername) 86 | } 87 | } 88 | End { 89 | $Task = ForEach ($Computer in $Computername) { 90 | [pscustomobject] @{ 91 | Computername = $Computer 92 | Task = (New-Object System.Net.NetworkInformation.Ping).SendPingAsync($Computer, $Timeout, $Buffer, $PingOptions) 93 | } 94 | } 95 | Try { 96 | [void][Threading.Tasks.Task]::WaitAll($Task.Task) 97 | } 98 | Catch {} 99 | $Task | ForEach { 100 | If ($_.Task.IsFaulted) { 101 | $Result = $_.Task.Exception.InnerException.InnerException.Message 102 | $IPAddress = $Null 103 | } 104 | Else { 105 | $Result = $_.Task.Result.Status 106 | $IPAddress = $_.task.Result.Address.ToString() 107 | } 108 | $Object = [pscustomobject]@{ 109 | Computername = $_.Computername 110 | IPAddress = $IPAddress 111 | Result = $Result 112 | } 113 | $Object.pstypenames.insert(0, 'Net.AsyncPingResult') 114 | $Object 115 | } 116 | } 117 | 118 | } -------------------------------------------------------------------------------- /MigrationWiz/Add-MigWizProject.ps1: -------------------------------------------------------------------------------- 1 | Function Add-MigWizProject { 2 | 3 | <# 4 | .SYNOPSIS 5 | Creates a new project in MigrationWiz and adds users to it. 6 | .EXAMPLE 7 | PS C:\> Set-MigWizToken -Credential (Get-Credential) 8 | PS C:\> Import-Module 'C:\Program Files (x86)\BitTitan\BitTitan PowerShell\BitTitanPowerShell.dll' 9 | PS C:\> $emails = @("user@domain.com","user2@domain.com") 10 | PS C:\> Add-MigWizProject -Name "MigrationProjectName" -Emails $emails 11 | .NOTES 12 | Creates a new project in MigrationWiz and adds users via email addresses to it, and sets the 13 | upn suffix to @domain.onmicrosoft.com. 14 | Make sure to run Set-MigWizToken before running this. 15 | #> 16 | 17 | [CmdletBinding()] 18 | Param( 19 | [parameter(Mandatory = $true)] 20 | [ValidateNotNullOrEmpty()] 21 | $Name, 22 | 23 | [parameter(Mandatory = $true)] 24 | [string[]] 25 | $Emails, 26 | 27 | [parameter(Mandatory = $true)] 28 | [string[]] 29 | $Domain 30 | ) 31 | 32 | Process { 33 | 34 | ## Check to make sure the project doesn't exist 35 | $MWproject = Get-MW_MailboxConnector -Ticket $global:mwticket -Name $name -ErrorAction SilentlyContinue 36 | 37 | if ($null -ne $MWproject) { 38 | Write-Error -Message "$Name already exists in MigrationWiz!" 39 | } 40 | else { 41 | ## This assumes you already have a project called "Rescheduled". This will place those users into this new project. 42 | ## Convert @$domain.com emails to @$domain.onmicrosoft.com emails, add to MigWiz Project, and add to group to create cloud mailbox 43 | $RescheduledProject = Get-MW_MailboxConnector -Ticket $global:mwticket -Name "Rescheduled" 44 | 45 | try { 46 | $RescheduledMailboxes = Get-MW_Mailbox -ConnectorId $RescheduledProject.Id -Ticket $global:mwticket -RetrieveAll -ErrorAction Stop 47 | } 48 | catch { 49 | Write-Error "Could not retrieve all mailboxes in Rescheduled project." -ForegroundColor Red 50 | Return 51 | } 52 | 53 | ## Create a project in Migration Wiz 54 | $null = New-MigWizProject -ProjectName $Name -Confirm:$false 55 | 56 | ## Get the project 57 | $MWproject = Get-MW_MailboxConnector -Ticket $global:mwticket -Name $name -ErrorAction SilentlyContinue 58 | 59 | foreach ($user in $emails) { 60 | ## Create cloud user 61 | $cloudUser = ($user -split '@')[0] + "@$domain.onmicrosoft.com" 62 | ## Get rescheduled user in migwiz and move to new project 63 | if ($null -ne $RescheduledMailboxes) { 64 | if ($RescheduledMailboxes.ExportEmailAddress.contains($user)) { 65 | $Mailbox = $RescheduledMailboxes | Where-Object { $psitem.ExportemailAddress -eq $user } 66 | try { 67 | $null = Set-MW_Mailbox -Ticket $global:mwticket -ConnectorId $MWProject.Id -mailbox $mailbox -ErrorAction Stop 68 | Write-Verbose "Successfully moved $user to $name Project in MigrationWiz." 69 | } 70 | catch { 71 | Write-Error "Unable to add $user to $name Project in MigrationWiz. Move manually." 72 | } 73 | } 74 | else { 75 | try { 76 | $null = Add-MW_Mailbox -Ticket $global:mwticket -ConnectorId $MWproject.id -ImportEmailAddress $cloudUser -ExportEmailAddress $user -Flags "3" -ErrorAction Stop | Out-Null 77 | Write-Verbose "Added $clouduser to MigrationWiz Project:`t $name" 78 | } 79 | catch { 80 | Write-Error "$cloudUser could not be added to MigrationWiz Project: $name" 81 | } 82 | } 83 | } 84 | else { 85 | try { 86 | $null = Add-MW_Mailbox -Ticket $global:mwticket -ConnectorId $MWproject.id -ImportEmailAddress $cloudUser -ExportEmailAddress $user -Flags "3" -ErrorAction Stop | Out-Null 87 | Write-Verbose "Added $clouduser to MigrationWiz Project: $name" 88 | } 89 | catch { 90 | Write-Error "$cloudUser could not be added to MigrationWiz Project: $name" 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Office/Install-OfficeUpdates.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Modules OSDUpdate,OSDSUS,Invoke-CommandAs 2 | function Install-OfficeUpdates { 3 | [CmdletBinding()] 4 | param ( 5 | [string[]] 6 | $ServerName, 7 | 8 | [Parameter(Mandatory)] 9 | [ValidateSet( 10 | "Office2010", 11 | "Office2013", 12 | "Office2016" 13 | )] 14 | $OfficeVersion, 15 | 16 | [Parameter(Mandatory)] 17 | [ValidateSet( 18 | "x86", 19 | "x64" 20 | )] 21 | $OS 22 | ) 23 | 24 | $filepath = "E:\$OfficeVersion" + "_" + "$OS" 25 | switch ($OfficeVersion) { 26 | "Office2010" { 27 | 28 | if ($OS -eq "x86") { 29 | 30 | ## Create a patch group for newest patches for Office 2010 31 | New-OSDUpdatePackage -PackageName 'Office 2010 32-Bit' -OfficeProfile Default -PackagePath $filepath -AppendPackageName -RemoveSuperseded 32 | 33 | ## Copy the path to the Servers 34 | $ServerName | ForEach-Object { 35 | Copy-Item $filepath -Destination "\\$_\c$\" -Recurse -Force 36 | } 37 | 38 | Invoke-CommandAs -ComputerName $ServerName -ScriptBlock { 39 | & "C:\Office2010_x86\Office 2010 32-Bit\Install-OSDUpdatePackage.ps1" 40 | } 41 | } 42 | else { 43 | ## Create a patch group for newest patches for Office 2010 44 | New-OSDUpdatePackage -PackageName 'Office 2010 64-Bit' -OfficeProfile Default -PackagePath $filepath -AppendPackageName -RemoveSuperseded 45 | 46 | ## Copy the path to the Servers 47 | $ServerName | ForEach-Object { 48 | Copy-Item $filepath -Destination "\\$_\c$\" -Recurse -Force 49 | } 50 | 51 | Invoke-CommandAs -ComputerName $ServerName -ScriptBlock { 52 | & "C:\Office2010_x64\Office 2010 64-Bit\Install-OSDUpdatePackage.ps1" 53 | } 54 | } 55 | 56 | 57 | } 58 | "Office2013" { 59 | 60 | if ($OS -eq "x86") { 61 | 62 | ## Create a patch group for newest patches for Office 2010 63 | New-OSDUpdatePackage -PackageName 'Office 2013 32-Bit' -OfficeProfile Default -PackagePath $filepath -AppendPackageName -RemoveSuperseded 64 | 65 | ## Copy the path to the Servers 66 | $ServerName | ForEach-Object { 67 | Copy-Item $filepath -Destination "\\$_\c$\" -Recurse -Force 68 | } 69 | 70 | Invoke-CommandAs -ComputerName $ServerName -ScriptBlock { 71 | & "C:\Office2013_x86\Office 2013 32-Bit\Install-OSDUpdatePackage.ps1" 72 | } 73 | } 74 | else { 75 | ## Create a patch group for newest patches for Office 2010 76 | New-OSDUpdatePackage -PackageName 'Office 2013 64-Bit' -OfficeProfile Default -PackagePath $filepath -AppendPackageName -RemoveSuperseded 77 | 78 | ## Copy the path to the Servers 79 | $ServerName | ForEach-Object { 80 | Copy-Item $filepath -Destination "\\$_\c$\" -Recurse -Force 81 | } 82 | 83 | Invoke-CommandAs -ComputerName $ServerName -ScriptBlock { 84 | & "C:\Office2013_x64\Office 2013 64-Bit\Install-OSDUpdatePackage.ps1" 85 | } 86 | } 87 | 88 | } 89 | "Office2016" { 90 | if ($OS -eq "x86") { 91 | 92 | ## Create a patch group for newest patches for Office 2010 93 | New-OSDUpdatePackage -PackageName 'Office 2016 32-Bit' -OfficeProfile Default -PackagePath $filepath -AppendPackageName -RemoveSuperseded 94 | 95 | ## Copy the path to the Servers 96 | $ServerName | ForEach-Object { 97 | Copy-Item $filepath -Destination "\\$_\c$\" -Recurse -Force 98 | } 99 | 100 | Invoke-CommandAs -ComputerName $ServerName -ScriptBlock { 101 | & "C:\Office2016_x86\Office 2016 32-Bit\Install-OSDUpdatePackage.ps1" 102 | } 103 | } 104 | else { 105 | ## Create a patch group for newest patches for Office 2010 106 | New-OSDUpdatePackage -PackageName 'Office 2016 64-Bit' -OfficeProfile Default -PackagePath $filepath -AppendPackageName -RemoveSuperseded 107 | 108 | ## Copy the path to the Servers 109 | $ServerName | ForEach-Object { 110 | Copy-Item $filepath -Destination "\\$_\c$\" -Recurse -Force 111 | } 112 | 113 | Invoke-CommandAs -ComputerName $ServerName -ScriptBlock { 114 | & "C:\Office2016_x64\Office 2016 64-Bit\Install-OSDUpdatePackage.ps1" 115 | } 116 | } 117 | } 118 | Default { 119 | } 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /VMware/Build-VM.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Creates a virtual machine in a vCenter environment and adds additional information to Active Directory. 4 | .DESCRIPTION 5 | In order to automate the creation of virtual machines in a vCenter environment, this script will clone a virtual 6 | machine from a template in vCenter, join the machine to a domain, update the AD description, create a group designated 7 | for administrators of the virtual machine, move the virtual machine to its final Organizational Unit, and send an email 8 | once the job is completed. 9 | .NOTES 10 | Version: 1.0 11 | Author: Jonathan Moss 12 | Creation Date: 7/10/17 13 | Purpose/Change: Initial upload to Github 14 | .EXAMPLE 15 | .\Build-VM.ps1 16 | #> 17 | 18 | ## Disconnects from any existing vCenter connection 19 | Disconnect-VIServer * -confirm:$false 20 | 21 | ## Import Modules to support connecting to vCenter and connecting to Active Directory (AD) 22 | Import-Module ActiveDirectory 23 | Import-Module VMware.PowerCLI 24 | 25 | ## Define variables to be used in creating the Virtual Machine and within AD 26 | $vc = Read-Host "Enter vCenter Server hostname or IP address" 27 | $name = Read-Host "Enter the Server Name" 28 | $ipaddress = Read-Host "Enter IP Address" 29 | $subnet = Read-Host "Enter Subnet, i.e. 255.255.255.0" 30 | $gateway = Read-Host "Enter Gateway" 31 | $dns1 = Read-Host "Enter primary DNS server" 32 | $dns2 = Read-Host "Enter secondary DNS server" 33 | $zonename = Read-Host "Enter Zone name for DNS" 34 | $dnsserver = Read-Host "Enter hostname for DNS Server that will be used to update DNS" 35 | $clustername = Read-Host "Enter the cluster name for $vc" 36 | $template = Read-Host "Enter the template to be used to clone VM from" 37 | $customization = Read-Host "Enter the customization to be used within the template" 38 | $NewDatastore = Read-Host "Enter the datastore to be used in $vc" 39 | $networkname = Read-Host "Enter the network name to be used for the primary virtual nic for $name" 40 | $ADDescription = Read-Host "Enter AD Description of $name" 41 | $targetOU = Read-Host "Enter target OU to move Computer object to, I.E 'OU=Computers,DC=blah,DC=blah' " 42 | Write-Output "Enter AD credentials that allow the Virtual Machine to be joined to the domain" 43 | $mycredential = Get-Credential 44 | $to = Read-Host "Enter the recipients of the new virtual machine email notification" 45 | $from = Read-Host "Enter the sender of the new virtual machine email notification" 46 | $smtpserver = Read-Host "Enter the SMTP Server hostname" 47 | 48 | ## Create AD Group for AD Administrators for the Virtual Machine 49 | $administrator = "_Administrators" 50 | $group = $name + $administrator 51 | $path = Read-Host "Enter target OU to create the administrator groups for $name, I.E 'OU=Users,DC=blah,DC=blah'" 52 | 53 | $adgroupvars = @{ 54 | 55 | Name = $group 56 | GroupScope = Global 57 | Description = "Members with Local Administrator Rights on $name" 58 | GroupCategory = Security 59 | Path = $path 60 | } 61 | 62 | New-ADGroup @adgroupvars 63 | 64 | ## Connect to vCenter 65 | Connect-VIServer $vc 66 | 67 | ## Remove existing customization spec 68 | Get-OSCustomizationSpec $customization | Get-OSCustomizationNicMapping | Remove-OSCustomizationNicMapping -Confirm:$false 69 | 70 | ## Configure networking information for the new customization spec 71 | $vmnetwork = @{ 72 | 73 | OSCustomizationSpec = $customization 74 | IpMode = UseStaticIP 75 | IpAddress = $ipaddress 76 | SubnetMask = $subnet 77 | DefaultGateway = $gateway 78 | DNS = $dns1, $dns2 79 | Position = 1 80 | } 81 | 82 | New-OSCustomizationNicMapping @vmnetwork 83 | 84 | ## Define the customization spec using domain credentials 85 | Set-OSCustomizationSpec $customization -DomainCredentials $mycredential 86 | 87 | ## Create the new VM from template 88 | 89 | $virtualmachine = @{ 90 | 91 | Name = $name 92 | Template = $template 93 | Resourcepool = $clustername 94 | Datastore = $NewDatastore 95 | OSCustomizationSpec = $customization 96 | Confirm = $false 97 | } 98 | 99 | New-VM @virtualmachine 100 | 101 | ## Configures networking for the VM 102 | Get-VM -Name $name | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName $networkname -Confirm:$false 103 | 104 | ## Powering on the machine 105 | Start-VM -vm $name -Confirm:$false 106 | 107 | ## Add DNS Record 108 | Add-DnsServerResourceRecordA -Name $name -IPv4Address $ipaddress -ZoneName $zonename -ComputerName $dnsserver -CreatePtr 109 | 110 | ## Wait until computer is on the domain, and then move it to the right OU 111 | do { 112 | Write-Host "." -nonewline -ForegroundColor Red 113 | Start-Sleep 5 114 | } until (Get-ADComputer -Filter {Name -eq $name}) 115 | 116 | Get-ADComputer $name | Move-ADobject -targetpath $targetOU 117 | 118 | ## Set AD Description 119 | Set-ADComputer -Identity $Name -Description $ADDescription 120 | 121 | ## Send Completion Email 122 | Send-MailMessage -To $to -From $from -Subject "New VM $name Created" -SmtpServer $smtpserver 123 | 124 | ## Disconnect from vCenter 125 | Disconnect-VIServer * -Confirm:$false -------------------------------------------------------------------------------- /Plex/plexfunctions.psm1: -------------------------------------------------------------------------------- 1 | function Set-4KMoviePoster { 2 | [CmdletBinding()] 3 | param ( 4 | [string] 5 | $PlexToken, 6 | 7 | [string] 8 | $TMDBToken, 9 | 10 | [System.IO.FileInfo] 11 | $4KLogoPath, 12 | 13 | [System.IO.FileInfo] 14 | $PosterPath, 15 | 16 | [string] 17 | $PlexURL, 18 | 19 | [string] 20 | $4KLibraryName, 21 | 22 | [switch] 23 | $SkipSSL 24 | ) 25 | 26 | process { 27 | 28 | ## Plex Libraries 29 | $libraries = Invoke-RestMethod -Uri ($plexURL + "/library/sections?X-Plex-Token=$plextoken") -Method Get 30 | 31 | ## If the get request is null, stop the script 32 | if ($null -eq $libraries) { 33 | throw "Unable to find Plex Library. Make sure your plex token is accurate!" 34 | } 35 | 36 | ## If the 4K movie library is null, stop the script 37 | $4K_PlexLibrary = $libraries.MediaContainer.Directory | Where-object { $psitem.Title -eq $4KLibraryName } 38 | if ($null -eq $4K_PlexLibrary) { 39 | throw "Unable to find $4KLibraryName. Is the name of your 4K library really named $4KLibraryName" 40 | } 41 | 42 | $4K_PlexLibrary_url = ($PlexURL + "/library/sections/$($4K_PlexLibrary.key)/all?X-Plex-Token=$plextoken") 43 | 44 | ## Return all of the 4K movies 45 | if ($SkipSSL) { 46 | $4K_PlexLibrary_results = (Invoke-RestMethod -uri $4K_PlexLibrary_url -SkipCertificateCheck).MediaContainer.Video 47 | } 48 | else { 49 | $4K_PlexLibrary_results = (Invoke-RestMethod -uri $4K_PlexLibrary_url).MediaContainer.Video 50 | } 51 | 52 | foreach ($m in $4K_PlexLibrary_results) { 53 | ## get the IMDB Id by extracing the numbers from the GUID of the movie result 54 | $imdbid_plex = "tt" + ($m.guid -replace "[^0-9]" , '') 55 | 56 | ## Get the movie from TMDB 57 | $tmdb = Get-TMDBMovie -ImdbID $imdbid_plex -API $TMDBToken 58 | 59 | ## Create the folder where we'll store the posters 60 | $Scriptblock = { 61 | Param( 62 | [PSObject] 63 | $Movie, 64 | 65 | [PSObject] 66 | $TMDB, 67 | 68 | [string] 69 | $PP, 70 | 71 | [string] 72 | $logopath, 73 | 74 | [string] 75 | $PlexURI, 76 | 77 | [string] 78 | $PlexToken, 79 | 80 | [string] 81 | $PlexFolderPath 82 | ) 83 | 84 | if (-not (Test-Path (Join-Path $PP "PlexMoviePosters" $($tmdb.Id)))) { 85 | 86 | Write-Verbose ("Creating folder - ($(Join-Path $pp "PlexMoviePosters" $($tmdb.Id)))") 87 | 88 | ## create the folder for the movie poster 89 | $null = New-Item -Path (Join-Path $PP "PlexMoviePosters") -Name $tmdb.Id -ItemType Directory 90 | 91 | Write-Verbose "Downloading the $($movie.title)" 92 | 93 | ## Picture path 94 | $picture = (Join-Path $PP "PlexMoviePosters" $($tmdb.Id) "poster.jpg") 95 | 96 | ## Download the poster 97 | Invoke-WebRequest -Uri "https://image.tmdb.org/t/p/original$($tmdb.poster_path)" -OutFile $picture 98 | 99 | Write-Verbose "Processing $($movie.title) - $($tmdb.Id) with magick" 100 | ## set the 4K picture path 101 | $4k_poster = Join-Path $pp "PlexMoviePosters" $($tmdb.Id) "4kposter.jpg" 102 | 103 | ## using magick, apply the 4K banner to the downloaded poster 104 | magick $picture $logopath -resize x"%[fx:t?u.h*0.1:u.h]" -background black -gravity north -extent "%[fx:u.w]x%[fx:s.h]" -composite $4k_poster 105 | 106 | $metadata_4k_url = $PlexURI + "/library/metadata/$($movie.ratingkey)/posters?includeExternalMedia=1&X-Plex-Token=$plextoken" 107 | 108 | $plexparams = @{ 109 | URI = $metadata_4k_url 110 | Method = "POST" 111 | InFile = $4k_poster 112 | } 113 | 114 | Write-Verbose "Setting 4K poster for $($movie.Title)" 115 | 116 | Invoke-RestMethod @plexparams 117 | } 118 | 119 | } 120 | 121 | Invoke-Command -ScriptBlock $Scriptblock -ArgumentList $m,$tmdb,$PosterPath,$4KLogoPath,$PlexURL,$PlexToken,$PosterPath 122 | } 123 | 124 | } 125 | 126 | } 127 | function Get-TMDBMovie { 128 | [CmdletBinding()] 129 | param ( 130 | [string] 131 | $ID, 132 | 133 | [string] 134 | $Name, 135 | 136 | [string] 137 | $IMDBID, 138 | 139 | [string] 140 | $API 141 | ) 142 | 143 | begin { 144 | $IRMParams = @{ 145 | Headers = @{ 146 | Authorization = ("Bearer {0}") -f $API 147 | } 148 | ContentType = "application/json" 149 | } 150 | } 151 | 152 | process { 153 | switch ($PSBoundParameters.Keys) { 154 | 'ID' { 155 | $URI = "https://api.themoviedb.org/3/movie/{0}" -f $ID 156 | Invoke-RestMethod -Uri $URI @IRMParams 157 | } 158 | 'Name' { 159 | $URI = "https://api.themoviedb.org/3/search/movie?query={0}" -f [uri]::EscapeDataString($name) 160 | (Invoke-RestMethod -Uri $URI @IRMParams).Results 161 | } 162 | 'IMDBID' { 163 | $URI = "https://api.themoviedb.org/3/find/{0}?api_key={1}&external_source=imdb_id" -f $IMDBID,$API 164 | (Invoke-RestMethod -Uri $URI).movie_results 165 | } 166 | Default { 167 | if ($ID -and $Name) { 168 | Write-Warning "Choose either ID or Movie name, not both." 169 | } 170 | } 171 | } 172 | } 173 | 174 | end { 175 | 176 | } 177 | } 178 | 179 | Export-ModuleMember -Function * -------------------------------------------------------------------------------- /Packer/Setup/autounattend.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | en-US 6 | 7 | 8 | 9 | 10 | 11 | B:\ 12 | 13 | 14 | 15 | 16 | 17 | 18 | true 19 | 20 | 21 | 22 | 23 | 24 | 25 | /IMAGE/NAME 26 | Windows Server 2016 SERVERSTANDARD 27 | 28 | 29 | true 30 | 31 | 32 | 33 | 34 | 35 | 0 36 | 37 | 38 | 1 39 | true 40 | Primary 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | false 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 1 60 | 61 | a:\vmtools.cmd 62 | Always 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | admin 73 | true</PlainText> 74 | </Password> 75 | <Enabled>true</Enabled> 76 | <Username>admin</Username> 77 | </AutoLogon> 78 | <FirstLogonCommands> 79 | <SynchronousCommand wcm:action="add"> 80 | <CommandLine>cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force"</CommandLine> 81 | <Description>Set Execution Policy 64 Bit</Description> 82 | <Order>1</Order> 83 | <RequiresUserInput>true</RequiresUserInput> 84 | </SynchronousCommand> 85 | <SynchronousCommand wcm:action="add"> 86 | <CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\Enable-WinRM.ps1</CommandLine> 87 | <Description>Enable WinRM and Reset AutoLogon Key</Description> 88 | <Order>2</Order> 89 | <RequiresUserInput>true</RequiresUserInput> 90 | </SynchronousCommand> 91 | </FirstLogonCommands> 92 | <OOBE> 93 | <HideEULAPage>true</HideEULAPage> 94 | <HideLocalAccountScreen>true</HideLocalAccountScreen> 95 | <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> 96 | <HideOnlineAccountScreens>true</HideOnlineAccountScreens> 97 | <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> 98 | <NetworkLocation>Home</NetworkLocation> 99 | <ProtectYourPC>1</ProtectYourPC> 100 | </OOBE> 101 | <UserAccounts> 102 | <AdministratorPassword> 103 | <Value>admin</Value> 104 | <PlainText>true</PlainText> 105 | </AdministratorPassword> 106 | <LocalAccounts> 107 | <LocalAccount wcm:action="add"> 108 | <Password> 109 | <Value>admin</Value> 110 | <PlainText>true</PlainText> 111 | </Password> 112 | <Group>administrators</Group> 113 | <DisplayName>admin</DisplayName> 114 | <Name>admin</Name> 115 | <Description>Admin User</Description> 116 | </LocalAccount> 117 | </LocalAccounts> 118 | </UserAccounts> 119 | <RegisteredOwner/> 120 | </component> 121 | </settings> 122 | </unattend> -------------------------------------------------------------------------------- /Utilities/Get-InstalledSoftware.ps1: -------------------------------------------------------------------------------- 1 | function Get-InstalledSoftware { 2 | <# 3 | .SYNOPSIS 4 | Get all installed from the Uninstall keys in the registry. 5 | .DESCRIPTION 6 | Read a list of installed software from each Uninstall key. 7 | 8 | This function provides an alternative to using Win32_Product. 9 | .EXAMPLE 10 | Get-InstalledSoftware 11 | 12 | Get the list of installed applications from the local computer. 13 | .EXAMPLE 14 | Get-InstalledSoftware -IncludeLoadedUserHives 15 | 16 | Get the list of installed applications from the local computer, including each loaded user hive. 17 | .EXAMPLE 18 | Get-InstalledSoftware -ComputerName None -DebugConnection 19 | 20 | Display all error messages thrown when attempting to audit the specified computer. 21 | .EXAMPLE 22 | Get-InstalledSoftware -IncludeBlankNames 23 | 24 | Display all results, including those with very limited information. 25 | #> 26 | 27 | [CmdletBinding()] 28 | [OutputType([PSObject])] 29 | param ( 30 | # The computer to execute against. By default, Get-InstalledSoftware reads registry keys on the local computer. 31 | [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] 32 | [String]$ComputerName = $env:COMPUTERNAME, 33 | 34 | # Attempt to start the remote registry service if it is not already running. This parameter will only take effect if the service is not disabled. 35 | [Switch]$StartRemoteRegistry, 36 | 37 | # Some software packages, such as DropBox install into a users profile rather than into shared areas. Get-InstalledSoftware can increase the search to include each loaded user hive. 38 | # 39 | # If a registry hive is not loaded it cannot be searched, this is a limitation of this search style. 40 | [Switch]$IncludeLoadedUserHives, 41 | 42 | # By default Get-InstalledSoftware will suppress the display of entries with minimal information. If no DisplayName is set it will be hidden from view. This behaviour may be changed using this parameter. 43 | [Switch]$IncludeBlankNames 44 | ) 45 | 46 | $keys = 'Software\Microsoft\Windows\CurrentVersion\Uninstall', 47 | 'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' 48 | 49 | # If the remote registry service is stopped before this script runs it will be stopped again afterwards. 50 | if ($StartRemoteRegistry) { 51 | $shouldStop = $false 52 | $service = Get-Service RemoteRegistry -Computer $ComputerName 53 | 54 | if ($service.Status -eq 'Stopped' -and $service.StartType -ne 'Disabled') { 55 | $shouldStop = $true 56 | $service | Start-Service 57 | } 58 | } 59 | 60 | $baseKeys = [System.Collections.Generic.List[Microsoft.Win32.RegistryKey]]::new() 61 | 62 | $baseKeys.Add([Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $ComputerName, 'Registry64')) 63 | if ($IncludeLoadedUserHives) { 64 | try { 65 | $baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $ComputerName, 'Registry64') 66 | foreach ($name in $baseKey.GetSubKeyNames()) { 67 | if (-not $name.EndsWith('_Classes')) { 68 | Write-Debug ('Opening {0}' -f $name) 69 | 70 | try { 71 | $baseKeys.Add($baseKey.OpenSubKey($name, $false)) 72 | } 73 | catch { 74 | $errorRecord = [System.Management.Automation.ErrorRecord]::new( 75 | $_.Exception.GetType()::new( 76 | ('Unable to access sub key {0} ({1})' -f $name, $_.Exception.InnerException.Message.Trim()), 77 | $_.Exception 78 | ), 79 | 'SubkeyAccessError', 80 | 'InvalidOperation', 81 | $name 82 | ) 83 | Write-Error -ErrorRecord $errorRecord 84 | } 85 | } 86 | } 87 | } 88 | catch [Exception] { 89 | Write-Error -ErrorRecord $_ 90 | } 91 | } 92 | 93 | foreach ($baseKey in $baseKeys) { 94 | Write-Verbose ('Reading {0}' -f $baseKey.Name) 95 | 96 | if ($basekey.Name -eq 'HKEY_LOCAL_MACHINE') { 97 | $username = 'LocalMachine' 98 | } 99 | else { 100 | # Attempt to resolve a SID 101 | try { 102 | [System.Security.Principal.SecurityIdentifier]$sid = Split-Path $baseKey.Name -Leaf 103 | $username = $sid.Translate([System.Security.Principal.NTAccount]).Value 104 | } 105 | catch { 106 | $username = Split-Path $baseKey.Name -Leaf 107 | } 108 | } 109 | 110 | foreach ($key in $keys) { 111 | try { 112 | $uninstallKey = $baseKey.OpenSubKey($key, $false) 113 | 114 | if ($uninstallKey) { 115 | $is64Bit = $true 116 | if ($key -match 'Wow6432Node') { 117 | $is64Bit = $false 118 | } 119 | 120 | foreach ($name in $uninstallKey.GetSubKeyNames()) { 121 | $packageKey = $uninstallKey.OpenSubKey($name) 122 | 123 | $installDate = Get-Date 124 | $dateString = $packageKey.GetValue('InstallDate') 125 | if (-not $dateString -or -not [DateTime]::TryParseExact($dateString, 'yyyyMMdd', (Get-Culture), 'None', [Ref]$installDate)) { 126 | $installDate = $null 127 | } 128 | 129 | [PSCustomObject]@{ 130 | Name = $name 131 | DisplayName = $packageKey.GetValue('DisplayName') 132 | DisplayVersion = $packageKey.GetValue('DisplayVersion') 133 | InstallDate = $installDate 134 | InstallLocation = $packageKey.GetValue('InstallLocation') 135 | HelpLink = $packageKey.GetValue('HelpLink') 136 | Publisher = $packageKey.GetValue('Publisher') 137 | UninstallString = $packageKey.GetValue('UninstallString') 138 | URLInfoAbout = $packageKey.GetValue('URLInfoAbout') 139 | Is64Bit = $is64Bit 140 | Hive = $baseKey.Name 141 | Path = Join-Path $key $name 142 | Username = $username 143 | ComputerName = $ComputerName 144 | } 145 | } 146 | } 147 | } 148 | catch { 149 | Write-Error -ErrorRecord $_ 150 | } 151 | } 152 | } 153 | 154 | # Stop the remote registry service if required 155 | if ($StartRemoteRegistry -and $shouldStop) { 156 | $service | Stop-Service 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /TLS/TLS.ps1: -------------------------------------------------------------------------------- 1 | Function Disable-LegacyProtocol { 2 | 3 | $TLSArray = @( 4 | "SSL 2.0", 5 | "SSL 3.0", 6 | "TLS 1.0", 7 | "TLS 1.1" 8 | ) 9 | 10 | Foreach ($item in $TLSArray) { 11 | ## Create the parent key for Server 12 | New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Server" -Force | Out-Null 13 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Server" -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null 14 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Server" -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null 15 | 16 | ## Create the parent key for Client 17 | New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Client" -Force | Out-Null 18 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Client" -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null 19 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Client" -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null 20 | } 21 | } 22 | 23 | Function Disable-WeakCipher { 24 | $insecureCiphers = @( 25 | 'DES 56/56', 26 | 'NULL', 27 | 'RC2 128/128', 28 | 'RC2 40/128', 29 | 'RC2 56/128', 30 | 'RC4 40/128', 31 | 'RC4 56/128', 32 | 'RC4 64/128', 33 | 'RC4 128/128', 34 | 'Triple DES 168' 35 | ) 36 | 37 | $CipherPath = 'HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers' 38 | New-Item $CipherPath -Force | Out-Null 39 | foreach ($item in $insecureCiphers) { 40 | New-Item -Path "$cipherpath\$item" 41 | New-ItemProperty -Path "$cipherPath\$item" -Name Enabled -Value 0 -PropertyType 'DWord' -Force | Out-Null 42 | } 43 | } 44 | 45 | Function Enable-StrongCipher { 46 | $insecureCiphers = @( 47 | 'AES 128/128', 48 | 'AES 256/256' 49 | ) 50 | 51 | New-Item 'HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers' -Force | Out-Null 52 | 53 | foreach ($item in $insecureCiphers) { 54 | New-Item -Path "HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\$item" 55 | New-ItemProperty -Path "HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\$item" -Name Enabled -Value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null 56 | } 57 | } 58 | 59 | Function Enable-ModernProtocol { 60 | 61 | $TLSArray = @( 62 | "TLS 1.2" 63 | ) 64 | 65 | Foreach ($item in $TLSArray) { 66 | ## Create the parent key for Server 67 | New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Server" -Force | Out-Null 68 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Server" -name Enabled -value "0xffffffff" -PropertyType 'DWord' -Force | Out-Null 69 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Server" -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null 70 | 71 | ## Create the parent key for Client 72 | New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Client" -Force | Out-Null 73 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Client" -name Enabled -value "0xffffffff" -PropertyType 'DWord' -Force | Out-Null 74 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$item\Client" -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null 75 | } 76 | } 77 | 78 | Function Enable-SecureHash { 79 | $secureHashes = @( 80 | 'SHA', 81 | 'SHA256', 82 | 'SHA384', 83 | 'SHA512' 84 | ) 85 | 86 | New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes" -Force | Out-Null 87 | 88 | Foreach ($secureHash in $secureHashes) { 89 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\$secureHash" -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null 90 | } 91 | } 92 | 93 | Function Enable-SecureyKeyExchangeAlgorithm { 94 | $secureKeyExchangeAlgorithms = @( 95 | 'Diffie-Hellman', 96 | 'ECDH', 97 | 'PKCS' 98 | ) 99 | 100 | New-Item 'HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms' -Force | Out-Null 101 | 102 | Foreach ($secureKeyExchangeAlgorithm in $secureKeyExchangeAlgorithms) { 103 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\$secureKeyExchangeAlgorithm" -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null 104 | 105 | } 106 | } 107 | 108 | Function Enable-DiffieHellmanKeyExchange { 109 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman" -name 'ServerMinKeyBitLength' -value '2048' -PropertyType 'DWord' -Force | Out-Null 110 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman" -name 'ClientMinKeyBitLength' -value '2048' -PropertyType 'DWord' -Force | Out-Null 111 | New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\PKCS" -name 'ClientMinKeyBitLength' -value '2048' -PropertyType 'DWord' -Force | Out-Null 112 | } 113 | 114 | Function Enable-TLSforDotNet { 115 | New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v2.0.50727" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null 116 | New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v2.0.50727" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null 117 | New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null 118 | New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null 119 | if (Test-Path 'HKLM:\SOFTWARE\Wow6432Node') { 120 | New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null 121 | New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null 122 | New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null 123 | New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null 124 | } 125 | } 126 | 127 | Function Enable-CipherSuiteOrder { 128 | $cipherSuitesOrder = @( 129 | 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', 130 | 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', 131 | 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384', 132 | 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', 133 | 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA', 134 | 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA', 135 | 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', 136 | 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', 137 | 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384', 138 | 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', 139 | 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA', 140 | 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA' 141 | ) 142 | $cipherSuitesAsString = [string]::join(',', $cipherSuitesOrder) 143 | # One user reported this key does not exists on Windows 2012R2. Cannot repro myself on a brand new Windows 2012R2 core machine. Adding this just to be save. 144 | New-Item 'HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002' -ErrorAction SilentlyContinue 145 | New-ItemProperty -path 'HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002' -name 'Functions' -value $cipherSuitesAsString -PropertyType 'String' -Force | Out-Null 146 | 147 | } 148 | 149 | Function Enable-TLSForWinHTTP { 150 | 151 | $file_version_winhttp_dll = (Get-Item $env:windir\System32\winhttp.dll).VersionInfo | 152 | ForEach-Object { ("{0}.{1}.{2}.{3}" -f $_.ProductMajorPart, $_.ProductMinorPart, $_.ProductBuildPart, $_.ProductPrivatePart) } 153 | 154 | $file_version_webio_dll = (Get-Item $env:windir\System32\Webio.dll).VersionInfo | 155 | ForEach-Object { ("{0}.{1}.{2}.{3}" -f $_.ProductMajorPart, $_.ProductMinorPart, $_.ProductBuildPart, $_.ProductPrivatePart) } 156 | 157 | if ([System.Version]$file_version_winhttp_dll -lt [System.Version]"6.1.7601.23375" -or [System.Version]$file_version_webio_dll -lt [System.Version]"6.1.7601.23375") { 158 | Write-Error 'WinHTTP: Cannot enable TLS 1.2. Please see https://support.microsoft.com/en-us/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-a-default-secure-protocols-in for system requirements.' 159 | } 160 | else { 161 | New-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -name 'DefaultSecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null 162 | if (Test-Path 'HKLM:\SOFTWARE\Wow6432Node') { 163 | # WinHttp key seems missing in Windows 2019 for unknown reasons. 164 | New-Item 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -ErrorAction SilentlyContinue | Out-Null 165 | New-ItemProperty -path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -name 'DefaultSecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null 166 | } 167 | } 168 | 169 | New-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name 'SecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null 170 | New-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings' -name 'SecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null 171 | 172 | } 173 | 174 | function Get-SecurityProtocol { 175 | Param( 176 | [Parameter(Mandatory)] 177 | [ValidateSet( 178 | "SSL 2.0", 179 | "SSL 3.0", 180 | "TLS 1.0", 181 | "TLS 1.0", 182 | "TLS 1.1", 183 | "TLS 1.2" 184 | )] 185 | $Protocol, 186 | 187 | [String[]] 188 | $ComputerName 189 | ) 190 | 191 | begin { 192 | $server = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$Protocol\Server" 193 | $client = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\$Protocol\Client" 194 | } 195 | 196 | process { 197 | ## Enabled key 198 | $server_enabled = Get-ItemProperty -Path $server -name 'Enabled' -ErrorAction SilentlyContinue 199 | $client_enabled = Get-ItemProperty -Path $client -name 'Enabled' -ErrorAction SilentlyContinue 200 | ## Disabled By Default Key 201 | 202 | } 203 | 204 | end { 205 | 206 | } 207 | } 208 | 209 | <# 210 | $tls12 = try { 211 | $resp = (New-Object System.Net.WebClient).DownloadString("https://tls-v1-2.badssl.com:1012/") 212 | [bool] $resp.Contains("green") 213 | } 214 | catch { 215 | $false 216 | } 217 | 218 | $url ="https://stackoverflow.com/questions/51405489/what-is-the-difference-between-the-disabledbydefault-and-enabled-ssl-tls-registr" 219 | 220 | $anotherurl = "https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#support-for-tls-12" 221 | #> -------------------------------------------------------------------------------- /Utilities/Get-PortCertificate.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PortCertificate { 2 | 3 | <# 4 | 5 | .SYNOPSIS 6 | Returns certificate information from a listening TLS/SSL service port. 7 | 8 | .DESCRIPTION 9 | Gets the associated certificate from a TLS/SSL application service port. 10 | 11 | .PARAMETER Computername 12 | Hostname or IP address of the target system (Default: localhost). The function uses the supplied computername to validate with the certificate's subject name(s). 13 | 14 | .PARAMETER Port 15 | Port to retrieve SSL certificate (Default: 443). 16 | 17 | .PARAMETER Path 18 | Directory path to save SSL certificate(s). 19 | 20 | .PARAMETER DownloadChain 21 | Save all chain certificates to file. A certificate chain folder will be created under the specfied -path directory. -DownloadChain is dependent on the path parameter. 22 | 23 | .NOTES 24 | Name: Get-PortCertificate 25 | Author: Caleb Keene 26 | Updated: 08-30-2016 27 | Version: 1.2 28 | 29 | .EXAMPLE 30 | Get-PortCertificate -Computername Server1 -Port 3389 -Path C:\temp -verbose 31 | 32 | .EXAMPLE 33 | "server1","server2","server3" | Get-PortCertificate 34 | #> 35 | 36 | 37 | [CmdletBinding()] 38 | param( 39 | [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] 40 | [Alias('IPAddress', 'Server', 'Computer')] 41 | [string]$ComputerName = $env:COMPUTERNAME, 42 | [Parameter(Mandatory = $false, Position = 1)] 43 | [ValidateRange(1, 65535)] 44 | [int]$Port = 443, 45 | [Parameter(Mandatory = $false)] 46 | [ValidateNotNullorEmpty()] 47 | [string]$Path 48 | 49 | ) 50 | #use a dynamic parameter to prevent -downloadchain without -path. 51 | DynamicParam { 52 | #Need some sort of conditional check before allowing Dynamic Parameter 53 | If ($PSBoundParameters.ContainsKey('Path')) { 54 | #Same as [Parameter()] 55 | $attribute = new-object System.Management.Automation.ParameterAttribute 56 | $attribute.Mandatory = $false 57 | $AttributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute] 58 | $AttributeCollection.Add($attribute) 59 | 60 | #Build out the Dynamic Parameter 61 | # Need the Parameter Name, Type and Attribute Collection (Built already) 62 | $DynamicParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("DownloadChain", [switch], $AttributeCollection) 63 | 64 | $ParamDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary 65 | $ParamDictionary.Add("DownloadChain", $DynamicParam) 66 | return $ParamDictionary 67 | } 68 | } 69 | 70 | Begin { 71 | #make sure the version is supported 72 | if ($psversiontable.psversion.Major -le 2 ) { 73 | Write-warning "Function requires PowerShell version 3 or later." 74 | break 75 | } 76 | 77 | #add a custom type name to control our objects default display properties 78 | try { Update-TypeData -TypeName 'Get.PortCertificate' -DefaultDisplayPropertySet Subject, Issuer, NotAfter, NotBefore, ExpiresIn, CertificateValidNames, TargetName, TargetNameStatus, TargetNameStatusDetails, TargetNameIsValid, ChainPath, ChainStatus, ChainStatusDetails, CertificateIsValid, Thumbprint -ErrorAction stop } 79 | catch { } 80 | 81 | #validate that the path is a filesystem directory 82 | if ($path) { 83 | 84 | if (-not(test-path -PathType Container FileSystem::$path)) { 85 | Write-warning "The supplied directory path is not valid: $path" 86 | break 87 | } 88 | 89 | } 90 | 91 | } 92 | 93 | Process { 94 | 95 | #make sure we are able to establish a port connection 96 | 97 | #Set our connection timeout 98 | $timeout = 1000 99 | 100 | #Create object to test the port connection 101 | $tcpobject = New-Object System.Net.Sockets.TcpClient 102 | 103 | #Connect to remote port 104 | $connect = $tcpobject.BeginConnect($ComputerName, $Port, $null, $null) 105 | 106 | #Configure connection timeout 107 | $wait = $connect.AsyncWaitHandle.WaitOne($timeout, $false) 108 | If (-NOT $Wait) { 109 | Write-Warning "[$($ComputerName)] Connection to port $($Port) timed out after $($timeout) milliseconds" 110 | return 111 | } 112 | Else { 113 | Try { 114 | [void]$tcpobject.EndConnect($connect) 115 | Write-Verbose "[$($ComputerName)] Successfully connected to port $($Port). Good!" 116 | } 117 | Catch { 118 | Write-Warning "[$($ComputerName)] $_" 119 | return 120 | } 121 | } 122 | 123 | #Note: This also works for validating the port connection, but the default timeout when unable to connect is a bit long. 124 | <# 125 | try { 126 | (New-Object system.net.sockets.tcpclient -ArgumentList $computername,$port -ErrorAction stop).Connected 127 | } 128 | catch{ 129 | Write-Warning ("Unable to connect to {0} on port {1}"-f$ComputerName,$Port) 130 | return 131 | } 132 | #> 133 | 134 | 135 | Write-Verbose "[$($ComputerName)] Getting SSL certificate from port $($Port)." 136 | 137 | #create our webrequest object for the ssl connection 138 | $sslrequest = [Net.WebRequest]::Create("https://$ComputerName`:$port") 139 | 140 | #make the connection and store the response (if any). 141 | try { $Response = $sslrequest.GetResponse() } 142 | catch { } 143 | 144 | #load the returned SSL certificate using x509certificate2 class 145 | if ($certificate = [Security.Cryptography.X509Certificates.X509Certificate2]$sslrequest.ServicePoint.Certificate.Handle) { 146 | 147 | Write-Verbose "[$($ComputerName)] Certificate found! Building certificate chain information and object data." 148 | 149 | #build our certificate chain object 150 | $chain = [Security.Cryptography.X509Certificates.X509Chain]::create() 151 | $isValid = $chain.Build($certificate) 152 | 153 | #get certificate subject names from our certificate extensions 154 | $validnames = @() 155 | try { [array]$validnames += @(($certificate.Extensions | ? { $_.Oid.Value -eq "2.5.29.17" }).Format($true).split("`n") | ? { $_ } | % { $_.split("=")[1].trim() }) }catch { } 156 | try { [array]$validnames += @($certificate.subject.split(",")[0].split("=")[1].trim()) }catch { } 157 | 158 | #validate the target name 159 | for ($i = 0; $i -le $validnames.count - 1; $i++) { 160 | if ($validnames[$i] -match '^\*') { 161 | $wildcard = $validnames[$i] -replace '^\*\.' 162 | if ($computername -match "$wildcard$") { 163 | $TargetNameIsValid = $true 164 | break 165 | } 166 | $TargetNameIsValid = $false 167 | } 168 | else { 169 | if ($validnames[$i] -match "^$ComputerName$") { 170 | $TargetNameIsValid = $true 171 | break 172 | } 173 | $TargetNameIsValid = $false 174 | } 175 | } 176 | 177 | #create custom object to later convert to PSobject (required in order to use the custom type name's default display properties) 178 | $customized = $certificate | select *, 179 | @{n = "ExtensionData"; e = { $_.Extensions | % { @{$_.oid.friendlyname.trim() = $_.format($true).trim() } } } }, 180 | @{n = "ResponseUri"; e = { if ($Response.ResponseUri) { $Response.ResponseUri }else { $false } } }, 181 | @{n = "ExpiresIn"; e = { if ((get-date) -gt $_.NotAfter) { "Certificate has expired!" }else { $timespan = New-TimeSpan -end $_.notafter; "{0} Days - {1} Hours - {2} Minutes" -f $timespan.days, $timespan.hours, $timespan.minutes } } }, 182 | @{n = "TargetName"; e = { $ComputerName } }, 183 | @{n = "CertificateValidNames"; e = { $validnames } }, 184 | @{n = "ChainPath"; e = { $count = 0; $chaincerts = @($chain.ChainElements.certificate.subject); $($chaincerts[($chaincerts.length - 1) .. 0] | % { "{0,$(5+$count)}{1}" -f "---", $_; $count += 3 }) -join "`n" } }, 185 | @{n = "ChainCertificates"; e = { @{"Certificates" = $chain.ChainElements.certificate } } }, 186 | @{n = "ChainStatus"; e = { if ($isvalid -and !$_.chainstatus) { "Good" }else { $chain.chainstatus.Status } } }, 187 | @{n = "ChainStatusDetails"; e = { if ($isvalid -and !$_.chainstatus) { "The certificate chain is valid." }else { $chain.chainstatus.StatusInformation.trim() } } }, 188 | @{n = "CertificateIsValid"; e = { $isValid } }, 189 | @{n = "TargetNameIsValid"; e = { $TargetNameIsValid } }, 190 | @{n = "TargetNameStatus"; e = { if ($TargetNameIsValid) { "Good" }else { "Invalid" } } }, 191 | @{n = "TargetNameStatusDetails"; e = { if ($TargetNameIsValid) { "The target name appears to be valid: $computername" }else { "TargetName $computername does not match any certificate subject name." } } } 192 | 193 | 194 | #get object properties for our PSObject 195 | $objecthash = [Ordered]@{ } 196 | ($customized | Get-Member -MemberType Properties).name | % { $objecthash += @{$_ = $customized.$_ } } 197 | 198 | #create the PSObject 199 | $psobject = New-Object psobject -Property $objecthash 200 | 201 | #add the custom type name to the PSObject 202 | $psobject.PSObject.TypeNames.Insert(0, 'Get.PortCertificate') 203 | 204 | #save our certificate(s) to file if applicable 205 | if ($path) { 206 | 207 | write-verbose "Saving certificate(s) to file." 208 | 209 | try { 210 | $psobject.RawData | Set-Content -Encoding Byte -Path "$path\Cert`_$ComputerName`_$port`.cer" -ErrorAction stop 211 | write-verbose "Certificate saved to $path\Cert`_$ComputerName`_$port`.cer." 212 | } 213 | catch { write-warning ("Unable to save certificate to {0}: {1}" -f "$path\Cert`_$ComputerName`_$port`.cer", $_.exception.message) } 214 | 215 | if ($PSBoundParameters.ContainsKey('DownloadChain')) { 216 | 217 | New-Item -ItemType directory -path "$path\ChainCerts`_$ComputerName`_$port" -ErrorAction SilentlyContinue > $null 218 | 219 | $psobject.chaincertificates.certificates | % { 220 | try { 221 | Set-Content $_.RawData -Encoding Byte -Path "$path\ChainCerts`_$ComputerName`_$port\$($_.thumbprint)`.cer" -ErrorAction stop 222 | write-verbose "Certificate chain certificate saved to $path\ChainCerts`_$ComputerName`_$port\$($_.thumbprint)`.cer." 223 | } 224 | catch { 225 | write-warning ("Unable to save certificate chain certificate to {0}: {1}" -f "$path\ChainCerts`_$ComputerName`_$port", $_.exception.message) 226 | } 227 | } 228 | } 229 | } 230 | 231 | #abort any connections 232 | $sslrequest.abort() 233 | 234 | #return the object 235 | $psobject 236 | 237 | } 238 | 239 | else { 240 | #we were able to connect to the port but no ssl certificate was returned 241 | write-warning ("[{0}] No certificate returned on port {1}." -f $ComputerName, $Port) 242 | 243 | #abort any connections 244 | $sslrequest.abort() 245 | 246 | return 247 | } 248 | } 249 | } -------------------------------------------------------------------------------- /Security/Get-TLSSetting.ps1: -------------------------------------------------------------------------------- 1 | function Get-TLSSetting { 2 | [CmdletBinding()] 3 | param ( 4 | [string[]] 5 | $ComputerName = $ENV:COMPUTERNAME 6 | ) 7 | 8 | ## Get Cipher Suite Values 9 | Invoke-Command -ComputerName $ComputerName -ScriptBlock { 10 | 11 | $ErrorActionPreference = "SilentlyContinue" 12 | 13 | ## Check SSL v2 14 | $ssl2clientenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client" -Name "Enabled" -ErrorAction SilentlyContinue 15 | $ssl2clientdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 16 | $ssl2serverenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server" -Name "Enabled" -ErrorAction SilentlyContinue 17 | $ssl2serverdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 18 | 19 | ## Check SSL v3 20 | $ssl3clientenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client" -Name "Enabled" -ErrorAction SilentlyContinue 21 | $ssl3clientdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 22 | $ssl3serverenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server" -Name "Enabled" -ErrorAction SilentlyContinue 23 | $ssl3serverdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 24 | 25 | ## Check TLS 1.0 26 | $tls1clientenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client" -Name "Enabled" -ErrorAction SilentlyContinue 27 | $tls1clientdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 28 | $tls1serverenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" -Name "Enabled" -ErrorAction SilentlyContinue 29 | $tls1serverdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 30 | 31 | ## Check TLS 1.1 32 | $tls11clientenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" -Name "Enabled" -ErrorAction SilentlyContinue 33 | $tls11clientdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 34 | $tls11serverenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" -Name "Enabled" -ErrorAction SilentlyContinue 35 | $tls11serverdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 36 | 37 | ## Check TLS 1.2 38 | $tls12clientenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client" -Name "Enabled" -ErrorAction SilentlyContinue 39 | $tls12clientdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 40 | $tls12serverenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server" -Name "Enabled" -ErrorAction SilentlyContinue 41 | $tls12serverdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 42 | 43 | ## Check TLS 1.3 44 | $tls13clientenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client" -Name "Enabled" -ErrorAction SilentlyContinue 45 | $tls13clientdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 46 | $tls13serverenabled = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server" -Name "Enabled" -ErrorAction SilentlyContinue 47 | $tls13serverdisabledbydefault = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server" -Name "DisabledByDefault" -ErrorAction SilentlyContinue 48 | 49 | ## Check Diffie Hellman 50 | $DiffieHellman = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman" -Name "Enabled" -ErrorAction SilentlyContinue 51 | $DiffieHellmanKeyBit = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman" -Name "ServerMinKeyBitLength" -ErrorAction SilentlyContinue 52 | 53 | ## Check Weak Ciphers 54 | $RC4128 = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 128/128" -Name "Enabled" -ErrorAction SilentlyContinue 55 | $RC456128 = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 56/128" -Name "Enabled" -ErrorAction SilentlyContinue 56 | $RC440128 = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\RC4 40/128" -Name "Enabled" -ErrorAction SilentlyContinue 57 | $tripledes168 = Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\Triple DES 168" -Name "Enabled" -ErrorAction SilentlyContinue 58 | 59 | ## SSL v2 Client Stuff 60 | if ((($ssl2clientenabled -eq 0) -and ($ssl2clientdisabledbydefault -eq 1)) -or ($null -eq $ssl2clientenabled) -and ($null -eq $ssl2clientdisabledbydefault)) { 61 | $ssl2clientenabled_result = $False 62 | } 63 | elseif (($ssl2clientenabled -eq 1) -and ($ssl2clientdisabledbydefault -eq 1)) { 64 | $ssl2clientenabled_result = "Partial" 65 | } 66 | elseif (($ssl2clientenabled -eq 0) -and ($ssl2clientdisabledbydefault -eq 0)) { 67 | $ssl2clientenabled_result = "Partial" 68 | } 69 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 70 | elseif (($ssl2clientenabled -eq 0) -and ($ssl2clientdisabledbydefault -eq 0)) { 71 | $ssl2clientenabled_result = "Partial" 72 | } 73 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 74 | elseif (($ssl2clientdisabledbydefault -eq 0) -and ($null -eq $ssl2clientenabled)) { 75 | $ssl2clientenabled_result = "Partial" 76 | } 77 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 78 | elseif (($ssl2clientdisabledbydefault -eq 1) -and ($null -eq $ssl2clientenabled)) { 79 | $ssl2clientenabled_result = "Partial" 80 | } 81 | else { 82 | $ssl2clientenabled_result = $True 83 | } 84 | 85 | ## SSL v2 Server Stuff 86 | if ((($ssl2serverenabled -eq 0) -and ($ssl2serverdisabledbydefault -eq 1)) -or ($null -eq $ssl2serverenabled) -and ($null -eq $ssl2serverdisabledbydefault)) { 87 | $ssl2serverenabled_result = $False 88 | } 89 | elseif (($ssl2serverenabled -eq 1) -and ($ssl2serverdisabledbydefault -eq 1)) { 90 | $ssl2serverenabled_result = "Partial" 91 | } 92 | elseif (($ssl2serverenabled -eq 0) -and ($ssl2serverdisabledbydefault -eq 0)) { 93 | $ssl2serverenabled_result = "Partial" 94 | } 95 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 96 | elseif (($ssl2serverenabled -eq 0) -and ($ssl2serverdisabledbydefault -eq 0)) { 97 | $ssl2serverenabled_result = "Partial" 98 | } 99 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 100 | elseif (($ssl2serverdisabledbydefault -eq 0) -and ($null -eq $ssl2serverenabled)) { 101 | $ssl2serverenabled_result = "Partial" 102 | } 103 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 104 | elseif (($ssl2serverdisabledbydefault -eq 1) -and ($null -eq $ssl2serverenabled)) { 105 | $ssl2serverenabled_result = "Partial" 106 | } 107 | else { 108 | $ssl2serverenabled_result = $True 109 | } 110 | 111 | ## SSL v3 Client Stuff 112 | if ((($ssl3clientenabled -eq 0) -and ($ssl3clientdisabledbydefault -eq 1)) -or ($null -eq $ssl3clientenabled) -and ($null -eq $ssl3clientdisabledbydefault)) { 113 | $ssl3clientenabled_result = $False 114 | } 115 | elseif (($ssl3clientenabled -eq 1) -and ($ssl3clientdisabledbydefault -eq 1)) { 116 | $ssl3clientenabled_result = "Partial" 117 | } 118 | elseif (($ssl3clientenabled -eq 0) -and ($ssl3clientdisabledbydefault -eq 0)) { 119 | $ssl3clientenabled_result = "Partial" 120 | } 121 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 122 | elseif (($ssl3clientenabled -eq 0) -and ($ssl3clientdisabledbydefault -eq 0)) { 123 | $ssl3clientenabled_result = "Partial" 124 | } 125 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 126 | elseif (($ssl3clientdisabledbydefault -eq 0) -and ($null -eq $ssl3clientenabled)) { 127 | $ssl3clientenabled_result = "Partial" 128 | } 129 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 130 | elseif (($ssl3clientdisabledbydefault -eq 1) -and ($null -eq $ssl3clientenabled)) { 131 | $ssl3clientenabled_result = "Partial" 132 | } 133 | else { 134 | $ssl3clientenabled_result = $True 135 | } 136 | 137 | ## SSL v3 Server Stuff 138 | if ((($ssl3serverenabled -eq 0) -and ($ssl3serverdisabledbydefault -eq 1)) -or ($null -eq $ssl3serverenabled) -and ($null -eq $ssl3serverdisabledbydefault)) { 139 | $ssl3serverenabled_result = $False 140 | } 141 | elseif (($ssl3serverenabled -eq 1) -and ($ssl3serverdisabledbydefault -eq 1)) { 142 | $ssl3serverenabled_result = "Partial" 143 | } 144 | elseif (($ssl3serverenabled -eq 0) -and ($ssl3serverdisabledbydefault -eq 0)) { 145 | $ssl3serverenabled_result = "Partial" 146 | } 147 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 148 | elseif (($ssl3serverenabled -eq 0) -and ($ssl3serverdisabledbydefault -eq 0)) { 149 | $ssl3serverenabled_result = "Partial" 150 | } 151 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 152 | elseif (($ssl3serverdisabledbydefault -eq 0) -and ($null -eq $ssl3serverenabled)) { 153 | $ssl3serverenabled_result = "Partial" 154 | } 155 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 156 | elseif (($ssl3serverdisabledbydefault -eq 1) -and ($null -eq $ssl3serverenabled)) { 157 | $ssl3serverenabled_result = "Partial" 158 | } 159 | else { 160 | $ssl3serverenabled_result = $True 161 | } 162 | 163 | ## TLS 1.0 Client Stuff 164 | if ((($tls1clientenabled -eq 0) -and ($tls1clientdisabledbydefault -eq 1)) -or ($null -eq $tls1clientenabled) -and ($null -eq $tls1clientdisabledbydefault)) { 165 | $tls1clientenabled_result = $False 166 | } 167 | elseif (($tls1clientenabled -eq 1) -and ($tls1clientdisabledbydefault -eq 1)) { 168 | $tls1clientenabled_result = "Partial" 169 | } 170 | elseif (($tls1clientenabled -eq 0) -and ($tls1clientdisabledbydefault -eq 0)) { 171 | $tls1clientenabled_result = "Partial" 172 | } 173 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 174 | elseif (($tls1clientenabled -eq 0) -and ($tls1clientdisabledbydefault -eq 0)) { 175 | $tls1clientenabled_result = "Partial" 176 | } 177 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 178 | elseif (($tls1clientdisabledbydefault -eq 0) -and ($null -eq $tls1clientenabled)) { 179 | $tls1clientenabled_result = "Partial" 180 | } 181 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 182 | elseif (($tls1clientdisabledbydefault -eq 1) -and ($null -eq $tls1clientenabled)) { 183 | $tls1clientenabled_result = "Partial" 184 | } 185 | else { 186 | $tls1clientenabled_result = $True 187 | } 188 | 189 | ## TLS 1.0 Server Stuff 190 | if ((($tls1serverenabled -eq 0) -and ($tls1serverdisabledbydefault -eq 1)) -or ($null -eq $tls1serverenabled) -and ($null -eq $tls1serverdisabledbydefault)) { 191 | $tls1serverenabled_result = $False 192 | } 193 | elseif (($tls1serverenabled -eq 1) -and ($tls1serverdisabledbydefault -eq 1)) { 194 | $tls1serverenabled_result = "Partial" 195 | } 196 | elseif (($tls1serverenabled -eq 0) -and ($tls1serverdisabledbydefault -eq 0)) { 197 | $tls1serverenabled_result = "Partial" 198 | } 199 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 200 | elseif (($tls1serverenabled -eq 0) -and ($tls1serverdisabledbydefault -eq 0)) { 201 | $tls1serverenabled_result = "Partial" 202 | } 203 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 204 | elseif (($tls1serverdisabledbydefault -eq 0) -and ($null -eq $tls1serverenabled)) { 205 | $tls1serverenabled_result = "Partial" 206 | } 207 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 208 | elseif (($tls1serverdisabledbydefault -eq 1) -and ($null -eq $tls1serverenabled)) { 209 | $tls1serverenabled_result = "Partial" 210 | } 211 | else { 212 | $tls1serverenabled_result = $True 213 | } 214 | 215 | ## TLS 1.1 Client Stuff 216 | if ((($tls11clientenabled -eq 0) -and ($tls11clientdisabledbydefault -eq 1)) -or ($null -eq $tls11clientenabled) -and ($null -eq $tls11clientdisabledbydefault)) { 217 | $tls11clientenabled_result = $False 218 | } 219 | elseif (($tls11clientenabled -eq 1) -and ($tls11clientdisabledbydefault -eq 1)) { 220 | $tls11clientenabled_result = "Partial" 221 | } 222 | elseif (($tls11clientenabled -eq 0) -and ($tls11clientdisabledbydefault -eq 0)) { 223 | $tls11clientenabled_result = "Partial" 224 | } 225 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 226 | elseif (($tls11clientenabled -eq 0) -and ($tls11clientdisabledbydefault -eq 0)) { 227 | $tls11serverenabled_result = "Partial" 228 | } 229 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 230 | elseif (($tls11clientdisabledbydefault -eq 0) -and ($null -eq $tls11clientenabled)) { 231 | $tls11serverenabled_result = "Partial" 232 | } 233 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 234 | elseif (($tls11clientdisabledbydefault -eq 1) -and ($null -eq $tls11clientenabled)) { 235 | $tls1serverenabled_result = "Partial" 236 | } 237 | else { 238 | $tls11serverenabled_result = $True 239 | } 240 | 241 | ## TLS 1.1 Server Stuff 242 | if ((($tls11serverenabled -eq 0) -and ($tls11serverdisabledbydefault -eq 1)) -or ($null -eq $tls11serverenabled) -and ($null -eq $tls11serverdisabledbydefault)) { 243 | $tls11serverenabled_result = $False 244 | } 245 | elseif (($tls11serverenabled -eq 1) -and ($tls11serverdisabledbydefault -eq 1)) { 246 | $tls11serverenabled_result = "Partial" 247 | } 248 | elseif (($tls11serverenabled -eq 0) -and ($tls11serverdisabledbydefault -eq 0)) { 249 | $tls11serverenabled_result = "Partial" 250 | } 251 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 252 | elseif (($tls11serverenabled -eq 0) -and ($tls11serverdisabledbydefault -eq 0)) { 253 | $tls11serverenabled_result = "Partial" 254 | } 255 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 256 | elseif (($tls11serverdisabledbydefault -eq 0) -and ($null -eq $tls11serverenabled)) { 257 | $tls11serverenabled_result = "Partial" 258 | } 259 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 260 | elseif (($tls11serverdisabledbydefault -eq 1) -and ($null -eq $tls11serverenabled)) { 261 | $tls11serverenabled_result = "Partial" 262 | } 263 | else { 264 | $tls11serverenabled_result = $True 265 | } 266 | 267 | ## TLS 1.2 Client Stuff 268 | 269 | ## If Client enabled is 0 and disabled by default is 1 or the entire client enabled key isn't there at all 270 | if ((($tls12clientenabled -eq 0) -and ($tls12clientdisabledbydefault -eq 1)) -or ($null -eq $tls12clientenabled) -and ($null -eq $tls12clientdisabledbydefault)) { 271 | $tls12clientenabled_result = "False" 272 | } 273 | ## If Client enabled is 1 but client disabled by default is still 1, then it's partially applied 274 | elseif (($tls12clientenabled -eq 1) -and ($tls12clientdisabledbydefault -eq 1)) { 275 | $tls12clientenabled_result = "Partial" 276 | } 277 | ## If Client enabled is 0 but client disabled by default is still 0, then it's partially applied 278 | elseif (($tls12clientenabled -eq 0) -and ($tls12clientdisabledbydefault -eq 0)) { 279 | $tls12clientenabled_result = "Partial" 280 | } 281 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 282 | elseif (($tls12clientdisabledbydefault -eq 0) -and ($null -eq $tls12clientenabled)) { 283 | $tls12clientenabled_result = "Partial" 284 | } 285 | ## If enabled is 1, but disabled by default is missing, then it's partially applied 286 | elseif (($tls12clientdisabledbydefault -eq 0) -and ($tls12clientenabled -eq 1)) { 287 | $tls12clientenabled_result = "Partial" 288 | } 289 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 290 | elseif (($tls12clientdisabledbydefault -eq 1) -and ($null -eq $tls12clientenabled)) { 291 | $tls12clientenabled_result = "Partial" 292 | } 293 | else { 294 | $tls12clientenabled_result = $True 295 | } 296 | 297 | ## TLS 1.2 Server Stuff 298 | if ((($tls12serverenabled -eq 0) -and ($tls12serverdisabledbydefault -eq 1)) -or ($null -eq $tls12serverenabled) -and ($null -eq $tls12serverdisabledbydefault)) { 299 | $tls12serverenabled_result = $False 300 | } 301 | elseif (($tls12serverenabled -eq 1) -and ($tls12serverdisabledbydefault -eq 1)) { 302 | $tls12serverenabled_result = "Partial" 303 | } 304 | elseif (($tls12serverenabled -eq 0) -and ($tls12serverdisabledbydefault -eq 0)) { 305 | $tls12serverenabled_result = "Partial" 306 | } 307 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 308 | elseif (($tls12serverdisabledbydefault -eq 0) -and ($null -eq $tls12serverenabled)) { 309 | $tls12serverenabled_result = "Partial" 310 | } 311 | ## If enabled is 1, but disabled by default is missing, then it's partially applied 312 | elseif (($tls12serverdisabledbydefault -eq 0) -and ($tls12serverenabled -eq 1)) { 313 | $tls12clientenabled_result = "Partial" 314 | } 315 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 316 | elseif (($tls12serverdisabledbydefault -eq 1) -and ($null -eq $tls12serverenabled)) { 317 | $tls12clientenabled_result = "Partial" 318 | } 319 | else { 320 | $tls12serverenabled_result = $True 321 | } 322 | 323 | ## TLS 1.3 Client Stuff 324 | if ((($tls13clientenabled -eq 0) -and ($tls13clientdisabledbydefault -eq 1)) -or ($null -eq $tls13clientenabled) -and ($null -eq $tls13clientdisabledbydefault)) { 325 | $tls13clientenabled_result = $False 326 | } 327 | elseif (($tls13clientenabled -eq 1) -and ($tls13clientdisabledbydefault -eq 1)) { 328 | $tls13clientenabled_result = "Partial" 329 | } 330 | elseif (($tls13clientenabled -eq 0) -and ($tls13clientdisabledbydefault -eq 0)) { 331 | $tls13clientenabled_result = "Partial" 332 | } 333 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 334 | elseif (($tls13clientdisabledbydefault -eq 0) -and ($null -eq $tls13clientenabled)) { 335 | $tls13clientenabled_result = "Partial" 336 | } 337 | ## If enabled is 1, but disabled by default is missing, then it's partially applied 338 | elseif (($tls13clientdisabledbydefault -eq 0) -and ($tls13clientenabled -eq 1)) { 339 | $tls13clientenabled_result = "Partial" 340 | } 341 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 342 | elseif (($tls13clientdisabledbydefault -eq 1) -and ($null -eq $tls13clientenabled)) { 343 | $tls13clientenabled_result = "Partial" 344 | } 345 | else { 346 | $tls13clientenabled_result = $True 347 | } 348 | 349 | ## TLS 1.3 Server Stuff 350 | if ((($tls13serverenabled -eq 0) -and ($tls13serverdisabledbydefault -eq 1)) -or ($null -eq $tls13serverenabled) -and ($null -eq $tls13serverdisabledbydefault)) { 351 | $tls13serverenabled_result = $False 352 | } 353 | elseif (($tls13serverenabled -eq 1) -and ($tls13serverdisabledbydefault -eq 1)) { 354 | $tls13serverenabled_result = "Partial" 355 | } 356 | elseif (($tls13serverenabled -eq 0) -and ($tls13serverdisabledbydefault -eq 0)) { 357 | $tls13serverenabled_result = "Partial" 358 | } 359 | ## If disabled by default is 0, but enabled key is missing, then it's partially applied 360 | elseif (($tls13serverdisabledbydefault -eq 0) -and ($null -eq $tls13serverenabled)) { 361 | $tls13serverenabled_result = "Partial" 362 | } 363 | ## If enabled is 1, but disabled by default is missing, then it's partially applied 364 | elseif (($tls13serverdisabledbydefault -eq 0) -and ($tls13serverenabled -eq 1)) { 365 | $tls13serverenabled_result = "Partial" 366 | } 367 | ## If disabled by default is 1, but enabled key is missing, then it's partially applied 368 | elseif (($tls13serverdisabledbydefault -eq 1) -and ($null -eq $tls13serverenabled)) { 369 | $tls13serverenabled_result = "Partial" 370 | } 371 | else { 372 | $tls13serverenabled_result = $True 373 | } 374 | 375 | [PSCustomObject]@{ 376 | SSL2ClientEnabled = $ssl2clientenabled_result 377 | SSL2ServerEnabled = $ssl2serverenabled_result 378 | SSL3ClientActive = $ssl3clientenabled_result 379 | SSL3ServerActive = $ssl3serverenabled_result 380 | TLS1ClientEnabled = $tls1clientenabled_result 381 | TLS1ServerEnabled = $tls1serverenabled_result 382 | TLS11ClientEnabled = $tls11clientenabled_result 383 | TLS11ServerEnabled = $tls11serverenabled_result 384 | TLS12ClientEnabled = $tls12clientenabled_result 385 | TLS12ServerEnabled = $tls12serverenabled_result 386 | TLS13ClientEnabled = $tls13clientenabled_result 387 | TLS13ServerEnabled = $tls13serverenabled_result 388 | DiffieHellmanEnabled = "" 389 | DiffieHellmanMinBitLength = "" 390 | "RC4 128/128" = "" 391 | "RC4 56/128" = "" 392 | "RC4 40/128" = "" 393 | TripleDES168 = "" 394 | Computer = $env:COMPUTERNAME 395 | OS = (Get-WmiObject win32_operatingsystem).Caption 396 | } 397 | } -ErrorAction "SilentlyContinue" | Select-Object *SSL*, *Diff*, *RC*, *Triple*, Computer, OS 398 | } --------------------------------------------------------------------------------