Created
February 8, 2023 21:12
-
-
Save neztach/4f04ee3ff54ae92194bd22d3b9bcc576 to your computer and use it in GitHub Desktop.
profile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Version 2.5 | |
Clear-Host | |
#region Paths | |
$env:PSModulePath = $env:PSModulePath + ';C:\Program Files\WindowsPowerShell\Modules' | |
#endregion | |
If ($env:USERNAME -like '*step*'){$amJames = $true} | |
#region Locations | |
If ($amJames -eq $true){ | |
Set-Location -Path "$env:SystemDrive\down" | |
} Else { | |
Set-Location -Path "$env:SystemDrive\" | |
} | |
#endregion | |
#region Prompt Functions | |
Function Test-Administrator { | |
<# | |
.SYNOPSIS | |
Checks if you are running as Administrator. | |
.DESCRIPTION | |
Tests if you are currently running powershell as administrator. | |
.EXAMPLE | |
Test-Administrator | |
If yes, returns true, if not, returns false | |
#> | |
# PowerShell 5.x only runs on Windows so use .NET types to determine isAdminProcess | |
# Or if we are on v6 or higher, check the $IsWindows pre-defined variable. | |
If (($PSVersionTable.PSVersion.Major -le 5) -or $IsWindows) { | |
$currentUser = [Security.Principal.WindowsPrincipal]([Security.Principal.WindowsIdentity]::GetCurrent()) | |
Return $currentUser.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) | |
} | |
# Must be Linux or OSX, so use the id util. Root has userid of 0. | |
Return 0 -eq (id -u) | |
} | |
Function Get-Elevation { | |
<# | |
.SYNOPSIS | |
Sets title value based on administrator status. | |
.DESCRIPTION | |
Sets title value based on administrator status. | |
.EXAMPLE | |
Get-Elevation | |
Sets title value to 'W.O.P.R.' if admin, stes to 'Joshua' if not | |
#> | |
[CmdletBinding()] | |
Param () | |
If (Test-Administrator) { | |
#$script:elevation = "Admin" | |
$elevation = 'W.O.P.R.' | |
Write-Verbose -Message ('Powershell is running as: {0}' -f $elevation) | |
} Else { | |
#$script:elevation = "Non-Admin" | |
$elevation = 'Joshua' | |
Write-Verbose -Message ('Powershell is running as: {0}' -f $elevation) | |
} | |
Return $elevation | |
} | |
Function Set-WindowTitle { | |
<# | |
.SYNOPSIS | |
Gets computer name and adds to Get-Elevation result to finally set the window title. | |
.DESCRIPTION | |
Gets computer name and adds to Get-Elevation result to finally set the window title. | |
.EXAMPLE | |
Set-WindowTitle | |
Sets the window title. | |
#> | |
[CmdletBinding()] | |
Param () | |
$host_title = [ordered]@{ | |
'Session' = "$env:COMPUTERNAME".ToUpper() | |
'Elevation' = Get-Elevation | |
#'Version' = "v$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)" | |
} | |
$formatted_title = "[$($host_title.Values -join ': ')]" | |
Write-Verbose -Message ("Setting Window Title to '{0}'" -f $formatted_title) | |
$Host.UI.RawUI.WindowTitle = $formatted_title | |
} | |
Function Copy-LastCommand { | |
<# | |
.SYNOPSIS | |
Looks through command history to copy the last command to clipboard. | |
.DESCRIPTION | |
Looks through command history to copy the last command to clipboard | |
.EXAMPLE | |
Copy-LastCommand | |
Looks through command history to copy the last command to clipboard | |
#> | |
Get-History -Id $(((Get-History) | Select-Object -Last 1 | Select-Object -Property ID -ExpandProperty ID)) | | |
Select-Object -ExpandProperty CommandLine | | |
& "$env:windir\system32\clip.exe" | |
} | |
New-Alias -Name copylast -Value Copy-LastCommand | |
Function Edit-Profile { | |
<# | |
.SYNOPSIS | |
Shortcut command to edit your $profile. | |
.DESCRIPTION | |
Shortcut command to edit your $profile. | |
.EXAMPLE | |
Edit-Profile | |
Opens your profile in Powershell_ISE | |
#> | |
If ($host.Name -match 'ise') { | |
$psISE.CurrentPowerShellTab.Files.Add($profile) | |
} Else { | |
& "$env:windir\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe" $profile | |
} | |
} | |
Function Open-HistoryFile { | |
<# | |
.SYNOPSIS | |
Opens yourcommand history in powershell_ise. | |
.DESCRIPTION | |
Opens your command history in powershell_ise. | |
.EXAMPLE | |
Open-HistoryFile | |
Opens your command history in powershell_ise | |
#> | |
& "$env:windir\system32\WindowsPowerShell\v1.0\powershell_ise.exe" (Get-PSReadLineOption | Select-Object -ExpandProperty HistorySavePath) | |
} | |
#endregion Prompt Functions | |
Try { | |
Import-Module -Name ActiveDirectory | |
} Catch { | |
Write-Warning -Message 'No ActiveDirectory Module' | |
} | |
$script:PDC = (Get-AdDomainController -Filter {OperationMasterRoles -like '*PDCEmulator*'}).HostName | |
#region Functions | |
#region Helpers | |
enum Colour { | |
Bk | |
DkBl | |
DkGr | |
DkCy | |
DkRe | |
DkMa | |
DkYe | |
Gy | |
DkGy | |
Bl | |
Gr | |
Cy | |
Re | |
Ma | |
Ye | |
Wh | |
} | |
Function Write-Short { | |
<# | |
.SYNOPSIS | |
Write-Short is a short-hand substitution for Write-Host. | |
.DESCRIPTION | |
Attempts to create a rudamentary method of using Write-Host with common parameters. | |
Valid Color Values: | |
* Bl = Black | |
* DkBl = DarkBlue | |
* DkGr = DarkGreen | |
* DkCy = DarkCyan | |
* DkRe = DarkRed | |
* DkMa = DarkMagenta | |
* DkYe = DarkYellow | |
* Gy = Gray | |
* DkGy = DarkGray | |
* Bl = Blue | |
* Gr = Green | |
* Cy = Cyan | |
* Re = Red | |
* Ma = Magenta | |
* Ye = Yellow | |
* Wh = White | |
.PARAMETER t | |
Text you would normally pass to Write-Host. | |
.PARAMETER b | |
BackgroundColor - Shorthand List: | |
.PARAMETER f | |
ForegroundColor - Shorthand: see BackgroundColor | |
.PARAMETER n | |
NoNewLine. | |
.EXAMPLE | |
WH -t 'This is a test' -b White -n | |
- eq - | |
Write-Host 'This is a test' -BackgroundColor White -NoNewLine | |
.EXAMPLE | |
WH -t 'This is a Color Test' -b Bl -f Cy -n | |
- eq - | |
Write-Host 'This is a Color Test' -BackgroundColor Black -ForegroundColor Cyan -NoNewLine | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
[CmdletBinding()] | |
[Alias('WH')] | |
Param ( | |
### Object normally sent to Write-Host (text) | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Text' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[Object]$t, | |
### BackgroundColor | |
[Colour]$b = $null, | |
### ForegroundColor | |
[Colour]$f = $null, | |
### NoNewLine | |
[Switch]$n | |
) | |
### Creating our Splat for Write-Host | |
$WriteObject = @{Object = $t} | |
Function Get-Color { | |
<# | |
.SYNOPSIS | |
Choose a Color. | |
#> | |
[CmdletBinding()] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Valid Colour Option' | |
)] | |
[Colour]$Color | |
) | |
Switch ($Color) { | |
'Bk' { $ColorChosen = 'Black' } | |
'DkBl' { $ColorChosen = 'DarkBlue' } | |
'DkGr' { $ColorChosen = 'DarkGreen' } | |
'DkCy' { $ColorChosen = 'DarkCyan' } | |
'DkRe' { $ColorChosen = 'DarkRed' } | |
'DkMa' { $ColorChosen = 'DarkMagenta'} | |
'DkYe' { $ColorChosen = 'DarkYellow' } | |
'Gy' { $ColorChosen = 'Gray' } | |
'DkGy' { $ColorChosen = 'DarkGray' } | |
'Bl' { $ColorChosen = 'Blue' } | |
'Gr' { $ColorChosen = 'Green' } | |
'Cy' { $ColorChosen = 'Cyan' } | |
'Re' { $ColorChosen = 'Red' } | |
'Ma' { $ColorChosen = 'Magenta' } | |
'Ye' { $ColorChosen = 'Yellow' } | |
'Wh' { $ColorChosen = 'White' } | |
default { $ColorChosen = $Color } | |
} | |
return $ColorChosen | |
} | |
### -BackgroundColor | |
If ($b) {$WriteObject.BackgroundColor = Get-Color -Color $b} | |
### -ForegroundColor | |
If ($f) {$WriteObject.ForegroundColor = Get-Color -Color $f} | |
### -NoNewLine | |
If ($n) {$WriteObject.NoNewLine = $true} | |
### Output our splat of Write-Host | |
Write-Host @WriteObject | |
} | |
Function Get-Container { | |
<# | |
.SYNOPSIS | |
Translates a CanonicalName to more of a container. | |
.DESCRIPTION | |
Translates a CanonicalName to a container to make it easier to read. | |
.PARAMETER can | |
CanonicalName | |
.EXAMPLE | |
Get-Container -can (Get-ADUser testuser -prop CanonicalName).CanonicalName | |
Turns the DistinguishedName of the OU the user is in to more of a container: | |
Before: CN=testuser,OU=CompanyOU,OU=Users,DC=Domain,DC=LOCAL | |
After : Domain.LOCAL/CompanyOU/Users | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
[Alias('container')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'CanonicalName required' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$can | |
) | |
$container = $can -ireplace '\/[^\/]+$','' | |
Return $container | |
} | |
Function Convert-StandardPhone { | |
<# | |
.SYNOPSIS | |
Convert value to Phone format. | |
.DESCRIPTION | |
Determine how many digits are in input and format to proper telephone syntax. | |
.PARAMETER NumtoConv | |
Number to convert. | |
.EXAMPLE | |
Convert-StandardPhone -NumtoConv 1234567 | |
123-4567 | |
.EXAMPLE | |
Convert-StandardPhone -NumtoConv 1234567890 | |
(123) 456-7890 | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Phone Number required' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$NumtoConv | |
) | |
If ($NumtoConv -notmatch 'Last|ADSI|N/A'){ | |
$pnum = $NumtoConv -replace '[^0-9]','' | |
$pnum = $pnum -replace '^0' -replace '^1' -replace '\s' -as [LONG] | |
$pnumlength = ($pnum | Measure-Object -Character).Characters | |
If ($pnumlength -eq 7) { | |
$newPhoneNumber = '{0:###-####}' -f ([long]$pnum) | |
} ElseIf ($pnumlength -eq '11') { | |
$pnum = $pnum.Substring(1) | |
$newPhoneNumber = '{0:(###) ###-####}' -f ([long]$pnum) | |
} ElseIf ($pnumlength -eq 10) { | |
$newPhoneNumber = '{0:(###) ###-####}' -f ([long]$pnum) | |
} Else { | |
$newPhoneNumber = $NumtoConv | |
} | |
} Else { | |
$newPhoneNumber = $null | |
} | |
Return $newPhoneNumber | |
} | |
Function Initialize-File { | |
<# | |
.SYNOPSIS | |
Creates an empty file | |
.DESCRIPTION | |
Creates an empty file | |
.PARAMETER <full path and name of file with extension> | |
Define the file to make | |
.EXAMPLE | |
Touch "C:\down\test.txt" | |
.INPUTS | |
String | |
.OUTPUTS | |
File | |
#> | |
[Alias('Touch')] | |
Param ( | |
[Parameter(Position = 0)] | |
[String]$file = $args[0] | |
) | |
If ($file -eq $null) { | |
Throw 'No filename supplied' | |
} | |
If (Test-Path -Path $file) { | |
(Get-ChildItem -Path $file).LastWriteTime = Get-Date | |
} Else { | |
Write-Output -InputObject $null > $file | |
} | |
} | |
Function Get-IPValid { | |
<# | |
.SYNOPSIS | |
Test if an IP address is valid. | |
.DESCRIPTION | |
Tests if an IP address is in a valid syntax and in acceptable IP range. | |
.PARAMETER testip | |
IP to test. | |
.EXAMPLE | |
Get-IPValid -testip '192.168.3.5' | |
.INPUTS | |
String | |
.OUTPUTS | |
Boolean | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'IP Address' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$testip | |
) | |
If ($testip -ne '0.0.0.0') { | |
### REGEX Pattern | |
[regex]$pattern = '^(?:(?:1\d\d|2[0-5][0-4]|2[0-4]\d|0?[1-9]\d|0?0?\d)\.){3}(?:1\d\d|2[0-5][0-4]|2[0-4]\d|0?[1-9]\d|0?0?\d)$' | |
### Evaluate if the test IP matches the REGEX | |
If ($testip -match $pattern) { | |
return $true | |
} Else { | |
return $false | |
} | |
} Else { | |
return $false | |
} | |
} | |
Function Get-String { | |
<# | |
.SYNOPSIS | |
Get string behaves like NIX grep | |
.DESCRIPTION | |
Iterates through any inbound string looking for specified string | |
.EXAMPLE | |
Get-Content whatever.txt | Get-String STRING | |
.NOTES | |
https://adamtheautomator.com/powershell-grep/ | |
.INPUTS | |
String | |
.OUTPUTS | |
Stream | |
#> | |
[Alias('grep')] | |
[CmdletBinding()] | |
Param ( | |
[Parameter(Position = 0)] | |
[ValidateNotNullOrEmpty()] | |
[String]$in = $args[0], | |
[Switch]$v | |
) | |
If (-not $v){ | |
$in | Out-String -Stream | Select-String -Pattern $args | |
} Else { | |
$skipping = $in | Out-String -Stream | Select-Object -Skip ($v + 1) | |
$skipping | |
} | |
} | |
Function Read-OpenFileDialog { | |
<# | |
.SYNOPSIS | |
An Open file GUI dialog | |
.DESCRIPTION | |
Open File GUI | |
.PARAMETER WindowTitle | |
Window Title | |
.PARAMETER InitialDirectory | |
Where you want the window to open from | |
.PARAMETER Filter | |
What kind of file filters you want | |
Examples: | |
* 'All files (*.*)|*.*' | |
* 'CSV files (*.csv)|*.csv' | |
* 'Excel files (*.xlsx)|*.xlsx' | |
.PARAMETER AllowMultiSelect | |
Allow user to select more than one thing. | |
.EXAMPLE | |
Read-OpenFileDialog | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'WindowTitle required' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$WindowTitle, | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Starting Directory required' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$InitialDirectory, | |
[ValidateSet('All files (*.*)|*.*','CSV files (*.csv)|*.csv','Excel files (*.xlsx)|*.xlsx','Text files (*.txt)|*.txt')] | |
[String]$Filter = 'All files (*.*)|*.*', | |
[Switch]$AllowMultiSelect | |
) | |
Add-Type -AssemblyName System.Windows.Forms | |
$openFileDialog = New-Object -TypeName System.Windows.Forms.OpenFileDialog | |
$openFileDialog.Title = $WindowTitle | |
If (![string]::IsNullOrWhiteSpace($InitialDirectory)){ | |
$openFileDialog.InitialDirectory = $InitialDirectory | |
} | |
$openFileDialog.Filter = $Filter | |
If ($AllowMultiSelect){ | |
$openFileDialog.MultiSelect = $true | |
} | |
$openFileDialog.ShowHelp = $true | |
$openFileDialog.ShowDialog() > $null | |
If ($AllowMultiSelect){ | |
Return $openFileDialog.Filenames | |
} Else { | |
Return $openFileDialog.Filename | |
} | |
} | |
Function Get-Tail { | |
<# | |
.SYNOPSIS | |
Equivalent of NIX tail -f | |
.DESCRIPTION | |
Will monitor any kind of text readable log and show changes in real time | |
.EXAMPLE | |
Get-Tail c:\somelog.log | |
.INPUTS | |
String | |
.OUTPUTS | |
Stream | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Path to file to tail' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$filepath | |
) | |
If ([String]::IsNullOrEmpty($filePath)) { | |
$filePath = Read-OpenFileDialog -WindowTitle 'Select Text File Example' -InitialDirectory "$env:SystemDrive\" | |
} ElseIf (![String]::IsNullOrEmpty($filePath)){ | |
Get-Content -Path ('{0}' -f $filePath) -Wait | |
} Else { | |
Write-Warning -Message 'You did not select a file.' | |
} | |
} | |
Function Optimize-HumanReadable { | |
<# | |
.SYNOPSIS | |
Convert raw file size to something human-readable | |
.DESCRIPTION | |
Convert raw size to something human readable | |
.EXAMPLE | |
gci .\file.xlsx | measure length -Sum | select @{n='Size';e={HR -size $_.Sum}} | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
[CmdletBinding()] | |
[Alias('HR')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'directory or file size summary required' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[int]$size | |
) | |
Switch ($size) { | |
{$_ -ge 1PB} { | |
"{0:#.#' PB'}" -f ($size / 1PB) | |
Break | |
} | |
{$_ -ge 1TB} { | |
"{0:#.#' TB'}" -f ($size / 1TB) | |
Break | |
} | |
{$_ -ge 1GB} { | |
"{0:#.#' GB'}" -f ($size / 1GB) | |
Break | |
} | |
{$_ -ge 1MB} { | |
"{0:#.#' MB'}" -f ($size / 1MB) | |
Break | |
} | |
{$_ -ge 1KB} { | |
"{0:#' KB'}" -f ($size / 1KB) | |
Break | |
} | |
default { | |
'{0:n0}' -f ($size) + ' Bytes' | |
} | |
} | |
} | |
Function Out-ExcelClip { | |
<# | |
.SYNOPSIS | |
Will take input and convert to excel ready data and copy to clipboard | |
.DESCRIPTION | |
Takes an array output and converts it to excel ready data and copies it to clipboard | |
.PARAMETER in | |
input can be something specified, otherwise it's whatever the incoming information stream is. | |
.PARAMETER delimiter | |
delimiter is used if you have information that is already delimited somehow that you're bringing in. | |
.EXAMPLE | |
Get-ChildItem C:\down | Out-ExcelClip | |
sends the output of get-childitem to your clipboard ready to be pasted into excel | |
.INPUTS | |
Array | |
.OUTPUTS | |
None | |
#> | |
[CmdletBinding()] | |
[Alias('clipXL')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Need input', | |
ValueFromPipelineByPropertyName = $true, | |
ValueFromPipeline = $true, | |
Position = 0 | |
)] | |
[ValidateNotNullOrEmpty()] | |
[Array]$in, | |
[String]$delimiter = ',' | |
) | |
End { | |
($in | ConvertTo-Csv -Delimiter $delimiter -NoTypeInformation) -replace "\$delimiter",[char]9 | Set-Clipboard | |
} | |
} | |
Function Get-PathLength { | |
<# | |
.SYNOPSIS | |
Counts characters in a string. | |
.DESCRIPTION | |
Intended to count characters in a filename - Windows path length is 260. | |
.PARAMETER path | |
Any string - Doesn't have to be a path as it will count the characters anyway. | |
.EXAMPLE | |
Get-PathLength -path "\\DFSServer\shared\Clients\Directory One\Directory Two\Directory Three\Directory Four\Directory 5\FileName One.pdf" | |
114 | |
.EXAMPLE | |
Get-PathLength -path "This is a test" | |
14 | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
[Alias('length')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Any string' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$path | |
) | |
$length = ($path | Measure-Object -Character).Characters | |
If ($length -gt 260) { | |
WH -t $length -f Re | |
} ElseIf ($length -gt 200) { | |
WH -t $length -f Ye | |
} Else { | |
WH -t $length -f Gr | |
} | |
} | |
#endregion Helpers | |
#region Credentials | |
Function Get-MySAUser { | |
<# | |
.SYNOPSIS | |
Probes AD to get your SA username. | |
.DESCRIPTION | |
Uses AD to lookup all users with your name and choose your SA account. | |
.EXAMPLE | |
Get-MySAUser | |
.INPUTS | |
None | |
.OUTPUTS | |
String | |
#> | |
$me = $env:USERNAME | |
$Domain = $env:USERDOMAIN | |
$meAD = Get-ADUser -Identity $me -ErrorAction Stop | |
$toMatch = 'sa-' | |
If (($me -notmatch $toMatch)){ | |
Write-Verbose -Message 'Running as SA user ...No.' | |
$sauser = $false | |
### Derive SA user SamAccountName | |
$find = $meAD.Name | |
$saun = (Get-ADUser -Filter {anr -eq $find} | | |
Where-Object {$_.SamAccountName -ne $env:USERNAME} | | |
Where-Object {$_.SamAccountName -match $toMatch}).SamAccountName | |
} Else { | |
Write-Verbose -Message 'Running as SA user ...Yes.' | |
$sauser = $true | |
} | |
If ($sauser) { | |
return $Domain + '\' + $me | |
} Else { | |
return $Domain + '\' + $saun | |
} | |
} | |
Function Test-Credential { | |
<# | |
.SYNOPSIS | |
Validate credential. | |
#> | |
[CmdletBinding()] | |
[OutputType([bool])] | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Username' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[string]$UserName, | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Password' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[string]$PW, | |
[ValidateSet('Domain','Machine')] | |
[string]$Context = 'Domain' | |
) | |
Begin { | |
Add-Type -AssemblyName System.DirectoryServices.AccountManagement | |
$ctx = New-Object -TypeName DirectoryServices.AccountManagement.PrincipalContext -ArgumentList ($context) | |
} | |
Process { | |
return $ctx.ValidateCredentials($UserName, $PW) | |
} | |
End { | |
$ctx.Dispose() | |
} | |
} | |
Function Clear-SavedCredential { | |
<# | |
.SYNOPSIS | |
Remove config file. | |
#> | |
[CmdletBinding()] | |
Param() | |
If (Test-Path -Path $CredentialsFile) { | |
#Remove credential file | |
Remove-Item -Path $CredentialsFile -Force | |
} | |
} | |
Function Register-SACreds { | |
<# | |
.SYNOPSIS | |
Save your SA credentials in a local file. | |
.DESCRIPTION | |
Securely save SA credentials into a CLIXML file. | |
.EXAMPLE | |
Register-SACreds | |
.INPUTS | |
None | |
.OUTPUTS | |
String | |
#> | |
If ((Get-Content -Path $profile | Out-String -Stream | Select-Object -Last 1) -notlike '*Credential*') { | |
WH -t 'Upon relaunch we will add the ability to store your SA credentials to file for future use.' | |
$AddtoProfile = @' | |
New-Variable -Name CredentialsFile -Value (Join-Path -Path $env:USERPROFILE -ChildPath 'MyVault.cred') -Scope Script -Force | |
### Create credential file and/or load creds to persistent memory | |
If (-not (Test-Path -Path $CredentialsFile)) { | |
Set-SavedCredential -Id "MySAUser" -UserName (Get-MySAUser) | |
Start-Sleep -Seconds 1 | |
$script:Credential = Get-SavedCredential -Id "MySAUser" | |
} Else {$script:Credential = Get-SavedCredential -Id "MySAUser"} | |
$PSDefaultParameterValues.Add("*:Credential",$Credential) | |
'@ | |
$AddtoProfile >> $profile | |
} Else { | |
WH -t 'MySAUser already in profile' | |
} | |
WH -t 'Relaunch Powershell and be prompted to enter your SA credentials to be saved to file' -b Bl -f Ye | |
pause | |
} | |
Function Set-SavedCredential() { | |
<# | |
.SYNOPSIS | |
Set credential information to config file. | |
.DESCRIPTION | |
Add a more complete description of what the function does. | |
.PARAMETER Id | |
Name for Credential. | |
.PARAMETER UserName | |
UserName to store. | |
.PARAMETER Password | |
Password to Store. | |
.PARAMETER Validate | |
Test credentials. | |
.EXAMPLE | |
Set-SavedCredential -Id Value -UserName Value -Password Value -Validate | |
Describe what this call does | |
.NOTES | |
Password in config file is encypted by Convert-FromSecureString (DAPI is used internally). | |
Config file is valid for LocalMachine/Currentuser context only. | |
.LINK | |
https://gist.github.com/altrive/6043181 | |
The first link is opened by Get-Help -Online Set-SavedCredential | |
.EXAMPLE | |
Set-SavedCredential -Id "LocalAdmin" -UserName "localhost\Administrator" -Password "Password!" | |
.EXAMPLE | |
Set-SavedCredential -Id "FileShare" -UserName "localhost\FileShare" -Password "Password!" | |
.EXAMPLE | |
Set-SavedCredential -Id "DomainAdmin" -UserName "TEST\Administrator" -Password "Password!" | |
.EXAMPLE | |
Set-SavedCredential -Id "SqlAdmin" -UserName "TEST\sqlSvc" -Password "Password!" | |
.EXAMPLE | |
Set-SavedCredential -Id "SA" -UserName "SHERMCO\sa-somebody" | |
.INPUTS | |
List of input types that are accepted by this function. | |
.OUTPUTS | |
List of output types produced by this function. | |
#> | |
[CmdletBinding()] | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'ID' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$Id, | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Username' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$UserName, | |
[Parameter( | |
Mandatory = $false, | |
HelpMessage = 'Password' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[string]$PW, | |
[switch]$Validate | |
) | |
#Validate credential | |
If ($Validate) { | |
If ($UserName.StartsWith('localhost\')){ | |
$validationContext = 'Machine' | |
} Else { | |
$validationContext = 'Domain' | |
} | |
$TestSplat = @{ | |
UserName = $UserName | |
Password = $PW | |
Context = $validationContext | |
} | |
$isValid = Test-Credential @TestSplat | |
If (-not $isValid) { | |
Write-Error -Message ('Credential Validation Failed: {0}({1})' -f $Id, $UserName) | |
} | |
} | |
#Convert password to SecureString plain text | |
If ($PW) { | |
$securePassword = $PW | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | |
} Else { | |
$securePassword = Get-Credential -Credential ($UserName) | |
} | |
#Get saved credential if exists | |
$credentials = @{} | |
If (Test-Path -Path $CredentialsFile) { | |
$credentials = Import-Clixml -Path $CredentialsFile | |
} Else { | |
#Ensure output directory exists | |
$baseDir = [IO.Path]::GetDirectoryName($CredentialsFile) | |
$null = New-Item -ItemType Directory -Path $baseDir -ErrorAction Ignore | |
} | |
#add/edit credential | |
$credentials[$Id] = @{ | |
UserName = $UserName | |
Password = $securePassword | |
} | |
#Save Credentials as CliXml Format | |
$credentials | Export-Clixml -Path $CredentialsFile -Encoding UTF8 -Force | |
} | |
Function Show-SavedCredential { | |
<# | |
.SYNOPSIS | |
Show credentials list stored in config file. | |
#> | |
[CmdletBinding()] | |
[OutputType([hashtable])] | |
Param () | |
If (!(Test-Path -Path $CredentialsFile)) { | |
Write-Error -Message 'Credential file not found!' | |
} | |
$result = Import-Clixml -Path $CredentialsFile -ErrorAction Ignore | |
return $result | |
} | |
Function Get-SavedCredential { | |
<# | |
.SYNOPSIS | |
Get credential information from config file. if no credential found, show credential enter dialog. | |
.EXAMPLE | |
$cred1 = Get-SavedCredential -Id "LocalAdmin" | |
$cred2 = Get-SavedCredential -Id "FileShare" -Validate | |
#> | |
[CmdletBinding()] | |
[OutputType([pscredential])] | |
Param ( | |
[Parameter(Mandatory,HelpMessage='Credential ID',Position=0)] | |
[ValidateNotNullOrEmpty()] | |
[String]$Id, | |
[Switch]$Validate | |
) | |
$credentials = Import-Clixml -Path $CredentialsFile -ErrorAction Ignore | |
If (($null -eq $credentials) -or !($credentials.ContainsKey($Id))) { | |
return Get-Credential -Message ('Enter Credential for {0}' -f $Id) #Don't save credential for temporary use. | |
} | |
#Get saved credential | |
$result = $credentials[$Id] | |
#Convert to PSCredential | |
[String]$userName = $result.Values.UserName | |
#$securePassword = ConvertTo-SecureString -String $result.Password | |
$securePassword = $result.Values.Password | |
$cred = New-Object -TypeName System.Management.Automation.PsCredential -ArgumentList ($userName, $securePassword) | |
#Validate Credential | |
If ($Validate) { | |
If ($cred.GetNetworkCredential().Domain -eq 'localhost') { | |
$validationContext = 'Machine' | |
} Else { | |
$validationContext = 'Domain' | |
} | |
$TestSplat = @{ | |
UserName = $cred.UserName | |
Password = $cred.GetNetworkCredential().Password | |
Context = $validationContext | |
} | |
#$isValid = Test-Credential -UserName $cred.UserName -Password $cred.GetNetworkCredential().Password -Context $validationContext | |
$isValid = Test-Credential @TestSplat | |
If (!$isValid) { | |
Write-Error -Message ('Credential Validation Failed: {0}({1})' -f $Id, $userName) | |
} | |
} | |
return $cred | |
} | |
Function Get-SavedPass { | |
<# | |
.SYNOPSIS | |
Get saved password as plain text to clipboard. | |
#> | |
[CmdletBinding()] | |
[Alias('ClipPass')] | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Credential ID', | |
Position = 0 | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$Id | |
) | |
$credentials = Import-Clixml -Path $CredentialsFile -ErrorAction Ignore | |
If (($null -eq $credentials) -or !($credentials.ContainsKey($Id))) { | |
return Get-Credential -Message ('Enter Credential for {0}' -f $Id) #Don't save credential for temporary use. | |
} | |
#Get saved credential | |
$result = $credentials[$Id] | |
$securePassword = $result.Values.Password | |
$PasswordPlain = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword)) | |
$PasswordPlain | Set-Clipboard | |
} | |
### Create credential file and/or load creds to persistent memory | |
<# | |
$MySAUser = 'MySAUser' | |
If (-not (Test-Path -Path $CredentialsFile)) { | |
Set-SavedCredential -Id $MySAUser -UserName (Get-MySAUser) | |
Start-Sleep -Seconds 1 | |
$script:Credential = Get-SavedCredential -Id $MySAUser | |
} Else { | |
$script:Credential = Get-SavedCredential -Id $MySAUser | |
} | |
$PSDefaultParameterValues.Add('*:Credential',$Credential) | |
#> | |
#endregion Credentials | |
#region Domain | |
Function Get-DC { | |
<# | |
.SYNOPSIS | |
Gets domain controllers | |
.DESCRIPTION | |
Gets domain controllers and their roles | |
.PARAMETER | |
thorough | |
Validates DNS and gets list using the old methd | |
.EXAMPLE | |
Get-DCs | Format-Table -AutoSize | |
.EXAMPLE | |
Get-DCs | ?{$_.Roles -ne $null} | FT | |
Get a list of all DCs but only return those with FSMO roles | format table | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
[CmdletBinding()] | |
[Alias('GetDCs')] | |
Param ( | |
[Switch]$thorough | |
) | |
If ($thorough.IsPresent){ | |
$rSel = @{ | |
Property = 'Forest', | |
@{n='Name';e={$_.Name.Split('.')[0]}}, | |
'OSVersion', | |
@{n='IP';e={[Net.Dns]::GetHostByName($_.Name).AddressList[0].IPAddressToString}}, | |
'SiteName', | |
'Roles' | |
} | |
$results = ([DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).DomainControllers | Select-Object @rSel | |
} Else { | |
$rSel = @{ | |
Property = 'Forest', | |
'Name', | |
@{n='OSVersion';e={$_.OperatingSystem}}, | |
@{n='IP';e={$_.IPv4Address}}, | |
@{n='SiteName';e={$_.Site}}, | |
@{n='Roles';e={$_.OperationMasterRoles}} | |
} | |
$results = Get-AdDomainController -Filter * | Select-Object @rSel | |
} | |
Return $results | |
} | |
Function Get-DNS { | |
<# | |
.SYNOPSIS | |
Gets DNS controllers | |
.DESCRIPTION | |
Gets a list of DNS controllers in the domain | |
.EXAMPLE | |
Get-DNS | Sort IP | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
[Alias('GetDNS')] | |
$DNSServers = @() | |
$Results = ((& "$env:windir\system32\nltest.exe" /DnsGetDC:$env:USERDNSDOMAIN | Select-Object -Skip 2 | Select-Object -SkipLast 1).Trim() -Replace '\s+',',') | |
$Results | ForEach-Object { | |
If ($_ -notmatch 'WARNING|successfully'){ | |
$DNSServers += [PSCustomObject][Ordered]@{ | |
Name = $_.Split(',')[0].Split('.')[0].toUpper() | |
IP = $_.Split(',')[1] | |
} | |
} | |
} | |
$results = @() | |
$DNSServers | Group-Object -Property Name,IP | ForEach-Object { | |
$results += [PSCustomObject][Ordered]@{ | |
Name = $_.Name.split(',')[0].trim() | |
IP = $_.Name.split(',')[1].trim() | |
} | |
} | |
Return $results | |
} | |
Function Find-PrintServers { | |
<# | |
.SYNOPSIS | |
Finds print servers on the network | |
.DESCRIPTION | |
Attempts to reach out to all windows servers to see if they have the Print-Services function | |
.EXAMPLE | |
Find-PrintServer | |
For every server it can reach, script determines if it has the Print-Services feature | |
installed. This will return a set of values for all matches with the following fields | |
DisplayName: Print and Document Services | |
ServerName : | |
IPAddress : | |
Location : <Physical location based on IPAddress> | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
[Alias('Find-PrintServer')] | |
$ErrorActionPreference = 'SilentlyContinue' | |
$InitialOutput = @() | |
$ScriptBlock = {Get-WindowsFeature -Name Print-Services | Where-Object {$_.Installed -match 'True'}} | |
$Servers = Get-ADComputer -Filter {Enabled -eq $true -AND OperatingSystem -like '*Windows Server*'} -Credential $Credential -Server $PDC | | |
Select-Object -ExpandProperty Name | |
$job = Try { | |
Invoke-Command -ComputerName $Servers -Credential $Credential -ScriptBlock $ScriptBlock -AsJob | |
} Catch { | |
Write-Error -Message "can't connect to $($_)" | |
} | |
While ((Get-Job -Id $job.Id).State -eq 'Running') { | |
Start-Sleep -MilliSeconds 500 | |
} | |
$InitialOutput += Get-Job -Id $job.Id -IncludeChildJob | Receive-Job | |
Get-Job -Id $job.Id | Remove-Job | |
$PostProcessedOutput = @() | |
ForEach ($item in $InitialOutput){ | |
$ServerIP = Get-ADComputer -Identity $item.PSComputerName -Credential $Credential -Properties IPv4Address -Server $PDC | | |
Select-Object -ExpandProperty IPv4Address | |
$PostProcessedOutput += [PsCustomObject][Ordered]@{ | |
DisplayName = $item.DisplayName | |
ServerName = $item.PSComputerName | |
IPAddress = $ServerIP | |
} | |
} | |
Return $PostProcessedOutput | |
} | |
Function Get-EmptyGroupDetails { | |
<# | |
.SYNOPSIS | |
Get empty AD Groups. | |
.DESCRIPTION | |
Get all empty AD groups. | |
.EXAMPLE | |
Get-EmptyGroupDetails | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
Function Get-EmptyGroup { | |
<# | |
.SYNOPSIS | |
This function queries the Active Directory domain the initiaing computer is in for all groups that have no members. | |
This is common when attempting to find groups that can be removed. | |
This does not include default AD groups like Domain Computers, Domain Users, etc. | |
.EXAMPLE | |
PS> Get-EmptyGroup | |
#> | |
[OutputType([PSCustomObject])] | |
[CmdletBinding()] | |
Param () | |
Begin { | |
$ErrorActionPreference = 'Stop' | |
} | |
Process { | |
Try { | |
@(Get-ADGroup -Filter * -Properties isCriticalSystemObject, Members).Where({(-not $_.isCriticalSystemObject) -and ($_.Members.Count -eq 0)}) | |
} Catch { | |
$PSCmdlet.ThrowTerminatingError($_) | |
} | |
} | |
} | |
### Prep Variables | |
$EmptyGroupTotal = @() | |
$EmptyGroups = Get-EmptyGroup | Sort-Object -Property Name | |
$pi = 0 | |
$Progress = @{ | |
Activity = 'Working through Groups . . .' | |
CurrentOperation = 'Loading' | |
PercentComplete = 0 | |
} | |
Foreach ($EmptyGroup in $EmptyGroups){ | |
$pi++ | |
[int]$percentage = ($pi / $EmptyGroups.Count)*100 | |
$Progress.CurrentOperation = "$pi of $($EmptyGroups.Count) - $($EmptyGroup.Name)" | |
$Progress.PercentComplete = $percentage | |
Write-Progress @Progress | |
$cParam = @{ | |
Identity = $EmptyGroup.Distinguishedname | |
Properties = 'CanonicalName', | |
'Created', | |
'Description', | |
'GroupCategory', | |
'GroupScope', | |
'MemberOf', | |
'Membership', | |
'Modified', | |
'Name' | |
} | |
$cGroup = Get-ADGroup @cParam | |
$EmptyGroupTotal += [PSCustomObject][Ordered]@{ | |
Name = $cGroup.Name | |
Description = $cGroup.Description | |
GroupScope = $cGroup.GroupScope | |
GroupCategory = $cGroup.GroupCategory | |
Memberof = $cGroup.MemberOf | |
Membership = ($cGroup.Membership).Count | |
Created = $cGroup.Created | |
Modified = $cGroup.Modified | |
CanonicalName = $cGroup.CanonicalName | |
} | |
} | |
### Cleanup | |
Write-Progress -Activity 'Working through users . . .' -Status 'Ready' -Completed | |
### Return results | |
$EmptyGroupTotal | Out-GridView | |
} | |
Function Get-EmptyOUs { | |
<# | |
.SYNOPSIS | |
Shows empty OUs. | |
.DESCRIPTION | |
Searches for, and displays Organizational Units that contain no objects. | |
.EXAMPLE | |
Get-EmptyOUs | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
$remove_ous = $false | |
$ous_to_keep = @( | |
'UAP - PEAP TLS', | |
'UAP - PEAP TLS Only', | |
'Disabled Users' | |
) | |
$ad_objects = Get-ADObject -Filter "ObjectClass -eq 'user' -or ObjectClass -eq 'computer' -or ObjectClass -eq 'group' -or ObjectClass -eq 'organizationalUnit'" | |
$aOuDns = @() | |
ForEach ($o in $ad_objects) { | |
$sDn = $o.DistinguishedName | |
If ($sDn -like '*OU=*' -and $sDn -notlike '*LostAndFound*') { | |
$sOuDn = $sDn.Substring($sDn.IndexOf('OU=')) | |
$aOuDns += $sOuDn | |
} | |
} | |
$a0CountOus = $aOuDns | Group-Object | Where-Object {$_.Count -eq 1} | ForEach-Object {$_.Name} | |
$empty_ous = 0 | |
$ous_removed = 0 | |
ForEach ($sOu in $a0CountOus) { | |
If (!(Get-ADObject -Filter "ObjectClass -eq 'organizationalUnit'" | Where-Object {$_.DistinguishedName -like "*$sOu*" -and $_.DistinguishedName -ne $sOu})) { | |
$ou = Get-AdObject -Filter {DistinguishedName -eq $sOu} | |
If ($ous_to_keep -notcontains $ou.Name) { | |
If ($remove_ous) { | |
Set-ADOrganizationalUnit -Identity $ou.DistinguishedName -ProtectedFromAccidentalDeletion $false -confirm:$false | |
Remove-AdOrganizationalUnit -Identity $ou.DistinguishedName -confirm:$false | |
$ous_removed++ | |
} | |
$ou | |
$empty_ous++ | |
} | |
} | |
} | |
Write-Output -InputObject '-------------------' | |
#echo "Total Empty OUs Removed: $ous_removed" | |
Write-Output -InputObject "Total Empty OUs: $empty_ous" | |
} | |
Function Get-SchemaVersion { | |
<# | |
.SYNOPSIS | |
Get domain Schema version. | |
.DESCRIPTION | |
Get domain Schema operating level. | |
.EXAMPLE | |
Get-SchemaVersion | |
Windows Server 2008 R2 | |
.INPUTS | |
None | |
.OUTPUTS | |
String | |
#> | |
$SchemaVersion = (Get-ADObject -Identity (Get-ADRootDSE).schemaNamingContext -Properties objectVersion).objectVersion | |
$HRSchemaVer = $null | |
Switch ($SchemaVersion){ | |
{'13'} {$HRSchemaVer = 'Windows Server 2000'} | |
{'30'} {$HRSchemaVer = 'Windows Server 2003'} | |
{'31'} {$HRSchemaVer = 'Windows Server 2003 R2'} | |
{'44'} {$HRSchemaVer = 'Windows Server 2008'} | |
{'47'} {$HRSchemaVer = 'Windows Server 2008 R2'} | |
{'56'} {$HRSchemaVer = 'Windows Server 2012'} | |
{'69'} {$HRSchemaVer = 'Windows Server 2012 R2'} | |
{'87'} {$HRSchemaVer = 'Windows Server 2016'} | |
{'88'} {$HRSchemaVer = 'Windows Server 2019'} | |
} | |
Return $HRSchemaVer | |
} | |
#endregion Domain | |
#region Updates/Misc | |
Function Get-UniquePerms { | |
<# | |
.SYNOPSIS | |
Get-UniquePerms iterates through a folder to show unique ACLs | |
.DESCRIPTION | |
Iterate through folders and show all folders that have permissions other than inherited | |
.PARAMETER shares | |
Parameter: -shares is needed to tell the function where to look | |
.PARAMETER csv | |
Parameter -csv tells the function to output in your run directory a csv output of what was found. | |
.EXAMPLE | |
Get-UniquePerms -shares '\\DFSPath\path\share' | |
Scans that one path | |
.EXAMPLE | |
Get-UniquePerms -shares '\\DFSPath\path\share','\\DFSPath\test\share' | |
Scans more than one path | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Need share path' | |
)] | |
[Object]$shares, | |
[Switch]$csv | |
) | |
If ($csv){ | |
$csvOut = "$($env:USERPROFILE)\desktop\Working_permissions.csv" | |
} | |
$output = @() | |
ForEach ($share in $shares) { | |
$folder = Get-Item -LiteralPath $share | |
$acl = Get-ACL -Path $folder.FullName | |
ForEach ($access in $acl.access) { | |
$output += [PSCustomObject]@{ | |
'Share' = $share | |
'Folder' = $folder.name | |
'User' = $access.identityreference | |
'IsInherited' = '' | |
'Permissions' = $access.FileSystemRights | |
'ParentPath' = $folder.Parent.FullName | |
} | |
} | |
$folders = Get-ChildItem -LiteralPath $share -Directory -Recurse | |
ForEach ($folder in $folders) { | |
Try { | |
$acl = Get-ACL -Path $folder.fullname | |
ForEach ($access in $acl.access) { | |
If ($access.isinherited -eq $false) { | |
$output += [PsCustomObject]@{ | |
'Share' = $share | |
'Folder' = $folder.name | |
'User' = $access.identityreference | |
'IsInherited' = $access.IsInherited | |
'Permissions' = $access.FileSystemRights | |
'ParentPath' = $folder.Parent.FullName | |
} | |
} | |
} | |
} Catch { | |
$output += [PSCustomObject]@{ | |
'Share' = $share | |
'Folder' = $folder | |
'User' = '???' | |
'IsInherited' = '???' | |
'Permissions' = '???' | |
'ParentPath' = $folder.Parent.FullName | |
} | |
} | |
} | |
} | |
If ($csv){ | |
$output | Export-Csv -Path $csvOut -NoTypeInformation -Encoding UTF8 -Delimiter ',' | |
} Else { | |
$output | Out-GridView | |
} | |
} | |
Function Get-UpdatesLastNight { | |
<# | |
.SYNOPSIS | |
Ask a computer to list all windows updates installed in the last 24 hours. | |
.DESCRIPTION | |
Send a query to a remote computer to get an inventory of all MS updates installed in the last 24 hours. | |
.PARAMETER comps | |
Computer name. | |
.PARAMETER Credential | |
You can specify either pre-stored Credentials or it will prompt | |
.EXAMPLE | |
Get-UpdatesLastNight -comps Test-Computer -Credential Value | |
Attempt to query remote computer using current credentials | |
.EXAMPLE | |
$CRD = Get-Credential | |
Get-UpdatesLastNight -comps @('Test-Computer','Test-Computer2') -Credential $CRD | Format-Table -Auto | |
Pre-set Credentials to use - Query Test-Computer and Test-Computer2 to Table-View | |
.NOTES | |
To kill all updates over the last 24 hours: | |
Get-HotFix | ?{$_.InstalledOn -gt [datetime]::Today.AddDays(-1)} | %{$kb=$_.HotFixID.trimStart('KB'); wusa /uninstall /kb:$kb} | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
Param ( | |
[Parameter( | |
Position = 0, | |
ValueFromPipeline = $true, | |
ValueFromPipelineByPropertyName = $true | |
)] | |
[Alias('hostname')] | |
[Alias('cn')] | |
[ValidateNotNullOrEmpty()] | |
[String[]]$comps = $env:COMPUTERNAME, | |
[Parameter(Position=1)] | |
[Alias('runas')] | |
[ValidateNotNull()] | |
[System.Management.Automation.Credential()] | |
[PSCredential]$Credential = $Credential | |
) | |
Begin { | |
$res = @() | |
If ($comps.count -gt 1){ | |
$pi = 0 | |
$Progress = @{ | |
Activity = 'Iterating thrugh servers Servers . . . ' | |
CurrentOperation = 'Loading' | |
PercentComplete = 0 | |
} | |
$multi = $true | |
} Else { | |
$multi = $false | |
} | |
} | |
Process { | |
ForEach ($srv in $comps){ | |
If (-not $srv.Name) { | |
$srv = [PSCustomObject]@{ | |
Name = $srv | |
} | |
} | |
If ($multi) { | |
$pi++ | |
$Progress.CurrentOperation = ('{0} of {1} - {2}' -f $pi, $comps.Count, $srv.Name) | |
$Progress.PercentComplete = [int](($pi / $comps.Count) * 100) | |
Write-Progress @Progress | |
} | |
Try { | |
If ($Credential) { | |
$ret += Invoke-Command -ComputerName $srv.Name -ScriptBlock { | |
Get-HotFix | Where-Object {$_.InstalledOn -gt [datetime]::Today.AddDays(-1)} | |
} -Credential $Credential -ErrorAction Stop | |
} Else { | |
$ret += Invoke-Command -ComputerName $srv.Name -ScriptBlock { | |
Get-HotFix | Where-Object {$_.InstalledOn -gt [datetime]::Today.AddDays(-1)} | |
} -ErrorAction Stop | |
} | |
ForEach ($r in $ret) { | |
$res += [PSCustomObject]@{ | |
ServerName = $srv.Name | |
OS = $srv.OperatingSystem | |
Description = $r.Description | |
HotFixID = $r.HotFixID | |
InstalledBy = $r.InstalledBy | |
InstalledOn = $r.InstalledOn | |
} | |
} | |
} Catch { | |
# Check for common DCOM errors and display "friendly" output | |
Switch ($_) { | |
{$_.Exception.FullyQualifiedErrorId -match 'ComputerNotFound'} { | |
$err = 'Cannot resolve Computer Name' | |
Break | |
} | |
{$_.CategoryInfo.FullyQualifiedErrorId -match 'WinRMOperationTimeOut'} { | |
$err = 'Access denied (Check User Permissions) - or Computer may be off' | |
Break | |
} | |
{$_.CategoryInfo.FullyQualifiedErrorId -match 'NetworkPathNotFound'} { | |
$err = 'Computer cannot be located on network. Still real?' | |
Break | |
} | |
default { | |
$err = $_.exception.gettype().fullname | |
} | |
} | |
Write-Warning -Message ('{0} - {1}' -f $srv, $err) | |
} | |
} | |
} | |
End { | |
If ($multi) { | |
Write-Progress -Activity 'Iterating thrugh servers Servers . . . ' -Status 'Ready' -Completed | |
} | |
return $res | |
} | |
} | |
Function Get-VPNCheck { | |
<# | |
.SYNOPSIS | |
Checks if a user is a member of VPN-Users group. | |
.DESCRIPTION | |
Checks if a user is a member of VPN-Users group. If not, attempts to add the user. | |
.PARAMETER user | |
username | |
.EXAMPLE | |
Get-VPNCheck -user test.user | |
Checks to see if the user is a member of VPN-Users. | |
If they aren't, prompts for SA credentials, then attempts to add the user to the VPN-Users group. | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
[Alias('vpncheck')] | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'username' | |
)] | |
[String]$user | |
) | |
Begin { | |
### Get the What-is | |
$UPA = @{ | |
Identity = $user | |
Properties = 'MemberOf' | |
Server = $script:PDC | |
} | |
$GDN = (Get-AdGroup -Identity 'VPN-Users').DistinguishedName | |
$UAD = Get-AdUser @UPA | |
} | |
Process { | |
### Evaluate | |
If ($UAD.MemberOf -contains $GDN){ | |
$msg = 'User is already in VPN-Users Group' | |
} Else { | |
### Add the user into the VPN-Users Group | |
Invoke-Command -ComputerName $PDC -Credential $Credential -ScriptBlock { | |
Get-ADUser -Identity $args[0] | ForEach-Object {Add-ADGroupMember -Identity 'VPN-Users' -Members $_} | |
} -ArgumentList $user | |
Write-Verbose -Message 'Attempted to add user to group' | |
Start-Sleep -Seconds 1 | |
### Re-Evluate for success | |
If ((Get-AdUser @UPA).MemberOf -contains $GDN){ | |
$msg = 'User was missing from VPN-Users group, but was successfully added.' | |
} Else { | |
$msg = 'User was missing from VPN-Users group, but attempt to add user failed' | |
} | |
} | |
} | |
End { | |
return $msg | |
} | |
} | |
Function Get-WinupdateAll { | |
<# | |
.SYNOPSIS | |
Use PSWindowsUpdate Module to perform updates. | |
.DESCRIPTION | |
Fetch and use PSWindowsUpdate module to fetch all updates to be current. | |
.PARAMETER norestart | |
Don't restart. | |
.EXAMPLE | |
Get-Winupdates -norestart | |
.INPUTS | |
None | |
.OUTPUTS | |
None | |
#> | |
[CmdletBinding()] | |
Param ( | |
[switch]$norestart | |
) | |
#region prereq | |
$Module = Get-Module -Name PSWindowsUpdate -ListAvailable | |
If ($Module.Count -eq 0) { | |
$Nuget = Get-PackageProvider -Name NuGet -ListAvailable | Select-Object -First 1 | |
$Get = Get-Module -Name PowerShellGet -ListAvailable | |
If ("$($NuGet.Version.Major).$($NuGet.Version.Minor)" -gt '2.7') { | |
If ($Get.Count -eq 0) { | |
$ProcessSplat1 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PowerShellGet -Force""' | |
Verb = 'RunAs' | |
} | |
Start-Process @ProcessSplat1 | |
Import-Module -Name PowerShellGet | |
} | |
} Else { | |
Try { | |
$ProcessSplat2 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
$ProcessSplat3 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PowerShellGet -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
Start-Process @ProcessSplat2 | |
Start-Process @ProcessSplat3 | |
} Catch { | |
$msg = 'Define PowerShell to use TLS1.2 in this session, needed since 1st April 2020 (https://devblogs.microsoft.com/powershell/powershell-gallery-tls-support/)' | |
Write-Output -InputObject $msg | |
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 | |
$ProcessSplat4 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
Start-Process @ProcessSplat4 | |
$ProcessSplat5 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PowerShellGet -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
Start-Process @ProcessSplat5 | |
$ProcessSplat6 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PSWindowsUpdate -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
Start-Process @ProcessSplat6 | |
} | |
} | |
} Else { | |
Import-Module -Name PSWindowsUpdate -Force | |
} | |
#endregion prereq | |
If ($norestart){ | |
$ProcessSplat7 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Get-WUInstall -AcceptAll -MicrosoftUpdate -Install -Verbose""' | |
Verb = 'RunAs' | |
} | |
Start-Process @ProcessSplat7 | |
} Else { | |
$ProcessSplat8 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Get-WUInstall -AutoReboot -AcceptAll -MicrosoftUpdate -Install -RecurseCycle 10 -Verbose""' | |
Verb = 'RunAs' | |
} | |
Start-Process @ProcessSplat8 | |
} | |
} | |
Function Install-WinUpdates { | |
<# | |
.SYNOPSIS | |
Use PSWindowsUpdate Module to perform updates. | |
.DESCRIPTION | |
Fetch and use PSWindowsUpdate module to fetch all updates to be current. | |
.PARAMETER norestart | |
Don't restart. | |
.EXAMPLE | |
Install-Winupdates -norestart | |
Installs as many updates as possible until restart required. | |
.INPUTS | |
None | |
.OUTPUTS | |
None | |
#> | |
[CmdletBinding()] | |
Param( | |
[Switch]$norestart | |
) | |
#region prereq | |
$Module = Get-Module -Name PSWindowsUpdate -ListAvailable | |
If ($Module.Count -eq 0) { | |
$Nuget = Get-PackageProvider -Name NuGet -ListAvailable | Select-Object -First 1 | |
$Get = Get-Module -Name PowerShellGet -ListAvailable | |
If ("$($NuGet.Version.Major).$($NuGet.Version.Minor)" -gt '2.7') { | |
If ($Get.Count -eq 0) { | |
$ProcessSplat = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PowerShellGet -Force""' | |
Verb = 'RunAs' | |
} | |
Start-Process @ProcessSplat | |
Import-Module -Name PowerShellGet | |
} | |
} Else { | |
Try { | |
$ProcessSplat1 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
$ProcessSplat2 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PowerShellGet -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
Start-Process @ProcessSplat1 | |
Start-Process @ProcessSplat2 | |
} Catch { | |
$msg = 'Define PowerShell to use TLS1.2 in this session, needed since 1st April 2020 (https://devblogs.microsoft.com/powershell/powershell-gallery-tls-support/)' | |
Write-Output -InputObject $msg | |
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 | |
$ProcessSplat3 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
$ProcessSplat4 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PowerShellGet -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
$ProcessSplat5 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Install-Module -Name PSWindowsUpdate -Force""' | |
Verb = 'RunAs' | |
Wait = $true | |
} | |
Start-Process @ProcessSplat3 | |
Start-Process @ProcessSplat4 | |
Start-Process @ProcessSplat5 | |
} | |
} | |
} Else { | |
Import-Module -Name PSWindowsUpdate -Force | |
} | |
#endregion prereq | |
If ($norestart) { | |
$ProcessSplat6 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Get-WUInstall -AcceptAll -MicrosoftUpdate -Install -Verbose""' | |
Verb = 'RunAs' | |
} | |
Start-Process @ProcessSplat6 | |
} Else { | |
$ProcessSplat7 = @{ | |
FilePath = 'PowerShell.exe' | |
ArgumentList = '-NoProfile -ExecutionPolicy Bypass -Command ""Get-WUInstall -AutoReboot -AcceptAll -MicrosoftUpdate -Install -RecurseCycle 10 -Verbose""' | |
Verb = 'RunAs' | |
} | |
Start-Process @ProcessSplat7 | |
} | |
} | |
Function Invoke-ElevatedCommand { | |
<# | |
.DESCRIPTION | |
Invokes the provided script block in a new elevated (Administrator) powershell process, | |
while retaining access to the pipeline (pipe in and out). Please note, "Write-Host" output | |
will be LOST - only the object pipeline and errors are handled. In general, prefer | |
"Write-Output" over "Write-Host" unless UI output is the only possible use of the information. | |
Also see Community Extensions "Invoke-Elevated"/"su" | |
.EXAMPLE | |
Invoke-ElevatedCommand {"Hello World"} | |
.EXAMPLE | |
"test" | Invoke-ElevatedCommand {$input | Out-File -filepath c:\test.txt} | |
.EXAMPLE | |
Invoke-ElevatedCommand {$one = 1; $zero = 0; $throwanerror = $one / $zero} | |
.PARAMETER Scriptblock | |
A script block to be executed with elevated priviledges. | |
.PARAMETER InputObject | |
An optional object (of any type) to be passed in to the scriptblock (available as $input) | |
.PARAMETER EnableProfile | |
A switch that enables powershell profile loading for the elevated command/block | |
.PARAMETER DisplayWindow | |
A switch that enables the display of the spawned process (for potential interaction) | |
.SYNOPSIS | |
Invoke a powershell script block as Administrator | |
.INPUTS | |
ScriptBlock | |
.OUTPUTS | |
Various | |
#> | |
[CmdletBinding()] | |
[Alias('sudo')] | |
Param ( | |
## The script block to invoke elevated. NOTE: to access the InputObject/pipeline data from the script block, use "$input"! | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Script block to invoke elevated' | |
)] | |
[ScriptBlock]$Scriptblock, | |
## Any input to give the elevated process | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Input Object', | |
ValueFromPipeline = $true | |
)] | |
$InputObject, | |
## Switch to enable the user profile | |
[Switch]$EnableProfile, | |
## Switch to display the spawned window (as interactive) | |
[Switch]$DisplayWindow | |
) | |
Begin { | |
$inputItems = New-Object -TypeName System.Collections.ArrayList | |
} | |
Process { | |
$null = $inputItems.Add($InputObject) | |
} | |
End { | |
## Create some temporary files for streaming input and output | |
$outputFile = [IO.Path]::GetTempFileName() | |
$inputFile = [IO.Path]::GetTempFileName() | |
$errorFile = [IO.Path]::GetTempFileName() | |
## Stream the input into the input file | |
$inputItems.ToArray() | Export-CliXml -Depth 1 -Path $inputFile | |
## Start creating the command line for the elevated PowerShell session | |
$commandLine = '' | |
If (-not $EnableProfile) { | |
$commandLine += '-NoProfile ' | |
} | |
If (-not $DisplayWindow) { | |
$commandLine += '-Noninteractive ' | |
$processWindowStyle = 'Hidden' | |
} Else { | |
$processWindowStyle = 'Normal' | |
} | |
## Convert the command into an encoded command for PowerShell | |
$commandString = "Set-Location '$($pwd.Path)'; " + | |
"`$output = Import-CliXml '$inputFile' | " + | |
'& {' + | |
$scriptblock.ToString() + | |
'} 2>&1 ; ' + | |
"Out-File -filepath '$errorFile' -inputobject `$error;" + | |
"Export-CliXml -Depth 1 -In `$output '$outputFile';" | |
$commandBytes = [Text.Encoding]::Unicode.GetBytes($commandString) | |
$encodedCommand = [Convert]::ToBase64String($commandBytes) | |
$commandLine += "-EncodedCommand $encodedCommand" | |
## Start the new PowerShell process | |
$process = Start-Process -FilePath (Get-Command -Name powershell).Definition -ArgumentList $commandLine -Passthru -Verb RunAs -WindowStyle $processWindowStyle | |
$process.WaitForExit() | |
$errorMessage = $(Get-Content -Path $errorFile | Out-String) | |
If ($errorMessage) { | |
Write-Error -Message $errorMessage | |
} Else { | |
If ((Get-Item -Path $outputFile).Length -gt 0) { | |
Import-CliXml -Path $outputFile | |
} | |
} | |
## Clean up | |
Remove-Item -Path $outputFile | |
Remove-Item -Path $inputFile | |
Remove-Item -Path $errorFile | |
} | |
} | |
Function New-RDPShortcut { | |
<# | |
.SYNOPSIS | |
Create an RDP Shortcut on desktop. | |
.DESCRIPTION | |
Create a generic RDP shortcut to desktop. | |
.PARAMETER CName | |
Computer Name. | |
.PARAMETER fn | |
Calculate Full Name. | |
.PARAMETER incdom | |
Include domain/username. | |
.EXAMPLE | |
New-RDPShortcut -CName server -fn -incdom | |
Creates a new RDP Shortcut on your desktop to server - attempt to resolve server FQDN, and include domain/username. | |
.INPUTS | |
String | |
.OUTPUTS | |
File | |
#> | |
# Generate RDP shortcuts from CSV file - Fills out Computer, Username, and Server Name fields | |
[CmdletBinding()] | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Server Name' | |
)] | |
[ValidateNotNullOrEmpty()] | |
[String]$CName, | |
[Switch]$fn, | |
[Switch]$incdom | |
) | |
Add-Type -AssemblyName System.Windows.Forms | |
$isIP = [ipaddress]::TryParse("$($CName)",[ref][ipaddress]::Loopback) | |
If ($isIP) { | |
If (Get-IPValid -testip $CName) { | |
Continue | |
} Else { | |
Break | |
} | |
} | |
#$Orientation = [System.Windows.Forms.SystemInformation]::ScreenOrientation | |
### Regular: Angle0 - Rotated: Angle90;$Res=[System.Windows.Forms.SystemInformation]::PrimaryMonitorSize | |
$Uname = $env:USERNAME | |
$Domain = $env:USERDOMAIN | |
$DesktopPath = [Environment]::GetFolderPath('Desktop') | |
#https://stackoverflow.com/questions/7967699/get-screen-resolution-using-wmi-powershell-in-windows-7 | |
$MonitorStats = @() | |
$screen_cnt = [Windows.Forms.Screen]::AllScreens.Count | |
$col_screens = [windows.forms.screen]::AllScreens | |
If ($screen_cnt -gt 1) { | |
$PrimaryMonitor = $col_screens | Where-Object {$_.Primary -eq $true} | |
} Else { | |
$PrimaryMonitor = $col_screens | |
} | |
$PrimaryMonitor | ForEach-Object { | |
If ("$($_.Bounds.Width)" -gt "$($_.Bounds.Height)") { | |
$monitor_orientation = 'Landscape' | |
} Else { | |
$monitor_orientation = 'Portrait' | |
} | |
$MonitorStats += [pscustomobject]@{ | |
Orientation = $monitor_orientation | |
Bounds = $_.Bounds | |
Primary = $_.Primary | |
Name = $_.DeviceName | |
Width = $_.Bounds.Width | |
Height = $_.Bounds.Height | |
Resolution = "$($_.Bounds.Width) x $($_.Bounds.Height)" | |
BitsPerPixel = $_.BitsPerPixel | |
WorkingArea = $_.WorkingArea | |
} | |
} | |
$W = $MonitorStats.Width | |
$H = $MonitorStats.Height | |
$B = $MonitorStats.BitsPerPixel | |
### Include domain/username | |
If ($incdom.IsPresent) {$U = "$Domain\$UName"} Else {$U = $UName} | |
If ($isIP) { | |
$F = $CName | |
} Else { | |
### Resolve Full Name | |
If ($fn.IsPresent) { | |
Try { | |
$F = (Resolve-DNSName -Name $CName -Type PTR -ErrorAction Stop).NameHost | |
} Catch { | |
Write-Warning -Message ('No DNS Record for {0}' -f $CName) | |
$F = $CName | |
} | |
} Else { | |
$F = "$($CName.toUpper())" | |
} | |
} | |
$RDP = "screen mode id:i:2 | |
use multimon:i:0 | |
desktopwidth:i:$W | |
desktopheight:i:$H | |
session bpp:i:$B | |
winposstr:s:0,1,0,12,$W,$H | |
compression:i:1 | |
keyboardhook:i:2 | |
audiocapturemode:i:0 | |
videoplaybackmode:i:1 | |
connection type:i:7 | |
networkautodetect:i:1 | |
bandwidthautodetect:i:1 | |
displayconnectionbar:i:1 | |
username:s:$U | |
enableworkspacereconnect:i:0 | |
disable wallpaper:i:0 | |
allow font smoothing:i:0 | |
allow desktop composition:i:0 | |
disable full window drag:i:1 | |
disable menu anims:i:1 | |
disable themes:i:0 | |
disable cursor setting:i:0 | |
bitmapcachepersistenable:i:1 | |
full address:s:$F | |
audiomode:i:0 | |
redirectprinters:i:1 | |
redirectcomports:i:0 | |
redirectsmartcards:i:1 | |
redirectclipboard:i:1 | |
redirectposdevices:i:0 | |
autoreconnection enabled:i:1 | |
authentication level:i:2 | |
prompt for credentials:i:0 | |
negotiate security layer:i:1 | |
remoteapplicationmode:i:0 | |
alternate shell:s: | |
shell working directory:s: | |
gatewayhostname:s: | |
gatewayusagemethod:i:4 | |
gatewaycredentialssource:i:4 | |
gatewayprofileusagemethod:i:0 | |
promptcredentialonce:i:1 | |
gatewaybrokeringtype:i:0 | |
use redirection server name:i:0 | |
rdgiskdcproxy:i:0 | |
kdcproxyname:s:" | |
$RDP | Out-File -FilePath "$DesktopPath\$F.rdp" | |
} | |
Function Start-ElevatedPowerShell { | |
<# | |
.SYNOPSIS | |
SU up to Administrator. | |
.DESCRIPTION | |
Spawn new Administrator window. | |
.EXAMPLE | |
Start-ElevatedPowerShell | |
.INPUTS | |
None | |
.OUTPUTS | |
New Shell | |
#> | |
[cmdletbinding()] | |
[Alias('SU')] | |
Param ( | |
[ValidateNotNull()] | |
[System.Management.Automation.Credential()] | |
[PSCredential]$Credential = $Credential | |
) | |
#If ($Credential -eq [pscredential]::Empty) {Register-SACreds} Else {[pscredential]$Credential = $Credential} | |
Start-Process -FilePath PowerShell -Credential $Credential -ArgumentList '-Command &{Start-Process PowerShell -Verb Runas}' | |
} | |
Function Step-MSTSC { | |
<# | |
.SYNOPSIS | |
RDP to machine. | |
.DESCRIPTION | |
Starts MSTSC to specified PC. | |
.PARAMETER RDPServer | |
Nme or IP of server/pc to connect to | |
.EXAMPLE | |
Step-MSTSC -RDPServer testcomputer | |
.INPUTS | |
None | |
.OUTPUTS | |
None | |
#> | |
[CmdletBinding()] | |
[Alias('RDP')] | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'RDP Destination', | |
Position = 0 | |
)] | |
[String]$RDPServer | |
) | |
Start-Process -FilePath "$env:windir\system32\mstsc.exe" -ArgumentList "/v:$RDPServer" | |
} | |
Function Update-AllPowerShellModule { | |
<# | |
.SYNOPSIS | |
This script will update all locally installed PowerShell modules to the newest ones if can find online. | |
.DESCRIPTION | |
The script will search the usual PowerShell module profile paths for all modules and update them to the | |
newest versions available online. | |
Updating modules depends on 'PackageManagement' and 'PowerShellGet', which are updated to the newest | |
versions before upgrading any modules. | |
By default, it searches for beta, nightly, preview versions, etc., but you can exclude those with | |
the "-NoPreviews" switch. | |
The script presents you with a list of all modules it finds and shows you if a newer version is detected | |
and when that new version was published. | |
PowerShell comes with a similar "Update-Module" command, but that does not try to update 'PackageManagement' | |
and 'PowerShellGet'. | |
It shows no data while operating, so you are left with an empty screen unless you use the "-verbose" switch, | |
which displays too much information. | |
You can use the "-AllowPrerelease", but only with a named module. This script will install Prerelease | |
versions of all modules if they exist. | |
.PARAMETER NoPreviews | |
If you want to avoid versions that include 'beta', 'preview', 'nightly', etc., and only upgrade to fully released | |
versions of the modules, use this switch. | |
.EXAMPLE | |
Update-AllPSModule | |
This will update all locally installed modules . | |
.EXAMPLE | |
Update-AllPSModule -NoPreviews | |
This will update all locally installed modules but not to versions that include 'beta', 'preview', 'nightly', etc. | |
.INPUTS | |
None | |
.OUTPUTS | |
None | |
#> | |
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'None')] | |
Param ([Switch]$NoPreviews) | |
Begin { | |
$NoPreviews = $true | |
#region Prereq's | |
If ($PSVersionTable.psversion -lt [version]'5.0.0') { | |
$msg = ('This script only works with PowerShell 5.0 or newer. You are running {0}' -f $PSVersionTable.PSVersion) | |
Write-Warning -Message $msg | |
break | |
} | |
If ($ExecutionContext.SessionState.LanguageMode -eq 'ConstrainedLanguage') { | |
$msg = 'Constrained Language mode is enabled, so the script cannot continue.' | |
Write-Warning -Message $msg | |
break | |
} | |
$CurrentUser = [Security.Principal.WindowsIdentity]::GetCurrent() | |
If (-not (New-Object -TypeName 'Security.Principal.WindowsPrincipal' -ArgumentList $CurrentUser).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) { | |
Write-Warning -Message 'The script is not being run as administrator so cannot continue.' | |
Break | |
} | |
#endregion Prereq's | |
$StartTime = Get-Date | |
#region PSRepository | |
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | |
$NewSessionRequired = $false | |
Try { | |
$RegisteredRepositories = Get-PSRepository -ErrorAction 'Stop' -WarningAction 'Stop' | |
} Catch { | |
$msg = "Unable to query 'PSGallery' online. The script cannot continue - check your proxy/firewall settings." | |
Write-Warning -Message $msg | |
break | |
} | |
If ($RegisteredRepositories -notmatch 'PSGallery') { | |
Try { | |
Set-PSRepository -Name 'PSGallery' -InstallationPolicy 'Trusted' -ErrorAction 'Stop' | |
} Catch { | |
Write-Warning -Message 'Unable to Set the PSRepository' | |
break | |
} | |
} | |
#endregion PSRepository | |
#region PackageManagement Module | |
WH -t "Checking which version of the 'PackageManagement' module is installed locally" -n | |
$PackageManagement = (Get-Module -ListAvailable -Name 'PackageManagement' | Sort-Object -Property Version -Descending)[0] | |
WH -t (" - found '{0}'." -f ($PackageManagement.version).tostring()) | |
If ([version]$PackageManagement.Version -lt [version]'1.4.7') { | |
"An updated version is required. Attempting to install 'Nuget'" | |
Try { | |
$NugetInstall = Install-PackageProvider -Name 'Nuget' -Force -ErrorAction 'Stop' | |
WH -t ("Successfully installed 'Nuget' version '{0}'" -f $NugetInstall.Version) | |
} Catch { | |
$msg = 'No match was found for the specified search criteria for the provider ' | |
If ($error[0].exception.message -match $msg) { | |
Write-Warning -Message 'Unable to find packages online. Check proxy settings.' | |
} Else { | |
WH -t -Object 'Unknown error.' | |
} | |
break | |
} | |
WH -t "Searching for a newer version of 'PackageManagement'." | |
Try { | |
$OnlinePackageManagement = Find-Module -Name 'PackageManagement' -Repository 'PSGallery' -ErrorAction 'Stop' | |
} Catch { | |
WH -t "Unable to find 'PackageManagement' online. Does this machine have an internet connection?" | |
break | |
} | |
Try { | |
$OnlinePackageManagement | Install-Module -Force -SkipPublisherCheck -ErrorAction 'Stop' | |
WH -t ("Successfully installed 'PackageManagement' version '{0}'" -f $OnlinePackageManagement.Version) | |
} Catch { | |
WH -t "Failed to install 'PackageManagement'." | |
break | |
} | |
WH -t "You need to close PowerShell and re-open it to use the new 'PackageManagement' module." | |
$NewSessionRequired = $true | |
} | |
#endregion PackageManagement Module | |
#region PowerShellGet Module | |
WH -t "Checking which version of the 'PowerShellGet' module is installed locally" -n | |
$PowershellGet = (Get-Module -ListAvailable -Name 'PowerShellGet' | Sort-Object -Property Version -Descending)[0] | |
WH -t (" - found '{0}'." -f ($PowershellGet.version).tostring()) | |
If ([version]$PowershellGet.Version -lt [version]'1.6.0') { | |
$OnlinePSGet = Find-Module -Name 'PowerShellGet' -Repository 'PSGallery' | |
WH -t ("Version '{0}' found online, will attempt to update." -f $OnlinePSGet.version) | |
Try { | |
$OnlinePSGet | Install-Module -Force -SkipPublisherCheck -ErrorAction 'Stop' | |
$msg = ("Successfully installed 'PowerShellGet' version '{0}'. Close PowerShell and re-open it to use the new module." -f $OnlinePSGet.Version) | |
WH -t $msg | |
$NewSessionRequired = $true | |
} Catch { | |
$msg = "Unable to install to 'C:\Program Files\WindowsPowerShell\Modules' so will try the Current User module path instead." | |
WH -t $msg | |
Try { | |
$OnlinePSGet | Install-Module -Force -SkipPublisherCheck -Scope CurrentUser -ErrorAction 'Stop' | |
$msg = ("Successfully installed 'PowerShellGet' version '{0}'. Close PowerShell and re-open it to use the new module." -f $OnlinePSGet.Version) | |
WH -t $msg | |
$NewSessionRequired = $true | |
} Catch { | |
$msg = 'Failed to install the latest version of PowerShellGet. This will mean you may not be able to install preview, or beta versions of the modules.' | |
Write-Warning -Message $msg | |
break | |
} | |
} | |
} | |
#endregion PowerShellGet Module | |
} | |
Process { | |
If ($NewSessionRequired) {break} | |
$Failed = @() | |
WH -t 'Searching for all locally installed modules' -n | |
$ignoredModules = 'PackageManagement|PowerShellGet|Az\.|AzureRM\.|Azure\.|Microsoft.Graph.|PSReadline|VMware.PowerCLI.|VMware.Sdk.' | |
$InstalledModules = Get-InstalledModule | Where-Object -FilterScript {($_.Name -notmatch $ignoredModules)} | Sort-Object -Property 'Name' | |
If ($InstalledModules) { | |
$SuccessfulUpdates = 0 | |
Write-Host -Object (' - {0} modules found.' -f ($InstalledModules | Measure-Object).count) | |
Write-Host -Object 'Checking for newer versions online and trying to update them.' | |
$MaxNameWidth = (($InstalledModules).'Name' | Sort-Object -Property 'Length' -Descending | Select-Object -First 1).length + 3 | |
$MaxVersionWidth = (($InstalledModules).'Version' | Sort-Object -Property 'Length' -Descending | Select-Object -First 1).length + 3 | |
ForEach ($InstalledModule in $InstalledModules) { | |
WH -t ("{0,-$MaxNameWidth}" -f $InstalledModule.Name) -n | |
Try { | |
$Module = Get-InstalledModule -Name $InstalledModule.Name -AllVersions | Sort-Object -Property {[version](($_.Version -split '-')[0])} -Descending | Select-Object -First 1 | |
$LatestAvailable = Find-Module -Name $InstalledModule.Name -ErrorAction 'Stop' | |
} Catch { | |
$Failed += $InstalledModule | |
continue | |
} | |
WH -t ("{0,-$MaxVersionWidth}" -f $Module.Version) -n | |
If ( | |
([version](($Module.Version -replace '[a-z]*', '').Replace('-', '.') -replace '\.$', '')) -ge | |
([version](($LatestAvailable.Version -replace '[a-z]*', '').Replace('-', '.') -replace '\.$', '')) | |
) { | |
WH -t $([char]0x2714) -f Gr | |
} Else { | |
$AllUsersFailed = $false | |
$Gap = (20 - (($LatestAvailable.version).length)) | |
WH -t ("Online version found: '{0}' - attempting to update. {1,$Gap}" -f "$($LatestAvailable.version)' - Published '$(Get-Date -Date ($LatestAvailable.PublishedDate) -Format 'yyyy-MM-dd')", ' ') -f Ye -n | |
Try { | |
Update-Module -AcceptLicense -Force -Name $Module.Name -Scope 'AllUsers' -ErrorAction 'Stop' | |
WH -t $([char]0x2714) -f Gr | |
$SuccessfulUpdates++ | |
} Catch { | |
$AllUsersFailed = $true | |
} | |
If ($AllUsersFailed) { | |
Try { | |
Update-Module -AcceptLicense -AllowPrerelease -RequiredVersion $LatestAvailable.version -Force -Name $Module.Name -Scope 'CurrentUser' -ErrorAction 'Stop' | |
WH -t $([char]0x2714) -f G -n | |
WH -t " ('Current User' scope only)" -f Ye | |
$SuccessfulUpdates++ | |
} Catch { | |
WH -t ([char]0x2718) -f Re -n | |
WH -t (' Update not possible, will uninstall and try a new install. ') -f Ye -n | |
Try { | |
Uninstall-Module -Name $Module.Name -AllowPrerelease -AllVersions -Force -ErrorAction 'Stop' | |
Try { | |
Install-Module -Name $Module.Name -RequiredVersion $LatestAvailable.version -AcceptLicense -AllowClobber -AllowPrerelease -Force -Scope 'AllUsers' -SkipPublisherCheck -ErrorAction 'Stop' | |
WH -t $([char]0x2714) -f Gr | |
$SuccessfulUpdates++ | |
} Catch { | |
Try { | |
Install-Module -Name $Module.Name -RequiredVersion $LatestAvailable.version -AcceptLicense -AllowClobber -AllowPrerelease -Force -Scope 'CurrentUser' -SkipPublisherCheck -ErrorAction 'Stop' | |
WH -t $([char]0x2714) -f Gr -n | |
WH -t " ('Current User' scope only)" -f Ye | |
$SuccessfulUpdates++ | |
} Catch { | |
WH -t ([char]0x2718) -f Re | |
} | |
} | |
} Catch { | |
WH -t ([char]0x2718) -f Re | |
} | |
} | |
} | |
} | |
} | |
} Else { | |
'. None found.' | |
} | |
$OnlinePSGet = Find-Module -Name 'PowerShellGet' -AllowPrerelease -Repository 'PSGallery' -ErrorAction 'Stop' | |
If (([version](($PowershellGet.Version -split ('-'))[0])) -lt ([version](($OnlinePSGet.Version -split ('-'))[0]))) { | |
WH -t "A newer version of 'PowerShellGet' is available online, will attempt to update." | |
Try { | |
$OnlinePSGet | Install-Module -Force -SkipPublisherCheck -ErrorAction 'Stop' | |
$msg = ("Successfully installed 'PowerShellGet' version '{0}'. Close PowerShell and re-open it to use the new module." -f $OnlinePSGet.Version) | |
WH -t $msg | |
$NewSessionRequired = $true | |
} Catch { | |
$msg = "Unable to install to 'C:\Program Files\WindowsPowerShell\Modules' so will try the Current User module path instead." | |
WH -t $msg | |
Try { | |
$OnlinePSGet | Install-Module -Force -SkipPublisherCheck -Scope CurrentUser -ErrorAction 'Stop' | |
$msg = ("Successfully installed 'PowerShellGet' version '{0}'. Close PowerShell and re-open it to use the new module." -f $OnlinePSGet.Version) | |
WH -t | |
$NewSessionRequired = $true | |
} Catch { | |
$msg = 'Failed to install the latest version of PowerShellGet. This will mean you may not be able to install preview, or beta versions of the modules.' | |
Write-Warning -Message $msg | |
break | |
} | |
} | |
} | |
} | |
End { | |
If ($Failed) { | |
'Unable to find these modules:' | |
$Failed | |
} | |
$EndTime = Get-Date | |
$TimeTaken = '' | |
$TakenSpan = New-TimeSpan -Start $StartTime -End $EndTime | |
If ($TakenSpan.Hours) { | |
$TimeTaken += ('{0} hours, {1} minutes, ' -f $TakenSpan.Hours, $TakenSpan.Minutes) | |
} Elseif ($TakenSpan.Minutes) { | |
$TimeTaken += ('{0} minutes, ' -f $TakenSpan.Minutes) | |
} | |
$TimeTaken += ('{0} seconds' -f $TakenSpan.Seconds) | |
If ($SuccessfulUpdates) { | |
WH -t ('Successfully updated {0} module(s) in {1}.' -f ($SuccessfulUpdates), ($TimeTaken)) | |
} Else { | |
WH -t -Object ('The script took {0} to complete and no updates were required.' -f $TimeTaken) | |
} | |
} | |
} | |
Function Step-UpdateModules { | |
<# | |
.SYNOPSIS | |
Update all installed modules without exception. | |
.DESCRIPTION | |
Update all installed modules without exception. | |
.EXAMPLE | |
Step-UpdateModules | |
Updates all modules including sub-modules | |
.INPUTS | |
None | |
.OUTPUTS | |
None | |
#> | |
[CmdletBinding()] | |
[Alias('UpdateModules')] | |
Param () | |
If (Test-Administrator){ | |
Update-AllPowerShellModules | |
} Else { | |
Invoke-ElevatedCommand -EnableProfile -DisplayWindow -Scriptblock {Update-AllPowerShellModules} | |
} | |
} | |
Function Connect-Office365Services { | |
<# | |
.SYNOPSIS | |
Connect-Office365Services | |
.DESCRIPTION | |
The functions are listed below. Note that functions may call eachother, for example to | |
connect to Exchange Online the Office 365 Credentials the user is prompted to enter these credentials. | |
Also, the credentials are persistent in the current session, there is no need to re-enter credentials | |
when connecting to Exchange Online Protection for example. Should different credentials be required, | |
call Get-Office365Credentials or Get-OnPremisesCredentials again. | |
Helper Functions: | |
================= | |
- Connect-AzureActiveDirectory Connects to Azure Active Directory | |
- Connect-AzureRMS Connects to Azure Rights Management | |
- Connect-ExchangeOnline Connects to Exchange Online (Graph module) | |
- Connect-SkypeOnline Connects to Skype for Business Online | |
- Connect-EOP Connects to Exchange Online Protection | |
- Connect-AIP Connects to Azure Information Protection | |
- Connect-PowerApps Connects to PowerApps | |
- Connect-ComplianceCenter Connects to Compliance Center | |
- Connect-SharePointOnline Connects to SharePoint Online | |
- Connect-MSTeams Connects to Microsoft Teams | |
- Get-Office365Credentials Gets Office 365 credentials | |
- Connect-ExchangeOnPremises Connects to Exchange On-Premises | |
- Get-OnPremisesCredentials Gets On-Premises credentials | |
- Get-ExchangeOnPremisesFQDN Gets FQDN for Exchange On-Premises | |
- Get-Office365Tenant Gets Office 365 tenant name | |
- Set-Office365Environment Configures Uri's and region to use | |
- Update-Office365Modules Updates supported Office 365 modules | |
- Report-Office365Modules Report on known vs online module versions | |
Functions to connect to other services provided by the module, e.g. Connect-MSGraph or Connect-MSTeams. | |
To register the PowerShell Test Gallery and install modules from there, use: | |
Register-PSRepository -Name PSGalleryInt -SourceLocation https://www.poshtestgallery.com/ -InstallationPolicy Trusted | |
Install-Module -Name MicrosoftTeams -Repository PSGalleryInt -Force -Scope AllUsers | |
To load the helper functions from your PowerShell profile, put Connect-Office365Services.ps1 in the same location | |
as your $profile file, and edit $profile as follows: | |
& (Join-Path $PSScriptRoot "Connect-Office365Services.ps1") | |
#> | |
##Requires -Version 3.0 | |
Add-Type -AssemblyName WindowsBase | |
Add-Type -AssemblyName PresentationCore | |
$local:ScriptVersion = '3.11' | |
Function script:Set-WindowTitle { | |
If ($host.ui.RawUI.WindowTitle -and $script:myOffice365Services['TenantID']) { | |
$local:PromptPrefix = '' | |
$ThisPrincipal = New-Object -TypeName System.Security.Principal.WindowsPrincipal -ArgumentList ([Security.Principal.WindowsIdentity]::GetCurrent()) | |
If ($ThisPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { | |
$local:PromptPrefix = 'Administrator:' | |
} | |
$local:Title = '{0}{1} connected to Tenant ID {2}' -f $local:PromptPrefix, $myOffice365Services['Office365Credentials'].UserName, $script:myOffice365Services['TenantID'] | |
$host.ui.RawUI.WindowTitle = $local:Title | |
} | |
} | |
Function script:Get-TenantIDfromMail { | |
[CmdletBinding()] | |
Param ( | |
[Parameter(Mandatory = $True, HelpMessage = 'Mail Address')] | |
[string]$mail | |
) | |
$domainPart= ($mail -split '@')[1] | |
If ($domainPart) { | |
$res = (Invoke-RestMethod -Uri ('https://login.microsoftonline.com/{0}/v2.0/.well-known/openid-configuration' -f $domainPart)).jwks_uri.split('/')[3] | |
If (!($res)) { | |
Write-Warning -Message 'Could not determine Tenant ID using e-mail address' | |
$res = $null | |
} | |
} Else { | |
Write-Warning -Message 'E-mail address invalid, cannot determine Tenant ID' | |
$res = $null | |
} | |
return $res | |
} | |
Function script:Get-TenantID { | |
$script:myOffice365Services['TenantID'] = Get-TenantIDfromMail $myOffice365Services['Office365Credentials'].UserName | |
If ($script:myOffice365Services['TenantID']) { | |
Write-Host ('TenantID: {0}' -f $global:myOffice365Services['TenantID']) | |
} | |
} | |
Function script:Get-Office365ModuleInfo { | |
# Menu | Submenu | Menu ScriptBlock | ModuleName | Description | (Repo)Link | |
@( | |
'Connect|Exchange Online|Connect-ExchangeOnline|ExchangeOnlineManagement|Exchange Online Management|https://www.powershellgallery.com/packages/ExchangeOnlineManagement', | |
'Connect|Exchange Online Protection|Connect-EOP', | |
'Connect|Exchange Compliance Center|Connect-ComplianceCenter', | |
'Connect|MSOnline|Connect-MSOnline|MSOnline|MSOnline|https://www.powershellgallery.com/packages/MSOnline', | |
'Connect|Azure AD (v2)|Connect-AzureAD|AzureAD|Azure Active Directory (v2)|https://www.powershellgallery.com/packages/azuread', | |
'Connect|Azure AD (v2 Preview)|Connect-AzureAD|AzureADPreview|Azure Active Directory (v2 Preview)|https://www.powershellgallery.com/packages/AzureADPreview', | |
'Connect|Azure Information Protection|Connect-AIP|AIPService|Azure Information Protection|https://www.powershellgallery.com/packages/AIPService', | |
'Connect|SharePoint Online|Connect-SharePointOnline|Microsoft.Online.Sharepoint.PowerShell|SharePoint Online|https://www.powershellgallery.com/packages/Microsoft.Online.SharePoint.PowerShell', | |
'Connect|Microsoft Teams|Connect-MSTeams|MicrosoftTeams|Microsoft Teams|https://www.powershellgallery.com/packages/MicrosoftTeams', | |
'Connect|Microsoft Commerce|Connect-MSCommerce|MSCommerce|Microsoft Commerce|https://www.powershellgallery.com/packages/MSCommerce', | |
'Connect|PnP.PowerShell|Connect-PnPOnline|PnP.PowerShell|PnP.PowerShell|https://www.powershellgallery.com/packages/PnP.PowerShell', | |
'Connect|PowerApps-Admin-PowerShell|Connect-PowerApps|Microsoft.PowerApps.Administration.PowerShell|PowerApps-Admin-PowerShell|https://www.powershellgallery.com/packages/Microsoft.PowerApps.Administration.PowerShell', | |
'Connect|PowerApps-PowerShell|Connect-PowerApps|Microsoft.PowerApps.PowerShell|PowerApps-PowerShell|https://www.powershellgallery.com/packages/Microsoft.PowerApps.PowerShell', | |
'Connect|MSGraph-Intune|Connect-MSGraph|Microsoft.Graph.Intune|MSGraph-Intune|https://www.powershellgallery.com/packages/Microsoft.Graph.Intune', | |
'Connect|Microsoft.Graph|Connect-MSGraph|Microsoft.Graph|Microsoft.Graph|https://www.powershellgallery.com/packages/Microsoft.Graph', | |
'Connect|MicrosoftPowerBIMgmt|Connect-PowerBIServiceAccount|MicrosoftPowerBIMgmt|MicrosoftPowerBIMgmt|https://www.powershellgallery.com/packages/MicrosoftPowerBIMgmt', | |
'Connect|Az|Connect-AzAccount|Az|Az|https://www.powershellgallery.com/packages/Az', | |
'Connect|Microsoft365DSC|New-M365DSCConnection|Microsoft365DSC|Microsoft365DSC|https://www.powershellgallery.com/packages/Microsoft36DSC', | |
'Connect|Whiteboard|Get-Whiteboard|WhiteboardAdmin|WhiteboardAdmin|https://www.powershellgallery.com/packages/WhiteboardAdmin', | |
'Connect|Microsoft Identity|Connect-MgGraph|MSIdentityTools|MSIdentityTools|https://www.powershellgallery.com/packages/MSIdentityTools', | |
'Settings|Office 365 Credentials|Get-Office365Credentials', | |
'Connect|Exchange On-Premises|Connect-ExchangeOnPremises', | |
'Settings|On-Premises Credentials|Get-OnPremisesCredentials', | |
'Settings|Exchange On-Premises FQDN|Get-ExchangeOnPremisesFQDN' | |
) | |
} | |
Function script:Set-Office365Environment { | |
[CmdletBinding()] | |
Param ( | |
[Parameter(Mandatory=$true,HelpMessage='Country')] | |
[ValidateSet('Germany', 'China', 'AzurePPE', 'USGovernment', 'Default')] | |
[string]$Environment | |
) | |
Switch ($Environment) { | |
'Germany' { | |
$script:myOffice365Services['ConnectionEndpointUri'] = 'https://outlook.office.de/PowerShell-LiveID' | |
$script:myOffice365Services['SCCConnectionEndpointUri'] = 'https://ps.compliance.protection.outlook.de/PowerShell-LiveId' | |
$script:myOffice365Services['EOPConnectionEndpointUri'] = 'https://ps.protection.protection.outlook.de/PowerShell-LiveId' | |
$script:myOffice365Services['AzureADAuthorizationEndpointUri'] = 'https://login.microsoftonline.de/common' | |
$script:myOffice365Services['SharePointRegion'] = 'Germany' | |
$script:myOffice365Services['AzureEnvironment'] = 'AzureGermanyCloud' | |
$script:myOffice365Services['TeamsEnvironment'] = '' | |
} | |
'China' { | |
$script:myOffice365Services['ConnectionEndpointUri'] = 'https://partner.outlook.cn/PowerShell-LiveID' | |
$script:myOffice365Services['SCCConnectionEndpointUri'] = 'https://ps.compliance.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['EOPConnectionEndpointUri'] = 'https://ps.protection.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['AzureADAuthorizationEndpointUri'] = 'https://login.chinacloudapi.cn/common' | |
$script:myOffice365Services['SharePointRegion'] = 'China' | |
$script:myOffice365Services['AzureEnvironment'] = 'AzureChinaCloud' | |
$script:myOffice365Services['TeamsEnvironment'] = '' | |
} | |
'AzurePPE' { | |
$script:myOffice365Services['ConnectionEndpointUri'] = '' | |
$script:myOffice365Services['SCCConnectionEndpointUri'] = 'https://ps.compliance.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['EOPConnectionEndpointUri'] = 'https://ps.protection.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['AzureADAuthorizationEndpointUri'] = '' | |
$script:myOffice365Services['SharePointRegion'] = '' | |
$script:myOffice365Services['AzureEnvironment'] = 'AzurePPE' | |
} | |
'USGovernment' { | |
$script:myOffice365Services['ConnectionEndpointUri'] = 'https://outlook.office365.com/PowerShell-LiveId' | |
$script:myOffice365Services['SCCConnectionEndpointUri'] = 'https://ps.compliance.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['EOPConnectionEndpointUri'] = 'https://ps.protection.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['AzureADAuthorizationEndpointUri'] = 'https://login.microsoftonline.com/common' | |
$script:myOffice365Services['SharePointRegion'] = 'ITAR' | |
$script:myOffice365Services['AzureEnvironment'] = 'AzureUSGovernment' | |
} | |
default { | |
$script:myOffice365Services['ConnectionEndpointUri'] = 'https://outlook.office365.com/PowerShell-LiveId' | |
$script:myOffice365Services['SCCConnectionEndpointUri'] = 'https://ps.compliance.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['EOPConnectionEndpointUri'] = 'https://ps.protection.protection.outlook.com/PowerShell-LiveId' | |
$script:myOffice365Services['AzureADAuthorizationEndpointUri'] = 'https://login.microsoftonline.com/common' | |
$script:myOffice365Services['SharePointRegion'] = 'Default' | |
$script:myOffice365Services['AzureEnvironment'] = 'AzureCloud' | |
} | |
} | |
} | |
Function script:Get-MultiFactorAuthenticationUsage { | |
$Answer = Read-host -Prompt 'Would you like to use Modern Authentication? (Y/n) ' | |
Switch ($Answer.ToUpper()) { | |
'N' {$rval = $false} | |
Default {$rval = $true} | |
} | |
return $rval | |
} | |
Function script:Get-ExchangeOnlineClickOnceVersion { | |
Try { | |
$ManifestURI = 'https://cmdletpswmodule.blob.core.windows.net/exopsmodule/Microsoft.Online.CSE.PSModule.Client.application' | |
$res = Invoke-WebRequest -Uri $ManifestURI -UseBasicParsing | |
$xml = [xml]($res.rawContent.substring( $res.rawContent.indexOf('<?xml'))) | |
$xml.assembly.assemblyIdentity.version | |
} Catch { | |
Write-Error -Message 'Cannot access or determine version of Microsoft.Online.CSE.PSModule.Client.application' | |
} | |
} | |
Function script:Connect-ExchangeOnline { | |
[CmdletBinding()] | |
Param( | |
[String]$ConnectionUri, | |
[String]$AzureADAuthorizationEndpointUri, | |
[Management.Automation.Remoting.PSSessionOption]$PSSessionOption, | |
[Switch]$BypassMailboxAnchoring = $false, | |
[String]$DelegatedOrganization, | |
[String]$Prefix, | |
[Switch]$ShowBanner = $False, | |
[String]$UserPrincipalName, | |
[System.Management.Automation.Credential()][pscredential]$Credential, | |
[Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, | |
[String]$CertificateFilePath, | |
[securestring]$CertificatePassword, | |
[String]$CertificateThumbprint, | |
[String]$AppId, | |
[String]$Organization, | |
[Switch]$EnableErrorReporting, | |
[String]$LogDirectoryPath, | |
$LogLevel, | |
[bool]$TrackPerformance, | |
[bool]$ShowProgress = $True, | |
[bool]$UseMultithreading, | |
[uint32]$PageSize, | |
[Switch]$Device, | |
[Switch]$InlineCredential, | |
[String[]]$CommandName = @('*'), | |
[String[]]$FormatTypeName = @('*'), | |
[Switch]$UseRPSSession = $false | |
) | |
If (!($PSBoundParameters.ContainsKey('ConnectionUri'))) { | |
$PSBoundParameters['ConnectionUri'] = $script:myOffice365Services['ConnectionEndpointUri'] | |
} | |
If (!($PSBoundParameters.ContainsKey('AzureADAuthorizationEndpointUri'))) { | |
$PSBoundParameters['AzureADAuthorizationEndpointUri'] = $script:myOffice365Services['AzureADAuthorizationEndpointUri'] | |
} | |
If (!($PSBoundParameters.ContainsKey('PSSessionOption'))) { | |
$PSBoundParameters['PSSessionOption'] = $script:myOffice365Services['SessionExchangeOptions'] | |
} | |
If ( | |
$PSBoundParameters.ContainsKey('UserPrincipalName') -or | |
$PSBoundParameters.ContainsKey('Certificate') -or | |
$PSBoundParameters.ContainsKey('CertificateFilePath') -or | |
$PSBoundParameters.ContainsKey('CertificateThumbprint') -or | |
$PSBoundParameters.ContainsKey('AppId') | |
) { | |
$script:myOffice365Services['Office365CredentialsMFA'] = $True | |
Write-Host ('Connecting to Exchange Online with specified Modern Authentication method ..') | |
} Else { | |
If ($PSBoundParameters.ContainsKey('Credential')) { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
If ($script:myOffice365Services['Office365CredentialsMFA']) { | |
Write-Host ('Connecting to Exchange Online with {0} using Modern Authentication ..' -f $script:myOffice365Services['Office365Credentials'].UserName) | |
$PSBoundParameters['UserPrincipalName'] = ($script:myOffice365Services['Office365Credentials']).UserName | |
} Else { | |
Write-Host ('Connecting to Exchange Online with {0} ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
$PSBoundParameters['Credential'] = $script:myOffice365Services['Office365Credentials'] | |
} | |
} Else { | |
Write-Host ('Connecting to Exchange Online with {0} using Legacy Authentication..' -f $PSBoundParameters['Credential'].UserName) | |
$script:myOffice365Services['Office365CredentialsMFA'] = $False | |
$script:myOffice365Services['Office365Credentials'] = $PSBoundParameters['Credential'] | |
} | |
} | |
$script:myOffice365Services['Session365'] = ExchangeOnlineManagement\Connect-ExchangeOnline @PSBoundParameters | |
If ($script:myOffice365Services['Session365']) { | |
Import-PSSession -Session $global:myOffice365Services['Session365'] -AllowClobber | |
} | |
} | |
Function script:Connect-ExchangeOnPremises { | |
If (!($script:myOffice365Services['OnPremisesCredentials'])) { | |
Get-OnPremisesCredentials | |
} | |
If (!($script:myOffice365Services['ExchangeOnPremisesFQDN'])) { | |
Get-ExchangeOnPremisesFQDN | |
} | |
Write-Host ('Connecting to Exchange On-Premises {0} using {1} ..' -f $script:myOffice365Services['ExchangeOnPremisesFQDN'], $script:myOffice365Services['OnPremisesCredentials'].username) | |
$script:myOffice365Services['SessionExchange'] = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$($script:myOffice365Services['ExchangeOnPremisesFQDN'])/PowerShell" -Credential $script:myOffice365Services['OnPremisesCredentials'] -Authentication Kerberos -AllowRedirection -SessionOption $script:myOffice365Services['SessionExchangeOptions'] | |
If ($script:myOffice365Services['SessionExchange']) { | |
Import-PSSession -Session $script:myOffice365Services['SessionExchange'] -AllowClobber | |
} | |
} | |
Function script:Get-ExchangeOnPremisesFQDN { | |
$script:myOffice365Services['ExchangeOnPremisesFQDN'] = Read-Host -Prompt 'Enter Exchange On-Premises endpoint, e.g. exchange1.contoso.com' | |
} | |
Function script:Connect-ComplianceCenter { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
If ($script:myOffice365Services['Office365CredentialsMFA']) { | |
Write-Host ('Connecting to Security & Compliance Center using {0} with Modern Authentication ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
$script:myOffice365Services['SessionCC'] = ExchangeOnlineManagement\Connect-IPPSSession -ConnectionUri $global:myOffice365Services['SCCConnectionEndpointUri'] -UserPrincipalName ($script:myOffice365Services['Office365Credentials']).UserName -PSSessionOption $script:myOffice365Services['SessionExchangeOptions'] | |
} Else { | |
Write-Host ('Connecting to Security & Compliance Center using {0} ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
$script:myOffice365Services['SessionCC'] = ExchangeOnlineManagement\Connect-IPPSSession -ConnectionUrl $script:myOffice365Services['SCCConnectionEndpointUri'] -Credential $script:myOffice365Services['Office365Credentials'] -PSSessionOption $script:myOffice365Services['SessionExchangeOptions'] | |
} | |
If ($global:myOffice365Services['SessionCC']) { | |
Import-PSSession -Session $script:myOffice365Services['SessionCC'] -AllowClobber | |
} | |
} | |
Function script:Connect-EOP { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
If ($script:myOffice365Services['Office365CredentialsMFA']) { | |
Write-Host ('Connecting to Exchange Online Protection using {0} with Modern Authentication ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
$script:myOffice365Services['SessionEOP'] = ExchangeOnlineManagement\Connect-IPPSSession -ConnectionUri $script:myOffice365Services['EOPConnectionEndpointUri'] -UserPrincipalName ($script:myOffice365Services['Office365Credentials']).UserName -PSSessionOption $script:myOffice365Services['SessionExchangeOptions'] | |
} Else { | |
Write-Host ('Connecting to Exchange Online Protection using {0} ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
$script:myOffice365Services['SessionEOP'] = ExchangeOnlineManagement\Connect-IPPSSession -ConnectionUrl $script:myOffice365Services['EOPConnectionEndpointUri'] -Credential $script:myOffice365Services['Office365Credentials'] -PSSessionOption $script:myOffice365Services['SessionExchangeOptions'] | |
} | |
If ($script:myOffice365Services['SessionEOP'] ) { | |
Import-PSSession -Session $script:myOffice365Services['SessionEOP'] -AllowClobber | |
} | |
} | |
Function script:Connect-MSTeams { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
If ($script:myOffice365Services['Office365CredentialsMFA']) { | |
Write-Host ('Connecting to Microsoft Teams using {0} with Modern Authentication ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
Connect-MicrosoftTeams -AccountId ($script:myOffice365Services['Office365Credentials']).UserName -TenantId $myOffice365Services['TenantId'] | |
} Else { | |
Write-Host ('Connecting to Exchange Online Protection using {0} ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
Connect-MicrosoftTeams -Credential $script:myOffice365Services['Office365Credentials'] | |
} | |
} | |
Function script:Connect-SkypeOnline { | |
If ( !($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
Write-Host ('Connecting to Skype Online using {0}' -f $script:myOffice365Services['Office365Credentials'].username) | |
$script:myOffice365Services['SessionSFBO'] = New-CsOnlineSession -Credential $global:myOffice365Services['Office365Credentials'] | |
If ($script:myOffice365Services['SessionSFBO']) { | |
Import-PSSession -Session $script:myOffice365Services['SessionSFBO'] -AllowClobber | |
} | |
} | |
Function script:Connect-AzureActiveDirectory { | |
If (!(Get-Module -Name AzureAD)) { | |
Import-Module -Name AzureAD -ErrorAction SilentlyContinue | |
} | |
If (!(Get-Module -Name AzureADPreview)) { | |
Import-Module -Name AzureADPreview -ErrorAction SilentlyContinue | |
} | |
If ((Get-Module -Name AzureAD) -or (Get-Module -Name AzureADPreview)) { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
If ($script:myOffice365Services['Office365CredentialsMFA']) { | |
Write-Host 'Connecting to Azure Active Directory with Modern Authentication ..' | |
$Parms = @{ | |
AccountId = $script:myOffice365Services['Office365Credentials'].UserName | |
AzureEnvironment = $script:myOffice365Services['AzureEnvironment'] | |
} | |
} Else { | |
Write-Host ('Connecting to Azure Active Directory using {0} ..' -f $global:myOffice365Services['Office365Credentials'].username) | |
$Parms = @{ | |
'Credential' = $script:myOffice365Services['Office365Credentials'] | |
'AzureEnvironment' = $script:myOffice365Services['AzureEnvironment'] | |
} | |
} | |
Connect-AzureAD @Parms | |
} Else { | |
If (!(Get-Module -Name MSOnline)) { | |
Import-Module -Name MSOnline -ErrorAction SilentlyContinue | |
} | |
If (Get-Module -Name MSOnline) { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
Write-Host ('Connecting to Azure Active Directory using {0} ..' -f $script:myOffice365Services['Office365Credentials'].username) | |
Connect-MsolService -Credential $script:myOffice365Services['Office365Credentials'] -AzureEnvironment $script:myOffice365Services['AzureEnvironment'] | |
} Else { | |
Write-Error -Message 'Cannot connect to Azure Active Directory - problem loading module.' | |
} | |
} | |
} | |
Function script:Connect-AIP { | |
If (!(Get-Module -Name AIPService)) {Import-Module -Name AIPService -ErrorAction SilentlyContinue} | |
If (Get-Module -Name AIPService) { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
Write-Host ('Connecting to Azure Information Protection using {0}' -f $script:myOffice365Services['Office365Credentials'].username) | |
Connect-AipService -Credential $script:myOffice365Services['Office365Credentials'] | |
} Else { | |
Write-Error -Message 'Cannot connect to Azure Information Protection - problem loading module.' | |
} | |
} | |
Function script:Connect-SharePointOnline { | |
If (!(Get-Module -Name Microsoft.Online.Sharepoint.PowerShell)) { | |
Import-Module -Name Microsoft.Online.Sharepoint.PowerShell -ErrorAction SilentlyContinue | |
} | |
If (Get-Module -Name Microsoft.Online.Sharepoint.PowerShell) { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
If (($script:myOffice365Services['Office365Credentials']).username -like '*.onmicrosoft.com') { | |
$script:myOffice365Services['Office365Tenant'] = ($script:myOffice365Services['Office365Credentials']).username.Substring(($script:myOffice365Services['Office365Credentials']).username.IndexOf('@') + 1).Replace('.onmicrosoft.com', '') | |
} Else { | |
If (!($script:myOffice365Services['Office365Tenant'])) { | |
Get-Office365Tenant | |
} | |
} | |
If ($script:myOffice365Services['Office365CredentialsMFA']) { | |
Write-Host 'Connecting to SharePoint Online with Modern Authentication ..' | |
$Parms = @{ | |
url = 'https://{0}-admin.sharepoint.com' -f $($script:myOffice365Services['Office365Tenant']) | |
region = $script:myOffice365Services['SharePointRegion'] | |
} | |
} Else { | |
Write-Host "Connecting to SharePoint Online using $($script:myOffice365Services['Office365Credentials'].username) .." | |
$Parms = @{ | |
url = 'https://{0}-admin.sharepoint.com' -f $script:myOffice365Services['Office365Tenant'] | |
credential = $script:myOffice365Services['Office365Credentials'] | |
region = $script:myOffice365Services['SharePointRegion'] | |
} | |
} | |
Connect-SPOService @Parms | |
} Else { | |
Write-Error -Message 'Cannot connect to SharePoint Online - problem loading module.' | |
} | |
} | |
Function script:Connect-PowerApps { | |
If (!(Get-Module -Name Microsoft.PowerApps.PowerShell)) { | |
Import-Module -Name Microsoft.PowerApps.PowerShell -ErrorAction SilentlyContinue | |
} | |
If (!(Get-Module -Name Microsoft.PowerApps.Administration.PowerShell)) { | |
Import-Module -Name Microsoft.PowerApps.Administration.PowerShell -ErrorAction SilentlyContinue | |
} | |
If (Get-Module -Name Microsoft.PowerApps.PowerShell) { | |
If (!($script:myOffice365Services['Office365Credentials'])) { | |
Get-Office365Credentials | |
} | |
Write-Host "Connecting to PowerApps using $($script:myOffice365Services['Office365Credentials'].username) .." | |
If ($script:myOffice365Services['Office365CredentialsMFA']) { | |
$Parms = @{ | |
'Username' = $script:myOffice365Services['Office365Credentials'].UserName | |
} | |
} Else { | |
$Parms = @{ | |
'Username' = $script:myOffice365Services['Office365Credentials'].UserName | |
'Password' = $script:myOffice365Services['Office365Credentials'].Password | |
} | |
} | |
Add-PowerAppsAccount @Parms | |
} | |
Else { | |
Write-Error -Message 'Cannot connect to SharePoint Online - problem loading module.' | |
} | |
} | |
Function script:Get-Office365Credentials { | |
$script:myOffice365Services['Office365Credentials'] = $host.ui.PromptForCredential('Office 365 Credentials', 'Please enter your Office 365 credentials', $script:myOffice365Services['Office365Credentials'].UserName, '') | |
$local:MFAenabledModulePresence = $true | |
$script:myOffice365Services['Office365CredentialsMFA'] = Get-MultiFactorAuthenticationUsage | |
Get-TenantID | |
Set-WindowTitle | |
} | |
Function script:Get-AllowPrereleaseModule { | |
If ($script:myOffice365Services['AllowPrerelease']) { | |
# Already asked | |
} Else { | |
$Answer = Read-host -Prompt 'Would you like to check for pre-release modules? (y/N) ' | |
Switch ($Answer.ToUpper()) { | |
'Y' {$rval = $true} | |
Default {$rval = $false} | |
} | |
$script:myOffice365Services['AllowPrerelease']= $rval | |
} | |
} | |
Function script:Get-OnPremisesCredentials { | |
$script:myOffice365Services['OnPremisesCredentials'] = $host.ui.PromptForCredential('On-Premises Credentials', 'Please Enter Your On-Premises Credentials', '', '') | |
} | |
Function script:Get-Office365Tenant { | |
$script:myOffice365Services['Office365Tenant'] = Read-Host -Prompt 'Enter tenant ID, e.g. contoso for contoso.onmicrosoft.com' | |
} | |
Function script:Get-ModuleScope { | |
[CmdletBinding()] | |
Param ($Module) | |
If ($Module.ModuleBase -ilike ('{0}*' -f (Join-Path -Path $ENV:HOMEDRIVE -ChildPath $ENV:HOMEPATH))) { | |
'CurrentUser' | |
} Else { | |
'AllUsers' | |
} | |
} | |
Function script:Get-ModuleVersionInfo { | |
[CmdletBinding()] | |
Param ($Module) | |
$ModuleManifestPath = $Module.Path | |
$isModuleManifestPathValid = Test-Path -Path $ModuleManifestPath | |
If(!($isModuleManifestPathValid)) { | |
# Module manifest path invalid, skipping extracting prerelease info | |
$ModuleVersion= $Module.Version.ToString() | |
} Else { | |
$ModuleManifestContent = Get-Content -Path $ModuleManifestPath | |
$preReleaseInfo = $ModuleManifestContent -match "Prerelease = '(.*)'" | |
If ($preReleaseInfo) { | |
$preReleaseVersion = $preReleaseInfo[0].Split('=')[1].Trim().Trim("'") | |
If ($preReleaseVersion) { | |
$ModuleVersion = ('{0}-{1}' -f $Module.Version.ToString(), $preReleaseVersion) | |
} Else { | |
$ModuleVersion = $Module.Version.ToString() | |
} | |
} Else { | |
$ModuleVersion = $Module.Version.ToString() | |
} | |
} | |
$ModuleVersion | |
} | |
Function script:Update-Office365Modules { | |
Get-AllowPrereleaseModule | |
$local:Functions= Get-Office365ModuleInfo | |
$local:IsAdmin = [Security.principal.windowsprincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) | |
If ($local:IsAdmin) { | |
If ((Get-Process -Name powershell, pwsh -ErrorAction SilentlyContinue | Measure-Object).Count -gt 1) { | |
Write-Warning -Message ('Running multiple PowerShell sessions, successful updating might be problematic.') | |
} | |
ForEach ($local:Function in $local:Functions) { | |
$local:Item = ($local:Function).split('|') | |
If ($local:Item[3]) { | |
$local:Module = Get-Module -Name ('{0}' -f $local:Item[3]) -ListAvailable | Sort-Object -Property Version -Descending | |
$local:CheckThisModule = $false | |
If (([uri]($local:Module | Select-Object -First 1).RepositorySourceLocation).Authority -eq (([uri]$local:Item[5])).Authority) { | |
$local:CheckThisModule = $true | |
} | |
If ($local:CheckThisModule) { | |
If ($local:Item[5]) { | |
$local:Module = $local:Module | Where-Object {([uri]($_.RepositorySourceLocation)).Authority -ieq ([uri]($local:Item[5])).Authority } | Select-Object -First 1 | |
} Else { | |
$local:Module = $local:Module | Select-Object -First 1 | |
} | |
If (($local:Module).RepositorySourceLocation) { | |
$local:Version = Get-ModuleVersionInfo -Module $local:Module | |
Write-Host ('Checking {0}' -f $local:Item[4]) -NoNewLine | |
$local:NewerAvailable= $false | |
If ($local:Item[5]) { | |
$local:Repo = $local:Repos | Where-Object {([uri]($_.SourceLocation)).Authority -eq (([uri]$local:Item[5])).Authority} | |
} | |
If([string]::IsNullOrEmpty($local:Repo)) {$local:Repo = 'PSGallery'} Else {$local:Repo = ($local:Repo).Name} | |
$OnlineModule = Find-Module -Name $local:Item[3] -Repository $local:Repo -AllowPrerelease:$script:myOffice365Services['AllowPrerelease'] -ErrorAction SilentlyContinue | |
If ($OnlineModule) { | |
Write-Host (': Local:{0}, Online:{1}' -f $local:Version, $OnlineModule.version) | |
If ((Compare-TextVersionNumber -Version $local:Version -CompareTo $OnlineModule.version) -eq 1) { | |
$local:NewerAvailable = $true | |
} #Else {# Local module up to date or newer} | |
} Else { | |
# Not installed from online or cannot determine | |
Write-Host ('Local:{0} Online:N/A' -f $local:Version) | |
} | |
If ($local:NewerAvailable) { | |
$local:UpdateSuccess = $false | |
Try { | |
$Parm = @{ | |
AllowPrerelease = $script:myOffice365Services['AllowPrerelease'] | |
Force = $True | |
Confirm = $False | |
Scope = Get-ModuleScope -Module $local:Module | |
AllowClobber = $True | |
} | |
# Pass AcceptLicense if current version of UpdateModule supports it | |
If ((Get-Command -name Update-Module).Parameters['AcceptLicense']) { | |
$Parm.AcceptLicense = $True | |
} | |
If (Get-Command -Name Install-Package -ErrorAction SilentlyContinue) { | |
If ((Get-Command -name Install-Package).Parameters['SkipPublisherCheck']) { | |
$Parm.SkipPublisherCheck = $True | |
} | |
Install-Package -Name $local:Item[3] -Source $local:Repo @Parm | Out-Null | |
} Else { | |
Update-Module -Name $local:Item[3] @Parm | |
} | |
$local:UpdateSuccess= $true | |
} Catch { | |
Write-Error -Message ('Problem updating module {0}:{1}' -f $local:Item[3], $Error[0].Message) | |
} | |
If ($local:UpdateSuccess) { | |
If (Get-Command -Name Get-InstalledModule -ErrorAction SilentlyContinue) { | |
$local:ModuleVersions = Get-InstalledModule -Name $local:Item[3] -AllVersions | |
} Else { | |
$local:ModuleVersions = Get-Module -Name $local:Item[3] -ListAvailable -All | |
} | |
$local:Module = $local:ModuleVersions | Sort-Object -Property @{e={ [version]($_.Version -replace '[^\d\.]','')}} -Descending | Select-Object -First 1 | |
$local:LatestVersion = ($local:Module).Version | |
Write-Host ('Updated {0} to version {1}' -f $local:Item[4], $local:LatestVersion) -ForegroundColor Green | |
# Uninstall all old versions of dependencies | |
If ($OnlineModule) { | |
ForEach ($DependencyModule in $OnlineModule.Dependencies) { | |
# Unload | |
Remove-Module -Name $DependencyModule.Name -Force -Confirm:$False -ErrorAction SilentlyContinue | |
$local:DepModuleVersions = Get-Module -Name $DependencyModule.Name -ListAvailable | |
$local:DepModule = $local:DepModuleVersions | Sort-Object -Property @{e={[version]($_.Version -replace '[^\d\.]','')}} -Descending | Select-Object -First 1 | |
$local:DepLatestVersion = ($local:DepModule).Version | |
$local:OldDepModules = $local:DepModuleVersions | Where-Object {$_.Version -ne $local:DepLatestVersion} | |
ForEach ($DepModule in $local:OldDepModules) { | |
Write-Host ('Uninstalling dependency module {0} version {1}' -f $DepModule.Name, $DepModule.Version) | |
Try { | |
$DepModule | Uninstall-Module -Confirm:$false -Force | |
} Catch { | |
Write-Error -Message ('Problem uninstalling module {0} version {1}' -f $DepModule.Name, $DepModule.Version) | |
} | |
} | |
} | |
} | |
# Uninstall all old versions of the module | |
$local:OldModules = $local:ModuleVersions | Where-Object {$_.Version -ne $local:LatestVersion} | |
If ($local:OldModules) { | |
# Unload module when currently loaded | |
Remove-Module -Name $local:Item[3] -Force -Confirm:$False -ErrorAction SilentlyContinue | |
ForEach ($OldModule in $local:OldModules) { | |
Write-Host ('Uninstalling {0} version {1}' -f $local:Item[4], $OldModule.Version) -ForegroundColor White | |
Try { | |
$OldModule | Uninstall-Module -Confirm:$false -Force | |
} Catch { | |
Write-Error -Message ('Problem uninstalling module {0} version {1}' -f $OldModule.Name, $OldModule.Version) | |
} | |
} | |
} | |
} #Else {# Problem during update} | |
} #Else {# No update available} | |
} Else { | |
Write-Host ('Skipping {0}: Not installed using PowerShellGet/Install-Module' -f $local:Item[4]) -ForegroundColor Yellow | |
} | |
} | |
} | |
} | |
} Else { | |
Write-Host ('Script not running with elevated privileges; cannot update modules') -ForegroundColor Yellow | |
} | |
} | |
# Compare-TextVersionNumber to handle (rich) version comparison, similar to [System.Version]'s CompareTo method | |
# 1=CompareTo is newer, 0 = Equal, -1 = Version is Newer | |
Function script:Compare-TextVersionNumber { | |
[CmdletBinding()] | |
Param ( | |
[String]$Version, | |
[String]$CompareTo | |
) | |
$res = 0 | |
$null = $Version -match '^(?<version>[\d\.]+)(\-)?([a-zA-Z]*(?<preview>[\d]*))?$' | |
$VersionVer = [version]($matches.Version) | |
If ($matches.Preview) { | |
# Suffix .0 to satisfy SystemVersion as '#' won't initialize | |
$VersionPreviewVer = [version]('{0}.0' -f $matches.Preview) | |
} Else { | |
$VersionPreviewVer = [version]'99999.99999' | |
} | |
$null = $CompareTo -match '^(?<version>[\d\.]+)(\-)?([a-zA-Z]*(?<preview>[\d]*))?$' | |
$CompareToVer = [version]($matches.Version) | |
If ($matches.Preview) { | |
$CompareToPreviewVer = [version]('{0}.0' -f $matches.Preview) | |
} Else { | |
$CompareToPreviewVer = [version]'99999.99999' | |
} | |
If ($VersionVer -gt $CompareToVer) { | |
$res = -1 | |
} Else { | |
If ($VersionVer -lt $CompareToVer) { | |
$res = 1 | |
} Else { | |
# Equal - Check Preview Tag | |
If ($VersionPreviewVer -gt $CompareToPreviewVer) { | |
$res = -1 | |
} Else { | |
If ($VersionPreviewVer -lt $CompareToPreviewVer) { | |
$res = 1 | |
} Else { | |
# Really Equal | |
$res = 0 | |
} | |
} | |
} | |
} | |
$res | |
} | |
Function script:Report-Office365Modules { | |
Get-AllowPrereleaseModule | |
$local:Functions = Get-Office365ModuleInfo | |
$local:Repos = Get-PSRepository | |
ForEach ($local:Function in $local:Functions) { | |
$local:Item = ($local:Function).split('|') | |
If ($local:Item[3]) { | |
$local:Module = Get-Module -Name ('{0}' -f $local:Item[3]) -ListAvailable | Sort-Object -Property Version -Descending | |
# Use specific or default repository | |
If ($local:Item[5]) { | |
$local:Repo= $local:Repos | Where-Object {([uri]($_.SourceLocation)).Authority -eq (([uri]$local:Item[5])).Authority} | |
} | |
If ([string]::IsNullOrEmpty($local:Repo)) { | |
$local:Repo = 'PSGallery' | |
} Else { | |
$local:Repo = ($local:Repo).Name | |
} | |
If ($local:Item[5]) { | |
$local:Module = $local:Module | Where-Object {([uri]($_.RepositorySourceLocation)).Authority -ieq ([uri]($local:Item[5])).Authority } | Select-Object -First 1 | |
} Else { | |
$local:Module = $local:Module | Select-Object -First 1 | |
} | |
If ($local:Module) { | |
$local:Version = Get-ModuleVersionInfo -Module $local:Module | |
Write-Host ('Module {0}: Local v{1}' -f $local:Item[4], $Local:Version) -NoNewline | |
$OnlineModule = Find-Module -Name $local:Item[3] -Repository $local:Repo -AllowPrerelease:$script:myOffice365Services['AllowPrerelease'] -ErrorAction SilentlyContinue | |
If ($OnlineModule) { | |
Write-Host (', Online v{0}' -f $OnlineModule.version) -NoNewline | |
} Else { | |
Write-Host (', Online N/A') -NoNewline | |
} | |
Write-Host (', Scope:{0} Status:' -f (Get-ModuleScope -Module $local:Module)) -NoNewline | |
If ([string]::IsNullOrEmpty( $local:Version) -or [string]::IsNullOrEmpty( $OnlineModule.version)) { | |
Write-Host ('Unknown') | |
} Else { | |
If ((Compare-TextVersionNumber -Version $local:Version -CompareTo $OnlineModule.version) -eq 1) { | |
Write-Host ('Outdated') -ForegroundColor Red | |
} Else { | |
Write-Host ('OK') -ForegroundColor Green | |
} | |
} | |
} Else { | |
Write-Host ('{0} module not found ({1})' -f $local:Item[4], $local:Item[5]) | |
} | |
} | |
} | |
} | |
Function script:Connect-Office365 { | |
Connect-AzureActiveDirectory | |
Connect-AzureRMS | |
Connect-ExchangeOnline | |
Connect-MSTeams | |
Connect-SkypeOnline | |
Connect-EOP | |
Connect-ComplianceCenter | |
Connect-SharePointOnline | |
} | |
$PSGetModule = Get-Module -Name PowerShellGet -ListAvailable -ErrorAction SilentlyContinue | Sort-Object -Property Version -Descending | Select-Object -First 1 | |
If (!$PSGetModule) { | |
$PSGetVer = 'N/A' | |
} Else { | |
$PSGetVer = $PSGetModule.Version | |
} | |
$PackageManagementModule = Get-Module -Name PackageManagement -ListAvailable -ErrorAction SilentlyContinue | Sort-Object -Property Version -Descending | Select-Object -First 1 | |
If (!$PackageManagementModule) { | |
$PMMVer = 'N/A' | |
} Else { | |
$PMMVer = $PackageManagementModule.Version | |
} | |
Write-Host ('*' * 78) | |
Write-Host ('Connect-Office365Services v{0}' -f $local:ScriptVersion) | |
# See if the Administator built-in role is part of your role | |
$local:IsAdmin = [Security.principal.windowsprincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) | |
$local:CreateISEMenu = $psISE -and -not [Windows.Input.Keyboard]::IsKeyDown([Windows.Input.Key]::LeftShift) | |
If ($local:CreateISEMenu) { | |
Write-Host 'ISE detected, adding ISE menu options' | |
} | |
# Initialize global state variable when needed | |
If (-not (Get-Variable -Name myOffice365Services -ErrorAction SilentlyContinue)) { | |
$script:myOffice365Services = @{} | |
} | |
# Local Exchange session options | |
$script:myOffice365Services['SessionExchangeOptions'] = New-PSSessionOption -ProxyAccessType None | |
# Initialize environment & endpoints | |
Set-Office365Environment -AzureEnvironment 'Default' | |
Write-Host ('Environment:{0}, Administrator:{1}' -f $global:myOffice365Services['AzureEnvironment'], $local:IsAdmin) | |
Write-Host ('Architecture:{0}, PS:{1}, PSGet:{2}, PackageManagement:{3}' -f ($ENV:PROCESSOR_ARCHITECTURE), ($PSVersionTable).PSVersion, $PSGetVer, $PMMVer) | |
Write-Host ('*' * 78) | |
$local:Functions = Get-Office365ModuleInfo | |
$local:Repos = Get-PSRepository | |
Write-Host ('Collecting Module information ..') | |
If (Get-Module -Name 'SkypeOnlineConnector' -ListAvailable) { | |
Write-Warning -Message 'Notice: The Skype for Business Online Connector PowerShell module functionality has moved to the Microsoft Teams module. Module retired February 15th, 2021.' | |
} | |
If (Get-Module -Name 'Microsoft.Exchange.Management.ExoPowershellModule' -ListAvailable) { | |
Write-Warning -Message 'Notice: The Exchange Online PowerShell module has been replaced by the Exchange Online Management module.' | |
} | |
ForEach ($local:Function in $local:Functions) { | |
$local:Item = ($local:Function).split('|') | |
If ($local:Item[3]) { | |
$local:Module = Get-Module -Name ('{0}' -f $local:Item[3]) -ListAvailable | Sort-Object -Property Version -Descending | |
$local:ModuleMatch = ([uri]($local:Module | Select-Object -First 1).RepositorySourceLocation).Authority -eq ([uri]$local:Item[5]).Authority | |
If ($local:ModuleMatch) { | |
If ($local:CreateISEMenu) { | |
$local:MenuObj = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus | Where-Object -FilterScript { $_.DisplayName -eq $local:Item[0] } | |
If (!($local:MenuObj)) { | |
Try { | |
$local:MenuObj = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add( $local:Item[0], $null, $null) | |
} Catch { | |
Write-Warning -Message $_ | |
} | |
} | |
Try { | |
$local:RemoveItems = $local:MenuObj.Submenus | Where-Object -FilterScript {$_.DisplayName -eq $local:Item[1] -or $_.Action -eq $local:Item[2]} | |
$null = $local:RemoveItems | ForEach-Object -Process { | |
$local:MenuObj.Submenus.Remove($_) | |
} | |
$null = $local:MenuObj.SubMenus.Add( $local:Item[1], [ScriptBlock]::Create( $local:Item[2]), $null) | |
} Catch { | |
Write-Warning -Message $_ | |
} | |
} | |
If ($local:Item[3]) { | |
$local:Module = $local:Module | Sort-Object -Property @{e={[version]($_.Version -replace '[^\d\.]','')}} -Descending | |
If ($local:Item[5]) { | |
$local:Module = $local:Module | Where-Object {([uri]($_.RepositorySourceLocation)).Authority -ieq ([uri]($local:Item[5])).Authority } | Select-Object -First 1 | |
} Else { | |
$local:Module = $local:Module | Select-Object -First 1 | |
} | |
$local:Version = Get-ModuleVersionInfo -Module $local:Module | |
Write-Host ('Found {0} module (v{1})' -f $local:Item[4], $local:Version) -ForegroundColor Green | |
} | |
} #Else {# Module not found} | |
} | |
} | |
} | |
#endregion Updates/Misc | |
#region Computer | |
Function Get-BLPass { | |
<# | |
.SYNOPSIS | |
Get BitLocker Recovery Password. | |
.DESCRIPTION | |
Get Bitlocker recovery key from AD. | |
.PARAMETER PC | |
Name of Computer. | |
.PARAMETER credential | |
PreSet credentials for yur SA. | |
.EXAMPLE | |
Get-BLPass -PC <ComputerName> | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Name of PC' | |
)] | |
[String]$PC, | |
[System.Management.Automation.Credential()] | |
[pscredential]$Credential = $Credential | |
) | |
$session = New-PSSession -ComputerName $PDC -Credential $credential | |
$BO = Invoke-Command -Session $session -ScriptBlock { | |
Param ([Parameter(Mandatory = $True, HelpMessage = 'Name of PC')][String]$cpu) | |
$C = Get-ADComputer -Identity $cpu -Server $script:PDC | |
$ADP = @{ | |
Filter = "objectclass -eq 'msFVE-RecoveryInformation'" | |
SearchBase = $C.DistinguishedName | |
Properties = 'msFVE-RecoveryPassword' | |
Server = $script:PDC | |
} | |
$B = Get-ADObject @ADP | |
return $B | |
} -ArgumentList $PC | |
return $BO.'msFVE-RecoveryPassword' | |
} | |
Function Get-DirectoryTreeSize { | |
<# | |
.SYNOPSIS | |
This is used to get the file count, subdirectory count and folder size for the path specified. The output will show the current folder stats unless you specify the "AllItemsAndAllFolders" property. | |
Since this uses Get-ChildItem as the underlying structure, this supports local paths, network UNC paths and mapped drives. | |
.NOTES | |
Name: Get-DirectoryTreeSize | |
Author: theSysadminChannel | |
Version: 1.0 | |
DateCreated: 2020-Feb-11 | |
.LINK | |
https://thesysadminchannel.com/get-directory-tree-size-using-powershell - | |
.PARAMETER Recurse | |
Using this parameter will drill down to the end of the folder structure and output the filecount, foldercount and size of each folder respectively. | |
.PARAMETER AllItemsAndAllFolders | |
Using this parameter will get the total file count, total directory count and total folder size in MB for everything under that directory recursively. | |
.EXAMPLE | |
Get-DirectoryTreeSize "C:\Some\Folder" | |
Path FileCount DirectoryCount FolderSizeInMB | |
---- --------- -------------- -------------- | |
C:\Some\folder 3 3 0.002 | |
.EXAMPLE | |
Get-DirectoryTreeSize "\\MyServer\Folder" -Recurse | |
Path FileCount DirectoryCount FolderSizeInMB | |
---- --------- -------------- -------------- | |
\\MyServer\Folder 2 1 40.082 | |
.\Subfolder 1 0 26.555 | |
.EXAMPLE | |
Get-DirectoryTreeSize "\\MyServer\Folder" -Folder | |
Path FileCount DirectoryCount FolderSizeInMB | |
---- --------- -------------- -------------- | |
\\MyServer\Folder 2 1 40.082 | |
.\Subfolder 1 0 26.555 | |
Shows size of Top-Level-Folders within target | |
.EXAMPLE | |
Get-DirectoryTreeSize "Z:\MyMapped\folder" -AllItemsAndAllFolders | |
Path TotalFileCount TotalDirectoryCount TotalFolderSizeInMB | |
---- -------------- ------------------- ------------------- | |
Z:\MyMapped\folder 3 1 68.492 | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[Alias('du')] | |
[CmdletBinding(DefaultParameterSetName = 'Default')] | |
Param( | |
[Parameter( | |
Mandatory = $True, | |
Position = 0, | |
HelpMessage = 'Path to check' | |
)] | |
[String]$Path, | |
[Parameter( | |
ParameterSetName='ShowRecursive' | |
)] | |
[Switch]$Recurse, | |
[Alias('All')] | |
[Parameter( | |
ParameterSetName = 'ShowTopFolderAllItemsAndAllFolders' | |
)] | |
[switch]$AllItemsAndAllFolders, | |
[Alias('Folders')] | |
[Parameter( | |
ParameterSetName='TopLevelFolders' | |
)] | |
[Switch]$TopLevelFolders | |
) | |
Begin { | |
#$ErrorActionPreference = "SilentlyContinue" | |
#Adding a trailing slash at the end of $path to make it consistent. | |
If (-not $Path.EndsWith('\')) { | |
$Path = "$Path\" | |
} | |
Function Get-HumanReadable { | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Value to evaluate required' | |
)] | |
$size | |
) | |
Switch ($size){ | |
{$_ -lt 1kb} { | |
$size = ([math]::Round($size / 1kb,2)) | |
$type = 'B' | |
$index = 0 | |
Break | |
} | |
{$_ -lt 1mb} { | |
$size = ([math]::Round($size / 1kb,2)) | |
$type = 'KB' | |
$index = 1 | |
Break | |
} | |
{$_ -lt 1gb} { | |
$size = ([math]::Round($size / 1mb,2)) | |
$type = 'MB' | |
$index = 2 | |
Break | |
} | |
{$_ -lt 1tb} { | |
$size = ([math]::Round($size / 1gb,2)) | |
$type = 'GB' | |
$index = 3 | |
Break | |
} | |
{$_ -lt 1pb} { | |
$size = ([math]::Round($size / 1tb,2)) | |
$type = 'TB' | |
$index = 4 | |
Break | |
} | |
} | |
$obj = New-Object -TypeName PsObject -Property @{ | |
size = $size | |
Type = $type | |
Index = $index | |
} | |
Return $obj | |
} | |
#> | |
$returnList = New-Object -TypeName System.Collections.Generic.List[PsObject] | |
} | |
Process { | |
Try { | |
If ( | |
-not $PSBoundParameters.ContainsKey('AllItemsAndAllFolders') -and | |
-not $PSBoundParameters.ContainsKey('Recurse') | |
) { | |
$FileStats = Get-ChildItem -Path $Path -File -ErrorAction Stop | Measure-Object -Property Length -Sum | |
$FileCount = $FileStats.Count | |
$DirectoryCount = Get-ChildItem -Path $Path -Directory | Measure-Object | Select-Object -ExpandProperty Count | |
$size = Get-HumanReadable -size $FileStats.Sum | |
$properties = [Ordered]@{ | |
Path = $Path | |
FileCount = $FileCount | |
DirectoryCount = $DirectoryCount | |
Size = $size.size | |
Type = $size.type | |
Index = $size.index | |
} | |
$obj = New-Object -TypeName PsObject -Property $properties | |
$returnList.Add($obj) | |
} | |
If ($PSBoundParameters.ContainsKey('AllItemsAndAllFolders')) { | |
$FileStats = Get-ChildItem -Path $Path -File -Recurse -ErrorAction Stop | Measure-Object -Property Length -Sum | |
$FileCount = $FileStats.Count | |
$DirectoryCount = Get-ChildItem -Path $Path -Directory -Recurse | Measure-Object | Select-Object -ExpandProperty Count | |
$size = Get-HumanReadable -size $FileStats.Sum | |
$properties = [Ordered]@{ | |
Path = $Path | |
TotalFileCount = $FileCount | |
TotalDirectoryCount = $DirectoryCount | |
Size = $size.size | |
Type = $size.type | |
Index = $size.index | |
} | |
$obj = New-Object -TypeName PsObject -Property $properties | |
$returnList.Add($obj) | |
} | |
If ($PSBoundParameters.ContainsKey('Recurse')) { | |
Get-DirectoryTreeSize -Path $Path | |
$FolderList = Get-ChildItem -Path $Path -Directory -Recurse | Select-Object -ExpandProperty FullName | |
If ($FolderList) { | |
ForEach ($Folder in $FolderList) { | |
$FileStats = Get-ChildItem -Path $Folder -File | Measure-Object -Property Length -Sum | |
$FileCount = $FileStats.Count | |
$DirectoryCount = Get-ChildItem -Path $Folder -Directory | Measure-Object | Select-Object -ExpandProperty Count | |
$size = Get-HumanReadable -size $FileStats.Sum | |
$properties = [Ordered]@{ | |
Path = $Folder#Replace($Path,'.\') | |
FileCount = $FileCount | |
DirectoryCount = $DirectoryCount | |
Size = $size.Size | |
Type = $size.Type | |
Index = $size.Index | |
} | |
$obj = New-Object -TypeName PsObject -Property $properties | |
$returnList.Add($obj) | |
$FileStats,$FileCount,$DirectoryCount,$Size = $null #clearing variables | |
} | |
} | |
} | |
If ($PSBoundParameters.ContainsKey('TopLevelFolders')) { | |
Get-DirectoryTreeSize -Path $Path | |
$FolderList = Get-ChildItem -Path $Path -Directory | Select-Object -ExpandProperty FullName | |
If ($FolderList) { | |
ForEach ($Folder in $FolderList) { | |
$FileStats = Get-ChildItem -Path $Folder -File | Measure-Object -Property Length -Sum | |
$FileCount = $FileStats.Count | |
$DirectoryCount = Get-ChildItem -Path $Folder -Directory | Measure-Object | Select-Object -ExpandProperty Count | |
$size = Get-HumanReadable -size $FileStats.Sum | |
$properties = [Ordered]@{ | |
Path = $Folder#.Replace($Path,'.\') | |
FileCount = $FileCount | |
DirectoryCount = $DirectoryCount | |
Size = $size.Size | |
Type = $size.Type | |
Index = $size.Index | |
} | |
$obj = New-Object -TypeName PsObject -Property $properties | |
$returnList.Add($obj) | |
$FileStats,$FileCount,$DirectoryCount,$Size = $null #clearing variables | |
} | |
} | |
} | |
} Catch { | |
Write-Error -Message $_.Exception.Message | |
} | |
} | |
End { | |
Return $returnList | Sort-Object -Property Index, Size -Descending | Select-Object -Property * -ExcludeProperty Index | |
} | |
} | |
Function Get-DiskFree { | |
<# | |
.SYNOPSIS | |
Script is used to display disk information similar to Linux df command | |
.DESCRIPTION | |
The df utility displays statistics about the amount of free disk space | |
on the specified filesystem. This PowerShell function attempts to | |
encapsulates the core functionality of the NIX command for the Windows platform. | |
The script queries the removable disk, local disk, network, CD/DVD, and | |
ram disk drive types and creates a custom PowerShell object for output. | |
.PARAMETER Computername | |
What system do you want to test connection to (you can also use hostname or cn) | |
.PARAMETER Format | |
Instead of having the function return separate PowerShell "disk" objects, if you | |
prefer to have the collection output in a structured table format with human-readable | |
numbers. This would be similar to the *nix df command output with the -h option. | |
Note: The -Format option should only be enabled when no further numeric operations | |
will need to be performed on the Available, Size, and Used properties. The option | |
converts these values to the string data type. | |
.PARAMETER Credential | |
If you're querying a remote computer you may need to specify a remote credential | |
such as 'example\administrator' (This is aliased as runas as well) | |
.EXAMPLE | |
PS> Get-DiskFree | |
FileSystem : NTFS | |
Type : Local Fixed Disk | |
Used : 13246943232 | |
Volume : C: | |
Available : 29595770880 | |
Computer : DC01 | |
Size : 42842714112 | |
FileSystem : CDFS | |
Type : CD-ROM Disc | |
Used : 623890432 | |
Volume : D: | |
Available : 0 | |
Computer : DC01 | |
Size : 623890432 | |
FileSystem : NTFS | |
Type : Network Connection | |
Used : 16416772096 | |
Volume : Z: | |
Available : 26425942016 | |
Computer : DC01 | |
Size : 42842714112 | |
.EXAMPLE | |
PS> $cred = Get-Credential -Credential 'example\administrator' | |
PS> 'db01','sp01' | Get-DiskFree -Credential $cred -Format | ft -GroupBy Name -auto | |
Name: DB01 | |
Name Vol Size Used Avail Use% FS Type | |
---- --- ---- ---- ----- ---- -- ---- | |
DB01 C: 39.9G 15.6G 24.3G 39 NTFS Local Fixed Disk | |
DB01 D: 4.1G 4.1G 0B 100 CDFS CD-ROM Disc | |
Name: SP01 | |
Name Vol Size Used Avail Use% FS Type | |
---- --- ---- ---- ----- ---- -- ---- | |
SP01 C: 39.9G 20G 19.9G 50 NTFS Local Fixed Disk | |
SP01 D: 722.8M 722.8M 0B 100 UDF CD-ROM Disc | |
This example is to query multiple Computers, as specific user, and make human readable | |
.EXAMPLE | |
PS> Import-Module ActiveDirectory | |
PS> $servers = Get-ADComputer -Filter { OperatingSystem -like '*win*server*' } | Select-Object -ExpandProperty Name | |
PS> Get-DiskFree -cn $servers | Where-Object { ($_.Volume -eq 'C:') -and ($_.Available / $_.Size) -lt .20 } | Select-Object Computer | |
Computer | |
-------- | |
FS01 | |
FS03 | |
This example gets a list of windows servers in AD that have disk space below 20% on c: | |
.Example | |
PS> $cred = Get-Credential 'example\administrator' | |
PS> $servers = 'dc01','db01','exch01','sp01' | |
PS> Get-DiskFree -Credential $cred -cn $servers -Format | ? { $_.Type -like '*fixed*' } | select * -ExcludeProperty Type | Out-GridView -Title 'Windows Servers Storage Statistics' | |
Get local harddrive info of four select servers and output to grid | |
.EXAMPLE | |
PS> $cred = Get-Credential 'example\administrator' | |
PS> $servers = 'dc01','db01','exch01','sp01' | |
PS> Get-DiskFree -Credential $cred -cn $servers -Format | ? { $_.Type -like '*fixed*' } | sort 'Use%' -Descending | select -Property Name,Vol,Size,'Use%' | Export-Csv -Path $HOME\Documents\windows_servers_storage_stats.csv -NoTypeInformation | |
Output CSV with previous example | |
.INPUTS | |
None. You cannot pipe objects to Get-DiskFree through normal usage | |
.OUTPUTS | |
System.Array. Get-DiskFree returns an array with the following properties | |
Available uint64 (-Format = Avail) | |
Computer string | |
FileSystem string (-Format = FS) | |
Size uint64 | |
Type string | |
Used uint64 | |
Volume string (-Format = Vol) | |
.NOTES | |
Version: 1.0 | |
.LINK | |
https://binarynature.blogspot.com/2010/04/powershell-version-of-df-command.html | |
#> | |
[Alias('DF')] | |
Param ( | |
[Parameter( | |
Position = 0, | |
ValueFromPipeline = $true, | |
ValueFromPipelineByPropertyName = $true | |
)] | |
[Alias('hostname')] | |
[Alias('cn')] | |
[String[]]$ComputerName = $env:COMPUTERNAME, | |
[Parameter(Position=1)] | |
[Alias('runas')] | |
[System.Management.Automation.Credential()] | |
[PSCredential]$Credential = $Credential, | |
[Parameter(Position=2)] | |
[Switch]$Format | |
) | |
Begin { | |
$wmiq = 'SELECT * FROM Win32_LogicalDisk WHERE Size != Null AND DriveType >= 2' | |
} | |
Process { | |
ForEach ($computer in $ComputerName) { | |
Try { | |
If ($computer -eq $env:COMPUTERNAME) { | |
$disks = Get-WmiObject -Query $wmiq -ComputerName $computer -ErrorAction Stop | |
} Else { | |
$disks = Get-WmiObject -Query $wmiq -ComputerName $computer -Credential $Credential -ErrorAction Stop | |
} | |
If ($Format) { | |
# Create array for $disk objects and then populate | |
$diskarray = @() | |
$disks | ForEach-Object {$diskarray += $_} | |
$diskarray | Select-Object -Property @{n='Name';e={$_.SystemName}}, | |
@{n='Vol';e={$_.DeviceID}}, | |
VolumeName, | |
@{n='Size';e={Optimize-HumanReadable -size $_.Size}}, | |
@{n='Used';e={Optimize-HumanReadable -size (($_.Size)-($_.FreeSpace))}}, | |
@{n='Avail';e={Optimize-HumanReadable -size $_.FreeSpace}}, | |
@{n='Use%';e={"$([int](((($_.Size)-($_.FreeSpace))/($_.Size) * 100)))%"}}, | |
@{n='FS';e={$_.FileSystem}}, | |
@{n='Type';e={$_.Description}} | |
} Else { | |
Foreach ($disk in $disks) { | |
$diskprops = [Ordered]@{ | |
'Computer' = $disk.SystemName | |
'Volume' = $disk.DeviceID | |
'VolumeName' = $disk.VolumeName | |
'Size' = $disk.Size | |
'Used' = ($disk.Size - $disk.FreeSpace) | |
'Available' = $disk.FreeSpace | |
'Use%' = "$([int](((($disk.Size)-($disk.FreeSpace))/($disk.Size) * 100)))%" | |
'FileSystem' = $disk.FileSystem | |
'Type' = $disk.Description | |
} | |
# Create custom PS object and apply type | |
$diskobj = New-Object -TypeName PSObject -Property $diskprops | |
$diskobj.PSObject.TypeNames.Insert(0,'BinaryNature.DiskFree') | |
Write-Output -InputObject $diskobj | |
} | |
} | |
} Catch { | |
# Check for common DCOM errors and display "friendly" output | |
Switch ($_) { | |
{$_.Exception.ErrorCode -eq 0x800706ba} { | |
$err = 'Unavailable (Host Offline or Firewall)' | |
Break | |
} | |
{$_.CategoryInfo.Reason -eq 'UnauthorizedAccessException'}{ | |
$err = 'Access denied (Check User Permissions)' | |
Break | |
} | |
default {$err = $_.Exception.Message} | |
} | |
Write-Warning -Message "$computer - $err" | |
} | |
} | |
} | |
#END {} | |
} | |
Function Get-DiskUsage { | |
<# | |
.SYNOPSIS | |
similar to du function | |
.DESCRIPTION | |
Gets size of objects in a path | |
.EXAMPLE | |
Get-DiskUsage C:\down | Format-Table -Property Name,Size,ActualSize -Autosize | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[Alias('DiskUsage')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Target folder required' | |
)] | |
[String]$dufolder | |
) | |
$results = @() | |
$target = Get-ChildItem -Path $dufolder | |
ForEach ($item in $target) { | |
$f = $item | |
$found = Get-ChildItem -Recurse -Path $f.FullName | | |
Measure-Object -Property length -Sum | | |
Select-Object -Property @{n='Name';e={$_.Name}}, | |
@{n='Size';e={Optimize-HumanReadable -size $_.Sum}}, | |
@{n='ActualSize';e={'{0:n0}' -f ($_.Sum) + ' Bytes'}}, | |
Sum | |
$results += $found | |
} | |
$results = $results | Sort-Object -Property Sum -Descending | |
Return $results | |
} | |
Function Get-FileSystem { | |
<# | |
.SYNOPSIS | |
Get file system details from remote computer. | |
.DESCRIPTION | |
Get remote file system details inclding free space, total size, file system type. | |
By design it ignores Removable drives (Floppy/CD/DVD). | |
.PARAMETER srv | |
Computer Name. | |
.EXAMPLE | |
Get-FileSystem -srv TestComputername | |
PSComputerName Name DriveType DriveFormat IsReady FreeSpace UsedSpace TotalSize Root VolumeLabel | |
-------------- ---- --------- ----------- ------- --------- --------- --------- ---- ----------- | |
TestComputername C:\ Fixed NTFS True 35.8 GB 163.7 GB 199.4 GB C:\ | |
TestComputername E:\ Fixed ReFS True 346.1 GB 403.7 GB 749.8 GB E:\ Data | |
TestComputername F:\ Fixed ReFS True 595 GB 154.8 GB 749.8 GB F:\ Log | |
TestComputername G:\ Fixed ReFS True 395.9 GB 116 GB 511.8 GB G:\ Backups | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
Param ( | |
[Parameter(Position=0)] | |
[String]$srv = $env:COMPUTERNAME | |
) | |
Begin { | |
$Sel = @{ | |
Property = 'PSComputerName', | |
'Name', | |
'DriveType', | |
'DriveFormat', | |
'IsReady', | |
@{n='FreeSpace';e={Optimize-HumanReadable -size $_.AvailableFreeSpace}}, | |
@{n='UsedSpace';e={Optimize-HumanReadable -size $($_.TotalSize - $_.AvailableFreeSpace)}}, | |
@{n='TotalSize';e={Optimize-HumanReadable -size $_.TotalSize}}, | |
@{n='Root';e={$_.RootDirectory}}, | |
'VolumeLabel' | |
} | |
} | |
Process { | |
$res = Invoke-Command -ComputerName $srv -ScriptBlock {[IO.DriveInfo]::getdrives()} | |
} | |
End { | |
### Remove Floppy/CD/DVD drives | |
### IgnoreFields: RunspaceId, TotalFreeSpace, (Calculate UsedSpace) | |
$return = $res | Where-Object {$_.DriveType -notmatch 'CD|Removable'} | Select-Object @Sel | |
return $return | |
} | |
} | |
Function Get-OutDatedOS { | |
<# | |
.SYNOPSIS | |
Find Computers with EOL Operating Systems on domain. | |
.DESCRIPTION | |
Search AD Computer objects running an OS that's End of Life. | |
.EXAMPLE | |
Get-OutDatedOS | Format-Table -Auto | |
Returns all EOL OS's registered with domain (Name, OS, IP, LastLogonDate, Container) | table format results returned. | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
$ODParams = @{ | |
Filter = 'Enabled -eq $true -and OperatingSystem -like "*Windows*"' | |
Properties = 'OperatingSystem', 'IPv4Address', 'CanonicalName', 'LastLogonDate' | |
Server = $script:PDC | |
} | |
$odsParams = @{ | |
Property = 'Name', | |
'OperatingSystem', | |
@{ | |
n = 'IP' | |
e = { | |
If ($null -eq $_.IPv4Address){ | |
'Off' | |
} Else { | |
$_.IPv4Address | |
} | |
} | |
}, | |
'LastLogonDate', | |
@{n='Container';e={Get-Container -can $_.CanonicalName}} | |
} | |
$OutDatedOSs = Get-ADComputer @ODParams | | |
Where-Object {$_.OperatingSystem -match '2000|2003|2008|xp|7|8.1'} | | |
Select-Object @odsParams | | |
Sort-Object -Property OperatingSystem, Container, Name | |
Return $OutDatedOSs | |
} | |
Function Get-PrinterInfo { | |
<# | |
.SYNOPSIS | |
Script to create a Excel spreadsheet with detailed information about | |
the printers installed on the server | |
.DESCRIPTION | |
Script was designed to give you a good description of how your print | |
server(s) are installed and configured. | |
* Requires Microsoft Excel be installed on the workstation you are running | |
the script from. | |
.PARAMETER PrintServers | |
Name of the server you wish to run the script again. Can also be an | |
array of servers. | |
.OUTPUTS | |
Excel spreadsheet | |
.EXAMPLE | |
.\Get-PrinterInfo.ps1 -PrintServers "MyPrintServer" | |
.EXAMPLE | |
.\Get-PrinterInfo.ps1 -PrintServers (Get-Content c:\scripts\myprintserverlist.txt) | |
.INPUTS | |
String | |
.OUTPUTS | |
Excel | |
#> | |
[CmdletBinding()] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Name of print Server' | |
)] | |
[String]$PrintServers, | |
[System.Management.Automation.Credential()] | |
[PSCredential]$Credential = $Credential | |
) | |
# Create new Excel workbook | |
Write-Verbose -Message "$(Get-Date): Script begins!" | |
Write-Verbose -Message "$(Get-Date): Opening Excel..." | |
$Excel = New-Object -ComObject Excel.Application | |
$Excel.Visible = $True | |
$Excel = $Excel.Workbooks.Add() | |
$Sheet = $Excel.Worksheets.Item(1) | |
$Sheet.Name = 'Printer Inventory' | |
#====================================================== | |
$Sheet.Cells.Item(1,1) = 'Print Server' | |
$Sheet.Cells.Item(1,2) = 'Printer Name' | |
$Sheet.Cells.Item(1,3) = 'Location' | |
$Sheet.Cells.Item(1,4) = 'Comment' | |
$Sheet.Cells.Item(1,5) = 'IP Address' | |
$Sheet.Cells.Item(1,6) = 'Driver Name' | |
$Sheet.Cells.Item(1,7) = 'Driver Version' | |
$Sheet.Cells.Item(1,8) = 'Driver' | |
$Sheet.Cells.Item(1,9) = 'Shared' | |
$Sheet.Cells.Item(1,10) = 'Share Name' | |
#======================================================= | |
$intRow = 2 | |
$WorkBook = $Sheet.UsedRange | |
$WorkBook.Interior.ColorIndex = 40 | |
$WorkBook.Font.ColorIndex = 11 | |
$WorkBook.Font.Bold = $True | |
#======================================================= | |
# Get printer information | |
ForEach ($PrintServer in $PrintServers) { | |
Write-Verbose -Message "$(Get-Date): Working on $PrintServer..." | |
$Printers = Get-WmiObject -Class Win32_Printer -ComputerName $PrintServer -Credential $credential | |
ForEach ($Printer in $Printers) { | |
$session = New-PSSession -ComputerName $PrintServer -Credential $credential | |
If ($Printer.Name -notlike 'Microsoft XPS*') { | |
$Sheet.Cells.Item($intRow, 1) = $PrintServer | |
$Sheet.Cells.Item($intRow, 2) = $Printer.Name | |
$Sheet.Cells.Item($intRow, 3) = $Printer.Location | |
$Sheet.Cells.Item($intRow, 4) = $Printer.Comment | |
If ($Printer.PortName -notlike '*\*') { | |
$Ports = Get-WmiObject -Class Win32_TcpIpPrinterPort -Filter "name = '$($Printer.Portname)'" -ComputerName $Printserver -Credential $credential | |
ForEach ($Port in $Ports) { | |
$Sheet.Cells.Item($intRow, 5) = $Port.HostAddress | |
} | |
} | |
#################### | |
$Drivers = Get-WmiObject -Class Win32_PrinterDriver -Filter "__path like '%$($Printer.DriverName)%'" -ComputerName $Printserver -Credential $credential | |
ForEach ($Driver in $Drivers) { | |
$Drive = $Driver.DriverPath.Substring(0,1) | |
$Sheet.Cells.Item($intRow,7) = (Get-ItemProperty -Path ($Driver.DriverPath.Replace("$Drive`:","\\$PrintServer\$Drive`$"))).VersionInfo.ProductVersion | |
$Sheet.Cells.Item($intRow,8) = Split-Path -Path $Driver.DriverPath -Leaf | |
} | |
#################### | |
$Sheet.Cells.Item($intRow, 6) = $Printer.DriverName | |
$Sheet.Cells.Item($intRow, 9) = $Printer.Shared | |
$Sheet.Cells.Item($intRow, 10) = $Printer.ShareName | |
$intRow ++ | |
} | |
Remove-PSSession -Id $session | |
} | |
$WorkBook.EntireColumn.AutoFit() | Out-Null | |
} | |
$intRow ++ | |
$Sheet.Cells.Item($intRow,1) = 'Printer inventory completed' | |
$Sheet.Cells.Item($intRow,1).Font.Bold = $True | |
$Sheet.Cells.Item($intRow,1).Interior.ColorIndex = 40 | |
$Sheet.Cells.Item($intRow,2).Interior.ColorIndex = 40 | |
Write-Verbose -Message "$(Get-Date): Completed!" | |
} | |
Function Get-remComputerInfo { | |
<# | |
.SYNOPSIS | |
Get basic info from a computer. | |
.DESCRIPTION | |
Get Model, Serial Number, and BIOS Version from a computer. | |
.PARAMETER <Computer> | |
Define the target computer | |
.EXAMPLE | |
Get-ComputerInfo testmachine01 | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $True, | |
HelpMessage = 'Computer' | |
)] | |
[String]$c | |
) | |
$CInfoResult = @() | |
WH -t 'Checking: ' -n | |
WH -t $c -f Cy | |
#$ping = Get-WmiObject -Class win32_pingstatus -Filter "address='$c'" | |
$ping = Test-Connection -ComputerName $c -Count 1 -Quiet | |
If ($ping -eq $true) { | |
$ping | ForEach-Object { | |
$CInfoResult += [PSCustomObject][Ordered]@{ | |
Name = $c | |
Status = 'Online' | |
Model = (Get-WmiObject -Class Win32_ComputerSystem -ComputerName $c).model | |
Serial = (Get-WmiObject -Class Win32_Bios -ComputerName $c).SerialNumber | |
Version = (Get-WmiObject -Class Win32_Bios -ComputerName $c).Version | |
} | |
} | |
} Else { | |
$CInfoResult += [PSCustomobject][Ordered]@{ | |
Name = $c | |
Status = 'Offline' | |
Model = 'NA' | |
Serial = 'NA' | |
Version = 'NA' | |
} | |
} | |
Return $CInfoResult | |
} | |
Function Search-ADComputer { | |
<# | |
.SYNOPSIS | |
Find any/all computers that match. | |
.DESCRIPTION | |
Finds any/all computers that even resemble your search criteria | |
.PARAMETER | |
Define the target to look for | |
.EXAMPLE | |
Search-ADComputer comply | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[CmdletBinding()] | |
[Alias('fputer')] | |
Param ( | |
[Parameter(Mandatory=$true,HelpMessage='Search String')] | |
[ValidateNotNullorEmpty()] | |
[String]$SearchString, | |
[Switch]$full | |
) | |
$adParam = @{ | |
Filter = "samaccountname -like '*$($SearchString)*' -or name -like '*$($SearchString)*'" | |
Properties = 'IPv4Address', | |
'DNSHostName', | |
'Enabled', | |
'Name', | |
'ObjectClass', | |
'Description', | |
'CanonicalName', | |
'OperatingSystem', | |
'LastLogonDate', | |
'PasswordLastSet', | |
'whenCreated' | |
Server = $script:PDC | |
} | |
$mSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountName', | |
'Name', | |
'IPv4Address', | |
'DNSHostName', | |
'Enabled', | |
'ObjectClass', | |
'ObjectGUID', | |
'SID', | |
'Description', | |
'OperatingSystem', | |
'LastLogonDate', | |
'PasswordLastSet', | |
'whenCreated', | |
@{ | |
n = 'Container' | |
e = {Get-Container -can $_.CanonicalName} | |
} | |
} | |
$Match = Get-ADComputer @adParam | Select-Object @mSel | |
If ($full) { | |
$Match = $Match | |
} Else { | |
$maSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountName', | |
'Name', | |
'IPv4Address', | |
'DNSHostName', | |
'Enabled', | |
'Description', | |
'OperatingSystem', | |
'LastLogonDate', | |
'PasswordLastSet', | |
'whenCreated', | |
'Container' | |
} | |
$Match = $Match | Select-Object @maSel | |
} | |
If ($null -eq $Match) { | |
WH -t 'No matching accounts were found.' | |
} Else { | |
$Match | |
} | |
} | |
Function Get-Serials { | |
<# | |
.SYNOPSIS | |
Gets serial numbers of PCs and their attached monitors | |
.DESCRIPTION | |
creates a list of PCs to query based on -EXAMPLE and retrieves PC serials | |
and the serials of monitors that are attached, as long as the PC is reachable. | |
.PARAMETER similar | |
add -similar to the end of your command to find all computers that resemble the pc name | |
.EXAMPLE | |
Get-Serials testpc01 | |
Usage: to look up information on a single machine | |
Gets Name/Manufacturer/Model/SerialNumber/Status and all Monitor details (size/manufacturer/serial) | |
.EXAMPLE | |
Get-Serials testpc -similar | |
Usage: to look up information on all computers that match testpc's name | |
Gets Name/Manufacturer/Model/SerialNumber/Status and all Monitor details (size/manufacturer/serial) | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Computer name required' | |
)] | |
[String]$example, | |
[Switch]$similar | |
) | |
Function Format-TableColored { | |
Param( | |
[Parameter( | |
Mandatory, | |
HelpMessage = 'Object to color required', | |
ValueFromPipeline, | |
Position = 0 | |
)] | |
[PSObject]$InputObject, | |
[Switch]$AutoSize, | |
[Switch]$HideTableHeaders, | |
[String]$ColorProperty = '__Color' | |
) | |
Begin { | |
$Output = @() | |
$Colors = @() | |
$FirstValue = '' | |
$StartColor = $False | |
$ColorArgs = @{} | |
} | |
Process { | |
If (!$FirstValue){ | |
$FirstValue = [regex]::Escape(($InputObject.PsObject.Properties | Select-Object -ExpandProperty Value -First 1)) | |
} | |
$Colors += If ($InputObject.$ColorProperty -is [hashtable]) { | |
$InputObject.$ColorProperty | |
} Else { | |
@{} | |
} | |
$Output += $InputObject | Select-Object -Property * -ExcludeProperty $ColorProperty | |
} | |
End { | |
$null = $PSBoundParameters.Remove('ColorProperty') | |
$PSBoundParameters['InputObject'] = $Output | |
$i = 0 | |
(Format-Table @PSBoundParameters | Out-String) -split "`r`n" | | |
ForEach-Object { | |
If (!$StartColor -and ($_ -match "\s*$($FirstValue)")){$StartColor = $True} | |
If ($StartColor -and $_){$ColorArgs = $Colors[$i++]} Else {$ColorArgs.Clear()} | |
Write-Host -Object $_ @ColorArgs | |
} | |
} | |
} | |
$Computers = @() | |
Switch ($similar) { | |
$true { | |
Search-ADComputer -SearchString $example | Foreach-Object {$Computers += $_.DNSHostName} | |
} | |
$false { | |
Search-ADComputer -SearchString $example -single | Foreach-Object {$Computers += $_.DNSHostName} | |
} | |
default { | |
Search-ADComputer -SearchString $example -single | Foreach-Object {$Computers += $_.DNSHostName} | |
} | |
} | |
If ($Computers) { | |
$computerlist = @() | |
# Loop through the computers | |
$computers | ForEach-Object { | |
If (($Computers | Select-Object -First 1) -eq 'NA') { | |
WH -t 'No matching Computers found.' | |
Break | |
} | |
$tempObj = New-Object -TypeName System.Management.Automation.PSObject | |
$tempObj | Add-Member -MemberType NoteProperty -Name 'ComputerName' -Value $_.split('.')[0].trim() | |
$tempCompName = $_ | |
If (Test-Connection -ComputerName $_ -Quiet -Count 1) { | |
$computerHold = Get-WmiObject -ComputerName $_ -Class Win32_ComputerSystem -ErrorAction SilentlyContinue | |
$computerMan = $computerHold.Manufacturer | |
$computerMod = $computerHold.Model | |
### PC Serial Number | |
$computerSerial = (Get-WmiObject -ComputerName $_ -Class Win32_Bios -ErrorAction SilentlyContinue).SerialNumber | |
If ($computerSerial -match 'VMware') {$computerSerial = 'VMware'} | |
If ($computerSerial -notmatch 'VMware') { | |
### Get Monitor WMI Objects | |
$monitorWmi = Get-WmiObject -ComputerName $_ -Class WMIMonitorID -Namespace 'root\wmi' -ErrorAction SilentlyContinue | |
$monitorSerials = @() | |
$monitorWmi | ForEach-Object { | |
$Man = ($_.ManufacturerName -notmatch 0 | ForEach-Object {[char]$_}) -join '' | |
$Nam = Try { | |
($_.UserFriendlyName -notmatch 0 | ForEach-Object {[char]$_}) -join '' | |
} Catch { | |
($_.UserFriendlyName -notMatch 0 | ForEach-Object {$_}) -join '' | |
} | |
$Ser = ($_.SerialNumberID -notmatch 0 | ForEach-Object {[char]$_}) -join '' | |
$MonInst = $_.InstanceName.split('\')[-1] | |
### $MonInfHold will fetch and store computername, monitor instance id, horizontal size, vertical size, do the match for overall size, and aspect ratio | |
$miParam = @{ | |
Property = @{ | |
n = 'Computer' | |
e = {$_.__SERVER} | |
}, | |
'InstanceName', | |
@{ | |
n = 'Horizontal' | |
e = {[Math]::Round(($_.MaxHorizontalImageSize/2.54), 2)} | |
}, | |
@{ | |
n = 'Vertical' | |
e = {[Math]::Round(($_.MaxVerticalImageSize/2.54), 2)} | |
}, | |
@{ | |
n = 'Size' | |
e = {[Math]::Round(([Math]::Sqrt([Math]::Pow($_.MaxHorizontalImageSize, 2) + [Math]::Pow($_.MaxVerticalImageSize, 2))/2.54),2)} | |
}, | |
@{ | |
n = 'Ratio' | |
e = {[Math]::Round(($_.MaxHorizontalImageSize)/($_.MaxVerticalImageSize),2)} | |
} | |
} | |
$MonInfHold = Get-WmiObject -ComputerName $tempCompName -Namespace root\wmi -Class WmiMonitorBasicDisplayParams | Select-Object @miParam | |
$MonSize = $MonInfHold | Where-Object {$_.InstanceName.split('\')[-1] -match $MonInst} | Select-Object -ExpandProperty Size | |
$monitorSerials += "$Man,$Nam,$Ser,$MonSize inch" | |
$monitorSerialOutput = '{' + $($monitorSerials -join ' / ') + '}' # Convert $monitor serials to string | |
} | |
} Else { | |
$monitorSerialOutput = '{NA}' | |
} | |
# Add the details to our $tempObj | |
$tempObj | Add-Member -MemberType NoteProperty -Name 'CompManufacturer' -Value $computerMan | |
$tempObj | Add-Member -MemberType NoteProperty -Name 'ComputerModel' -Value $computerMod | |
$tempObj | Add-Member -MemberType NoteProperty -Name 'ComputerSerialNumber' -Value $computerSerial | |
$tempObj | Add-Member -MemberType NoteProperty -Name 'MonitorSerialNumbers' -Value $monitorSerialOutput | |
$tempObj | Add-Member -MemberType NoteProperty -Name 'Status' -Value 'ONLINE' | |
} Else { | |
# If the computer is off, set the status property to offline so we can easily sort and filter them | |
$tempObj | Add-Member -MemberType NoteProperty -Name 'Status' -Value 'UNREACHABLE' | |
} | |
$computerList += $tempObj # Add the $temoObj to the $computerList array | |
} | |
# Output the $computerList | |
#$computerList | |
If ($similar){ | |
$cParam = @{ | |
Property = 'ComputerName', | |
'CompManufacturer', | |
'ComputerModel', | |
'ComputerSerialNumber', | |
'MonitorSerialNumbers', | |
'Status', | |
@{ | |
n = '__Color' | |
e = { | |
If ($_.Status -eq 'UNREACHABLE') { | |
@{Fore = 'Red'} | |
} | |
} | |
} | |
} | |
$computerList | Select-Object @cParam | Sort-Object -Property Status, ComputerName | Format-TableColored | |
} Else { | |
$cParam = @{ | |
Property = 'ComputerName', | |
'CompManufacturer', | |
'ComputerModel', | |
'ComputerSerialNumber', | |
'MonitorSerialNumbers', | |
'Status' | |
} | |
$computerlist = $computerList | Select-Object @cParam | Sort-Object -Property Status,ComputerName | |
Return $computerlist | |
} | |
} Else { | |
WH -t 'No matching Computers found.' | |
} | |
} | |
Function Get-StalePCs { | |
<# | |
.SYNOPSIS | |
Get a list of stale PCs 200 days old and deletes or disables those chosen | |
.DESCRIPTION | |
Get a list of PCs that haven't logged on to domain in 200 days and either deletes or disables what you choose | |
.PARAMETER Disable | |
Disable alters Description, sets to disabled and moves to Disabled Computer OU | |
.PARAMETER Delete | |
Delete is self-explanatory | |
.EXAMPLE | |
Get-StalePCs -Delete | |
Show a list of machines that haven't checked in in 200 days, then gives a grid to select from (multiple). | |
Those chosen are deleted. | |
.INPUTS | |
String | |
.OUTPUTS | |
Out-GridView | |
#> | |
[CmdletBinding()] | |
Param ( | |
[Switch]$Disable, | |
[Switch]$Delete | |
) | |
#$ErrorActionPreference = 'SilentlyContinue' | |
If ($Disable.IsPresent -or $Delete.IsPresent) { | |
$Act = $true | |
} Else { | |
$Act = $false | |
} | |
If ($Disable.IsPresent -and $Delete.IsPresent) { | |
Write-Information -MessageData 'Choose one - Disable or Delete' -Tags Choice | |
return | |
} | |
### Get Stale PCs to choose from | |
Write-Information -MessageData 'Getting Computers...' -Tags Progress | |
$term = '200' | |
$StalePCs = Show-DeadPCs -term $term | Where-Object {$null -eq $_.IPv4Address} | Sort-Object -Property Container,LastLogonAge | |
If ($Act -eq $true) { | |
### Choose machines to disable/delete | |
$mSel = @{Property = 'Name', 'OS', 'PWDLastSetAge', 'LastLogonDate', 'LastLogonDateDays', 'LastLogonAge', 'Container', 'Description'} | |
$Marked = $StalePCs | Select-Object @mSel | Out-GridView -Title "Computers that haven't logged on in $($term) days" -Passthru | |
If ($Marked) { | |
ForEach ($Mark in $Marked) { | |
If ($Disable.IsPresent) { | |
Write-Information -MessageData 'Beginning Disabling' -Tags Action,Disable | |
### Disabling | |
$PreDesc = '[Scripted - Disabled for inactivity]' ### to Disable | |
$MarkedTarget = $Desc = $null | |
$hadDesc = $false | |
$MarkedTarget = Get-ADComputer -Identity $Mark.Name | |
$TargetDesc = Get-ADComputer -Identity $Mark.Name -Properties Description | |
If ($TargetDesc.Description){ | |
If (($null -ne $TargetDesc.Description) -or ($TargetDesc.Description -like '*')) { | |
$hadDesc = $true | |
$Desc = $("$($PreDesc) Disabled on $(Get-Date -Format yyyy-MMM-dd) $(($TargetDesc.Description).trim()) by $($env:USERNAME)").trim() | |
} Else { | |
$hadDesc = $false | |
$Desc = $("[Scripted - Disabled for inactivity] Disabled on $(Get-Date -Format yyyy-MMM-dd) by $($env:USERNAME)").trim() | |
} | |
} Else { | |
$hadDesc = $false | |
$Desc = $("[Scripted - Disabled for inactivity] Disabled on $(Get-Date -Format yyyy-MMM-dd) by $($env:USERNAME)").trim() | |
#Set-ADComputer -Identity $MarkedTarget -Add @{"description"="$($Desc)"} | |
} | |
### Change Description | |
If ($hadDesc -eq $true) { | |
#Set-ADComputer -Identity $MarkedTarget -replace @{"description"="$($Desc)"} | |
Write-Information -MessageData "Set-ADComputer -Identity $($MarkedTarget.Name) -replace @{`"description`"=`"$($Desc)`"}" -Tags Action,Disable,Description | |
} Else { | |
#Set-ADComputer -Identity $MarkedTarget -Add @{"description"="$($Desc)"} | |
Write-Information -MessageData "Set-ADComputer -Identity $($MarkedTarget.Name) -Add @{`"description`"=`"$($Desc)`"}" -Tags Action,Disable,Description | |
} | |
### Disable | |
#Set-ADComputer -Identity $MarkedTarget -Enabled $false | |
Write-Information -MessageData "Set-ADComputer -Identity $($MarkedTarget.Name) -Enabled `$false" -Tags Action,Disable | |
### Move to Terminated OU | |
#Move-ADObject -Identity $MarkedTarget -targetpath "OU=Terminated,OU=Computers,OU=SI,DC=shermco,DC=ind" | |
Write-Information -MessageData "Move-ADObject -Identity $($MarkedTarget.Name) -targetpath `"OU=Terminated,OU=Computers,OU=SI,DC=shermco,DC=ind`"" -Tags Action,Disable | |
### Verify Object | |
#Get-ADComputer -Identity $Mark.DistinguishedName -Properties Description,Enabled | |
} | |
If ($Delete.IsPresent) { | |
Write-Information -MessageData 'Beginning Deleting' -Tags Action,Delete | |
### Deleting | |
Get-ADComputer -Identity $Mark.DistinguishedName | Remove-ADObject -Recursive -Confirm:$false | |
#WH -t "Get-ADComputer $($Mark.Name) | Remove-ADObject -Recursive -Confirm:`$false" | |
Write-Information -MessageData "$($Mark.Name) - Deleted" -Tags Action,Delete | |
} | |
} | |
} Else { | |
Write-Information -MessageData 'Nothing Selected' -Tags NoAction | |
} | |
} Else { | |
$StalePCs | Out-GridView -Title "Computers that haven't logged on in $($term) days" | |
} | |
} | |
Function Get-SystemInfo { | |
<# | |
.SYNOPSIS | |
Get raw sysinfo from one or more machines. | |
.DESCRIPTION | |
Gets raw sysinfo directly off of a single machine or group of machines. | |
.PARAMETER Scope | |
Add -Scope to specify a scope of machines as outlined below. | |
-Scope ServerOnly: Run sysinfo on all servers. | |
-Scope DCOnly: Run sysinfo on all DCs. | |
-Scope LocalHost: Run sysinfo on local computer. | |
-Scope ClientOnly: Run sysinfo on all machines that are not a server. | |
-Scope AllComputer: Sysinfo on every machine | |
.PARAMETER ComputerName | |
Use -ComputerName to specify a single computer. | |
.EXAMPLE | |
Get-SystemInfo serveronly | ogv | |
Gets sysinfo for all servers and output to gridview | |
.NOTES | |
Suggested to specify a field you're looking for | |
or use ' | ft -auto' or ' | ogv' to make the results more readable. | |
.OUTPUTS | |
Fields returned: | |
'Host Name','OS','Version','Manufacturer','Configuration','Build Type', | |
'Registered Owner','Registered Organization','Product ID','Install Date', | |
'Boot Time','System Manufacturer','Model','Type','Processor','Bios', | |
'Windows Directory','System Directory','Boot Device','Language','Keyboard', | |
'Time Zone','Total Physical Memory','Available Physical Memory','Virtual Memory', | |
'Virtual Memory Available','Virtual Memory in Use','Page File','Domain', | |
'Logon Server','Hotfix','Network Card','Hyper-V' | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
[CmdletBinding()] | |
Param ( | |
[ValidateSet('LocalHost', 'ServerOnly', 'DCOnly', 'ClientOnly', 'AllComputer')] | |
[String]$Scope, | |
[String]$ComputerName | |
) | |
#$sysinforeturn = @() | |
$E = @{ErrorAction = 'SilentlyContinue'} | |
$header = 'Host Name', | |
'OS', | |
'Version', | |
'Manufacturer', | |
'Configuration', | |
'Build Type', | |
'Registered Owner', | |
'Registered Organization', | |
'Product ID', | |
'Install Date', | |
'Boot Time', | |
'System Manufacturer', | |
'Model', | |
'Type', | |
'Processor', | |
'Bios', | |
'Windows Directory', | |
'System Directory', | |
'Boot Device', | |
'Language', | |
'Keyboard', | |
'Time Zone', | |
'Total Physical Memory', | |
'Available Physical Memory', | |
'Virtual Memory', | |
'Virtual Memory Available', | |
'Virtual Memory in Use', | |
'Page File', | |
'Domain', | |
'Logon Server', | |
'Hotfix', | |
'Network Card', | |
'Hyper-V' | |
Switch ($Scope) { | |
'ServerOnly' { | |
Invoke-Command -ComputerName (Get-ADComputer -Filter {OperatingSystem -like '*server*'}).Name -ScriptBlock { | |
& "$env:windir\system32\systeminfo.exe" /FO CSV | Select-Object -Skip 1 | |
} @E | ConvertFrom-Csv -Header $header | |
} | |
'DCOnly' { | |
Invoke-Command -ComputerName (Get-ADDomainController -Filter *).Name -ScriptBlock { | |
& "$env:windir\system32\systeminfo.exe" /FO CSV | Select-Object -Skip 1 | |
} @E | ConvertFrom-Csv -Header $header | |
} | |
'LocalHost' { | |
& "$env:windir\system32\systeminfo.exe" /FO CSV | Select-Object -Skip 1 | ConvertFrom-Csv -Header $header | |
} | |
'ClientOnly' { | |
Invoke-Command -ComputerName (Get-ADComputer -Filter {OperatingSystem -notlike '*server*'}).Name -ScriptBlock { | |
& "$env:windir\system32\systeminfo.exe" /FO CSV | Select-Object -Skip 1 | |
} @E | ConvertFrom-Csv -Header $header | |
} | |
'AllComputer' { | |
Invoke-Command -ComputerName (Get-ADComputer -Filter *).Name -ScriptBlock { | |
& "$env:windir\system32\systeminfo.exe" /FO CSV | Select-Object -Skip 1 | |
} @E | ConvertFrom-Csv -Header $header | |
} | |
} | |
If ($ComputerName) { | |
If (Test-Connection -ComputerName $ComputerName -Count 1 -Quiet){ | |
Invoke-Command -ComputerName $ComputerName -ScriptBlock { | |
& "$env:windir\system32\systeminfo.exe" /FO CSV | Select-Object -Skip 1 | |
} @E | ConvertFrom-Csv -Header $header | |
} Else { | |
Write-Error -Message "$($ComputerName) unreachable" | |
} | |
} | |
} | |
Function Get-TrustStatus { | |
<# | |
.SYNOPSIS | |
Directly queries a computer to test if its trusted on domain | |
.DESCRIPTION | |
Inquires with the domain about the trust status of a given computer | |
.PARAMETER Computer | |
-Computer: Specify which computer you're targeting. | |
.EXAMPLE | |
Get-TrustStatus -Computer samplecomputername | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Computer Name' | |
)] | |
[String]$Computer | |
) | |
$TrustResult = New-Object -TypeName System.Collections.Arraylist | |
$Computer | Foreach-Object { | |
If (-not (Test-Connection -ComputerName $_ -Quiet -Count 1)) { | |
$trustStatus = 'Offline' | |
} Else { | |
$trustStatus = Invoke-Command -ComputerName $_ -ScriptBlock {Test-ComputerSecureChannel -Verbose} | |
} | |
$null = $TrustResult.add((New-Object -TypeName PSObject -Property @{ | |
ComputerName = $_ | |
Status = If ($trustStatus -eq $true) {'Trusted'} Else {'False'} | |
})) | |
} | |
$TrustResult | |
} | |
Function Show-DeadPCs { | |
<# | |
.SYNOPSIS | |
Get a list of stale PCs based on number of days | |
.DESCRIPTION | |
Get a list of PCs that haven't logged on to domain in a specified number of days | |
.EXAMPLE | |
Show-DeadPCs 365 | |
Show a list of machines that haven't checked in in 365 days | |
.INPUTS | |
Int | |
.OUTPUTS | |
Array | |
.NOTES | |
Author : James Stephens | |
Created On : 12/16/2022 | |
Organization : Shermco | |
Filename : Show-DeadPCs.ps1 | |
Version : 1.0 - Initial release. | |
1.1 - Refining. | |
.FUNCTIONALITY | |
Get-ADComputer | |
#> | |
[Alias('stalepcs')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Amount of days to use for what dead means' | |
)] | |
[Alias('term')] | |
[String]${Enter how many days old} | |
) | |
If (-not ($term)) {$term = ${Enter how many days old}} | |
#Requires -Module ActiveDirectory | |
$ErrorActionPreference = 'SilentlyContinue' | |
$Days = (Get-Date).addDays(-$term) | |
$StalePCParams = @{ | |
Filter = '(LastLogonDate -NotLike "*") -OR (LastLogondate -ge $Days) -OR (PasswordLastSet -le $Days)' | |
Properties = 'PasswordLastSet', | |
'LastLogonDate', | |
'LastLogonTimeStamp', | |
'CanonicalName', | |
'OperatingSystem', | |
'Description', | |
'IPv4Address', | |
'Enabled' | |
Server = $script:PDC | |
} | |
$oParam = @{ | |
Property = 'Name', | |
'Enabled', | |
@{n='OS';e={$_.OperatingSystem}}, | |
@{n='PWDLastSetAge';e={((Get-Date) - $_.PasswordLastSet).Days}}, | |
'LastLogonDate', | |
@{n='LastLogonDateDays';e={((Get-Date) - $_.LastLogonDate).days}}, | |
@{n='LastLogonAge';e={((Get-Date) - [DateTime]::FromFileTime($_.LastLogonTimeStamp)).Days}}, | |
@{n='Container';e={$_.CanonicalName -ireplace '\/[^\/]+$',''}}, | |
'Description', | |
'IPv4Address', | |
'DistinguishedName' | |
} | |
$output = Get-ADComputer @StalePCParams | | |
Select-Object @oParam | | |
Where-Object {$_.LastLogonAge -gt $term} | | |
Where-Object {$_.Name -notmatch 'NTNX'} | | |
Sort-Object -Property Container, LastLogonAge | |
Return $output | |
} | |
Function Show-SysInfos { | |
<# | |
.SYNOPSIS | |
Leverages cmdlet Get-SystemInfo to return sysinfo | |
.DESCRIPTION | |
Shows in depth system info for computer you specify. | |
.Example | |
Show-SysInfos testcomputer | |
------------------------------------------- | |
Buildtype : Multiprocessor Free | |
OSName : Microsoft Windows 10 Enterprise LTSC | |
NetworkAdapter : 2 NIC(s) Installed. | |
[01]: Intel(R) Dual Band Wireless-AC 8260 | |
Connection Name: Wi-Fi | |
Status: Media disconnected | |
[02]: Realtek PCIe GBE Family Controller | |
Connection Name: Ethernet | |
DHCP Enabled: Yes | |
DHCP Server: 192.168.1.12 | |
IP address(es) | |
[01]: 192.168.1.254 | |
[02]: fe80::6ce8:a18c:c64d:68b | |
RegisteredOwner : admini | |
UsedVirtualMemory : 1,722 MB | |
RegisteredOrganization : | |
PagingFile : C:\pagefile.sys | |
StartTime : 1/27/2020, 7:59:50 AM | |
AvailableVirtualMemory : 7,652 MB | |
LogonServer : N/A | |
Language : en-us;English (United States) | |
OSManufacturer : Microsoft Corporation | |
OSVersion : 10.0.17763 N/A Build 17763 | |
Hotfix : 7 Hotfix(s) Installed. | |
[01]: KB4533013 | |
[02]: KB4465065 | |
[03]: KB4470788 | |
[04]: KB4487038 | |
[05]: KB4516115 | |
[06]: KB4523204 | |
[07]: KB4530715 | |
Model : OptiPlex 3240 AIO | |
Type : x64-based PC | |
Manufacturer : Dell Inc. | |
Hostname : testcomputer | |
BIOSVersion : Dell Inc. 1.5.10, 11/14/2016 | |
OSConfig : Member Workstation | |
Domain : shermco.ind | |
ProductID : 00424-90090-18465-AA859 | |
PhysicalMemory : 8,094 MB | |
Processor : 1 Processor(s) Installed.,[01]: Intel64 Family 6 Model 94 Stepping 3 GenuineIntel ~3192 Mhz | |
AvailablePhysicalMemory : 6,153 MB | |
Keyboard : en-us;English (United States) | |
SystemFolder : C:\Windows\system32 | |
WindowsFolder : C:\Windows | |
MaxVirtualMemory : 9,374 MB | |
InstallDate : 12/16/2019, 10:25:53 AM | |
TimeZone : (UTC-06:00) Central Time (US & Canada) | |
StartDevice : \Device\HarddiskVolume2 | |
HyperV : VM Monitor Mode Extensions: Yes | |
Virtualization Enabled In Firmware: Yes | |
Second Level Address Translation: Yes | |
Data Execution Prevention Available: Yes | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
.OUTPUTS | |
Hostname,OSName,OSVersion,OSManufacturer,OSConfig,Buildtype,RegisteredOwner | |
RegisteredOrganization,ProductID,InstallDate,StartTime,Manufacturer,Model | |
Type,Processor,BIOSVersion,WindowsFolder,SystemFolder,StartDevice,Language | |
Keyboard,TimeZone,PhysicalMemory,AvailablePhysicalMemory,MaxVirtualMemory | |
AvailableVirtualMemory,UsedVirtualMemory,PagingFile,Domain,LogonServer,Hotfix | |
NetworkAdapter,HyperV | |
#> | |
Param ( | |
[Parameter(Mandatory,HelpMessage='ComputerName')] | |
[String]$ComputerName | |
) | |
$sysinfoarray = @() | |
$sysinfo = $null | |
$Selection = @{ | |
Property = 'Host name', | |
'OS', | |
'Version', | |
'Manufacturer', | |
'Configuration', | |
'Build Type', | |
'Registered Owner', | |
'Registered Organization', | |
'Product ID', | |
'Install Date', | |
'Boot Time', | |
'System Manufacturer', | |
'Model', | |
'Type', | |
'Processor', | |
'BIOS', | |
'Windows Directory', | |
'System Directory', | |
'Boot Device', | |
'Language', | |
'Keyboard', | |
'Time Zone', | |
'Total Physical Memory', | |
'Available Physical Memory', | |
'Virtual Memory', | |
'Virtual Memory Available', | |
'Virtual Memory in Use', | |
'Page File', | |
'Domain', | |
'Logon Server', | |
@{n="'Hotfix'";e={$_.Hotfix.replace(',',"`n")}}, | |
@{n="'NetworkCard'";e={$_.'Network Card'.replace(',',"`n")}}, | |
@{n="'HyperV'";e={$_.'Hyper-V'.replace(',',"`n")}} | |
} | |
If ($ComputerName){ | |
$sysinfo = Get-SystemInfo -Computername $ComputerName | Select-Object @Selection | |
} Else { | |
$sysinfo = Get-SystemInfo -Scope localhost | Select-Object @Selection | |
} | |
ForEach ($line in $sysinfo){ | |
$sysinfoarray += [pscustomobject][ordered]@{ | |
Hostname = $line.'Host name' | |
OSName = $line.'OS' | |
OSVersion = $line.'Version' | |
OSManufacturer = $line.'Manufacturer' | |
OSConfig = $line.'Configuration' | |
Buildtype = $line.'Build Type' | |
RegisteredOwner = $line.'Registered Owner' | |
RegisteredOrganization = $line.'Registered Organization' | |
ProductID = $line.'Product ID' | |
InstallDate = $line.'Install Date' | |
StartTime = $line.'Boot Time' | |
Manufacturer = $line.'System Manufacturer' | |
Model = $line.'Model' | |
Type = $line.'Type' | |
Processor = $line.'Processor' | |
BIOSVersion = $line.'BIOS' | |
WindowsFolder = $line.'Windows Directory' | |
SystemFolder = $line.'System Directory' | |
StartDevice = $line.'Boot Device' | |
Language = $line.'Language' | |
Keyboard = $line.'Keyboard' | |
TimeZone = $line.'Time Zone' | |
PhysicalMemory = $line.'Total Physical Memory' | |
AvailablePhysicalMemory = $line.'Available Physical Memory' | |
MaxVirtualMemory = $line.'Virtual Memory' | |
AvailableVirtualMemory = $line.'Virtual Memory Available' | |
UsedVirtualMemory = $line.'Virtual Memory in Use' | |
PagingFile = $line.'Page File' | |
Domain = $line.'Domain' | |
LogonServer = $line.'Logon Server' | |
Hotfix = $line.'Hotfix' | |
NetworkAdapter = $line.'NetworkCard' | |
HyperV = $line.'HyperV' | |
} | |
} | |
Return $sysinfoarray | |
} | |
#endregion Computer | |
#region User | |
Function Get-Mgr { | |
<# | |
.SYNOPSIS | |
Gets manager from AD if one is listed | |
.DESCRIPTION | |
Gets user manager from AD if one is listed. | |
.PARAMETER user | |
AD samaccountname | |
.EXAMPLE | |
get-mgr username | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[Alias('gmgr')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'AD Username' | |
)] | |
[String]$user | |
) | |
$sel = @{Property = @{n='MgrName';e={(Get-ADUser -Identity $_.Manager -Server $script:PDC).Name}}} | |
If ($user.SamAccountName){ | |
$Props = @{ | |
Identity = $user.SamAccountName | |
Properties = 'Manager' | |
Server = $script:PDC | |
} | |
} Else { | |
$Props = @{ | |
Identity = $user | |
Properties = 'Manager' | |
Server = $script:PDC | |
} | |
} | |
$mgr = (Get-ADUser @Props | Select-Object @sel).MgrName | |
Return $mgr | |
} | |
Function Get-Phones { | |
<# | |
.SYNOPSIS | |
Gets Users all user phone numbers possible from AD | |
.DESCRIPTION | |
Makes a best effort to get and parse all user phone numbers into a readable format | |
.PARAMETER find | |
you can specify a name you're looking for | |
.PARAMETER grid | |
you can send results to gridview | |
.EXAMPLE | |
Get-Phones -grid | |
Returns all user phone numbers into gridview | |
.EXAMPLE | |
Get-Phones <samaccountname> | |
Returns all phone numbers for <samaccountname> | |
.EXAMPLE | |
Get-Phones -grid | |
Returns all phone numbers in gridview | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[CmdletBinding()] | |
Param ( | |
[String[]]$find, | |
[Switch]$grid | |
) | |
$ErrorActionPreference = 'SilentlyContinue' | |
#region Poll AD for all phone number fields | |
$ADPhoneParams = @{ | |
Properties = 'Fax', | |
'IpPhone', | |
'mobile', | |
'OfficePhone', | |
'otherTelephone' | |
} | |
$ADSelParm = @{ | |
Property = 'Name', | |
'Fax', | |
'IpPhone', | |
'mobile', | |
'OfficePhone', | |
@{n='otherTelephone';e={($_.OtherTelephone -join ', ').TrimEnd(', ')}} | |
} | |
If ($find){ | |
$users = @() | |
ForEach ($u in $find) { | |
$ADPhoneParams.Identity = $u | |
$users += Get-ADUser @ADPhoneParams | Select-Object @ADSelParm | |
} | |
} Else { | |
$ADPhoneParams.Filter = '(enabled -eq $true) -and (Fax -like "*" -or IpPhone -like "*" -or mobile -like "*" -or OfficePhone -like "*" -or OtherTelephone -like "*")' | |
$users = Get-ADUser @ADPhoneParams | Select-Object @ADSelParm | |
} | |
#endregion Poll AD | |
#region Build Array | |
$phones = @() | |
$users | ForEach-Object { | |
### Fax | |
If ($null -ne $_.Fax) {$Fax = Convert-StandardPhone -NumtoConv $_.Fax} Else {$Fax = $null} | |
### IPPhone | |
If ($null -ne $_.IpPhone) {$IpPhone = Convert-StandardPhone -NumtoConv $_.IpPhone} Else {$IpPhone = $null} | |
### Mobile | |
If ($null -ne $_.Mobile) {$Mobile = Convert-StandardPhone -NumtoConv $_.mobile} Else {$Mobile = $null} | |
### OfficePhone | |
If ($_.OfficePhone -match '^*[0-9]') { ### If the contents of OfficePhone attrib is a number | |
$OfficePhone = @() | |
$oTemp = $_.OfficePhone | |
### If the current object contains 'ext' -- replace 'ext' with a comma | |
If ($oTemp -match 'ext') {$oTemp = $oTemp.replace('ext',',')} | |
If ($oTemp -notmatch ',') { | |
### Deal with non-commas | |
### remove all characters that aren't numbers | |
$item = $oTemp -replace '\D' | |
$itemNum = ($item | Measure-Object -Character).Characters | |
### If the current object is 1-6 characters long, add 'x' just before it to indicate extension -- else -- If the current object is greater than 6 characters, format to phonenumber | |
If (($itemNum -ge 1) -and ($itemNum -le 6)){$OfficePhone = "x$($item)"} Else {$OfficePhone = Convert-StandardPhone -NumtoConv $item} | |
} Else { | |
### Deal with commas | |
$OfficePhoneTemp = @() | |
$oTemp.split(',') | ForEach-Object { ### split the current object on commas -- then deal with each item | |
If ($_ -like '*') { ### if the item is not null | |
$item = $_ -replace '\D' ### select only numbers | |
$itemNum = ($item | Measure-Object -Character).Characters | |
If (($itemNum -ge 1) -and ($itemNum -le 6)) {$OfficePhoneTemp += "x$($item)"} Else {$OfficePhoneTemp += Convert-StandardPhone -NumtoConv $item} | |
} | |
} | |
$OfficePhone = ($OfficePhoneTemp | Select-Object -Unique) -join ' ' ### Select unique items -> Convert to string -> Store in $OfficePhone | |
} | |
} Else { ### If the contents of OfficePhone attrib isn't a number or is empty, set $OfficePhone value to $null | |
$OfficePhone = $null | |
} | |
### otherTelephone | |
If ($_.OtherTelephone -match '^*[0-9]') { | |
$OtherPhone = @() | |
$OtTemp = $_.OtherTelephone | |
If ($OtTemp -notmatch ','){ | |
$item = $OtTemp -replace '\D' | |
$itemNum = ($item | Measure-Object -Character).Characters | |
If (($itemNum -ge 1) -and ($itemNum -le 6)) {$OtherPhone = "x$($item)"} Else {$OtherPhone = Convert-StandardPhone -NumtoConv $OtTemp} | |
} Else { | |
$OtherPhoneTemp = @() | |
$OtTemp.split(',') | ForEach-Object { | |
If ($_ -like '*'){ | |
$item = $_ -replace '\D' | |
$itemNum = ($item | Measure-Object -Character).Characters | |
If (($itemNum -ge 1) -and ($itemNum -le 6)) {$OtherPhoneTemp += "x$($item)"} Else {$OtherPhoneTemp += Convert-StandardPhone -NumtoConv $item} | |
} | |
} | |
$OtherPhone = ($OtherPhoneTemp | Select-Object -Unique) -join ' ' | |
} | |
} Else { | |
$OtherPhone = $null | |
} | |
$phones += [PSCustomObject][Ordered]@{ | |
Name = $_.Name | |
#HomePhone = $HomePhone | |
Fax = $Fax | |
IpPhone = $IpPhone | |
Mobile = $Mobile | |
OfficePhone = $OfficePhone | |
OtherPhone = $OtherPhone | |
Ext = If ($OfficePhone -match 'x'){$OfficePhone.split('x')[-1]} ElseIf (($IpPhone) -and (($IpPhone | Measure-Object -Character).Characters -le 6)){$IpPhone} | |
} | |
} | |
#endregion Build Array | |
### If a name was specified to search for | |
### Try to match the name in the phone array --> $match | |
If ($grid.IsPresent){ ### If grid was specified | |
$phones | Out-GridView ### Output results to grid | |
} Else { ### No grid specified | |
Return $phones ### return full phone array results | |
} | |
} | |
Function Get-Exts { | |
<# | |
.SYNOPSIS | |
Gets Users Phone extensions | |
.DESCRIPTION | |
Gets users phone extensions populated by the telep[honeNumber field in AD | |
.EXAMPLE | |
Get-Exts james | |
Returns any extensions where the name on it is "james" | |
.EXAMPLE | |
Get-Exts | |
Returns all extensions | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[Alias('GetExts')] | |
[CmdletBinding()] | |
Param ([String]$person) | |
$EXTUsers = Get-Phones | |
$ExtList = @() | |
If ($person) { | |
$ExtList += $ExtUsers | Where-Object {$_.Name -match $person} | Select-Object -Property Name, IpPhone, OfficePhone, Ext | |
} Else { | |
$ExtList = $ExtUsers | Select-Object -Property Name, IpPhone, OfficePhone, Ext | |
} | |
Return $ExtList | |
} | |
Function Search-ADUser { | |
<# | |
.SYNOPSIS | |
Find any/all users that match. | |
.DESCRIPTION | |
Finds any/all users that even resemble your search criteria | |
.PARAMETER | |
Define the target to look for | |
.EXAMPLE | |
Search-ADUser jess | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[Alias('fUser')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'partial name/username' | |
)] | |
[ValidateNotNullorEmpty()] | |
[String]$SearchString, | |
[Switch]$full | |
) | |
$AdParam = @{ | |
Filter = "samaccountname -like '*$($SearchString)*' -or name -like '*$($SearchString)*' -or givenname -like '*$($SearchString)*' -or surname -like '*$($SearchString)*' -or userprincipalname -like '*$($SearchString)*'" | |
Properties = 'Company', | |
'CanonicalName', | |
'Department', | |
'Description', | |
'EmployeeID', | |
'Enabled', | |
'GivenName', | |
'Manager', | |
'Surname', | |
'Title', | |
'extensionAttribute7', | |
'Fax', | |
'mobile', | |
'OfficePhone', | |
'otherTelephone', | |
'PasswordLastSet', | |
'whenCreated', | |
'whenChanged' | |
Server = $script:PDC | |
} | |
$mSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountname', | |
'Name', | |
'Enabled', | |
'EmployeeID', | |
@{n='exAt7';e={$_.extensionAttribute7}}, | |
'GivenName', | |
'Surname', | |
'Company', | |
'Title', | |
'Description', | |
'Department', | |
@{n='Manager';e={Get-Mgr -user $_.Manager}}, | |
@{n='Container';e={Get-Container -can $_.CanonicalName}}, | |
'ObjectClass', | |
'ObjectGUID', | |
'SID', | |
'UserPrincipalName', | |
@{n='MobilePhone';e={Convert-StandardPhone -NumtoConv $_.mobile}}, | |
@{n='OfficePhone';e={Convert-StandardPhone -NumtoConv $_.OfficePhone}}, | |
@{n='otherTelephone';e={(@($_.otherTelephone | ForEach-Object {Convert-StandardPhone -NumtoConv $_}) -join ', ').TrimEnd(', ')}}, | |
@{n='Fax';e={Convert-StandardPhone -NumtoConv $_.Fax}}, | |
'PasswordLastSet', | |
'whenCreated', | |
'whenChanged' | |
} | |
$Match = Get-ADUser @AdParam | Select-Object @mSel | |
If ($full){ | |
$Match = $Match | |
} Else { | |
$maSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountname', | |
'Name', | |
'Enabled', | |
'EmployeeID', | |
'exAt7', | |
'Company', | |
'Title', | |
'Description', | |
'Department', | |
'Manager', | |
'Container', | |
'UserPrincipalName', | |
'MobilePhone', | |
'OfficePhone', | |
'otherTelephone', | |
'Fax', | |
'PasswordLastSet', | |
'whenCreated', | |
'whenChanged' | |
} | |
$Match = $Match | Select-Object @maSel | |
} | |
If ($null -eq $Match){ | |
WH -t 'No matching accounts were found.' | |
} Else { | |
$Match | |
} | |
} | |
Function Search-EmpID { | |
<# | |
.SYNOPSIS | |
EmployeeID finder | |
.DESCRIPTION | |
Searches AD for the string you're trying to find in the Description field | |
.EXAMPLE | |
Search-EmpID 0123 | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[CmdletBinding()] | |
[Alias('flid')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Search String' | |
)] | |
[ValidateNotNullorEmpty()] | |
[String]$SearchString, | |
[Switch]$full | |
) | |
$AdParam = @{ | |
Filter = "EmployeeID -like '*$($SearchString)*'" | |
Properties = 'Company', | |
'CanonicalName', | |
'Department', | |
'Description', | |
'EmployeeID', | |
'Enabled', | |
'GivenName', | |
'Manager', | |
'Surname', | |
'Title' | |
Server = $script:PDC | |
} | |
$mSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountname', | |
'Name', | |
'Enabled', | |
'EmployeeID', | |
'GivenName', | |
'Surname', | |
'Company', | |
'Title', | |
'Description', | |
'Department', | |
@{n='Manager';e={Get-Mgr -user $_.Manager}}, | |
@{n='Container';e={Get-Container -can $_.CanonicalName}}, | |
'ObjectClass', | |
'ObjectGUID', | |
'SID', | |
'UserPrincipalName' | |
} | |
$Match = Get-ADUser @AdParam | Select-Object @mSel | |
If ($full){ | |
$Match = $Match | |
} Else { | |
$maSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountname', | |
'Name', | |
'Enabled', | |
'EmployeeID', | |
'Company', | |
'Title', | |
'Description', | |
'Department', | |
'Manager', | |
'Container', | |
'UserPrincipalName' | |
} | |
$Match = $Match | Select-Object @maSel | |
} | |
If ($null -eq $Match) { | |
WH -t 'No matching accounts were found.' | |
} Else { | |
Return $Match | |
} | |
} | |
Function Search-Position { | |
<# | |
.SYNOPSIS | |
Department / Title finder | |
.DESCRIPTION | |
Searches AD for the string you're trying to find in the Description and Title field | |
.EXAMPLE | |
Search-Position 8080 | |
.EXAMPLE | |
Search-Position Supervisor | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[CmdletBinding()] | |
[Alias('FindDPT')] | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Search String' | |
)] | |
[String]$DeptString, | |
[Switch]$full | |
) | |
$AdParam = @{ | |
Filter = "Department -like '*$($DeptString)*' -or departmentNumber -like '*$($DeptString)*' -or Title -like '*$($DeptString)*'" | |
Properties = 'Company', | |
'CanonicalName', | |
'Department', | |
'Description', | |
'EmployeeID', | |
'Enabled', | |
'GivenName', | |
'Manager', | |
'Surname', | |
'Title', | |
'Fax', | |
'mobile', | |
'OfficePhone', | |
'otherTelephone' | |
Server = $script:PDC | |
} | |
$mSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountname', | |
'Name', | |
'Enabled', | |
'EmployeeID', | |
'GivenName', | |
'Surname', | |
'Company', | |
'Title', | |
'Description', | |
'Department', | |
@{n='Manager';e={Get-Mgr -user $_.Manager}}, | |
@{n='Container';e={Get-Container -can $_.CanonicalName}}, | |
'ObjectClass', | |
'ObjectGUID', | |
'SID', | |
'UserPrincipalName', | |
@{n='MobilePhone';e={Convert-StandardPhone -NumtoConv $_.mobile}}, | |
@{n='OfficePhone';e={Convert-StandardPhone -NumtoConv $_.OfficePhone}}, | |
@{n='otherTelephone';e={(@($_.otherTelephone | ForEach-Object {Convert-StandardPhone -NumtoConv $_}) -join ', ').TrimEnd(', ')}}, | |
@{n='Fax';e={Convert-StandardPhone -NumtoConv $_.Fax}} | |
} | |
$Match = Get-ADUser @AdParam | Select-Object @mSel | |
If ($full) { | |
$Match = $Match | |
} Else { | |
$maSel = @{ | |
Property = 'DistinguishedName', | |
'SamAccountname', | |
'Name', | |
'Enabled', | |
'EmployeeID', | |
'Company', | |
'Title', | |
'Description', | |
'Department', | |
'Manager', | |
'Container', | |
'UserPrincipalName', | |
'MobilePhone', | |
'OfficePhone', | |
'otherTelephone', | |
'Fax' | |
} | |
$Match = $Match | Select-Object @maSel | |
} | |
If ($null -eq $Match) { | |
WH -t 'No matching accounts were found.' | |
} Else { | |
Return $Match | |
} | |
} | |
Function Find-Lockout { | |
<# | |
.SYNOPSIS | |
Find all users that are locked out | |
.DESCRIPTION | |
Finds all users that are locked out | |
.PARAMETER Unlock | |
Unlock all those locked out | |
.EXAMPLE | |
Find-Lockouts -Unlock | |
Unlocks all locked users | |
.EXAMPLE | |
Unlocker | |
menu to unlock users | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[CmdletBinding()] | |
[Alias('Unlocker')] | |
[Alias('WhosLocked')] | |
Param([Switch]$Unlock) | |
Add-Type -AssemblyName PresentationFramework | |
$LockedOutUsers = Search-ADAccount -LockedOut | |
If (-not $Credential) { | |
If (Show-SavedCredential | Where-Object {$_.Keys -eq 'MySAUser'}) { | |
$Credential = Get-SavedCredential -Id 'MySAUser' | |
} Else { | |
Get-Credential | |
Register-SACreds | |
} | |
$Credential = Get-Credential | |
} Else { | |
$Credential = $Credential | |
} | |
If ($Unlock -OR ($MyInvocation.InvocationName -eq 'Unlocker')) { | |
If ($LockedOutUsers) { | |
### Function to test for a specific account lockout (verify) | |
Function Get-UserLockedOut { | |
<# | |
.SYNOPSIS | |
Find lockout status of a specific user | |
.DESCRIPTION | |
Finds current lockout status of a specific user by samaccountname | |
.PARAMETER CheckUser | |
The user to check if locked out. | |
.EXAMPLE | |
Get-UserLockedOut testuser | |
#> | |
Param ( | |
[Parameter( | |
Mandatory = $true, | |
HelpMessage = 'Username required' | |
)] | |
[String]$CheckUser | |
) | |
$lockstatus = Get-ADUser -Identity $CheckUser -Properties LockedOut -Server $script:PDC | | |
Select-Object -Property Name, @{n='Username';e={$_.SamAccountName}}, LockedOut | |
$lockstatus = $lockstatus | Select-Object -Property Username, Name, LockedOut | |
Return $lockstatus | |
} | |
### 1. Get list of lockouts | |
$StepOne = Search-ADAccount -LockedOut | | |
Select-Object -Property Name, @{n='Username';e={$_.SamAccountName}} | | |
Sort-Object -Property Name | |
### 2. Put up menu (gridview) of locked accounts or tell user none were found | |
$StepTwo = If ($StepOne) { | |
#SINGLE $StepOne | Select-Object -Property Username,Name | Out-GridView -Title "User unlocker $(Get-Date)" -OutputMode Single | |
$StepOne | | |
Select-Object -Property Username, Name | | |
Out-GridView -Title "User unlocker $(Get-Date)" -Passthru | |
} Else { | |
[Windows.MessageBox]::Show('No locked out users found') | |
} | |
### 3. Check if a username was selected, and if-so unlock | |
If ($StepTwo.Username) { | |
### MULTIPLE | |
ForEach ($lockedUser in $StepTwo) { | |
#If ($lockedUser.Username){ | |
#SINGLE $lockeduser = $StepTwo.Username | |
$lockedusername = $lockedUser.Username | |
$unlocks += $lockedusername | |
#SINGLE Get-ADUser $lockeduser | Unlock-ADAccount | |
Invoke-Command -ComputerName $PDC -Credential $Credential -ScriptBlock { | |
[CmdletBinding()] | |
Param ([string]$user) | |
Get-ADUser -Identity $user -Server $script:PDC | | |
Unlock-ADAccount | |
} -ArgumentList $lockedusername | |
} | |
} Else { | |
WH -t 'No user selected' -f Ye | |
} | |
### 4. Verify account was unlocked | |
### MULTIPLE | |
ForEach ($verification in $unlocks) { | |
#SINGLE If ($StepTwo.Username){ | |
$v = Get-UserLockedOut -Checkuser $verification | |
If ($v.Lockedout -eq $false) { | |
#SINGLE Write-Host "Unlocked: $($lockeduser.name)" -ForegroundColor Green | |
WH -t ('Unlocked: {0}' -f $v.name) -f Gr | |
Return | |
} Else { | |
#SINGLE Write-Host "Unable to unlock $($lockeduser.name)" -ForegroundColor Red | |
WH -t ('Unable to unlock {0}' -f $v.name) -f Re | |
#SINGLE $lockedUser.DistinguishedName | |
$v.DistinguishedName | |
Return | |
} | |
} | |
$LockedOutUsers | Select-object -Property SamAccountName, Name | |
} Else { | |
WH -t 'Checked for user lockouts - none found.' -f Gr | |
} | |
} Else { | |
If ($LockedOutUsers) { | |
$LockedOutUsers | Select-Object -Property SamAccountName, Name | |
} Else { | |
WH -t 'No locked out users to report' -f Gr | |
} | |
} | |
} | |
Function Get-ADNestedGroupMembers { | |
<# | |
.SYNOPSIS | |
added displayname to the output, changed name to samaccountname in case of user objects. | |
.DESCRIPTION | |
Get nested group membership from a given group or a number of groups. | |
Function enumerates members of a given AD group recursively along with nesting level and parent group information. | |
It also displays if each user account is enabled. | |
When used with an -indent switch, it will display only names, but in a more user-friendly way (sort of a tree view) | |
.EXAMPLE | |
Get-ADNestedGroupMembers "MyGroup" | Export-CSV .\NedstedMembers.csv -NoTypeInformation | |
.EXAMPLE | |
Get-ADGroup -filter {Name -like "*MyGroup*"} | Get-ADNestedGroupMembers | ft -autosize | |
.EXAMPLE | |
Get-ADNestedGroupMembers "MyGroup" -indent | |
.INPUTS | |
String | |
.OUTPUTS | |
String | |
#> | |
[Alias('GetMembers')] | |
Param ( | |
[Parameter( | |
ValuefromPipeline = $true, | |
HelpMessage = 'Name of the Group', | |
Mandatory = $true | |
)] | |
[String]$GroupName, | |
[Int]$nesting = -1, | |
[Int]$Circular = $null, | |
[Switch]$Indent | |
) | |
Function Format-Indent { | |
[CmdletBinding()] | |
Param ($List) | |
ForEach ($Line in $List) { | |
$Space = $null | |
For ($i=0;$i -lt $Line.Nesting;$i++) {$Space += ' '} | |
$Line.Name = "$Space" + "$($Line.Name)" | |
} | |
Return $List | |
} | |
$Table = $NestedMembers = $ADGroupName = $null | |
$Nesting++ | |
$ADGroupName = Get-ADGroup -Identity $GroupName -Properties MemberOf,Members | |
$MemberOf = $ADGroupName | Select-Object -ExpandProperty MemberOf | |
Write-Verbose -Message ('Checking group: {0}' -f $ADGroupName.Name) | |
If ($ADGroupName) { | |
If ($Circular) { | |
$NestedMembers = Get-ADGroupMember -Identity $GroupName -Recursive | |
$Circular = $null | |
} Else { | |
$NestedMembers = Get-ADGroupMember -Identity $GroupName | Sort-Object -Property objectClass -Descending | |
If (!($NestedMembers)) { | |
$Unknown = $ADGroupName | Select-Object -ExpandProperty Members | |
If ($Unknown) { | |
$NestedMembers = @() | |
ForEach ($Member in $Unknown){$NestedMembers += Get-ADObject -Identity $Member} | |
} | |
} | |
} | |
ForEach ($NestedMember in $NestedMembers) { | |
$Props = @{ | |
Type = $NestedMember.objectClass | |
Name = $NestedMember.Name | |
DisplayName = '' | |
ParentGroup = $ADGroupName.Name | |
Enabled = '' | |
Nesting = $Nesting | |
DN = $NestedMember.DistinguishedName | |
Comment = '' | |
} | |
If ($NestedMember.objectclass -eq 'user') { | |
$NestedADMember = Get-ADUser -Identity $NestedMember -Properties Enabled,DisplayName,Description | |
$Table = New-Object -TypeName PSObject -Property $props | |
$Table.Enabled = $NestedADMember.Enabled | |
$Table.Name = $NestedADMember.SamAccountName | |
$Table.DisplayName = $NestedADMember.DisplayName | |
$Table.Comment = $NestedADMember.Description | |
If ($Indent) { | |
Format-Indent -List $Table | Select-Object -Property @{N='Name';E={"$($_.Name) ($($_.DisplayName))"}} | |
} Else { | |
$Table | Select-Object -Property Type, Name, DisplayName, ParentGroup, Nesting, Enabled, DN, Comment | |
} | |
} ElseIf ($NestedMember.objectclass -eq 'group') { | |
$Table = New-Object -TypeName PSObject -Property $props | |
If ($MemberOf -contains $NestedMember.DistinguishedName) { | |
$Table.Comment = 'Circular membership' | |
$Circular = 1 | |
} | |
If ($Indent) { | |
Format-Indent -List $Table | Select-Object -Property Name,Comment | Foreach-Object { | |
If ($_.Comment -ne ''){ | |
WH -t ('{0} (Circular Membership)' -f $_.Name) -f Re | |
} Else { | |
WH -t ('{0}' -f $_.Name) -f Ye | |
} | |
} | |
} Else { | |
$Table | Select-Object -Property Type, Name, DisplayName, ParentGroup, Nesting, Enabled, DN, Comment | |
} | |
If ($Indent) { | |
Get-ADNestedGroupMembers -GroupName $NestedMember.distinguishedName -nesting $Nesting -circular $Circular -indent | |
} Else { | |
Get-ADNestedGroupMembers -GroupName $NestedMember.distinguishedName -nesting $Nesting -circular $Circular | |
} | |
} Else { | |
If ($NestedMember) { | |
$Table = New-Object -TypeName PSObject -Property $props | |
If ($Indent) { | |
Format-Indent -List $Table | Select-Object -Property Name | |
} Else { | |
$Table | Select-Object -Property Type, Name, DisplayName, ParentGroup, Nesting, Enabled, DN, Comment | |
} | |
} | |
} | |
} | |
} | |
} | |
Function Get-NewUsers { | |
<# | |
.SYNOPSIS | |
Get newly created users. | |
.DESCRIPTION | |
Get all newly created users within a specified amount of days. | |
If you choose -ft or -grid, you can only choose one. | |
If you choose both, ft is selected by default. | |
.PARAMETER cutoff | |
How many days old must a user be to be considered 'New'. | |
.PARAMETER app | |
Users created by app are put into root/Users. | |
.PARAMETER ft | |
Format output as Table | |
.PARAMETER grid | |
Format output as grid | |
.EXAMPLE | |
Get-NewUsers -cutoff 5 -app | |
show newly created users created in the past 5 days only in the root/Users OU. | |
.EXAMPLE | |
Get-NewUsers -cutoff 5 | |
Shows all users everywhere created in the past 5 days. | |
Describe what this call does | |
.INPUTS | |
String | |
.OUTPUTS | |
Array | |
#> | |
[Alias('fnu')] | |
Param ( | |
[Parameter( | |
Position = 0, | |
HelpMessage = 'Days old', | |
Mandatory = $true, | |
ValueFromPipelineByPropertyName = $true | |
)] | |
[Int]$cutoff, | |
[Switch]$app, | |
[Switch]$ft, | |
[Switch]$grid | |
) | |
If ($ft -and $grid) {$grid = $false} | |
$DateCutOff = (Get-Date).AddDays(-$cutoff) | |
If ($app) { | |
$fetchParams = @{ | |
Filter = '*' | |
SearchBase = 'CN=Users,DC=shermco,DC=ind' | |
Properties = 'CanonicalName', | |
'Company', | |
'Department', | |
'Description', | |
'EmployeeID', | |
'Enabled', | |
'GivenName', | |
'Surname', | |
'Title', | |
'whenCreated', | |
'extensionAttribute7' | |
} | |
} Else { | |
$fetchParams = @{ | |
Filter = '*' | |
Properties = 'CanonicalName', | |
'Company', | |
'Department', | |
'Description', | |
'EmployeeID', | |
'Enabled', | |
'GivenName', | |
'Surname', | |
'Title', | |
'whenCreated', | |
'extensionAttribute7' | |
} | |
} | |
$trSel = @{ | |
Property = 'SamAccountName', | |
'Name', | |
#'UserPrincipalName', | |
#'GivenName', | |
#'Surname', | |
'EmployeeID', | |
'Enabled', | |
'Company', | |
'Title', | |
'Department', | |
@{n='exAt7';e={$_.extensionAttribute7}}, | |
'whenCreated', | |
#'Description', | |
@{n='Container';e={Get-Container -can $_.CanonicalName}} | |
} | |
$toReturn = Get-ADUser @fetchParams | | |
Where-Object {$_.whenCreated -gt $datecutoff} | | |
Select-Object @trSel | | |
Sort-Object -Property 'Container', 'whenCreated' | |
If ($ft) { | |
$toReturn | Format-Table | |
} ElseIf ($grid) { | |
$toReturn | Out-GridView -Title ('{0} Users - Created in the past {1} Days' -f $toReturn.Count, $cutoff) | |
} Else { | |
Return $toReturn | |
} | |
} | |
Function Get-TreeStart { | |
<# | |
.SYNOPSIS | |
Get org chart tree start. | |
.DESCRIPTION | |
Attempt to figure out where an org chart tree begins. | |
.EXAMPLE | |
Get-TreeStart | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
<# | |
### This is where we figure out where to start our tree from (highest person listed in AD with most number of Direct Reports) | |
Get all users where: | |
* (They are enabled) AND | |
* (They have a title) AND | |
* (their name does not contain 'test') AND | |
* (they have someone directlyreporting to them | |
* and get the extended attributes of Manager/DirectReports/Title as well -- store in $treeStarter | |
#> | |
$tsParam = @{ | |
Filter = '(Enabled -eq $true) -and (title -like "*") -and (name -notlike "*test*") -and (DirectReports -ne 0)' | |
Properties = 'Manager', 'DirectReports', 'Title' | |
} | |
$treeStarter = Get-ADUser @tsParam | | |
Where-Object {$null -eq $_.Manager} | | |
Select-Object -Property SamAccountName, Name, Title, @{n='DR';e={($_.directreports).count}} | | |
### Sort by dr then by name in descending order (if eyeball verifying, add " | formt-table" on the | |
### end of this line and only run from 'get-aduser' to 'format-table' to see the results) | |
Sort-Object -Property DR, Name -Descending | | |
Select-Object -First 1 | | |
Select-Object -ExpandProperty SamAccountName | |
Return $treeStarter | |
} | |
Function Get-OrgChart { | |
<# | |
.SYNOPSIS | |
display an on-screen org chart based on directreports in AD | |
.DESCRIPTION | |
Will utlize DirectReports attribute in AD to create and visually represent org chart tree on screen | |
.PARAMETER | |
start - give a username to start the tree from | |
.EXAMPLE | |
Get-OrgChart eWilliams | |
Draws an Org chart on-screen starting with Ed at the top | |
.EXAMPLE | |
Get-OrgChart | |
No username was specified so the script figures out who's logically the CEO and starts from there. | |
.INPUTS | |
String | |
.OUTPUTS | |
Stream | |
#> | |
Param ( | |
[Parameter(Position=0)][String]$start, | |
[Switch]$noLegend | |
) | |
Begin { | |
### We use $count to declare how far into the tre we are. 0 is the very top | |
$count = 0 | |
Function Get-DirectReports { | |
### $args is the argument given to the function which should be the user to start the tree building from | |
ForEach ($user in $args) { | |
### $currUser - get-aduser for the current user, include the attributes of Enabled,Title,Company,GivenName,SN (SurName),Department, and EmployeeId | |
$currUser = (Get-ADUser -Identity $user -Properties Enabled, Title, Company, GivenName, SN, Department, EmployeeId) | |
### Define what character set to use ('--') to indent as we expand through the tree... | |
### and how many times to use it depending on how far into the tree we are ("* $count") | |
$spacing = '--' * $count | |
### If the current user is enabled | |
If ($currUser.Enabled -eq $true) { | |
### Write what the count level we're at is (heirarchy level) -- don't line break | |
WH -t "$($count) " -f Ma -n | |
### If the current user EmployeeId field is populated, display it | |
### If thy don't, space over enough so the indentation aligns. -- dont line break | |
If ($currUser.EmployeeId) { | |
WH -t "$($currUser.EmployeeId) " -f Ma -n | |
} Else { | |
WH -t ' ' -n | |
} | |
### Re-create their proper name using their GivenName and SurName -- don't line break | |
WH -t "$($spacing) $($currUser.GivenName) $($currUser.SN) " -n | |
### include a separator to distinguish between the users name and everything else -- don't line break | |
WH -t '- ' -f DkCy -n | |
### Display whtever is in their Title field -- don't line break | |
WH -t "$($currUser.Title.trim()) " -f Cy -n | |
### If the user Department attribute has data... | |
If ($currUser.Department){ | |
### if the data in the Department field is 6 characters long, display in green -- don't line break | |
If ((($currUser.Department | out-string).trim() | Measure-Object -Character).Characters -eq 6) { | |
WH -t "[$($currUser.Department)] " -f Gr -n | |
} Else { | |
### If the data in the Department field is not 6 characters (less/greater than) display it in Yellow -- don't line break | |
WH -t "[$($currUser.Department)] " -f Ye -n | |
} | |
} Else { | |
### If the user Department attribute is empty, display our brackets in Red -- don't line break | |
WH -t "[$($currUser.Department)] " -f Re -n | |
} | |
### If the Company attribute has data... | |
If ($currUser.Company) { | |
### Display the information in the Company field | |
WH -t "($($currUser.Company))" -f Cy | |
} Else { | |
### If the Company attribute is empty, display '(NA)' in Red | |
WH -t '(NA)' -f Re | |
} | |
} Else { | |
### If the current user is disabled, all of the code is the same with one exception | |
WH -t "$($count) " -f Ma -n | |
If ($currUser.EmployeeId) { | |
WH -t "$($currUser.EmployeeId) " -f Ma -n | |
} Else { | |
WH -t ' ' -n | |
} | |
WH -t "$($spacing) " -n | |
### Since the user is disabled, Write that in Red -- don't line break | |
WH -t '[Disabled] ' -f Re -n | |
WH -t "$($currUser.GivenName) $($currUser.SN) " -n | |
WH -t '- ' -f DkCy -n | |
WH -t "$($currUser.Title) " -f Ye -n | |
If ($currUser.Department) { | |
If ((($currUser.Department | Out-String).Trim() | Measure-Object -Character).Characters -eq 6) { | |
WH -t "[$($currUser.Department)] " -f Gr -n | |
} Else { | |
WH -t "[$($currUser.Department)] " -f Ye -n | |
} | |
} Else { | |
WH -t "[$($currUser.Department)] " -f Re -n | |
} | |
If ($currUser.Company){ | |
WH -t "($($currUser.Company))" -f Cy | |
} Else { | |
WH -t '(NA)' -f Re | |
} | |
} | |
$count++ | |
Get-ADUser -Identity $user -Properties DirectReports | Select-Object -ExpandProperty DirectReports | ForEach-Object {Get-DirectReports $_} | |
$count-- | |
} | |
} | |
} | |
Process { | |
If ($start) { | |
$RootUser = $start | |
} Else { | |
$RootUser = Get-TreeStart | |
} | |
Get-DirectReports $RootUser | |
If (-not $noLegend) { | |
WH -t "`n --------- Legend ---------- " -f Ye | |
WH -t ' X E00000 : ' -f Ma -n | |
WH -t 'Number of levels between that person and the source along with EmployeeID (if populated).' | |
WH -t ' ------ : ' -n | |
WH -t 'Visual representation of depth' | |
WH -t ' Name : ' -n | |
WH -t 'Name ' -n | |
WH -t 'May be prefixed with ' -n | |
WH -t '[Disabled]' -f Re -n | |
WH -t ' to maybe revisit later.' | |
WH -t ' Title : ' -n | |
WH -t 'Cyan' -f Cy | |
WH -t ' Department: ' -n | |
WH -t 'Green = Good, ' -f Gr -n | |
WH -t 'Yellow = Bad, ' -f Ye -n | |
WH -t 'Red = empty' -f Re | |
WH -t ' Company : ' -n | |
WH -t 'Cyan' -f Cy -n | |
WH -t ' - If empty: ' -n | |
WH -t '(NA)' -f Re | |
} | |
} | |
} | |
Function Show-Everyone { | |
<# | |
.SYNOPSIS | |
Show everyone who is enabled | |
.DESCRIPTION | |
Will show name,company,title,description,username,license, and manager for all enabled users | |
.EXAMPLE | |
Show-Everyone | |
Raw output | |
.EXAMPLE | |
Show-Everyone -Grid | |
Out to Gridview | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
#Requires -Module ActiveDirectory | |
[CmdletBinding()] | |
[Alias('everyone')] | |
Param ([Switch]$Grid) | |
$pi = 0 | |
$Progress = @{ | |
Activity = 'Working through users . . .' | |
CurrentOperation = 'Loading' | |
PercentComplete = 0 | |
} | |
### Fetch Users | |
$EveryoneParams = @{ | |
Filter = 'Enabled -eq $true -and Company -like "*" -and Title -like "*" -and Department -like "*"' | |
Properties = 'DisplayName', | |
'Enabled', | |
'Company', | |
'Department', | |
'Title', | |
'Manager', | |
'Description', | |
'EmployeeID', | |
'EmailAddress', | |
'GivenName', | |
'sn', | |
'CanonicalName' | |
} | |
$ActiveUsers = Get-ADUser @EveryoneParams | |
### Organize users and add to array | |
$ActiveEveryone = @() | |
Foreach ($aUser in $ActiveUsers) { | |
$ProperName = "$($aUser.GivenName) $($aUser.sn)" | |
$pi++ | |
[Int]$percentage = ($pi / $ActiveUsers.Count)*100 | |
$Progress.CurrentOperation = "$pi of $($ActiveUsers.Count) - $($aUser.Name)" | |
$Progress.PercentComplete = $percentage | |
Write-Progress @Progress | |
$ActiveEveryone += [PSCustomObject][Ordered]@{ | |
UserName = $aUser.SamAccountName | |
DisplayName = $aUser.DisplayName | |
ProperName = $ProperName | |
Enabled = $aUser.Enabled | |
Company = $aUser.Company | |
Department = $aUser.Department | |
Title = $aUser.Title | |
Manager = If ($aUser.Manager){($aUser.Manager).split('OU')[0].trimend(',').split('=')[1].replace('\','')}; | |
Description = $aUser.Description | |
EmployeeID = $aUser.EmployeeID | |
EmailAddress = $aUser.EmailAddress | |
Container = $aUser.CanonicalName -ireplace '\/[^\/]+$','' | |
} | |
} | |
#region Cleanup | |
Write-Progress -Activity 'Working through users . . .' -Status 'Ready' -Completed | |
$ActiveEveryone = $ActiveEveryone | Sort-Object -Property EmployeeID | |
Remove-Variable -Name ActiveUsers | |
#endregion Cleanup | |
If (-not $Grid) { | |
Return $ActiveEveryone | |
} Else { | |
$ActiveEveryone | Out-GridView -Title "EVERYONE! $($ActiveEveryone.Count) - $(Get-Date)" | |
Remove-Variable -Name ActiveEveryone | |
} | |
} | |
#endregion User | |
#region Reminders | |
Function script:365reminder { | |
WH -t ' • Connect-AzureActiveDirectory ' -f Ye -n | |
WH -t ' Connects to Azure Active Directory' -f Cy | |
WH -t ' • Connect-AzureRMS ' -f Ye -n | |
WH -t ' Connects to Azure Rights Management' -f Cy | |
WH -t ' • Connect-ExchangeOnline ' -f Ye -n | |
WH -t ' Connects to Exchange Online' -f Cy | |
WH -t ' • Connect-ExchangeOnlinev2 ' -f Ye -n | |
WH -t ' Connects to Exchange Online using REST module' -f Cy | |
WH -t ' • Connect-SkypeOnline ' -f Ye -n | |
WH -t ' Connects to Skype for Business Online' -f Cy | |
WH -t ' • Connect-EOP ' -f Ye -n | |
WH -t ' Connects to Exchange Online Protection' -f Cy | |
WH -t ' • Connect-ComplianceCenter ' -f Ye -n | |
WH -t ' Connects to Compliance Center' -f Cy | |
WH -t ' • Connect-SharePointOnline ' -f Ye -n | |
WH -t ' Connects to SharePoint Online' -f Cy | |
WH -t ' • Connect-MSTeams ' -f Ye -n | |
WH -t ' Connects to Microsoft Teams' -f Cy | |
WH -t ' • Get-Office365Credentials ' -f Ye -n | |
WH -t ' Gets Office 365 credentials' -f Cy | |
WH -t ' • Connect-ExchangeOnPremises ' -f Ye -n | |
WH -t ' Connects to Exchange On-Premises' -f Cy | |
WH -t ' • Get-OnPremisesCredentials ' -f Ye -n | |
WH -t ' Gets On-Premises credentials' -f Cy | |
WH -t ' • Get-ExchangeOnPremisesFQDN ' -f Ye -n | |
WH -t ' Gets FQDN for Exchange On-Premises' -f Cy | |
WH -t ' • Get-Office365Tenant ' -f Ye -n | |
WH -t ' Gets Office 365 tenant name' -f Cy | |
WH -t ' • Set-Office365Environment ' -f Ye -n | |
WH -t " Configures Uri's and region to use" -f Cy | |
WH -t ' • Update-Office365Modules ' -f Ye -n | |
WH -t ' Updates supported Office 365 modules' -f Cy | |
WH -t ' • Report-Office365Modules ' -f Ye -n | |
WH -t ' Report on known vs online module versions' -f Cy | |
$DOTS = '••••' | |
WH -t $DOTS -f Re -n | |
WH -t ' Use ' -f Ye -n | |
WH -t 'load365 ' -f Cy -n | |
WH -t ' to load 365 connectors ' -f Ye -n | |
WH -t $DOTS -f Re | |
WH -t $DOTS -f Re -n | |
WH -t ' Use ' -f Ye -n | |
WH -t '365reminder' -f Cy -n | |
WH -t ' for a reminder of the 365 plugins ' -f Ye -n | |
WH -t $DOTS -f Re | |
} | |
Function Get-Reminder { | |
<# | |
.SYNOPSIS | |
Brief reminder of some commands in this module. | |
.DESCRIPTION | |
Highlight of some commands in this module. | |
.EXAMPLE | |
Get-Reminder | |
.INPUTS | |
None | |
.OUTPUTS | |
Stream | |
#> | |
WH -t "This is just a slight overview of commands:`r`n" -f Ye | |
WH -t ' --- Operational -------------------------------------------------------' -f Ma | |
### Get-Container (container) | |
WH -t ' • HR - Changes a disk size to human readable' -f Ye | |
WH -t ' • DU - Display Disk Usage on a directory' -f Ye | |
WH -t ' • DF - Display Drive information' -f Ye | |
WH -t ' • DiskUsage - Get disk usage ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'Get-DiskFree ' -f Cy -n | |
WH -t 'servername ' -f Re -n | |
WH -t '-- ' -f Ye -n | |
WH -t '[' -f Ma -n | |
WH -t 'add ' -f Gr -n | |
WH -t '-format ' -f Cy -n | |
WH -t 'to make output more readable' -f Gr -n | |
WH -t ']' -f Ma -n | |
WH -t ')' -f Ye | |
WH -t ' • Grep - Find a string' -f Ye | |
### Read-OpenFileDialog | |
WH -t ' • Tail - Follow a log file' -f Ye | |
### Get-UniquePerms | |
WH -t ' • Touch - Create a blank file' -f Ye | |
WH -t ' • SUDO - Run next command as admin' -f Ye | |
### Out-ExcelClip (clipXL) | |
WH -t ' • SU - Start new Admin session' -f Ye | |
WH -t ' • UpdateModules - Checks installed PS modules and updates accordingly' -f Ye | |
### Install-WinUpdates | |
### Update-JProfile | |
WH -t ' --- Domain ------------------------------------------------------------' -f Ma | |
WH -t ' • GetDCs - Get domain controller list with roles' -f Ye | |
WH -t ' • GetDHCPs - Get list of DHCP servers' -f Ye | |
WH -t ' • GetDNS - Get list of DNS Servers' -f Ye | |
WH -t ' • Find-PrintServers - Finds print servers on the network' -f Ye | |
### Get-EmptyOUs | |
### Get-SchemaVersion | |
WH -t ' --- User --------------------------------------------------------------' -f Ma | |
WH -t ' • WhosLocked - List all locked out users ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'whoslocked ' -f Cy -n | |
WH -t '| ' -n | |
WH -t 'ft' -f Cy -n | |
WH -t ')' -f Ye -n | |
WH -t ' -- or -- ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'unlocker' -f Cy -n | |
WH -t ')' -f Ye | |
### Get-CurrentUser | |
WH -t ' • Get-Phones - Get phone list' -f Ye | |
WH -t ' • Get-Exts - Get phone extension if listed ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'GetExts ' -f Cy -n | |
WH -t 'john' -f Re -n | |
WH -t ')' -f Ye | |
WH -t ' • WhosOn - Get whos on a PC' -f Ye | |
### Get-Mgr (gmgr) | |
WH -t ' • FUser - Find all users who even resemble search ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'fuser ' -f Cy -n | |
WH -t 'jessica ' -f Re -n | |
WH -t '| ' -n | |
WH -t 'select name ' -f Cy -n | |
WH -t '| ' -n | |
WH -t 'ft' -f Cy -n | |
WH -t '(' -f Ye | |
WH -t ' • Flid - Find an EmployeeID' -f Ye | |
WH -t ' • FindDPT - Find matches to Description, Dept fields, or Title' -f Ye | |
WH -t ' • FNU - Get New Users ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'fnu ' -f Cy -n | |
WH -t '5' -f Re -n | |
WH -t ' -- ' -f Ye -n | |
WH -t '[' -f Ma -n | |
WH -t 'add ' -f Gr -n | |
WH -t '-app ' -f Cy -n | |
WH -t 'to see App-Created Users.' -f Gr -n | |
WH -t ' | ' -f Ye -n | |
WH -t 'use ' -f Gr -n | |
WH -t '-ft ' -f Cy -n | |
WH -t 'or ' -f Gr -n | |
WH -t '-grid' -f Cy -n | |
WH -t ' to format output.' -f Gr -n | |
WH -t ']' -f Ma -n | |
WH -t ')' -f Ye | |
### Search-Position (FindDPT) | |
WH -t ' • Everyone - Show all users' -f Ye | |
### Get-OrgChart | |
WH -t ' • Get-ADFSLocks - Find all ADFS lock events for a user' -f Ye | |
WH -t ' • Get-UserRestore - Restore auto-Disabled user ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'restoreuser' -f Cy -n | |
WH -t ')' -f Ye | |
WH -t ' • Deny-User - Disabled user(s) ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'killuser' -f Cy -n | |
WH -t ')' -f Ye | |
WH -t ' --- Group -------------------------------------------------------------' -f Ma | |
WH -t ' • GetMembers - Get all users of a group even if nested' -f Ye | |
### Get-EmptyGroupDetails | |
WH -t ' --- Computer ----------------------------------------------------------' -f Ma | |
WH -t ' • GetVitals - Get basic info from a computer ' -f Ye -n | |
WH -t '(' -f Ye -n | |
WH -t 'Get-ComputerInfo ' -f Cy -n | |
WH -t 'testmachine01' -f Re -n | |
WH -t ')' -f Ye | |
WH -t ' • Get-Serials - Get serial numbers from PCs and monitors' -f Ye | |
### Get-SystemInfo | |
### Get-TrustStatus | |
WH -t ' • FPuter - Find all computers who even resemble search word' -f Ye | |
WH -t ' • StalePCs - Get list of dead computer objects' -f Ye | |
### Show-SysInfos | |
### Get-OutDatedOS | |
### Get-StalePCs | |
#WH ' • DHCPReport - Get DHCP Report' -f Ye | |
#WH ' • UsersOn - Runs WhosOn for a set of machines' -f Ye | |
$DOTS = '••••' | |
WH -t ' ' | |
WH -t $DOTS -f Re -n | |
WH -t ' Use ' -f Ye -n | |
WH -t 'Get-Help <Command Name>' -f Cy -n | |
WH -t ' for help ' -f Ye -n | |
WH -t $DOTS -f Re | |
WH -t $DOTS -f Re -n | |
WH -t ' Use ' -f Ye -n | |
WH -t 'reminder' -f Cy -n | |
WH -t ' to get this reminder of functions ' -f Ye -n | |
WH -t $DOTS -f Re | |
WH -t $DOTS -f Re -n | |
WH -t ' Use ' -f Ye -n | |
WH -t 'Show-Commands' -f Cy -n | |
WH -t ' for a full list of cmdlets ' -f Ye -n | |
WH -t $DOTS -f Re | |
WH -t $DOTS -f Re -n | |
WH -t ' Use ' -f Ye -n | |
WH -t 'Show-Alias' -f Cy -n | |
WH -t ' for a full list of aliases from ' -f Ye -n | |
WH -t 'Show-Commands ' -f Cy -n | |
WH -t $DOTS -f Re | |
WH -t $DOTS -f Re -n | |
WH -t ' Use ' -f Ye -n | |
WH -t '365reminder' -f Cy -n | |
WH -t ' for a reminder of the 365 plugins ' -f Ye -n | |
WH -t $DOTS -f Re | |
WH -t ' ' | |
} | |
$script:helper = (Get-Module -Name $profile -ListAvailable | Select-Object -ExpandProperty ExportedCommands).Values | |
Function Show-Commands { | |
<# | |
.SYNOPSIS | |
Show commands in this module. | |
.DESCRIPTION | |
Shows all functions within this module. | |
.EXAMPLE | |
Show-Commands | |
Describe what this call does | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
$mh = @() | |
$temp = $helper | |
Foreach ($c in $temp) { | |
$ho = [PsCustomObject][Ordered]@{ | |
Name = $c.Name | |
Alias = (Get-Alias -Definition $c.Name -ErrorAction SilentlyContinue).Name | |
Description = $((Get-Help -Name $c.Name).Description).Text | |
} | |
$mh += $ho | |
} | |
$res = $mh | Sort-Object -Property Name | |
Return $res | |
} | |
Function Show-Alias { | |
<# | |
.SYNOPSIS | |
Show Aliases for Shermco-Module Functions. | |
.DESCRIPTION | |
Show Aliases for Shermco-Module Functions. | |
.EXAMPLE | |
Show-Alias | |
Describe what this call does | |
.INPUTS | |
None | |
.OUTPUTS | |
Array | |
#> | |
($helper | ForEach-Object {Get-Alias -Definition $_.Name -ErrorAction SilentlyContinue}) | | |
Select-Object -Property @{n='Function';e={$_.Definition}}, @{n='Alias';e={$_.Name}} | |
} | |
#endregion Reminders | |
#endregion Functions | |
#region Customizations | |
$PSDefaultParameterValues = @{ | |
'Export-Csv:Delimiter' = ',' | |
'Export-Csv:Encoding' = 'UTF8' | |
'Export-Csv:NoTypeInformation' = $true | |
'Convertto-Csv:Delimiter' = ',' | |
'Convertto-Csv:NoTypeInformation' = $true | |
} | |
#endregion Customizations | |
#region Cosmetics | |
$script:Root = Test-Administrator | |
If ($Host.Name -eq 'ConsoleHost') { | |
Get-Elevation | |
Set-WindowTitle | |
Set-PSReadlineOption -HistoryNoDuplicates | |
Set-PSReadlineOption -HistorySearchCursorMovesToEnd | |
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward | |
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward | |
Set-PSReadlineKeyHandler -Key 'Ctrl+[' -Function CaptureScreen | |
Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete | |
Set-PSReadlineOption -ShowToolTips -BellStyle None | |
} | |
#endregion | |
#region Prompt | |
$script:PromptSettings = [PSCustomObject] @{ | |
Separator = ' > ' | |
OpeningBrace = '[' | |
ClosingBrace = ']' | |
DefaultForegroundColor = $Host.UI.RawUI.ForegroundColor | |
DefaultBackgroundColor = $Host.UI.RawUI.BackgroundColor | |
IsAdminForeGroundColor = [ConsoleColor]::DarkGray | |
IsAdminBackGroundColor = [ConsoleColor]::Red | |
UserForegroundColor = [ConsoleColor]::Gray | |
UserBackgroundColor = [ConsoleColor]::DarkBlue | |
LocationForegroundColor = [ConsoleColor]::White | |
LocationBackgroundColor = [ConsoleColor]::DarkBlue | |
ElevatedPrompt = '#' | |
StandardPrompt = '$' | |
PromptForegroundColor = [ConsoleColor]::DarkCyan | |
PromptBackgroundColor = [ConsoleColor]::DarkBlue | |
PromptErrorForegroundColor = [ConsoleColor]::White | |
PromptErrorBackgroundColor = [ConsoleColor]::Red | |
AddedSymbol = '+' | |
ModifiedSymbol = '~' | |
DeletedSymbol = '-' | |
UnmergedSymbol = '?' | |
Delimiter = ' |' | |
} | |
Function script:Prompt { | |
# Locking on console, we need to remember to use the mutex name "ConsoleMtx" | |
$mtx = New-Object -TypeName System.Threading.Mutex -ArgumentList ($false, 'ConsoleMtx') | |
$null = $mtx.WaitOne() | |
$Script:Last = $? | |
$s = $script:PromptSettings | |
#$U = '[{0}@{1}' -f $env:USERNAME.ToLower(), $env:COMPUTERNAME.ToLower() | |
$U = '[{0}' -f $env:USERNAME.ToLower() | |
Write-Host $U -NoNewLine -ForegroundColor $s.UserForegroundColor -BackgroundColor $s.UserBackgroundColor | |
Write-Host $s.Separator -NoNewLine -ForegroundColor magenta -BackgroundColor $s.LocationBackgroundColor | |
$Location = '{0}] ' -f ((Get-Location).Path.Replace($env:USERPROFILE, '~')) | |
Write-Host $Location -NoNewLine -BackgroundColor $s.LocationBackgroundColor -ForegroundColor $s.LocationForegroundColor | |
If ($Script:Last) { | |
$promptForegroundColor = $s.PromptForegroundColor | |
$promptBackgroundColor = $s.PromptBackgroundColor | |
} Else { | |
$promptForegroundColor = $s.PromptErrorForegroundColor | |
$promptBackgroundColor = $s.PromptErrorBackgroundColor | |
} | |
If ($script:Root) { | |
$p = $s.ElevatedPrompt | |
} else { | |
$p = $s.StandardPrompt | |
} | |
Write-Host $p -NoNewLine -ForegroundColor $promptForegroundColor -BackgroundColor $promptBackgroundColor | |
$null = $mtx.ReleaseMutex() | |
$mtx.Dispose() | |
Return ' ' | |
} | |
#endregion Prompt | |
#region playful quotes typed out | |
Function Greetings { | |
$strings = "How about a nice game of chess?`n", | |
"Would you like to play a game?`n", | |
"How about a nice game of Global Thermonuclear War.`n", | |
"The primary goal is to win the game.`n", | |
"The only winning move is not to play`n" | |
Write-Host "> Greetings Professor Falken . . .`n> " -NoNewLine -ForegroundColor Gray #-BackgroundColor Black | |
#$string = "Greetings Professor Falken...`nShall we play a game?`n" | |
Start-Sleep -milliseconds 500 | |
$string = Get-Random -InputObject $strings | |
$Random = New-Object -TypeName System.Random | |
$string -split '' | ForEach-Object { | |
Write-Host $_ -nonew -ForegroundColor Gray #-BackgroundColor Black | |
Start-Sleep -milliseconds $(1 + $Random.Next(60)) | |
} | |
} | |
#endregion | |
Get-reminder |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment