CommonScriptFunctions.psm1

# https://powershellexplained.com/2017-05-27-Powershell-module-building-basics/

function Clear-SessionData {
 Write-Verbose 'Clearing session data'
 Get-PSSession | Remove-PSSession -Confirm:$false
}

function Connect-ADSession {
 [CmdletBinding()]
 param (
  [string[]]$DomainControllers,
  [System.Management.Automation.PSCredential]$Credential,
  [string[]]$Cmdlets,
  [switch]$WhatIf
 )
 $SessionErrors = $null
 $dc = (Get-Random $DomainControllers).ToUpper()
 Write-Verbose ('{0},{1},{2}' -f $MyInvocation.MyCommand.Name, $dc, ($cmdLets -join ','))
 $mySession = New-PSSession -ComputerName $dc -Credential $Credential -ErrorAction SilentlyContinue -ErrorVariable SessionErrors
 if ($SessionErrors) {
  Write-Host ($dc + ': ' + $SessionErrors.Exception.TransportMessage | Out-String) -F Red
  Write-Host ('{0},Server:{1},New Session failed. Trying again in 30 seconds...' -f $MyInvocation.MyCommand.Name, $dc) -F Magenta
  if (!$WhatIf) { Start-Sleep 30 }
  Connect-ADSession -DomainControllers $DomainControllers -Credential $Credential -Cmdlets $Cmdlets
  return
 }
 try { Import-Module (Import-PSSession -Session $mySession -Module ActiveDirectory -CommandName $Cmdlets -AllowClobber) -Global }
 catch {
  Remove-PSSession -ComputerName $dc
  Write-Host ('{0},Server:{1},Unable to import AD session. Trying again in 30 seconds...' -f $MyInvocation.MyCommand.Name, $dc) -F Magenta
  if (!$WhatIf) { Start-Sleep 30 }
  Connect-ADSession -DomainControllers $DomainControllers -Credential $Credential -Cmdlets $Cmdlets
 }
}

function Import-MyModules {
 process {
  Write-Verbose ('{0}: {1}' -f $MyInvocation.MyCommand.Name, $_)
  if (-not(Get-Module -Name $_ -ListAvailable)) {
   Install-Module -Name $_ -Scope CurrentUser -AllowClobber -Confirm:$false -Force
  }
  Import-Module -Name $_ -Force -ErrorAction Stop -Verbose:$false | Out-Null
  # Get-Module -Name $_
 }
}

function New-ADSession {
 [CmdletBinding()]
 param (
  [string]$DC,
  [System.Management.Automation.PSCredential]$Credential,
  [string[]]$Cmdlets
 )
 $msgVars = $MyInvocation.MyCommand.Name, $DC, ($cmdLets -join ',')
 Write-Verbose ('{0},{1},{2}' -f $msgVars)
 $adSession = New-PSSession -ComputerName $DC -Credential $Credential
 Import-Module (Import-PSSession -Session $adSession -Module ActiveDirectory -CommandName $Cmdlets -AllowClobber) -Global
}


function New-RandomPassword ($length) {
 function Get-RandomCharacters($max, $characters) {
  $random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length }
  $private:ofs = ''
  return [String]$characters[$random]
 }
 if ($null -eq $length) { $length = 8 }
 $chars = 'ABCDEFGHKLMNOPRSTUVWXYZabcdefghiklmnoprstuvwxyz1234567890!$#%&*@'
 do { $pw = (Get-RandomCharacters -max $length -characters $chars) }
 until ($pw -match '[A-Za-z\d!$#%&*@]') # Make sure minimum criteria met using regex p@ttern.
 $pw # Output random password
}

function New-SqlOperation ($Server, $Database, $Credential, $Query, $Parameters) {
 # https://dbatools.io/getting-started/
 # https://wp.larnu.uk/an-introduction-to-parametrised-queries-with-dbatools/
 Set-DbatoolsConfig -FullName sql.connection.trustcert -Value $true -Register
 Set-DbatoolsConfig -FullName sql.connection.encrypt -Value $true -Register
 $sqlParams = @{SqlInstance = $Server }
 $baseType = ($Server.GetType() | Select-Object -Property BaseType).BaseType.name
 if ($baseType -ne 'SqlSmoObject') {
  $missing = @()
  if (!$Database) { $missing += 'Database' } else { $sqlParams.Database = $Database }
  if (!$Credential) { $missing += 'Credential' } else { $sqlParams.SqlCredential = $Credential }
 }
 if (!$Query) { $missing += 'Query' } else { $sqlParams.Query = $Query }
 if ($missing) {
  Write-Host ('{0},These required params are missing: {1}' -f $MyInvocation.MyCommand.Name, ($missing -join ',')) -F Yellow
  return
 }
 if ($Parameters) {
  $paramList = @{}
  foreach ($item in $Parameters) {
   $key = $item.split('=')[0]
   $value = $item.split('=')[1]
   $paramList.Add($key, $value)
  }
  $sqlParams.SqlParameter = $paramList
 }
 Invoke-DbaQuery @sqlParams
}

function Select-DomainController {
 [CmdletBinding()]
 param ([string[]]$DomainControllers)
 $dc = Get-Random $DomainControllers
 if ( Test-Connection -ComputerName $dc -Count 1 -ErrorAction SilentlyContinue ) {
  Write-Verbose ('{0},{1}' -f $MyInvocation.MyCommand.Name, $dc)
  return $dc
 }
 else {
  $msg = $MyInvocation.MyCommand.Name, $dc
  Write-Host ('{0},{1} Not responding. Trying random Domain Controller in 30 seconds...' -f $msg)
  Start-Sleep 30
  Select-DomainController $DomainControllers
 }
}

function Set-PSCred {
 [CmdletBinding()]
 param (
  [string]$Username,
  [string]$Password
 )
 $securePw = ConvertTo-SecureString $Password -AsPlainText -Force
 New-Object System.Management.Automation.PSCredential ($Username, $securePw )
}

function Show-BlockInfo {
 [cmdletbinding()]
 param($str)
 $textInfo = (Get-Culture).TextInfo
 $str = $textInfo.ToTitleCase($str)
 Write-Host ('=== {0} {1}' -f $str, ('=' * (50 - $str.length))) -Fore DarkMagenta
 Write-Debug 'Proceed?'
}

function Show-TestRun {
 $str = '
           _______ ______ _____ _______ _____ _ _ _ _
  ______ |__ __| | ____| / ____| |__ __| | __ \ | | | | | \ | | ______
 |______| | | | |__ | (___ | | | |__) | | | | | | \| | |______|
  ______ | | | __| \___ \ | | | _ / | | | | | | ______
 |______| | | | |____ ____) | | | | | \ \ | |__| | | |\ | |______|
             |_| |______| |_____/ |_| |_| \_\ \____/ |_| \_|
 
'

 Write-Host $str -ForegroundColor Blue
}