PSCommonCore.psm1
<#
=========================================================================== Created with: SAPIEN Technologies, Inc., PowerShell Studio 2019 v5.6.166 Created on: 8/6/2019 11:59 AM Created by: Gary Cook Organization: Quest Filename: PSCommonCore.psm1 ------------------------------------------------------------------------- Module Name: PSCommonCore =========================================================================== #requires the PShellLogging module found on the Powershell Gallery #> Function Test-Module { param ( [parameter(Mandatory = $true)] [string]$Module, [parameter(Mandatory = $true)] [bool]$Load = $false ) [CmdletBinding] $Return = New-Object System.Management.Automation.PSObject $Return | Add-Member -MemberType NoteProperty -Name Status -Value $null $Return | Add-Member -MemberType NoteProperty -Name Message -Value $null if (!(get-module $Module)) { If (!(Get-Module -ListAvailable $Module)) { $Return.Status = "Not Loaded" $Return.Message = "The Module $($Module) was not available to load" } else { if ($Load -eq $true) { Import-Module ActiveDirectory -ErrorAction SilentlyContinue if (!(Get-Module activedirectory)) { $Return.Status = "Not Loaded" $Return.Message = "The Module $($Module) was available but failed to load" } else { $Return.Status = "Loaded" $Return.Message = "Module $($Module) was loaded successfully" } } else { $Return.Status = "Not Loaded" $Return.Message = "The Module $($Module) was available but not loaded due to switch" } } } else { $Return.Status = "Loaded" $Return.Message = "Module $($Module) was already loaded" } return $Return } function Test-PSVersion { param ( [parameter(Mandatory = $true)] [string]$Min, [parameter(Mandatory = $true)] [ValidateSet("Desktop","Core")] [string]$Edition = "Desktop" ) if ($Min.contains(".") -eq $true) { #Write-Host "Checking Powershell against $($Min)" $Major = ($Min -split "\.")[0] #Write-Host "Major Version: $($Major)" $Minor = ($Min -split "\.")[1] #Write-Host "Minor Version: $($Minor)" } else { #Write-Host "Checking Powershell against $($Min)" $Major = $Min #Write-Host "Major Version: $($Major)" $Minor = "0" #Write-Host "Minor Version: $($Minor)" } $Version = $PSVersionTable.pscompatibleversions $Return = $false #Write-Host "Processing PowerShell Compatable Versions" foreach ($V in $Version) { #Write-Host "Checking Version Major:$($V.major) Minor:$($V.minor)" if ($V.major -eq $Major -and $V.minor -eq $Minor) { #Write-Host "Matches Minimum Version" $Return = $true } } if ($Edition -eq $PSVersionTable.PSEdition) { return $Return } else { return $false } } function Write-Color([String[]]$Text, [ConsoleColor[]]$Color = (get-host).ui.rawui.ForegroundColor, [ConsoleColor[]]$BackColor = (get-host).ui.rawui.BackgroundColor, [int]$StartTab = 0, [int]$LinesBefore = 0, [int]$LinesAfter = 0) { $DefaultColor = $Color[0] $DefaultBackColor = $BackColor[0] if ($LinesBefore -ne 0) { for ($i = 0; $i -lt $LinesBefore; $i++) { Write-Host "`n" -NoNewline } } # Add empty line before if ($StartTab -ne 0) { for ($i = 0; $i -lt $StartTab; $i++) { Write-Host "`t" -NoNewLine } } # Add TABS before text if ($Color.Count -ge $Text.Count -and $BackColor.count -ge $Text.count) { for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -backgroundcolor $BackColor[$i] -NoNewLine } } else { if ($Color.Count -ge $Text.Count -and $BackColor.Count -lt $Text.Count) { for ($i = 0; $i -lt $BackColor.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackColor[$i] -NoNewLine } for ($i = $BackColor.Length; $i -lt $Text.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $DefaultBackColor -NoNewLine } } if ($Color.Count -lt $Text.Count -and $BackColor.Count -ge $Text.Count) { for ($i = 0; $i -lt $Color.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackColor[$i] -NoNewLine } for ($i = $BackColor.Length; $i -lt $Text.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $BackColor[$i] -NoNewLine } } if ($Color.Count -lt $Text.Count -and $BackColor.Count -lt $Text.Count) { if ($Color.Count -lt $BackColor.count) { for ($i = 0; $i -lt $Color.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackColor[$i] -NoNewLine } for ($i = $Color.Length; $i -lt $BackColor.length; $i++) { Write-Host $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $BackColor[$i] -NoNewLine } for ($i = $BackColor.Length; $i -lt $Text.length; $i++) { Write-Host $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $DefaultBackColor -NoNewLine } } if ($Color.Count -gt $BackColor.count) { for ($i = 0; $i -lt $BackColor.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackColor[$i] -NoNewLine } for ($i = $BackColor.Length; $i -lt $Color.length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $DefaultBackColor -NoNewLine } for ($i = $Color.Length; $i -lt $Text.length; $i++) { Write-Host $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $DefaultBackColor -NoNewLine } } if ($Color.Count -eq $BackColor.count) { for ($i = 0; $i -lt $BackColor.Length; $i++) { Write-Host $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackColor[$i] -NoNewLine } for ($i = $BackColor.Length; $i -lt $text.length; $i++) { Write-Host $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $DefaultBackColor -NoNewLine } } } } Write-Host if ($LinesAfter -ne 0) { for ($i = 0; $i -lt $LinesAfter; $i++) { Write-Host "`n" } } # Add empty line after } function Connect-Exchange { param ( [parameter(Mandatory = $false)] [System.Management.Automation.PSCredential]$Credential, [parameter(Mandatory = $false)] [ValidateSet ("EONPREM", "EOL")] [string]$Type = "EONPREM" ) if ($Credential -eq $null) { $Credential = Get-Credential -Message "Please Enter your Exchange Online Admin Credential." } if ($Type -eq "EOL") { $Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $Credential -Authentication Basic -AllowRedirection Import-PSSession $Session -DisableNameChecking -AllowClobber return $session } else { $server = Read-Host "Please enter On Prem Exchange Server Name" $Session = New-PSSession -ConfigurationName "Microsoft.Exchange" -ConnectionUri "https://$($server)/powershell/" -Credential $Credential -AllowRedirection Import-PSSession $Session -DisableNameChecking -AllowClobber return $session } } function Disconnect-EOL { param ( [parameter(Mandatory = $true,ValueFromPipeline = $true)] $Session ) Remove-PSSession -Session $Session } function Start-Log { <# .SYNOPSIS Creates the supplied log file $Log. .DESCRIPTION .PARAMETER $Log the complete path to the log to write to. required. $type the type of log file to generate TXT is assumed. Possible Values are TXT, CSV, JSON. .EXAMPLE creates a log at location and returns object representing the log and type Start-Log -Log "C:\applog.txt" -Type CSV .NOTES FunctionName : Write-Log Created by : Gary Cook Date Coded : 07/26/2019 .OUTPUTS Returns and object containing the path to the log and the type of the log. #> [CmdletBinding()] Param ( [parameter (position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$Log, [Parameter (Position = 1, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateSet("TXT", "CSV", "JSON")] [string]$Type = "TXT" ) Begin { } Process { # Format Date for our Log File $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" #if log does not exists create log with application runtime banner if (!(Test-Path $Log -PathType Leaf)) { if (!(Test-Path $Log)) { #create file including path if the path does not exist $NewLogFile = New-Item $Log -Force -ItemType File } if ($Type -eq "TXT") { #create file with banner $Banner = "*************************************************" $Banner | Out-File -FilePath $Log -Append -force $Banner = "Application log created $($FormattedDate) on computer $($env:COMPUTERNAME)" $Banner | Out-File -FilePath $Log -Append $Banner = "*************************************************" $Banner | Out-File -FilePath $Log -Append } if ($Type -eq "CSV") { #open out file with headder $Banner = "Date,Level,Message" $Banner | Out-File -FilePath $Log -Append -force $Banner = "$($FormattedDate),INFO:,Application Log file Created for computer $($env:COMPUTERNAME)" $Banner | Out-File -FilePath $Log -Append } if ($Type -eq "JSON") { $Banner = "{`"DATE`": `"$($FormattedDate)`",`"LEVEL`": `"INFO:`",`"MESSAGE`": `"Application Log file Created for computer $($env:COMPUTERNAME)`"}" $Banner | Out-File -FilePath $Log -Append -force } } $obj = new-object System.Management.Automation.PSObject $obj | Add-Member -MemberType NoteProperty -Name Log -Value (get-item $log).VersionInfo.filename $obj | Add-Member -MemberType NoteProperty -Name Type -Value $Type return $obj } end { } } Function Write-Log { <# .SYNOPSIS Writes the Entry in $Line to the supplied log file $Log. Built to take pipeline input from object returned from start-log. .DESCRIPTION .PARAMETER $Line String of data to write to the log file. required. $Log the complete path to the log to write to. required. $Level The type of line to write to the log. Valid vales are Error,Warn,Info. Default is Info. $Type the type of log file to generate TXT is assumed. Possible Values are TXT, CSV, JSON. .EXAMPLE $mylog | Write-Log -Line "This is an entry for the log" -level Info .NOTES FunctionName : Write-Log Created by : Gary Cook Date Coded : 07/26/2019 .OUTPUTS Returns 0 if log exists or -1 if the log file does not exist #> [CmdletBinding()] Param ( [parameter (position = 0, Mandatory = $true)] [string]$Line, [parameter (position = 1, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$Log, [Parameter (position = 2, Mandatory = $false)] [ValidateSet("Error", "Warn", "Info")] [string]$Level = "Info", [Parameter (Position = 3, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateSet("TXT", "CSV", "JSON")] [string]$Type = "TXT" ) Begin { } Process { # Format Date for our Log File $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" # Write message to error, warning, or verbose pipeline and specify $LevelText switch ($Level) { 'Error' { $LevelText = 'ERROR:' } 'Warn' { $LevelText = 'WARNING:' } 'Info' { $LevelText = 'INFO:' } } #if log does not exists reutrn -1 else return 0 if (!(Test-Path $Log -PathType Leaf)) { if (!(Test-Path $Log)) { return -1 break } } # Write message to proper log type switch ($Type) { 'TXT' { "$($FormattedDate) $($LevelText) $($Line)" | Out-File -FilePath $Log -Append } 'CSV' { "$($FormattedDate),$($LevelText),$($Line)" | Out-File -FilePath $Log -Append } 'JSON' { "{`"DATE`": `"$($FormattedDate)`",`"LEVEL`": `"$($LevelText)`",`"MESSAGE`": `"$($Line)`"}" | Out-File -FilePath $Log -Append } } return 0 } End { } } Function Close-Log { <# .SYNOPSIS Closes the supplied log file $Log. Built to take pipeline input from object returned from start-log. .DESCRIPTION .PARAMETER $Log the complete path to the log to write to. required. $Type the type of log file to generate TXT is assumed. Possible Values are TXT, CSV, JSON. .EXAMPLE $mylog | Close-Log .NOTES FunctionName : Write-Log Created by : Gary Cook Date Coded : 07/26/2019 #> [CmdletBinding()] Param ( [parameter (position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$Log, [Parameter (Position = 1, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateSet("TXT", "CSV", "JSON")] [string]$Type = "TXT" ) Begin { } Process { # Format Date for our Log File $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" if ($Type -eq "TXT") { #close out file with footer $Footer = "*************************************************" $Footer | Out-File -FilePath $Log -Append $Footer = "Application log end $($FormattedDate) on computer $($env:COMPUTERNAME)" $Footer | Out-File -FilePath $Log -Append $Footer = "*************************************************" $Footer | Out-File -FilePath $Log -Append } if ($Type -eq "CSV") { #close out file with footer $Footer = "$($FormattedDate),INFO:,Application Log file end for computer $($env:COMPUTERNAME)" $Footer | Out-File -FilePath $Log -Append } if ($Type -eq "JSON") { $Footer = "{`"DATE`": `"$($FormattedDate)`",`"LEVEL`": `"INFO:`",`"MESSAGE`": `"Application Log file end for computer $($env:COMPUTERNAME)`"}" $Footer | Out-File -FilePath $Log -Append } } End { } } function New-RandomString([string]$inputString) { $characterArray = $inputString.ToCharArray() $scrambledStringArray = $characterArray | Get-Random -Count $characterArray.Length $outputString = -join $scrambledStringArray return $outputString } function Get-RandomCharacters($length, $characters) { $random = 1 .. $length | ForEach-Object { Get-Random -Maximum $characters.length } $private:ofs = "" return [String]$characters[$random] } function New-password { param ( [parameter(Mandatory = $true)] [int]$Length, [parameter(Mandatory = $false)] [switch]$Upper = $false, [parameter(Mandatory = $false)] [switch]$Lower = $false, [parameter(Mandatory = $false)] [switch]$Number = $false, [parameter(Mandatory = $false)] [switch]$Symbol = $false, [parameter(Mandatory = $false)] [int]$MinLower = 1, [parameter(Mandatory = $false)] [int]$MinUpper = 1, [parameter(Mandatory = $false)] [int]$MinNumber = 1, [parameter(Mandatory = $false)] [int]$MinSymbol = 1, [parameter(Mandatory = $false)] [switch]$NonAmbiguous = $false ) if ($Upper -eq $false -and $Lower -eq $false -and $Number -eq $false -and $Symbol -eq $false) { Write-Error "Must Specify at least one character type for password i.e. -lower in call to new-password" } else { # Fix password length if minchars is more than length $BaseCount = 1 if ($Upper) { $BaseCount += $MinUpper } if ($Lower) { $BaseCount += $MinLower } if ($Number) { $BaseCount += $MinNumber } if ($Symbol) { $BaseCount += $MinSymbol } if ($BaseCount -gt $Length) { $Length = $BaseCount } $remaining = $Length - $BaseCount # Creates character arrays for the different character classes, based on ASCII character values. [string]$charsLower = (97 .. 122 | %{ [Char]$_ }) $charsLower = $charsLower -replace " ", "" [string]$charsUpper = (65 .. 90 | %{ [Char]$_ }) $charsUpper = $charsUpper -replace " ", "" [string]$charsNumber = (48 .. 57 | %{ [Char]$_ }) $charsNumber = $charsNumber -replace " ", "" [string]$charsSymbol = (35, 36, 40, 41, 42, 44, 45, 46, 47, 58, 59, 63, 64, 92, 95 | %{ [Char]$_ }) $charsSymbol = $charsSymbol -replace " ", "" # Create character arrays for non ambiguous characters l (ell), 1 (one), I (capital i), O (capital o), 0 (zero), B (capital b), 8 (eight), q (queue), g (gee), | (pipe) [string]$charsLowera = "abcdefhijkmnoprstuvwxyz" $charsLowera = $charsLowera -replace " ", "" [string]$charsUppera = "ACDEFGHJKLMNPQRTUVWXYZ" $charsUppera = $charsUppera -replace " ", "" [string]$charsNumbera = "234679" $charsNumbera = $charsNumbera -replace " ", "" [string]$charsSymbola = "!@#$%^&*()-=+:,?_.~" $charsSymbola = $charsSymbola -replace " ", "" if ($NonAmbiguous -eq $false) { if ($Upper) { $RandomUString = Get-RandomCharacters -length $MinUpper -characters $charsUpper } else { $RandomUString = "" } if ($Lower) { $RandomLString = Get-RandomCharacters -length $MinLower -characters $charsLower } else { $RandomLString = "" } if ($Number) { $RandomNString = Get-RandomCharacters -length $MinNumber -characters $charsNumber } else { $RandomNString = "" } if ($Symbol) { $RandomSString = Get-RandomCharacters -length $MinSymbol -characters $charsSymbol } else { $RandomSString = "" } if ($remaining -gt 0) { $Tempc = "" if ($Upper) { $Tempc += $charsUpper } if ($Lower) { $Tempc += $charsLower } if ($Number) { $Tempc += $charsNumber } if ($Symbol) { $Tempc += $charsSymbol } $RandomString = Get-RandomCharacters -length $remaining -characters $Tempc } else { $RandomString = "" } } else { if ($Upper) { $RandomUString = Get-RandomCharacters -length $MinUpper -characters $charsUppera } else { $RandomUString = "" } if ($Lower) { $RandomLString = Get-RandomCharacters -length $MinLower -characters $charsLowera } else { $RandomLString = "" } if ($Number) { $RandomNString = Get-RandomCharacters -length $MinNumber -characters $charsNumbera } else { $RandomNString = "" } if ($Symbol) { $RandomSString = Get-RandomCharacters -length $MinSymbol -characters $charsSymbola } else { $RandomSString = "" } if ($remaining -gt 0) { $Tempc = "" if ($Upper) { $Tempc += $charsUppera } if ($Lower) { $Tempc += $charsLowera } if ($Number) { $Tempc += $charsNumbera } if ($Symbol) { $Tempc += $charsSymbola } $RandomString = Get-RandomCharacters -length $remaining -characters $Tempc } else { $RandomString = "" } } #combine all into a single string $Return = $RandomUString + $RandomLString + $RandomNString + $RandomSString + $RandomString #scramble the scring $Return = New-RandomString -inputString $Return return $Return } } function get-loggedonuser () { [CmdletBinding()] Param ( [parameter (position = 0, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$computername , [Parameter (Position = 1, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateSet($true,$false)] [bool]$local = $false, [Parameter (Position = 2, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [System.Management.Automation.PSCredential]$credential ) Begin { } Process { if ($local -eq $false -and $computername -eq $null) { $computername = Read-Host "Remote computername was not provided please enter remote computername" if ($computername -eq "") { Write-Host "Computername not provided exiting" end } } if ($credential -eq $null) { write-host "User Credential not provided using logged on user" $localuser = $true } $regexa = '.+Domain="(.+)",Name="(.+)"$' $regexd = '.+LogonId="(\d+)"$' $logontype = @{ "0" = "Local System" "2" = "Interactive" #(Local logon) "3" = "Network" # (Remote logon) "4" = "Batch" # (Scheduled task) "5" = "Service" # (Service account logon) "7" = "Unlock" #(Screen saver) "8" = "NetworkCleartext" # (Cleartext network logon) "9" = "NewCredentials" #(RunAs using alternate credentials) "10" = "RemoteInteractive" #(RDP\TS\RemoteAssistance) "11" = "CachedInteractive" #(Local w\cached credentials) } switch ($local) { $true { $logon_sessions = @(gwmi win32_logonsession -ComputerName "localhost") $logon_users = @(gwmi win32_loggedonuser -ComputerName "localhost") } $false { if ($localuser -ne $true) { $logon_sessions = @(gwmi win32_logonsession -ComputerName $computername -Credential $credential) $logon_users = @(gwmi win32_loggedonuser -ComputerName $computername -Credential $credential) } else { $logon_sessions = @(gwmi win32_logonsession -ComputerName $computername ) $logon_users = @(gwmi win32_loggedonuser -ComputerName $computername ) } } } $session_user = @{ } $logon_users | % { $_.antecedent -match $regexa > $nul $username = $matches[1] + "\" + $matches[2] $_.dependent -match $regexd > $nul $session = $matches[1] $session_user[$session] += $username } $logon_sessions | %{ $starttime = [management.managementdatetimeconverter]::todatetime($_.starttime) $loggedonuser = New-Object -TypeName psobject $loggedonuser | Add-Member -MemberType NoteProperty -Name "Session" -Value $_.logonid $loggedonuser | Add-Member -MemberType NoteProperty -Name "User" -Value $session_user[$_.logonid] $loggedonuser | Add-Member -MemberType NoteProperty -Name "Type" -Value $logontype[$_.logontype.tostring()] $loggedonuser | Add-Member -MemberType NoteProperty -Name "Auth" -Value $_.authenticationpackage $loggedonuser | Add-Member -MemberType NoteProperty -Name "StartTime" -Value $starttime $loggedonuser } } end { } } Function Set-Owner { <# .SYNOPSIS Changes owner of a file or folder to another user or group. .DESCRIPTION Changes owner of a file or folder to another user or group. .PARAMETER Path The folder or file that will have the owner changed. .PARAMETER Account Optional parameter to change owner of a file or folder to specified account. Default value is 'Builtin\Administrators' .PARAMETER Recurse Recursively set ownership on subfolders and files beneath given folder. .NOTES Name: Set-Owner Author: Boe Prox Version History: 1.0 - Boe Prox - Initial Version 2.0 - Gary Cook - Added PShellLogging to capture Success and Error Information - Fixed issues processing owner on specific server OS's Requires the PSHellLogging Modules Available on PowerShell gallery https://www.powershellgallery.com/packages/PShellLogging/1.1.13 Use "Install-Module -Name PShellLogging" on powershell 5.0 and higher to install .EXAMPLE Set-Owner -Path C:\temp\test.txt -Log c:\logs\ownerlog.csv -logtype CSV Description ----------- Changes the owner of test.txt to Builtin\Administrators, Logs output to c:\logs\ownerlog.csv in comma Seperated Format .EXAMPLE Set-Owner -Path C:\temp\test.txt -Account 'Domain\bprox -Log c:\logs\ownerlog.TXT -logtype TXT Description ----------- Changes the owner of test.txt to Domain\bprox, Logs output to c:\logs\ownerlog.csv in text format .EXAMPLE Set-Owner -Path C:\temp -Recurse -Log c:\logs\ownerlog.csv -logtype CSV Description ----------- Changes the owner of all files and folders under C:\Temp to Builtin\Administrators, Logs output to c:\logs\ownerlog.csv in comma Seperated Format .EXAMPLE Get-ChildItem C:\Temp | Set-Owner -Recurse -Account 'Domain\bprox' -Log c:\logs\ownerlog.csv -logtype CSV Description ----------- Changes the owner of all files and folders under C:\Temp to Domain\bprox, Logs output to c:\logs\ownerlog.csv in comma Seperated Format #> [cmdletbinding( SupportsShouldProcess = $True )] Param ( [parameter(mandatory = $true, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] [Alias('FullName')] [string[]]$Path, [parameter()] [string]$Account = 'Builtin\Administrators', [parameter()] [switch]$Recurse, [parameter()] [string]$Log, [parameter()] [ValidateSet("TXT", "CSV", "JSON")] [string]$logtype = "CSV" ) Begin { #Create Log if necessary if ($Log -ne $null) { $MyLog = Start-Log -Log $Log -Type $logtype $logging = $true } #Prevent Confirmation on each Write-Debug command when using -Debug If ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Try { [void][TokenAdjuster] } Catch { $AdjustTokenPrivileges = @" using System; using System.Runtime.InteropServices; public class TokenAdjuster { [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen); [DllImport("kernel32.dll", ExactSpelling = true)] internal static extern IntPtr GetCurrentProcess(); [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok); [DllImport("advapi32.dll", SetLastError = true)] internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct TokPriv1Luid { public int Count; public long Luid; public int Attr; } internal const int SE_PRIVILEGE_DISABLED = 0x00000000; internal const int SE_PRIVILEGE_ENABLED = 0x00000002; internal const int TOKEN_QUERY = 0x00000008; internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; public static bool AddPrivilege(string privilege) { try { bool retVal; TokPriv1Luid tp; IntPtr hproc = GetCurrentProcess(); IntPtr htok = IntPtr.Zero; retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); tp.Count = 1; tp.Luid = 0; tp.Attr = SE_PRIVILEGE_ENABLED; retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid); retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); return retVal; } catch (Exception ex) { throw ex; } } public static bool RemovePrivilege(string privilege) { try { bool retVal; TokPriv1Luid tp; IntPtr hproc = GetCurrentProcess(); IntPtr htok = IntPtr.Zero; retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); tp.Count = 1; tp.Luid = 0; tp.Attr = SE_PRIVILEGE_DISABLED; retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid); retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); return retVal; } catch (Exception ex) { throw ex; } } } "@ Add-Type $AdjustTokenPrivileges } #Activate necessary admin privileges to make changes without NTFS perms [void][TokenAdjuster]::AddPrivilege("SeRestorePrivilege") #Necessary to set Owner Permissions [void][TokenAdjuster]::AddPrivilege("SeBackupPrivilege") #Necessary to bypass Traverse Checking [void][TokenAdjuster]::AddPrivilege("SeTakeOwnershipPrivilege") #Necessary to override FilePermissions } Process { ForEach ($Item in $Path) { Write-Verbose "FullName: $Item" if ($logging) { $MyLog | Write-Log -Line "Proicessing item $($Item)" -Level Info } #The ACL objects do not like being used more than once, so re-create them on the Process block $DirOwner = New-Object System.Security.AccessControl.DirectorySecurity $DirOwner.SetOwner([System.Security.Principal.NTAccount]$Account) $FileOwner = New-Object System.Security.AccessControl.FileSecurity $FileOwner.SetOwner([System.Security.Principal.NTAccount]$Account) $DirAdminAcl = New-Object System.Security.AccessControl.DirectorySecurity $FileAdminAcl = New-Object System.Security.AccessControl.DirectorySecurity $AdminACL = New-Object System.Security.AccessControl.FileSystemAccessRule('Builtin\Administrators', 'FullControl', 'ContainerInherit,ObjectInherit', 'InheritOnly', 'Allow') $FileAdminAcl.AddAccessRule($AdminACL) $DirAdminAcl.AddAccessRule($AdminACL) Try { $Item = Get-Item -LiteralPath $Item -Force -ErrorAction Stop If (-NOT $Item.PSIsContainer) { If ($PSCmdlet.ShouldProcess($Item, 'Set File Owner')) { Try { $Item.SetAccessControl($FileOwner) } Catch { Write-Warning "Couldn't take ownership of $($Item.FullName)! Taking FullControl of $($Item.Directory.FullName)" $Item.Directory.SetAccessControl($FileAdminAcl) $Item.SetAccessControl($FileOwner) } } } Else { If ($PSCmdlet.ShouldProcess($Item, 'Set Directory Owner')) { Try { $Item.SetAccessControl($DirOwner) } Catch { Write-Warning "Couldn't take ownership of $($Item.FullName)! Taking FullControl of $($Item.Parent.FullName)" $Item.Parent.SetAccessControl($DirAdminAcl) $Item.SetAccessControl($DirOwner) } } If ($Recurse) { [void]$PSBoundParameters.Remove('Path') Get-ChildItem $Item -Force | Set-Owner @PSBoundParameters } } if ($logging) { $MyLog | Write-Log -Line "Item $($Item) was successfully processed" -Level Info } } Catch { Write-Warning "$($Item): $($_.Exception.Message)" if ($logging) { $MyLog | Write-Log -Line "Item $($Item) processing failed error message $($_.Exception.Message)" -Level Error } } } } End { #Remove priviledges that had been granted [void][TokenAdjuster]::RemovePrivilege("SeRestorePrivilege") [void][TokenAdjuster]::RemovePrivilege("SeBackupPrivilege") [void][TokenAdjuster]::RemovePrivilege("SeTakeOwnershipPrivilege") if ($logging) { $MyLog | Close-Log } } } |