PSSharedGoods.psm1
function Write-Color { <# .SYNOPSIS Write-Color is a wrapper around Write-Host delivering a lot of additional features for easier color options. .DESCRIPTION Write-Color is a wrapper around Write-Host delivering a lot of additional features for easier color options. It provides: - Easy manipulation of colors, - Logging output to file (log) - Nice formatting options out of the box. - Ability to use aliases for parameters .PARAMETER Text Text to display on screen and write to log file if specified. Accepts an array of strings. .PARAMETER Color Color of the text. Accepts an array of colors. If more than one color is specified it will loop through colors for each string. If there are more strings than colors it will start from the beginning. Available colors are: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER BackGroundColor Color of the background. Accepts an array of colors. If more than one color is specified it will loop through colors for each string. If there are more strings than colors it will start from the beginning. Available colors are: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White .PARAMETER StartTab Number of tabs to add before text. Default is 0. .PARAMETER LinesBefore Number of empty lines before text. Default is 0. .PARAMETER LinesAfter Number of empty lines after text. Default is 0. .PARAMETER StartSpaces Number of spaces to add before text. Default is 0. .PARAMETER LogFile Path to log file. If not specified no log file will be created. .PARAMETER DateTimeFormat Custom date and time format string. Default is yyyy-MM-dd HH:mm:ss .PARAMETER LogTime If set to $true it will add time to log file. Default is $true. .PARAMETER LogRetry Number of retries to write to log file, in case it can't write to it for some reason, before skipping. Default is 2. .PARAMETER Encoding Encoding of the log file. Default is Unicode. .PARAMETER ShowTime Switch to add time to console output. Default is not set. .PARAMETER NoNewLine Switch to not add new line at the end of the output. Default is not set. .PARAMETER NoConsoleOutput Switch to not output to console. Default all output goes to console. .EXAMPLE Write-Color -Text "Red ", "Green ", "Yellow " -Color Red,Green,Yellow .EXAMPLE Write-Color -Text "This is text in Green ", "followed by red ", "and then we have Magenta... ", "isn't it fun? ", "Here goes DarkCyan" -Color Green,Red,Magenta,White,DarkCyan .EXAMPLE Write-Color -Text "This is text in Green ", "followed by red ", "and then we have Magenta... ", "isn't it fun? ", "Here goes DarkCyan" -Color Green,Red,Magenta,White,DarkCyan -StartTab 3 -LinesBefore 1 -LinesAfter 1 .EXAMPLE Write-Color "1. ", "Option 1" -Color Yellow, Green Write-Color "2. ", "Option 2" -Color Yellow, Green Write-Color "3. ", "Option 3" -Color Yellow, Green Write-Color "4. ", "Option 4" -Color Yellow, Green Write-Color "9. ", "Press 9 to exit" -Color Yellow, Gray -LinesBefore 1 .EXAMPLE Write-Color -LinesBefore 2 -Text "This little ","message is ", "written to log ", "file as well." ` -Color Yellow, White, Green, Red, Red -LogFile "C:\testing.txt" -TimeFormat "yyyy-MM-dd HH:mm:ss" Write-Color -Text "This can get ","handy if ", "want to display things, and log actions to file ", "at the same time." ` -Color Yellow, White, Green, Red, Red -LogFile "C:\testing.txt" .EXAMPLE Write-Color -T "My text", " is ", "all colorful" -C Yellow, Red, Green -B Green, Green, Yellow Write-Color -t "my text" -c yellow -b green Write-Color -text "my text" -c red .EXAMPLE Write-Color -Text "Testuję czy się ładnie zapisze, czy będą problemy" -Encoding unicode -LogFile 'C:\temp\testinggg.txt' -Color Red -NoConsoleOutput .NOTES Understanding Custom date and time format strings: https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings Project support: https://github.com/EvotecIT/PSWriteColor Original idea: Josh (https://stackoverflow.com/users/81769/josh) #> [alias('Write-Colour')] [CmdletBinding()] param ( [alias ('T')] [String[]]$Text, [alias ('C', 'ForegroundColor', 'FGC')] [ConsoleColor[]]$Color = [ConsoleColor]::White, [alias ('B', 'BGC')] [ConsoleColor[]]$BackGroundColor = $null, [alias ('Indent')][int] $StartTab = 0, [int] $LinesBefore = 0, [int] $LinesAfter = 0, [int] $StartSpaces = 0, [alias ('L')] [string] $LogFile = '', [Alias('DateFormat', 'TimeFormat')][string] $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss', [alias ('LogTimeStamp')][bool] $LogTime = $true, [int] $LogRetry = 2, [ValidateSet('unknown', 'string', 'unicode', 'bigendianunicode', 'utf8', 'utf7', 'utf32', 'ascii', 'default', 'oem')][string]$Encoding = 'Unicode', [switch] $ShowTime, [switch] $NoNewLine, [alias('HideConsole')][switch] $NoConsoleOutput ) if (-not $NoConsoleOutput) { $DefaultColor = $Color[0] if ($null -ne $BackGroundColor -and $BackGroundColor.Count -ne $Color.Count) { Write-Error "Colors, BackGroundColors parameters count doesn't match. Terminated." return } if ($LinesBefore -ne 0) { for ($i = 0; $i -lt $LinesBefore; $i++) { Write-Host -Object "`n" -NoNewline } } if ($StartTab -ne 0) { for ($i = 0; $i -lt $StartTab; $i++) { Write-Host -Object "`t" -NoNewline } } if ($StartSpaces -ne 0) { for ($i = 0; $i -lt $StartSpaces; $i++) { Write-Host -Object ' ' -NoNewline } } if ($ShowTime) { Write-Host -Object "[$([datetime]::Now.ToString($DateTimeFormat))] " -NoNewline } if ($Text.Count -ne 0) { if ($Color.Count -ge $Text.Count) { if ($null -eq $BackGroundColor) { for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -NoNewline } } else { for ($i = 0; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackGroundColor[$i] -NoNewline } } } else { if ($null -eq $BackGroundColor) { for ($i = 0; $i -lt $Color.Length ; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -NoNewline } for ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $DefaultColor -NoNewline } } else { for ($i = 0; $i -lt $Color.Length ; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $Color[$i] -BackgroundColor $BackGroundColor[$i] -NoNewline } for ($i = $Color.Length; $i -lt $Text.Length; $i++) { Write-Host -Object $Text[$i] -ForegroundColor $DefaultColor -BackgroundColor $BackGroundColor[0] -NoNewline } } } } if ($NoNewLine -eq $true) { Write-Host -NoNewline } else { Write-Host } if ($LinesAfter -ne 0) { for ($i = 0; $i -lt $LinesAfter; $i++) { Write-Host -Object "`n" -NoNewline } } } if ($Text.Count -and $LogFile) { $TextToFile = "" for ($i = 0; $i -lt $Text.Length; $i++) { $TextToFile += $Text[$i] } $Saved = $false $Retry = 0 Do { $Retry++ try { if ($LogTime) { "[$([datetime]::Now.ToString($DateTimeFormat))] $TextToFile" | Out-File -FilePath $LogFile -Encoding $Encoding -Append -ErrorAction Stop -WhatIf:$false } else { "$TextToFile" | Out-File -FilePath $LogFile -Encoding $Encoding -Append -ErrorAction Stop -WhatIf:$false } $Saved = $true } catch { if ($Saved -eq $false -and $Retry -eq $LogRetry) { Write-Warning "Write-Color - Couldn't write to log file $($_.Exception.Message). Tried ($Retry/$LogRetry))" } else { Write-Warning "Write-Color - Couldn't write to log file $($_.Exception.Message). Retrying... ($Retry/$LogRetry)" } } } Until ($Saved -eq $true -or $Retry -ge $LogRetry) } } function Get-PSRegistryDictionaries { [cmdletBinding()] param() if ($Script:Dictionary) { return } $Script:Dictionary = @{ 'HKUAD:' = 'HKEY_ALL_USERS_DEFAULT' 'HKUA:' = 'HKEY_ALL_USERS' 'HKUD:' = 'HKEY_DEFAULT_USER' 'HKUDUD:' = 'HKEY_ALL_DOMAIN_USERS_DEFAULT' 'HKUDU:' = 'HKEY_ALL_DOMAIN_USERS' 'HKUDUO:' = 'HKEY_ALL_DOMAIN_USERS_OTHER' 'HKUDUDO:' = 'HKEY_ALL_DOMAIN_USERS_OTHER_DEFAULT' 'HKCR:' = 'HKEY_CLASSES_ROOT' 'HKCU:' = 'HKEY_CURRENT_USER' 'HKLM:' = 'HKEY_LOCAL_MACHINE' 'HKU:' = 'HKEY_USERS' 'HKCC:' = 'HKEY_CURRENT_CONFIG' 'HKDD:' = 'HKEY_DYN_DATA' 'HKPD:' = 'HKEY_PERFORMANCE_DATA' } $Script:HiveDictionary = [ordered] @{ 'HKEY_ALL_USERS_DEFAULT' = 'All+Default' 'HKUAD' = 'All+Default' 'HKEY_ALL_USERS' = 'All' 'HKUA' = 'All' 'HKEY_ALL_DOMAIN_USERS_DEFAULT' = 'AllDomain+Default' 'HKUDUD' = 'AllDomain+Default' 'HKEY_ALL_DOMAIN_USERS' = 'AllDomain' 'HKUDU' = 'AllDomain' 'HKEY_DEFAULT_USER' = 'Default' 'HKUD' = 'Default' 'HKEY_ALL_DOMAIN_USERS_OTHER' = 'AllDomain+Other' 'HKUDUO' = 'AllDomain+Other' 'HKUDUDO' = 'AllDomain+Other+Default' 'HKEY_ALL_DOMAIN_USERS_OTHER_DEFAULT' = 'AllDomain+Other+Default' 'HKEY_CLASSES_ROOT' = 'ClassesRoot' 'HKCR' = 'ClassesRoot' 'ClassesRoot' = 'ClassesRoot' 'HKCU' = 'CurrentUser' 'HKEY_CURRENT_USER' = 'CurrentUser' 'CurrentUser' = 'CurrentUser' 'HKLM' = 'LocalMachine' 'HKEY_LOCAL_MACHINE' = 'LocalMachine' 'LocalMachine' = 'LocalMachine' 'HKU' = 'Users' 'HKEY_USERS' = 'Users' 'Users' = 'Users' 'HKCC' = 'CurrentConfig' 'HKEY_CURRENT_CONFIG' = 'CurrentConfig' 'CurrentConfig' = 'CurrentConfig' 'HKDD' = 'DynData' 'HKEY_DYN_DATA' = 'DynData' 'DynData' = 'DynData' 'HKPD' = 'PerformanceData' 'HKEY_PERFORMANCE_DATA ' = 'PerformanceData' 'PerformanceData' = 'PerformanceData' } $Script:ReverseTypesDictionary = [ordered] @{ 'REG_SZ' = 'string' 'REG_NONE' = 'none' 'REG_EXPAND_SZ' = 'expandstring' 'REG_BINARY' = 'binary' 'REG_DWORD' = 'dword' 'REG_MULTI_SZ' = 'multistring' 'REG_QWORD' = 'qword' 'string' = 'string' 'expandstring' = 'expandstring' 'binary' = 'binary' 'dword' = 'dword' 'multistring' = 'multistring' 'qword' = 'qword' 'none' = 'none' } } $Script:RGBColors = [ordered] @{ None = $null AirForceBlue = 93, 138, 168 Akaroa = 195, 176, 145 AlbescentWhite = 227, 218, 201 AliceBlue = 240, 248, 255 Alizarin = 227, 38, 54 Allports = 18, 97, 128 Almond = 239, 222, 205 AlmondFrost = 159, 129, 112 Amaranth = 229, 43, 80 Amazon = 59, 122, 87 Amber = 255, 191, 0 Amethyst = 153, 102, 204 AmethystSmoke = 156, 138, 164 AntiqueWhite = 250, 235, 215 Apple = 102, 180, 71 AppleBlossom = 176, 92, 82 Apricot = 251, 206, 177 Aqua = 0, 255, 255 Aquamarine = 127, 255, 212 Armygreen = 75, 83, 32 Arsenic = 59, 68, 75 Astral = 54, 117, 136 Atlantis = 164, 198, 57 Atomic = 65, 74, 76 AtomicTangerine = 255, 153, 102 Axolotl = 99, 119, 91 Azure = 240, 255, 255 Bahia = 176, 191, 26 BakersChocolate = 93, 58, 26 BaliHai = 124, 152, 171 BananaMania = 250, 231, 181 BattleshipGrey = 85, 93, 80 BayOfMany = 35, 48, 103 Beige = 245, 245, 220 Bermuda = 136, 216, 192 Bilbao = 42, 128, 0 BilobaFlower = 181, 126, 220 Bismark = 83, 104, 114 Bisque = 255, 228, 196 Bistre = 61, 43, 31 Bittersweet = 254, 111, 94 Black = 0, 0, 0 BlackPearl = 31, 38, 42 BlackRose = 85, 31, 47 BlackRussian = 23, 24, 43 BlanchedAlmond = 255, 235, 205 BlizzardBlue = 172, 229, 238 Blue = 0, 0, 255 BlueDiamond = 77, 26, 127 BlueMarguerite = 115, 102, 189 BlueSmoke = 115, 130, 118 BlueViolet = 138, 43, 226 Blush = 169, 92, 104 BokaraGrey = 22, 17, 13 Bole = 121, 68, 59 BondiBlue = 0, 147, 175 Bordeaux = 88, 17, 26 Bossanova = 86, 60, 92 Boulder = 114, 116, 114 Bouquet = 183, 132, 167 Bourbon = 170, 108, 57 Brass = 181, 166, 66 BrickRed = 199, 44, 72 BrightGreen = 102, 255, 0 BrightRed = 146, 43, 62 BrightTurquoise = 8, 232, 222 BrilliantRose = 243, 100, 162 BrinkPink = 250, 110, 121 BritishRacingGreen = 0, 66, 37 Bronze = 205, 127, 50 Brown = 165, 42, 42 BrownPod = 57, 24, 2 BuddhaGold = 202, 169, 6 Buff = 240, 220, 130 Burgundy = 128, 0, 32 BurlyWood = 222, 184, 135 BurntOrange = 255, 117, 56 BurntSienna = 233, 116, 81 BurntUmber = 138, 51, 36 ButteredRum = 156, 124, 56 CadetBlue = 95, 158, 160 California = 224, 141, 60 CamouflageGreen = 120, 134, 107 Canary = 255, 255, 153 CanCan = 217, 134, 149 CannonPink = 145, 78, 117 CaputMortuum = 89, 39, 32 Caramel = 255, 213, 154 Cararra = 237, 230, 214 Cardinal = 179, 33, 52 CardinGreen = 18, 53, 36 CareysPink = 217, 152, 160 CaribbeanGreen = 0, 222, 164 Carmine = 175, 0, 42 CarnationPink = 255, 166, 201 CarrotOrange = 242, 142, 28 Cascade = 141, 163, 153 CatskillWhite = 226, 229, 222 Cedar = 67, 48, 46 Celadon = 172, 225, 175 Celeste = 207, 207, 196 Cello = 55, 79, 107 Cement = 138, 121, 93 Cerise = 222, 49, 99 Cerulean = 0, 123, 167 CeruleanBlue = 42, 82, 190 Chantilly = 239, 187, 204 Chardonnay = 255, 200, 124 Charlotte = 167, 216, 222 Charm = 208, 116, 139 Chartreuse = 127, 255, 0 ChartreuseYellow = 223, 255, 0 ChelseaCucumber = 135, 169, 107 Cherub = 246, 214, 222 Chestnut = 185, 78, 72 ChileanFire = 226, 88, 34 Chinook = 150, 200, 162 Chocolate = 210, 105, 30 Christi = 125, 183, 0 Christine = 181, 101, 30 Cinnabar = 235, 76, 66 Citron = 159, 169, 31 Citrus = 141, 182, 0 Claret = 95, 25, 51 ClassicRose = 251, 204, 231 ClayCreek = 145, 129, 81 Clinker = 75, 54, 33 Clover = 74, 93, 35 Cobalt = 0, 71, 171 CocoaBrown = 44, 22, 8 Cola = 60, 48, 36 ColumbiaBlue = 166, 231, 255 CongoBrown = 103, 76, 71 Conifer = 178, 236, 93 Copper = 218, 138, 103 CopperRose = 153, 102, 102 Coral = 255, 127, 80 CoralRed = 255, 64, 64 CoralTree = 173, 111, 105 Coriander = 188, 184, 138 Corn = 251, 236, 93 CornField = 250, 240, 190 Cornflower = 147, 204, 234 CornflowerBlue = 100, 149, 237 Cornsilk = 255, 248, 220 Cosmic = 132, 63, 91 Cosmos = 255, 204, 203 CostaDelSol = 102, 93, 30 CottonCandy = 255, 188, 217 Crail = 164, 90, 82 Cranberry = 205, 96, 126 Cream = 255, 255, 204 CreamCan = 242, 198, 73 Crimson = 220, 20, 60 Crusta = 232, 142, 90 Cumulus = 255, 255, 191 Cupid = 246, 173, 198 CuriousBlue = 40, 135, 200 Cyan = 0, 255, 255 Cyprus = 6, 78, 64 DaisyBush = 85, 53, 146 Dandelion = 250, 218, 94 Danube = 96, 130, 182 DarkBlue = 0, 0, 139 DarkBrown = 101, 67, 33 DarkCerulean = 8, 69, 126 DarkChestnut = 152, 105, 96 DarkCoral = 201, 90, 73 DarkCyan = 0, 139, 139 DarkGoldenrod = 184, 134, 11 DarkGray = 169, 169, 169 DarkGreen = 0, 100, 0 DarkGreenCopper = 73, 121, 107 DarkGrey = 169, 169, 169 DarkKhaki = 189, 183, 107 DarkMagenta = 139, 0, 139 DarkOliveGreen = 85, 107, 47 DarkOrange = 255, 140, 0 DarkOrchid = 153, 50, 204 DarkPastelGreen = 3, 192, 60 DarkPink = 222, 93, 131 DarkPurple = 150, 61, 127 DarkRed = 139, 0, 0 DarkSalmon = 233, 150, 122 DarkSeaGreen = 143, 188, 143 DarkSlateBlue = 72, 61, 139 DarkSlateGray = 47, 79, 79 DarkSlateGrey = 47, 79, 79 DarkSpringGreen = 23, 114, 69 DarkTangerine = 255, 170, 29 DarkTurquoise = 0, 206, 209 DarkViolet = 148, 0, 211 DarkWood = 130, 102, 68 DeepBlush = 245, 105, 145 DeepCerise = 224, 33, 138 DeepKoamaru = 51, 51, 102 DeepLilac = 153, 85, 187 DeepMagenta = 204, 0, 204 DeepPink = 255, 20, 147 DeepSea = 14, 124, 97 DeepSkyBlue = 0, 191, 255 DeepTeal = 24, 69, 59 Denim = 36, 107, 206 DesertSand = 237, 201, 175 DimGray = 105, 105, 105 DimGrey = 105, 105, 105 DodgerBlue = 30, 144, 255 Dolly = 242, 242, 122 Downy = 95, 201, 191 DutchWhite = 239, 223, 187 EastBay = 76, 81, 109 EastSide = 178, 132, 190 EchoBlue = 169, 178, 195 Ecru = 194, 178, 128 Eggplant = 162, 0, 109 EgyptianBlue = 16, 52, 166 ElectricBlue = 125, 249, 255 ElectricIndigo = 111, 0, 255 ElectricLime = 208, 255, 20 ElectricPurple = 191, 0, 255 Elm = 47, 132, 124 Emerald = 80, 200, 120 Eminence = 108, 48, 130 Endeavour = 46, 88, 148 EnergyYellow = 245, 224, 80 Espresso = 74, 44, 42 Eucalyptus = 26, 162, 96 Falcon = 126, 94, 96 Fallow = 204, 153, 102 FaluRed = 128, 24, 24 Feldgrau = 77, 93, 83 Feldspar = 205, 149, 117 Fern = 113, 188, 120 FernGreen = 79, 121, 66 Festival = 236, 213, 64 Finn = 97, 64, 81 FireBrick = 178, 34, 34 FireBush = 222, 143, 78 FireEngineRed = 211, 33, 45 Flamingo = 233, 92, 75 Flax = 238, 220, 130 FloralWhite = 255, 250, 240 ForestGreen = 34, 139, 34 Frangipani = 250, 214, 165 FreeSpeechAquamarine = 0, 168, 119 FreeSpeechRed = 204, 0, 0 FrenchLilac = 230, 168, 215 FrenchRose = 232, 83, 149 FriarGrey = 135, 134, 129 Froly = 228, 113, 122 Fuchsia = 255, 0, 255 FuchsiaPink = 255, 119, 255 Gainsboro = 220, 220, 220 Gallery = 219, 215, 210 Galliano = 204, 160, 29 Gamboge = 204, 153, 0 Ghost = 196, 195, 208 GhostWhite = 248, 248, 255 Gin = 216, 228, 188 GinFizz = 247, 231, 206 Givry = 230, 208, 171 Glacier = 115, 169, 194 Gold = 255, 215, 0 GoldDrop = 213, 108, 43 GoldenBrown = 150, 113, 23 GoldenFizz = 240, 225, 48 GoldenGlow = 248, 222, 126 GoldenPoppy = 252, 194, 0 Goldenrod = 218, 165, 32 GoldenSand = 233, 214, 107 GoldenYellow = 253, 238, 0 GoldTips = 225, 189, 39 GordonsGreen = 37, 53, 41 Gorse = 255, 225, 53 Gossamer = 49, 145, 119 GrannySmithApple = 168, 228, 160 Gray = 128, 128, 128 GrayAsparagus = 70, 89, 69 Green = 0, 128, 0 GreenLeaf = 76, 114, 29 GreenVogue = 38, 67, 72 GreenYellow = 173, 255, 47 Grey = 128, 128, 128 GreyAsparagus = 70, 89, 69 GuardsmanRed = 157, 41, 51 GumLeaf = 178, 190, 181 Gunmetal = 42, 52, 57 Hacienda = 155, 135, 12 HalfAndHalf = 232, 228, 201 HalfBaked = 95, 138, 139 HalfColonialWhite = 246, 234, 190 HalfPearlLusta = 240, 234, 214 HanPurple = 63, 0, 255 Harlequin = 74, 255, 0 HarleyDavidsonOrange = 194, 59, 34 Heather = 174, 198, 207 Heliotrope = 223, 115, 255 Hemp = 161, 122, 116 Highball = 134, 126, 54 HippiePink = 171, 75, 82 Hoki = 110, 127, 128 HollywoodCerise = 244, 0, 161 Honeydew = 240, 255, 240 Hopbush = 207, 113, 175 HorsesNeck = 108, 84, 30 HotPink = 255, 105, 180 HummingBird = 201, 255, 229 HunterGreen = 53, 94, 59 Illusion = 244, 152, 173 InchWorm = 202, 224, 13 IndianRed = 205, 92, 92 Indigo = 75, 0, 130 InternationalKleinBlue = 0, 24, 168 InternationalOrange = 255, 79, 0 IrisBlue = 28, 169, 201 IrishCoffee = 102, 66, 40 IronsideGrey = 113, 112, 110 IslamicGreen = 0, 144, 0 Ivory = 255, 255, 240 Jacarta = 61, 50, 93 JackoBean = 65, 54, 40 JacksonsPurple = 46, 45, 136 Jade = 0, 171, 102 JapaneseLaurel = 47, 117, 50 Jazz = 93, 43, 44 JazzberryJam = 165, 11, 94 JellyBean = 68, 121, 142 JetStream = 187, 208, 201 Jewel = 0, 107, 60 Jon = 79, 58, 60 JordyBlue = 124, 185, 232 Jumbo = 132, 132, 130 JungleGreen = 41, 171, 135 KaitokeGreen = 30, 77, 43 Karry = 255, 221, 202 KellyGreen = 70, 203, 24 Keppel = 93, 164, 147 Khaki = 240, 230, 140 Killarney = 77, 140, 87 KingfisherDaisy = 85, 27, 140 Kobi = 230, 143, 172 LaPalma = 60, 141, 13 LaserLemon = 252, 247, 94 Laurel = 103, 146, 103 Lavender = 230, 230, 250 LavenderBlue = 204, 204, 255 LavenderBlush = 255, 240, 245 LavenderPink = 251, 174, 210 LavenderRose = 251, 160, 227 LawnGreen = 124, 252, 0 LemonChiffon = 255, 250, 205 LightBlue = 173, 216, 230 LightCoral = 240, 128, 128 LightCyan = 224, 255, 255 LightGoldenrodYellow = 250, 250, 210 LightGray = 211, 211, 211 LightGreen = 144, 238, 144 LightGrey = 211, 211, 211 LightPink = 255, 182, 193 LightSalmon = 255, 160, 122 LightSeaGreen = 32, 178, 170 LightSkyBlue = 135, 206, 250 LightSlateGray = 119, 136, 153 LightSlateGrey = 119, 136, 153 LightSteelBlue = 176, 196, 222 LightYellow = 255, 255, 224 Lilac = 204, 153, 204 Lime = 0, 255, 0 LimeGreen = 50, 205, 50 Limerick = 139, 190, 27 Linen = 250, 240, 230 Lipstick = 159, 43, 104 Liver = 83, 75, 79 Lochinvar = 86, 136, 125 Lochmara = 38, 97, 156 Lola = 179, 158, 181 LondonHue = 170, 152, 169 Lotus = 124, 72, 72 LuckyPoint = 29, 41, 81 MacaroniAndCheese = 255, 189, 136 Madang = 193, 249, 162 Madras = 81, 65, 0 Magenta = 255, 0, 255 MagicMint = 170, 240, 209 Magnolia = 248, 244, 255 Mahogany = 215, 59, 62 Maire = 27, 24, 17 Maize = 230, 190, 138 Malachite = 11, 218, 81 Malibu = 93, 173, 236 Malta = 169, 154, 134 Manatee = 140, 146, 172 Mandalay = 176, 121, 57 MandarianOrange = 146, 39, 36 Mandy = 191, 79, 81 Manhattan = 229, 170, 112 Mantis = 125, 194, 66 Manz = 217, 230, 80 MardiGras = 48, 25, 52 Mariner = 57, 86, 156 Maroon = 128, 0, 0 Matterhorn = 85, 85, 85 Mauve = 244, 187, 255 Mauvelous = 255, 145, 175 MauveTaupe = 143, 89, 115 MayaBlue = 119, 181, 254 McKenzie = 129, 97, 60 MediumAquamarine = 102, 205, 170 MediumBlue = 0, 0, 205 MediumCarmine = 175, 64, 53 MediumOrchid = 186, 85, 211 MediumPurple = 147, 112, 219 MediumRedViolet = 189, 51, 164 MediumSeaGreen = 60, 179, 113 MediumSlateBlue = 123, 104, 238 MediumSpringGreen = 0, 250, 154 MediumTurquoise = 72, 209, 204 MediumVioletRed = 199, 21, 133 MediumWood = 166, 123, 91 Melon = 253, 188, 180 Merlot = 112, 54, 66 MetallicGold = 211, 175, 55 Meteor = 184, 115, 51 MidnightBlue = 25, 25, 112 MidnightExpress = 0, 20, 64 Mikado = 60, 52, 31 MilanoRed = 168, 55, 49 Ming = 54, 116, 125 MintCream = 245, 255, 250 MintGreen = 152, 255, 152 Mischka = 168, 169, 173 MistyRose = 255, 228, 225 Moccasin = 255, 228, 181 Mojo = 149, 69, 53 MonaLisa = 255, 153, 153 Mongoose = 179, 139, 109 Montana = 53, 56, 57 MoodyBlue = 116, 108, 192 MoonYellow = 245, 199, 26 MossGreen = 173, 223, 173 MountainMeadow = 28, 172, 120 MountainMist = 161, 157, 148 MountbattenPink = 153, 122, 141 Mulberry = 211, 65, 157 Mustard = 255, 219, 88 Myrtle = 25, 89, 5 MySin = 255, 179, 71 NavajoWhite = 255, 222, 173 Navy = 0, 0, 128 NavyBlue = 2, 71, 254 NeonCarrot = 255, 153, 51 NeonPink = 255, 92, 205 Nepal = 145, 163, 176 Nero = 20, 20, 20 NewMidnightBlue = 0, 0, 156 Niagara = 58, 176, 158 NightRider = 59, 47, 47 Nobel = 152, 152, 152 Norway = 169, 186, 157 Nugget = 183, 135, 39 OceanGreen = 95, 167, 120 Ochre = 202, 115, 9 OldCopper = 111, 78, 55 OldGold = 207, 181, 59 OldLace = 253, 245, 230 OldLavender = 121, 104, 120 OldRose = 195, 33, 72 Olive = 128, 128, 0 OliveDrab = 107, 142, 35 OliveGreen = 181, 179, 92 Olivetone = 110, 110, 48 Olivine = 154, 185, 115 Onahau = 196, 216, 226 Opal = 168, 195, 188 Orange = 255, 165, 0 OrangePeel = 251, 153, 2 OrangeRed = 255, 69, 0 Orchid = 218, 112, 214 OuterSpace = 45, 56, 58 OutrageousOrange = 254, 90, 29 Oxley = 95, 167, 119 PacificBlue = 0, 136, 220 Padua = 128, 193, 151 PalatinatePurple = 112, 41, 99 PaleBrown = 160, 120, 90 PaleChestnut = 221, 173, 175 PaleCornflowerBlue = 188, 212, 230 PaleGoldenrod = 238, 232, 170 PaleGreen = 152, 251, 152 PaleMagenta = 249, 132, 239 PalePink = 250, 218, 221 PaleSlate = 201, 192, 187 PaleTaupe = 188, 152, 126 PaleTurquoise = 175, 238, 238 PaleVioletRed = 219, 112, 147 PalmLeaf = 53, 66, 48 Panache = 233, 255, 219 PapayaWhip = 255, 239, 213 ParisDaisy = 255, 244, 79 Parsley = 48, 96, 48 PastelGreen = 119, 221, 119 PattensBlue = 219, 233, 244 Peach = 255, 203, 164 PeachOrange = 255, 204, 153 PeachPuff = 255, 218, 185 PeachYellow = 250, 223, 173 Pear = 209, 226, 49 PearlLusta = 234, 224, 200 Pelorous = 42, 143, 189 Perano = 172, 172, 230 Periwinkle = 197, 203, 225 PersianBlue = 34, 67, 182 PersianGreen = 0, 166, 147 PersianIndigo = 51, 0, 102 PersianPink = 247, 127, 190 PersianRed = 192, 54, 44 PersianRose = 233, 54, 167 Persimmon = 236, 88, 0 Peru = 205, 133, 63 Pesto = 128, 117, 50 PictonBlue = 102, 153, 204 PigmentGreen = 0, 173, 67 PigPink = 255, 218, 233 PineGreen = 1, 121, 111 PineTree = 42, 47, 35 Pink = 255, 192, 203 PinkFlare = 191, 175, 178 PinkLace = 240, 211, 220 PinkSwan = 179, 179, 179 Plum = 221, 160, 221 Pohutukawa = 102, 12, 33 PoloBlue = 119, 158, 203 Pompadour = 129, 20, 83 Portage = 146, 161, 207 PotPourri = 241, 221, 207 PottersClay = 132, 86, 60 PowderBlue = 176, 224, 230 Prim = 228, 196, 207 PrussianBlue = 0, 58, 108 PsychedelicPurple = 223, 0, 255 Puce = 204, 136, 153 Pueblo = 108, 46, 31 PuertoRico = 67, 179, 174 Pumpkin = 255, 99, 28 Purple = 128, 0, 128 PurpleMountainsMajesty = 150, 123, 182 PurpleTaupe = 93, 57, 84 QuarterSpanishWhite = 230, 224, 212 Quartz = 220, 208, 255 Quincy = 106, 84, 69 RacingGreen = 26, 36, 33 RadicalRed = 255, 32, 82 Rajah = 251, 171, 96 RawUmber = 123, 63, 0 RazzleDazzleRose = 254, 78, 218 Razzmatazz = 215, 10, 83 Red = 255, 0, 0 RedBerry = 132, 22, 23 RedDamask = 203, 109, 81 RedOxide = 99, 15, 15 RedRobin = 128, 64, 64 RichBlue = 84, 90, 167 Riptide = 141, 217, 204 RobinsEggBlue = 0, 204, 204 RobRoy = 225, 169, 95 RockSpray = 171, 56, 31 RomanCoffee = 131, 105, 83 RoseBud = 246, 164, 148 RoseBudCherry = 135, 50, 96 RoseTaupe = 144, 93, 93 RosyBrown = 188, 143, 143 Rouge = 176, 48, 96 RoyalBlue = 65, 105, 225 RoyalHeath = 168, 81, 110 RoyalPurple = 102, 51, 152 Ruby = 215, 24, 104 Russet = 128, 70, 27 Rust = 192, 64, 0 RusticRed = 72, 6, 7 Saddle = 99, 81, 71 SaddleBrown = 139, 69, 19 SafetyOrange = 255, 102, 0 Saffron = 244, 196, 48 Sage = 143, 151, 121 Sail = 161, 202, 241 Salem = 0, 133, 67 Salmon = 250, 128, 114 SandyBeach = 253, 213, 177 SandyBrown = 244, 164, 96 Sangria = 134, 1, 17 SanguineBrown = 115, 54, 53 SanMarino = 80, 114, 167 SanteFe = 175, 110, 77 Sapphire = 6, 42, 120 Saratoga = 84, 90, 44 Scampi = 102, 102, 153 Scarlet = 255, 36, 0 ScarletGum = 67, 28, 83 SchoolBusYellow = 255, 216, 0 Schooner = 139, 134, 128 ScreaminGreen = 102, 255, 102 Scrub = 59, 60, 54 SeaBuckthorn = 249, 146, 69 SeaGreen = 46, 139, 87 Seagull = 140, 190, 214 SealBrown = 61, 12, 2 Seance = 96, 47, 107 SeaPink = 215, 131, 127 SeaShell = 255, 245, 238 Selago = 250, 230, 250 SelectiveYellow = 242, 180, 0 SemiSweetChocolate = 107, 68, 35 Sepia = 150, 90, 62 Serenade = 255, 233, 209 Shadow = 133, 109, 77 Shakespeare = 114, 160, 193 Shalimar = 252, 255, 164 Shamrock = 68, 215, 168 ShamrockGreen = 0, 153, 102 SherpaBlue = 0, 75, 73 SherwoodGreen = 27, 77, 62 Shilo = 222, 165, 164 ShipCove = 119, 139, 165 Shocking = 241, 156, 187 ShockingPink = 255, 29, 206 ShuttleGrey = 84, 98, 111 Sidecar = 238, 224, 177 Sienna = 160, 82, 45 Silk = 190, 164, 147 Silver = 192, 192, 192 SilverChalice = 175, 177, 174 SilverTree = 102, 201, 146 SkyBlue = 135, 206, 235 SlateBlue = 106, 90, 205 SlateGray = 112, 128, 144 SlateGrey = 112, 128, 144 Smalt = 0, 48, 143 SmaltBlue = 74, 100, 108 Snow = 255, 250, 250 SoftAmber = 209, 190, 168 Solitude = 235, 236, 240 Sorbus = 233, 105, 44 Spectra = 53, 101, 77 SpicyMix = 136, 101, 78 Spray = 126, 212, 230 SpringBud = 150, 255, 0 SpringGreen = 0, 255, 127 SpringSun = 236, 235, 189 SpunPearl = 170, 169, 173 Stack = 130, 142, 132 SteelBlue = 70, 130, 180 Stiletto = 137, 63, 69 Strikemaster = 145, 92, 131 StTropaz = 50, 82, 123 Studio = 115, 79, 150 Sulu = 201, 220, 135 SummerSky = 33, 171, 205 Sun = 237, 135, 45 Sundance = 197, 179, 88 Sunflower = 228, 208, 10 Sunglow = 255, 204, 51 SunsetOrange = 253, 82, 64 SurfieGreen = 0, 116, 116 Sushi = 111, 153, 64 SuvaGrey = 140, 140, 140 Swamp = 35, 43, 43 SweetCorn = 253, 219, 109 SweetPink = 243, 153, 152 Tacao = 236, 177, 118 TahitiGold = 235, 97, 35 Tan = 210, 180, 140 Tangaroa = 0, 28, 61 Tangerine = 228, 132, 0 TangerineYellow = 253, 204, 13 Tapestry = 183, 110, 121 Taupe = 72, 60, 50 TaupeGrey = 139, 133, 137 TawnyPort = 102, 66, 77 TaxBreak = 79, 102, 106 TeaGreen = 208, 240, 192 Teak = 176, 141, 87 Teal = 0, 128, 128 TeaRose = 255, 133, 207 Temptress = 60, 20, 33 Tenne = 200, 101, 0 TerraCotta = 226, 114, 91 Thistle = 216, 191, 216 TickleMePink = 245, 111, 161 Tidal = 232, 244, 140 TitanWhite = 214, 202, 221 Toast = 165, 113, 100 Tomato = 255, 99, 71 TorchRed = 255, 3, 62 ToryBlue = 54, 81, 148 Tradewind = 110, 174, 161 TrendyPink = 133, 96, 136 TropicalRainForest = 0, 127, 102 TrueV = 139, 114, 190 TulipTree = 229, 183, 59 Tumbleweed = 222, 170, 136 Turbo = 255, 195, 36 TurkishRose = 152, 119, 123 Turquoise = 64, 224, 208 TurquoiseBlue = 118, 215, 234 Tuscany = 175, 89, 62 TwilightBlue = 253, 255, 245 Twine = 186, 135, 89 TyrianPurple = 102, 2, 60 Ultramarine = 10, 17, 149 UltraPink = 255, 111, 255 Valencia = 222, 82, 70 VanCleef = 84, 61, 55 VanillaIce = 229, 204, 201 VenetianRed = 209, 0, 28 Venus = 138, 127, 128 Vermilion = 251, 79, 20 VeryLightGrey = 207, 207, 207 VidaLoca = 94, 140, 49 Viking = 71, 171, 204 Viola = 180, 131, 149 ViolentViolet = 50, 23, 77 Violet = 238, 130, 238 VioletRed = 255, 57, 136 Viridian = 64, 130, 109 VistaBlue = 159, 226, 191 VividViolet = 127, 62, 152 WaikawaGrey = 83, 104, 149 Wasabi = 150, 165, 60 Watercourse = 0, 106, 78 Wedgewood = 67, 107, 149 WellRead = 147, 61, 65 Wewak = 255, 152, 153 Wheat = 245, 222, 179 Whiskey = 217, 154, 108 WhiskeySour = 217, 144, 88 White = 255, 255, 255 WhiteSmoke = 245, 245, 245 WildRice = 228, 217, 111 WildSand = 229, 228, 226 WildStrawberry = 252, 65, 154 WildWatermelon = 255, 84, 112 WildWillow = 172, 191, 96 Windsor = 76, 40, 130 Wisteria = 191, 148, 228 Wistful = 162, 162, 208 Yellow = 255, 255, 0 YellowGreen = 154, 205, 50 YellowOrange = 255, 174, 66 YourPink = 244, 194, 194 } function Convert-BinaryToIP { [cmdletBinding()] param( [string] $Binary ) $Binary = $Binary -replace '\s+' if ($Binary.Length % 8) { Write-Warning -Message "Convert-BinaryToIP - Binary string '$Binary' is not evenly divisible by 8." return $Null } [int] $NumberOfBytes = $Binary.Length / 8 $Bytes = @(foreach ($i in 0..($NumberOfBytes - 1)) { try { [System.Convert]::ToByte($Binary.Substring(($i * 8), 8), 2) } catch { Write-Warning -Message "Convert-BinaryToIP - Error converting '$Binary' to bytes. `$i was $i." return $Null } }) return $Bytes -join '.' } function Convert-GenericRightsToFileSystemRights { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER OriginalRights Parameter description .EXAMPLE An example .NOTES .LINK Improved https://blog.cjwdev.co.uk/2011/06/28/permissions-not-included-in-net-accessrule-filesystemrights-enum/ #> [cmdletBinding()] param( [System.Security.AccessControl.FileSystemRights] $OriginalRights ) Begin { $FileSystemRights = [System.Security.AccessControl.FileSystemRights] $GenericRights = @{ GENERIC_READ = 0x80000000; GENERIC_WRITE = 0x40000000; GENERIC_EXECUTE = 0x20000000; GENERIC_ALL = 0x10000000; FILTER_GENERIC = 0x0FFFFFFF; } $MappedGenericRights = @{ FILE_GENERIC_EXECUTE = $FileSystemRights::ExecuteFile -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::ReadAttributes -bor $FileSystemRights::Synchronize FILE_GENERIC_READ = $FileSystemRights::ReadAttributes -bor $FileSystemRights::ReadData -bor $FileSystemRights::ReadExtendedAttributes -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::Synchronize FILE_GENERIC_WRITE = $FileSystemRights::AppendData -bor $FileSystemRights::WriteAttributes -bor $FileSystemRights::WriteData -bor $FileSystemRights::WriteExtendedAttributes -bor $FileSystemRights::ReadPermissions -bor $FileSystemRights::Synchronize FILE_GENERIC_ALL = $FileSystemRights::FullControl } } Process { $MappedRights = [System.Security.AccessControl.FileSystemRights]::new() if ($OriginalRights -band $GenericRights.GENERIC_EXECUTE) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_EXECUTE } if ($OriginalRights -band $GenericRights.GENERIC_READ) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_READ } if ($OriginalRights -band $GenericRights.GENERIC_WRITE) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_WRITE } if ($OriginalRights -band $GenericRights.GENERIC_ALL) { $MappedRights = $MappedRights -bor $MappedGenericRights.FILE_GENERIC_ALL } (($OriginalRights -bAND $GenericRights.FILTER_GENERIC) -bOR $MappedRights) -as $FileSystemRights } End { } } function Convert-IPToBinary { [cmdletBinding()] param( [string] $IP ) $IPv4Regex = '(?:(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)\.){3}(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)' $IP = $IP.Trim() if ($IP -match "\A${IPv4Regex}\z") { try { return ($IP.Split('.') | ForEach-Object { [System.Convert]::ToString([byte] $_, 2).PadLeft(8, '0') }) -join '' } catch { Write-Warning -Message "Convert-IPToBinary - Error converting '$IP' to a binary string: $_" return $Null } } else { Write-Warning -Message "Convert-IPToBinary - Invalid IP detected: '$IP'. Conversion failed." return $Null } } function ConvertFrom-HTML { [alias('Convert-HTMLToString')] [CmdletBinding()] param( [string[]] $HTML, [switch] $RemoveTags ) foreach ($H in $HTML) { if ($RemoveTags) { $H = $H -replace '<[^>]+>', '' } $H -replace '“', '"' -replace '’', "'" -replace '”', '"' -replace '…', '...' -replace '—', '-' -replace '–', '-' } } function ConvertTo-HkeyUser { [CmdletBinding()] param( [System.Collections.IDictionary] $HiveDictionary, [Array] $SubKeys, [string] $DictionaryKey, [string] $RegistryPath ) $OutputRegistryKeys = foreach ($Sub in $Subkeys) { if ($HiveDictionary[$DictionaryKey] -eq 'All') { if ($Sub -notlike "*_Classes*" -and $Sub -ne '.DEFAULT') { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'All+Default') { if ($Sub -notlike "*_Classes*") { if (-not $Script:DefaultRegistryMounted) { $Script:DefaultRegistryMounted = Mount-DefaultRegistryPath } if ($Sub -eq '.DEFAULT') { $RegistryPath.Replace($DictionaryKey, "Users\.DEFAULT_USER") } else { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } } } elseif ($HiveDictionary[$DictionaryKey] -eq 'Default') { if ($Sub -eq '.DEFAULT') { if (-not $Script:DefaultRegistryMounted) { $Script:DefaultRegistryMounted = Mount-DefaultRegistryPath } $RegistryPath.Replace($DictionaryKey, "Users\.DEFAULT_USER") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain+Default') { if (($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*") -or $Sub -eq '.DEFAULT') { if (-not $Script:DefaultRegistryMounted) { $Script:DefaultRegistryMounted = Mount-DefaultRegistryPath } if ($Sub -eq '.DEFAULT') { $RegistryPath.Replace($DictionaryKey, "Users\.DEFAULT_USER") } else { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } } } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain+Other') { if (($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*")) { if (-not $Script:OfflineRegistryMounted) { $Script:OfflineRegistryMounted = Mount-AllRegistryPath foreach ($Key in $Script:OfflineRegistryMounted.Keys) { $RegistryPath.Replace($DictionaryKey, "Users\$Key") } } $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain+Other+Default') { if (($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*") -or $Sub -eq '.DEFAULT') { if (-not $Script:DefaultRegistryMounted) { $Script:DefaultRegistryMounted = Mount-DefaultRegistryPath } if (-not $Script:OfflineRegistryMounted) { $Script:OfflineRegistryMounted = Mount-AllRegistryPath foreach ($Key in $Script:OfflineRegistryMounted.Keys) { $RegistryPath.Replace($DictionaryKey, "Users\$Key") } } if ($Sub -eq '.DEFAULT') { $RegistryPath.Replace($DictionaryKey, "Users\.DEFAULT_USER") } else { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } } } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain') { if ($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*") { $RegistryPath.Replace($DictionaryKey, "Users\$Sub") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'Users') { if ($Sub -like "Offline_*") { $Script:OfflineRegistryMounted = Mount-AllRegistryPath -MountUsers $Sub foreach ($Key in $Script:OfflineRegistryMounted.Keys) { if ($Script:OfflineRegistryMounted[$Key].Status -eq $true) { $RegistryPath } } } } } $OutputRegistryKeys | Sort-Object -Unique } function ConvertTo-StringByType { <# .SYNOPSIS Private function to use within ConvertTo-JsonLiteral .DESCRIPTION Private function to use within ConvertTo-JsonLiteral .PARAMETER Value Value to convert to JsonValue .PARAMETER Depth Specifies how many levels of contained objects are included in the JSON representation. The default value is 0. .PARAMETER AsArray Outputs the object in array brackets, even if the input is a single object. .PARAMETER DateTimeFormat Changes DateTime string format. Default "yyyy-MM-dd HH:mm:ss" .PARAMETER NumberAsString Provides an alternative serialization option that converts all numbers to their string representation. .PARAMETER BoolAsString Provides an alternative serialization option that converts all bool to their string representation. .PARAMETER PropertyName Uses PropertyNames provided by user (only works with Force) .PARAMETER ArrayJoin Forces any array to be a string regardless of depth level .PARAMETER ArrayJoinString Uses defined string or char for array join. By default it uses comma with a space when used. .PARAMETER Force Forces using property names from first object or given thru PropertyName parameter .EXAMPLE $Value = ConvertTo-StringByType -Value $($Object[$a][$i]) -DateTimeFormat $DateTimeFormat .NOTES General notes #> [cmdletBinding()] param( [Object] $Value, [int] $Depth, [int] $MaxDepth, [string] $DateTimeFormat, [switch] $NumberAsString, [switch] $BoolAsString, [System.Collections.IDictionary] $NewLineFormat = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $NewLineFormatProperty = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $AdvancedReplace, [System.Text.StringBuilder] $TextBuilder, [string[]] $PropertyName, [switch] $ArrayJoin, [string] $ArrayJoinString, [switch] $Force ) Process { if ($null -eq $Value) { "`"`"" } elseif ($Value -is [string]) { $Value = $Value.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormat.NewLineCarriage).Replace("`n", $NewLineFormat.NewLine).Replace("`r", $NewLineFormat.Carriage) foreach ($Key in $AdvancedReplace.Keys) { $Value = $Value.Replace($Key, $AdvancedReplace[$Key]) } "`"$Value`"" } elseif ($Value -is [DateTime]) { "`"$($($Value).ToString($DateTimeFormat))`"" } elseif ($Value -is [bool]) { if ($BoolAsString) { "`"$($Value)`"" } else { $Value.ToString().ToLower() } } elseif ($Value -is [System.Collections.IDictionary]) { if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { "`"$($Value)`"" } else { $Depth++ $null = $TextBuilder.AppendLine("{") for ($i = 0; $i -lt ($Value.Keys).Count; $i++) { $Property = ([string[]]$Value.Keys)[$i] $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $OutputValue = ConvertTo-StringByType -Value $Value[$Property] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -ArrayJoinString $ArrayJoinString -ArrayJoin:$ArrayJoin.IsPresent $null = $TextBuilder.Append("$OutputValue") if ($i -ne ($Value.Keys).Count - 1) { $null = $TextBuilder.AppendLine(',') } } $null = $TextBuilder.Append("}") } } elseif ($Value -is [System.Collections.IList] -or $Value -is [System.Collections.ReadOnlyCollectionBase]) { if ($ArrayJoin) { $Value = $Value -join $ArrayJoinString $Value = "$Value".Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) "`"$Value`"" } else { if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { $Value = "$Value".Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) "`"$Value`"" } else { $CountInternalObjects = 0 $null = $TextBuilder.Append("[") foreach ($V in $Value) { $CountInternalObjects++ if ($CountInternalObjects -gt 1) { $null = $TextBuilder.Append(',') } if ($Force -and -not $PropertyName) { $PropertyName = $V.PSObject.Properties.Name } elseif ($Force -and $PropertyName) { } else { $PropertyName = $V.PSObject.Properties.Name } $OutputValue = ConvertTo-StringByType -Value $V -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -PropertyName $PropertyName -ArrayJoinString $ArrayJoinString -ArrayJoin:$ArrayJoin.IsPresent $null = $TextBuilder.Append($OutputValue) } $null = $TextBuilder.Append("]") } } } elseif ($Value -is [System.Enum]) { "`"$($($Value).ToString())`"" } elseif (($Value | IsNumeric) -eq $true) { $Value = $($Value).ToString().Replace(',', '.') if ($NumberAsString) { "`"$Value`"" } else { $Value } } elseif ($Value -is [PSObject]) { if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { "`"$($Value)`"" } else { $Depth++ $CountInternalObjects = 0 $null = $TextBuilder.AppendLine("{") if ($Force -and -not $PropertyName) { $PropertyName = $Value.PSObject.Properties.Name } elseif ($Force -and $PropertyName) { } else { $PropertyName = $Value.PSObject.Properties.Name } foreach ($Property in $PropertyName) { $CountInternalObjects++ if ($CountInternalObjects -gt 1) { $null = $TextBuilder.AppendLine(',') } $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $OutputValue = ConvertTo-StringByType -Value $Value.$Property -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -ArrayJoinString $ArrayJoinString -ArrayJoin:$ArrayJoin.IsPresent $null = $TextBuilder.Append("$OutputValue") } $null = $TextBuilder.Append("}") } } else { $Value = $Value.ToString().Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) "`"$Value`"" } } } function Get-ComputerSMBInfo { [cmdletbinding()] param( [string] $ComputerName, [string[]] $Name, [switch] $SkipDiskSpace #, # [System.Management.Automation.PSCmdlet]$PSC ) $buffer = [IntPtr]::Zero $read = 0 $total = 0 $resume = 0 $res = [Win32Share.NativeMethods]::NetShareEnum( $ComputerName, 1, [ref]$buffer, ([UInt32]"0xFFFFFFFF"), [ref]$read, [ref]$total, [ref]$resume ) if ($res -ne 0) { $exp = [System.ComponentModel.Win32Exception]$res $er = [System.Management.Automation.ErrorRecord]::new( $exp, 'Win32Share.NativeMethods.GetSmbInf.RemoteException', [System.Management.Automation.ErrorCategory]::NotSpecified, $ComputerName ) $er.ErrorDetails = "Failed to enum share for '$ComputerName': $($exp.Message)" if ($ErrorActionPreference -eq 'Stop') { Write-Error -ErrorRecord $er } else { Write-Warning -Message "Get-ComputerSMBShareList - Failed to enumarate share on '$ComputerName'." } return } try { $entryPtr = $buffer for ($i = 0; $i -lt $total; $i++) { $shareInfo = [System.Runtime.InteropServices.Marshal]::PtrToStructure($entryPtr, [Type]([Win32Share.NativeHelpers+SHARE_INFO_1])) $netNm = $shareInfo.shi1_netname if ($Name) { $isLike = $false foreach ($nm in $Name) { if ($netNm -like $nm) { $isLike = $true continue } } if (-not $isLike) { $entryPtr = [IntPtr]::Add($entryPtr, [System.Runtime.InteropServices.Marshal]::SizeOf($shareInfo)) continue } } $shTyp = $shareInfo.shi1_type $shrPath = "\\$ComputerName\$netNm\" if (-not $SkipDiskSpace) { $freeBytesAvailableToCaller = 0 [System.Nullable[UInt64]]$freeBytesAvailableToCallerNull = $null $totalNumberOfBytes = 0 [System.Nullable[UInt64]]$totalNumberOfBytesNull = $null $totalNumberOfFreeBytes = 0 [System.Nullable[UInt64]]$totalNumberOfFreeBytesNull = $null $lastWin32Error = 0 if (($shTyp -bor [Win32Share.ShareType]::Disk) -eq [Win32Share.ShareType]::Disk) { $dskRes = [Win32Share.NativeMethods]::GetDiskFreeSpaceEx( $shrPath, [ref]$freeBytesAvailableToCaller, [ref]$totalNumberOfBytes, [ref]$totalNumberOfFreeBytes ) if ($dskRes) { $freeBytesAvailableToCallerNull = $freeBytesAvailableToCaller $totalNumberOfBytesNull = $totalNumberOfBytes $totalNumberOfFreeBytesNull = $totalNumberOfFreeBytes } else { $lastWin32Error = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error() $exp = [System.ComponentModel.Win32Exception]$lastWin32Error $er = [System.Management.Automation.ErrorRecord]::new( $exp, 'Win32Share.NativeMethods.GetSmbInf.ShareException', [System.Management.Automation.ErrorCategory]::NotSpecified, $shrPath ) $er.ErrorDetails = "Failed to get disk space on '$shrPath' for '$ComputerName': $($exp.Message)" if ($ErrorActionPreference -eq 'Stop') { Write-Error -ErrorRecord $er } else { Write-Warning -Message "Get-ComputerSMBShareList - Failed to get disk space on '$shrPath' for '$ComputerName': $($exp.Message)" } } } [PSCustomObject]@{ PSTypeName = 'Win32Share.NativeMethods' ComputerName = $ComputerName Path = $shrPath Name = $netNm Type = $shTyp Remark = $shareInfo.shi1_remark TotalBytes = $totalNumberOfBytesNull TotalFreeBytes = $totalNumberOfFreeBytesNull FreeBytesAvailableToUser = $freeBytesAvailableToCallerNull } } else { [PSCustomObject]@{ PSTypeName = 'Win32Share.NativeMethods' ComputerName = $ComputerName Path = $shrPath Name = $netNm Type = $shTyp Remark = $shareInfo.shi1_remark } } $entryPtr = [IntPtr]::Add($entryPtr, [System.Runtime.InteropServices.Marshal]::SizeOf($shareInfo)) } } finally { $null = [Win32Share.NativeMethods]::NetApiBufferFree($buffer) } } function Get-ComputerSplit { [CmdletBinding()] param( [string[]] $ComputerName ) if ($null -eq $ComputerName) { $ComputerName = $Env:COMPUTERNAME } try { $LocalComputerDNSName = [System.Net.Dns]::GetHostByName($Env:COMPUTERNAME).HostName } catch { $LocalComputerDNSName = $Env:COMPUTERNAME } $ComputersLocal = $null [Array] $Computers = foreach ($Computer in $ComputerName) { if ($Computer -eq '' -or $null -eq $Computer) { $Computer = $Env:COMPUTERNAME } if ($Computer -ne $Env:COMPUTERNAME -and $Computer -ne $LocalComputerDNSName) { $Computer } else { $ComputersLocal = $Computer } } , @($ComputersLocal, $Computers) } function Get-IPRange { [cmdletBinding()] param( [string] $StartBinary, [string] $EndBinary ) [int64] $StartInt = [System.Convert]::ToInt64($StartBinary, 2) [int64] $EndInt = [System.Convert]::ToInt64($EndBinary, 2) for ($BinaryIP = $StartInt; $BinaryIP -le $EndInt; $BinaryIP++) { Convert-BinaryToIP ([System.Convert]::ToString($BinaryIP, 2).PadLeft(32, '0')) } } function Get-LocalComputerSid { <# .SYNOPSIS Get the SID of the local computer. .DESCRIPTION Get the SID of the local computer. .EXAMPLE Get-LocalComputerSid .NOTES General notes #> [cmdletBinding()] param() try { Add-Type -AssemblyName System.DirectoryServices.AccountManagement $PrincipalContext = [System.DirectoryServices.AccountManagement.PrincipalContext]::new([System.DirectoryServices.AccountManagement.ContextType]::Machine) $UserPrincipal = [System.DirectoryServices.AccountManagement.UserPrincipal]::new($PrincipalContext) $Searcher = [System.DirectoryServices.AccountManagement.PrincipalSearcher]::new() $Searcher.QueryFilter = $UserPrincipal $User = $Searcher.FindAll() foreach ($U in $User) { if ($U.Sid.Value -like "*-500") { return $U.Sid.Value.TrimEnd("-500") } } } catch { Write-Warning -Message "Get-LocalComputerSid - Error: $($_.Exception.Message)" } } function Get-OfflineRegistryProfilesPath { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE Get-OfflineRegistryProfilesPath .NOTES Name Value ---- ----- Przemek {[FilePath, C:\Users\Przemek\NTUSER.DAT], [Status, ]} test.1 {[FilePath, C:\Users\test.1\NTUSER.DAT], [Status, ]} #> [CmdletBinding()] param( ) $Profiles = [ordered] @{} $CurrentMapping = (Get-PSRegistry -RegistryPath 'HKEY_USERS' -ExpandEnvironmentNames -DoNotUnmount).PSSubKeys $UsersInSystem = (Get-PSRegistry -RegistryPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' -ExpandEnvironmentNames -DoNotUnmount).PSSubKeys $MissingProfiles = foreach ($Profile in $UsersInSystem) { if ($Profile.StartsWith("S-1-5-21") -and $CurrentMapping -notcontains $Profile) { Get-PSRegistry -RegistryPath "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$Profile" -ExpandEnvironmentNames -DoNotUnmount } } foreach ($Profile in $MissingProfiles) { $PathToNTUser = [io.path]::Combine($Profile.ProfileImagePath, 'NTUSER.DAT') $ProfileName = [io.path]::GetFileName($Profile.ProfileImagePath) $StartPath = "Offline_$ProfileName" try { $PathExists = Test-Path -LiteralPath $PathToNTUser -ErrorAction Stop if ($PathExists) { $Profiles[$StartPath] = [ordered] @{ FilePath = $PathToNTUser Status = $null } } } catch { Write-Warning -Message "Mount-OfflineRegistryPath - Couldn't execute. Error: $($_.Exception.Message)" continue } } $Profiles } function Get-PrivateRegistryTranslated { [cmdletBinding()] param( [Array] $RegistryPath, [System.Collections.IDictionary] $HiveDictionary, [System.Collections.IDictionary] $ReverseTypesDictionary, [Parameter()][ValidateSet('REG_SZ', 'REG_NONE', 'None', 'REG_EXPAND_SZ', 'REG_BINARY', 'REG_DWORD', 'REG_MULTI_SZ', 'REG_QWORD', 'string', 'binary', 'dword', 'qword', 'multistring', 'expandstring')][string] $Type, [Parameter()][string] $Key, [Parameter()][object] $Value ) foreach ($Registry in $RegistryPath) { if ($Registry -is [string]) { $Registry = $Registry.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } else { $Registry.RegistryPath = $Registry.RegistryPath.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } foreach ($Hive in $HiveDictionary.Keys) { if ($Registry -is [string] -and $Registry.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) { if ($Hive.Length -eq $Registry.Length) { [ordered] @{ HiveKey = $HiveDictionary[$Hive] SubKeyName = $null ValueKind = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null } Key = $Key Value = $Value } } else { [ordered] @{ HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.substring($Hive.Length + 1) ValueKind = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null } Key = $Key Value = $Value } } break } elseif ($Registry -isnot [string] -and $Registry.RegistryPath.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) { if ($Hive.Length -eq $Registry.RegistryPath.Length) { [ordered] @{ ComputerName = $Registry.ComputerName HiveKey = $HiveDictionary[$Hive] SubKeyName = $null ValueKind = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null } Key = $Key Value = $Value } } else { [ordered] @{ ComputerName = $Registry.ComputerName HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.RegistryPath.substring($Hive.Length + 1) ValueKind = if ($Type) { [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) } else { $null } Key = $Key Value = $Value } } break } } } } function Get-PSConvertSpecialRegistry { [cmdletbinding()] param( [Array] $RegistryPath, [Array] $Computers, [System.Collections.IDictionary] $HiveDictionary, [switch] $ExpandEnvironmentNames ) $FixedPath = foreach ($R in $RegistryPath) { foreach ($DictionaryKey in $HiveDictionary.Keys) { $SplitParts = $R.Split("\") $FirstPart = $SplitParts[0] if ($FirstPart -eq $DictionaryKey) { if ($HiveDictionary[$DictionaryKey] -in 'All', 'All+Default', 'Default', 'AllDomain+Default', 'AllDomain', 'AllDomain+Other', 'AllDomain+Other+Default') { foreach ($Computer in $Computers) { $SubKeys = Get-PSRegistry -RegistryPath "HKEY_USERS" -ComputerName $Computer -ExpandEnvironmentNames:$ExpandEnvironmentNames.IsPresent -DoNotUnmount if ($SubKeys.PSSubKeys) { $RegistryKeys = ConvertTo-HKeyUser -SubKeys ($SubKeys.PSSubKeys | Sort-Object) -HiveDictionary $HiveDictionary -DictionaryKey $DictionaryKey -RegistryPath $R foreach ($S in $RegistryKeys) { [PSCustomObject] @{ ComputerName = $Computer RegistryPath = $S Error = $null ErrorMessage = $null } } } else { [PSCustomObject] @{ ComputerName = $Computer RegistryPath = $R Error = $true ErrorMessage = "Couldn't connect to $Computer to list HKEY_USERS" } } } } elseif ($FirstPart -in 'Users', 'HKEY_USERS', 'HKU' -and $SplitParts[1] -and $SplitParts[1] -like "Offline_*") { foreach ($Computer in $Computers) { $SubKeys = Get-PSRegistry -RegistryPath "HKEY_USERS" -ComputerName $Computer -ExpandEnvironmentNames:$ExpandEnvironmentNames.IsPresent -DoNotUnmount if ($SubKeys.PSSubKeys) { $RegistryKeys = ConvertTo-HKeyUser -SubKeys ($SubKeys.PSSubKeys + $SplitParts[1] | Sort-Object) -HiveDictionary $HiveDictionary -DictionaryKey $DictionaryKey -RegistryPath $R foreach ($S in $RegistryKeys) { [PSCustomObject] @{ ComputerName = $Computer RegistryPath = $S Error = $null ErrorMessage = $null } } } else { [PSCustomObject] @{ ComputerName = $Computer RegistryPath = $R Error = $true ErrorMessage = "Couldn't connect to $Computer to list HKEY_USERS" } } } } else { $R } break } } } $FixedPath } function Get-PSSubRegistry { [cmdletBinding()] param( [System.Collections.IDictionary] $Registry, [string] $ComputerName, [switch] $Remote, [switch] $ExpandEnvironmentNames ) if ($Registry.ComputerName) { if ($Registry.ComputerName -ne $ComputerName) { return } } if (-not $Registry.Error) { try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Registry.HiveKey, $ComputerName, 0 ) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($Registry.HiveKey, 0 ) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) } } else { $PSConnection = $false $PSError = $($Registry.ErrorMessage) } if ($PSError) { [PSCustomObject] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = $null PSType = $null } } else { try { $SubKey = $BaseHive.OpenSubKey($Registry.SubKeyName, $false) if ($null -ne $SubKey) { [PSCustomObject] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $false PSErrorMessage = $null PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = if (-not $ExpandEnvironmentNames) { $SubKey.GetValue($Registry.Key, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) } else { $SubKey.GetValue($Registry.Key) } PSType = $SubKey.GetValueKind($Registry.Key) } } else { [PSCustomObject] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = "Registry path $($Registry.Registry) doesn't exists." PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = $null PSType = $null } } } catch { [PSCustomObject] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $_.Exception.Message PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = $null PSType = $null } } } if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } } function Get-PSSubRegistryComplete { [cmdletBinding()] param( [System.Collections.IDictionary] $Registry, [string] $ComputerName, [switch] $Remote, [switch] $Advanced, [switch] $ExpandEnvironmentNames ) if ($Registry.ComputerName) { if ($Registry.ComputerName -ne $ComputerName) { return } } if (-not $Registry.Error) { try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Registry.HiveKey, $ComputerName, 0 ) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($Registry.HiveKey, 0 ) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) } } else { $PSConnection = $false $PSError = $($Registry.ErrorMessage) } if ($PSError) { [PSCustomObject] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError PSSubKeys = $null PSPath = $Registry.Registry PSKey = $Registry.Key } } else { try { $SubKey = $BaseHive.OpenSubKey($Registry.SubKeyName, $false) if ($null -ne $SubKey) { $Object = [ordered] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $false PSErrorMessage = $null PSSubKeys = $SubKey.GetSubKeyNames() PSPath = $Registry.Registry } $Keys = $SubKey.GetValueNames() foreach ($K in $Keys) { if ($K -eq "") { if ($Advanced) { $Object['DefaultKey'] = [ordered] @{ Value = if (-not $ExpandEnvironmentNames) { $SubKey.GetValue($K, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) } else { $SubKey.GetValue($K) } Type = $SubKey.GetValueKind($K) } } else { $Object['DefaultKey'] = $SubKey.GetValue($K) } } else { if ($Advanced) { $Object[$K] = [ordered] @{ Value = if (-not $ExpandEnvironmentNames) { $SubKey.GetValue($K, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) } else { $SubKey.GetValue($K) } Type = $SubKey.GetValueKind($K) } } else { $Object[$K] = if (-not $ExpandEnvironmentNames) { $SubKey.GetValue($K, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) } else { $SubKey.GetValue($K) } } } } [PSCustomObject] $Object } else { [PSCustomObject] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = "Registry path $($Registry.Registry) doesn't exists." PSSubKeys = $null PSPath = $Registry.Registry } } } catch { [PSCustomObject] @{ PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $_.Exception.Message PSSubKeys = $null PSPath = $Registry.Registry } } } if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } } function Get-PSSubRegistryTranslated { [cmdletBinding()] param( [Array] $RegistryPath, [System.Collections.IDictionary] $HiveDictionary, [string] $Key ) foreach ($Registry in $RegistryPath) { if ($Registry -is [string]) { $Registry = $Registry.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") $FirstPartSplit = $Registry -split "\\" $FirstPart = $FirstPartSplit[0] } else { $Registry.RegistryPath = $Registry.RegistryPath.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") $FirstPartSplit = $Registry.RegistryPath -split "\\" $FirstPart = $FirstPartSplit[0] } foreach ($Hive in $HiveDictionary.Keys) { if ($Registry -is [string] -and $FirstPart -eq $Hive) { if ($Hive.Length -eq $Registry.Length) { [ordered] @{ Registry = $Registry HiveKey = $HiveDictionary[$Hive] SubKeyName = $null Key = if ($Key -eq "") { $null } else { $Key } Error = $null ErrorMessage = $null } } else { [ordered] @{ Registry = $Registry HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.substring($Hive.Length + 1) Key = if ($Key -eq "") { $null } else { $Key } Error = $null ErrorMessage = $null } } break } elseif ($Registry -isnot [string] -and $FirstPart -eq $Hive) { if ($Hive.Length -eq $Registry.RegistryPath.Length) { [ordered] @{ ComputerName = $Registry.ComputerName Registry = $Registry.RegistryPath HiveKey = $HiveDictionary[$Hive] SubKeyName = $null Key = if ($Key -eq "") { $null } else { $Key } Error = $Registry.Error ErrorMessage = $Registry.ErrorMessage } } else { [ordered] @{ ComputerName = $Registry.ComputerName Registry = $Registry.RegistryPath HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.RegistryPath.substring($Hive.Length + 1) Key = if ($Key -eq "") { $null } else { $Key } Error = $Registry.Error ErrorMessage = $Registry.ErrorMessage } } break } } } } function Mount-AllRegistryPath { [CmdletBinding()] param( [string] $MountPoint = "HKEY_USERS\", [string] $MountUsers ) $AllProfiles = Get-OfflineRegistryProfilesPath foreach ($Profile in $AllProfiles.Keys) { if ($MountUsers) { if ($MountUsers -ne $Profile) { continue } } $WhereMount = "$MountPoint\$Profile".Replace("\\", "\") Write-Verbose -Message "Mount-OfflineRegistryPath - Mounting $WhereMount to $($AllProfiles[$Profile].FilePath)" $AllProfiles[$Profile].Status = Mount-PSRegistryPath -MountPoint $WhereMount -FilePath $AllProfiles[$Profile].FilePath } $AllProfiles } function Mount-DefaultRegistryPath { [CmdletBinding()] param( [string] $MountPoint = "HKEY_USERS\.DEFAULT_USER" ) $DefaultRegistryPath = Get-PSRegistry -RegistryPath 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' -Key 'Default' -ExpandEnvironmentNames -DoNotUnmount if ($PSError -ne $true) { $PathToNTUser = [io.path]::Combine($DefaultRegistryPath.PSValue, 'NTUSER.DAT') Write-Verbose -Message "Mount-DefaultRegistryPath - Mounting $MountPoint to $PathToNTUser" Mount-PSRegistryPath -MountPoint $MountPoint -FilePath $PathToNTUser } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $PSErrorMessage } else { Write-Warning -Message "Mount-DefaultRegistryPath - Couldn't execute. Error: $PSErrorMessage" } } } function New-PrivateRegistry { [CmdletBinding(SupportsShouldProcess)] param( [System.Collections.IDictionary] $RegistryValue, [string] $Computer, [switch] $Remote ) try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryValue.HiveKey, $Computer, 0 ) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryValue.HiveKey, 0 ) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) if ($PSBoundParameters.ErrorAction -eq 'Stop') { if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } throw } else { Write-Warning "New-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } } if ($PSError) { if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" } } } else { try { if ($PSCmdlet.ShouldProcess($Computer, "Creating registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)")) { $SubKey = $BaseHive.OpenSubKey($RegistryValue.SubKeyName, $true) if (-not $SubKey) { $SubKeysSplit = $RegistryValue.SubKeyName.Split('\') $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true) if (-not $SubKey) { $SubKey = $BaseHive.CreateSubKey($SubKeysSplit[0]) } $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true) foreach ($S in $SubKeysSplit | Select-Object -Skip 1) { $SubKey = $SubKey.CreateSubKey($S) } $PSError = $false $PSErrorMessage = $null } else { $PSError = $false $PSErrorMessage = "$($RegistryValue.SubKeyName) already exists." } } else { $PSError = $true $PSErrorMessage = "WhatIf was used. No changes done." } if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $PSError PSErrorMessage = $PSErrorMessage Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" } } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } throw } else { Write-Warning "New-PSRegistry - Creating registry $RegistryPath on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $($_.Exception.Message) Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" } } } } if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } } function Remove-PrivateRegistry { [cmdletBinding(SupportsShouldProcess)] param( [string] $Computer, [string] $Key, [System.Collections.IDictionary] $RegistryValue, [switch] $Remote, [switch] $Suppress ) $PSConnection = $null $PSError = $null $PSErrorMessage = $null try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryValue.HiveKey, $Computer, 0 ) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryValue.HiveKey, 0 ) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) if ($PSBoundParameters.ErrorAction -eq 'Stop') { if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } throw } else { Write-Warning "Remove-PSRegistry - Removing registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) key $($RegistryValue.Key) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } } if ($PSError) { if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key } } } else { try { if ($Key) { $SubKey = $BaseHive.OpenSubKey($RegistryValue.SubKeyName, $true) if ($PSCmdlet.ShouldProcess($Computer, "Removing registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) key $($RegistryValue.Key)")) { if ($SubKey) { $SubKey.DeleteValue($RegistryValue.Key, $true) } } else { $PSError = $true $PSErrorMessage = "WhatIf was used. No changes done." } } else { if ($PSCmdlet.ShouldProcess($Computer, "Removing registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) folder")) { if ($BaseHive) { if ($Recursive) { $BaseHive.DeleteSubKeyTree($RegistryValue.SubKeyName, $true) } else { $BaseHive.DeleteSubKey($RegistryValue.SubKeyName, $true) } } } else { $PSError = $true $PSErrorMessage = "WhatIf was used. No changes done." } } if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $PSError PSErrorMessage = $PSErrorMessage Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key } } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } throw } else { Write-Warning "Remove-PSRegistry - Removing registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) key $($RegistryValue.Key) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $_.Exception.Message Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key } } } } if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } } function Request-Credentials { [CmdletBinding()] param( [string] $UserName, [string] $Password, [switch] $AsSecure, [switch] $FromFile, [switch] $Output, [switch] $NetworkCredentials, [string] $Service ) if ($FromFile) { if (($Password -ne '') -and (Test-Path $Password)) { Write-Verbose "Request-Credentials - Reading password from file $Password" $Password = Get-Content -Path $Password } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = 'File with password unreadable.' } } else { Write-Warning "Request-Credentials - Secure password from file couldn't be read. File not readable. Terminating." return } } } if ($AsSecure) { try { $NewPassword = $Password | ConvertTo-SecureString -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($ErrorMessage -like '*Key not valid for use in specified state*') { if ($Output) { return @{ Status = $false; Output = $Service; Extended = "Couldn't use credentials provided. Most likely using credentials from other user/session/computer." } } else { Write-Warning -Message "Request-Credentials - Couldn't use credentials provided. Most likely using credentials from other user/session/computer." return } } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = $ErrorMessage } } else { Write-Warning -Message "Request-Credentials - $ErrorMessage" return } } } } else { $NewPassword = $Password } if ($UserName -and $NewPassword) { if ($AsSecure) { $Credentials = New-Object System.Management.Automation.PSCredential($Username, $NewPassword) } else { Try { $SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($ErrorMessage -like '*Key not valid for use in specified state*') { if ($Output) { return @{ Status = $false; Output = $Service; Extended = "Couldn't use credentials provided. Most likely using credentials from other user/session/computer." } } else { Write-Warning -Message "Request-Credentials - Couldn't use credentials provided. Most likely using credentials from other user/session/computer." return } } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = $ErrorMessage } } else { Write-Warning -Message "Request-Credentials - $ErrorMessage" return } } } $Credentials = New-Object System.Management.Automation.PSCredential($Username, $SecurePassword) } } else { if ($Output) { return @{ Status = $false; Output = $Service; Extended = 'Username or/and Password is empty' } } else { Write-Warning -Message 'Request-Credentials - UserName or Password are empty.' return } } if ($NetworkCredentials) { return $Credentials.GetNetworkCredential() } else { return $Credentials } } function Resolve-PrivateRegistry { [CmdletBinding()] param( [alias('Path')][string[]] $RegistryPath ) foreach ($R in $RegistryPath) { $R = $R.Replace("\\", "\").Replace("\\", "\") If ($R.StartsWith("Users\.DEFAULT_USER") -or $R.StartsWith('HKEY_USERS\.DEFAULT_USER')) { $R = $R.Replace("Users\.DEFAULT_USER", "HKUD") $R.Replace('HKEY_USERS\.DEFAULT_USER', "HKUD") } elseif ($R -like '*:*') { $Found = $false foreach ($DictionaryKey in $Script:Dictionary.Keys) { $SplitParts = $R.Split("\") $FirstPart = $SplitParts[0] if ($FirstPart -eq $DictionaryKey) { $R -replace $DictionaryKey, $Script:Dictionary[$DictionaryKey] $Found = $true break } } if (-not $Found) { $R.Replace(":", "") } } else { $R } } } function Set-PrivateRegistry { [cmdletBinding(SupportsShouldProcess)] param( [System.Collections.IDictionary] $RegistryValue, [string] $Computer, [switch] $Remote, [switch] $Suppress ) Write-Verbose -Message "Set-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer" if ($RegistryValue.ComputerName) { if ($RegistryValue.ComputerName -ne $Computer) { return } } try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryValue.HiveKey, $Computer, 0 ) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryValue.HiveKey, 0 ) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) if ($PSBoundParameters.ErrorAction -eq 'Stop') { if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } throw } else { Write-Warning "Set-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } } if ($PSCmdlet.ShouldProcess($Computer, "Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind)")) { if ($PSError) { if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } else { try { $SubKey = $BaseHive.OpenSubKey($RegistryValue.SubKeyName, $true) if (-not $SubKey) { $SubKeysSplit = $RegistryValue.SubKeyName.Split('\') $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true) if (-not $SubKey) { $SubKey = $BaseHive.CreateSubKey($SubKeysSplit[0]) } $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true) foreach ($S in $SubKeysSplit | Select-Object -Skip 1) { $SubKey = $SubKey.CreateSubKey($S) } } if ($RegistryValue.ValueKind -eq [Microsoft.Win32.RegistryValueKind]::MultiString) { $SubKey.SetValue($RegistryValue.Key, [string[]] $RegistryValue.Value, $RegistryValue.ValueKind) } elseif ($RegistryValue.ValueKind -in [Microsoft.Win32.RegistryValueKind]::None, [Microsoft.Win32.RegistryValueKind]::Binary) { $SubKey.SetValue($RegistryValue.Key, [byte[]] $RegistryValue.Value, $RegistryValue.ValueKind) } else { $SubKey.SetValue($RegistryValue.Key, $RegistryValue.Value, $RegistryValue.ValueKind) } if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $false PSErrorMessage = $null Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } throw } else { Write-Warning "Set-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $_.Exception.Message Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } } } else { if (-not $Suppress) { [PSCustomObject] @{ PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = if ($PSError) { $PSError } else { "WhatIf used - skipping registry setting" } Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } if ($null -ne $SubKey) { $SubKey.Close() $SubKey.Dispose() } if ($null -ne $BaseHive) { $BaseHive.Close() $BaseHive.Dispose() } } function Test-IPIsInNetwork { [cmdletBinding()] param( [string] $IP, [string] $StartBinary, [string] $EndBinary ) $TestIPBinary = Convert-IPToBinary $IP [int64] $TestIPInt64 = [System.Convert]::ToInt64($TestIPBinary, 2) [int64] $StartInt64 = [System.Convert]::ToInt64($StartBinary, 2) [int64] $EndInt64 = [System.Convert]::ToInt64($EndBinary, 2) if ($TestIPInt64 -ge $StartInt64 -and $TestIPInt64 -le $EndInt64) { return $True } else { return $False } } function Unregister-MountedRegistry { [CmdletBinding()] param( ) if ($null -ne $Script:DefaultRegistryMounted) { Write-Verbose -Message "Unregister-MountedRegistry - Dismounting HKEY_USERS\.DEFAULT_USER" $null = Dismount-PSRegistryPath -MountPoint "HKEY_USERS\.DEFAULT_USER" $Script:DefaultRegistryMounted = $null } if ($null -ne $Script:OfflineRegistryMounted) { foreach ($Key in $Script:OfflineRegistryMounted.Keys) { if ($Script:OfflineRegistryMounted[$Key].Status -eq $true) { Write-Verbose -Message "Unregister-MountedRegistry - Dismounting HKEY_USERS\$Key" $null = Dismount-PSRegistryPath -MountPoint "HKEY_USERS\$Key" } } $Script:OfflineRegistryMounted = $null } } function Add-WinADUserGroups { [CmdletBinding()] [alias("Add-ADUserGroups")] param( [parameter(Mandatory = $true)][Object] $User, [string[]] $Groups, [string] $FieldSearch = 'Name', [switch] $WhatIf ) $Object = @() try { $ADgroups = Get-ADPrincipalGroupMembership -Identity $User.DistinguishedName | Where-Object { $_.Name -ne "Domain Users" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } if ($Groups) { foreach ($Group in $Groups) { if ($ADgroups.$FieldSearch -notcontains $Group) { try { if (-not $WhatIf) { Add-ADGroupMember -Identity $Group -Members $User.DistinguishedName -ErrorAction Stop } $Object += @{ Status = $true; Output = $Group; Extended = 'Added to group.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group; Extended = $ErrorMessage } } } else { } } } return $Object } function Convert-ADGuidToSchema { <# .SYNOPSIS Converts Guid to schema properties .DESCRIPTION Converts Guid to schema properties .PARAMETER Guid Guid to Convert to Schema Name .PARAMETER Domain Domain to query. By default the current domain is used .PARAMETER RootDSE RootDSE to query. By default RootDSE is queried from the domain .PARAMETER DisplayName Return the schema name by display name. By default it returns as Name .EXAMPLE $T2 = '570b9266-bbb3-4fad-a712-d2e3fedc34dd' $T = [guid] '570b9266-bbb3-4fad-a712-d2e3fedc34dd' Convert-ADGuidToSchema -Guid $T Convert-ADGuidToSchema -Guid $T2 .NOTES General notes #> [alias('Get-WinADDomainGUIDs', 'Get-WinADForestGUIDs')] [cmdletbinding()] param( [string] $Guid, [string] $Domain, [Microsoft.ActiveDirectory.Management.ADEntity] $RootDSE, [switch] $DisplayName ) if (-not $Script:ADSchemaMap -or -not $Script:ADSchemaMapDisplayName) { if ($RootDSE) { $Script:RootDSE = $RootDSE } elseif (-not $Script:RootDSE) { if ($Domain) { $Script:RootDSE = Get-ADRootDSE -Server $Domain } else { $Script:RootDSE = Get-ADRootDSE } } $DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $Script:RootDSE.defaultNamingContext -ToDomainCN $QueryServer = (Get-ADDomainController -DomainName $DomainCN -Discover -ErrorAction Stop).Hostname[0] $Script:ADSchemaMap = @{ } $Script:ADSchemaMapDisplayName = @{ } $Script:ADSchemaMapDisplayName['00000000-0000-0000-0000-000000000000'] = 'All' $Script:ADSchemaMap.Add('00000000-0000-0000-0000-000000000000', 'All') Write-Verbose "Convert-ADGuidToSchema - Querying Schema from $QueryServer" $Time = [System.Diagnostics.Stopwatch]::StartNew() if (-not $Script:StandardRights) { $Script:StandardRights = Get-ADObject -SearchBase $Script:RootDSE.schemaNamingContext -LDAPFilter "(schemaidguid=*)" -Properties name, lDAPDisplayName, schemaIDGUID -Server $QueryServer -ErrorAction Stop | Select-Object name, lDAPDisplayName, schemaIDGUID } foreach ($S in $Script:StandardRights) { $Script:ADSchemaMap["$(([System.GUID]$S.schemaIDGUID).Guid)"] = $S.name $Script:ADSchemaMapDisplayName["$(([System.GUID]$S.schemaIDGUID).Guid)"] = $S.lDAPDisplayName } $Time.Stop() $TimeToExecute = "$($Time.Elapsed.Days) days, $($Time.Elapsed.Hours) hours, $($Time.Elapsed.Minutes) minutes, $($Time.Elapsed.Seconds) seconds, $($Time.Elapsed.Milliseconds) milliseconds" Write-Verbose "Convert-ADGuidToSchema - Querying Schema from $QueryServer took $TimeToExecute" Write-Verbose "Convert-ADGuidToSchema - Querying Extended Rights from $QueryServer" $Time = [System.Diagnostics.Stopwatch]::StartNew() if (-not $Script:ExtendedRightsGuids) { $Script:ExtendedRightsGuids = Get-ADObject -SearchBase $Script:RootDSE.ConfigurationNamingContext -LDAPFilter "(&(objectclass=controlAccessRight)(rightsguid=*))" -Properties name, displayName, lDAPDisplayName, rightsGuid -Server $QueryServer -ErrorAction Stop | Select-Object name, displayName, lDAPDisplayName, rightsGuid } foreach ($S in $Script:ExtendedRightsGuids) { $Script:ADSchemaMap["$(([System.GUID]$S.rightsGUID).Guid)"] = $S.name $Script:ADSchemaMapDisplayName["$(([System.GUID]$S.rightsGUID).Guid)"] = $S.displayName } $Time.Stop() $TimeToExecute = "$($Time.Elapsed.Days) days, $($Time.Elapsed.Hours) hours, $($Time.Elapsed.Minutes) minutes, $($Time.Elapsed.Seconds) seconds, $($Time.Elapsed.Milliseconds) milliseconds" Write-Verbose "Convert-ADGuidToSchema - Querying Extended Rights from $QueryServer took $TimeToExecute" } if ($Guid) { if ($DisplayName) { $Script:ADSchemaMapDisplayName[$Guid] } else { $Script:ADSchemaMap[$Guid] } } else { if ($DisplayName) { $Script:ADSchemaMapDisplayName } else { $Script:ADSchemaMap } } } function Convert-ADSchemaToGuid { <# .SYNOPSIS Converts name of schema properties to guids .DESCRIPTION Converts name of schema properties to guids .PARAMETER SchemaName Schema Name to convert to guid .PARAMETER All Get hashtable of all schema properties and their guids .PARAMETER Domain Domain to query. By default the current domain is used .PARAMETER RootDSE RootDSE to query. By default RootDSE is queried from the domain .PARAMETER AsString Return the guid as a string .EXAMPLE Convert-ADSchemaToGuid -SchemaName 'ms-Exch-MSO-Forward-Sync-Cookie' .EXAMPLE Convert-ADSchemaToGuid -SchemaName 'ms-Exch-MSO-Forward-Sync-Cookie' -AsString .NOTES General notes #> [CmdletBinding()] param( [string] $SchemaName, [string] $Domain, [Microsoft.ActiveDirectory.Management.ADEntity] $RootDSE, [switch] $AsString ) if (-not $Script:ADGuidMap -or -not $Script:ADGuidMapString) { if ($RootDSE) { $Script:RootDSE = $RootDSE } elseif (-not $Script:RootDSE) { if ($Domain) { $Script:RootDSE = Get-ADRootDSE -Server $Domain } else { $Script:RootDSE = Get-ADRootDSE } } $DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $Script:RootDSE.defaultNamingContext -ToDomainCN $QueryServer = (Get-ADDomainController -DomainName $DomainCN -Discover -ErrorAction Stop).Hostname[0] $Script:ADGuidMap = [ordered] @{ 'All' = [System.GUID]'00000000-0000-0000-0000-000000000000' } $Script:ADGuidMapString = [ordered] @{ 'All' = '00000000-0000-0000-0000-000000000000' } Write-Verbose "Convert-ADSchemaToGuid - Querying Schema from $QueryServer" $Time = [System.Diagnostics.Stopwatch]::StartNew() if (-not $Script:StandardRights) { $Script:StandardRights = Get-ADObject -SearchBase $Script:RootDSE.schemaNamingContext -LDAPFilter "(schemaidguid=*)" -Properties name, lDAPDisplayName, schemaIDGUID -Server $QueryServer -ErrorAction Stop | Select-Object name, lDAPDisplayName, schemaIDGUID } foreach ($Guid in $Script:StandardRights) { $Script:ADGuidMapString[$Guid.lDAPDisplayName] = ([System.GUID]$Guid.schemaIDGUID).Guid $Script:ADGuidMapString[$Guid.Name] = ([System.GUID]$Guid.schemaIDGUID).Guid $Script:ADGuidMap[$Guid.lDAPDisplayName] = ([System.GUID]$Guid.schemaIDGUID) $Script:ADGuidMap[$Guid.Name] = ([System.GUID]$Guid.schemaIDGUID) } $Time.Stop() $TimeToExecute = "$($Time.Elapsed.Days) days, $($Time.Elapsed.Hours) hours, $($Time.Elapsed.Minutes) minutes, $($Time.Elapsed.Seconds) seconds, $($Time.Elapsed.Milliseconds) milliseconds" Write-Verbose "Convert-ADSchemaToGuid - Querying Schema from $QueryServer took $TimeToExecute" Write-Verbose "Convert-ADSchemaToGuid - Querying Extended Rights from $QueryServer" $Time = [System.Diagnostics.Stopwatch]::StartNew() if (-not $Script:ExtendedRightsGuids) { $Script:ExtendedRightsGuids = Get-ADObject -SearchBase $Script:RootDSE.ConfigurationNamingContext -LDAPFilter "(&(objectclass=controlAccessRight)(rightsguid=*))" -Properties name, displayName, lDAPDisplayName, rightsGuid -Server $QueryServer -ErrorAction Stop | Select-Object name, displayName, lDAPDisplayName, rightsGuid } foreach ($Guid in $Script:ExtendedRightsGuids) { $Script:ADGuidMapString[$Guid.Name] = ([System.GUID]$Guid.RightsGuid).Guid $Script:ADGuidMapString[$Guid.DisplayName] = ([System.GUID]$Guid.RightsGuid).Guid $Script:ADGuidMap[$Guid.Name] = ([System.GUID]$Guid.RightsGuid) $Script:ADGuidMap[$Guid.DisplayName] = ([System.GUID]$Guid.RightsGuid) } $Time.Stop() $TimeToExecute = "$($Time.Elapsed.Days) days, $($Time.Elapsed.Hours) hours, $($Time.Elapsed.Minutes) minutes, $($Time.Elapsed.Seconds) seconds, $($Time.Elapsed.Milliseconds) milliseconds" Write-Verbose "Convert-ADSchemaToGuid - Querying Extended Rights from $QueryServer took $TimeToExecute" } if ($SchemaName) { if ($AsString) { return $Script:ADGuidMapString[$SchemaName] } else { return $Script:ADGuidMap[$SchemaName] } } else { if ($AsString) { $Script:ADGuidMapString } else { $Script:ADGuidMap } } } function Find-ADConnectServer { [alias('Find-ADSyncServer')] param( ) $Description = Get-ADUser -Filter { Name -like "MSOL*" } -Properties Description | Select-Object Description -ExpandProperty Description foreach ($Desc in $Description) { $PatternType = "(?<=(Account created by ))(.*)(?=(with installation identifier))" $PatternServerName = "(?<=(on computer ))(.*)(?=(configured))" $PatternTenantName = "(?<=(to tenant ))(.*)(?=(. This))" $PatternInstallationID = "(?<=(installation identifier ))(.*)(?=( running on ))" if ($Desc -match $PatternServerName) { $ServerName = ($Matches[0]).Replace("'", '').Replace(' ', '') if ($Desc -match $PatternTenantName) { $TenantName = ($Matches[0]).Replace("'", '').Replace(' ', '') } else { $TenantName = '' } if ($Desc -match $PatternInstallationID) { $InstallationID = ($Matches[0]).Replace("'", '').Replace(' ', '') } else { $InstallationID = '' } if ($Desc -match $PatternType) { $Type = ($Matches[0]).Replace("'", '').Replace('by ', '').Replace('the ', '') } else { $Type = '' } $Data = Get-ADComputer -Identity $ServerName [PSCustomObject] @{ Name = $Data.Name FQDN = $Data.DNSHostName DistinguishedName = $Data.DistinguishedName Type = $Type TenantName = $TenantName InstallatioNID = $InstallationID } } } } function Find-ExchangeServer { <# .SYNOPSIS Find Exchange Servers in Active Directory .DESCRIPTION Find Exchange Servers in Active Directory .EXAMPLE Find-ExchangeServer .NOTES General notes #> [CmdletBinding()] param( ) $ExchangeServers = Get-ADGroup -Identity "Exchange Servers" foreach ($Server in $ExchangeServers) { $Data = Get-ADComputer -Identity $Server.SamAccountName -Properties Name, DNSHostName, OperatingSystem, DistinguishedName, ServicePrincipalName [PSCustomObject] @{ Name = $Data.Name FQDN = $Data.DNSHostName OperatingSystem = $Data.OperatingSystem DistinguishedName = $Data.DistinguishedName Enabled = $Data.Enabled } } } function Find-HyperVServer { [cmdletbinding()] param() try { $ADObjects = Get-ADObject -Filter 'ObjectClass -eq "serviceConnectionPoint" -and Name -eq "Microsoft Hyper-V"' -ErrorAction Stop } catch { Write-Error "Error: $_" } foreach ($Server in $ADObjects) { $Temporary = $Server.DistinguishedName.split(",") $DistinguishedName = $Temporary[1..$Temporary.Count] -join "," $Data = Get-ADComputer -Identity $DistinguishedName -Properties Name, DNSHostName, OperatingSystem, DistinguishedName, ServicePrincipalName [PSCustomObject] @{ Name = $Data.Name FQDN = $Data.DNSHostName OperatingSystem = $Data.OperatingSystem DistinguishedName = $Data.DistinguishedName Enabled = $Data.Enabled } } } function Find-ServerTypes { [cmdletbinding()] param( [string[]][ValidateSet('All', 'ADConnect', 'DomainController', 'Exchange', 'Hyper-V', 'RDSLicense', 'SQL', 'VirtualMachine')] $Type = 'All' ) $Forest = Get-ADForest foreach ($Domain in $Forest.Domains) { try { $DomainInformation = Get-ADDomain -Server $Domain -ErrorAction Stop } catch { Write-Warning "Find-ServerTypes - Domain $Domain couldn't be reached. Skipping" continue } try { $ServiceConnectionPoint = Get-ADObject -Filter 'ObjectClass -eq "serviceConnectionPoint"' -ErrorAction Stop -Server $Domain foreach ($Point in $ServiceConnectionPoint) { $Temporary = $Point.DistinguishedName.split(",") $DistinguishedName = $Temporary[1..$Temporary.Count] -join "," $Point | Add-Member -MemberType 'NoteProperty' -Name 'DN' -Value $DistinguishedName -Force } } catch { Write-Error "Find-ServerTypes - Get-ADObject command failed. Terminating. Error $_" return } $ADConnect = Find-ADConnectServer $Computers = Get-ADComputer -Filter * -Properties Name, DNSHostName, OperatingSystem, DistinguishedName, ServicePrincipalName -Server $Domain $Servers = foreach ($Computer in $Computers) { $Services = foreach ($Service in $Computer.servicePrincipalName) { ($Service -split '/')[0] } [PSCustomObject] @{ Name = $Computer.Name FQDN = $Computer.DNSHostName OperatingSystem = $Computer.OperatingSystem DistinguishedName = $Computer.DistinguishedName Enabled = $Computer.Enabled IsExchange = if ($Services -like '*ExchangeMDB*' -or $Services -like '*ExchangeRFR*') { $true } else { $false } IsSql = if ($Services -like '*MSSql*') { $true } else { $false } IsVM = if ($ServiceConnectionPoint.DN -eq $Computer.DistinguishedName -and $ServiceConnectionPoint.Name -eq 'Windows Virtual Machine') { $true } else { $false } IsHyperV = if ($Services -like '*Hyper-V Replica*') { $true } else { $false } IsSPHyperV = if ($ServiceConnectionPoint.DN -eq $Computer.DistinguishedName -and $ServiceConnectionPoint.Name -eq 'Microsoft Hyper-V') { $true } else { $false } IsRDSLicense = if ($ServiceConnectionPoint.DN -eq $Computer.DistinguishedName -and $ServiceConnectionPoint.Name -eq 'TermServLicensing') { $true } else { $false } IsDC = if ($DomainInformation.ReplicaDirectoryServers -contains $Computer.DNSHostName) { $true } else { $false } IsADConnect = if ($ADConnect.FQDN -eq $Computer.DNSHostName) { $true } else { $false } Forest = $Forest.Name Domain = $Domain ServicePrincipalName = ($Services | Sort-Object -Unique) -Join ',' ServiceConnectionPoint = ($ServiceConnectionPoint | Where-Object { $_.DN -eq $Computer.DistinguishedName }).Name -join ',' } } if ($Type -eq 'All') { $Servers } else { if ($Type -contains 'SQL') { $Servers | Where-Object { $_.IsSql -eq $true } } if ($Type -contains 'Exchange' ) { $Servers | Where-Object { $_.IsExchange -eq $true } } if ($Type -contains 'Hyper-V') { $Servers | Where-Object { $_.IsHyperV -eq $true -or $_.IsSPHyperV -eq $true } } if ($Type -contains 'VirtualMachine') { $Servers | Where-Object { $_.IsVM -eq $true } } if ($Type -contains 'RDSLicense') { $Servers | Where-Object { $_.IsRDSLicense -eq $true } } if ($Type -contains 'DomainController') { $Servers | Where-Object { $_.IsDC -eq $true } } if ($Type -contains 'DomainController') { $Servers | Where-Object { $_.IsDC -eq $true } } if ($Type -contains 'ADConnect') { $Servers | Where-Object { $_.IsADConnect -eq $true } } } } } function Find-UsersProxyAddressesStatus { param( $User ) $status = 'No proxy' if ($null -ne $user.proxyAddresses) { $count = 0 foreach ($proxy in $($user.ProxyAddresses)) { if ($proxy.SubString(0, 4) -ceq 'SMTP') { $count++ } } if ($count -eq 0) { $status = 'Missing primary proxy' } elseif ($count -gt 1) { $status = 'Multiple primary proxy' } else { $status = 'All OK' } } else { $status = 'Missing all proxy' } return $status } function Get-ADADministrativeGroups { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Type Parameter description .PARAMETER Forest Parameter description .PARAMETER ExcludeDomains Parameter description .PARAMETER IncludeDomains Parameter description .PARAMETER ExtendedForestInformation Parameter description .EXAMPLE Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins Output (Where VALUE is Get-ADGroup output): Name Value ---- ----- ByNetBIOS {EVOTEC\Domain Admins, EVOTEC\Enterprise Admins, EVOTECPL\Domain Admins} ad.evotec.xyz {DomainAdmins, EnterpriseAdmins} ad.evotec.pl {DomainAdmins} .NOTES General notes #> [cmdletBinding()] param( [parameter(Mandatory)][validateSet('DomainAdmins', 'EnterpriseAdmins')][string[]] $Type, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) $ADDictionary = [ordered] @{ } $ADDictionary['ByNetBIOS'] = [ordered] @{ } $ADDictionary['BySID'] = [ordered] @{ } $ForestInformation = Get-WinADForestDetails -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation foreach ($Domain in $ForestInformation.Domains) { $ADDictionary[$Domain] = [ordered] @{ } $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] $DomainInformation = Get-ADDomain -Server $QueryServer if ($Type -contains 'DomainAdmins') { Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-512'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { $ADDictionary['ByNetBIOS']["$($DomainInformation.NetBIOSName)\$($_.Name)"] = $_ $ADDictionary[$Domain]['DomainAdmins'] = "$($DomainInformation.NetBIOSName)\$($_.Name)" $ADDictionary['BySID'][$_.SID.Value] = $_ } } } foreach ($Domain in $ForestInformation.Forest.Domains) { if (-not $ADDictionary[$Domain]) { $ADDictionary[$Domain] = [ordered] @{ } } if ($Type -contains 'EnterpriseAdmins') { $QueryServer = $ForestInformation['QueryServers'][$Domain]['HostName'][0] $DomainInformation = Get-ADDomain -Server $QueryServer Get-ADGroup -Filter "SID -eq '$($DomainInformation.DomainSID)-519'" -Server $QueryServer -ErrorAction SilentlyContinue | ForEach-Object { $ADDictionary['ByNetBIOS']["$($DomainInformation.NetBIOSName)\$($_.Name)"] = $_ $ADDictionary[$Domain]['EnterpriseAdmins'] = "$($DomainInformation.NetBIOSName)\$($_.Name)" $ADDictionary['BySID'][$_.SID.Value] = $_ } } } return $ADDictionary } function Get-ADEncryptionTypes { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Value Parameter description .EXAMPLE Get-ADEncryptionTypes -Value 24 Output: AES128-CTS-HMAC-SHA1-96 AES256-CTS-HMAC-SHA1-96 .NOTES General notes #> [cmdletbinding()] Param( [parameter(Mandatory = $false, ValueFromPipeline = $True)][int32]$Value ) [String[]]$EncryptionTypes = @( Foreach ($V in $Value) { if ([int32]$V -band 0x00000001) { "DES-CBC-CRC" } if ([int32]$V -band 0x00000002) { "DES-CBC-MD5" } if ([int32]$V -band 0x00000004) { "RC4-HMAC" } if ([int32]$V -band 0x00000008) { "AES128-CTS-HMAC-SHA1-96" } if ([int32]$V -band 0x00000010) { "AES256-CTS-HMAC-SHA1-96" } if ([int32]$V -band 0x00000020) { "FAST-supported" } if ([int32]$V -band 0x00000040) { "Compound-identity-supported" } if ([int32]$V -band 0x00000080) { "Claims-supported" } if ([int32]$V -band 0x00000200) { "Resource-SID-compression-disabled" } } ) $EncryptionTypes } function Get-ADTrustAttributes { [cmdletbinding()] Param( [parameter(Mandatory = $false, ValueFromPipeline = $True)][int32]$Value ) [String[]]$TrustAttributes = @( Foreach ($V in $Value) { if ([int32]$V -band 0x00000001) { "Non Transitive" } if ([int32]$V -band 0x00000002) { "UpLevel Only" } if ([int32]$V -band 0x00000004) { "Quarantined Domain" } if ([int32]$V -band 0x00000008) { "Forest Transitive" } if ([int32]$V -band 0x00000010) { "Cross Organization" } if ([int32]$V -band 0x00000020) { "Within Forest" } if ([int32]$V -band 0x00000040) { "Treat as External" } if ([int32]$V -band 0x00000080) { "Uses RC4 Encryption" } if ([int32]$V -band 0x00000200) { "No TGT DELEGATION" } if ([int32]$V -band 0x00000800) { "Enable TGT DELEGATION" } if ([int32]$V -band 0x00000400) { "PIM Trust" } } ) return $TrustAttributes } function Get-WinADDSAGuid { <# .SYNOPSIS Get DSA GUIDs from a forest for all domain controllers .DESCRIPTION This function retrieves DSA GUIDs from a forest for all domain controllers .PARAMETER Forest Target different Forest, by default current forest is used .PARAMETER ExcludeDomains Exclude domain from search, by default whole forest is scanned .PARAMETER IncludeDomains Include only specific domains, by default whole forest is scanned .PARAMETER ExcludeDomainControllers Exclude specific domain controllers, by default there are no exclusions, as long as VerifyDomainControllers switch is enabled. Otherwise this parameter is ignored. .PARAMETER IncludeDomainControllers Include only specific domain controllers, by default all domain controllers are included, as long as VerifyDomainControllers switch is enabled. Otherwise this parameter is ignored. .PARAMETER SkipRODC Skip Read-Only Domain Controllers. By default all domain controllers are included. .PARAMETER ExtendedForestInformation Ability to provide Forest Information from another command to speed up processing .EXAMPLE Get-WinADDSAGuid | Format-Table .NOTES General notes #> [CmdletBinding()] param( [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [string[]] $ExcludeDomainControllers, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [alias('DomainControllers', 'ComputerName')][string[]] $IncludeDomainControllers, [switch] $SkipRODC, [System.Collections.IDictionary] $ExtendedForestInformation ) $Forest = Get-WinADForestDetails -Forest $Forest -ExtendedForestInformation $ExtendedForestInformation -ExcludeDomains $ExcludeDomains -ExcludeDomainControllers $ExcludeDomainControllers -IncludeDomains $IncludeDomains -IncludeDomainControllers $IncludeDomainControllers -SkipRODC:$SkipRODC $ListDSA = [ordered]@{} foreach ($DC in $Forest.ForestDomainControllers) { $ListDSA[$DC.DsaGuid] = [PSCustomObject] @{ Domain = $DC.Domain HostName = $DC.HostName DsaGuid = $DC.DsaGuid DsaGuidName = $DC.DsaGuidName } } if ($Hashtable) { $ListDSA } else { $ListDSA.Values | ForEach-Object { $_ } } } function Get-WinADForestControllers { [alias('Get-WinADDomainControllers')] <# .SYNOPSIS .DESCRIPTION Long description .PARAMETER TestAvailability Parameter description .EXAMPLE Get-WinADForestControllers -TestAvailability | Format-Table .EXAMPLE Get-WinADDomainControllers .EXAMPLE Get-WinADDomainControllers -Credential $Credential .EXAMPLE Get-WinADDomainControllers | Format-Table * Output: Domain HostName Forest IPV4Address IsGlobalCatalog IsReadOnly SchemaMaster DomainNamingMasterMaster PDCEmulator RIDMaster InfrastructureMaster Comment ------ -------- ------ ----------- --------------- ---------- ------------ ------------------------ ----------- --------- -------------------- ------- ad.evotec.xyz AD1.ad.evotec.xyz ad.evotec.xyz 192.168.240.189 True False True True True True True ad.evotec.xyz AD2.ad.evotec.xyz ad.evotec.xyz 192.168.240.192 True False False False False False False ad.evotec.pl ad.evotec.xyz False False False False False Unable to contact the server. This may be becau... .NOTES General notes #> [CmdletBinding()] param( [string[]] $Domain, [switch] $TestAvailability, [switch] $SkipEmpty, [pscredential] $Credential ) try { if ($Credential) { $Forest = Get-ADForest -Credential $Credential } else { $Forest = Get-ADForest } if (-not $Domain) { $Domain = $Forest.Domains } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Warning "Get-WinADForestControllers - Couldn't use Get-ADForest feature. Error: $ErrorMessage" return } $Servers = foreach ($D in $Domain) { try { $LocalServer = Get-ADDomainController -Discover -DomainName $D -ErrorAction Stop -Writable if ($Credential) { $DC = Get-ADDomainController -Server $LocalServer.HostName[0] -Credential $Credential -Filter * -ErrorAction Stop } else { $DC = Get-ADDomainController -Server $LocalServer.HostName[0] -Filter * -ErrorAction Stop } foreach ($S in $DC) { $Server = [ordered] @{ Domain = $D HostName = $S.HostName Name = $S.Name Forest = $Forest.RootDomain IPV4Address = $S.IPV4Address IPV6Address = $S.IPV6Address IsGlobalCatalog = $S.IsGlobalCatalog IsReadOnly = $S.IsReadOnly Site = $S.Site SchemaMaster = ($S.OperationMasterRoles -contains 'SchemaMaster') DomainNamingMaster = ($S.OperationMasterRoles -contains 'DomainNamingMaster') PDCEmulator = ($S.OperationMasterRoles -contains 'PDCEmulator') RIDMaster = ($S.OperationMasterRoles -contains 'RIDMaster') InfrastructureMaster = ($S.OperationMasterRoles -contains 'InfrastructureMaster') LdapPort = $S.LdapPort SslPort = $S.SslPort Pingable = $null Comment = '' } if ($TestAvailability) { $Server['Pingable'] = foreach ($_ in $Server.IPV4Address) { Test-Connection -Count 1 -Server $_ -Quiet -ErrorAction SilentlyContinue } } [PSCustomObject] $Server } } catch { [PSCustomObject]@{ Domain = $D HostName = '' Name = '' Forest = $Forest.RootDomain IPV4Address = '' IPV6Address = '' IsGlobalCatalog = '' IsReadOnly = '' Site = '' SchemaMaster = $false DomainNamingMasterMaster = $false PDCEmulator = $false RIDMaster = $false InfrastructureMaster = $false LdapPort = '' SslPort = '' Pingable = $null Comment = $_.Exception.Message -replace "`n", " " -replace "`r", " " } } } if ($SkipEmpty) { return $Servers | Where-Object { $_.HostName -ne '' } } return $Servers } function Get-WinADForestDetails { <# .SYNOPSIS Get details about Active Directory Forest, Domains and Domain Controllers in a single query .DESCRIPTION Get details about Active Directory Forest, Domains and Domain Controllers in a single query .PARAMETER Forest Target different Forest, by default current forest is used .PARAMETER ExcludeDomains Exclude domain from search, by default whole forest is scanned .PARAMETER IncludeDomains Include only specific domains, by default whole forest is scanned .PARAMETER ExcludeDomainControllers Exclude specific domain controllers, by default there are no exclusions, as long as VerifyDomainControllers switch is enabled. Otherwise this parameter is ignored. .PARAMETER IncludeDomainControllers Include only specific domain controllers, by default all domain controllers are included, as long as VerifyDomainControllers switch is enabled. Otherwise this parameter is ignored. .PARAMETER SkipRODC Skip Read-Only Domain Controllers. By default all domain controllers are included. .PARAMETER ExtendedForestInformation Ability to provide Forest Information from another command to speed up processing .PARAMETER Filter Filter for Get-ADDomainController .PARAMETER TestAvailability Check if Domain Controllers are available .PARAMETER Test Pick what to check for availability. Options are: All, Ping, WinRM, PortOpen, Ping+WinRM, Ping+PortOpen, WinRM+PortOpen. Default is All .PARAMETER Ports Ports to check for availability. Default is 135 .PARAMETER PortsTimeout Ports timeout for availability check. Default is 100 .PARAMETER PingCount How many pings to send. Default is 1 .PARAMETER PreferWritable Prefer writable domain controllers over read-only ones when returning Query Servers .PARAMETER Extended Return extended information about domains with NETBIOS names .EXAMPLE Get-WinADForestDetails | Format-Table .EXAMPLE Get-WinADForestDetails -Forest 'ad.evotec.xyz' | Format-Table .NOTES General notes #> [CmdletBinding()] param( [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [string[]] $ExcludeDomainControllers, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [alias('DomainControllers', 'ComputerName')][string[]] $IncludeDomainControllers, [switch] $SkipRODC, [string] $Filter = '*', [switch] $TestAvailability, [ValidateSet('All', 'Ping', 'WinRM', 'PortOpen', 'Ping+WinRM', 'Ping+PortOpen', 'WinRM+PortOpen')] $Test = 'All', [int[]] $Ports = 135, [int] $PortsTimeout = 100, [int] $PingCount = 1, [switch] $PreferWritable, [switch] $Extended, [System.Collections.IDictionary] $ExtendedForestInformation ) if ($Global:ProgressPreference -ne 'SilentlyContinue') { $TemporaryProgress = $Global:ProgressPreference $Global:ProgressPreference = 'SilentlyContinue' } if (-not $ExtendedForestInformation) { $Findings = [ordered] @{ } try { if ($Forest) { $ForestInformation = Get-ADForest -ErrorAction Stop -Identity $Forest } else { $ForestInformation = Get-ADForest -ErrorAction Stop } } catch { Write-Warning "Get-WinADForestDetails - Error discovering DC for Forest - $($_.Exception.Message)" return } if (-not $ForestInformation) { return } $Findings['Forest'] = $ForestInformation $Findings['ForestDomainControllers'] = @() $Findings['QueryServers'] = @{ } $Findings['DomainDomainControllers'] = @{ } [Array] $Findings['Domains'] = foreach ($Domain in $ForestInformation.Domains) { if ($IncludeDomains) { if ($Domain -in $IncludeDomains) { $Domain.ToLower() } continue } if ($Domain -notin $ExcludeDomains) { $Domain.ToLower() } } [Array] $DomainsActive = foreach ($Domain in $Findings['Forest'].Domains) { try { $DC = Get-ADDomainController -DomainName $Domain -Discover -ErrorAction Stop -Writable:$PreferWritable.IsPresent $OrderedDC = [ordered] @{ Domain = $DC.Domain Forest = $DC.Forest HostName = [Array] $DC.HostName IPv4Address = $DC.IPv4Address IPv6Address = $DC.IPv6Address Name = $DC.Name Site = $DC.Site } } catch { Write-Warning "Get-WinADForestDetails - Error discovering DC for domain $Domain - $($_.Exception.Message)" continue } if ($Domain -eq $Findings['Forest']['Name']) { $Findings['QueryServers']['Forest'] = $OrderedDC } $Findings['QueryServers']["$Domain"] = $OrderedDC $Domain } [Array] $Findings['Domains'] = foreach ($Domain in $Findings['Domains']) { if ($Domain -notin $DomainsActive) { Write-Warning "Get-WinADForestDetails - Domain $Domain doesn't seem to be active (no DCs). Skipping." continue } $Domain } [Array] $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) { $QueryServer = $Findings['QueryServers'][$Domain]['HostName'][0] [Array] $AllDC = try { try { $DomainControllers = Get-ADDomainController -Filter $Filter -Server $QueryServer -ErrorAction Stop } catch { Write-Warning "Get-WinADForestDetails - Error listing DCs for domain $Domain - $($_.Exception.Message)" continue } foreach ($S in $DomainControllers) { if ($IncludeDomainControllers.Count -gt 0) { If (-not $IncludeDomainControllers[0].Contains('.')) { if ($S.Name -notin $IncludeDomainControllers) { continue } } else { if ($S.HostName -notin $IncludeDomainControllers) { continue } } } if ($ExcludeDomainControllers.Count -gt 0) { If (-not $ExcludeDomainControllers[0].Contains('.')) { if ($S.Name -in $ExcludeDomainControllers) { continue } } else { if ($S.HostName -in $ExcludeDomainControllers) { continue } } } $DSAGuid = (Get-ADObject -Identity $S.NTDSSettingsObjectDN -Server $QueryServer).ObjectGUID $Server = [ordered] @{ Domain = $Domain HostName = $S.HostName Name = $S.Name Forest = $ForestInformation.RootDomain Site = $S.Site IPV4Address = $S.IPV4Address IPV6Address = $S.IPV6Address IsGlobalCatalog = $S.IsGlobalCatalog IsReadOnly = $S.IsReadOnly IsSchemaMaster = ($S.OperationMasterRoles -contains 'SchemaMaster') IsDomainNamingMaster = ($S.OperationMasterRoles -contains 'DomainNamingMaster') IsPDC = ($S.OperationMasterRoles -contains 'PDCEmulator') IsRIDMaster = ($S.OperationMasterRoles -contains 'RIDMaster') IsInfrastructureMaster = ($S.OperationMasterRoles -contains 'InfrastructureMaster') OperatingSystem = $S.OperatingSystem OperatingSystemVersion = $S.OperatingSystemVersion OperatingSystemLong = ConvertTo-OperatingSystem -OperatingSystem $S.OperatingSystem -OperatingSystemVersion $S.OperatingSystemVersion LdapPort = $S.LdapPort SslPort = $S.SslPort DistinguishedName = $S.ComputerObjectDN NTDSSettingsObjectDN = $S.NTDSSettingsObjectDN DsaGuid = $DSAGuid DsaGuidName = "$DSAGuid._msdcs.$($ForestInformation.RootDomain)" Pingable = $null WinRM = $null PortOpen = $null Comment = '' } if ($TestAvailability) { if ($Test -eq 'All' -or $Test -like 'Ping*') { $Server.Pingable = Test-Connection -ComputerName $Server.IPV4Address -Quiet -Count $PingCount } if ($Test -eq 'All' -or $Test -like '*WinRM*') { $Server.WinRM = (Test-WinRM -ComputerName $Server.HostName).Status } if ($Test -eq 'All' -or '*PortOpen*') { $Server.PortOpen = (Test-ComputerPort -Server $Server.HostName -PortTCP $Ports -Timeout $PortsTimeout).Status } } [PSCustomObject] $Server } } catch { [PSCustomObject]@{ Domain = $Domain HostName = '' Name = '' Forest = $ForestInformation.RootDomain IPV4Address = '' IPV6Address = '' IsGlobalCatalog = '' IsReadOnly = '' Site = '' SchemaMaster = $false DomainNamingMasterMaster = $false PDCEmulator = $false RIDMaster = $false InfrastructureMaster = $false LdapPort = '' SslPort = '' DistinguishedName = '' NTDSSettingsObjectDN = '' DsaGuid = '' DsaGuidName = '' Pingable = $null WinRM = $null PortOpen = $null Comment = $_.Exception.Message -replace "`n", " " -replace "`r", " " } } if ($SkipRODC) { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC | Where-Object { $_.IsReadOnly -eq $false } } else { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC } if ($null -ne $Findings['DomainDomainControllers'][$Domain]) { [Array] $Findings['DomainDomainControllers'][$Domain] } } if ($Extended) { $Findings['DomainsExtended'] = @{ } $Findings['DomainsExtendedNetBIOS'] = @{ } foreach ($DomainEx in $Findings['Domains']) { try { $Findings['DomainsExtended'][$DomainEx] = Get-ADDomain -Server $Findings['QueryServers'][$DomainEx].HostName[0] | ForEach-Object { [ordered] @{ AllowedDNSSuffixes = $_.AllowedDNSSuffixes | ForEach-Object -Process { $_ } ChildDomains = $_.ChildDomains | ForEach-Object -Process { $_ } ComputersContainer = $_.ComputersContainer DeletedObjectsContainer = $_.DeletedObjectsContainer DistinguishedName = $_.DistinguishedName DNSRoot = $_.DNSRoot DomainControllersContainer = $_.DomainControllersContainer DomainMode = $_.DomainMode DomainSID = $_.DomainSID.Value ForeignSecurityPrincipalsContainer = $_.ForeignSecurityPrincipalsContainer Forest = $_.Forest InfrastructureMaster = $_.InfrastructureMaster LastLogonReplicationInterval = $_.LastLogonReplicationInterval LinkedGroupPolicyObjects = $_.LinkedGroupPolicyObjects | ForEach-Object -Process { $_ } LostAndFoundContainer = $_.LostAndFoundContainer ManagedBy = $_.ManagedBy Name = $_.Name NetBIOSName = $_.NetBIOSName ObjectClass = $_.ObjectClass ObjectGUID = $_.ObjectGUID ParentDomain = $_.ParentDomain PDCEmulator = $_.PDCEmulator PublicKeyRequiredPasswordRolling = $_.PublicKeyRequiredPasswordRolling | ForEach-Object -Process { $_ } QuotasContainer = $_.QuotasContainer ReadOnlyReplicaDirectoryServers = $_.ReadOnlyReplicaDirectoryServers | ForEach-Object -Process { $_ } ReplicaDirectoryServers = $_.ReplicaDirectoryServers | ForEach-Object -Process { $_ } RIDMaster = $_.RIDMaster SubordinateReferences = $_.SubordinateReferences | ForEach-Object -Process { $_ } SystemsContainer = $_.SystemsContainer UsersContainer = $_.UsersContainer } } $NetBios = $Findings['DomainsExtended'][$DomainEx]['NetBIOSName'] $Findings['DomainsExtendedNetBIOS'][$NetBios] = $Findings['DomainsExtended'][$DomainEx] } catch { Write-Warning "Get-WinADForestDetails - Error gathering Domain Information for domain $DomainEx - $($_.Exception.Message)" continue } } } if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress } $Findings } else { $Findings = Copy-DictionaryManual -Dictionary $ExtendedForestInformation [Array] $Findings['Domains'] = foreach ($_ in $Findings.Domains) { if ($IncludeDomains) { if ($_ -in $IncludeDomains) { $_.ToLower() } continue } if ($_ -notin $ExcludeDomains) { $_.ToLower() } } foreach ($_ in [string[]] $Findings.DomainDomainControllers.Keys) { if ($_ -notin $Findings.Domains) { $Findings.DomainDomainControllers.Remove($_) } } foreach ($_ in [string[]] $Findings.DomainsExtended.Keys) { if ($_ -notin $Findings.Domains) { $Findings.DomainsExtended.Remove($_) $NetBiosName = $Findings.DomainsExtended.$_.'NetBIOSName' if ($NetBiosName) { $Findings.DomainsExtendedNetBIOS.Remove($NetBiosName) } } } [Array] $Findings['ForestDomainControllers'] = foreach ($Domain in $Findings.Domains) { [Array] $AllDC = foreach ($S in $Findings.DomainDomainControllers["$Domain"]) { if ($IncludeDomainControllers.Count -gt 0) { If (-not $IncludeDomainControllers[0].Contains('.')) { if ($S.Name -notin $IncludeDomainControllers) { continue } } else { if ($S.HostName -notin $IncludeDomainControllers) { continue } } } if ($ExcludeDomainControllers.Count -gt 0) { If (-not $ExcludeDomainControllers[0].Contains('.')) { if ($S.Name -in $ExcludeDomainControllers) { continue } } else { if ($S.HostName -in $ExcludeDomainControllers) { continue } } } $S } if ($SkipRODC) { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC | Where-Object { $_.IsReadOnly -eq $false } } else { [Array] $Findings['DomainDomainControllers'][$Domain] = $AllDC } [Array] $Findings['DomainDomainControllers'][$Domain] } $Findings } } Function Get-WinADForestOptions { <# .SYNOPSIS This Cmdlet gets Active Directory Site Options. .DESCRIPTION This Cmdlet gets Active Directory Site Options. We can fill out the rest of this comment-based help later. .LINK http://myotherpcisacloud.com .LINK https://serverfault.com/questions/543143/detecting-ad-site-options-using-powershell .NOTES Written by Ryan Ries, October 2013. ryanries09@gmail.com. #> [CmdletBinding()] Param( [string] $Domain = $Env:USERDNSDOMAIN ) BEGIN { Add-Type -TypeDefinition @" [System.Flags] public enum nTDSSiteSettingsFlags { NTDSSETTINGS_OPT_IS_AUTO_TOPOLOGY_DISABLED = 0x00000001, NTDSSETTINGS_OPT_IS_TOPL_CLEANUP_DISABLED = 0x00000002, NTDSSETTINGS_OPT_IS_TOPL_MIN_HOPS_DISABLED = 0x00000004, NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED = 0x00000008, NTDSSETTINGS_OPT_IS_INTER_SITE_AUTO_TOPOLOGY_DISABLED = 0x00000010, NTDSSETTINGS_OPT_IS_GROUP_CACHING_ENABLED = 0x00000020, NTDSSETTINGS_OPT_FORCE_KCC_WHISTLER_BEHAVIOR = 0x00000040, NTDSSETTINGS_OPT_FORCE_KCC_W2K_ELECTION = 0x00000080, NTDSSETTINGS_OPT_IS_RAND_BH_SELECTION_DISABLED = 0x00000100, NTDSSETTINGS_OPT_IS_SCHEDULE_HASHING_ENABLED = 0x00000200, NTDSSETTINGS_OPT_IS_REDUNDANT_SERVER_TOPOLOGY_ENABLED = 0x00000400, NTDSSETTINGS_OPT_W2K3_IGNORE_SCHEDULES = 0x00000800, NTDSSETTINGS_OPT_W2K3_BRIDGES_REQUIRED = 0x00001000 } "@ if ($Domain) { $RootDSE = Get-ADRootDSE -Server $Domain } else { $RootDSE = Get-ADRootDSE } $DomainCN = ConvertFrom-DistinguishedName -DistinguishedName $RootDSE.defaultNamingContext -ToDomainCN $QueryServer = (Get-ADDomainController -DomainName $DomainCN -Discover -ErrorAction Stop).Hostname[0] $Sites = Get-ADObject -Filter 'objectClass -eq "site"' -SearchBase ($RootDSE).ConfigurationNamingContext -Server $QueryServer ForEach ($Site In $Sites) { $SiteSettings = Get-ADObject "CN=NTDS Site Settings,$($Site.DistinguishedName)" -Properties Options -Server $QueryServer If (!$SiteSettings.PSObject.Properties.Match('Options').Count -OR $SiteSettings.Options -EQ 0) { [PSCustomObject]@{ SiteName = $Site.Name DistinguishedName = $Site.DistinguishedName SiteOptions = '(none)' } } Else { [PSCustomObject]@{ SiteName = $Site.Name DistinguishedName = $Site.DistinguishedName SiteOptions = [Enum]::Parse('nTDSSiteSettingsFlags', $SiteSettings.Options) } } } } } function Get-WinADOrganizationalUnitData { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER OrganizationalUnit Parameter description .EXAMPLE An example Get-WinADOrganizationalUnitData -OrganizationalUnit 'OU=Users-O365,OU=Production,DC=ad,DC=evotec,DC=xyz' .NOTES Output of function: CanonicalName : ad.evotec.xyz/Production/Users-O365 City : CN : Country : PL Created : 09.11.2018 17:38:32 Description : OU for Synchronization of Users to Office 365 DisplayName : DistinguishedName : OU=Users-O365,OU=Production,DC=ad,DC=evotec,DC=xyz LinkedGroupPolicyObjects : {cn={74D09C6F-35E9-4743-BCF7-F87D7010C60D},cn=policies,cn=system,DC=ad,DC=evotec,DC=xyz} ManagedBy : Modified : 19.11.2018 22:54:47 Name : Users-O365 PostalCode : ProtectedFromAccidentalDeletion : True State : StreetAddress : #> [CmdletBinding()] param( [string[]] $OrganizationalUnit ) $Output = foreach ($OU in $OrganizationalUnit) { $Data = Get-ADOrganizationalUnit -Identity $OU -Properties CanonicalName, City, CN, Country, Created, Description, DisplayName, DistinguishedName, ManagedBy, Modified, Name, OU, PostalCode, ProtectedFromAccidentalDeletion, State, StreetAddress [PsCustomobject][Ordered] @{ CanonicalName = $Data.CanonicalName City = $Data.City CN = $Data.CN Country = $Data.Country Created = $Data.Created Description = $Data.Description DisplayName = $Data.DisplayName DistinguishedName = $Data.DistinguishedName LinkedGroupPolicyObjects = $Data.LinkedGroupPolicyObjects ManagedBy = Get-WinADUsersByDN -DistinguishedName $U.ManagedBy Modified = $Data.Modified Name = $Data.Name PostalCode = $Data.PostalCode ProtectedFromAccidentalDeletion = $Data.ProtectedFromAccidentalDeletion State = $Data.State StreetAddress = $Data.StreetAddress } } return $Output } function Get-WinADOrganizationalUnitFromDN { <# .SYNOPSIS .DESCRIPTION Long description .PARAMETER DistinguishedName Parameter description .EXAMPLE An example $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' Get-WinADOrganizationalUnitFromDN -DistinguishedName $DistinguishedName .NOTES General notes #> [CmdletBinding()] param( $DistinguishedName ) return [Regex]::Match($DistinguishedName, '(?=OU)(.*\n?)(?<=.)').Value } function Get-WinADUsersByDN { param( [alias('DN')][string[]]$DistinguishedName, [string] $Field = 'DisplayName', # return field [switch] $All ) $Properties = 'DistinguishedName', 'Enabled', 'GivenName', 'Name', 'SamAccountName', 'SID', 'Surname', 'UserPrincipalName', 'EmailAddress', 'DisplayName' $Users = foreach ($DN in $DistinguishedName) { try { Get-ADUser -Identity $DN -Properties $Properties } catch { } } if ($All) { return $Users } else { return $Users.$Field } } function Get-WinADUsersByOU { [CmdletBinding()] param ( $OrganizationalUnit ) $OU = Get-ADOrganizationalUnit $OrganizationalUnit if ($OU.ObjectClass -eq 'OrganizationalUnit') { try { $Users = Get-ADUser -SearchBase $OU -Filter * -Properties $Script:UserProperties } catch { Write-Color @Script:WriteParameters -Text '[i]', ' One or more properties are invalid - Terminating', ' Terminating' -Color Yellow, White, Red return } } return $Users } function Get-WinADUserSnapshot { [CmdletBinding()] [alias("Get-ADUserSnapshot")] param ( [parameter(Mandatory = $true)][Object] $User, [string] $XmlPath, [switch] $WhatIf ) $Object = @() try { $FullData = Get-ADUser -Identity $User.DistinguishedName -Properties * if (($XmlPath) -and (Test-Path $XmlPath)) { $FullPath = [IO.Path]::Combine($XmlPath, "$($User.SamAccountName).xml") if (-not $WhatIf) { $FullData | Export-Clixml -Path $FullPath -ErrorAction Stop } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Saved to $FullPath" } } else { $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = 'XmlPath Incorrect' } } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } } return $Object } function Remove-WinADUserGroups { [CmdletBinding()] [alias("Remove-ADUserGroups")] param( [parameter(Mandatory = $true)][Object] $User, [ValidateSet("Distribution", "Security")][String] $GroupCategory , [ValidateSet("DomainLocal", "Global", "Universal")][String] $GroupScope, [string[]] $Groups, [switch] $All, [switch] $WhatIf ) $Object = @() try { $ADgroups = Get-ADPrincipalGroupMembership -Identity $User.DistinguishedName -ErrorAction Stop | Where-Object { $_.Name -ne "Domain Users" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } if ($ADgroups) { if ($All) { foreach ($Group in $ADgroups) { try { if (-not $WhatIf) { Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $Group -Confirm:$false -ErrorAction Stop } $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } } if ($GroupCategory) { $ADGroupsByCategory = $ADgroups | Where-Object { $_.GroupCategory -eq $GroupCategory } if ($ADGroupsByCategory) { foreach ($Group in $ADGroupsByCategory) { try { if (-not $WhatIf) { Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $Group -Confirm:$false -ErrorAction Stop } $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } } } if ($GroupScope) { $ADGroupsByScope = $ADgroups | Where-Object { $_.GroupScope -eq $GroupScope } if ($ADGroupsByScope) { foreach ($Group in $ADGroupsByScope) { try { if (-not $WhatIf) { Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $Group -Confirm:$false -ErrorAction Stop } $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } } } if ($Groups) { foreach ($Group in $Groups) { $ADGroupsByName = $ADgroups | Where-Object { $_.Name -like $Group } if ($ADGroupsByName) { try { if (-not $WhatIf) { Remove-ADPrincipalGroupMembership -Identity $User.DistinguishedName -MemberOf $ADGroupsByName -Confirm:$false -ErrorAction Stop } $Object += @{ Status = $true; Output = $Group.Name; Extended = 'Removed from group.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } else { $Object += @{ Status = $false; Output = $Group.Name; Extended = 'Not available on user.' } } } } } return $Object } function Set-WinADGroupSynchronization { [CmdletBinding()] param( [parameter(Mandatory = $true)][string] $GroupFrom, [parameter(Mandatory = $true)][string] $GroupTo, [parameter(Mandatory = $false)][ValidateSet("User", "Group", "All")][string] $Type = 'User', [parameter(Mandatory = $false)][ValidateSet("None", "RecursiveFrom", "RecursiveBoth", "RecursiveTo")] $Recursive = 'None', [switch] $WhatIf ) Begin { $Object = @() if ($Recursive -eq 'None') { $GroupFromRecursive = $false $GroupToRecursive = $false } elseif ($Recursive -eq 'RecursiveFrom') { $GroupFromRecursive = $true $GroupToRecursive = $false } elseif ($Recursive -eq 'RecursiveBoth') { $GroupFromRecursive = $true $GroupToRecursive = $true } else { $GroupFromRecursive = $false $GroupToRecursive = $true } } Process { try { $GroupMembersFrom = Get-ADGroupMember -Identity $GroupFrom -Recursive:$GroupFromRecursive | Select-Object Name, ObjectClass, SamAccountName, UserPrincipalName } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } try { $GroupMembersTo = Get-ADGroupMember -Identity $GroupTo -Recursive:$GroupToRecursive | Select-Object Name, ObjectClass, SamAccountName, UserPrincipalName } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } if ($Object.Count -gt 0) { return $Object } foreach ($User in $GroupMembersFrom) { if ($User.ObjectClass -eq "user") { if ($Type -eq 'User' -or $Type -eq 'All') { if ($GroupMembersTo.SamAccountName -notcontains $User.SamAccountName) { try { if (-not $WhatIf) { Add-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Added to group $GroupTo" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } } } else { if ($Type -eq 'Group' -or $Type -eq 'All') { if ($GroupMembersTo.SamAccountName -notcontains $User.SamAccountName) { try { if (-not $WhatIf) { Add-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Added to group $GroupTo" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } } } } foreach ($User in $GroupMembersTo) { if ($User.ObjectClass -eq "user") { if ($Type -eq 'User' -or $Type -eq 'All') { if ($GroupMembersFrom.SamAccountName -notcontains $User.SamAccountName) { Write-Color "Not a member of $GroupFrom - requires removal from $GroupTo ", $User.SamAccountName -Color Red -LogFile $LogFile try { if (-not $WhatIf) { Remove-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName -Confirm:$false } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Removed from group $GroupTo" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } } } else { if ($Type -eq 'Group' -or $Type -eq 'All') { if ($GroupMembersFrom.SamAccountName -notcontains $User.SamAccountName) { Write-Color "Not a member of $GroupFrom - requires removal from $GroupTo ", $User.SamAccountName -Color Red -LogFile $LogFile try { if (-not $WhatIf) { Remove-ADGroupMember -Identity $GroupTo -Members $User.SamAccountName -Confirm:$false } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Removed from group $GroupTo" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $Group.Name; Extended = $ErrorMessage } } } } } } } End { return $object } } function Set-WinADUserFields { [CmdletBinding()] [alias("Set-ADUserName")] param ( [parameter(Mandatory = $true)][Object] $User, [parameter(Mandatory = $false)][ValidateSet("Before", "After")][String] $Option, [string] $TextToAdd, [string] $TextToRemove, [string[]] $Fields, [switch] $WhatIf ) $Object = @() if ($TextToAdd) { foreach ($Field in $Fields) { if ($User.$Field -notlike "*$TextToAdd*") { if ($Option -eq 'After') { $NewName = "$($User.$Field)$TextToAdd" } elseif ($Option -eq 'Before') { $NewName = "$TextToAdd$($User."$Field")" } if ($NewName -ne $User.$Field) { if ($Field -eq 'Name') { try { if (-not $WhatIf) { Rename-ADObject -Identity $User.DistinguishedName -NewName $NewName } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed account '$Field' to '$NewName'" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } } } else { $Splat = @{ Identity = $User.DistinguishedName "$Field" = $NewName } try { if (-not $WhatIf) { Set-ADUser @Splat } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed field '$Field' to '$NewName'" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } } } } } } } if ($TextToRemove) { foreach ($Field in $Fields) { if ($User.$Field -like "*$TextToRemove*") { $NewName = $($User.$Field).Replace($TextToRemove, '') if ($Field -eq 'Name') { try { if (-not $WhatIf) { Rename-ADObject -Identity $User.DistinguishedName -NewName $NewName } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed account '$Field' to '$NewName'" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = "Field: '$Field' Error: '$ErrorMessage'" } } } else { $Splat = @{ Identity = $User.DistinguishedName "$Field" = $NewName } try { if (-not $WhatIf) { Set-ADUser @Splat } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = "Renamed field $Field to $NewName" } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = "Field: $Field Error: $ErrorMessage" } } } } } } return $Object } Function Set-WinADUserSettingGAL { [CmdletBinding()] [alias("Set-ADUserSettingGAL")] param ( [parameter(Mandatory = $true)][Object] $User, [parameter(Mandatory = $true)][ValidateSet("Hide", "Show")][String]$Option, [switch] $WhatIf ) $Object = @() if ($User) { if ($Option -eq 'Hide') { if (-not $User.msExchHideFromAddressLists) { try { if (-not $WhatIf) { Set-ADObject -Identity $User.DistinguishedName -Replace @{msExchHideFromAddressLists = $true } } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Hidden from GAL.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } } } } elseif ($Option -eq 'Show') { if ($User.msExchHideFromAddressLists) { try { if ($WhatIf) { Set-ADObject -Identity $User.DistinguishedName -Clear msExchHideFromAddressLists } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Unhidden in GAL.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } } } } } return $Object } function Set-WinADUserStatus { [CmdletBinding()] [alias("Set-ADUserStatus")] param ( [parameter(Mandatory = $true)][Object] $User, [parameter(Mandatory = $true)][ValidateSet("Enable", "Disable")][String] $Option, [switch] $WhatIf # $WriteParameters ) $Object = @() if ($Option -eq 'Enable' -and $User.Enabled -eq $false) { try { if (-not $WhatIf) { Set-ADUser -Identity $User.DistinguishedName -Enabled $true } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Enabled user.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } } } elseif ($Option -eq 'Disable' -and $User.Enabled -eq $true) { try { if (-not $WhatIf) { Set-ADUser -Identity $User.DistinguishedName -Enabled $false } $Object += @{ Status = $true; Output = $User.SamAccountName; Extended = 'Disabled user.' } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " $Object += @{ Status = $false; Output = $User.SamAccountName; Extended = $ErrorMessage } } } return $Object } function Get-CimData { <# .SYNOPSIS Helper function for retreiving CIM data from local and remote computers .DESCRIPTION Helper function for retreiving CIM data from local and remote computers .PARAMETER ComputerName Specifies computer on which you want to run the CIM operation. You can specify a fully qualified domain name (FQDN), a NetBIOS name, or an IP address. If you do not specify this parameter, the cmdlet performs the operation on the local computer using Component Object Model (COM). .PARAMETER Protocol Specifies the protocol to use. The acceptable values for this parametDer are: DCOM, Default, or Wsman. .PARAMETER Class Specifies the name of the CIM class for which to retrieve the CIM instances. You can use tab completion to browse the list of classes, because PowerShell gets a list of classes from the local WMI server to provide a list of class names. .PARAMETER Properties Specifies a set of instance properties to retrieve. Use this parameter when you need to reduce the size of the object returned, either in memory or over the network. The object returned also contains the key properties even if you have not listed them using the Property parameter. Other properties of the class are present but they are not populated. .PARAMETER NameSpace Specifies the namespace for the CIM operation. The default namespace is root\cimv2. You can use tab completion to browse the list of namespaces, because PowerShell gets a list of namespaces from the local WMI server to provide a list of namespaces. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. .EXAMPLE Get-CimData -Class 'win32_bios' -ComputerName AD1,EVOWIN .EXAMPLE Get-CimData -Class 'win32_bios' .EXAMPLE Get-CimClass to get all classes .NOTES General notes #> [CmdletBinding()] param( [parameter(Mandatory)][string] $Class, [string] $NameSpace = 'root\cimv2', [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [pscredential] $Credential, [string[]] $Properties = '*' ) $ExcludeProperties = 'CimClass', 'CimInstanceProperties', 'CimSystemProperties', 'SystemCreationClassName', 'CreationClassName' [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName $CimObject = @( [string[]] $PropertiesOnly = $Properties | Where-Object { $_ -ne 'PSComputerName' } $Computers = $ComputersSplit[1] if ($Computers.Count -gt 0) { if ($Protocol -eq 'Default' -and $null -eq $Credential) { Get-CimInstance -ClassName $Class -ComputerName $Computers -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsToProcess | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties } else { $Option = New-CimSessionOption -Protocol $Protocol $newCimSessionSplat = @{ ComputerName = $Computers SessionOption = $Option ErrorAction = 'SilentlyContinue' } if ($Credential) { $newCimSessionSplat['Credential'] = $Credential } $Session = New-CimSession @newCimSessionSplat -Verbose:$false if ($Session) { Try { $Info = Get-CimInstance -ClassName $Class -CimSession $Session -ErrorAction Stop -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsToProcess | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties } catch { Write-Warning -Message "Get-CimData - No data for computer $($E.OriginInfo.PSComputerName). Failed with errror: $($E.Exception.Message)" } try { $null = Remove-CimSession -CimSession $Session -ErrorAction SilentlyContinue } catch { Write-Warning -Message "Get-CimData - Failed to remove CimSession $($Session). Failed with errror: $($E.Exception.Message)" } $Info } else { Write-Warning -Message "Get-CimData - Failed to create CimSession for $($Computers). Problem with credentials?" } } foreach ($E in $ErrorsToProcess) { Write-Warning -Message "Get-CimData - No data for computer $($E.OriginInfo.PSComputerName). Failed with errror: $($E.Exception.Message)" } } else { $Computers = $ComputersSplit[0] if ($Computers.Count -gt 0) { $Info = Get-CimInstance -ClassName $Class -ErrorAction SilentlyContinue -Property $PropertiesOnly -Namespace $NameSpace -Verbose:$false -ErrorVariable ErrorsLocal | Select-Object -Property $Properties -ExcludeProperty $ExcludeProperties $Info | Add-Member -Name 'PSComputerName' -Value $Computers -MemberType NoteProperty -Force $Info } foreach ($E in $ErrorsLocal) { Write-Warning -Message "Get-CimData - No data for computer $($Env:COMPUTERNAME). Failed with errror: $($E.Exception.Message)" } } ) $CimObject } function Get-Computer { [cmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Application', 'BIOS', 'CPU', 'RAM', 'Disk', 'DiskLogical', 'Network', 'NetworkFirewall', 'OperatingSystem', 'Services', 'System', 'Startup', 'Time', 'WindowsUpdates' )][string[]] $Type, [switch] $AsHashtable ) Begin { } Process { foreach ($Computer in $ComputerName) { $OutputObject = [ordered] @{} if ($Type -contains 'Application' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing Application for $Computer" $Application = Get-ComputerApplication -ComputerName $Computer $OutputObject['Application'] = $Application } if ($Type -contains 'BIOS' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing BIOS for $Computer" $BIOS = Get-ComputerBios -ComputerName $Computer $OutputObject['BIOS'] = $BIOS } if ($Type -contains 'CPU' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing CPU for $Computer" $CPU = Get-ComputerCPU -ComputerName $Computer $OutputObject['CPU'] = $CPU } if ($Type -contains 'RAM' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing RAM for $Computer" $RAM = Get-ComputerRAM -ComputerName $Computer $OutputObject['RAM'] = $RAM } if ($Type -contains 'Disk' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing Disk for $Computer" $Disk = Get-ComputerDisk -ComputerName $Computer $OutputObject['Disk'] = $Disk } if ($Type -contains 'DiskLogical' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing DiskLogical for $Computer" $DiskLogical = Get-ComputerDiskLogical -ComputerName $Computer $OutputObject['DiskLogical'] = $DiskLogical } if ($Type -contains 'OperatingSystem' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing OperatingSystem for $Computer" $OperatingSystem = Get-ComputerOperatingSystem -ComputerName $Computer $OutputObject['OperatingSystem'] = $OperatingSystem } if ($Type -contains 'Network' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing Network for $Computer" $Network = Get-ComputerNetwork -ComputerName $Computer $OutputObject['Network'] = $Network } if ($Type -contains 'NetworkFirewall' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing NetworkFirewall for $Computer" $NetworkFirewall = Get-ComputerNetwork -ComputerName $Computer -NetworkFirewallOnly $OutputObject['NetworkFirewall'] = $NetworkFirewall } if ($Type -contains 'RDP' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing RDP for $Computer" $RDP = Get-ComputerRDP -ComputerName $Computer $OutputObject['RDP'] = $RDP } if ($Type -contains 'Services' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing Services for $Computer" $Services = Get-ComputerService -ComputerName $Computer $OutputObject['Services'] = $Services } if ($Type -contains 'System' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing System for $Computer" $System = Get-ComputerSystem -ComputerName $Computer $OutputObject['System'] = $System } if ($Type -contains 'Startup' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing Startup for $Computer" $Startup = Get-ComputerStartup -ComputerName $Computer $OutputObject['Startup'] = $Startup } if ($Type -contains 'Time' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing Time for $Computer" $Time = Get-ComputerTime -TimeTarget $Computer $OutputObject['Time'] = $Time } if ($Type -contains 'Tasks' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing Tasks for $Computer" $Tasks = Get-ComputerTask -ComputerName $Computer $OutputObject['Tasks'] = $Tasks } if ($Type -contains 'WindowsUpdates' -or $null -eq $Type) { Write-Verbose "Get-Computer - Processing WindowsUpdates for $Computer" $WindowsUpdates = Get-ComputerWindowsUpdates -ComputerName $Computer $OutputObject['WindowsUpdates'] = $WindowsUpdates } if ($AsHashtable) { $OutputObject } else { [PSCustomObject] $OutputObject } } } } function Get-ComputerApplication { <# .SYNOPSIS Get software installed on computer or server .DESCRIPTION Get software installed on computer or server .PARAMETER ComputerName Specifies computer on which you want to run the operation. .EXAMPLE Get-ComputerApplications -Verbose | Format-Table .EXAMPLE Get-ComputerApplications -Verbose -ComputerName AD1, AD2 | Format-Table .NOTES General notes #> [alias('Get-ComputerApplications')] [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME ) $ScriptBlock = { $objapp1 = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* $objapp2 = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* $app1 = $objapp1 | Select-Object Displayname, Displayversion , Publisher, Installdate, @{Expression = { 'x64' }; Label = 'WindowsType' } $app2 = $objapp2 | Select-Object Displayname, Displayversion , Publisher, Installdate, @{Expression = { 'x86' }; Label = 'WindowsType' } | Where-Object { -NOT (([string]$_.displayname).contains('Security Update for Microsoft') -or ([string]$_.displayname).contains('Update for Microsoft')) } $app = $app1 + $app2 $app | Where-Object { $null -ne $_.Displayname } } foreach ($Computer in $ComputerName) { try { $LocalComputerDNSName = [System.Net.Dns]::GetHostByName($Env:COMPUTERNAME).HostName } catch { $LocalComputerDNSName = $Computer } if ($Computer -eq $Env:COMPUTERNAME -or $Computer -eq $LocalComputerDNSName) { $Parameters = @{ ScriptBlock = $ScriptBlock } } else { $Parameters = @{ ComputerName = $Computer ScriptBlock = $ScriptBlock } } try { $Data = Invoke-Command @Parameters } catch { Write-Warning "Get-ComputerApplication - No data for computer $Computer" continue } foreach ($Information in $Data) { if ($Information.Installdate) { try { $InstallDate = [datetime]::ParseExact($Information.Installdate, 'yyyyMMdd', $null) } catch { Write-Verbose "Get-ComputerApplication - InstallDate $($Information.Installdate) couldn't be converted." $InstallDate = $null } } else { $InstallDate = $null } [PSCustomObject] @{ DisplayName = $Information.DisplayName Version = $Information.DisplayVersion Publisher = $Information.Publisher Installdate = $InstallDate Type = $Information.WindowsType ComputerName = $Computer } } } } function Get-ComputerBios { [CmdletBinding()] param( [string] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All ) [string] $Class = 'win32_bios' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'PSComputerName', 'Status', 'Version', 'PrimaryBIOS', 'Manufacturer', 'ReleaseDate', 'SerialNumber', 'SMBIOSBIOSVersion', 'SMBIOSMajorVersion', 'SMBIOSMinorVersion', 'SystemBiosMajorVersion', 'SystemBiosMinorVersion' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Status = $Data.Status Version = $Data.Version VersionBIOS = -join ($Data.SMBIOSMajorVersion, ".", $Data.SMBIOSMinorVersion, ".", $Data.SystemBiosMajorVersion, ".", $Data.SystemBiosMinorVersion) PrimaryBIOS = $Data.PrimaryBIOS Manufacturer = $Data.Manufacturer ReleaseDate = $Data.ReleaseDate } } } } } function Get-ComputerCPU { [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All ) [string] $Class = 'win32_processor' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'PSComputerName', 'Name', 'DeviceID', 'Caption', 'SystemName', 'CurrentClockSpeed', 'MaxClockSpeed', 'ProcessorID', 'ThreadCount', 'Architecture', 'Status', 'LoadPercentage', 'L3CacheSize', 'Manufacturer', 'VirtualizationFirmwareEnabled', 'NumberOfCores', 'NumberOfEnabledCore', 'NumberOfLogicalProcessors' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Name = $Data.Name DeviceID = $Data.DeviceID Caption = $Data.Caption CurrentClockSpeed = $Data.CurrentClockSpeed MaxClockSpeed = $Data.MaxClockSpeed ProcessorID = $Data.ProcessorID ThreadCount = $Data.ThreadCount Architecture = $Data.Architecture Status = $Data.Status LoadPercentage = $Data.LoadPercentage Manufacturer = $Data.Manufacturer NumberOfCores = $Data.NumberOfCores NumberOfEnabledCore = $Data.NumberOfEnabledCore NumberOfLogicalProcessors = $Data.NumberOfLogicalProcessors } } } } } function Get-ComputerCulture { [CmdletBinding()] param( [string] $ComputerName = $Env:COMPUTERNAME ) $ScriptBlock = { Get-Culture | Select-Object KeyboardLayoutId, DisplayName, @{Expression = { $_.ThreeLetterWindowsLanguageName }; Label = "Windows Language" } } if ($ComputerName -eq $Env:COMPUTERNAME) { $Data8 = Invoke-Command -ScriptBlock $ScriptBlock } else { $Data8 = Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock } return $Data8 } function Get-ComputerDevice { [CmdletBinding()] param( [string] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All, [switch] $Extended ) [string] $Class = 'win32_pnpentity' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = @( 'PNPClass' 'Name' 'Status' 'ConfigManagerErrorCode' 'DeviceID' 'ErrorCleared' 'ErrorDescription' 'LastErrorCode' 'StatusInfo' 'ClassGuid' 'CompatibleID' 'HardwareID' 'Manufacturer' 'PSComputerName' ) } $ConfigManagerErrorCode = @{ '0' = "This device is working properly." '1' = 'This device is not configured correctly.' '2' = 'Windows cannot load the driver for this device.' '3' = "The driver for this device might be corrupted, or your system may be running low on memory or other resources." '4' = "This device is not working properly. One of its drivers or your registry might be corrupted." '5' = "The driver for this device needs a resource that Windows cannot manage." '6' = "The boot configuration for this device conflicts with other devices." '7' = "Cannot filter." '8' = "The driver loader for the device is missing." '9' = "This device is not working properly because the controlling firmware is reporting the resources for the device incorrectly." '10' = "This device cannot start." '11' = "This device failed." '12' = "This device cannot find enough free resources that it can use." '13' = "Windows cannot verify this device's resources." '14' = "This device cannot work properly until you restart your computer." '15' = "This device is not working properly because there is probably a re-enumeration problem." '16' = "Windows cannot identify all the resources this device uses." '17' = "This device is asking for an unknown resource type." '18' = "Reinstall the drivers for this device." '19' = "Failure using the VxD loader." '20' = "Your registry might be corrupted." '21' = "System failure: Try changing the driver for this device. If that does not work, see your hardware documentation. Windows is removing this device." '22' = "This device is disabled." '23' = "System failure: Try changing the driver for this device. If that doesn't work, see your hardware documentation." '24' = "This device is not present, is not working properly, or does not have all its drivers installed." '25' = "Windows is still setting up this device." '26' = "Windows is still setting up this device." '27' = "This device does not have valid log configuration." '28' = "The drivers for this device are not installed." '29' = "This device is disabled because the firmware of the device did not give it the required resources." '30' = "This device is using an Interrupt Request (IRQ) resource that another device is using." '31' = "This device is not working properly because Windows cannot load the drivers required for this device." } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { $Device = [ordered]@{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } 'DeviceClass' = $Data.PNPClass 'Name' = $Data.Name 'Status' = $Data.Status 'ErrorCode' = $ConfigManagerErrorCode["$($Data.ConfigManagerErrorCode)"] 'DeviceID' = $Data.DeviceID } if ($Extended) { $DeviceUpgrade = [ordered]@{ 'ErrorCleared' = $Data.ErrorCleared 'ErrorDescription' = $Data.ErrorDescription 'LastErrorCode' = $Data.LastErrorCode 'StatusInfo' = $Data.StatusInfo 'ClassGuid' = $Data.ClassGuid 'CompatibleID' = $Data.CompatibleID 'HardwareID' = $Data.HardwareID 'Manufacturer' = if ($Data.Manufacturer) { $Data.Manufacturer.Replace('(', '').Replace(')', '') } else { } } [PSCustomObject] ($Device + $DeviceUpgrade) } else { [PSCustomObject] $Device } } } } } function Get-ComputerDisk { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ComputerName Parameter description .PARAMETER Protocol Parameter description .PARAMETER All Parameter description .EXAMPLE Get-ComputerDisk -ComputerName AD1, AD2, EVO1, AD2019 | Format-Table -AutoSize * Output: WARNING: Get-ComputerSystem - No data for computer AD2019. Most likely an error on receiving side. ComputerName Index Model Caption SerialNumber Description MediaType FirmwareRevision Partitions SizeGB PNPDeviceID ------------ ----- ----- ------- ------------ ----------- --------- ---------------- ---------- ------ ----------- AD1 0 Microsoft Virtual Disk Microsoft Virtual Disk Disk drive Fixed hard disk media 1.0 3 127 SCSI\DISK&VEN_MSFT&PROD_VIRTUAL_DISK\000000 AD2 0 Microsoft Virtual Disk Microsoft Virtual Disk Disk drive Fixed hard disk media 1.0 3 127 SCSI\DISK&VEN_MSFT&PROD_VIRTUAL_DISK\000000 EVO1 0 WDC WD30EFRX-68AX9N0 WDC WD30EFRX-68AX9N0 WD-WMC1T2351095 Disk drive Fixed hard disk media 80.00A80 1 2795 SCSI\DISK&VEN_WDC&PROD_WD30EFRX-68AX9N0\4&191557A4&0&000000 EVO1 2 Samsung SSD 950 PRO 512GB Samsung SSD 950 PRO 512GB 0025_3857_61B0_0EF2. Disk drive Fixed hard disk media 2B0Q 3 477 SCSI\DISK&VEN_NVME&PROD_SAMSUNG_SSD_950\5&35365596&0&000000 EVO1 1 Samsung SSD 860 EVO 500GB Samsung SSD 860 EVO 500GB S3Z2NB0K176976A Disk drive Fixed hard disk media RVT01B6Q 1 466 SCSI\DISK&VEN_SAMSUNG&PROD_SSD\4&191557A4&0&000100 .NOTES General notes #> [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All ) [string] $Class = 'win32_diskdrive' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'Index', 'Model', 'Caption', 'SerialNumber', 'Description', 'MediaType', 'FirmwareRevision', 'Partitions', 'Size', 'PNPDeviceID', 'PSComputerName' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Index = $Data.Index Model = $Data.Model Caption = $Data.Caption SerialNumber = if ($Data.SerialNumber) { $Data.SerialNumber.Trim() } else { '' } Description = $Data.Description MediaType = $Data.MediaType FirmwareRevision = $Data.FirmwareRevision Partitions = $Data.Partitions SizeGB = $Data.Size / 1Gb -as [int] PNPDeviceID = $Data.PNPDeviceID } } } } } function Get-ComputerDiskLogical { <# .SYNOPSIS Getting drive space .DESCRIPTION Long description .PARAMETER ComputerName Parameter description .PARAMETER Protocol Parameter description .PARAMETER RoundingPlaceRoundingPlace .PARAMETER RoundingPlace .PARAMETER OnlyLocalDisk Parameter description .PARAMETER All Parameter description .EXAMPLE Get-ComputerDiskLogical -ComputerName AD1, AD2, EVOWIN -OnlyLocalDisk | ft -AutoSize Output: ComputerName DeviceID DriveType ProviderName FreeSpace UsedSpace TotalSpace FreePercent UsedPercent VolumeName ------------ -------- --------- ------------ --------- --------- ---------- ----------- ----------- ---------- AD2 C: Local Disk 96,96 29,49 126,45 76,68 23,32 AD1 C: Local Disk 103,17 23,28 126,45 81,59 18,41 EVOWIN C: Local Disk 133,31 343,03 476,34 27,99 72,01 EVOWIN D: Local Disk 2433 361,4 2794,39 87,07 12,93 Media EVOWIN E: Local Disk 66,05 399,7 465,75 14,18 85,82 Testing Environment .NOTES General notes #> [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [string][ValidateSet('GB', 'TB', 'MB')] $Size = 'GB', [int] $RoundingPlace = 2, [int] $RoundingPlacePercent = 2, [switch] $OnlyLocalDisk, [switch] $All ) [string] $Class = 'win32_logicalDisk' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'DeviceID', 'DriveType', 'ProviderName', 'FreeSpace', 'Size', 'VolumeName', 'PSComputerName' } $DriveType = @{ '0' = 'Unknown' '1' = 'No Root Directory' '2' = 'Removable Disk' '3' = 'Local Disk' '4' = 'Network Drive' '5' = 'Compact Disc' '6' = 'RAM Disk' } $Divider = "1$Size" $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { $Output = foreach ($Info in $Information) { foreach ($Data in $Info) { [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } DeviceID = $Data.DeviceID DriveType = $DriveType["$($Data.DriveType)"] ProviderName = $Data.ProviderName FreeSpace = [Math]::Round($Data.FreeSpace / $Divider, $RoundingPlace) UsedSpace = [Math]::Round(($Data.Size - $Data.FreeSpace) / $Divider, $RoundingPlace) TotalSpace = [Math]::Round($Data.Size / $Divider, $RoundingPlace) FreePercent = if ($Data.Size -gt 0 ) { [Math]::round(($Data.FreeSpace / $Data.Size) * 100, $RoundingPlacePercent) } else { '0' } UsedPercent = if ($Data.Size -gt 0 ) { [Math]::round((($Data.Size - $Data.FreeSpace) / $Data.Size) * 100, $RoundingPlacePercent) } else { '0' } VolumeName = $Data.VolumeName } } } if ($OnlyLocalDisk) { $Output | Where-Object { $_.DriveType -eq 'Local Disk' } } else { $Output } } } function Get-ComputerInstalledUpdates { [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet( 'Antivirus', 'Cumulative Update', 'Windows Update', 'Servicing Stack Update', 'Other' )][string[]] $IncludeType, [ValidateSet( 'Antivirus', 'Cumulative Update', 'Windows Update', 'Servicing Stack Update', 'Other' )][string[]] $ExcludeType, [string] $SearchKB, [pscredential] $Credential ) $Properties = @( 'ComputerName', 'InstalledOn', 'KB', 'Categories', 'Type', 'Version', 'Title', 'ClientApplicationID', 'InstalledFrom', 'Description', 'Operation', 'Status', 'SupportUrl', 'UpdateID', 'RevisionNumber', 'UnmappedResultCode', 'HResult', 'ServiceID', 'UninstallationSteps', 'UninstallationNotes' ) $ScriptBlock = { $Session = New-Object -ComObject Microsoft.Update.Session $Searcher = $Session.CreateUpdateSearcher() $historyCount = $Searcher.GetTotalHistoryCount() $kbRegex = '(KB\d+)' $versionRegex = 'Version (\d+\.\d+\.\d+\.\d+)' $QueryHistory = $Searcher.QueryHistory(0, $historyCount) $QueryHistory | Where-Object date -GT (Get-Date "1/1/2000") | ForEach-Object { $KbMatch = Select-String $kbRegex -InputObject $_.Title $Kb = if ($kbMatch) { $kbMatch.matches.groups[0].value } else { $null } $VersionMatch = Select-String $VersionRegex -InputObject $_.Title $Version = if ($VersionMatch) { $VersionMatch.matches.groups[1].value } else { $null } $Categories = $_.Categories | ForEach-Object { $_.Name } if ($_.Title -like "*Security Intelligence Update*" -or $_.Title -like "*Antivirus*" -or $_.Title -like "*Malicious Software*") { $Type = "Antivirus" } elseif ($_.Title -like "*Cumulative Update*") { $Type = "Cumulative Update" } elseif ($_.Title -like "*Update for Windows*" -or $_.Title -like "*Security Update*" -or $_.Title -like "*Update for Microsoft*" -or $_.Title -like "*Update for Internet Explorer*") { $Type = "Windows Update" } elseif ($_.Title -like "*Servicing Stack Update*") { $Type = "Servicing Stack Update" } else { $Type = "Other" } [PSCustomObject]@{ "ComputerName" = $Env:COMPUTERNAME "InstalledOn" = $_.Date "KB" = $Kb "Categories" = $Categories "Type" = $Type "Version" = $Version "ClientApplicationID" = $_.ClientApplicationID "InstalledFrom" = switch ($_.ServerSelection) { 0 { "Default" }; 1 { "Managed Server" }; 2 { "Windows Update" }; 3 { "Others" } } "Title" = $_.Title "Description" = $_.Description "Operation" = switch ($_.operation) { 1 { "Installation" }; 2 { "Uninstallation" }; 3 { "Other" } } "Status" = switch ($_.resultcode) { 1 { "In Progress" }; 2 { "Succeeded" }; 3 { "Succeeded With Errors" }; 4 { "Failed" }; 5 { "Aborted" } } "SupportUrl" = $_.SupportUrl "UpdateID" = $_.UpdateIdentity.UpdateID "RevisionNumber" = $_.UpdateIdentity.RevisionNumber "UnmappedResultCode" = $_.UnmappedResultCode "HResult" = $_.HResult "ServiceID" = $_.ServiceID "UninstallationSteps" = $_.UninstallationSteps.Name "UninstallationNotes" = $_.UninstallationNotes } } } [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName $Computers = $ComputersSplit[1] $Data = if ($Computers.Count -gt 0) { foreach ($Computer in $Computers) { try { $invokeCommandSplat = @{ ComputerName = $Computer ScriptBlock = $ScriptBlock ErrorAction = 'Stop' } if ($Credential) { $invokeCommandSplat.Credential = $Credential } Invoke-Command @invokeCommandSplat | Select-Object -Property $Properties } catch { Write-Warning -Message "Get-ComputerInstalledUpdates - No data for computer $Computer. Failed with error: $($_.Exception.Message)" } } } else { try { $invokeCommandSplat = @{ ScriptBlock = $ScriptBlock ErrorAction = 'Stop' } if ($Credential) { $invokeCommandSplat.Credential = $Credential } Invoke-Command @invokeCommandSplat } catch { Write-Warning -Message "Get-ComputerInstalledUpdates - No data for computer $($Env:COMPUTERNAME). Failed with error: $($_.Exception.Message)" } } if ($SearchKB) { foreach ($D in $Data) { if ($D.KB -like "*$SearchKB*") { $D } } } else { foreach ($Update in $Data) { if ($IncludeType -and $IncludeType -notcontains $Update.Type) { continue } if ($ExcludeType -and $ExcludeType -contains $Update.Type) { continue } $Update } } } function Get-ComputerMemory { [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All ) [string] $Class = 'win32_operatingsystem' if ($All) { [string] $Properties = '*' } else { [string] $Properties = "*" } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Data in $Information) { $FreeMB = [math]::Round($Data.FreePhysicalMemory / 1024, 2) $TotalMB = [math]::Round($Data.TotalVisibleMemorySize / 1024, 2) $UsedMB = $TotalMB - $FreeMB $UsedPercent = [math]::Round(($UsedMB / $TotalMB) * 100, 2) $FreeVirtualMB = [math]::Round($Data.FreeVirtualMemory / 1024, 2) $TotalVirtualMB = [math]::Round($Data.TotalVirtualMemorySize / 1024, 2) $UsedVirtualMB = $TotalVirtualMB - $FreeVirtualMB $UsedVirtualPercent = [math]::Round(($UsedVirtualMB / $TotalVirtualMB) * 100, 2) [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } MemoryUsed = $UsedMB MemoryFree = $FreeMB MemoryTotal = $TotalMB MemoryUsedPercentage = $UsedPercent VirtualMemoryUsed = $UsedVirtualMB VirtualMemoryUsedPercentage = $UsedVirtualPercent VirtualMemoryFree = $FreeVirtualMB VirtualMemoryTotal = $TotalVirtualMB } } } } function Get-ComputerMissingDrivers { [CmdletBinding()] param( [string] $ComputerName = $Env:COMPUTERNAME ) $Data = Get-WmiObject Win32_PNPEntity -ComputerName $ComputerName | Where-Object { $_.Configmanagererrorcode -ne 0 } | Select-Object Caption, ConfigmanagererrorCode, Description, DeviceId, HardwareId, PNPDeviceID return $Data } function Get-ComputerNetwork { [alias('Get-ComputerNetworkCard')] <# .SYNOPSIS .DESCRIPTION Long description .PARAMETER ComputerName Parameter description .PARAMETER NetworkFirewallOnly Parameter description .PARAMETER NetworkFirewallSummaryOnly Parameter description .EXAMPLE Get-ComputerNetworkCard -ComputerName AD1, AD2, AD3 Output Name NetworkCardName NetworkCardIndex FirewallProfile FirewallStatus IPv4Connectivity IPv6Connectivity Caption Description ElementName DefaultInboundAction DefaultOutboundAction AllowInboundRules AllowLocalFirewallRules AllowLocalIPsecRules AllowUserApps AllowUserPorts AllowUnicastResponseToMulticast NotifyOnListen EnableStealthModeForIPsec LogFileName LogMaxSizeKilobytes LogAllowed LogBlo cked ---- --------------- ---------------- --------------- -------------- ---------------- ---------------- ------- ----------- ----------- -------------------- --------------------- ----------------- ----------------------- -------------------- ------------- -------------- ------------------------------- -------------- ------------------------- ----------- ------------------- ---------- ------ ad.evotec.xyz vEthernet (External Switch) 13 DomainAuthenticated True Internet NoTraffic NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured True NotConfigured %systemroot%\system32\LogFiles\Firewall\pfirewall.log 4096 False False Network 2 Ethernet 2 2 Private True Internet NoTraffic Block Allow NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured False NotConfigured %systemroot%\system32\LogFiles\Firewall\pfirewall.log 4096 False False Network Ethernet 2 Private True LocalNetwork NoTraffic NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured False NotConfigured %systemroot%\system32\LogFiles\Firewall\pfirewall.log 4096 False False ad.evotec.xyz Ethernet 5 3 DomainAuthenticated False Internet NoTraffic NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured False NotConfigured %systemroot%\system32\LogFiles\Firewall\pfirewall.log 4096 False False Network 2 Ethernet 4 12 Private False LocalNetwork NoTraffic NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured False NotConfigured %systemroot%\system32\LogFiles\Firewall\pfirewall.log 4096 False False .EXAMPLE Get-ComputerNetworkCard -ComputerName EVOWIN -NetworkFirewallOnly PSComputerName Profile Enabled DefaultInboundAction DefaultOutboundAction AllowInboundRules AllowLocalFirewallRules AllowLocalIPsecRules AllowUserApps AllowUserPorts AllowUnicastResponseToMulticast NotifyOnListen EnableStealthModeForIPsec LogMaxSizeKilobytes LogAllowed LogBlocked LogIgnored Caption Description ElementName InstanceID DisabledInterfaceAliases LogFileName Name CimClass -------------- ------- ------- -------------------- --------------------- ----------------- ----------------------- -------------------- ------------- -------------- ------------------------------- -------------- ------------------------- ------------------- ---------- ---------- ---------- ------- ----------- ----------- ---------- ------------------------ ----------- ---- -------- EVOWIN Domain True NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured True NotConfigured 4096 False False NotConfigured MSFT|FW|FirewallProfile|Domain {NotConfigured} %systemroot%\system32\LogFiles\Firewall\pfirewall.log Domain root/stand... EVOWIN Private True NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured True NotConfigured 4096 False False NotConfigured MSFT|FW|FirewallProfile|Private {NotConfigured} %systemroot%\system32\LogFiles\Firewall\pfirewall.log Private root/stand... EVOWIN Public True NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured NotConfigured True NotConfigured 4096 False False NotConfigured MSFT|FW|FirewallProfile|Public {NotConfigured} %systemroot%\system32\LogFiles\Firewall\pfirewall.log Public root/stand... .NOTES General notes #> [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [switch] $NetworkFirewallOnly, [switch] $NetworkFirewallSummaryOnly, [alias('Joiner')][string] $Splitter ) [Array] $CollectionComputers = $ComputerName.Where( { $_ -eq $Env:COMPUTERNAME }, 'Split') $Firewall = @{ } $NetworkFirewall = @( if ($CollectionComputers[0].Count -gt 0) { $Firewall[$Env:COMPUTERNAME] = @{ } $Output = Get-NetFirewallProfile foreach ($_ in $Output) { Add-Member -InputObject $_ -Name 'PSComputerName' -Value $Env:COMPUTERNAME -Type NoteProperty -Force $_ if ($_.Name -eq 'Domain') { $Firewall[$Env:COMPUTERNAME]['DomainAuthenticated'] = $_ } else { $Firewall[$Env:COMPUTERNAME][$($_.Name)] = $_ } } } if ($CollectionComputers[1].Count -gt 0) { foreach ($_ in $CollectionComputers[1]) { $Firewall[$_] = @{ } } $Output = Get-NetFirewallProfile -CimSession $CollectionComputers[1] foreach ($_ in $Output) { if ($_.Name -eq 'Domain') { $Firewall[$_.PSComputerName]['DomainAuthenticated'] = $_ } else { $Firewall[$_.PSComputerName][$($_.Name)] = $_ } } } ) if ($NetworkFirewallOnly) { return $NetworkFirewall } if ($NetworkFirewallSummaryOnly) { return $Firewall } $NetworkCards = @( if ($CollectionComputers[0].Count -gt 0) { $Output = Get-NetConnectionProfile foreach ($_ in $Output) { Add-Member -InputObject $_ -Name 'PSComputerName' -Value $Env:COMPUTERNAME -Type NoteProperty -Force $_ } } if ($CollectionComputers[1].Count -gt 0) { Get-NetConnectionProfile -CimSession $CollectionComputers[1] } ) foreach ($_ in $NetworkCards) { $NetworkCardsConfiguration = Get-CimData -ComputerName $ComputerName -Class 'Win32_NetworkAdapterConfiguration' $CurrentCard = foreach ($Configuration in $NetworkCardsConfiguration) { if ($_.PSComputerName -eq $Configuration.PSComputerName) { if ($Configuration.InterfaceIndex -eq $_.InterfaceIndex) { $Configuration } } } $NetbiosTCPIP = @{ '0' = 'Default' '1' = 'Enabled' '2' = 'Disabled' } [PSCustomObject] @{ Name = $_.Name NetworkCardName = $_.InterfaceAlias NetworkCardIndex = $_.InterfaceIndex FirewallProfile = $_.NetworkCategory FirewallStatus = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].'Enabled' IPAddress = $CurrentCard.IPAddress IPGateway = $CurrentCard.DefaultIPGateway IPSubnet = $CurrentCard.IPSubnet IPv4Connectivity = $_.IPv4Connectivity IPv6Connectivity = $_.IPv6Connectivity DNSServerSearchOrder = $CurrentCard.DNSServerSearchOrder DNSDomainSuffixSearchOrder = $CurrentCard.DNSDomainSuffixSearchOrder FullDNSRegistrationEnabled = $CurrentCard.FullDNSRegistrationEnabled DHCPEnabled = $CurrentCard.DHCPEnabled DHCPServer = $CurrentCard.DHCPServer DHCPLeaseObtained = $CurrentCard.DHCPLeaseObtained NetBIOSOverTCPIP = $NetBiosTCPIP["$($CurrentCard.TcpipNetbiosOptions)"] Caption = $_.Caption Description = $_.Description ElementName = $_.ElementName DefaultInboundAction = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].DefaultInboundAction DefaultOutboundAction = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].DefaultOutboundAction AllowInboundRules = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].AllowInboundRules AllowLocalFirewallRules = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].AllowLocalFirewallRules AllowLocalIPsecRules = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].AllowLocalIPsecRules AllowUserApps = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].AllowUserApps AllowUserPorts = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].AllowUserPorts AllowUnicastResponseToMulticast = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].AllowUnicastResponseToMulticast NotifyOnListen = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].NotifyOnListen EnableStealthModeForIPsec = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].EnableStealthModeForIPsec LogFileName = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].LogFileName LogMaxSizeKilobytes = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].LogMaxSizeKilobytes LogAllowed = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].LogAllowed LogBlocked = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].LogBlocked LogIgnored = $Firewall[$_.PSComputerName]["$($_.NetworkCategory)"].LogIgnored ComputerName = $_.PSComputerName } } } function Get-ComputerOemInformation { [CmdletBinding()] param( [string] $ComputerName = $Env:COMPUTERNAME ) $ScriptBlock = { Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\OEMInformation | Select-Object Model, Manufacturer, Logo, SupportPhone, SupportURL, SupportHours } if ($ComputerName -eq $Env:COMPUTERNAME) { $Data = Invoke-Command -ScriptBlock $ScriptBlock } else { $Data = Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock } return $Data } function Get-ComputerOperatingSystem { [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All ) [string] $Class = 'win32_operatingsystem' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'Caption', 'Manufacturer', 'InstallDate', 'OSArchitecture', 'Version', 'SerialNumber', 'BootDevice', 'WindowsDirectory', 'CountryCode', 'OSLanguage', 'OSProductSuite', 'PSComputerName', 'LastBootUpTime', 'LocalDateTime' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Data in $Information) { [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } OperatingSystem = $Data.Caption OperatingSystemVersion = ConvertTo-OperatingSystem -OperatingSystem $Data.Caption -OperatingSystemVersion $Data.Version OperatingSystemBuild = $Data.Version Manufacturer = $Data.Manufacturer OSArchitecture = $Data.OSArchitecture OSLanguage = ConvertFrom-LanguageCode -LanguageCode $Data.OSLanguage OSProductSuite = [Microsoft.PowerShell.Commands.OSProductSuite] $($Data.OSProductSuite) InstallDate = $Data.InstallDate LastBootUpTime = $Data.LastBootUpTime LocalDateTime = $Data.LocalDateTime SerialNumber = $Data.SerialNumber BootDevice = $Data.BootDevice WindowsDirectory = $Data.WindowsDirectory CountryCode = $Data.CountryCode } } } } function Get-ComputerRAM { [CmdletBinding()] param( [string] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All, [switch] $Extended ) [string] $Class = 'Win32_physicalmemory ' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = @( 'InstallDate' 'Manufacturer' 'Model' 'OtherIdentifyingInfo' 'PartNumber' 'PoweredOn' 'SerialNumber' 'SKU' 'Tag' 'Version' 'HotSwappable' 'Removable' 'Replaceable' 'FormFactor' 'BankLabel' 'Capacity' 'InterleavePosition' 'MemoryType' 'Speed' 'ConfiguredClockSpeed' 'ConfiguredVoltage' 'DeviceLocator' 'MaxVoltage' 'MinVoltage' 'SMBIOSMemoryType' 'TypeDetail' 'PSComputerName' ) } $FormFactor = @{ '0' = 'Unknown' '1' = 'Other' '2' = 'SIP' '3' = 'DIP' '4' = 'ZIP' '5' = 'SOJ' '6' = 'Proprietary' '7' = 'SIMM' '8' = 'DIMM' '9' = 'TSOP' '10' = 'PGA' '11' = 'RIMM' '12' = 'SODIMM' '13' = 'SRIMM' '14' = 'SMD' '15' = 'SSMP' '16' = 'QFP' '17' = 'TQFP' '18' = 'SOIC' '19' = 'LCC' '20' = 'PLCC' '21' = 'BGA' '22' = 'FPBGA' '23' = 'LGA' } $TypeDetails = @{ '1' = 'Reserved' '2' = 'Other' '4' = 'Unknown' '8' = 'Fast-paged' '16' = 'Static column' '32' = 'Pseudo-static' '64' = 'RAMBUS' '128' = 'Synchronous' '256' = 'CMOS' '512' = 'EDO' '1024' = 'Window DRAM' '2048' = 'Cache DRAM' '4096' = 'Non-volatile' } $InterleavePosition = @{ '0' = "Non-Interleaved" '1' = "First Position" '2' = "Second Position" } $MemoryType = @{ '0' = "Unknown" '1' = "Other" '2' = "DRAM" '3' = "Synchronous DRAM" '4' = "Cache DRAM" '5' = "EDO" '6' = "EDRAM" '7' = "VRAM" '8' = "SRAM" '9' = "ROM" '10' = "ROM" '11' = "FLASH" '12' = "EEPROM" '13' = "FEPROM" '14' = "EPROM" '15' = "CDRAM" '16' = "3DRAM" '17' = "SDRAM" '18' = "SGRAM" '19' = "RDRAM" '20' = "DDR" } $MemoryTypeSMBIOS = @{ '0' = 'Unknown' '1' = 'Other' '2' = 'DRAM' '3' = 'Synchronous DRAM' '4' = 'Cache DRAM' '5' = 'EDO' '6' = 'EDRAM' '7' = 'VRAM' '8' = 'SRAM' '9' = 'RAM' '10' = 'ROM' '11' = 'Flash' '12' = 'EEPROM' '13' = 'FEPROM' '14' = 'EPROM' '15' = 'CDRAM' '16' = '3DRAM' '17' = 'SDRAM' '18' = 'SGRAM' '19' = 'RDRAM' '20' = 'DDR' '21' = 'DDR2' '22' = 'DDR2 FB-DIMM' '24' = 'DDR3' '25' = 'FBD2' '26' = 'DDR4' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { $Ram = [ordered] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Manufacturer = $Data.Manufacturer FormFactor = $FormFactor["$($Data.FormFactor)"] SMBIOSMemoryType = $MemoryTypeSMBIOS["$($Data.SMBIOSMemoryType)"] Size = [math]::round($Data.Capacity / 1GB, 2) Speed = $Data.Speed InterleavePosition = $InterleavePosition["$($Data.InterleavePosition)"] MemoryType = $MemoryType["$($Data.MemoryType)"] TypeDetail = $TypeDetails["$($Data.TypeDetail)"] PartNumber = $Data.PartNumber DeviceLocator = $Data.DeviceLocator } if ($Extended) { $RamExtended = [ordered] @{ InstallDate = $Data.InstallDate Model = $Data.Model OtherIdentifyingInfo = $Data.OtherIdentifyingInfo PoweredOn = $Data.PoweredOn SerialNumber = $Data.SerialNumber SKU = $Data.SKU Tag = $Data.Tag Version = $Data.Version HotSwappable = $Data.HotSwappable Removable = $Data.Removable Replaceable = $Data.Replaceable BankLabel = $Data.BankLabel ConfiguredClockSpeed = $Data.ConfiguredClockSpeed ConfiguredVoltage = $Data.ConfiguredVoltage MaxVoltage = $Data.MaxVoltage MinVoltage = $Data.MinVoltage } [PSCustomObject] ($Ram + $RamExtended) } else { [PSCustomObject] $Ram } } } } } function Get-ComputerRDP { [alias('Get-RDPSecurity')] [cmdletbinding()] param( [string[]] $ComputerName ) $Output = Get-CimData -Class 'Win32_TSGeneralSetting' -NameSpace 'root\cimv2\terminalservices' -ComputerName $ComputerName foreach ($_ in $Output) { $EncryptionLevels = @{ '1' = 'Low' '2' = 'Medium / Client Compatible' '3' = 'High' '4' = 'FIPS Compliant' } $PolicyConfiguredBy = @{ '0' = 'Server' '1' = 'Group policy' '2' = 'Default' } $SecurityLayers = @{ '1' = 'RDP Security Layer' '2' = 'Negotiate' '3' = 'SSL' '4' = 'NEWTBD' } $HashType = @{ '0' = 'Not valid' '1' = 'Self-signed' '2' = 'Custom' } $Connectivity = Test-ComputerPort -ComputerName $_.PSComputerName -PortTCP 3389 -WarningAction SilentlyContinue [PSCustomObject] @{ ComputerName = $_.PSComputerName Name = $_.TerminalName Connectivity = $Connectivity.Status ConnectivitySummary = $Connectivity.Summary SecurityLayer = $SecurityLayers["$($_.SecurityLayer)"] MinimalEncryptionLevel = $EncryptionLevels["$($_.MinEncryptionLevel)"] MinimalEncryptionLevelValue = $_.MinEncryptionLevel PolicySourceUserAuthenticationRequired = $PolicyConfiguredBy["$($_.PolicySourceUserAuthenticationRequired)"] PolicySourceMinimalEncryptionLevel = $PolicyConfiguredBy["$($_.PolicySourceMinEncryptionLevel)"] PolicySourceSecurityLayer = $PolicyConfiguredBy["$($_.PolicySourceSecurityLayer)"] CertificateName = $_.CertificateName CertificateThumbprint = $_.SSLCertificateSHA1Hash CertificateType = $HashType["$($_.SSLCertificateSHA1HashType)"] Transport = $_.Transport Protocol = $_.TerminalProtocol UserAuthenticationRequired = [bool] $_.UserAuthenticationRequired WindowsAuthentication = [bool] $_.WindowsAuthentication } } } function Get-ComputerRoles { <# .SYNOPSIS Get Computer/Server Roles .DESCRIPTION Get Computer/Server Roles .PARAMETER ComputerName Parameter description .PARAMETER FeatureType Display all or limited types. Choices are Role, Role Service and Feature. .PARAMETER EnabledOnly Display only enabled/installed features or roles .EXAMPLE Get-ComputerRoles -ComputerName AD1 -EnabledOnly -FeatureType Role | Format-Table .NOTES General notes #> [alias('Get-ServerRoles')] [CmdletBinding()] param ( [string[]] $ComputerName = $env:COMPUTERNAME, [ValidateSet('Role', 'Role Service', 'Feature')] $FeatureType, [switch] $EnabledOnly ) if ($Global:ProgressPreference -ne 'SilentlyContinue') { $TemporaryProgress = $Global:ProgressPreference $Global:ProgressPreference = 'SilentlyContinue' } foreach ($Computer in $ComputerName) { try { $Output = Get-WindowsFeature -ComputerName $Computer -ErrorAction Stop } catch [System.Exception] { if ($_.FullyQualifiedErrorId -like 'UnSupportedTargetDevice,*') { $output = Invoke-Command -ComputerName $computer { Import-Module ServerManager Get-WindowsFeature } } } foreach ($Data in $Output) { if ($EnabledOnly -and $Data.Installed -eq $false) { continue } if ($FeatureType) { if ($Data.FeatureType -notin $FeatureType) { continue } } [PSCustomObject] @{ ComputerName = $Computer Name = $Data.Name DisplayName = $Data.DisplayName FeatureType = $Data.FeatureType Installed = $Data.Installed Description = $Data.Description } } } if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress } } function Get-ComputerService { [alias('Get-ComputerServices')] [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME ) Process { foreach ($Computer in $ComputerName) { $Services = Get-PSService -ComputerName $Computer | Select-Object ComputerName, Name, Displayname, Status, StartType $Services } } } function Get-ComputerSMB { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ComputerName Parameter description .EXAMPLE Get-ComputerSMB -ComputerName $ENV:COMPUTERNAME .NOTES General notes #> [CmdletBinding()] param( [string[]] $ComputerName ) [Array] $CollectionComputers = $ComputerName.Where( { $_ -eq $Env:COMPUTERNAME }, 'Split') $SMB = @( if ($CollectionComputers[0].Count -gt 0) { $Output = Get-SmbServerConfiguration foreach ($_ in $Output) { [PSCustomObject] @{ ComputerName = $Env:COMPUTERNAME AnnounceComment = $_.AnnounceComment AnnounceServer = $_.AnnounceServer AsynchronousCredits = $_.AsynchronousCredits AuditSmb1Access = $_.AuditSmb1Access AutoDisconnectTimeout = $_.AutoDisconnectTimeout AutoShareServer = $_.AutoShareServer AutoShareWorkstation = $_.AutoShareWorkstation CachedOpenLimit = $_.CachedOpenLimit DurableHandleV2TimeoutInSeconds = $_.DurableHandleV2TimeoutInSeconds EnableAuthenticateUserSharing = $_.EnableAuthenticateUserSharing EnableDownlevelTimewarp = $_.EnableDownlevelTimewarp EnableForcedLogoff = $_.EnableForcedLogoff EnableLeasing = $_.EnableLeasing EnableMultiChannel = $_.EnableMultiChannel EnableOplocks = $_.EnableOplocks EnableSecuritySignature = $_.EnableSecuritySignature EnableSMB1Protocol = $_.EnableSMB1Protocol EnableSMB2Protocol = $_.EnableSMB2Protocol EnableStrictNameChecking = $_.EnableStrictNameChecking EncryptData = $_.EncryptData IrpStackSize = $_.IrpStackSize KeepAliveTime = $_.KeepAliveTime MaxChannelPerSession = $_.MaxChannelPerSession MaxMpxCount = $_.MaxMpxCount MaxSessionPerConnection = $_.MaxSessionPerConnection MaxThreadsPerQueue = $_.MaxThreadsPerQueue MaxWorkItems = $_.MaxWorkItems NullSessionPipes = $_.NullSessionPipes NullSessionShares = $_.NullSessionShares OplockBreakWait = $_.OplockBreakWait PendingClientTimeoutInSeconds = $_.PendingClientTimeoutInSeconds RejectUnencryptedAccess = $_.RejectUnencryptedAccess RequireSecuritySignature = $_.RequireSecuritySignature ServerHidden = $_.ServerHidden Smb2CreditsMax = $_.Smb2CreditsMax Smb2CreditsMin = $_.Smb2CreditsMin SmbServerNameHardeningLevel = $_.SmbServerNameHardeningLevel TreatHostAsStableStorage = $_.TreatHostAsStableStorage ValidateAliasNotCircular = $_.ValidateAliasNotCircular ValidateShareScope = $_.ValidateShareScope ValidateShareScopeNotAliased = $_.ValidateShareScopeNotAliased ValidateTargetName = $_.ValidateTargetName } } } if ($CollectionComputers[1].Count -gt 0) { $Output = Get-SmbServerConfiguration -CimSession $CollectionComputers[1] foreach ($_ in $Output) { [PSCustomObject] @{ ComputerName = $_.PSComputerName AnnounceComment = $_.AnnounceComment AnnounceServer = $_.AnnounceServer AsynchronousCredits = $_.AsynchronousCredits AuditSmb1Access = $_.AuditSmb1Access AutoDisconnectTimeout = $_.AutoDisconnectTimeout AutoShareServer = $_.AutoShareServer AutoShareWorkstation = $_.AutoShareWorkstation CachedOpenLimit = $_.CachedOpenLimit DurableHandleV2TimeoutInSeconds = $_.DurableHandleV2TimeoutInSeconds EnableAuthenticateUserSharing = $_.EnableAuthenticateUserSharing EnableDownlevelTimewarp = $_.EnableDownlevelTimewarp EnableForcedLogoff = $_.EnableForcedLogoff EnableLeasing = $_.EnableLeasing EnableMultiChannel = $_.EnableMultiChannel EnableOplocks = $_.EnableOplocks EnableSecuritySignature = $_.EnableSecuritySignature EnableSMB1Protocol = $_.EnableSMB1Protocol EnableSMB2Protocol = $_.EnableSMB2Protocol EnableStrictNameChecking = $_.EnableStrictNameChecking EncryptData = $_.EncryptData IrpStackSize = $_.IrpStackSize KeepAliveTime = $_.KeepAliveTime MaxChannelPerSession = $_.MaxChannelPerSession MaxMpxCount = $_.MaxMpxCount MaxSessionPerConnection = $_.MaxSessionPerConnection MaxThreadsPerQueue = $_.MaxThreadsPerQueue MaxWorkItems = $_.MaxWorkItems NullSessionPipes = $_.NullSessionPipes NullSessionShares = $_.NullSessionShares OplockBreakWait = $_.OplockBreakWait PendingClientTimeoutInSeconds = $_.PendingClientTimeoutInSeconds RejectUnencryptedAccess = $_.RejectUnencryptedAccess RequireSecuritySignature = $_.RequireSecuritySignature ServerHidden = $_.ServerHidden Smb2CreditsMax = $_.Smb2CreditsMax Smb2CreditsMin = $_.Smb2CreditsMin SmbServerNameHardeningLevel = $_.SmbServerNameHardeningLevel TreatHostAsStableStorage = $_.TreatHostAsStableStorage ValidateAliasNotCircular = $_.ValidateAliasNotCircular ValidateShareScope = $_.ValidateShareScope ValidateShareScopeNotAliased = $_.ValidateShareScopeNotAliased ValidateTargetName = $_.ValidateTargetName } } } ) $SMB } function Get-ComputerSMBShare { [CmdletBinding()] param( [string[]] $ComputerName, [switch] $Translated ) [Array] $CollectionComputers = Get-ComputerSplit -ComputerName $ComputerName if ($CollectionComputers[0].Count -gt 0) { $Output = Get-SmbShare foreach ($O in $Output) { if (-not $Translated) { Add-Member -InputObject $_ -Name 'PSComputerName' -Value $Env:COMPUTERNAME -MemberType NoteProperty -Force $O } else { [PSCustomObject] @{ Name = $O.Name ScopeName = $O.ScopeName Path = $O.Path Description = $O.Description ComputerName = $O.PSComputerName PresetPathAcl = $O.PresetPathAcl ShareState = $O.ShareState.ToString() AvailabilityType = $O.AvailabilityType.ToString() ShareType = $O.ShareType.ToString() FolderEnumerationMode = $O.FolderEnumerationMode.ToString() CachingMode = $O.CachingMode.ToString() LeasingMode = $O.LeasingMode.ToString() QoSFlowScope = $O.QoSFlowScope SmbInstance = $O.SmbInstance.ToString() CATimeout = $O.CATimeout ConcurrentUserLimit = $O.ConcurrentUserLimit ContinuouslyAvailable = $O.ContinuouslyAvailable CurrentUsers = $O.CurrentUsers EncryptData = $O.EncryptData Scoped = $O.Scoped SecurityDescriptor = $O.SecurityDescriptor ShadowCopy = $O.ShadowCopy Special = $O.Special Temporary = $O.Temporary Volume = $O.Volume } } } } if ($CollectionComputers[1].Count -gt 0) { $Output = Get-SmbShare -CimSession $CollectionComputers[1] foreach ($O in $Output) { if (-not $Translated) { $O } else { [PSCustomObject] @{ Name = $O.Name ScopeName = $O.ScopeName Path = $O.Path Description = $O.Description ComputerName = $O.PSComputerName PresetPathAcl = $O.PresetPathAcl ShareState = $O.ShareState.ToString() AvailabilityType = $O.AvailabilityType.ToString() ShareType = $O.ShareType.ToString() FolderEnumerationMode = $O.FolderEnumerationMode.ToString() CachingMode = $O.CachingMode.ToString() LeasingMode = $O.LeasingMode QoSFlowScope = $O.QoSFlowScope SmbInstance = $O.SmbInstance.ToString() CATimeout = $O.CATimeout ConcurrentUserLimit = $O.ConcurrentUserLimit ContinuouslyAvailable = $O.ContinuouslyAvailable CurrentUsers = $O.CurrentUsers EncryptData = $O.EncryptData Scoped = $O.Scoped SecurityDescriptor = $O.SecurityDescriptor ShadowCopy = $O.ShadowCopy Special = $O.Special Temporary = $O.Temporary Volume = $O.Volume } } } } } function Get-ComputerSMBShareList { <# .SYNOPSIS Enumerate shares on a remote or local host and returns the name, type, and special remark for those shares. .DESCRIPTION Enumerate shares on a remote or local host and returns the name, type, and special remark for those shares. Doesnt return the permissions on the share, or logging to given computer Similar to 'net view /All \\ComputerName' .PARAMETER ComputerName The host to enumerate the shares for. Can be accepted as pipeline input by value. .PARAMETER Name The name of the share to filter on. Can be accepted as pipeline input by value. .OUTPUTS [PSCustomObject]@{ ComputerName = [String]'The computer the share relates to' Name = [String]'The name of the share' Path = [string]'\\ComputerName\Name\' Type = [Win32Share.ShareType] An flag enum of the share properties, can be Disk = Disk drive share PrintQueue = Print queue share CommunicationDevice = Communication device share Ipc = Interprocess communication share Temporary = A temporary share Special = Typically a special/admin share like IPC$, C$, ADMIN$ Remark = [String]'More info on the share' TotalBytes = [System.Nullable[int]] TotalFreeBytes = [System.Nullable[int]] FreeBytesAvailableToUser = [System.Nullable[int]] } .LINK https://gist.github.com/jborean93/017d3d890ae8d33276a08d3f5cc7eb45 .EXAMPLE Get-ComputerSMBShareList -ComputerName some-host .EXAMPLE Get-ComputerSMBShareList -ComputerName "DC1" | ft -AutoSize .NOTES Original author: Jordan Borean (@jborean93) Modified by: Matt Cargile (@mattcargile) Modified by: Przemyslaw Klys #> [CmdletBinding(DefaultParameterSetName = 'ComputerName')] param ( [Parameter(Mandatory, ParameterSetName = 'ComputerName', Position = 0)] [string[]] $ComputerName, [Parameter(ValueFromPipeline, ParameterSetName = 'Pipeline')] [string] $InputObject, [Parameter(ParameterSetName = 'ComputerName', Position = 1)] [Parameter(ParameterSetName = 'Pipeline')] [SupportsWildcards()][Alias('ShareName')][string[]] $Name, [switch] $SkipDiskSpace ) begin { if (-not ('Win32Share.NativeMethods' -as [type])) { Add-Type -ErrorAction 'Stop' -TypeDefinition @' using System; using System.Runtime.InteropServices; namespace Win32Share { public class NativeHelpers { [StructLayout(LayoutKind.Sequential)] public struct SHARE_INFO_1 { [MarshalAs(UnmanagedType.LPWStr)] public string shi1_netname; public ShareType shi1_type; [MarshalAs(UnmanagedType.LPWStr)] public string shi1_remark; } } public class NativeMethods { [DllImport("Netapi32.dll")] public static extern UInt32 NetApiBufferFree( IntPtr Buffer); [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern Int32 NetShareEnum( string servername, UInt32 level, ref IntPtr bufptr, UInt32 prefmaxlen, ref UInt32 entriesread, ref UInt32 totalentries, ref UInt32 resume_handle); [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool GetDiskFreeSpaceEx( string lpDirectoryName, ref UInt64 lpFreeBytesAvailableToCaller, ref UInt64 lptotalNumberOfBytes, ref UInt64 lpTotalNumberOfFreeBytes ); } [Flags] public enum ShareType : uint { Disk = 0, PrintQueue = 1, CommunicationDevice = 2, Ipc = 3, Temporary = 0x40000000, Special = 0x80000000, } } '@ } } process { foreach ($compNm in $ComputerName) { Write-Verbose -Message "Get-ComputerSMBShareList - Enumerating shares on '$compNm'" $PSBoundParameters['ComputerName'] = $compNm Get-ComputerSMBInfo @PSBoundParameters } } } function Get-ComputerSMBSharePermissions { [CmdletBinding()] param( [string[]] $ComputerName, [Parameter(Mandatory = $true)][alias('Name')][string[]] $ShareName, [switch] $Translated ) [Array] $Computers = Get-ComputerSplit -ComputerName $ComputerName if ($Computers[0].Count -gt 0) { foreach ($Share in $ShareName) { try { $Output = Get-SmbShareAccess -Name $Share -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message Write-Warning -Message "Get-ComputerSMBSharePermissions - Computer $Env:COMPUTERNAME, Share $Share, Error: $ErrorMessage" } foreach ($O in $Output) { if (-not $Translated) { $O | Add-Member -Name 'PSComputerName' -Value $Env:COMPUTERNAME -MemberType NoteProperty -Force $O } else { [PSCustomObject] @{ Name = $O.Name ScopeName = $O.ScopeName AccountName = $O.AccountName.ToString() AccessControlType = $O.AccessControlType.ToString() AccessRight = $O.AccessRight.ToString() ComputerName = $Env:COMPUTERNAME } } } } } if ($Computers[1].Count -gt 0) { foreach ($Share in $ShareName) { try { $Output = Get-SmbShareAccess -CimSession $Computers[1] -Name $Share -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message Write-Warning -Message "Get-ComputerSMBSharePermissions - Computer $($Computers[1]), Share $Share, Error: $ErrorMessage" } foreach ($O in $Output) { if (-not $Translated) { $O } else { [PSCustomObject] @{ Name = $O.Name ScopeName = $O.ScopeName AccountName = $O.AccountName.ToString() AccessControlType = $O.AccessControlType.ToString() AccessRight = $O.AccessRight.ToString() ComputerName = $O.PSComputerName } } } } } } function Get-ComputerStartup { [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All ) [string] $Class = 'win32_startupCommand' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'Caption', 'Description', 'Command', 'Location', 'Name', 'User', 'UserSID', 'PSComputerName' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Caption = $Data.Caption Description = $Data.Description Command = $Data.Command Location = $Data.Location Name = $Data.Name User = $Data.User UserSID = $Data.UserSID } } } } } function Get-ComputerSystem { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ComputerName Parameter description .PARAMETER Protocol Parameter description .PARAMETER All Parameter description .EXAMPLE Get-ComputerSystem -ComputerName AD1, AD2, EVO1, ADFFS | ft -a * Output: WARNING: Get-ComputerSystem - No data for computer ADFFS. Most likely an error on receiving side. ComputerName Name Manufacturer Domain Model Systemtype PrimaryOwnerName PCSystemType PartOfDomain CurrentTimeZone BootupState SystemFamily Roles ------------ ---- ------------ ------ ----- ---------- ---------------- ------------ ------------ --------------- ----------- ------------ ----- AD1 AD1 Microsoft Corporation ad.evotec.xyz Virtual Machine x64-based PC Windows User 1 True 60 Normal boot Virtual Machine LM_Workstation, LM_Server, Primary_Domain_Controller, Timesource, NT, DFS AD2 AD2 Microsoft Corporation ad.evotec.xyz Virtual Machine x64-based PC Windows User 1 True 60 Normal boot Virtual Machine LM_Workstation, LM_Server, Backup_Domain_Controller, Timesource, NT, DFS EVO1 EVO1 MSI ad.evotec.xyz MS-7980 x64-based PC 1 True 60 Normal boot Default string LM_Workstation, LM_Server, SQLServer, NT, Potential_Browser, Master_Browser .NOTES General notes #> [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $All ) [string] $Class = 'Win32_ComputerSystem' if ($All) { $Properties = '*' } else { $Properties = 'PSComputerName', 'Name', 'Manufacturer' , 'Domain', 'Model' , 'Systemtype', 'PrimaryOwnerName', 'PCSystemType', 'PartOfDomain', 'CurrentTimeZone', 'BootupState', 'Roles', 'SystemFamily' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Name = $Data.Name Manufacturer = $Data.Manufacturer Domain = $Data.Domain Model = $Data.Model Systemtype = $Data.Systemtype PrimaryOwnerName = $Data.PrimaryOwnerName PCSystemType = [Microsoft.PowerShell.Commands.PCSystemType] $Data.PCSystemType PartOfDomain = $Data.PartOfDomain CurrentTimeZone = $Data.CurrentTimeZone BootupState = $Data.BootupState SystemFamily = $Data.SystemFamily Roles = $Data.Roles -join ', ' } } } } } function Get-ComputerTask { <# .SYNOPSIS Get Task Schedule information .DESCRIPTION Get Task Schedule information .PARAMETER ComputerName Specifies computer on which you want to run the operation. .EXAMPLE Get-ComputerTask | Format-Table .NOTES General notes #> [alias('Get-ComputerTasks')] [cmdletbinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME ) foreach ($Computer in $ComputerName) { try { $LocalComputerDNSName = [System.Net.Dns]::GetHostByName($Env:COMPUTERNAME).HostName } catch { $LocalComputerDNSName = $Computer } if ($Computer -eq $Env:COMPUTERNAME -or $Computer -eq $LocalComputerDNSName) { $TaskParameters = @{} } else { $TaskParameters = @{ CimSession = $Computer } } $Tasks = Get-ScheduledTask @TaskParameters foreach ($Task in $Tasks) { $Info = $Task | Get-ScheduledTaskInfo @TaskParameters $Actions = foreach ($_ in $Task.Actions) { -join ($_.Execute, $_.Arguments) } [PSCustomObject] @{ ComputerName = $Computer TaskName = $Task.TaskName TaskPath = $Task.TaskPath State = $Task.State Actions = $Actions Author = $Task.Author Date = $Task.Date Description = $Task.Description Documentation = $Task.Documentation PrincipalDisplayName = $Task.Principal.DisplayName PrincipalUserID = $Task.Principal.UserID PrincipalGroupID = $Task.Principal.GroupID PrincipalLogonType = $Task.Principal.LogonType PrincipalRunLevel = $Task.Principal.RunLevel PrincipalProcessTokenSidType = $Task.Principal.ProcessTokenSidType PrincipalRequiredPrivilege = $Task.Principal.RequiredPrivilege SettingsAllowDemandStart = $Task.Settings.AllowDemandStart SettingsAllowHardTerminate = $Task.Settings.AllowHardTerminate SettingsCompatibility = $Task.Settings.Compatibility SettingsDeleteExpiredTaskAfter = $Task.Settings.DeleteExpiredTaskAfter SettingsDisallowStartIfOnBatteries = $Task.Settings.DisallowStartIfOnBatteries SettingsEnabled = $Task.Settings.Enabled SettingsExecutionTimeLimit = $Task.Settings.ExecutionTimeLimit SettingsHidden = $Task.Settings.Hidden SettingsIdleSettings = $Task.Settings.IdleSettings SettingsMultipleInstances = $Task.Settings.MultipleInstances SettingsNetworkSettings = $Task.Settings.NetworkSettings SettingsPriority = $Task.Settings.Priority SettingsRestartCount = $Task.Settings.RestartCount SettingsRestartInterval = $Task.Settings.RestartInterval SettingsRunOnlyIfIdle = $Task.Settings.RunOnlyIfIdle SettingsRunOnlyIfNetworkAvailable = $Task.Settings.RunOnlyIfNetworkAvailable SettingsStartWhenAvailable = $Task.Settings.StartWhenAvailable SettingsStopIfGoingOnBatteries = $Task.Settings.StopIfGoingOnBatteries SettingsWakeToRun = $Task.Settings.WakeToRun SettingsDisallowStartOnRemoteAppSession = $Task.Settings.DisallowStartOnRemoteAppSession SettingsUseUnifiedSchedulingEngine = $Task.Settings.UseUnifiedSchedulingEngine SettingsMaintenanceSettings = $Task.Settings.MaintenanceSettings SettingsVolatile = $Task.Settings.volatile Source = $Task.Source URI = $Task.URI Version = $Task.Version LastRunTime = $Info.LastRunTime LastTaskResult = $Info.LastTaskResult NextRunTime = $Info.NextRunTime NumberOfMissedRuns = $Info.NumberOfMissedRuns } } } } function Get-ComputerTime { <# .SYNOPSIS Gets time difference between computers and time source including boot time .DESCRIPTION Gets time difference between computers and time source including boot time .PARAMETER TimeSource Parameter description .PARAMETER Domain Parameter description .PARAMETER TimeTarget Specifies computer on which you want to run the CIM operation. You can specify a fully qualified domain name (FQDN), a NetBIOS name, or an IP address. If you do not specify this parameter, the cmdlet performs the operation on the local computer using Component Object Model (COM). .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. .PARAMETER ForceCIM .PARAMETER ToLocal .EXAMPLE Get-ComputerTime -TimeTarget AD2, AD3, EVOWin | Format-Table -AutoSize Output Name LocalDateTime RemoteDateTime InstallTime LastBootUpTime TimeDifferenceMinutes TimeDifferenceSeconds TimeDifferenceMilliseconds TimeSourceName ---- ------------- -------------- ----------- -------------- --------------------- --------------------- -------------------------- -------------- AD2 13.08.2019 23:40:26 13.08.2019 23:40:26 30.05.2018 18:30:48 09.08.2019 18:40:31 8,33333333333333E-05 0,005 5 AD1.ad.evotec.xyz AD3 13.08.2019 23:40:26 13.08.2019 17:40:26 26.05.2019 17:30:17 09.08.2019 18:40:30 0,000266666666666667 0,016 16 AD1.ad.evotec.xyz EVOWin 13.08.2019 23:40:26 13.08.2019 23:40:26 24.05.2019 22:46:45 09.08.2019 18:40:06 6,66666666666667E-05 0,004 4 AD1.ad.evotec.xyz .EXAMPLE Get-ComputerTime -TimeSource AD1 -TimeTarget AD2, AD3, EVOWin | Format-Table -AutoSize .EXAMPLE Get-ComputerTime -TimeSource 'pool.ntp.org' -TimeTarget AD2, AD3, EVOWin | Format-Table -AutoSize .NOTES General notes #> [CmdletBinding()] param( [string] $TimeSource, [string] $Domain = $Env:USERDNSDOMAIN, [alias('ComputerName')][string[]] $TimeTarget = $ENV:COMPUTERNAME, [pscredential] $Credential, [switch] $ForceCIM ) if (-not $TimeSource) { $TimeSource = (Get-ADDomainController -Discover -Service PrimaryDC -DomainName $Domain).HostName } if ($ForceCIM) { $TimeSourceInformation = Get-CimData -ComputerName $TimeSource -Class 'win32_operatingsystem' -Credential $Credential if ($TimeSourceInformation.LocalDateTime) { $TimeSourceInformation = $TimeSourceInformation.LocalDateTime } else { $TimeSourceInformation = $null } } else { $TimeSourceInformation = Get-ComputerTimeNtp -Server $TimeSource -ToLocal } $TimeTargetInformationCache = @{ } $TimeTargetInformation = Get-CimData -ComputerName $TimeTarget -Class 'win32_operatingsystem' -Credential $Credential foreach ($_ in $TimeTargetInformation) { $TimeTargetInformationCache[$_.PSComputerName] = $_ } $TimeLocalCache = @{ } $TimeLocal = Get-CimData -ComputerName $TimeTarget -Class 'Win32_LocalTime' -Credential $Credential foreach ($_ in $TimeLocal) { $TimeLocalCache[$_.PSComputerName] = $_ } $AllResults = foreach ($Computer in $TimeTarget) { $WMIComputerTime = $TimeLocalCache[$Computer] $WMIComputerTarget = $TimeTargetInformationCache[$Computer] if ($WMIComputerTime -and $WMIComputerTime.Year -and $WMIComputerTime.Month) { $RemoteDateTime = Get-Date -Year $WMIComputerTime.Year -Month $WMIComputerTime.Month -Day $WMIComputerTime.Day -Hour $WMIComputerTime.Hour -Minute $WMIComputerTime.Minute -Second $WMIComputerTime.Second } else { $RemoteDateTIme = '' } if ($WMIComputerTarget.LocalDateTime -and $TimeSourceInformation) { $Result = New-TimeSpan -Start $TimeSourceInformation -End $WMIComputerTarget.LocalDateTime $ResultFromBoot = New-TimeSpan -Start $WMIComputerTarget.LastBootUpTime -End $WMIComputerTarget.LocalDateTime [PSCustomObject] @{ Name = $Computer LocalDateTime = $WMIComputerTarget.LocalDateTime RemoteDateTime = $RemoteDateTime InstallTime = $WMIComputerTarget.InstallDate LastBootUpTime = $WMIComputerTarget.LastBootUpTime LastBootUpTimeInDays = [math]::Round($ResultFromBoot.TotalDays, 2) TimeDifferenceMinutes = if ($Result.TotalMinutes -lt 0) { ($Result.TotalMinutes * -1) } else { $Result.TotalMinutes } TimeDifferenceSeconds = if ($Result.TotalSeconds -lt 0) { ($Result.TotalSeconds * -1) } else { $Result.TotalSeconds } TimeDifferenceMilliseconds = if ($Result.TotalMilliseconds -lt 0) { ($Result.TotalMilliseconds * -1) } else { $Result.TotalMilliseconds } TimeSourceName = $TimeSource Status = '' } } else { if ($WMIComputerTarget.LastBootUpTime) { $ResultFromBoot = New-TimeSpan -Start $WMIComputerTarget.LastBootUpTime -End $WMIComputerTarget.LocalDateTime } else { $ResultFromBoot = '' } [PSCustomObject] @{ Name = $Computer LocalDateTime = $WMIComputerTarget.LocalDateTime RemoteDateTime = $RemoteDateTime InstallTime = $WMIComputerTarget.InstallDate LastBootUpTime = $WMIComputerTarget.LastBootUpTime LastBootUpTimeInDays = [math]::Round($ResultFromBoot.TotalDays, 2) TimeDifferenceMinutes = $null TimeDifferenceSeconds = $null TimeDifferenceMilliseconds = $null TimeSourceName = $TimeSource Status = 'Unable to get time difference.' } } } $AllResults } function Get-ComputerTimeNtp { <# .Synopsis Gets (Simple) Network Time Protocol time (SNTP/NTP, rfc-1305, rfc-2030) from a specified server .DESCRIPTION This function connects to an NTP server on UDP port 123 and retrieves the current NTP time. Selected components of the returned time information are decoded and returned in a PSObject. .PARAMETER Server The NTP Server to contact. Uses pool.ntp.org by default. .EXAMPLE Get-NtpTime uk.pool.ntp.org Gets time from the specified server. .EXAMPLE Get-NtpTime | fl * Get time from default server (pool.ntp.org) and displays all output object attributes. .FUNCTIONALITY Gets NTP time from a specified server. .NOTES Author https://github.com/ChrisWarwick/PowerShell-NTP-Time Slightly simplified for different usage scenarios #> [CmdletBinding()] Param ( [String]$Server = 'pool.ntp.org', [switch]$ToLocal ) $StartOfEpoch = New-Object DateTime(1900, 1, 1, 0, 0, 0, [DateTimeKind]::Utc) [Byte[]]$NtpData = , 0 * 48 $NtpData[0] = 0x1B $Socket = [Net.Sockets.Socket]::new([Net.Sockets.AddressFamily]::InterNetwork, [Net.Sockets.SocketType]::Dgram, [Net.Sockets.ProtocolType]::Udp) $Socket.SendTimeOut = 2000 $Socket.ReceiveTimeOut = 2000 Try { $Socket.Connect($Server, 123) } Catch { $_.Error Write-Warning "Get-ComputerTimeNtp - Failed to connect to server $Server" return } $t1 = Get-Date Try { [Void]$Socket.Send($NtpData) [Void]$Socket.Receive($NtpData) } Catch { Write-Warning "Get-ComputerTimeNtp - Failed to communicate with server $Server" return } $t4 = Get-Date $Socket.Shutdown("Both") $Socket.Close() $LI = ($NtpData[0] -band 0xC0) -shr 6 If ($LI -eq 3) { Write-Warning 'Get-ComputerTimeNtp - Alarm condition from server (clock not synchronized)' return } $IntPart = [BitConverter]::ToUInt32($NtpData[43..40], 0) $FracPart = [BitConverter]::ToUInt32($NtpData[47..44], 0) $t3ms = $IntPart * 1000 + ($FracPart * 1000 / 0x100000000) $IntPart = [BitConverter]::ToUInt32($NtpData[35..32], 0) $FracPart = [BitConverter]::ToUInt32($NtpData[39..36], 0) $t2ms = $IntPart * 1000 + ($FracPart * 1000 / 0x100000000) $t1ms = ([TimeZoneInfo]::ConvertTimeToUtc($t1) - $StartOfEpoch).TotalMilliseconds $t4ms = ([TimeZoneInfo]::ConvertTimeToUtc($t4) - $StartOfEpoch).TotalMilliseconds $Offset = (($t2ms - $t1ms) + ($t3ms - $t4ms)) / 2 [DateTime] $NTPDateTime = $StartOfEpoch.AddMilliseconds($t4ms + $Offset) if ($ToLocal) { $NTPDateTime.ToLocalTime() } else { $NTPDateTime } } function Get-ComputerWindowsFeatures { <# .SYNOPSIS Get Windows Features status on one or more computers/servers .DESCRIPTION Get Windows Features status on one or more computers/servers .PARAMETER ComputerName ComputerName to provide when executing query remotly. By default current computer name is used. .PARAMETER Protocol Protocol to use when gathering data. Choices are Default, Dcom, WSMan .PARAMETER EnabledOnly Returns only data if Windows Feature is enabled .PARAMETER All Gets all properties without any preprocessing .EXAMPLE Get-ComputerWindowsFeatures -EnabledOnly | Format-Table .NOTES General notes #> [CmdletBinding()] param( [string] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [switch] $EnabledOnly, [switch] $All ) [string] $Class = 'Win32_OptionalFeature' if ($All) { [string] $Properties = '*' } else { [string[]] $Properties = 'Name', 'Caption' , 'Status', 'InstallState', 'InstallDate', 'PSComputerName' } $State = @{ '1' = 'Enabled' '2' = 'Disabled' '3' = 'Absent' '4' = 'Unknown' } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { $Information } else { foreach ($Info in $Information) { foreach ($Data in $Info) { $InstallState = $State["$($Data.InstallState)"] if ($EnabledOnly -and $InstallState -ne 'Enabled') { continue } [PSCustomObject] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Name = $Data.Name Caption = $Data.Caption InstallState = $InstallState } } } } } function Get-ComputerWindowsUpdates { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ComputerName Parameter description .EXAMPLE $Hotfix = Get-ComputerWindowsUpdates -ComputerName EVOWIN, AD1 $Hotfix | ft -a * $Hotfix[0] | fl * .NOTES General notes #> [CmdletBinding()] param( [string[]] $ComputerName = $Env:COMPUTERNAME ) foreach ($Computer in $ComputerName) { try { $Data = Get-HotFix -ComputerName $Computer $Output = foreach ($Update in $Data) { [PSCustomObject] @{ ComputerName = $Computer InstalledOn = $Update.InstalledOn Description = $Update.Description KB = $Update.HotFixId InstalledBy = $Update.InstalledBy Caption = $Update.Caption } } $Output | Sort-Object -Descending InstalledOn } catch { Write-Warning -Message "Get-ComputerWindowsUpdates - No data for computer $($Computer). Failed with errror: $($_.Exception.Message)" } } } function Get-OperatingSystem { [cmdletbinding()] param( [string] $Version ) $ListOperatingSystems = [ordered] @{ '10.0 (19043)' = [PSCustomObject] @{ Name = 'Windows 10 21H1'; Version = '10.0 (19043)'; CodeName = '21H1'; MarketingName = 'May 2021 Update'; BuildNumber = '19043'; ReleaseDate = (Get-Date -Year 2021 -Month 5 -Day 18 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2022 -Month 12 -Day 13 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2022 -Month 12 -Day 13 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = $null } '10.0 (19042)' = [PSCustomObject] @{ Name = 'Windows 10 20H2'; Version = '10.0 (19042)'; CodeName = '20H2'; MarketingName = 'October 2020 Update'; BuildNumber = '19042'; ReleaseDate = (Get-Date -Year 2020 -Month 9 -Day 20 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2022 -Month 5 -Day 10 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2023 -Month 5 -Day 9 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = $null } '10.0 (19041)' = [PSCustomObject] @{ Name = 'Windows 10 2004'; Version = '10.0 (19041)'; CodeName = '20H1'; MarketingName = 'May 2020 Update'; BuildNumber = '19041'; ReleaseDate = (Get-Date -Year 2020 -Month 5 -Day 27 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2021 -Month 12 -Day 14 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2021 -Month 12 -Day 14 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = $null } '10.0 (18363)' = [PSCustomObject] @{ Name = "Windows 10 1909"; Version = '10.0 (18363)'; CodeName = '19H2'; MarketingName = 'November 2019 Update'; BuildNumber = '18363'; ReleaseDate = (Get-Date -Year 2019 -Month 11 -Day 12 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2021 -Month 5 -Day 11 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2022 -Month 5 -Day 10 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = $null } '10.0 (18362)' = [PSCustomObject] @{ Name = "Windows 10 1903"; Version = '10.0 (18362)'; CodeName = '19H1'; MarketingName = 'May 2019 Update'; BuildNumber = '18362'; ReleaseDate = (Get-Date -Year 2019 -Month 5 -Day 21 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2020 -Month 12 -Day 8 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2020 -Month 12 -Day 8 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = $null } '10.0 (17763)' = [PSCustomObject] @{ Name = "Windows 10 1809"; Version = '10.0 (17763)'; CodeName = 'Redstone 5'; MarketingName = 'October 2018 Update'; BuildNumber = '17763'; ReleaseDate = (Get-Date -Year 2018 -Month 11 -Day 13 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2020 -Month 11 -Day 10 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2021 -Month 5 -Day 11 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = (Get-Date -Year 2029 -Month 1 -Day 9 -Second 1 -Minute 1 -Hour 1 -Millisecond 1) } '10.0 (17134)' = [PSCustomObject] @{ Name = "Windows 10 1803"; Version = '10.0 (17134)'; CodeName = 'Redstone 4'; MarketingName = 'April 2018 Update'; BuildNumber = '17134'; ReleaseDate = (Get-Date -Year 2018 -Month 4 -Day 30 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2020 -Month 11 -Day 12 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2021 -Month 5 -Day 11 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = $null } '10.0 (16299)' = [PSCustomObject] @{ Name = "Windows 10 1709"; Version = '10.0 (16299)'; CodeName = 'Redstone 3'; MarketingName = 'Fall Creators Update'; BuildNumber = '16299'; ReleaseDate = (Get-Date -Year 2017 -Month 9 -Day 17 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2019 -Month 4 -Day 9 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2020 -Month 10 -Day 13 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); ; LTSC = $null } '10.0 (15063)' = [PSCustomObject] @{ Name = "Windows 10 1703"; Version = '10.0 (15063)'; CodeName = 'Redstone 2'; MarketingName = 'Creators Update'; BuildNumber = '15063'; ReleaseDate = (Get-Date -Year 2017 -Month 4 -Day 5 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2018 -Month 10 -Day 9 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2019 -Month 10 -Day 8 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); ; LTSC = $null } '10.0 (14393)' = [PSCustomObject] @{ Name = "Windows 10 1607"; Version = '10.0 (14393)'; CodeName = 'Redstone 1'; MarketingName = 'Anniversary Update'; BuildNumber = '14393'; ReleaseDate = (Get-Date -Year 2016 -Month 8 -Day 2 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2018 -Month 4 -Day 10 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2019 -Month 4 -Day 9 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = (Get-Date -Year 2026 -Month 10 -Day 13 -Second 1 -Minute 1 -Hour 1 -Millisecond 1) } '10.0 (10586)' = [PSCustomObject] @{ Name = "Windows 10 1511"; Version = '10.0 (10586)'; CodeName = 'Threshold 2'; MarketingName = 'November Update'; BuildNumber = '10586'; ReleaseDate = (Get-Date -Year 2015 -Month 11 -Day 10 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2017 -Month 10 -Day 10 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2018 -Month 4 -Day 10 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = $null } '10.0 (10240)' = [PSCustomObject] @{ Name = "Windows 10 1507"; Version = '10.0 (10240)' ; CodeName = 'Threshold 1'; MarketingName = 'N/A'; BuildNumber = '10240'; ReleaseDate = (Get-Date -Year 2015 -Month 7 -Day 29 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndPro = (Get-Date -Year 2017 -Month 5 -Day 9 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); SupportEndEnterprise = (Get-Date -Year 2017 -Month 5 -Day 9 -Second 1 -Minute 1 -Hour 1 -Millisecond 1); LTSC = (Get-Date -Year 2025 -Month 10 -Day 14 -Second 1 -Minute 1 -Hour 1 -Millisecond 1) } } if ($Version) { $ListOperatingSystems[$Version] } else { $ListOperatingSystems.Values } } function Get-IPAddressInformation { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER IP Parameter description .EXAMPLE Get-IpAddressInformation -IP 1.1.1.1 .NOTES General notes #> [cmdletbinding()] param( [string] $IP ) try { $Information = Invoke-RestMethod -Method get -Uri "http://ip-api.com/json/$ip" } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Warning "Get-IPAddressInformation - Error occured on IP $IP`: $ErrorMessage" } return $Information } function Get-MyIpAddress { [alias('Get-MyIP')] [CmdletBinding()] param() $DNSParam = @{ Name = 'myip.opendns.com' Server = 'resolver1.opendns.com' DnsOnly = $true } return Resolve-DnsName @DNSParam | ForEach-Object IPAddress } function Set-PasswordRemotely { [CmdletBinding(DefaultParameterSetName = 'Secure')] param( [Parameter(ParameterSetName = 'Secure', Mandatory)][string] $UserName, [Parameter(ParameterSetName = 'Secure', Mandatory)][securestring] $OldPassword, [Parameter(ParameterSetName = 'Secure', Mandatory)][securestring] $NewPassword, [Parameter(ParameterSetName = 'Secure')][alias('DC', 'Server', 'ComputerName')][string] $DomainController ) Begin { $DllImport = @' [DllImport("netapi32.dll", CharSet = CharSet.Unicode)] public static extern bool NetUserChangePassword(string domain, string username, string oldpassword, string newpassword); '@ $NetApi32 = Add-Type -MemberDefinition $DllImport -Name 'NetApi32' -Namespace 'Win32' -PassThru if (-not $DomainController) { if ($env:computername -eq $env:userdomain) { $DomainController = Read-Host -Prompt 'Domain Controller DNS name or IP Address' } else { $Domain = $Env:USERDNSDOMAIN $Context = [System.DirectoryServices.ActiveDirectory.DirectoryContext]::new([System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain, $Domain) $DomainController = ([System.DirectoryServices.ActiveDirectory.DomainController]::FindOne($Context)).Name } } } Process { if ($DomainController -and $OldPassword -and $NewPassword -and $UserName) { $OldPasswordPlain = [System.Net.NetworkCredential]::new([string]::Empty, $OldPassword).Password $NewPasswordPlain = [System.Net.NetworkCredential]::new([string]::Empty, $NewPassword).Password $result = $NetApi32::NetUserChangePassword($DomainController, $UserName, $OldPasswordPlain, $NewPasswordPlain) if ($result) { Write-Host -Object "Set-PasswordRemotely - Password change for account $UserName failed on $DomainController. Please try again." -ForegroundColor Red } else { Write-Host -Object "Set-PasswordRemotely - Password change for account $UserName succeeded on $DomainController." -ForegroundColor Cyan } } else { Write-Warning "Set-PasswordRemotely - Password change for account failed. All parameters are required. " } } End { $OldPassword = $null $NewPassword = $null $OldPasswordPlain = $null $NewPasswordPlain = $null [System.GC]::Collect() } } function Convert-BinaryToHex { param( [alias('Bin')] [Parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)] [Byte[]]$Binary ) if ($null -eq $Binary) { return } if ($Binary.Length -eq 1) { $Binary = @($input) } $Return = -join ($Binary | ForEach-Object { "{0:X2}" -f $_ }) Write-Output $Return } function Convert-BinaryToString { param( [alias('Bin')] [Parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)] [Byte[]]$Binary ) if ($null -ne $Binary) { return [System.Text.Encoding]::Unicode.GetString($Binary) } } function Convert-Color { <# .Synopsis This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX) .Description This color converter gives you the hexadecimal values of your RGB colors and vice versa (RGB to HEX). Use it to convert your colors and prepare your graphics and HTML web pages. .Parameter RBG Enter the Red Green Blue value comma separated. Red: 51 Green: 51 Blue: 204 for example needs to be entered as 51,51,204 .Parameter HEX Enter the Hex value to be converted. Do not use the '#' symbol. (Ex: 3333CC converts to Red: 51 Green: 51 Blue: 204) .Example .\convert-color -hex FFFFFF Converts hex value FFFFFF to RGB .Example .\convert-color -RGB 123,200,255 Converts Red = 123 Green = 200 Blue = 255 to Hex value #> param( [Parameter(ParameterSetName = "RGB", Position = 0)] [ValidateScript( { $_ -match '^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$' })] $RGB, [Parameter(ParameterSetName = "HEX", Position = 0)] [ValidateScript( { $_ -match '[A-Fa-f0-9]{6}' })] [string] $HEX ) switch ($PsCmdlet.ParameterSetName) { "RGB" { if ($null -eq $RGB[2]) { Write-Error "Value missing. Please enter all three values seperated by comma." } $red = [convert]::Tostring($RGB[0], 16) $green = [convert]::Tostring($RGB[1], 16) $blue = [convert]::Tostring($RGB[2], 16) if ($red.Length -eq 1) { $red = '0' + $red } if ($green.Length -eq 1) { $green = '0' + $green } if ($blue.Length -eq 1) { $blue = '0' + $blue } Write-Output $red$green$blue } "HEX" { $red = $HEX.Remove(2, 4) $Green = $HEX.Remove(4, 2) $Green = $Green.remove(0, 2) $Blue = $hex.Remove(0, 4) $Red = [convert]::ToInt32($red, 16) $Green = [convert]::ToInt32($green, 16) $Blue = [convert]::ToInt32($blue, 16) Write-Output $red, $Green, $blue } } } function Convert-CountryCodeToCountry { <# .SYNOPSIS Converts a country code to a country name, or when used with a switch to full culture information .DESCRIPTION Converts a country code to a country name, or when used with a switch to full culture information .PARAMETER CountryCode Country code .PARAMETER All Provide full culture information rather than just the country name .EXAMPLE Convert-CountryCodeToCountry -CountryCode 'PL' .EXAMPLE Convert-CountryCodeToCountry -CountryCode 'PL' -All .EXAMPLE $Test = Convert-CountryCodeToCountry $Test['PL']['Culture'] | fl $Test['PL']['RegionInformation'] .EXAMPLE Convert-CountryCodeToCountry -CountryCode 'PL' Convert-CountryCodeToCountry -CountryCode 'POL' .NOTES General notes #> [cmdletBinding()] param( [string] $CountryCode, [switch] $All ) if ($Script:QuickSearch) { if ($PSBoundParameters.ContainsKey('CountryCode')) { if ($All) { $Script:QuickSearch[$CountryCode] } else { $Script:QuickSearch[$CountryCode].RegionInformation.EnglishName } } else { $Script:QuickSearch } } else { $Script:QuickSearch = [ordered] @{} $AllCultures = [cultureinfo]::GetCultures([System.Globalization.CultureTypes]::SpecificCultures) foreach ($Culture in $AllCultures) { $RegionInformation = [System.Globalization.RegionInfo]::new($Culture) $Script:QuickSearch[$RegionInformation.TwoLetterISORegionName] = @{ 'Culture' = $Culture 'RegionInformation' = $RegionInformation } $Script:QuickSearch[$RegionInformation.ThreeLetterISORegionName] = @{ 'Culture' = $Culture 'RegionInformation' = $RegionInformation } } if ($PSBoundParameters.ContainsKey('CountryCode')) { if ($All) { $Script:QuickSearch[$CountryCode] } else { $Script:QuickSearch[$CountryCode].RegionInformation.EnglishName } } else { $Script:QuickSearch } } } function Convert-CountryToContinent { <# .SYNOPSIS Convert country to continent .DESCRIPTION Convert country to continent or return a hashtable of countries and their corresponding continent. If the country is not found (for example empty), it will return "Unknown" .PARAMETER Country Country to convert. If country is not given it will return a hashtable of countries and their corresponding continent. .EXAMPLE Convert-CountryToContinent -Country "Poland" .EXAMPLE Convert-CountryToContinent .NOTES General notes #> [CmdletBinding()] param( [string] $Country, [switch] $ReturnHashTable ) $CountryToContinent = [ordered] @{ "Afghanistan" = "Asia" "Albania" = "Europe" "Algeria" = "Africa" "Andorra" = "Europe" "Angola" = "Africa" "Antigua and Barbuda" = "North America" "Argentina" = "South America" "Armenia" = "Asia" "Australia" = "Australia/Oceania" "Austria" = "Europe" "Azerbaijan" = "Asia" "Bahamas" = "North America" "Bahrain" = "Asia" "Bangladesh" = "Asia" "Barbados" = "North America" "Belarus" = "Europe" "Belgium" = "Europe" "Belize" = "North America" "Benin" = "Africa" "Bhutan" = "Asia" "Bolivia" = "South America" "Bosnia and Herzegovina" = "Europe" "Botswana" = "Africa" "Brazil" = "South America" "Brunei" = "Asia" "Bulgaria" = "Europe" "Burkina Faso" = "Africa" "Burundi" = "Africa" "Cabo Verde" = "Africa" "Cambodia" = "Asia" "Cameroon" = "Africa" "Canada" = "North America" "Central African Republic" = "Africa" "Chad" = "Africa" "Chile" = "South America" "China" = "Asia" "Colombia" = "South America" "Comoros" = "Africa" "Congo, Democratic Republic of the" = "Africa" "Congo, Republic of the" = "Africa" "Costa Rica" = "North America" "Cote d'Ivoire" = "Africa" "Croatia" = "Europe" "Cuba" = "North America" "Cyprus" = "Asia" "Czechia" = "Europe" "Denmark" = "Europe" "Djibouti" = "Africa" "Dominica" = "North America" "Dominican Republic" = "North America" "Ecuador" = "South America" "Egypt" = "Africa" "El Salvador" = "North America" "Equatorial Guinea" = "Africa" "Eritrea" = "Africa" "Estonia" = "Europe" "Eswatini" = "Africa" "Ethiopia" = "Africa" "Fiji" = "Australia/Oceania" "Finland" = "Europe" "France" = "Europe" "Gabon" = "Africa" "Gambia" = "Africa" "Georgia" = "Asia" "Germany" = "Europe" "Ghana" = "Africa" "Greece" = "Europe" "Grenada" = "North America" "Guatemala" = "North America" "Guinea" = "Africa" "Guinea-Bissau" = "Africa" "Guyana" = "South America" "Haiti" = "North America" "Honduras" = "North America" "Hungary" = "Europe" "Iceland" = "Europe" "India" = "Asia" "Indonesia" = "Asia" "Iran" = "Asia" "Iraq" = "Asia" "Ireland" = "Europe" "Israel" = "Asia" "Italy" = "Europe" "Jamaica" = "North America" "Japan" = "Asia" "Jordan" = "Asia" "Kazakhstan" = "Asia" "Kenya" = "Africa" "Kiribati" = "Australia/Oceania" "Kosovo" = "Europe" "Kuwait" = "Asia" "Kyrgyzstan" = "Asia" "Laos" = "Asia" "Latvia" = "Europe" "Lebanon" = "Asia" "Lesotho" = "Africa" "Liberia" = "Africa" "Libya" = "Africa" "Liechtenstein" = "Europe" "Lithuania" = "Europe" "Luxembourg" = "Europe" "Madagascar" = "Africa" "Malawi" = "Africa" "Malaysia" = "Asia" "Maldives" = "Asia" "Mali" = "Africa" "Malta" = "Europe" "Marshall Islands" = "Australia/Oceania" "Mauritania" = "Africa" "Mauritius" = "Africa" "Mexico" = "North America" "Micronesia" = "Australia/Oceania" "Moldova" = "Europe" "Monaco" = "Europe" "Mongolia" = "Asia" "Montenegro" = "Europe" "Morocco" = "Africa" "Mozambique" = "Africa" "Myanmar" = "Asia" "Namibia" = "Africa" "Nauru" = "Australia/Oceania" "Nepal" = "Asia" "Netherlands" = "Europe" "New Zealand" = "Australia/Oceania" "Nicaragua" = "North America" "Niger" = "Africa" "Nigeria" = "Africa" "North Korea" = "Asia" "North Macedonia" = "Europe" "Norway" = "Europe" "Oman" = "Asia" "Pakistan" = "Asia" "Palau" = "Australia/Oceania" "Panama" = "North America" "Papua New Guinea" = "Australia/Oceania" "Paraguay" = "South America" "Peru" = "South America" "Philippines" = "Asia" "Poland" = "Europe" "Portugal" = "Europe" "Qatar" = "Asia" "Romania" = "Europe" "Russia" = "Asia" "Rwanda" = "Africa" "Saint Kitts and Nevis" = "North America" "Saint Lucia" = "North America" "Saint Vincent and the Grenadines" = "North America" "Samoa" = "Australia/Oceania" "San Marino" = "Europe" "Sao Tome and Principe" = "Africa" "Saudi Arabia" = "Asia" "Senegal" = "Africa" "Serbia" = "Europe" "Seychelles" = "Africa" "Sierra Leone" = "Africa" "Singapore" = "Asia" "Slovakia" = "Europe" "Slovenia" = "Europe" "Solomon Islands" = "Australia/Oceania" "Somalia" = "Africa" "South Africa" = "Africa" "South Korea" = "Asia" "South Sudan" = "Africa" "Spain" = "Europe" "Sri Lanka" = "Asia" "Sudan" = "Africa" "Suriname" = "South America" "Sweden" = "Europe" "Switzerland" = "Europe" "Syria" = "Asia" "Taiwan" = "Asia" "Tajikistan" = "Asia" "Tanzania" = "Africa" "Thailand" = "Asia" "Timor-Leste" = "Asia" "Togo" = "Africa" "Tonga" = "Australia/Oceania" "Trinidad and Tobago" = "North America" "Tunisia" = "Africa" "Turkey" = "Asia" "Turkmenistan" = "Asia" "Tuvalu" = "Australia/Oceania" "Uganda" = "Africa" "Ukraine" = "Europe" "United Arab Emirates" = "Asia" "United Kingdom" = "Europe" "United States of America" = "North America" "Uruguay" = "South America" "Uzbekistan" = "Asia" "Vanuatu" = "Australia/Oceania" "Vatican City (Holy See)" = "Europe" "Venezuela" = "South America" "Vietnam" = "Asia" "Yemen" = "Asia" "Zambia" = "Africa" "Zimbabwe" = "Africa" } if ($PSBoundParameters.ContainsKey('Country')) { if ($CountryToContinent[$Country]) { $CountryToContinent[$Country] } else { "Unknown" } } else { $CountryToContinent } } function Convert-CountryToCountryCode { <# .SYNOPSIS Converts a country name to a country code, or when used with a switch to full culture information .DESCRIPTION Converts a country name to a country code, or when used with a switch to full culture information .PARAMETER CountryName Country name in it's english name .PARAMETER All Provide full culture information rather than just the country code .EXAMPLE Convert-CountryToCountryCode -CountryName 'Poland' .EXAMPLE Convert-CountryToCountryCode -CountryName 'Poland' -All .EXAMPLE $Test = Convert-CountryToCountryCode $Test['India']['Culture'] $Test['India']['RegionInformation'] .EXAMPLE $Test = Convert-CountryToCountryCode $Test['Poland']['Culture'] $Test['Poland']['RegionInformation'] .EXAMPLE Convert-CountryToCountryCode -CountryName 'Polska' Convert-CountryToCountryCode -CountryName 'Poland' Convert-CountryToCountryCode -CountryName 'CZECH REPUBLIC' Convert-CountryToCountryCode -CountryName 'USA' .NOTES General notes #> [cmdletBinding()] param( [string] $CountryName, [switch] $All ) if ($Script:QuickSearchCountries) { if ($CountryName) { if ($All) { $Script:QuickSearchCountries[$CountryName] } else { if ($Script:QuickSearchCountries[$CountryName]) { $Script:QuickSearchCountries[$CountryName].RegionInformation.TwoLetterISORegionName.ToUpper() } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw "Country $CountryName not found" } else { Write-Warning -Message "Convert-CountryToCountryCode - Country $CountryName name not found" } } } } else { $Script:QuickSearchCountries } } else { $AllCultures = [cultureinfo]::GetCultures([System.Globalization.CultureTypes]::SpecificCultures) $Script:QuickSearchCountries = [ordered] @{ 'Czech Republic' = @{ 'Culture' = [cultureinfo] 'CZ' 'RegionInformation' = [System.Globalization.RegionInfo] 'CZ' } 'Korea, REPUBLIC OF' = @{ 'Culture' = [cultureinfo] 'KR' 'RegionInformation' = [System.Globalization.RegionInfo] 'KR' } 'VIET NAM' = @{ 'Culture' = [cultureinfo] 'VN' 'RegionInformation' = [System.Globalization.RegionInfo] 'VN' } } foreach ($Culture in $AllCultures) { $RegionInformation = [System.Globalization.RegionInfo]::new($Culture) $Script:QuickSearchCountries[$RegionInformation.EnglishName] = @{ 'Culture' = $Culture 'RegionInformation' = $RegionInformation } $Script:QuickSearchCountries[$RegionInformation.DisplayName] = @{ 'Culture' = $Culture 'RegionInformation' = $RegionInformation } $Script:QuickSearchCountries[$RegionInformation.NativeName] = @{ 'Culture' = $Culture 'RegionInformation' = $RegionInformation } $Script:QuickSearchCountries[$RegionInformation.ThreeLetterISORegionName] = @{ 'Culture' = $Culture 'RegionInformation' = $RegionInformation } } if ($CountryName) { if ($All) { $Script:QuickSearchCountries[$CountryName] } else { if ($Script:QuickSearchCountries[$CountryName]) { $Script:QuickSearchCountries[$CountryName].RegionInformation.TwoLetterISORegionName.ToUpper() } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw "Country $CountryName not found" } else { Write-Warning -Message "Convert-CountryToCountryCode - Country $CountryName name not found" } } } } else { $Script:QuickSearchCountries } } } Function Convert-DomainFqdnToNetBIOS { <# .SYNOPSIS Converts FQDN to NetBIOS name for Active Directory Domain .DESCRIPTION Converts FQDN to NetBIOS name for Active Directory Domain .PARAMETER DomainName DomainName for current forest or trusted forest .EXAMPLE Convert-DomainFqdnToNetBIOS -Domain 'ad.evotec.xyz' .EXAMPLE Convert-DomainFqdnToNetBIOS -Domain 'ad.evotec.pl' .NOTES General notes #> [cmdletBinding()] param ( [string] $DomainName ) if (-not $Script:CacheFQDN) { $Script:CacheFQDN = @{} } if ($Script:CacheFQDN[$DomainName]) { $Script:CacheFQDN[$DomainName] } else { $objRootDSE = [System.DirectoryServices.DirectoryEntry] "LDAP://$DomainName/RootDSE" $ConfigurationNC = $objRootDSE.configurationNamingContext $Searcher = [System.DirectoryServices.DirectorySearcher] @{ SearchScope = "subtree" SearchRoot = "LDAP://cn=Partitions,$ConfigurationNC" Filter = "(&(objectcategory=Crossref)(dnsRoot=$DomainName)(netbiosname=*))" } $null = $Searcher.PropertiesToLoad.Add("netbiosname") $Script:CacheFQDN[$DomainName] = ($Searcher.FindOne()).Properties.Item("netbiosname") $Script:CacheFQDN[$DomainName] } } function Convert-DomainToSid { <# .SYNOPSIS Converts Domain Name to SID .DESCRIPTION Converts Domain Name to SID .PARAMETER DomainName DomainName for current forest or trusted forest .EXAMPLE Convert-DomainToSid -DomainName 'test.evotec.pl' .NOTES General notes #> [cmdletBinding()] param( [parameter(Mandatory)][string] $DomainName ) try { $BinarySID = ([ADSI]"LDAP://$DomainName").objectsid $DomainSidValue = [System.Security.Principal.SecurityIdentifier]::new($BinarySID.Value, 0).Value $DomainSidValue } catch { Write-Warning -Message "Convert-DomainToSid - Failed conversion with error $($_.Exception.Message)" } } function Convert-ExchangeEmail { <# .SYNOPSIS Function that helps converting Exchange email address list into readable, exportable format. .DESCRIPTION Function that helps converting Exchange email address list into readable, exportable format. .PARAMETER Emails List of emails as available in Exchange or Exchange Online, otherwise known as proxy addresses list .PARAMETER Separator .PARAMETER RemoveDuplicates .PARAMETER RemovePrefix .PARAMETER AddSeparator .EXAMPLE $Emails = @() $Emails += 'SIP:test@email.com' $Emails += 'SMTP:elo@maiu.com' $Emails += 'sip:elo@maiu.com' $Emails += 'Spo:dfte@sdsd.com' $Emails += 'SPO:myothertest@sco.com' Convert-ExchangeEmail -Emails $Emails -RemovePrefix -RemoveDuplicates -AddSeparator .NOTES General notes #> [CmdletBinding()] param( [string[]] $Emails, [string] $Separator = ', ', [switch] $RemoveDuplicates, [switch] $RemovePrefix, [switch] $AddSeparator ) if ($RemovePrefix) { $Emails = $Emails -replace 'smtp:', '' -replace 'sip:', '' -replace 'spo:', '' } if ($RemoveDuplicates) { $Emails = $Emails | Sort-Object -Unique } if ($AddSeparator) { $Emails = $Emails -join $Separator } return $Emails } function Convert-ExchangeItems { [cmdletbinding()] param( $Count, [string] $Default = 'N/A' ) if ($null -eq $Count) { return $Default } else { return $Count } } function Convert-ExchangeRecipient { <# .SYNOPSIS Convert msExchRemoteRecipientType, msExchRecipientDisplayType, msExchRecipientTypeDetails to their respective name .DESCRIPTION Convert msExchRemoteRecipientType, msExchRecipientDisplayType, msExchRecipientTypeDetails to their respective name .PARAMETER RecipientTypeDetails RecipientTypeDetails to convert .PARAMETER RecipientType RecipientType to convert .PARAMETER RemoteRecipientType Parameter description .EXAMPLE $Users = Get-ADUser -Filter * -Properties Mail, ProxyAddresses, msExchRemoteRecipientType, msExchRecipientDisplayType, msExchRecipientTypeDetails, MailNickName $UsersModified = foreach ($User in $Users) { [PSCUstomObject] @{ Name = $User.Name Mail = $User.Mail MailNickName = $User.MailNickName msExchRemoteRecipientType = Convert-ExchangeRecipient -msExchRemoteRecipientType $User.msExchRemoteRecipientType msExchRecipientDisplayType = Convert-ExchangeRecipient -msExchRecipientDisplayType $User.msExchRecipientDisplayType msExchRecipientTypeDetails = Convert-ExchangeRecipient -msExchRecipientTypeDetails $User.msExchRecipientTypeDetails ProxyAddresses = Convert-ExchangeEmail -AddSeparator -RemovePrefix -RemoveDuplicates -Separator ',' -Emails $User.ProxyAddresses } } $UsersModified | Out-HtmlView -Filtering -ScrollX .EXAMPLE Convert-ExchangeRecipient -msExchRemoteRecipientType 17 Convert-ExchangeRecipient -msExchRecipientDisplayType 17 Convert-ExchangeRecipient -msExchRecipientTypeDetails 17 .NOTES Based on: - https://granikos.eu/exchange-recipient-type-values/ - https://answers.microsoft.com/en-us/msoffice/forum/all/recipient-type-values/7c2620e5-9870-48ba-b5c2-7772c739c651 - https://www.undocumented-features.com/2020/05/06/every-last-msexchrecipientdisplaytype-and-msexchrecipienttypedetails-value/ #> [alias('Convert-ExchangeRecipientDetails')] [cmdletbinding(DefaultParameterSetName = 'msExchRecipientTypeDetails')] param( [parameter(ParameterSetName = 'msExchRecipientTypeDetails')][alias('RecipientTypeDetails')][string] $msExchRecipientTypeDetails, [parameter(ParameterSetName = 'msExchRecipientDisplayType')][alias('RecipientType')][string] $msExchRecipientDisplayType, [parameter(ParameterSetName = 'msExchRemoteRecipientType')][alias('RemoteRecipientType')][string] $msExchRemoteRecipientType, [parameter(ParameterSetName = 'msExchRecipientTypeDetails')] [parameter(ParameterSetName = 'msExchRecipientDisplayType')] [parameter(ParameterSetName = 'msExchRemoteRecipientType')] [switch] $All ) if ($PSBoundParameters.ContainsKey('msExchRecipientTypeDetails')) { $ListMsExchRecipientTypeDetails = [ordered] @{ '0' = 'None' '1' = 'UserMailbox' '2' = 'LinkedMailbox' '4' = 'SharedMailbox' '8' = 'LegacyMailbox' '16' = 'RoomMailbox' '32' = 'EquipmentMailbox' '64' = 'MailContact' '128' = 'MailUser' '256' = 'MailUniversalDistributionGroup' '512' = 'MailNonUniversalGroup' '1024' = 'MailUniversalSecurityGroup' '2048' = 'DynamicDistributionGroup' '4096' = 'PublicFolder' '8192' = 'SystemAttendantMailbox' '16384' = 'SystemMailbox' '32768' = 'MailForestContact' '65536' = 'User' '131072' = 'Contact' '262144' = 'UniversalDistributionGroup' '524288' = 'UniversalSecurityGroup' '1048576' = 'NonUniversalGroup' '2097152' = 'Disable User' '4194304' = 'MicrosoftExchange' '8388608' = 'ArbitrationMailbox' '16777216' = 'MailboxPlan' '33554432' = 'LinkedUser' '268435456' = 'RoomList' '536870912' = 'DiscoveryMailbox' '1073741824' = 'RoleGroup' '2147483648' = 'RemoteUserMailbox' '4294967296' = 'Computer' '8589934592' = 'RemoteRoomMailbox' '17179869184' = 'RemoteEquipmentMailbox' '34359738368' = 'RemoteSharedMailbox' '68719476736' = 'PublicFolderMailbox' '137438953472' = 'Team Mailbox' '274877906944' = 'RemoteTeamMailbox' '549755813888' = 'MonitoringMailbox' '1099511627776' = 'GroupMailbox' '2199023255552' = 'LinkedRoomMailbox' '4398046511104' = 'AuditLogMailbox' '8796093022208' = 'RemoteGroupMailbox' '17592186044416' = 'SchedulingMailbox' '35184372088832' = 'GuestMailUser' '70368744177664' = 'AuxAuditLogMailbox' '140737488355328' = 'SupervisoryReviewPolicyMailbox' } if ($All) { $ListMsExchRecipientTypeDetails } else { if ($null -ne $ListMsExchRecipientTypeDetails[$msExchRecipientTypeDetails]) { $ListMsExchRecipientTypeDetails[$msExchRecipientTypeDetails] } else { $msExchRecipientTypeDetails } } } elseif ($PSBoundParameters.ContainsKey('msExchRecipientDisplayType')) { $ListMsExchRecipientDisplayType = [ordered] @{ '0' = 'MailboxUser' '1' = 'DistributionGroup' '2' = 'PublicFolder' '3' = 'DynamicDistributionGroup' '4' = 'Organization' '5' = 'PrivateDistributionList' '6' = 'RemoteMailUser' '7' = 'ConferenceRoomMailbox' '8' = 'EquipmentMailbox' '10' = 'ArbitrationMailbox' '11' = 'MailboxPlan' '12' = 'LinkedUser' '15' = 'RoomList' '17' = 'Microsoft365Group' '-2147483642' = 'SyncedMailboxUser' '-2147483391' = 'SyncedUDGasUDG' '-2147483386' = 'SyncedUDGasContact' '-2147483130' = 'SyncedPublicFolder' '-2147482874' = 'SyncedDynamicDistributionGroup' '-2147482106' = 'SyncedRemoteMailUser' '-2147481850' = 'SyncedConferenceRoomMailbox' '-2147481594' = 'SyncedEquipmentMailbox' '-2147481343' = 'SyncedUSGasUDG' '-2147481338' = 'SyncedUSGasContact' '-1073741818' = 'ACLableSyncedMailboxUser' '-1073740282' = 'ACLableSyncedRemoteMailUser' '-1073739514' = 'ACLableSyncedUSGasContact' '-1073739511' = 'SyncedUSGasUSG' '1043741833' = 'SecurityDistributionGroup' '1073739511' = 'SyncedUSGasUSG' '1073739514' = 'ACLableSyncedUSGasContact' '1073741824' = 'ACLableMailboxUser' '1073741830' = 'ACLableRemoteMailUser' } if ($All) { $ListMsExchRecipientDisplayType } else { if ($null -ne $ListMsExchRecipientDisplayType[$msExchRecipientDisplayType]) { $ListMsExchRecipientDisplayType[$msExchRecipientDisplayType] } else { $msExchRecipientDisplayType } } } elseif ($PSBoundParameters.ContainsKey('msExchRemoteRecipientType')) { $ListMsExchRemoteRecipientType = [ordered] @{ '1' = 'ProvisionMailbox' '2' = 'ProvisionArchive (On-Prem Mailbox)' '3' = 'ProvisionMailbox, ProvisionArchive' '4' = 'Migrated (UserMailbox)' '6' = 'ProvisionArchive, Migrated' '8' = 'DeprovisionMailbox' '10' = 'ProvisionArchive, DeprovisionMailbox' '16' = 'DeprovisionArchive (On-Prem Mailbox)' '17' = 'ProvisionMailbox, DeprovisionArchive' '20' = 'Migrated, DeprovisionArchive' '24' = 'DeprovisionMailbox, DeprovisionArchive' '33' = 'ProvisionMailbox, RoomMailbox' '35' = 'ProvisionMailbox, ProvisionArchive, RoomMailbox' '36' = 'Migrated, RoomMailbox' '38' = 'ProvisionArchive, Migrated, RoomMailbox' '49' = 'ProvisionMailbox, DeprovisionArchive, RoomMailbox' '52' = 'Migrated, DeprovisionArchive, RoomMailbox' '65' = 'ProvisionMailbox, EquipmentMailbox' '67' = 'ProvisionMailbox, ProvisionArchive, EquipmentMailbox' '68' = 'Migrated, EquipmentMailbox' '70' = 'ProvisionArchive, Migrated, EquipmentMailbox' '81' = 'ProvisionMailbox, DeprovisionArchive, EquipmentMailbox' '84' = 'Migrated, DeprovisionArchive, EquipmentMailbox' '100' = 'Migrated, SharedMailbox' '102' = 'ProvisionArchive, Migrated, SharedMailbox' '116' = 'Migrated, DeprovisionArchive, SharedMailbox' } if ($All) { $ListMsExchRemoteRecipientType } else { if ($null -ne $ListMsExchRemoteRecipientType[$msExchRemoteRecipientType]) { $ListMsExchRemoteRecipientType[$msExchRemoteRecipientType] } else { $msExchRemoteRecipientType } } } } function Convert-ExchangeSize { [cmdletbinding()] param( [validateset("Bytes", "KB", "MB", "GB", "TB")][string]$To = 'MB', [string]$Size, [int]$Precision = 4, [switch]$Display, [string]$Default = 'N/A' ) if ([string]::IsNullOrWhiteSpace($Size)) { return $Default } $Pattern = [Regex]::new('(?<=\()([0-9]*[,.].*[0-9])') $Value = ($Size | Select-String $Pattern -AllMatches).Matches.Value if ($null -ne $Value) { $Value = $Value.Replace(',', '').Replace('.', '') } switch ($To) { "Bytes" { return $value } "KB" { $Value = $Value / 1KB } "MB" { $Value = $Value / 1MB } "GB" { $Value = $Value / 1GB } "TB" { $Value = $Value / 1TB } } if ($Display) { return "$([Math]::Round($value,$Precision,[MidPointRounding]::AwayFromZero)) $To" } else { return [Math]::Round($value, $Precision, [MidPointRounding]::AwayFromZero) } } function ConvertFrom-Color { [alias('Convert-FromColor')] [CmdletBinding()] param ( [ValidateScript( { if ($($_ -in $Script:RGBColors.Keys -or $_ -match "^#([A-Fa-f0-9]{6})$" -or $_ -eq "") -eq $false) { throw "The Input value is not a valid colorname nor an valid color hex code." } else { $true } })] [alias('Colors')][string[]] $Color, [switch] $AsDecimal, [switch] $AsDrawingColor ) $Colors = foreach ($C in $Color) { $Value = $Script:RGBColors."$C" if ($C -match "^#([A-Fa-f0-9]{6})$") { $C continue } if ($null -eq $Value) { continue } $HexValue = Convert-Color -RGB $Value Write-Verbose "Convert-FromColor - Color Name: $C Value: $Value HexValue: $HexValue" if ($AsDecimal) { [Convert]::ToInt64($HexValue, 16) } elseif ($AsDrawingColor) { [System.Drawing.Color]::FromArgb("#$($HexValue)") } else { "#$($HexValue)" } } $Colors } $ScriptBlockColors = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $Script:RGBColors.Keys | Where-Object { $_ -like "$wordToComplete*" } } Register-ArgumentCompleter -CommandName ConvertFrom-Color -ParameterName Color -ScriptBlock $ScriptBlockColors function Convert-HexToBinary { [CmdletBinding()] param( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] [string] $Hex ) $return = for ($i = 0; $i -lt $Hex.Length ; $i += 2) { [Byte]::Parse($Hex.Substring($i, 2), [System.Globalization.NumberStyles]::HexNumber) } Write-Output $return -NoEnumerate } function Convert-Identity { <# .SYNOPSIS Small command that tries to resolve any given object .DESCRIPTION Small command that tries to resolve any given object - be it SID, DN, FSP or Netbiosname .PARAMETER Identity Type to resolve in form of Identity, DN, SID .PARAMETER SID Allows to pass SID directly, rather then going thru verification process .PARAMETER Name Allows to pass Name directly, rather then going thru verification process .PARAMETER Force Allows to clear cache, useful when you want to force refresh .EXAMPLE $Identity = @( 'S-1-5-4' 'S-1-5-4' 'S-1-5-11' 'S-1-5-32-549' 'S-1-5-32-550' 'S-1-5-32-548' 'S-1-5-64-10' 'S-1-5-64-14' 'S-1-5-64-21' 'S-1-5-18' 'S-1-5-19' 'S-1-5-32-544' 'S-1-5-20-20-10-51' # Wrong SID 'S-1-5-21-853615985-2870445339-3163598659-512' 'S-1-5-21-3661168273-3802070955-2987026695-512' 'S-1-5-21-1928204107-2710010574-1926425344-512' 'CN=Test Test 2,OU=Users,OU=Production,DC=ad,DC=evotec,DC=pl' 'Test Local Group' 'przemyslaw.klys@evotec.pl' 'test2' 'NT AUTHORITY\NETWORK' 'NT AUTHORITY\SYSTEM' 'S-1-5-21-853615985-2870445339-3163598659-519' 'TEST\some' 'EVOTECPL\Domain Admins' 'NT AUTHORITY\INTERACTIVE' 'INTERACTIVE' 'EVOTEC\Domain Admins' 'EVOTECPL\Domain Admins' 'Test\Domain Admins' 'CN=S-1-5-21-1928204107-2710010574-1926425344-512,CN=ForeignSecurityPrincipals,DC=ad,DC=evotec,DC=xyz' # Valid 'CN=S-1-5-21-1928204107-2710010574-512,CN=ForeignSecurityPrincipals,DC=ad,DC=evotec,DC=xyz' # not valid 'CN=S-1-5-21-1928204107-2710010574-1926425344-512,CN=ForeignSecurityPrincipals,DC=ad,DC=evotec,DC=xyz' # cached ) $TestOutput = Convert-Identity -Identity $Identity -Verbose Output: Name SID DomainName Type Error ---- --- ---------- ---- ----- NT AUTHORITY\INTERACTIVE S-1-5-4 WellKnownGroup NT AUTHORITY\INTERACTIVE S-1-5-4 WellKnownGroup NT AUTHORITY\Authenticated Users S-1-5-11 WellKnownGroup BUILTIN\Server Operators S-1-5-32-549 WellKnownGroup BUILTIN\Print Operators S-1-5-32-550 WellKnownGroup BUILTIN\Account Operators S-1-5-32-548 WellKnownGroup NT AUTHORITY\NTLM Authentication S-1-5-64-10 WellKnownGroup NT AUTHORITY\SChannel Authentication S-1-5-64-14 WellKnownGroup NT AUTHORITY\Digest Authentication S-1-5-64-21 WellKnownGroup NT AUTHORITY\SYSTEM S-1-5-18 WellKnownAdministrative NT AUTHORITY\NETWORK SERVICE S-1-5-19 WellKnownGroup BUILTIN\Administrators S-1-5-32-544 WellKnownAdministrative S-1-5-20-20-10-51 S-1-5-20-20-10-51 Unknown Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated." EVOTEC\Domain Admins S-1-5-21-853615985-2870445339-3163598659-512 ad.evotec.xyz Administrative EVOTECPL\Domain Admins S-1-5-21-3661168273-3802070955-2987026695-512 ad.evotec.pl Administrative TEST\Domain Admins S-1-5-21-1928204107-2710010574-1926425344-512 test.evotec.pl Administrative EVOTECPL\TestingAD S-1-5-21-3661168273-3802070955-2987026695-1111 ad.evotec.pl NotAdministrative EVOTEC\Test Local Group S-1-5-21-853615985-2870445339-3163598659-3610 ad.evotec.xyz NotAdministrative EVOTEC\przemyslaw.klys S-1-5-21-853615985-2870445339-3163598659-1105 ad.evotec.xyz NotAdministrative test2 Unknown Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated." NT AUTHORITY\NETWORK S-1-5-2 WellKnownGroup NT AUTHORITY\SYSTEM S-1-5-18 WellKnownAdministrative EVOTEC\Enterprise Admins S-1-5-21-853615985-2870445339-3163598659-519 ad.evotec.xyz Administrative TEST\some S-1-5-21-1928204107-2710010574-1926425344-1106 test.evotec.pl NotAdministrative EVOTECPL\Domain Admins S-1-5-21-3661168273-3802070955-2987026695-512 ad.evotec.pl Administrative NT AUTHORITY\INTERACTIVE S-1-5-4 WellKnownGroup NT AUTHORITY\INTERACTIVE S-1-5-4 WellKnownGroup EVOTEC\Domain Admins S-1-5-21-853615985-2870445339-3163598659-512 ad.evotec.xyz Administrative EVOTECPL\Domain Admins S-1-5-21-3661168273-3802070955-2987026695-512 ad.evotec.pl Administrative TEST\Domain Admins S-1-5-21-1928204107-2710010574-1926425344-512 test.evotec.pl Administrative TEST\Domain Admins S-1-5-21-1928204107-2710010574-1926425344-512 test.evotec.pl Administrative S-1-5-21-1928204107-2710010574-512 S-1-5-21-1928204107-2710010574-512 Unknown Exception calling "Translate" with "1" argument(s): "Some or all identity references could not be translated." TEST\Domain Admins S-1-5-21-1928204107-2710010574-1926425344-512 test.evotec.pl Administrative .NOTES General notes #> [cmdletBinding(DefaultParameterSetName = 'Identity')] param( [parameter(ParameterSetName = 'Identity', Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)][string[]] $Identity, [parameter(ParameterSetName = 'SID', Mandatory)][System.Security.Principal.SecurityIdentifier[]] $SID, [parameter(ParameterSetName = 'Name', Mandatory)][string[]] $Name, [switch] $Force ) Begin { if (-not $Script:GlobalCacheSidConvert -or $Force) { $Script:GlobalCacheSidConvert = @{ 'NT AUTHORITY\SYSTEM' = [PSCustomObject] @{ Name = 'BUILTIN\Administrators' SID = 'S-1-5-18' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'BUILTIN\Administrators' = [PSCustomObject] @{ Name = 'BUILTIN\Administrators' SID = 'S-1-5-32-544' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'BUILTIN\Users' = [PSCustomObject] @{ Name = 'BUILTIN\Users' SID = 'S-1-5-32-545' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Guests' = [PSCustomObject] @{ Name = 'BUILTIN\Guests' SID = 'S-1-5-32-546' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Power Users' = [PSCustomObject] @{ Name = 'BUILTIN\Power Users' SID = 'S-1-5-32-547' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Account Operators' = [PSCustomObject] @{ Name = 'BUILTIN\Account Operators' SID = 'S-1-5-32-548' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Server Operators' = [PSCustomObject] @{ Name = 'BUILTIN\Server Operators' SID = 'S-1-5-32-549' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Print Operators' = [PSCustomObject] @{ Name = 'BUILTIN\Print Operators' SID = 'S-1-5-32-550' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Backup Operators' = [PSCustomObject] @{ Name = 'BUILTIN\Backup Operators' SID = 'S-1-5-32-551' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Replicator' = [PSCustomObject] @{ Name = 'BUILTIN\Replicators' SID = 'S-1-5-32-552' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Pre-Windows 2000 Compatible Access' = [PSCustomObject] @{ Name = 'BUILTIN\Pre-Windows 2000 Compatible Access' SID = 'S-1-5-32-554' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Remote Desktop Users' = [PSCustomObject] @{ Name = 'BUILTIN\Remote Desktop Users' SID = 'S-1-5-32-555' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Network Configuration Operators' = [PSCustomObject] @{ Name = 'BUILTIN\Network Configuration Operators' SID = 'S-1-5-32-556' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Incoming Forest Trust Builders' = [PSCustomObject] @{ Name = 'BUILTIN\Incoming Forest Trust Builders' SID = 'S-1-5-32-557' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Performance Monitor Users' = [PSCustomObject] @{ Name = 'BUILTIN\Performance Monitor Users' SID = 'S-1-5-32-558' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Performance Log Users' = [PSCustomObject] @{ Name = 'BUILTIN\Performance Log Users' SID = 'S-1-5-32-559' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Windows Authorization Access Group' = [PSCustomObject] @{ Name = 'BUILTIN\Windows Authorization Access Group' SID = 'S-1-5-32-560' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Terminal Server License Servers' = [PSCustomObject] @{ Name = 'BUILTIN\Terminal Server License Servers' SID = 'S-1-5-32-561' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Distributed COM Users' = [PSCustomObject] @{ Name = 'BUILTIN\Distributed COM Users' SID = 'S-1-5-32-562' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\IIS_IUSRS' = [PSCustomObject] @{ Name = 'BUILTIN\IIS_IUSRS' SID = 'S-1-5-32-568' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Cryptographic Operators' = [PSCustomObject] @{ Name = 'BUILTIN\Cryptographic Operators' SID = 'S-1-5-32-569' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Event Log Readers' = [PSCustomObject] @{ Name = 'BUILTIN\Event Log Readers' SID = 'S-1-5-32-573' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Certificate Service DCOM Access' = [PSCustomObject] @{ Name = 'BUILTIN\Certificate Service DCOM Access' SID = 'S-1-5-32-574' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\RDS Remote Access Servers' = [PSCustomObject] @{ Name = 'BUILTIN\RDS Remote Access Servers' SID = 'S-1-5-32-575' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\RDS Endpoint Servers' = [PSCustomObject] @{ Name = 'BUILTIN\RDS Endpoint Servers' SID = 'S-1-5-32-576' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\RDS Management Servers' = [PSCustomObject] @{ Name = 'BUILTIN\RDS Management Servers' SID = 'S-1-5-32-577' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Hyper-V Administrators' = [PSCustomObject] @{ Name = 'BUILTIN\Hyper-V Administrators' SID = 'S-1-5-32-578' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Access Control Assistance Operators' = [PSCustomObject] @{ Name = 'BUILTIN\Access Control Assistance Operators' SID = 'S-1-5-32-579' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'BUILTIN\Remote Management Users' = [PSCustomObject] @{ Name = 'BUILTIN\Remote Management Users' SID = 'S-1-5-32-580' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'Window Manager\Window Manager Group' = [PSCustomObject] @{ Name = 'Window Manager\Window Manager Group' SID = 'S-1-5-90-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'NT SERVICE\WdiServiceHost' = [PSCustomObject] @{ Name = 'NT SERVICE\WdiServiceHost' SID = 'S-1-5-80-3139157870-2983391045-3678747466-658725712-1809340420' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'NT SERVICE\MSSQLSERVER' = [PSCustomObject] @{ Name = 'NT SERVICE\MSSQLSERVER' SID = 'S-1-5-80-3880718306-3832830129-1677859214-2598158968-1052248003' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'NT SERVICE\SQLSERVERAGENT' = [PSCustomObject] @{ Name = 'NT SERVICE\SQLSERVERAGENT' SID = 'S-1-5-80-344959196-2060754871-2302487193-2804545603-1466107430' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'NT SERVICE\SQLTELEMETRY' = [PSCustomObject] @{ Name = 'NT SERVICE\SQLTELEMETRY' SID = 'S-1-5-80-2652535364-2169709536-2857650723-2622804123-1107741775' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'NT SERVICE\ADSync' = [PSCustomObject] @{ Name = 'NT SERVICE\ADSync' SID = 'S-1-5-80-3245704983-3664226991-764670653-2504430226-901976451' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'NT Service\himds' = [PSCustomObject] @{ Name = 'NT Service\himds' SID = 'S-1-5-80-4215458991-2034252225-2287069555-1155419622-2701885083' DomainName = '' Type = 'WellKnownGroup' Error = '' } } } } Process { if ($Identity) { foreach ($Ident in $Identity) { $MatchRegex = [Regex]::Matches($Ident, "S-\d-\d+-(\d+-|){1,14}\d+") if ($Script:GlobalCacheSidConvert[$Ident]) { Write-Verbose "Convert-Identity - Processing $Ident (Cache)" $Script:GlobalCacheSidConvert[$Ident] } elseif ($MatchRegex.Success) { Write-Verbose "Convert-Identity - Processing $Ident (SID)" if ($MatchRegex.Value -ne $Ident) { $Script:GlobalCacheSidConvert[$Ident] = ConvertFrom-SID -SID $MatchRegex.Value } else { $Script:GlobalCacheSidConvert[$Ident] = ConvertFrom-SID -SID $Ident } $Script:GlobalCacheSidConvert[$Ident] } elseif ($Ident -like '*DC=*') { Write-Verbose "Convert-Identity - Processing $Ident (DistinguishedName)" try { $Object = [adsi]"LDAP://$($Ident)" $SIDValue = [System.Security.Principal.SecurityIdentifier]::new($Object.objectSid.Value, 0).Value $Script:GlobalCacheSidConvert[$Ident] = ConvertFrom-SID -SID $SIDValue } catch { $Script:GlobalCacheSidConvert[$Ident] = [PSCustomObject] @{ Name = $Ident SID = $null DomainName = '' Type = 'Unknown' Error = $_.Exception.Message -replace [environment]::NewLine, ' ' } } $Script:GlobalCacheSidConvert[$Ident] } else { Write-Verbose "Convert-Identity - Processing $Ident (Other)" try { $SIDValue = ([System.Security.Principal.NTAccount] $Ident).Translate([System.Security.Principal.SecurityIdentifier]).Value $Script:GlobalCacheSidConvert[$Ident] = ConvertFrom-SID -SID $SIDValue } catch { $Script:GlobalCacheSidConvert[$Ident] = [PSCustomObject] @{ Name = $Ident SID = $null DomainName = '' Type = 'Unknown' Error = $_.Exception.Message -replace [environment]::NewLine, ' ' } } $Script:GlobalCacheSidConvert[$Ident] } } } else { if ($SID) { foreach ($S in $SID) { if ($Script:GlobalCacheSidConvert[$S]) { $Script:GlobalCacheSidConvert[$S] } else { $Script:GlobalCacheSidConvert[$S] = ConvertFrom-SID -SID $S $Script:GlobalCacheSidConvert[$S] } } } else { foreach ($Ident in $Name) { if ($Script:GlobalCacheSidConvert[$Ident]) { $Script:GlobalCacheSidConvert[$Ident] } else { $Script:GlobalCacheSidConvert[$Ident] = ([System.Security.Principal.NTAccount] $Ident).Translate([System.Security.Principal.SecurityIdentifier]).Value $Script:GlobalCacheSidConvert[$Ident] } } } } } End { } } function Convert-IpAddressToPtr { <# .SYNOPSIS Converts an IP address to a PTR record .DESCRIPTION This function takes an IP address as input and converts it to a PTR record. .PARAMETER IPAddress The IP address to convert .PARAMETER AsObject Should the function return an object instead of a string? .EXAMPLE Convert-IpAddressToPtr -IPAddress "10.1.2.3" .EXAMPLE Convert-IpAddressToPtr -IPAddress "10.1.2.3", "8.8.8.8" -AsObject .NOTES General notes #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string[]]$IPAddress, [switch] $AsObject ) foreach ($IP in $IPAddress) { $octets = $IP -split "\." [array]::Reverse($octets) $ptrString = ($octets -join ".") + ".in-addr.arpa" if ($AsObject) { [pscustomobject] @{ IPAddress = $IP PTR = $ptrString } } else { $ptrString } } } function Convert-KeyToKeyValue { [CmdletBinding()] param ( [object] $Object ) $NewHash = [ordered] @{} foreach ($O in $Object.Keys) { $KeyName = "$O ($($Object.$O))" $KeyValue = $Object.$O $NewHash.$KeyName = $KeyValue } return $NewHash } function Convert-Office365License { <# .SYNOPSIS This function helps converting Office 365 licenses from/to their SKU equivalent .DESCRIPTION This function helps converting Office 365 licenses from/to their SKU equivalent .PARAMETER License License SKU or License Name. Takes multiple values. .PARAMETER ToSku Converts license name to SKU .PARAMETER Separator .PARAMETER ReturnArray .EXAMPLE Convert-Office365License -License 'VISIOCLIENT','PROJECTONLINE_PLAN_1','test','tenant:VISIOCLIENT' .EXAMPLE Convert-Office365License -License "Office 365 A3 for faculty", "Project Plan 3 (for Department)", 'test' -ToSku .NOTES Based on https://learn.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference #> [CmdletBinding()] param( [Parameter(Position = 0, ValueFromPipeline)][Array] $License, [alias('SKU')][switch] $ToSku, [string] $Separator = ', ', [switch] $ReturnArray ) Begin { $O365SKU = [ordered] @{ 'AAD_BASIC' = "Azure Active Directory Basic" 'AAD_BASIC_EDU' = "Azure Active Directory Basic for Education" 'AAD_EDU' = "Azure Active Directory for Education" 'AAD_PREMIUM' = "Azure Active Directory Premium P1" 'AAD_PREMIUM_FACULTY' = "Azure Active Directory Premium P1 for Faculty" 'AAD_PREMIUM_P2' = "Azure Active Directory Premium P2" 'AAD_SMB' = "Azure Active Directory" 'ADALLOM_FOR_AATP' = "SecOps Investigation for MDI" 'ADALLOM_O365' = "Office 365 Cloud App Security" 'ADALLOM_S_DISCOVERY' = "CLOUD APP SECURITY DISCOVERY" 'ADALLOM_S_O365' = "Office 365 Cloud App Security" 'ADALLOM_S_STANDALONE' = "MICROSOFT CLOUD APP SECURITY" 'ADALLOM_S_STANDALONE_DOD' = "Microsoft Defender for Cloud Apps for DOD" 'ADALLOM_STANDALONE' = "Microsoft Cloud App Security" 'ADV_COMMS' = "Advanced Communications" 'ATA' = "Microsoft Defender for Identity" 'ATP_ENTERPRISE' = "Microsoft Defender for Office 365 (Plan 1)" 'ATP_ENTERPRISE_FACULTY' = "Microsoft Defender for Office 365 (Plan 1) Faculty" 'ATP_ENTERPRISE_GOV' = "Microsoft Defender for Office 365 (Plan 1) GCC" 'AX7_USER_TRIAL' = "Microsoft Dynamics AX7 User Trial" 'BI_AZURE_P_2_GOV' = "Power BI Pro for Government" 'BI_AZURE_P0' = "Power BI (free)" 'BI_AZURE_P1' = "Microsoft Power BI Reporting and Analytics Plan 1" 'BI_AZURE_P2' = "Power BI Pro" 'BI_AZURE_P3' = "Power BI Premium Per User" 'BPOS_S_DlpAddOn' = "Data Loss Prevention" 'BPOS_S_TODO_1' = "To-Do (Plan 1)" 'BPOS_S_TODO_2' = "To-Do (Plan 2)" 'BPOS_S_TODO_3' = "To-Do (Plan 3)" 'BPOS_S_TODO_FIRSTLINE' = "To-Do (Firstline)" 'CCIBOTS_PRIVPREV_VIRAL' = "Power Virtual Agents Viral Trial" 'CDS_ATTENDED_RPA' = "Common Data Service Attended RPA" 'CDS_CUSTOMER_INSIGHTS' = "Common Data Service for Customer Insights" 'CDS_CUSTOMER_INSIGHTS_BASE' = "Dataverse for Customer Insights�BASE" 'CDS_CUSTOMER_INSIGHTS_TRIAL' = "Common Data Service for Customer Insights Trial" 'CDS_DB_CAPACITY' = "Common Data Service Database Capacity" 'CDS_DB_CAPACITY_GOV' = "Common Data Service Database Capacity for Government" 'CDS_FILE_CAPACITY' = "Common Data Service for Apps File Capacity" 'CDS_Flow_Business_Process' = "Common data service for Flow per business process plan" 'CDS_FORM_PRO_USL' = "Common Data Service" 'CDS_LOG_CAPACITY' = "Common Data Service Log Capacity" 'CDS_O365_E5_KM' = "Common Data Service for SharePoint Syntex" 'CDS_O365_F1' = "Common Data Service for Teams" 'CDS_O365_F1_GCC' = "Common Data Service for Teams_F1 GCC" 'CDS_O365_P1' = "COMMON DATA SERVICE FOR TEAMS_P1" 'CDS_O365_P1_GCC' = "Common Data Service for Teams_P1 GCC" 'CDS_O365_P2' = "Common Data Service for Teams" 'CDS_O365_P2_GCC' = "COMMON DATA SERVICE FOR TEAMS_P2 GCC" 'CDS_O365_P3' = "Common Data Service for Teams" 'CDS_O365_P3_GCC' = "Common Data Service for Teams" 'CDS_PER_APP' = "CDS PowerApps per app plan" 'CDS_PER_APP_IWTRIAL' = "CDS Per app baseline access" 'CDS_POWERAPPS_PORTALS_LOGIN' = "Common Data Service Power Apps Portals Login Capacity" 'CDS_POWERAPPS_PORTALS_LOGIN_GCC' = "Common Data Service Power Apps Portals Login Capacity for GCC" 'CDS_POWERAPPS_PORTALS_PAGEVIEW' = "CDS PowerApps Portals page view capacity add-on" 'CDS_POWERAPPS_PORTALS_PAGEVIEW_GCC' = "CDS PowerApps Portals page view capacity add-on for GCC" 'CDS_REMOTE_ASSIST' = "Common Data Service for Remote Assist" 'CDS_UNATTENDED_RPA' = "Common Data Service Unattended RPA" 'CDS_VIRTUAL_AGENT_BASE' = "Common Data Service for Virtual Agent Base" 'CDS_VIRTUAL_AGENT_USL' = "Common Data Service" 'CDSAICAPACITY' = "AI Builder Capacity add-on" 'CDSAICAPACITY_PERAPP' = "AI Builder capacity Per App add-on" 'CDSAICAPACITY_PERUSER' = "AI Builder capacity Per User add-on" 'CDSAICAPACITY_PERUSER_NEW' = "AI Builder capacity Per User add-on" 'CMPA_addon' = "Compliance Manager Premium Assessment Add-On" 'CMPA_addon_GCC' = "Compliance Manager Premium Assessment Add-On for GCC" 'COMMUNICATIONS_COMPLIANCE' = "Microsoft Communications Compliance" 'COMMUNICATIONS_DLP' = "Microsoft Communications DLP" 'COMPLIANCE_MANAGER_PREMIUM_ASSESSMENT_ADDON' = "Compliance Manager Premium Assessment Add-On" 'Content_Explorer' = "Information Protection and Governance Analytics - Premium" 'ContentExplorer_Standard' = "Information Protection and Governance Analytics � Standard" 'CORTEX' = "Microsoft Viva Topics" 'CPC_1' = "Windows 365 Enterprise 2 vCPU 4 GB 128 GB" 'CPC_2' = "Windows 365 Enterprise 2 vCPU 8 GB 128 GB" 'CPC_B_1C_2RAM_64GB' = "Windows 365 Business 1 vCPU 2 GB 64 GB" 'CPC_B_2C_4RAM_128GB' = "Windows 365 Business 2 vCPU 4 GB 128 GB" 'CPC_B_2C_4RAM_256GB' = "Windows 365 Business 2 vCPU 4 GB 256 GB" 'CPC_B_2C_4RAM_64GB' = "Windows 365 Business 2 vCPU 4 GB 64 GB" 'CPC_B_2C_8RAM_128GB' = "Windows 365 Business 2 vCPU 8 GB 128 GB" 'CPC_B_2C_8RAM_256GB' = "Windows 365 Business 2 vCPU 8 GB 256 GB" 'CPC_B_4C_16RAM_128GB' = "Windows 365 Business 4 vCPU 16 GB 128 GB" 'CPC_B_4C_16RAM_128GB_WHB' = "Windows 365 Business 4 vCPU 16 GB 128 GB (with Windows Hybrid Benefit)" 'CPC_B_4C_16RAM_256GB' = "Windows 365 Business 4 vCPU 16 GB 256 GB" 'CPC_B_4C_16RAM_512GB' = "Windows 365 Business 4 vCPU 16 GB 512 GB" 'CPC_B_8C_32RAM_128GB' = "Windows 365 Business 8 vCPU 32 GB 128 GB" 'CPC_B_8C_32RAM_256GB' = "Windows 365 Business 8 vCPU 32 GB 256 GB" 'CPC_B_8C_32RAM_512GB' = "Windows 365 Business 8 vCPU 32 GB 512 GB" 'CPC_E_1C_2GB_64GB' = "Windows 365 Enterprise 1 vCPU 2 GB 64 GB" 'CPC_E_2C_4GB_128GB' = "Windows 365 Enterprise 2 vCPU 4 GB 128 GB" 'CPC_E_2C_4GB_256GB' = "Windows 365 Enterprise 2 vCPU 4 GB 256 GB" 'CPC_E_2C_4GB_64GB' = "Windows 365 Enterprise 2 vCPU 4 GB 64 GB" 'CPC_E_2C_8GB_128GB' = "Windows 365 Enterprise 2 vCPU 8 GB 128 GB" 'CPC_E_2C_8GB_256GB' = "Windows 365 Enterprise 2 vCPU 8 GB 256 GB" 'CPC_E_4C_16GB_128GB' = "Windows 365 Enterprise 4 vCPU 16 GB 128 GB" 'CPC_E_4C_16GB_256GB' = "Windows 365 Enterprise 4 vCPU 16 GB 256 GB" 'CPC_E_4C_16GB_512GB' = "Windows 365 Enterprise 4 vCPU 16 GB 512 GB" 'CPC_E_8C_32GB_128GB' = "Windows 365 Enterprise 8 vCPU 32 GB 128 GB" 'CPC_E_8C_32GB_256GB' = "Windows 365 Enterprise 8 vCPU 32 GB 256 GB" 'CPC_E_8C_32GB_512GB' = "Windows 365 Enterprise 8 vCPU 32 GB 512 GB" 'CPC_LVL_1' = "Windows 365 Enterprise 2 vCPU 4 GB 128 GB (Preview)" 'CPC_LVL_2' = "Windows 365 Enterprise 2 vCPU 8 GB 128 GB (Preview)" 'CPC_LVL_3' = "Windows 365 Enterprise 4 vCPU 16 GB 256 GB (Preview)" 'CPC_S_2C_4GB_128GB' = "Windows 365 Shared Use 2 vCPU 4 GB 128 GB" 'CPC_S_2C_4GB_256GB' = "Windows 365 Shared Use 2 vCPU 4 GB 256 GB" 'CPC_S_2C_4GB_64GB' = "Windows 365 Shared Use 2 vCPU 4 GB 64 GB" 'CPC_S_2C_8GB_128GB' = "Windows 365 Shared Use 2 vCPU 8 GB 128 GB" 'CPC_S_2C_8GB_256GB' = "Windows 365 Shared Use 2 vCPU 8 GB 256 GB" 'CPC_S_4C_16GB_128GB' = "Windows 365 Shared Use 4 vCPU 16 GB 128 GB" 'CPC_S_4C_16GB_256GB' = "Windows 365 Shared Use 4 vCPU 16 GB 256 GB" 'CPC_S_4C_16GB_512GB' = "Windows 365 Shared Use 4 vCPU 16 GB 512 GB" 'CPC_S_8C_32GB_128GB' = "Windows 365 Shared Use 8 vCPU 32 GB 128 GB" 'CPC_S_8C_32GB_256GB' = "Windows 365 Shared Use 8 vCPU 32 GB 256 GB" 'CPC_S_8C_32GB_512GB' = "Windows 365 Shared Use 8 vCPU 32 GB 512 GB" 'CPC_SS_2' = "Windows 365 Business 2 vCPU, 8 GB, 128 GB" 'CRM_AUTO_ROUTING_ADDON' = "Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization" 'CRM_AUTO_ROUTING_ENGINE_ADDON' = "Field Service � Automated Routing Engine Add-On" 'CRM_HYBRIDCONNECTOR' = "Dynamics 365 Hybrid Connector" 'CRM_ONLINE_PORTAL' = "Dynamics 365 Enterprise Edition - Additional Portal (Qualified Offer)" 'CRMINSTANCE' = "Dynamics 365 - Additional Production Instance (Qualified Offer)" 'CRMPLAN2' = "Microsoft Dynamics CRM Online Basic" 'CRMSTANDARD' = "Microsoft Dynamics CRM Online" 'CRMSTORAGE' = "Dynamics 365 - Additional Database Storage (Qualified Offer)" 'CRMTESTINSTANCE' = "Dynamics 365 - Additional Non-Production Instance (Qualified Offer)" 'CUSTOMER_KEY' = "Microsoft Customer Key" 'CUSTOMER_VOICE_ADDON' = "Dynamics Customer Voice Add-On" 'Customer_Voice_Base' = "Dynamics 365 Customer Voice Base Plan" 'Customer_Voice_Customer_Insights' = "Microsoft Dynamics 365 Customer Voice for Customer Insights App" 'CUSTOMER_VOICE_DYN365_VIRAL_TRIAL' = "Customer Voice for Dynamics 365 vTrial" 'D365_AssetforSCM' = "Asset Maintenance Add-in" 'D365_CSI_EMBED_CE' = "Dynamics 365 Customer Service Insights for CE Plan" 'D365_CSI_EMBED_CSEnterprise' = "Dynamics 365 Customer Service Insights for CS Enterprise" 'D365_CUSTOMER_SERVICE_ENT_ATTACH' = "Dynamics 365 for Customer Service Enterprise Attach to Qualifying Dynamics 365 Base Offer A" 'D365_FIELD_SERVICE_ATTACH' = "Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer" 'D365_Finance' = "Microsoft Dynamics 365 for Finance" 'D365_IOTFORSCM' = "Iot Intelligence Add-in for D365 Supply Chain Management" 'D365_IOTFORSCM_ADDITIONAL' = "IoT Intelligence Add-in Additional Machines" 'D365_MARKETING_USER' = "Dynamics 365 for Marketing USL" 'D365_ProjectOperations' = "Dynamics 365 Project Operations" 'D365_ProjectOperationsCDS' = "Dynamics 365 Project Operations CDS" 'D365_SALES_ENT_ATTACH' = "Dynamics 365 Sales Enterprise Attach to Qualifying Dynamics 365 Base Offer" 'D365_SALES_PRO' = "Dynamics 365 For Sales Professional" 'D365_SALES_PRO_ATTACH' = "Dynamics 365 Sales Professional Attach to Qualifying Dynamics 365 Base Offer" 'D365_SALES_PRO_IW' = "Dynamics 365 For Sales Professional Trial" 'D365_SALES_PRO_IW_Trial' = "Dynamics 365 for Sales Professional Trial" 'D365_SCM' = "DYNAMICS 365 FOR SUPPLY CHAIN MANAGEMENT" 'DATA_INVESTIGATIONS' = "Microsoft Data Investigations" 'DATAVERSE_FOR_POWERAUTOMATE_DESKTOP' = "Dataverse for PAD" 'DATAVERSE_POWERAPPS_PER_APP_NEW' = "Dataverse for Power Apps per app" 'DDYN365_CDS_DYN_P2' = "COMMON DATA SERVICE" 'DEFENDER_ENDPOINT_P1' = "Microsoft Defender for Endpoint P1" 'DEFENDER_ENDPOINT_P1_EDU' = "Microsoft Defender for Endpoint P1 for EDU" 'Defender_Threat_Intelligence' = "Defender Threat Intelligence" 'Deskless' = "Microsoft StaffHub" 'DESKLESSPACK' = "Office 365 F3" 'DEVELOPERPACK' = "Office 365 E3 Developer" 'DEVELOPERPACK_E5' = "Microsoft 365 E5 Developer (without Windows and Audio Conferencing)" 'DYN365_ ENTERPRISE _RELATIONSHIP_SALES' = "Microsoft Relationship Sales solution" 'DYN365_AI_SERVICE_INSIGHTS' = "Dynamics 365 Customer Service Insights Trial" 'DYN365_ASSETMANAGEMENT' = "Dynamics 365 Asset Management Addl Assets" 'DYN365_BUSCENTRAL_ADD_ENV_ADDON' = "Dynamics 365 Business Central Additional Environment Addon" 'DYN365_BUSCENTRAL_DB_CAPACITY' = "Dynamics 365 Business Central Database Capacity" 'DYN365_BUSCENTRAL_ENVIRONMENT' = "Dynamics 365 Business Central Additional Environment Addon" 'DYN365_BUSCENTRAL_ESSENTIAL' = "Dynamics 365 Business Central Essentials" 'DYN365_BUSCENTRAL_PREMIUM' = "Dynamics 365 Business Central Premium" 'DYN365_BUSCENTRAL_TEAM_MEMBER' = "Dynamics 365 Business Central Team Members" 'DYN365_BUSINESS_MARKETING' = "Dynamics 365 for Marketing Business Edition" 'DYN365_CDS_CCI_BOTS' = "Common Data Service for CCI Bots" 'DYN365_CDS_DEV_VIRAL' = "Common Data Service - DEV VIRAL" 'DYN365_CDS_DYN_APPS' = "Common Data Service" 'DYN365_CDS_FINANCE' = "Common Data Service for Dynamics 365 Finance" 'DYN365_CDS_FOR_PROJECT_P1' = "COMMON DATA SERVICE FOR PROJECT P1" 'DYN365_CDS_FORMS_PRO' = "Common Data Service" 'DYN365_CDS_GUIDES' = "Common Data Service" 'DYN365_CDS_O365_F1' = "Common Data Service" 'DYN365_CDS_O365_F1_GCC' = "Common Data Service - O365 F1" 'DYN365_CDS_O365_P1' = "Common Data Service - O365 P1" 'DYN365_CDS_O365_P1_GCC' = "Common Data Service - O365 P1 GCC" 'DYN365_CDS_O365_P2' = "Common Data Service" 'DYN365_CDS_O365_P2_GCC' = "COMMON DATA SERVICE - O365 P2 GCC" 'DYN365_CDS_O365_P3' = "Common Data Service" 'DYN365_CDS_O365_P3_GCC' = "Common Data Service" 'DYN365_CDS_P1_GOV' = "Common Data Service for Government" 'DYN365_CDS_P2' = "Common Data Service - P2" 'DYN365_CDS_P2_GOV' = "Common Data Service for Government" 'DYN365_CDS_PROJECT' = "Common Data Service for Project" 'DYN365_CDS_SUPPLYCHAINMANAGEMENT' = "COMMON DATA SERVICE FOR DYNAMICS 365 SUPPLY CHAIN MANAGEMENT" 'DYN365_CDS_VIRAL' = "Common Data Service" 'DYN365_CS_CHAT' = "Dynamics 365 for Customer Service Chat" 'DYN365_CS_CHAT_FPA' = "Dynamics 365 Customer Service Chat Application Integration" 'DYN365_CS_ENTERPRISE_VIRAL_TRIAL' = "Dynamics 365 Customer Service Enterprise vTrial" 'DYN365_CS_MESSAGING_TPS' = "Dynamics 365 Customer Service Digital Messaging add-on" 'DYN365_CS_MESSAGING_VIRAL_TRIAL' = "Dynamics 365 Customer Service Digital Messaging vTrial" 'DYN365_CS_VOICE' = "Dynamics 365 for Customer Service Voice Add-in" 'DYN365_CS_VOICE_VIRAL_TRIAL' = "Dynamics 365 Customer Service Voice vTrial" 'DYN365_CUSTOMER_INSIGHTS_ATTACH' = "Dynamics 365 Customer Insights Attach" 'DYN365_CUSTOMER_INSIGHTS_BASE' = "Dynamics 365 Customer Insights Standalone" 'DYN365_CUSTOMER_INSIGHTS_ENGAGEMENT_INSIGHTS_BASE' = "Dynamics 365 Customer Insights Engagement Insights" 'DYN365_CUSTOMER_INSIGHTS_ENGAGEMENT_INSIGHTS_BASE_TRIAL' = "Dynamics 365 Customer Insights Engagement Insights Viral" 'DYN365_CUSTOMER_INSIGHTS_VIRAL' = "Dynamics 365 Customer Insights vTrial" 'DYN365_CUSTOMER_SERVICE_PRO' = "Dynamics 365 Customer Service Professional" 'DYN365_CUSTOMER_VOICE_ADDON' = "Dynamics 365 Customer Voice Additional Responses" 'DYN365_CUSTOMER_VOICE_BASE' = "Dynamics 365 Customer Voice" 'DYN365_ENTERPRISE_CASE_MANAGEMENT' = "Dynamics 365 for Case Management Enterprise Edition" 'DYN365_ENTERPRISE_CUSTOMER_SERVICE' = "Dynamics 365 for Customer Service Enterprise Edition" 'DYN365_ENTERPRISE_FIELD_SERVICE' = "Dynamics 365 for Field Service Enterprise Edition" 'DYN365_ENTERPRISE_P1' = "Dynamics 365 P1" 'DYN365_ENTERPRISE_P1_IW' = "Dynamics 365 P1 Tria for Information Workers" 'DYN365_ENTERPRISE_PLAN1' = "Dynamics 365 Customer Engagement Plan" 'DYN365_ENTERPRISE_SALES' = "Dynamics 365 for Sales Enterprise Edition" 'DYN365_ENTERPRISE_SALES_CUSTOMERSERVICE' = "Dynamics 365 for Sales and Customer Service Enterprise Edition" 'DYN365_Enterprise_Talent_Attract_TeamMember' = "DYNAMICS 365 FOR TALENT - ATTRACT EXPERIENCE TEAM MEMBER" 'DYN365_Enterprise_Talent_Onboard_TeamMember' = "DYNAMICS 365 FOR TALENT - ONBOARD EXPERIENCE" 'DYN365_ENTERPRISE_TEAM_MEMBERS' = "Dynamics 365 for Team Members Enterprise Edition" 'DYN365_FINANCE' = "Dynamics 365 Finance" 'DYN365_FINANCIALS_ACCOUNTANT' = "Dynamics 365 Business Central External Accountant" 'DYN365_FINANCIALS_ACCOUNTANT_SKU' = "Dynamics 365 Business Central External Accountant" 'DYN365_FINANCIALS_BUSINESS' = "Dynamics 365 for Business Central Essentials" 'DYN365_FINANCIALS_BUSINESS_SKU' = "Dynamics 365 for Financials Business Edition" 'DYN365_FINANCIALS_TEAM_MEMBERS' = "Dynamics 365 for Team Members" 'DYN365_FS_ENTERPRISE_VIRAL_TRIAL' = "Dynamics 365 Field Service Enterprise vTrial" 'DYN365_IOT_INTELLIGENCE_ADDL_MACHINES' = "Sensor Data Intelligence Additional Machines Add-in for Dynamics 365 Supply Chain Management" 'DYN365_IOT_INTELLIGENCE_SCENARIO' = "Sensor Data Intelligence Scenario Add-in for Dynamics 365 Supply Chain Management" 'DYN365_MARKETING_50K_CONTACT_ADDON' = "Dynamics 365 for Marketing 50K Addnl Contacts" 'DYN365_MARKETING_APP' = "Dynamics 365 for Marketing" 'DYN365_MARKETING_APP_ATTACH' = "Dynamics 365 for Marketing Attach" 'DYN365_MARKETING_APPLICATION_ADDON' = "Dynamics 365 for Marketing Additional Application" 'DYN365_MARKETING_CONTACT_ADDON_T3' = "Dynamics 365 for Marketing Addnl Contacts Tier 3" 'DYN365_MARKETING_CONTACT_ADDON_T5' = "Dynamics 365 for Marketing Addnl Contacts Tier 5" 'DYN365_MARKETING_MSE_USER' = "Dynamics 365 for Marketing MSE User" 'DYN365_MARKETING_SANDBOX_APPLICATION_ADDON' = "Dynamics 365 for Marketing Additional Non-Prod Application" 'DYN365_MARKETING_USER' = "Dynamics 365 for Marketing USL" 'DYN365_REGULATORY_SERVICE' = "Dynamics 365 Regulatory Service - Enterprise Edition Trial" 'DYN365_RETAIL_DEVICE' = "Dynamics 365 for Retail Device" 'DYN365_RETAIL_TRIAL' = "Dynamics 365 Commerce Trial" 'DYN365_SALES_ENTERPRISE_VIRAL_TRIAL' = "Dynamics 365 Sales Enterprise vTrial" 'DYN365_SALES_INSIGHTS' = "Dynamics 365 AI for Sales (Embedded)" 'DYN365_SALES_INSIGHTS_VIRAL_TRIAL' = "Dynamics 365 Sales Insights vTrial" 'DYN365_SALES_PREMIUM' = "Dynamics 365 Sales Premium" 'DYN365_SALES_PRO' = "Dynamics 365 for Sales Professional" 'DYN365_SCM' = "Dynamics 365 for Supply Chain Management" 'DYN365_TALENT_ENTERPRISE' = "DYNAMICS 365 FOR TALENT" 'DYN365_TEAM_MEMBERS' = "Dynamics 365 Team Members" 'DYN365BC_MS_INVOICING' = "Microsoft Invoicing" 'Dynamics_365_Customer_Service_Enterprise_admin_trial' = "Dynamics 365 Customer Service Enterprise Admin" 'Dynamics_365_Customer_Service_Enterprise_viral_trial' = "Dynamics 365 Customer Service Enterprise Viral Trial" 'Dynamics_365_Field_Service_Enterprise_viral_trial' = "Dynamics 365 Field Service Viral Trial" 'Dynamics_365_for_HCM_Trial' = "Dynamics 365 for HCM Trial" 'Dynamics_365_for_Operations' = "Dynamics 365 UNF OPS Plan ENT Edition" 'Dynamics_365_for_Operations_Devices' = "Dynamics 365 Operations - Device" 'Dynamics_365_for_Operations_Sandbox_Tier2' = "Dynamics 365 for Operations non-production multi-box instance for standard acceptance testing (Tier 2)" 'Dynamics_365_for_Operations_Sandbox_Tier2_SKU' = "Dynamics 365 Operations - Sandbox Tier 2:Standard Acceptance Testing" 'Dynamics_365_for_Operations_Sandbox_Tier4' = "Dynamics 365 for Operations Enterprise Edition - Sandbox Tier 4:Standard Performance Testing" 'Dynamics_365_for_Operations_Sandbox_Tier4_SKU' = "Dynamics 365 Operations - Sandbox Tier 4:Standard Performance Testing" 'DYNAMICS_365_FOR_OPERATIONS_TEAM_MEMBERS' = "DYNAMICS 365 FOR OPERATIONS TEAM MEMBERS" 'Dynamics_365_for_OperationsDevices' = "Dynamics 365 for Operations Devices" 'Dynamics_365_for_Retail' = "DYNAMICS 365 FOR RETAIL" 'Dynamics_365_for_Retail_Team_members' = "DYNAMICS 365 FOR RETAIL TEAM MEMBERS" 'Dynamics_365_for_Talent_Team_members' = "DYNAMICS 365 FOR TALENT TEAM MEMBERS" 'Dynamics_365_Hiring_Free_PLAN' = "Dynamics 365 for Talent: Attract" 'Dynamics_365_Hiring_SKU' = "Dynamics 365 Talent: Attract" 'Dynamics_365_Onboarding_Free_PLAN' = "Dynamics 365 for Talent: Onboard" 'DYNAMICS_365_ONBOARDING_SKU' = "Dynamics 365 Talent: Onboard" 'Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox' = "Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox" 'Dynamics_365_Sales_Premium_Viral_Trial' = "Dynamics 365 Sales Premium Viral Trial" 'Dynamics_365_Talent_Onboard' = "DYNAMICS 365 FOR TALENT: ONBOARD" 'DYNB365_CSI_VIRAL_TRIAL' = "Dynamics 365 Customer Service Insights vTrial" 'E3_VDA_only' = "Windows 10/11 Enterprise E3 VDA" 'EducationAnalyticsP1' = "Education Analytics" 'EMS' = "Enterprise Mobility + Security E3" 'EMS_EDU_FACULTY' = "Enterprise Mobility + Security A3 for Faculty" 'EMS_GOV' = "Enterprise Mobility + Security G3 GCC" 'EMSPREMIUM' = "Enterprise Mobility + Security E5" 'EMSPREMIUM_GOV' = "Enterprise Mobility + Security G5 GCC" 'ENTERPRISEPACK' = "Office 365 E3" 'ENTERPRISEPACK_GOV' = "Office 365 G3 GCC" 'ENTERPRISEPACK_USGOV_DOD' = "Office 365 E3_USGOV_DOD" 'ENTERPRISEPACK_USGOV_GCCHIGH' = "Office 365 E3_USGOV_GCCHIGH" 'ENTERPRISEPACKPLUS_FACULTY' = "Office 365 A3 for faculty" 'ENTERPRISEPACKPLUS_STUDENT' = "Office 365 A3 for students" 'ENTERPRISEPREMIUM' = "Office 365 E5" 'ENTERPRISEPREMIUM_FACULTY' = "Office 365 A5 for faculty" 'ENTERPRISEPREMIUM_GOV' = "Office 365 G5 GCC" 'ENTERPRISEPREMIUM_NOPSTNCONF' = "Office 365 E5 Without Audio Conferencing" 'ENTERPRISEPREMIUM_STUDENT' = "Office 365 A5 for students" 'ENTERPRISEWITHSCAL' = "Office 365 E4" 'EOP_ENTERPRISE' = "Exchange Online Protection" 'EOP_ENTERPRISE_PREMIUM' = "Exchange Enterprise CAL Services (EOP DLP)" 'EQUIVIO_ANALYTICS' = "Office 365 Advanced Compliance" 'EQUIVIO_ANALYTICS_GOV' = "Office 365 Advanced Compliance for GCC" 'ERP_TRIAL_INSTANCE' = "Dynamics 365 Operations Trial Environment" 'EXCEL_PREMIUM' = "Microsoft Excel Advanced Analytics" 'EXCHANGE_ANALYTICS' = "Microsoft MyAnalytics (Full)" 'EXCHANGE_ANALYTICS_GOV' = "Microsoft MyAnalytics for Government (Full)" 'EXCHANGE_B_STANDARD' = "EXCHANGE ONLINE POP" 'EXCHANGE_FOUNDATION_GOV' = "EXCHANGE FOUNDATION FOR GOVERNMENT" 'EXCHANGE_L_STANDARD' = "EXCHANGE ONLINE (P1)" 'EXCHANGE_S_ARCHIVE' = "EXCHANGE ONLINE ARCHIVING FOR EXCHANGE SERVER" 'EXCHANGE_S_ARCHIVE_ADDON' = "EXCHANGE ONLINE ARCHIVING FOR EXCHANGE ONLINE" 'EXCHANGE_S_DESKLESS' = "EXCHANGE ONLINE KIOSK" 'EXCHANGE_S_DESKLESS_GOV' = "Exchange Online (Kiosk) for Government" 'EXCHANGE_S_ENTERPRISE' = "EXCHANGE ONLINE (PLAN 2)" 'EXCHANGE_S_ENTERPRISE_GOV' = "Exchange Online (Plan 2) for Government" 'EXCHANGE_S_ESSENTIALS' = "Exchange Online Essentials" 'EXCHANGE_S_FOUNDATION' = "Exchange Foundation" 'EXCHANGE_S_FOUNDATION_GOV' = "Exchange Foundation for Government" 'EXCHANGE_S_STANDARD' = "Exchange Online (Plan 1)" 'EXCHANGE_S_STANDARD_GOV' = "Exchange Online (Plan 1) for Government" 'EXCHANGE_S_STANDARD_MIDMARKET' = "EXCHANGE ONLINE PLAN" 'EXCHANGEARCHIVE' = "Exchange Online Archiving for Exchange Server" 'EXCHANGEARCHIVE_ADDON' = "Exchange Online Archiving for Exchange Online" 'EXCHANGEDESKLESS' = "Exchange Online Kiosk" 'EXCHANGEENTERPRISE' = "Exchange Online (Plan 2)" 'EXCHANGEENTERPRISE_FACULTY' = "Exchange Online (Plan 2) for Faculty" 'EXCHANGEESSENTIALS' = "Exchange Online Essentials (ExO P1 Based)" 'EXCHANGEONLINE_MULTIGEO' = "Exchange Online Multi-Geo" 'EXCHANGESTANDARD' = "Exchange Online (Plan 1)" 'EXCHANGESTANDARD_ALUMNI' = "Exchange Online (Plan 1) for Alumni with Yammer" 'EXCHANGESTANDARD_GOV' = "Exchange Online (Plan 1) for GCC" 'EXCHANGESTANDARD_STUDENT' = "Exchange Online (Plan 1) for Students" 'EXCHANGETELCO' = "Exchange Online POP" 'EXPERTS_ON_DEMAND' = "Microsoft Threat Experts - Experts on Demand" 'FLOW_BUSINESS_PROCESS' = "Power Automate per flow plan" 'FLOW_CCI_BOTS' = "Flow for CCI Bots" 'FLOW_CUSTOMER_SERVICE_PRO' = "Power Automate for Customer Service Pro" 'FLOW_DEV_VIRAL' = "Flow for Developer" 'FLOW_DYN_APPS' = "Flow for Dynamics 365" 'FLOW_DYN_P2' = "Flow for Dynamics 365" 'FLOW_DYN_TEAM' = "Power Automate for Dynamics 365" 'FLOW_FOR_PROJECT' = "Flow for Project" 'FLOW_FORMS_PRO' = "Power Automate for Dynamics 365 Customer Voice" 'FLOW_FREE' = "Microsoft Power Automate Free" 'FLOW_O365_P1' = "FLOW FOR OFFICE 365" 'FLOW_O365_P1_GOV' = "Power Automate for Office 365 for Government" 'FLOW_O365_P2' = "Power Automate for Office 365" 'FLOW_O365_P2_GOV' = "POWER AUTOMATE FOR OFFICE 365 FOR GOVERNMENT" 'FLOW_O365_P3' = "Power Automate for Office 365" 'FLOW_O365_P3_GOV' = "Power Automate for Office 365 for Government" 'FLOW_O365_S1' = "Power Automate for Office 365 F3" 'FLOW_O365_S1_GOV' = "Power Automate for Office 365 F3 for Government" 'FLOW_P1_GOV' = "Power Automate (Plan 1) for Government" 'FLOW_P2' = "Microsoft Power Automate Plan 2" 'FLOW_P2_VIRAL' = "Flow Free" 'FLOW_P2_VIRAL_REAL' = "Flow P2 Viral" 'Flow_Per_APP' = "Power Automate for Power Apps per App Plan" 'Flow_Per_APP_IWTRIAL' = "Flow per app baseline access" 'FLOW_PER_USER' = "Power Automate per user plan" 'FLOW_PER_USER_DEPT' = "Power Automate per user plan dept" 'FLOW_PER_USER_GCC' = "Power Automate per user plan for Government" 'Flow_PowerApps_PerUser' = "Power Automate for Power Apps per User Plan" 'Flow_PowerApps_PerUser_GCC' = "Power Automate for Power Apps per User Plan for GCC" 'FLOW_VIRTUAL_AGENT_BASE' = "Power Automate for Virtual Agent" 'FLOW_VIRTUAL_AGENT_USL' = "Power Automate for Virtual Agent" 'FORMS_GOV_E1' = "Forms for Government (Plan E1)" 'FORMS_GOV_E3' = "FORMS FOR GOVERNMENT (PLAN E3)" 'FORMS_GOV_E5' = "Microsoft Forms for Government (Plan E5)" 'FORMS_GOV_F1' = "Forms for Government (Plan F1)" 'FORMS_PLAN_E1' = "MICROSOFT FORMS (PLAN E1)" 'FORMS_PLAN_E3' = "Microsoft Forms (Plan E3)" 'FORMS_PLAN_E5' = "Microsoft Forms (Plan E5)" 'FORMS_PLAN_K' = "Microsoft Forms (Plan F1)" 'FORMS_PRO' = "Dynamics 365 Customer Voice Trial" 'Forms_Pro_AddOn' = "Dynamics 365 Customer Voice Additional Responses" 'Forms_Pro_CE' = "Microsoft Dynamics 365 Customer Voice for Customer Engagement Plan" 'Forms_Pro_Customer_Insights' = "Microsoft Dynamics 365 Customer Voice for Customer Insights" 'Forms_Pro_FS' = "Microsoft Dynamics 365 Customer Voice for Field Service" 'Forms_Pro_Marketing' = "Microsoft Dynamics 365 Customer Voice for Marketing" 'Forms_Pro_Marketing_App' = "Microsoft Dynamics 365 Customer Voice for Marketing Application" 'Forms_Pro_Relationship_Sales' = "Microsoft Dynamics 365 Customer Voice for Relationship Sales" 'Forms_Pro_SalesEnt' = "Microsoft Dynamics 365 Customer Voice for Sales Enterprise" 'Forms_Pro_Service' = "Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise" 'Forms_Pro_USL' = "Dynamics 365 Customer Voice USL" 'GRAPH_CONNECTORS_SEARCH_INDEX' = "Graph Connectors Search with Index" 'GRAPH_CONNECTORS_SEARCH_INDEX_TOPICEXP' = "Graph Connectors Search with Index (Microsoft Viva Topics)" 'GUIDES' = "Dynamics 365 Guides" 'GUIDES_USER' = "Dynamics 365 Guides" 'IDENTITY_THREAT_PROTECTION' = "Microsoft 365 E5 Security" 'IDENTITY_THREAT_PROTECTION_FOR_EMS_E5' = "Microsoft 365 E5 Security for EMS E5" 'INFO_GOVERNANCE' = "Microsoft Information Governance" 'INFORMATION_BARRIERS' = "Information Barriers" 'INFORMATION_PROTECTION_COMPLIANCE' = "Microsoft 365 E5 Compliance" 'INSIDER_RISK' = "Microsoft Insider Risk Management" 'INSIDER_RISK_MANAGEMENT' = "Microsoft Insider Risk Management" 'Intelligent_Content_Services' = "SharePoint Syntex" 'Intelligent_Content_Services_SPO_type' = "SharePoint Syntex - SPO type" 'INTUNE_A' = "Intune" 'INTUNE_A_D' = "Microsoft Intune Device" 'INTUNE_A_D_GOV' = "Microsoft Intune Device for Government" 'Intune_AdvancedEA' = "Intune Advanced endpoint analytics" 'Intune_Defender' = "MDE_SecurityManagement" 'INTUNE_EDU' = "Intune for Education" 'INTUNE_O365' = "Mobile Device Management for Office 365" 'INTUNE_P2' = "Intune Plan 2" 'INTUNE_SMB' = "Microsoft Intune SMB" 'INTUNE_SMBIZ' = "Microsoft Intune" 'Intune-EPM' = "Intune Endpoint Privilege Management" 'Intune-MAMTunnel' = "Microsoft Tunnel for Mobile Application Management" 'IT_ACADEMY_AD' = "Microsoft Imagine Academy" 'KAIZALA_O365_P1' = "Microsoft Kaizala Pro" 'KAIZALA_O365_P2' = "Microsoft Kaizala Pro" 'KAIZALA_O365_P3' = "Microsoft Kaizala Pro" 'KAIZALA_STANDALONE' = "Microsoft Kaizala Pro" 'LITEPACK' = "Office 365 Small Business" 'LITEPACK_P2' = "Office 365 Small Business Premium" 'LOCKBOX_ENTERPRISE' = "Customer Lockbox" 'LOCKBOX_ENTERPRISE_GOV' = "Customer Lockbox for Government" 'M365_A5_SUITE_COMPONENTS_FACULTY' = "Microsoft 365 A5 Suite features for faculty" 'M365_ADVANCED_AUDITING' = "Microsoft 365 Advanced Auditing" 'M365_AUDIT_PLATFORM' = "Microsoft 365 Audit Platform" 'M365_E5_SUITE_COMPONENTS' = "Microsoft 365 E5 Suite features" 'M365_F1' = "Microsoft 365 F1" 'M365_F1_COMM' = "Microsoft 365 F1" 'M365_F1_GOV' = "Microsoft 365 F3 GCC" 'M365_G3_GOV' = "Microsoft 365 G3 GCC" 'M365_G5_GCC' = "Microsoft 365 GCC G5" 'M365_LIGHTHOUSE_CUSTOMER_PLAN1' = "Microsoft 365 Lighthouse (Plan 1)" 'M365_LIGHTHOUSE_PARTNER_PLAN1' = "Microsoft 365 Lighthouse (Plan 2)" 'M365_SECURITY_COMPLIANCE_FOR_FLW' = "Microsoft 365 Security and Compliance for Firstline Workers" 'M365EDU_A1' = "Microsoft 365 A1" 'M365EDU_A3_FACULTY' = "Microsoft 365 A3 for Faculty" 'M365EDU_A3_STUDENT' = "Microsoft 365 A3 for Students" 'M365EDU_A3_STUUSEBNFT' = "Microsoft 365 A3 for students use benefit" 'M365EDU_A3_STUUSEBNFT_RPA1' = "Microsoft 365 A3 - Unattended License for students use benefit" 'M365EDU_A5_FACULTY' = "Microsoft 365 A5 for Faculty" 'M365EDU_A5_NOPSTNCONF_STUUSEBNFT' = "Microsoft 365 A5 without Audio Conferencing for students use benefit" 'M365EDU_A5_STUDENT' = "Microsoft 365 A5 for Students" 'M365EDU_A5_STUUSEBNFT' = "Microsoft 365 A5 for students use benefit" 'MCO_TEAMS_IW' = "MICROSOFT TEAMS" 'MCO_VIRTUAL_APPT' = "Microsoft Teams Premium Virtual Appointments" 'MCOCAP' = "Microsoft Teams Shared Devices" 'MCOCAP_GOV' = "Microsoft Teams Shared Devices for GCC" 'MCOEV' = "Microsoft Teams Phone Standard" 'MCOEV_DOD' = "Microsoft Teams Phone Standard for DOD" 'MCOEV_FACULTY' = "Microsoft Teams Phone Standard for Faculty" 'MCOEV_GCCHIGH' = "Microsoft Teams Phone Standard for GCCHIGH" 'MCOEV_GOV' = "Microsoft Teams Phone Standard for GCC" 'MCOEV_STUDENT' = "Microsoft Teams Phone Standard for Students" 'MCOEV_TELSTRA' = "Microsoft Teams Phone Standard for TELSTRA" 'MCOEV_USGOV_DOD' = "Microsoft Teams Phone Standard_USGOV_DOD" 'MCOEV_USGOV_GCCHIGH' = "Microsoft Teams Phone Standard_USGOV_GCCHIGH" 'MCOEV_VIRTUALUSER' = "Microsoft 365 Phone Standard Resource Account" 'MCOEV_VIRTUALUSER_GOV' = "Microsoft 365 Phone Standard Resource Account for Government" 'MCOEVSMB' = "SKYPE FOR BUSINESS CLOUD PBX FOR SMALL AND MEDIUM BUSINESS" 'MCOEVSMB_1' = "Microsoft Teams Phone Standard for Small and Medium Business" 'MCOFREE' = "MCO FREE FOR MICROSOFT TEAMS (FREE)" 'MCOIMP' = "Skype for Business Online (Plan 1)" 'MCOIMP_GOV' = "Skype for Business Online (Plan 1) for Government" 'MCOLITE' = "SKYPE FOR BUSINESS ONLINE (PLAN P1)" 'MCOMEETACPEA' = "Microsoft 365 Audio Conferencing Pay-Per-Minute - EA" 'MCOMEETADV' = "Microsoft 365 Audio Conferencing" 'MCOMEETADV_GOV' = "Microsoft 365 Audio Conferencing for GCC" 'MCOMEETBASIC' = "Microsoft Teams Audio Conferencing with dial-out to select geographies" 'MCOPSTN_1_GOV' = "Microsoft 365 Domestic Calling Plan for GCC" 'MCOPSTN_5' = "Microsoft 365 Domestic Calling Plan (120 Minutes)" 'MCOPSTN1' = "Skype for Business PSTN Domestic Calling" 'MCOPSTN1_GOV' = "Domestic Calling for Government" 'MCOPSTN2' = "Skype for Business PSTN Domestic and International Calling" 'MCOPSTN3' = "MCOPSTN3" 'MCOPSTN5' = "Skype for Business PSTN Domestic Calling (120 Minutes)" 'MCOPSTN8' = "Microsoft 365 Domestic Calling Plan (120 min) at User Level" 'MCOPSTNC' = "Communications Credits" 'MCOPSTNEAU' = "AUSTRALIA CALLING PLAN" 'MCOPSTNEAU2' = "TELSTRA Calling for O365" 'MCOPSTNPP' = "Skype for Business PSTN Usage Calling Plan" 'MCOSTANDARD' = "Skype for Business Online (Plan 2)" 'MCOSTANDARD_GOV' = "Skype for Business Online (Plan 2) for Government" 'MCOSTANDARD_MIDMARKET' = "SKYPE FOR BUSINESS ONLINE (PLAN 2) FOR MIDSIZ" 'MCOTEAMS_ESSENTIALS' = "Teams Phone with Calling Plan" 'MCOVOICECONF' = "SKYPE FOR BUSINESS ONLINE (PLAN 3)" 'MCS_BizApps_Cloud_for_Sustainability_vTrial' = "MCS - BizApps_Cloud for Sustainability_vTrial" 'MDATP_Server' = "Microsoft Defender for Endpoint Server" 'MDATP_XPLAT' = "Microsoft Defender for Endpoint P2_XPLAT" 'MDE_LITE' = "Microsoft Defender for Endpoint Plan 1" 'MDE_SMB' = "Microsoft Defender for Business" 'MDM_SALES_COLLABORATION' = "MICROSOFT DYNAMICS MARKETING SALES COLLABORATION - ELIGIBILITY CRITERIA APPLY" 'MEE_FACULTY' = "Minecraft Education Faculty" 'MEE_STUDENT' = "Minecraft Education Student" 'MEETING_ROOM' = "Microsoft Teams Rooms Standard" 'MEETING_ROOM_NOAUDIOCONF' = "Microsoft Teams Rooms Standard without Audio Conferencing" 'MFA_PREMIUM' = "MICROSOFT AZURE MULTI-FACTOR AUTHENTICATION" 'MFA_STANDALONE' = "Microsoft Azure Multi-Factor Authentication" 'Microsoft 365 A3 Suite features for faculty' = "Microsoft 365 A3 Suite features for faculty" 'Microsoft_365_E3' = "Microsoft 365 E3 (500 seats min)_HUB" 'Microsoft_365_E3_Extra_Features' = "Microsoft 365 E3 Extra Features" 'Microsoft_365_E5' = "Microsoft 365 E5 (500 seats min)_HUB" 'Microsoft_365_E5_without_Audio_Conferencing' = "Microsoft 365 E5 without Audio Conferencing (500 seats min)_HUB" 'MICROSOFT_APPLICATION_PROTECTION_AND_GOVERNANCE_A' = "Microsoft Application Protection and Governance (A)" 'MICROSOFT_APPLICATION_PROTECTION_AND_GOVERNANCE_D' = "Microsoft Application Protection and Governance (D)" 'MICROSOFT_BUSINESS_CENTER' = "Microsoft Business Center" 'Microsoft_Cloud_App_Security_App_Governance_Add_On' = "App governance add-on to Microsoft Defender for Cloud Apps" 'Microsoft_Cloud_for_Sustainability_vTrial' = "Microsoft Cloud for Sustainability vTrial" 'MICROSOFT_COMMUNICATION_COMPLIANCE' = "Microsoft 365 Communication Compliance" 'MICROSOFT_ECDN' = "Microsoft eCDN" 'Microsoft_Intune_Suite' = "Microsoft Intune Suite" 'MICROSOFT_REMOTE_ASSIST' = "Dynamics 365 Remote Assist" 'MICROSOFT_REMOTE_ASSIST_HOLOLENS' = "Dynamics 365 Remote Assist HoloLens" 'MICROSOFT_SEARCH' = "Microsoft Search" 'Microsoft_Teams_Audio_Conferencing_select_dial_out' = "Microsoft Teams Audio Conferencing with dial-out to USA/CAN" 'Microsoft_Teams_Premium' = "Microsoft Teams Premium Introductory Pricing" 'Microsoft_Teams_Rooms_Basic' = "Microsoft Teams Rooms Basic" 'Microsoft_Teams_Rooms_Basic_FAC' = "Microsoft Teams Rooms Basic for EDU" 'Microsoft_Teams_Rooms_Basic_without_Audio_Conferencing' = "Microsoft Teams Rooms Basic without Audio Conferencing" 'Microsoft_Teams_Rooms_Pro' = "Microsoft Teams Rooms Pro" 'Microsoft_Teams_Rooms_Pro_FAC' = "Microsoft Teams Rooms Pro for EDU" 'Microsoft_Teams_Rooms_Pro_without_Audio_Conferencing' = "Microsoft Teams Rooms Pro without Audio Conferencing" 'Microsoft_Viva_Goals' = "Microsoft Viva Goals" 'Microsoft_Viva_Sales_PowerAutomate' = "Microsoft Viva Sales Premium with Power Automate" 'Microsoft_Viva_Sales_PremiumTrial' = "Microsoft Viva Sales Premium & Trial" 'Microsoft365_Lighthouse' = "Microsoft 365 Lighthouse" 'MICROSOFTBOOKINGS' = "Microsoft Bookings" 'MICROSOFTENDPOINTDLP' = "Microsoft Endpoint DLP" 'MICROSOFTSTREAM' = "MICROSOFT STREAM" 'MIDSIZEPACK' = "Office 365 Midsize Business" 'MINECRAFT_EDUCATION_EDITION' = "Minecraft Education Edition" 'MIP_S_CLP1' = "Information Protection for Office 365 - Standard" 'MIP_S_CLP2' = "Information Protection for Office 365 - Premium" 'MIP_S_Exchange' = "Data Classification in Microsoft 365" 'MIP_S_EXCHANGE_CO' = "Data Classification in Microsoft 365 - Company Level" 'ML_CLASSIFICATION' = "Microsoft ML-Based Classification" 'MMR_P1' = "Meeting Room Managed Services" 'MS_TEAMS_IW' = "Microsoft Teams Trial" 'MTP' = "Microsoft 365 Defender" 'MTR_PREM' = "Teams Rooms Premium" 'MTRProManagement' = "Microsoft Teams Rooms Pro Management" 'MYANALYTICS_P2' = "Insights by MyAnalytics" 'MYANALYTICS_P2_GOV' = "INSIGHTS BY MYANALYTICS FOR GOVERNMENT" 'NBENTERPRISE' = "Microsoft Social Engagement Enterprise" 'NBPROFESSIONALFORCRM' = "MICROSOFT SOCIAL ENGAGEMENT PROFESSIONAL - ELIGIBILITY CRITERIA APPLY" 'NONPROFIT_PORTAL' = "Nonprofit Portal" 'Nucleus' = "Nucleus" 'O365_BUSINESS' = "Microsoft 365 Apps for Business" 'O365_BUSINESS_ESSENTIALS' = "Microsoft 365 Business Basic" 'O365_BUSINESS_PREMIUM' = "Microsoft 365 Business Standard" 'O365_SB_Relationship_Management' = "OUTLOOK CUSTOMER MANAGER" 'OFFICE_BUSINESS' = "OFFICE 365 BUSINESS" 'OFFICE_FORMS_PLAN_2' = "Microsoft Forms (Plan 2)" 'OFFICE_FORMS_PLAN_3' = "Microsoft Forms (Plan 3)" 'OFFICE_PRO_PLUS_SUBSCRIPTION_SMBIZ' = "OFFICE 365 SMALL BUSINESS SUBSCRIPTION" 'OFFICE_PROPLUS_DEVICE' = "Microsoft 365 Apps for Enterprise (Device)" 'OFFICE_PROPLUS_DEVICE1' = "Microsoft 365 Apps for enterprise (device)" 'OFFICE_SHARED_COMPUTER_ACTIVATION' = "Office Shared Computer Activation" 'OFFICE365_MULTIGEO' = "Multi-Geo Capabilities in Office 365" 'OFFICEMOBILE_SUBSCRIPTION' = "OFFICEMOBILE_SUBSCRIPTION" 'OFFICEMOBILE_SUBSCRIPTION_GOV' = "Office Mobile Apps for Office 365 for GCC" 'OFFICESUBSCRIPTION' = "Microsoft 365 Apps for Enterprise" 'OFFICESUBSCRIPTION_FACULTY' = "Microsoft 365 Apps for Faculty" 'OFFICESUBSCRIPTION_GOV' = "Microsoft 365 Apps for enterprise G" 'OFFICESUBSCRIPTION_STUDENT' = "Microsoft 365 Apps for Students" 'OFFICESUBSCRIPTION_unattended' = "Microsoft 365 Apps for Enterprise (Unattended)" 'ONEDRIVE_BASIC' = "OneDrive for business Basic" 'ONEDRIVE_BASIC_GOV' = "ONEDRIVE FOR BUSINESS BASIC FOR GOVERNMENT" 'ONEDRIVE_BASIC_P2' = "OneDrive for Business (Basic 2)" 'ONEDRIVEENTERPRISE' = "ONEDRIVEENTERPRISE" 'ONEDRIVESTANDARD' = "ONEDRIVESTANDARD" 'PAM_ENTERPRISE' = "Office 365 Privileged Access Management" 'PBI_PREMIUM_P1_ADDON' = "Power BI Premium P1" 'PBI_PREMIUM_PER_USER' = "Power BI Premium Per User" 'PBI_PREMIUM_PER_USER_ADDON' = "Power BI Premium Per User Add-On" 'PBI_PREMIUM_PER_USER_DEPT' = "Power BI Premium Per User Dept" 'PBI_PREMIUM_PER_USER_FACULTY' = "Power BI Premium Per User for Faculty" 'PHONESYSTEM_VIRTUALUSER' = "Microsoft Teams Phone Resource Account" 'PHONESYSTEM_VIRTUALUSER_GOV' = "Microsoft Teams Phone Resource Account for GCC" 'POWER_APPS_DYN365_VIRAL_TRIAL' = "Power Apps for Dynamics 365 vTrial" 'POWER_AUTOMATE_ATTENDED_RPA' = "Power Automate RPA Attended" 'POWER_AUTOMATE_DYN365_VIRAL_TRIAL' = "Power Automate for Dynamics 365 vTrial" 'Power_Automate_For_Project_P1' = "POWER AUTOMATE FOR PROJECT P1" 'POWER_AUTOMATE_UNATTENDED_RPA' = "Power Automate Unattended RPA add-on" 'POWER_BI_ADDON' = "Power BI for Office 365 Add-On" 'POWER_BI_INDIVIDUAL_USER' = "Power BI" 'POWER_BI_PRO' = "Power BI Pro" 'POWER_BI_PRO_CE' = "Power BI Pro CE" 'POWER_BI_PRO_DEPT' = "Power BI Pro Dept" 'POWER_BI_PRO_FACULTY' = "Power BI Pro for Faculty" 'POWER_BI_STANDARD' = "Power BI (free)" 'POWER_BI_STANDARD_FACULTY' = "Microsoft Fabric (Free) for faculty" 'POWER_BI_STANDARD_STUDENT' = "Microsoft Fabric (Free) for student" 'Power_Pages_Internal_User' = "Power Pages Internal User" 'POWER_PAGES_VTRIAL' = "Power Pages vTrial for Makers" 'Power_Pages_vTrial_for_Makers' = "Power Pages vTrial for Makers" 'POWER_VIRTUAL_AGENTS_D365_CS_CHAT' = "Power Virtual Agents for Chat" 'POWER_VIRTUAL_AGENTS_D365_CS_MESSAGING' = "Power Virtual Agents for Digital Messaging" 'POWER_VIRTUAL_AGENTS_D365_CS_VOICE' = "Power Virtual Agents for Customer Service Voice" 'POWER_VIRTUAL_AGENTS_O365_F1' = "Power Virtual Agents for Office 365" 'POWER_VIRTUAL_AGENTS_O365_P1' = "POWER VIRTUAL AGENTS FOR OFFICE 365 P1" 'POWER_VIRTUAL_AGENTS_O365_P2' = "Power Virtual Agents for Office 365" 'POWER_VIRTUAL_AGENTS_O365_P3' = "Power Virtual Agents for Office 365" 'POWERAPPS_CUSTOMER_SERVICE_PRO' = "Power Apps for Customer Service Pro" 'POWERAPPS_DEV' = "Microsoft Power Apps for Developer" 'POWERAPPS_DEV_VIRAL' = "PowerApps for Developer" 'POWERAPPS_DYN_APPS' = "PowerApps for Dynamics 365" 'POWERAPPS_DYN_P2' = "Power Apps for Dynamics 365" 'POWERAPPS_DYN_TEAM' = "Power Apps for Dynamics 365" 'POWERAPPS_GUIDES' = "Power Apps for Guides" 'POWERAPPS_INDIVIDUAL_USER' = "Power Apps and Logic Flows" 'POWERAPPS_O365_P1' = "POWERAPPS FOR OFFICE 365" 'POWERAPPS_O365_P1_GOV' = "Power Apps for Office 365 for Government" 'POWERAPPS_O365_P2' = "Power Apps for Office 365" 'POWERAPPS_O365_P2_GOV' = "POWER APPS FOR OFFICE 365 FOR GOVERNMENT" 'POWERAPPS_O365_P3' = "Power Apps for Office 365 (Plan 3)" 'POWERAPPS_O365_P3_GOV' = "Power Apps for Office 365 for Government" 'POWERAPPS_O365_S1' = "Power Apps for Office 365 F3" 'POWERAPPS_O365_S1_GOV' = "Power Apps for Office 365 F3 for Government" 'POWERAPPS_P1_GOV' = "PowerApps Plan 1 for Government" 'POWERAPPS_P2' = "Power Apps (Plan 2)" 'POWERAPPS_P2_VIRAL' = "PowerApps Trial" 'POWERAPPS_PER_APP' = "Power Apps per app plan" 'POWERAPPS_PER_APP_IW' = "PowerApps per app baseline access" 'POWERAPPS_PER_APP_IWTRIAL' = "PowerApps per app baseline access" 'POWERAPPS_PER_APP_NEW' = "Power Apps per app plan (1 app or portal)" 'POWERAPPS_PER_USER' = "Power Apps per user plan" 'POWERAPPS_PER_USER_GCC' = "Power Apps per user plan for Government" 'POWERAPPS_PORTALS_LOGIN' = "Power Apps Portals Login Capacity Add-On" 'POWERAPPS_PORTALS_LOGIN_GCC' = "Power Apps Portals Login Capacity Add-On for Government" 'POWERAPPS_PORTALS_LOGIN_T2' = "Power Apps Portals login capacity add-on Tier 2 (10 unit min)" 'POWERAPPS_PORTALS_LOGIN_T2_GCC' = "Power Apps Portals login capacity add-on Tier 2 (10 unit min) for Government" 'POWERAPPS_PORTALS_LOGIN_T3' = "Power Apps Portals login capacity add-on Tier 3 (50 unit min)" 'POWERAPPS_PORTALS_PAGEVIEW' = "Power Apps Portals page view capacity add-on" 'POWERAPPS_PORTALS_PAGEVIEW_GCC' = "Power Apps Portals page view capacity add-on for Government" 'POWERAPPS_SALES_PRO' = "Power Apps for Sales Pro" 'POWERAPPS_VIRAL' = "Microsoft Power Apps Plan 2 Trial" 'POWERAPPSFREE' = "MICROSOFT POWERAPPS" 'POWERAUTOMATE_ATTENDED_RPA' = "Power Automate per user with attended RPA plan" 'POWERAUTOMATE_DESKTOP_FOR_WIN' = "PAD for Windows" 'POWERAUTOMATE_UNATTENDED_RPA' = "Power Automate unattended RPA add-on" 'POWERBI_PRO_GOV' = "Power BI Pro for GCC" 'POWERFLOW_P2' = "Microsoft Power Apps Plan 2 (Qualified Offer)" 'POWERFLOWSFREE' = "LOGIC FLOWS" 'POWERVIDEOSFREE' = "MICROSOFT POWER VIDEOS BASIC" 'PREMIUM_ENCRYPTION' = "Premium Encryption in Office 365" 'PRIVACY_MANAGEMENT_RISK' = "Privacy Management � risk" 'PRIVACY_MANAGEMENT_RISK_EDU' = "Privacy Management - risk for EDU" 'PRIVACY_MANAGEMENT_RISK_GCC' = "Privacy Management - risk GCC" 'PRIVACY_MANAGEMENT_RISK_USGOV_DOD' = "Privacy Management - risk_USGOV_DOD" 'PRIVACY_MANAGEMENT_RISK_USGOV_GCCHIGH' = "Privacy Management - risk_USGOV_GCCHIGH" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_EDU_V2' = "Privacy Management - subject rights request (1) for EDU" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2' = "Privacy Management - subject rights request (1)" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2_GCC' = "Privacy Management - subject rights request (1) GCC" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2_USGOV_DOD' = "Privacy Management - subject rights request (1) USGOV_DOD" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2_USGOV_GCCHIGH' = "Privacy Management - subject rights request (1) USGOV_GCCHIGH" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_EDU_V2' = "Privacy Management - subject rights request (10) for EDU" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2' = "Privacy Management - subject rights request (10)" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2_GCC' = "Privacy Management - subject rights request (10) GCC" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2_USGOV_DOD' = "Privacy Management - subject rights request (10) USGOV_DOD" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2_USGOV_GCCHIGH' = "Privacy Management - subject rights request (10) USGOV_GCCHIGH" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_EDU_V2' = "Privacy Management - subject rights request (100) for EDU" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2' = "Privacy Management - subject rights request (100)" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2_GCC' = "Privacy Management - subject rights request (100) GCC" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2_USGOV_DOD' = "Privacy Management - subject rights request (100) USGOV_DOD" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2_USGOV_GCCHIGH' = "Privacy Management - subject rights request (100) USGOV_GCCHIGH" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_50' = "Privacy Management - subject rights request (50)" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_50_EDU_V2' = "Privacy Management - subject rights request (50) for EDU" 'PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_50_V2' = "Privacy Management - subject rights request (50)" 'PRIVACY_MANGEMENT_DSR' = "Privacy Management - Subject Rights Request" 'PRIVACY_MANGEMENT_DSR_1' = "Privacy Management - Subject Rights Request (1 - Exchange)" 'PRIVACY_MANGEMENT_DSR_10' = "Privacy Management - Subject Rights Request (10)" 'PRIVACY_MANGEMENT_DSR_100' = "Privacy Management - Subject Rights Request (100)" 'PRIVACY_MANGEMENT_DSR_EXCHANGE' = "Privacy Management - Subject Rights Request (Exchange)" 'PRIVACY_MANGEMENT_DSR_EXCHANGE_1' = "Privacy Management - Subject Rights Request (1)" 'PRIVACY_MANGEMENT_DSR_EXCHANGE_10' = "Privacy Management - Subject Rights Request (10 - Exchange)" 'PRIVACY_MANGEMENT_DSR_EXCHANGE_100' = "Privacy Management - Subject Rights Request (100 - Exchange)" 'PRIVACY_MANGEMENT_RISK' = "Priva - Risk" 'PRIVACY_MANGEMENT_RISK_EXCHANGE' = "Priva - Risk (Exchange)" 'PROJECT_CLIENT_SUBSCRIPTION' = "Project Online Desktop Client" 'PROJECT_CLIENT_SUBSCRIPTION_GOV' = "Project Online Desktop Client for Government" 'PROJECT_ESSENTIALS' = "Project Online Essentials" 'PROJECT_ESSENTIALS_GOV' = "Project Online Essentials for Government" 'PROJECT_FOR_PROJECT_OPERATIONS' = "Project for Project Operations" 'PROJECT_MADEIRA_PREVIEW_IW' = "Dynamics 365 Business Central for IWs" 'PROJECT_MADEIRA_PREVIEW_IW_SKU' = "Dynamics 365 Business Central for IWs" 'PROJECT_O365_F3' = "Project for Office (Plan F)" 'PROJECT_O365_P1' = "Project for Office (Plan E1)" 'PROJECT_O365_P2' = "Project for Office (Plan E3)" 'PROJECT_O365_P3' = "Project for Office (Plan E5)" 'PROJECT_P1' = "Project Plan 1" 'PROJECT_PLAN1_DEPT' = "Project Plan 1 (for Department)" 'PROJECT_PLAN3_DEPT' = "Project Plan 3 (for Department)" 'PROJECT_PROFESSIONAL' = "Project P3" 'PROJECT_PROFESSIONAL_FACULTY' = "Project P3 for Faculty" 'PROJECTCLIENT' = "Project for Office 365" 'PROJECTESSENTIALS' = "Project Online Essentials" 'PROJECTESSENTIALS_FACULTY' = "Project Online Essentials for Faculty" 'PROJECTESSENTIALS_GOV' = "Project Online Essentials for GCC" 'PROJECTONLINE_PLAN_1' = "Project Online Premium Without Project Client" 'PROJECTONLINE_PLAN_1_FACULTY' = "Project Plan 5 without Project Client for Faculty" 'PROJECTONLINE_PLAN_2' = "Project Online With Project for Office 365" 'PROJECTPREMIUM' = "Project Online Premium" 'PROJECTPREMIUM_GOV' = "Project Plan 5 for GCC" 'PROJECTPROFESSIONAL' = "Project Plan 3" 'PROJECTPROFESSIONAL_FACULTY' = "Project Plan 3 for Faculty" 'PROJECTPROFESSIONAL_GOV' = "Project Plan 3 for GCC" 'PROJECTWORKMANAGEMENT' = "Microsoft Planner" 'PROJECTWORKMANAGEMENT_GOV' = "Office 365 Planner for Government" 'RECORDS_MANAGEMENT' = "Microsoft Records Management" 'REMOTE_HELP' = "Remote help" 'RIGHTSMANAGEMENT' = "Azure Information Protection Plan 1" 'RIGHTSMANAGEMENT_ADHOC' = "Rights Management Adhoc" 'RMS_S_ADHOC' = "Rights Management Adhoc" 'RMS_S_BASIC' = "Microsoft Azure Rights Management Service" 'RMS_S_ENTERPRISE' = "AZURE INFORMATION PROTECTION PREMIUM P1" 'RMS_S_ENTERPRISE)' = "Microsoft Azure Active Directory Rights" 'RMS_S_ENTERPRISE_GOV' = "Azure Rights Management" 'RMS_S_PREMIUM' = "MICROSOFT AZURE ACTIVE DIRECTORY RIGHTS" 'RMS_S_PREMIUM_GOV' = "Azure Information Protection Premium P1 for GCC" 'RMS_S_PREMIUM2' = "AZURE INFORMATION PROTECTION PREMIUM P2" 'RMS_S_PREMIUM2_GOV' = "Azure Information Protection Premium P2 for GCC" 'RMSBASIC' = "Rights Management Service Basic Content Protection" 'SAFEDOCS' = "Office 365 SafeDocs" 'SCHOOL_DATA_SYNC_P1' = "School Data Sync (Plan 1)" 'SCHOOL_DATA_SYNC_P2' = "School Data Sync (Plan 2)" 'SharePoint Plan 1G' = "SharePoint Plan 1G" 'SHAREPOINT_PROJECT' = "Project Online Service" 'SHAREPOINT_PROJECT_EDU' = "Project Online Service for Education" 'SHAREPOINT_PROJECT_GOV' = "Project Online Service for Government" 'SHAREPOINT_S_DEVELOPER' = "SHAREPOINT FOR DEVELOPER" 'SHAREPOINTDESKLESS' = "SharePoint Online Kiosk" 'SHAREPOINTDESKLESS_GOV' = "SharePoint KioskG" 'SHAREPOINTENTERPRISE' = "SharePoint Online (Plan 2)" 'SHAREPOINTENTERPRISE_EDU' = "SharePoint (Plan 2) for Education" 'SHAREPOINTENTERPRISE_GOV' = "SharePoint Plan 2G" 'SHAREPOINTENTERPRISE_MIDMARKET' = "SHAREPOINT PLAN 1" 'SHAREPOINTLITE' = "SHAREPOINTLITE" 'SHAREPOINTONLINE_MULTIGEO' = "SharePoint Multi-Geo" 'SHAREPOINTSTANDARD' = "SharePoint Online (Plan 1)" 'SHAREPOINTSTANDARD_EDU' = "SharePoint (Plan 1) for Education" 'SHAREPOINTSTORAGE' = "Office 365 Extra File Storage" 'SHAREPOINTSTORAGE_GOV' = "Office 365 Extra File Storage for GCC" 'SHAREPOINTWAC' = "Office for the web" 'SHAREPOINTWAC_DEVELOPER' = "OFFICE ONLINE FOR DEVELOPER" 'SHAREPOINTWAC_EDU' = "Office for the Web for Education" 'SHAREPOINTWAC_GOV' = "Office for the Web for Government" 'SKU_Dynamics_365_for_HCM_Trial' = "Dynamics 365 for Talent" 'SMB_APPS' = "Business Apps (free)" 'SMB_BUSINESS' = "Microsoft 365 Apps for Business" 'SMB_BUSINESS_ESSENTIALS' = "Microsoft 365 Business Basic" 'SMB_BUSINESS_PREMIUM' = "Microsoft 365 Business Standard - Prepaid Legacy" 'SOCIAL_ENGAGEMENT_APP_USER' = "Dynamics 365 AI for Market Insights (Preview)" 'SPB' = "Microsoft 365 Business Premium" 'SPE_E3' = "Microsoft 365 E3" 'SPE_E3_RPA1' = "Microsoft 365 E3 - Unattended License" 'SPE_E3_USGOV_DOD' = "Microsoft 365 E3_USGOV_DOD" 'SPE_E3_USGOV_GCCHIGH' = "Microsoft 365 E3_USGOV_GCCHIGH" 'SPE_E5' = "Microsoft 365 E5" 'SPE_E5_CALLINGMINUTES' = "Microsoft 365 E5 with Calling Minutes" 'SPE_E5_NOPSTNCONF' = "Microsoft 365 E5 without Audio Conferencing" 'SPE_F1' = "Microsoft 365 F3" 'SPE_F5_COMP' = "Microsoft 365 F5 Compliance Add-on" 'SPE_F5_COMP_AR_D_USGOV_DOD' = "Microsoft 365 F5 Compliance Add-on AR (DOD)_USGOV_DOD" 'SPE_F5_COMP_AR_USGOV_GCCHIGH' = "Microsoft 365 F5 Compliance Add-on AR_USGOV_GCCHIGH" 'SPE_F5_COMP_GCC' = "Microsoft 365 F5 Compliance Add-on GCC" 'SPE_F5_SEC' = "Microsoft 365 F5 Security Add-on" 'SPE_F5_SECCOMP' = "Microsoft 365 F5 Security + Compliance Add-on" 'SPZA' = "APP CONNECT" 'SPZA_IW' = "App Connect IW" 'SQL_IS_SSIM' = "Microsoft Power BI Information Services Plan 1" 'STANDARDPACK' = "Office 365 E1" 'STANDARDPACK_GOV' = "Office 365 G1 GCC" 'STANDARDWOFFPACK' = "Office 365 E2" 'STANDARDWOFFPACK_FACULTY' = "Office 365 A1 for faculty" 'STANDARDWOFFPACK_IW_FACULTY' = "Office 365 A1 Plus for faculty" 'STANDARDWOFFPACK_IW_STUDENT' = "Office 365 A1 Plus for students" 'STANDARDWOFFPACK_STUDENT' = "Office 365 A1 for students" 'STREAM' = "Microsoft Stream" 'STREAM_O365_E1' = "Microsoft Stream for Office 365 E1" 'STREAM_O365_E1_GOV' = "Microsoft Stream for O365 for Government (E1)" 'STREAM_O365_E3' = "Microsoft Stream for Office 365 E3" 'STREAM_O365_E3_GOV' = "MICROSOFT STREAM FOR O365 FOR GOVERNMENT (E3)" 'STREAM_O365_E5' = "Microsoft Stream for Office 365 E5" 'STREAM_O365_E5_GOV' = "Stream for Office 365 for Government (E5)" 'STREAM_O365_K' = "Microsoft Stream for O365 K SKU" 'STREAM_O365_K_GOV' = "Microsoft Stream for O365 for Government (F1)" 'STREAM_O365_SMB' = "Stream for Office 365" 'STREAM_P2' = "Microsoft Stream Plan 2" 'STREAM_STORAGE' = "Microsoft Stream Storage Add-On (500 GB)" 'SWAY' = "Sway" 'TEAMS_ADVCOMMS' = "Microsoft 365 Advanced Communications" 'TEAMS_AR_DOD' = "Microsoft Teams for DOD (AR)" 'TEAMS_AR_GCCHIGH' = "Microsoft Teams for GCCHigh (AR)" 'TEAMS_COMMERCIAL_TRIAL' = "Microsoft Teams Commercial Cloud" 'Teams_Ess' = "Microsoft Teams Essentials" 'TEAMS_ESSENTIALS_AAD' = "Microsoft Teams Essentials (AAD Identity)" 'TEAMS_EXPLORATORY' = "Microsoft Teams Exploratory" 'TEAMS_FREE' = "Microsoft Teams (Free)" 'TEAMS_FREE_SERVICE' = "TEAMS FREE SERVICE" 'TEAMS_GOV' = "Microsoft Teams for Government" 'Teams_Room_Basic' = "Teams Room Basic" 'Teams_Room_Pro' = "Teams Room Pro" 'Teams_Room_Standard' = "Teams Room Standard" 'TEAMS1' = "Microsoft Teams" 'TeamsEss' = "Microsoft Teams Essentials" 'TEAMSMULTIGEO' = "Teams Multi-Geo" 'TEAMSPRO_CUST' = "Microsoft Teams Premium Personalized" 'TEAMSPRO_MGMT' = "Microsoft Teams Premium Intelligent" 'TEAMSPRO_PROTECTION' = "Microsoft Teams Premium Secure" 'TEAMSPRO_VIRTUALAPPT' = "Microsoft Teams Premium Virtual Appointment" 'TEAMSPRO_WEBINAR' = "Microsoft Teams Premium Webinar" 'THREAT_INTELLIGENCE' = "Microsoft Defender for Office 365 (Plan 2)" 'THREAT_INTELLIGENCE_APP' = "Defender Threat Intelligence" 'THREAT_INTELLIGENCE_GOV' = "Microsoft Defender for Office 365 (Plan 2) GCC" 'TOPIC_EXPERIENCES' = "Viva Topics" 'TVM_PREMIUM_1' = "Microsoft Defender Vulnerability Management" 'TVM_Premium_Add_on' = "Microsoft Defender Vulnerability Management Add-on" 'TVM_Premium_Standalone' = "Microsoft Defender Vulnerability Management" 'UNIVERSAL_PRINT' = "Universal Print" 'UNIVERSAL_PRINT_01' = "Universal Print" 'UNIVERSAL_PRINT_NO_SEEDING' = "Universal Print Without Seeding" 'VIRTUAL_AGENT_BASE' = "Power Virtual Agent" 'VIRTUAL_AGENT_USL' = "Power Virtual Agent User License" 'Virtualization Rights for Windows 10 (E3/E5+VDA)' = "Windows 10 Enterprise (New)" 'Virtualization Rights for Windows 10' = "Windows 10/11 Enterprise" 'Virtualization Rights for Windows 10 (E3/E5+VDA)' = "Windows 10/11 Enterprise" 'VISIO_CLIENT_SUBSCRIPTION' = "Visio Desktop App" 'VISIO_CLIENT_SUBSCRIPTION_GOV' = "VISIO DESKTOP APP FOR Government" 'VISIO_PLAN1_DEPT' = "Visio Plan 1" 'VISIO_PLAN2_DEPT' = "Visio Plan 2" 'VISIOCLIENT' = "Visio Online Plan 2" 'VISIOCLIENT_FACULTY' = "Visio Plan 2 for Faculty" 'VISIOCLIENT_GOV' = "Visio Plan 2 for GCC" 'VISIOONLINE' = "Visio web app" 'VISIOONLINE_GOV' = "VISIO WEB APP FOR GOVERNMENT" 'VISIOONLINE_PLAN1' = "Visio Online Plan 1" 'VIVA' = "Microsoft Viva Suite" 'Viva_Goals_Premium' = "Viva Goals" 'VIVA_LEARNING_PREMIUM' = "Viva Learning" 'VIVA_LEARNING_SEEDED' = "Viva Learning Seeded" 'VIVAENGAGE_COMMUNITIES_AND_COMMUNICATIONS' = "Viva Engage Communities and Communications" 'VIVAENGAGE_CORE' = "Viva Engage Core" 'VIVAENGAGE_KNOWLEDGE' = "Viva Engage Knowledge" 'WACONEDRIVEENTERPRISE' = "OneDrive for Business (Plan 2)" 'WACONEDRIVESTANDARD' = "OneDrive for Business (Plan 1)" 'WHITEBOARD_FIRSTLINE1' = "Whiteboard (Firstline)" 'WHITEBOARD_PLAN1' = "Whiteboard (Plan 1)" 'WHITEBOARD_PLAN2' = "Whiteboard (Plan 2)" 'WHITEBOARD_PLAN3' = "Whiteboard (Plan 3)" 'WIN_DEF_ATP' = "Microsoft Defender for Endpoint" 'WIN_ENT_E5' = "Windows 10/11 Enterprise E5 (Original)" 'WIN10_ENT_A3_FAC' = "Windows 10/11 Enterprise A3 for faculty" 'WIN10_ENT_A3_STU' = "Windows 10/11 Enterprise A3 for students" 'WIN10_ENT_A5_FAC' = "Windows 10/11 Enterprise A5 for faculty" 'WIN10_ENT_LOC_F1' = "Windows 10 Enterprise E3 (Local Only)" 'WIN10_PRO_ENT_SUB' = "Windows 10/11 Enterprise E3" 'WIN10_VDA_E3' = "Windows 10/11 Enterprise E3" 'WIN10_VDA_E5' = "Windows 10/11 Enterprise E5" 'WINBIZ' = "Windows 10/11 Business" 'WINDEFATP' = "Microsoft Defender for Endpoint" 'Windows Autopatch' = "Windows Autopatch" 'Windows Store for Business EDU Store_faculty' = "Windows Store for Business EDU Store_faculty" 'Windows_365_S_2vCPU_4GB_128GB' = "Windows 365 Shared Use 2 vCPU 4 GB 128 GB" 'Windows_365_S_2vCPU_4GB_256GB' = "Windows 365 Shared Use 2 vCPU 4 GB 256 GB" 'Windows_365_S_2vCPU_4GB_64GB' = "Windows 365 Shared Use 2 vCPU 4 GB 64 GB" 'Windows_365_S_2vCPU_8GB_128GB' = "Windows 365 Shared Use 2 vCPU 8 GB 128 GB" 'Windows_365_S_2vCPU_8GB_256GB' = "Windows 365 Shared Use 2 vCPU 8 GB 256 GB" 'Windows_365_S_4vCPU_16GB_128GB' = "Windows 365 Shared Use 4 vCPU 16 GB 128 GB" 'Windows_365_S_4vCPU_16GB_256GB' = "Windows 365 Shared Use 4 vCPU 16 GB 256 GB" 'Windows_365_S_4vCPU_16GB_512GB' = "Windows 365 Shared Use 4 vCPU 16 GB 512 GB" 'Windows_365_S_8vCPU_32GB_128GB' = "Windows 365 Shared Use 8 vCPU 32 GB 128 GB" 'Windows_365_S_8vCPU_32GB_256GB' = "Windows 365 Shared Use 8 vCPU 32 GB 256 GB" 'Windows_365_S_8vCPU_32GB_512GB' = "Windows 365 Shared Use 8 vCPU 32 GB 512 GB" 'Windows_Autopatch' = "Windows Autopatch" 'WINDOWS_STORE' = "Windows Store for Business" 'WINDOWSUPDATEFORBUSINESS_DEPLOYMENTSERVICE' = "Windows Update for Business Deployment Service" 'WINE5_GCC_COMPAT' = "Windows 10/11 Enterprise E5 Commercial (GCC Compatible)" 'WORKPLACE_ANALYTICS' = "Microsoft Workplace Analytics" 'WORKPLACE_ANALYTICS_INSIGHTS_BACKEND' = "Microsoft Viva Insights Backend" 'WORKPLACE_ANALYTICS_INSIGHTS_USER' = "Microsoft Viva Insights" 'WSFB_EDU_FACULTY' = "Windows Store for Business EDU Faculty" 'YAMMER_EDU' = "Yammer for Academic" 'YAMMER_ENTERPRISE' = "YAMMER_ENTERPRISE" 'YAMMER_MIDSIZE' = "YAMMER MIDSIZE" } $SKUO365 = [ordered] @{ 'AAD_PREMIUM' = "AAD_PREMIUM" 'ADALLOM_S_DISCOVERY' = "ADALLOM_S_DISCOVERY" 'ADALLOM_S_O365' = "ADALLOM_S_O365" 'Advanced Communications' = "ADV_COMMS" 'AI Builder Capacity add-on' = "CDSAICAPACITY" 'AI Builder capacity Per App add-on' = "CDSAICAPACITY_PERAPP" 'AI Builder capacity Per User add-on' = "CDSAICAPACITY_PERUSER" 'APP CONNECT' = "SPZA" 'App Connect IW' = "SPZA_IW" 'App governance add-on to Microsoft Defender for Cloud Apps' = "Microsoft_Cloud_App_Security_App_Governance_Add_On" 'Asset Maintenance Add-in' = "D365_AssetforSCM" 'ATP_ENTERPRISE_GOV' = "ATP_ENTERPRISE_GOV" 'AUSTRALIA CALLING PLAN' = "MCOPSTNEAU" 'Azure Active Directory' = "AAD_SMB" 'Azure Active Directory Basic' = "AAD_BASIC" 'Azure Active Directory Basic for EDU' = "AAD_BASIC_EDU" 'Azure Active Directory Basic for Education' = "AAD_BASIC_EDU" 'Azure Active Directory for Education' = "AAD_EDU" 'Azure Active Directory Premium P1' = "AAD_PREMIUM" 'Azure Active Directory Premium P1 for Faculty' = "AAD_PREMIUM_FACULTY" 'Azure Active Directory Premium P2' = "AAD_PREMIUM_P2" 'Azure Active Directory Premium Plan 1' = "AAD_PREMIUM" 'Azure Information Protection Plan 1' = "RIGHTSMANAGEMENT" 'Azure Information Protection Premium P' = "RMS_S_PREMIUM" 'AZURE INFORMATION PROTECTION PREMIUM P1' = "RMS_S_ENTERPRISE" 'Azure Information Protection Premium P1 for GCC' = "RMS_S_PREMIUM_GOV" 'AZURE INFORMATION PROTECTION PREMIUM P2' = "RMS_S_PREMIUM2" 'Azure Information Protection Premium P2 for GCC' = "RMS_S_PREMIUM2_GOV" 'Azure Rights Management' = "RMS_S_ENTERPRISE" 'AZURE RIGHTS MANAGEMENT PREMIUM FOR GOVERNMENT' = "RMS_S_PREMIUM_GOV" 'BI_AZURE_P_2_GOV' = "BI_AZURE_P_2_GOV" 'BI_AZURE_P0' = "BI_AZURE_P0" 'BPOS_S_TODO_1' = "BPOS_S_TODO_1" 'BPOS_S_TODO_2' = "BPOS_S_TODO_2" 'BPOS_S_TODO_3' = "BPOS_S_TODO_3" 'Business Apps (free)' = "SMB_APPS" 'CDS Per app baseline access' = "CDS_PER_APP_IWTRIAL" 'CDS PowerApps per app plan' = "CDS_PER_APP" 'CDS PowerApps Portals page view capacity add-on' = "CDS_POWERAPPS_PORTALS_PAGEVIEW" 'CDS PowerApps Portals page view capacity add-on for GCC' = "CDS_POWERAPPS_PORTALS_PAGEVIEW_GCC" 'CDS_O365_P3_GCC' = "CDS_O365_P3_GCC" 'CLOUD APP SECURITY DISCOVERY' = "ADALLOM_S_DISCOVERY" 'Common Data Service' = "DYN365_CDS_FORMS_PRO" 'Common Data Service - DEV VIRAL' = "DYN365_CDS_DEV_VIRAL" 'Common Data Service - O365 F1' = "DYN365_CDS_O365_F1_GCC" 'Common Data Service - O365 P1' = "DYN365_CDS_O365_P1" 'Common Data Service - O365 P1 GCC' = "DYN365_CDS_O365_P1_GCC" 'Common Data Service - O365 P2' = "DYN365_CDS_O365_P2" 'COMMON DATA SERVICE - O365 P2 GCC' = "DYN365_CDS_O365_P2_GCC" 'Common Data Service - O365 P3' = "DYN365_CDS_O365_P3" 'Common Data Service - P2' = "DYN365_CDS_P2" 'Common Data Service - VIRAL' = "DYN365_CDS_VIRAL" 'Common Data Service Attended RPA' = "CDS_ATTENDED_RPA" 'Common Data Service Database Capacity' = "CDS_DB_CAPACITY" 'Common Data Service Database Capacity for Government' = "CDS_DB_CAPACITY_GOV" 'Common Data Service for Apps Database Capacity' = "CDS_DB_CAPACITY" 'Common Data Service for Apps Database Capacity for Government' = "CDS_DB_CAPACITY_GOV" 'Common Data Service for Apps File Capacity' = "CDS_FILE_CAPACITY" 'Common Data Service for Apps Log Capacity' = "CDS_LOG_CAPACITY" 'Common Data Service for CCI Bots' = "DYN365_CDS_CCI_BOTS" 'Common Data Service for Customer Insights' = "CDS_CUSTOMER_INSIGHTS" 'Common Data Service for Customer Insights Trial' = "CDS_CUSTOMER_INSIGHTS_TRIAL" 'Common Data Service for Dynamics 365 Finance' = "DYN365_CDS_FINANCE" 'COMMON DATA SERVICE FOR DYNAMICS 365 SUPPLY CHAIN MANAGEMENT' = "DYN365_CDS_SUPPLYCHAINMANAGEMENT" 'Common data service for Flow per business process plan' = "CDS_Flow_Business_Process" 'Common Data Service for Government' = "DYN365_CDS_P2_GOV" 'Common Data Service for Project' = "DYN365_CDS_PROJECT" 'COMMON DATA SERVICE FOR PROJECT P1' = "DYN365_CDS_FOR_PROJECT_P1" 'Common Data Service for Remote Assist' = "CDS_REMOTE_ASSIST" 'Common Data Service for SharePoint Syntex' = "CDS_O365_E5_KM" 'Common Data Service for Teams' = "CDS_O365_P2" 'Common Data Service for Teams_F1' = "CDS_O365_F1" 'Common Data Service for Teams_F1 GCC' = "CDS_O365_F1_GCC" 'COMMON DATA SERVICE FOR TEAMS_P1' = "CDS_O365_P1" 'Common Data Service for Teams_P1 GCC' = "CDS_O365_P1_GCC" 'Common Data Service for Teams_P2' = "CDS_O365_P2" 'COMMON DATA SERVICE FOR TEAMS_P2 GCC' = "CDS_O365_P2_GCC" 'Common Data Service for Teams_P3' = "CDS_O365_P3" 'Common Data Service for Virtual Agent Base' = "CDS_VIRTUAL_AGENT_BASE" 'Common Data Service Log Capacity' = "CDS_LOG_CAPACITY" 'Common Data Service Power Apps Portals Login Capacity' = "CDS_POWERAPPS_PORTALS_LOGIN" 'Common Data Service Power Apps Portals Login Capacity for GCC' = "CDS_POWERAPPS_PORTALS_LOGIN_GCC" 'Common Data Service Unattended RPA' = "CDS_UNATTENDED_RPA" 'Communications Credits' = "MCOPSTNC" 'COMMUNICATIONS_DLP' = "COMMUNICATIONS_DLP" 'Compliance Manager Premium Assessment Add-On' = "CMPA_addon" 'Compliance Manager Premium Assessment Add-On for GCC' = "CMPA_addon_GCC" 'Content_Explorer' = "Content_Explorer" 'ContentExplorer_Standard' = "ContentExplorer_Standard" 'CRM Hybrid Connector' = "CRM_HYBRIDCONNECTOR" 'Customer Lockbox' = "LOCKBOX_ENTERPRISE" 'Customer Lockbox for Government' = "LOCKBOX_ENTERPRISE_GOV" 'Customer Voice for Dynamics 365 vTrial' = "CUSTOMER_VOICE_DYN365_VIRAL_TRIAL" 'CUSTOMER_KEY' = "CUSTOMER_KEY" 'Data Classification in Microsoft 365' = "MIP_S_Exchange" 'Data Classification in Microsoft 365 - Company Level' = "MIP_S_EXCHANGE_CO" 'Data Loss Prevention' = "BPOS_S_DlpAddOn" 'Dataverse for Cust Insights�BASE' = "CDS_CUSTOMER_INSIGHTS_BASE" 'Dataverse for Customer Insights�BASE' = "CDS_CUSTOMER_INSIGHTS_BASE" 'Dataverse for PAD' = "DATAVERSE_FOR_POWERAUTOMATE_DESKTOP" 'Dataverse for Power Apps per app' = "DATAVERSE_POWERAPPS_PER_APP_NEW" 'Defender Threat Intelligence' = "Defender_Threat_Intelligence" 'DOMESTIC AND INTERNATIONAL CALLING PLAN' = "MCOPSTN2" 'Domestic Calling for Government' = "MCOPSTN1_GOV" 'DOMESTIC CALLING PLAN' = "MCOPSTN1" 'DYN365_CDS_O365_F1' = "DYN365_CDS_O365_F1" 'DYN365_CDS_O365_P3_GCC' = "DYN365_CDS_O365_P3_GCC" 'Dynamics 365 - Additional Database Storage (Qualified Offer)' = "CRMSTORAGE" 'Dynamics 365 - Additional Non-Production Instance (Qualified Offer)' = "CRMTESTINSTANCE" 'Dynamics 365 - Additional Production Instance (Qualified Offer)' = "CRMINSTANCE" 'Dynamics 365 AI for Customer Service Trial' = "DYN365_AI_SERVICE_INSIGHTS" 'Dynamics 365 AI for Customer Service Virtual Agents Viral' = "CCIBOTS_PRIVPREV_VIRAL" 'Dynamics 365 AI for Market Insights - Free' = "SOCIAL_ENGAGEMENT_APP_USER" 'Dynamics 365 AI for Market Insights (Preview)' = "SOCIAL_ENGAGEMENT_APP_USER" 'Dynamics 365 AI for Sales (Embedded)' = "DYN365_SALES_INSIGHTS" 'Dynamics 365 Asset Management Addl Assets' = "DYN365_ASSETMANAGEMENT" 'Dynamics 365 Business Central Additional Environment Addon' = "DYN365_BUSCENTRAL_ADD_ENV_ADDON" 'Dynamics 365 Business Central Database Capacity' = "DYN365_BUSCENTRAL_DB_CAPACITY" 'Dynamics 365 Business Central Essentials' = "DYN365_BUSCENTRAL_ESSENTIAL" 'Dynamics 365 Business Central External Accountant' = "DYN365_FINANCIALS_ACCOUNTANT_SKU" 'Dynamics 365 Business Central for IWs' = "PROJECT_MADEIRA_PREVIEW_IW_SKU" 'Dynamics 365 Business Central Premium' = "DYN365_BUSCENTRAL_PREMIUM" 'Dynamics 365 Business Central Team Members' = "DYN365_BUSCENTRAL_TEAM_MEMBER" 'Dynamics 365 Commerce Trial' = "DYN365_RETAIL_TRIAL" 'Dynamics 365 Customer Engagement Plan' = "DYN365_ENTERPRISE_PLAN1" 'Dynamics 365 Customer Insights' = "DYN365_CUSTOMER_INSIGHTS_BASE" 'Dynamics 365 Customer Insights Attach' = "DYN365_CUSTOMER_INSIGHTS_ATTACH" 'Dynamics 365 Customer Insights Engagement Insights' = "DYN365_CUSTOMER_INSIGHTS_ENGAGEMENT_INSIGHTS_BASE" 'Dynamics 365 Customer Insights Engagement Insights Viral' = "DYN365_CUSTOMER_INSIGHTS_ENGAGEMENT_INSIGHTS_BASE_TRIAL" 'Dynamics 365 Customer Insights Standalone' = "DYN365_CUSTOMER_INSIGHTS_BASE" 'Dynamics 365 Customer Insights Viral Plan' = "DYN365_CUSTOMER_INSIGHTS_VIRAL" 'Dynamics 365 Customer Insights vTrial' = "DYN365_CUSTOMER_INSIGHTS_VIRAL" 'Dynamics 365 Customer Service Chat Application Integration' = "DYN365_CS_CHAT_FPA" 'Dynamics 365 Customer Service Digital Messaging add-on' = "DYN365_CS_MESSAGING_TPS" 'Dynamics 365 Customer Service Digital Messaging vTrial' = "DYN365_CS_MESSAGING_VIRAL_TRIAL" 'Dynamics 365 Customer Service Enterprise Admin' = "Dynamics_365_Customer_Service_Enterprise_admin_trial" 'Dynamics 365 Customer Service Enterprise Viral Trial' = "Dynamics_365_Customer_Service_Enterprise_viral_trial" 'Dynamics 365 Customer Service Enterprise vTrial' = "DYN365_CS_ENTERPRISE_VIRAL_TRIAL" 'Dynamics 365 Customer Service Insights for CE Plan' = "D365_CSI_EMBED_CE" 'Dynamics 365 Customer Service Insights for CS Enterprise' = "D365_CSI_EMBED_CSEnterprise" 'Dynamics 365 Customer Service Insights Trial' = "DYN365_AI_SERVICE_INSIGHTS" 'Dynamics 365 Customer Service Insights vTrial' = "DYNB365_CSI_VIRAL_TRIAL" 'Dynamics 365 Customer Service Professional' = "DYN365_CUSTOMER_SERVICE_PRO" 'Dynamics 365 Customer Service Voice vTrial' = "DYN365_CS_VOICE_VIRAL_TRIAL" 'Dynamics 365 Customer Voice' = "DYN365_CUSTOMER_VOICE_BASE" 'Dynamics 365 Customer Voice Additional Responses' = "DYN365_CUSTOMER_VOICE_ADDON" 'Dynamics 365 Customer Voice Base Plan' = "Customer_Voice_Base" 'Dynamics 365 Customer Voice Trial' = "FORMS_PRO" 'Dynamics 365 Customer Voice USL' = "Forms_Pro_USL" 'Dynamics 365 Enterprise Edition - Additional Portal (Qualified Offer)' = "CRM_ONLINE_PORTAL" 'Dynamics 365 Field Service Enterprise vTrial' = "DYN365_FS_ENTERPRISE_VIRAL_TRIAL" 'Dynamics 365 Field Service Viral Trial' = "Dynamics_365_Field_Service_Enterprise_viral_trial" 'Dynamics 365 Field Service, Enterprise Edition - Resource Scheduling Optimization' = "CRM_AUTO_ROUTING_ADDON" 'Dynamics 365 Finance' = "DYN365_FINANCE" 'Dynamics 365 for Business Central Essentials' = "DYN365_FINANCIALS_BUSINESS" 'Dynamics 365 for Case Management' = "DYN365_ENTERPRISE_CASE_MANAGEMENT" 'Dynamics 365 for Case Management Enterprise Edition' = "DYN365_ENTERPRISE_CASE_MANAGEMENT" 'Dynamics 365 for Customer Service' = "DYN365_ENTERPRISE_CUSTOMER_SERVICE" 'Dynamics 365 for Customer Service Chat' = "DYN365_CS_CHAT" 'Dynamics 365 for Customer Service Enterprise Attach' = "D365_CUSTOMER_SERVICE_ENT_ATTACH" 'Dynamics 365 for Customer Service Enterprise Attach to Qualifying Dynamics 365 Base Offer A' = "D365_CUSTOMER_SERVICE_ENT_ATTACH" 'Dynamics 365 for Customer Service Enterprise Edition' = "DYN365_ENTERPRISE_CUSTOMER_SERVICE" 'Dynamics 365 for Customer Service Pro' = "DYN365_CUSTOMER_SERVICE_PRO" 'Dynamics 365 for Customer Service Voice Add-in' = "DYN365_CS_VOICE" 'Dynamics 365 for Field Service' = "DYN365_ENTERPRISE_FIELD_SERVICE" 'Dynamics 365 for Field Service Attach' = "D365_FIELD_SERVICE_ATTACH" 'Dynamics 365 for Field Service Attach to Qualifying Dynamics 365 Base Offer' = "D365_FIELD_SERVICE_ATTACH" 'Dynamics 365 for Field Service Enterprise Edition' = "DYN365_ENTERPRISE_FIELD_SERVICE" 'Dynamics 365 for Finance and Operations Enterprise edition - Regulatory Service' = "DYN365_REGULATORY_SERVICE" 'DYNAMICS 365 FOR FINANCIALS' = "POWERAPPS_DYN_APPS" 'Dynamics 365 for Financials Business Edition' = "DYN365_FINANCIALS_BUSINESS_SKU" 'Dynamics 365 for HCM Trial' = "Dynamics_365_for_HCM_Trial" 'Dynamics 365 for Marketing' = "DYN365_MARKETING_APP" 'Dynamics 365 for Marketing 50K Addnl Contacts' = "DYN365_MARKETING_50K_CONTACT_ADDON" 'Dynamics 365 for Marketing Additional Application' = "DYN365_MARKETING_APPLICATION_ADDON" 'Dynamics 365 for Marketing Additional Non-Prod Application' = "DYN365_MARKETING_SANDBOX_APPLICATION_ADDON" 'Dynamics 365 for Marketing Addnl Contacts Tier 3' = "DYN365_MARKETING_CONTACT_ADDON_T3" 'Dynamics 365 for Marketing Addnl Contacts Tier 5' = "DYN365_MARKETING_CONTACT_ADDON_T5" 'Dynamics 365 for Marketing Attach' = "DYN365_MARKETING_APP_ATTACH" 'Dynamics 365 for Marketing Business Edition' = "DYN365_BUSINESS_MARKETING" 'Dynamics 365 for Marketing MSE User' = "DYN365_MARKETING_MSE_USER" 'Dynamics 365 for Marketing USL' = "D365_MARKETING_USER" 'Dynamics 365 for Operations Devices' = "Dynamics_365_for_OperationsDevices" 'Dynamics 365 for Operations Enterprise Edition - Sandbox Tier 4:Standard Performance Testing' = "Dynamics_365_for_Operations_Sandbox_Tier4" 'Dynamics 365 for Operations non-production multi-box instance for standard acceptance testing (Tier 2)' = "Dynamics_365_for_Operations_Sandbox_Tier2" 'DYNAMICS 365 FOR OPERATIONS TEAM MEMBERS' = "DYNAMICS_365_FOR_OPERATIONS_TEAM_MEMBERS" 'DYNAMICS 365 FOR RETAIL' = "Dynamics_365_for_Retail" 'Dynamics 365 for Retail Device' = "DYN365_RETAIL_DEVICE" 'DYNAMICS 365 FOR RETAIL TEAM MEMBERS' = "Dynamics_365_for_Retail_Team_members" 'Dynamics 365 for Retail Trial' = "DYN365_RETAIL_TRIAL" 'DYNAMICS 365 FOR SALES' = "DYN365_ENTERPRISE_SALES" 'Dynamics 365 for Sales and Customer Service Enterprise Edition' = "DYN365_ENTERPRISE_SALES_CUSTOMERSERVICE" 'Dynamics 365 for Sales Enterprise Attach' = "D365_SALES_ENT_ATTACH" 'Dynamics 365 for Sales Enterprise Edition' = "DYN365_ENTERPRISE_SALES" 'Dynamics 365 for Sales Pro Attach' = "D365_SALES_PRO_ATTACH" 'Dynamics 365 For Sales Professional' = "D365_SALES_PRO" 'Dynamics 365 For Sales Professional Trial' = "D365_SALES_PRO_IW" 'Dynamics 365 for Supply Chain Management' = "DYN365_SCM" 'Dynamics 365 for Talent' = "SKU_Dynamics_365_for_HCM_Trial" 'DYNAMICS 365 FOR TALENT - ATTRACT EXPERIENCE TEAM MEMBER' = "DYN365_Enterprise_Talent_Attract_TeamMember" 'DYNAMICS 365 FOR TALENT - ONBOARD EXPERIENCE' = "DYN365_Enterprise_Talent_Onboard_TeamMember" 'DYNAMICS 365 FOR TALENT TEAM MEMBERS' = "Dynamics_365_for_Talent_Team_members" 'Dynamics 365 for Talent: Attract' = "Dynamics_365_Hiring_Free_PLAN" 'Dynamics 365 for Talent: Onboard' = "Dynamics_365_Onboarding_Free_PLAN" 'Dynamics 365 for Team Members' = "DYN365_FINANCIALS_TEAM_MEMBERS" 'Dynamics 365 for Team Members Enterprise Edition' = "DYN365_ENTERPRISE_TEAM_MEMBERS" 'DYNAMICS 365 FOR_OPERATIONS' = "Dynamics_365_for_Operations" 'Dynamics 365 Guides' = "GUIDES_USER" 'DYNAMICS 365 HIRING FREE PLAN' = "DYNAMICS_365_HIRING_FREE_PLAN" 'Dynamics 365 Hybrid Connector' = "CRM_HYBRIDCONNECTOR" 'Dynamics 365 Marketing' = "DYN365_BUSINESS_Marketing" 'Dynamics 365 Marketing Sandbox Application AddOn' = "DYN365_MARKETING_SANDBOX_APPLICATION_ADDON" 'Dynamics 365 Operations - Device' = "Dynamics_365_for_Operations_Devices" 'Dynamics 365 Operations - Sandbox Tier 2:Standard Acceptance Testing' = "Dynamics_365_for_Operations_Sandbox_Tier2_SKU" 'Dynamics 365 Operations - Sandbox Tier 4:Standard Performance Testing' = "Dynamics_365_for_Operations_Sandbox_Tier4_SKU" 'Dynamics 365 Operations Trial Environment' = "ERP_TRIAL_INSTANCE" 'Dynamics 365 P1' = "DYN365_ENTERPRISE_P1" 'Dynamics 365 P1 Tria for Information Workers' = "DYN365_ENTERPRISE_P1_IW" 'DYNAMICS 365 P1 TRIAL FOR INFORMATION WORKERS' = "DYN365_ENTERPRISE_P1_IW" 'Dynamics 365 Project Operations' = "D365_ProjectOperations" 'Dynamics 365 Project Operations CDS' = "D365_ProjectOperationsCDS" 'Dynamics 365 Regulatory Service - Enterprise Edition Trial' = "DYN365_REGULATORY_SERVICE" 'Dynamics 365 Remote Assist' = "MICROSOFT_REMOTE_ASSIST" 'Dynamics 365 Remote Assist HoloLens' = "MICROSOFT_REMOTE_ASSIST_HOLOLENS" 'Dynamics 365 Sales Enterprise Attach to Qualifying Dynamics 365 Base Offer' = "D365_SALES_ENT_ATTACH" 'Dynamics 365 Sales Enterprise vTrial' = "DYN365_SALES_ENTERPRISE_VIRAL_TRIAL" 'Dynamics 365 Sales Insights vTrial' = "DYN365_SALES_INSIGHTS_VIRAL_TRIAL" 'Dynamics 365 Sales Premium' = "DYN365_SALES_PREMIUM" 'Dynamics 365 Sales Premium Viral Trial' = "Dynamics_365_Sales_Premium_Viral_Trial" 'Dynamics 365 Sales Professional Attach to Qualifying Dynamics 365 Base Offer' = "D365_SALES_PRO_ATTACH" 'Dynamics 365 Sales, Field Service and Customer Service Partner Sandbox' = "Dynamics_365_Sales_Field_Service_and_Customer_Service_Partner_Sandbox" 'Dynamics 365 Talent: Attract' = "Dynamics_365_Hiring_SKU" 'Dynamics 365 Talent: Onboard' = "DYNAMICS_365_ONBOARDING_SKU" 'Dynamics 365 Team Members' = "DYN365_TEAM_MEMBERS" 'Dynamics 365 UNF OPS Plan ENT Edition' = "Dynamics_365_for_Operations" 'Dynamics Customer Voice Add-On' = "CUSTOMER_VOICE_ADDON" 'Education Analytics' = "EducationAnalyticsP1" 'Enterprise Mobility + Security A3 for Faculty' = "EMS_EDU_FACULTY" 'Enterprise Mobility + Security E3' = "EMS" 'Enterprise Mobility + Security E5' = "EMSPREMIUM" 'Enterprise Mobility + Security G3 GCC' = "EMS_GOV" 'Enterprise Mobility + Security G5 GCC' = "EMSPREMIUM_GOV" 'EQUIVIO_ANALYTICS_GOV' = "EQUIVIO_ANALYTICS_GOV" 'Exchange Enterprise CAL Services (EOP DLP)' = "EOP_ENTERPRISE_PREMIUM" 'EXCHANGE ESSENTIALS' = "EXCHANGE_S_ESSENTIALS" 'Exchange Foundation' = "EXCHANGE_S_FOUNDATION" 'Exchange Foundation for Government' = "EXCHANGE_S_FOUNDATION_GOV" 'Exchange Online (Kiosk) for Government' = "EXCHANGE_S_DESKLESS_GOV" 'EXCHANGE ONLINE (P1)' = "EXCHANGE_L_STANDARD" 'Exchange Online (Plan 1)' = "EXCHANGESTANDARD" 'Exchange Online (Plan 1) for Alumni with Yammer' = "EXCHANGESTANDARD_ALUMNI" 'Exchange Online (Plan 1) for GCC' = "EXCHANGESTANDARD_GOV" 'Exchange Online (Plan 1) for Government' = "EXCHANGE_S_STANDARD_GOV" 'Exchange Online (Plan 1) for Students' = "EXCHANGESTANDARD_STUDENT" 'Exchange Online (Plan 2)' = "EXCHANGEENTERPRISE" 'Exchange Online (Plan 2) for Faculty' = "EXCHANGEENTERPRISE_FACULTY" 'Exchange Online (Plan 2) for Government' = "EXCHANGE_S_ENTERPRISE_GOV" 'Exchange Online Archiving' = "EXCHANGE_S_ARCHIVE_ADDON" 'Exchange Online Archiving for Exchange Online' = "EXCHANGEARCHIVE_ADDON" 'Exchange Online Archiving for Exchange Server' = "EXCHANGEARCHIVE" 'Exchange Online Essentials' = "EXCHANGE_S_ESSENTIALS" 'Exchange Online Essentials (ExO P1 Based)' = "EXCHANGEESSENTIALS" 'Exchange Online Kiosk' = "EXCHANGEDESKLESS" 'Exchange Online Multi-Geo' = "EXCHANGEONLINE_MULTIGEO" 'EXCHANGE ONLINE PLAN' = "EXCHANGE_S_STANDARD_MIDMARKET" 'Exchange Online POP' = "EXCHANGETELCO" 'Exchange Online Protection' = "EOP_ENTERPRISE" 'EXCHANGE PLAN 2G' = "EXCHANGE_S_ENTERPRISE_GOV" 'EXCHANGE_ANALYTICS_GOV' = "EXCHANGE_ANALYTICS_GOV" 'EXCHANGE_S_DESKLESS' = "EXCHANGE_S_DESKLESS" 'EXCHANGE_S_ENTERPRISE_GOV' = "EXCHANGE_S_ENTERPRISE_GOV" 'EXCHANGE_S_FOUNDATION' = "EXCHANGE_S_FOUNDATION" 'EXCHANGE_S_FOUNDATION_GOV' = "EXCHANGE_S_FOUNDATION_GOV" 'Field Service � Automated Routing Engine Add-On' = "CRM_AUTO_ROUTING_ENGINE_ADDON" 'Flow for CCI Bots' = "FLOW_CCI_BOTS" 'Flow for Developer' = "FLOW_DEV_VIRAL" 'FLOW FOR DYNAMICS 36' = "FLOW_DYN_P2" 'Flow for Dynamics 365' = "FLOW_DYN_APPS" 'FLOW FOR OFFICE 365' = "FLOW_O365_P1" 'Flow for Project' = "FLOW_FOR_PROJECT" 'Flow Free' = "FLOW_P2_VIRAL" 'Flow P2 Viral' = "FLOW_P2_VIRAL_REAL" 'Flow per app baseline access' = "Flow_Per_APP_IWTRIAL" 'Flow per business process plan' = "FLOW_BUSINESS_PROCESS" 'Flow per user plan' = "FLOW_PER_USER" 'FLOW_O365_P3_GOV' = "FLOW_O365_P3_GOV" 'Forms for Government (Plan E1)' = "FORMS_GOV_E1" 'FORMS FOR GOVERNMENT (PLAN E3)' = "FORMS_GOV_E3" 'Forms for Government (Plan F1)' = "FORMS_GOV_F1" 'FORMS_GOV_E5' = "FORMS_GOV_E5" 'Graph Connectors Search with Index' = "GRAPH_CONNECTORS_SEARCH_INDEX" 'Graph Connectors Search with Index (Microsoft Viva Topics)' = "GRAPH_CONNECTORS_SEARCH_INDEX_TOPICEXP" 'Graph Connectors Search with Index (Viva Topics)' = "GRAPH_CONNECTORS_SEARCH_INDEX_TOPICEXP" 'INFO_GOVERNANCE' = "INFO_GOVERNANCE" 'Information Barriers' = "INFORMATION_BARRIERS" 'Information Protection and Governance Analytics � Premium' = "Content_Explorer" 'Information Protection and Governance Analytics - Premium' = "Content_Explorer" 'Information Protection and Governance Analytics - Premium)' = "Content_Explorer" 'Information Protection and Governance Analytics � Standard' = "ContentExplorer_Standard" 'Information Protection and Governance Analytics - Standard' = "ContentExplorer_Standard" 'Information Protection and Governance Analytics -Premium' = "Content_Explorer" 'Information Protection for Office 365 - Premium' = "MIP_S_CLP2" 'Information Protection for Office 365 - Standard' = "MIP_S_CLP1" 'INFORMATION_BARRIERS' = "INFORMATION_BARRIERS" 'Insights by MyAnalytics' = "MYANALYTICS_P2" 'INSIGHTS BY MYANALYTICS FOR GOVERNMENT' = "MYANALYTICS_P2_GOV" 'Intune' = "INTUNE_A" 'Intune Advanced endpoint analytics' = "Intune_AdvancedEA" 'Intune Endpoint Privilege Management' = "Intune-EPM" 'Intune for Education' = "INTUNE_EDU" 'Intune Plan 2' = "INTUNE_P2" 'INTUNE_A' = "INTUNE_A" 'INTUNE_O365' = "INTUNE_O365" 'IoT Intelligence Add-in Additional Machines' = "D365_IOTFORSCM_ADDITIONAL" 'Iot Intelligence Add-in for D365 Supply Chain Management' = "D365_IOTFORSCM" 'LOCKBOX_ENTERPRISE_GOV' = "LOCKBOX_ENTERPRISE_GOV" 'LOGIC FLOWS' = "POWERFLOWSFREE" 'M365 Communication Compliance' = "MICROSOFT_COMMUNICATION_COMPLIANCE" 'M365_ADVANCED_AUDITING' = "M365_ADVANCED_AUDITING" 'MCO FREE FOR MICROSOFT TEAMS (FREE)' = "MCOFREE" 'MCOEV_GOV' = "MCOEV_GOV" 'MCOIMP' = "MCOIMP" 'MCOMEETADV_GOV' = "MCOMEETADV_GOV" 'MCOPSTN3' = "MCOPSTN3" 'MCOSTANDARD_GOV' = "MCOSTANDARD_GOV" 'MCS - BizApps_Cloud for Sustainability_vTrial' = "MCS_BizApps_Cloud_for_Sustainability_vTrial" 'MDE_SecurityManagement' = "Intune_Defender" 'Meeting Room Managed Services' = "MMR_P1" 'MFA_PREMIUM' = "MFA_PREMIUM" 'Microsoft 365 A1' = "M365EDU_A1" 'Microsoft 365 A3 - Unattended License for students use benefit' = "M365EDU_A3_STUUSEBNFT_RPA1" 'Microsoft 365 A3 for Faculty' = "M365EDU_A3_FACULTY" 'Microsoft 365 A3 for Students' = "M365EDU_A3_STUDENT" 'Microsoft 365 A3 for students use benefit' = "M365EDU_A3_STUUSEBNFT" 'Microsoft 365 A3 Suite features for faculty' = "Microsoft 365 A3 Suite features for faculty" 'Microsoft 365 A5 for Faculty' = "M365EDU_A5_FACULTY" 'Microsoft 365 A5 for Students' = "M365EDU_A5_STUDENT" 'Microsoft 365 A5 for students use benefit' = "M365EDU_A5_STUUSEBNFT" 'Microsoft 365 A5 Suite features for faculty' = "M365_A5_SUITE_COMPONENTS_FACULTY" 'Microsoft 365 A5 without Audio Conferencing for students use benefit' = "M365EDU_A5_NOPSTNCONF_STUUSEBNFT" 'Microsoft 365 Advanced Auditing' = "M365_ADVANCED_AUDITING" 'Microsoft 365 Advanced Communications' = "TEAMS_ADVCOMMS" 'Microsoft 365 Apps for Business' = "SMB_BUSINESS" 'Microsoft 365 Apps for Enterprise' = "OFFICESUBSCRIPTION" 'Microsoft 365 Apps for enterprise (device)' = "OFFICE_PROPLUS_DEVICE1" 'Microsoft 365 Apps for Enterprise (Unattended)' = "OFFICESUBSCRIPTION_unattended" 'Microsoft 365 Apps for enterprise G' = "OFFICESUBSCRIPTION_GOV" 'Microsoft 365 Apps for Faculty' = "OFFICESUBSCRIPTION_FACULTY" 'Microsoft 365 Apps for Students' = "OFFICESUBSCRIPTION_STUDENT" 'Microsoft 365 Audio Conferencing' = "MCOMEETADV" 'Microsoft 365 Audio Conferencing for GCC' = "MCOMEETADV_GOV" 'MICROSOFT 365 AUDIO CONFERENCING FOR GOVERNMENT' = "MCOMEETADV_GOV" 'Microsoft 365 Audio Conferencing Pay-Per-Minute' = "MCOMEETACPEA" 'Microsoft 365 Audio Conferencing Pay-Per-Minute - EA' = "MCOMEETACPEA" 'Microsoft 365 Audit Platform' = "M365_AUDIT_PLATFORM" 'Microsoft 365 Business Basic' = "SMB_BUSINESS_ESSENTIALS" 'Microsoft 365 Business Premium' = "SPB" 'Microsoft 365 Business Standard' = "O365_BUSINESS_PREMIUM" 'Microsoft 365 Business Standard - Prepaid Legacy' = "SMB_BUSINESS_PREMIUM" 'Microsoft 365 Communication Compliance' = "MICROSOFT_COMMUNICATION_COMPLIANCE" 'Microsoft 365 Defender' = "MTP" 'Microsoft 365 Domestic Calling Plan' = "MCOPSTN1" 'MICROSOFT 365 DOMESTIC CALLING PLAN (120 min)' = "MCOPSTN5" 'Microsoft 365 Domestic Calling Plan (120 min) at User Level' = "MCOPSTN8" 'Microsoft 365 Domestic Calling Plan (120 Minutes)' = "MCOPSTN_5" 'Microsoft 365 Domestic Calling Plan for GCC' = "MCOPSTN_1_GOV" 'Microsoft 365 E3' = "SPE_E3" 'Microsoft 365 E3 - Unattended License' = "SPE_E3_RPA1" 'Microsoft 365 E3 (500 seats min)_HUB' = "Microsoft_365_E3" 'Microsoft 365 E3 Extra Features' = "Microsoft_365_E3_Extra_Features" 'Microsoft 365 E3_USGOV_DOD' = "SPE_E3_USGOV_DOD" 'Microsoft 365 E3_USGOV_GCCHIGH' = "SPE_E3_USGOV_GCCHIGH" 'Microsoft 365 E5' = "SPE_E5" 'Microsoft 365 E5 (500 seats min)_HUB' = "Microsoft_365_E5" 'Microsoft 365 E5 Compliance' = "INFORMATION_PROTECTION_COMPLIANCE" 'Microsoft 365 E5 Developer (without Windows and Audio Conferencing)' = "DEVELOPERPACK_E5" 'Microsoft 365 E5 Security' = "IDENTITY_THREAT_PROTECTION" 'Microsoft 365 E5 Security for EMS E5' = "IDENTITY_THREAT_PROTECTION_FOR_EMS_E5" 'Microsoft 365 E5 Suite features' = "M365_E5_SUITE_COMPONENTS" 'Microsoft 365 E5 with Calling Minutes' = "SPE_E5_CALLINGMINUTES" 'Microsoft 365 E5 without Audio Conferencing' = "SPE_E5_NOPSTNCONF" 'Microsoft 365 E5 without Audio Conferencing (500 seats min)_HUB' = "Microsoft_365_E5_without_Audio_Conferencing" 'Microsoft 365 F1' = "M365_F1_COMM" 'Microsoft 365 F3' = "SPE_F1" 'Microsoft 365 F3 GCC' = "M365_F1_GOV" 'Microsoft 365 F5 Compliance Add-on' = "SPE_F5_COMP" 'Microsoft 365 F5 Compliance Add-on AR (DOD)_USGOV_DOD' = "SPE_F5_COMP_AR_D_USGOV_DOD" 'Microsoft 365 F5 Compliance Add-on AR_USGOV_GCCHIGH' = "SPE_F5_COMP_AR_USGOV_GCCHIGH" 'Microsoft 365 F5 Compliance Add-on GCC' = "SPE_F5_COMP_GCC" 'Microsoft 365 F5 Security + Compliance Add-on' = "SPE_F5_SECCOMP" 'Microsoft 365 F5 Security Add-on' = "SPE_F5_SEC" 'Microsoft 365 G3 GCC' = "M365_G3_GOV" 'Microsoft 365 GCC G5' = "M365_G5_GCC" 'Microsoft 365 Lighthouse' = "Microsoft365_Lighthouse" 'Microsoft 365 Lighthouse (Plan 1)' = "M365_LIGHTHOUSE_CUSTOMER_PLAN1" 'Microsoft 365 Lighthouse (Plan 2)' = "M365_LIGHTHOUSE_PARTNER_PLAN1" 'Microsoft 365 Phone Standard Resource Account' = "MCOEV_VIRTUALUSER" 'Microsoft 365 Phone Standard Resource Account for Government' = "MCOEV_VIRTUALUSER_GOV" 'MICROSOFT 365 PHONE SYSTE' = "MCOEV" 'Microsoft 365 Phone System' = "MCOEV" 'Microsoft 365 Phone System for Government' = "MCOEV_GOV" 'Microsoft 365 Security and Compliance for Firstline Workers' = "M365_SECURITY_COMPLIANCE_FOR_FLW" 'Microsoft Application Protection and Governance (A)' = "MICROSOFT_APPLICATION_PROTECTION_AND_GOVERNANCE_A" 'Microsoft Application Protection and Governance (D)' = "MICROSOFT_APPLICATION_PROTECTION_AND_GOVERNANCE_D" 'MICROSOFT AZURE ACTIVE DIRECTORY BASIC' = "AAD_BASIC" 'MICROSOFT AZURE ACTIVE DIRECTORY RIGHTS' = "RMS_S_PREMIUM" 'Microsoft Azure Multi-Factor Authentication' = "MFA_STANDALONE" 'Microsoft Azure Rights Management Service' = "RMS_S_BASIC" 'Microsoft Bookings' = "MICROSOFTBOOKINGS" 'Microsoft Business Center' = "MICROSOFT_BUSINESS_CENTER" 'Microsoft Cloud App Security' = "ADALLOM_STANDALONE" 'Microsoft Cloud for Sustainability vTrial' = "Microsoft_Cloud_for_Sustainability_vTrial" 'Microsoft Communications Compliance' = "COMMUNICATIONS_COMPLIANCE" 'Microsoft Communications DLP' = "COMMUNICATIONS_DLP" 'Microsoft Customer Key' = "CUSTOMER_KEY" 'Microsoft Data Investigations' = "DATA_INVESTIGATIONS" 'Microsoft Defender for Business' = "MDE_SMB" 'Microsoft Defender for Cloud Apps' = "ADALLOM_S_STANDALONE" 'Microsoft Defender for Cloud Apps Discovery' = "ADALLOM_S_DISCOVERY" 'Microsoft Defender for Cloud Apps for DOD' = "ADALLOM_S_STANDALONE_DOD" 'Microsoft Defender for Endpoint' = "WIN_DEF_ATP" 'Microsoft Defender for Endpoint P1' = "DEFENDER_ENDPOINT_P1" 'Microsoft Defender for Endpoint P1 for EDU' = "DEFENDER_ENDPOINT_P1_EDU" 'Microsoft Defender for Endpoint P2_XPLAT' = "MDATP_XPLAT" 'Microsoft Defender for Endpoint Plan 1' = "MDE_LITE" 'Microsoft Defender for Endpoint Server' = "MDATP_Server" 'Microsoft Defender for Identity' = "ATA" 'Microsoft Defender for Office 365 (Plan 1)' = "ATP_ENTERPRISE" 'Microsoft Defender for Office 365 (Plan 1) Faculty' = "ATP_ENTERPRISE_FACULTY" 'Microsoft Defender for Office 365 (Plan 1) for Government' = "ATP_ENTERPRISE_GOV" 'Microsoft Defender for Office 365 (Plan 1) GCC' = "ATP_ENTERPRISE_GOV" 'Microsoft Defender for Office 365 (Plan 2)' = "THREAT_INTELLIGENCE" 'Microsoft Defender for Office 365 (Plan 2) for Government' = "THREAT_INTELLIGENCE_GOV" 'Microsoft Defender for Office 365 (Plan 2) GCC' = "THREAT_INTELLIGENCE_GOV" 'Microsoft Defender Vulnerability Management' = "TVM_Premium_Standalone" 'Microsoft Defender Vulnerability Management Add-on' = "TVM_Premium_Add_on" 'Microsoft Dynamics 365 Customer Voice Add-on' = "Forms_Pro_AddOn" 'Microsoft Dynamics 365 Customer Voice for Customer Engagement Plan' = "Forms_Pro_CE" 'Microsoft Dynamics 365 Customer Voice for Customer Insights' = "Forms_Pro_Customer_Insights" 'Microsoft Dynamics 365 Customer Voice for Customer Insights App' = "Customer_Voice_Customer_Insights" 'Microsoft Dynamics 365 Customer Voice for Customer Service Enterprise' = "Forms_Pro_Service" 'Microsoft Dynamics 365 Customer Voice for Field Service' = "Forms_Pro_FS" 'Microsoft Dynamics 365 Customer Voice for Marketing' = "Forms_Pro_Marketing" 'Microsoft Dynamics 365 Customer Voice for Marketing Application' = "Forms_Pro_Marketing_App" 'Microsoft Dynamics 365 Customer Voice for Relationship Sales' = "Forms_Pro_Relationship_Sales" 'Microsoft Dynamics 365 Customer Voice for Sales Enterprise' = "Forms_Pro_SalesEnt" 'Microsoft Dynamics 365 Customer Voice USL' = "Forms_Pro_USL" 'Microsoft Dynamics 365 for Finance' = "D365_Finance" 'Microsoft Dynamics AX7 User Trial' = "AX7_USER_TRIAL" 'Microsoft Dynamics CRM Online' = "CRMSTANDARD" 'Microsoft Dynamics CRM Online - Portal Add-On' = "CRM_ONLINE_PORTAL" 'Microsoft Dynamics CRM Online Additional Test Instance' = "CRMTESTINSTANCE" 'Microsoft Dynamics CRM Online Basic' = "CRMPLAN2" 'Microsoft Dynamics CRM Online Instance' = "CRMINSTANCE" 'MICROSOFT DYNAMICS CRM ONLINE PROFESSIONA' = "CRMSTANDARD" 'Microsoft Dynamics CRM Online Storage Add-On' = "CRMSTORAGE" 'MICROSOFT DYNAMICS MARKETING SALES COLLABORATION - ELIGIBILITY CRITERIA APPLY' = "MDM_SALES_COLLABORATION" 'Microsoft eCDN' = "MICROSOFT_ECDN" 'Microsoft Endpoint DLP' = "MICROSOFTENDPOINTDLP" 'Microsoft Excel Advanced Analytics' = "EXCEL_PREMIUM" 'Microsoft Fabric (Free)' = "POWER_BI_STANDARD" 'Microsoft Fabric (Free) for faculty' = "POWER_BI_STANDARD_FACULTY" 'Microsoft Fabric (Free) for student' = "POWER_BI_STANDARD_STUDENT" 'Microsoft Forms (Plan 2)' = "OFFICE_FORMS_PLAN_2" 'Microsoft Forms (Plan 3)' = "OFFICE_FORMS_PLAN_3" 'MICROSOFT FORMS (PLAN E1)' = "FORMS_PLAN_E1" 'Microsoft Forms (Plan E3)' = "FORMS_PLAN_E3" 'Microsoft Forms (Plan E5)' = "FORMS_PLAN_E5" 'Microsoft Forms (Plan F1)' = "FORMS_PLAN_K" 'Microsoft Forms for Government (Plan E5)' = "FORMS_GOV_E5" 'Microsoft Imagine Academy' = "IT_ACADEMY_AD" 'Microsoft Information Governance' = "INFO_GOVERNANCE" 'Microsoft Insider Risk Management' = "INSIDER_RISK" 'Microsoft Intune' = "INTUNE_A" 'Microsoft Intune Device' = "INTUNE_A_D" 'Microsoft Intune Device for Government' = "INTUNE_A_D_GOV" 'Microsoft Intune for Education' = "INTUNE_EDU" 'Microsoft Intune Plan 1' = "INTUNE_A" 'Microsoft Intune Plan 1 for Education' = "INTUNE_EDU" 'Microsoft Intune SMB' = "INTUNE_SMB" 'Microsoft Intune Suite' = "Microsoft_Intune_Suite" 'Microsoft Invoicing' = "DYN365BC_MS_INVOICING" 'Microsoft Kaizala' = "KAIZALA_STANDALONE" 'Microsoft Kaizala Pro' = "KAIZALA_O365_P3" 'Microsoft Kaizala Pro Plan 1' = "KAIZALA_O365_P1" 'Microsoft Kaizala Pro Plan 2' = "KAIZALA_O365_P2" 'Microsoft Kaizala Pro Plan 3' = "KAIZALA_O365_P3" 'Microsoft ML-Based Classification' = "ML_CLASSIFICATION" 'Microsoft MyAnalytics (Full)' = "EXCHANGE_ANALYTICS" 'Microsoft MyAnalytics for Government (Full)' = "EXCHANGE_ANALYTICS_GOV" 'MICROSOFT PLANNE' = "PROJECTWORKMANAGEMENT" 'Microsoft Planner' = "PROJECTWORKMANAGEMENT" 'Microsoft Power Apps for Developer' = "POWERAPPS_DEV" 'Microsoft Power Apps Plan 2 (Qualified Offer)' = "POWERFLOW_P2" 'Microsoft Power Apps Plan 2 Trial' = "POWERAPPS_VIRAL" 'Microsoft Power Automate Free' = "FLOW_FREE" 'Microsoft Power Automate Plan 2' = "FLOW_P2" 'MICROSOFT POWER BI INFORMATION SERVICES PLAN' = "SQL_IS_SSIM" 'Microsoft Power BI Information Services Plan 1' = "SQL_IS_SSIM" 'Microsoft Power BI Reporting and Analytics Plan 1' = "BI_AZURE_P1" 'MICROSOFT POWER VIDEOS BASIC' = "POWERVIDEOSFREE" 'MICROSOFT POWERAPPS' = "POWERAPPSFREE" 'Microsoft Records Management' = "RECORDS_MANAGEMENT" 'Microsoft Relationship Sales solution' = "DYN365_ ENTERPRISE _RELATIONSHIP_SALES" 'Microsoft Remote Assist' = "MICROSOFT_REMOTE_ASSIST" 'Microsoft Search' = "MICROSOFT_SEARCH" 'MICROSOFT SOCIAL ENGAGEMENT - SERVICE DISCONTINUATION' = "DYN365_ENTERPRISE_CUSTOMER_SERVICE" 'Microsoft Social Engagement Enterprise' = "NBENTERPRISE" 'MICROSOFT SOCIAL ENGAGEMENT PROFESSIONAL - ELIGIBILITY CRITERIA APPLY' = "NBPROFESSIONALFORCRM" 'Microsoft StaffHub' = "Deskless" 'Microsoft Stream' = "STREAM" 'MICROSOFT STREAM FOR O365 E1 SKU' = "STREAM_O365_E1" 'Microsoft Stream for O365 E3 SKU' = "STREAM_O365_E3" 'MICROSOFT STREAM FOR O365 E5 SKU' = "STREAM_O365_E5" 'Microsoft Stream for O365 for Government (E1)' = "STREAM_O365_E1_GOV" 'MICROSOFT STREAM FOR O365 FOR GOVERNMENT (E3)' = "STREAM_O365_E3_GOV" 'Microsoft Stream for O365 for Government (F1)' = "STREAM_O365_K_GOV" 'Microsoft Stream for O365 K SKU' = "STREAM_O365_K" 'Microsoft Stream for Office 365 E1' = "STREAM_O365_E1" 'Microsoft Stream for Office 365 E3' = "STREAM_O365_E3" 'Microsoft Stream for Office 365 E5' = "STREAM_O365_E5" 'Microsoft Stream for Office 365 F3' = "STREAM_O365_K" 'Microsoft Stream Plan 2' = "STREAM_P2" 'Microsoft Stream Storage Add-On' = "STREAM_STORAGE" 'Microsoft Stream Storage Add-On (500 GB)' = "STREAM_STORAGE" 'Microsoft Teams' = "TEAMS1" 'Microsoft Teams (Free)' = "TEAMS_FREE" 'Microsoft Teams Audio Conferencing with dial-out to select geographies' = "MCOMEETBASIC" 'Microsoft Teams Audio Conferencing with dial-out to USA/CAN' = "Microsoft_Teams_Audio_Conferencing_select_dial_out" 'Microsoft Teams Commercial Cloud' = "TEAMS_COMMERCIAL_TRIAL" 'Microsoft Teams Essentials' = "Teams_Ess" 'Microsoft Teams Essentials (AAD Identity)' = "TEAMS_ESSENTIALS_AAD" 'Microsoft Teams Exploratory' = "TEAMS_EXPLORATORY" 'Microsoft Teams for DOD (AR)' = "TEAMS_AR_DOD" 'Microsoft Teams for GCCHigh (AR)' = "TEAMS_AR_GCCHIGH" 'Microsoft Teams for Government' = "TEAMS_GOV" 'Microsoft Teams Phone Resource Account' = "PHONESYSTEM_VIRTUALUSER" 'Microsoft Teams Phone Resource Account for GCC' = "PHONESYSTEM_VIRTUALUSER_GOV" 'Microsoft Teams Phone Standard' = "MCOEV" 'Microsoft Teams Phone Standard for DOD' = "MCOEV_DOD" 'Microsoft Teams Phone Standard for Faculty' = "MCOEV_FACULTY" 'Microsoft Teams Phone Standard for GCC' = "MCOEV_GOV" 'Microsoft Teams Phone Standard for GCCHIGH' = "MCOEV_GCCHIGH" 'Microsoft Teams Phone Standard for Small and Medium Business' = "MCOEVSMB_1" 'Microsoft Teams Phone Standard for Students' = "MCOEV_STUDENT" 'Microsoft Teams Phone Standard for TELSTRA' = "MCOEV_TELSTRA" 'Microsoft Teams Phone Standard_USGOV_DOD' = "MCOEV_USGOV_DOD" 'Microsoft Teams Phone Standard_USGOV_GCCHIGH' = "MCOEV_USGOV_GCCHIGH" 'Microsoft Teams Premium Intelligent' = "TEAMSPRO_MGMT" 'Microsoft Teams Premium Introductory Pricing' = "Microsoft_Teams_Premium" 'Microsoft Teams Premium Personalized' = "TEAMSPRO_CUST" 'Microsoft Teams Premium Secure' = "TEAMSPRO_PROTECTION" 'Microsoft Teams Premium Virtual Appointment' = "TEAMSPRO_VIRTUALAPPT" 'Microsoft Teams Premium Virtual Appointments' = "MCO_VIRTUAL_APPT" 'Microsoft Teams Premium Webinar' = "TEAMSPRO_WEBINAR" 'Microsoft Teams Rooms Basic' = "Microsoft_Teams_Rooms_Basic" 'Microsoft Teams Rooms Basic for EDU' = "Microsoft_Teams_Rooms_Basic_FAC" 'Microsoft Teams Rooms Basic without Audio Conferencing' = "Microsoft_Teams_Rooms_Basic_without_Audio_Conferencing" 'Microsoft Teams Rooms Pro' = "Microsoft_Teams_Rooms_Pro" 'Microsoft Teams Rooms Pro for EDU' = "Microsoft_Teams_Rooms_Pro_FAC" 'Microsoft Teams Rooms Pro Management' = "MTRProManagement" 'Microsoft Teams Rooms Pro without Audio Conferencing' = "Microsoft_Teams_Rooms_Pro_without_Audio_Conferencing" 'Microsoft Teams Rooms Standard' = "MEETING_ROOM" 'Microsoft Teams Rooms Standard without Audio Conferencing' = "MEETING_ROOM_NOAUDIOCONF" 'Microsoft Teams Shared Devices' = "MCOCAP" 'Microsoft Teams Shared Devices for GCC' = "MCOCAP_GOV" 'Microsoft Teams Trial' = "MS_TEAMS_IW" 'Microsoft Threat Experts - Experts on Demand' = "EXPERTS_ON_DEMAND" 'Microsoft Tunnel for Mobile Application Management' = "Intune-MAMTunnel" 'Microsoft Viva Goals' = "Microsoft_Viva_Goals" 'Microsoft Viva Insights' = "WORKPLACE_ANALYTICS_INSIGHTS_USER" 'Microsoft Viva Insights Backend' = "WORKPLACE_ANALYTICS_INSIGHTS_BACKEND" 'Microsoft Viva Sales Premium & Trial' = "Microsoft_Viva_Sales_PremiumTrial" 'Microsoft Viva Sales Premium with Power Automate' = "Microsoft_Viva_Sales_PowerAutomate" 'Microsoft Viva Suite' = "VIVA" 'Microsoft Viva Topics' = "CORTEX" 'Microsoft Workplace Analytics' = "WORKPLACE_ANALYTICS" 'Microsoft Workplace Analytics Insights Backend' = "WORKPLACE_ANALYTICS_INSIGHTS_BACKEND" 'Microsoft Workplace Analytics Insights User' = "WORKPLACE_ANALYTICS_INSIGHTS_USER" 'MICROSOFT_COMMUNICATION_COMPLIANCE' = "MICROSOFT_COMMUNICATION_COMPLIANCE" 'MICROSOFT_SEARCH' = "MICROSOFT_SEARCH" 'MICROSOFTBOOKINGS' = "MICROSOFTBOOKINGS" 'Minecraft Education' = "MINECRAFT_EDUCATION_EDITION" 'Minecraft Education Edition' = "MINECRAFT_EDUCATION_EDITION" 'Minecraft Education Faculty' = "MEE_FACULTY" 'Minecraft Education Student' = "MEE_STUDENT" 'MIP_S_CLP1' = "MIP_S_CLP1" 'MIP_S_CLP2' = "MIP_S_CLP2" 'Mobile Device Management for Office 365' = "INTUNE_O365" 'MS IMAGINE ACADEMY' = "IT_ACADEMY_AD" 'MTP' = "MTP" 'Multi-Geo Capabilities in Office 365' = "OFFICE365_MULTIGEO" 'Nonprofit Portal' = "NONPROFIT_PORTAL" 'Nucleus' = "Nucleus" 'Office 365 A1 for faculty' = "STANDARDWOFFPACK_FACULTY" 'Office 365 A1 for students' = "STANDARDWOFFPACK_STUDENT" 'Office 365 A1 Plus for faculty' = "STANDARDWOFFPACK_IW_FACULTY" 'Office 365 A1 Plus for students' = "STANDARDWOFFPACK_IW_STUDENT" 'Office 365 A3 for faculty' = "ENTERPRISEPACKPLUS_FACULTY" 'Office 365 A3 for students' = "ENTERPRISEPACKPLUS_STUDENT" 'Office 365 A5 for faculty' = "ENTERPRISEPREMIUM_FACULTY" 'Office 365 A5 for students' = "ENTERPRISEPREMIUM_STUDENT" 'Office 365 Advanced Compliance' = "EQUIVIO_ANALYTICS" 'Office 365 Advanced Compliance for GCC' = "EQUIVIO_ANALYTICS_GOV" 'Office 365 Advanced eDiscovery' = "EQUIVIO_ANALYTICS" 'Office 365 Advanced eDiscovery for Government' = "EQUIVIO_ANALYTICS_GOV" 'Office 365 Advanced Security Management' = "ADALLOM_S_O365" 'OFFICE 365 BUSINESS' = "OFFICE_BUSINESS" 'Office 365 Cloud App Security' = "ADALLOM_O365" 'Office 365 E1' = "STANDARDPACK" 'Office 365 E2' = "STANDARDWOFFPACK" 'Office 365 E3' = "ENTERPRISEPACK" 'Office 365 E3 Developer' = "DEVELOPERPACK" 'Office 365 E3_USGOV_DOD' = "ENTERPRISEPACK_USGOV_DOD" 'Office 365 E3_USGOV_GCCHIGH' = "ENTERPRISEPACK_USGOV_GCCHIGH" 'Office 365 E4' = "ENTERPRISEWITHSCAL" 'Office 365 E5' = "ENTERPRISEPREMIUM" 'Office 365 E5 Without Audio Conferencing' = "ENTERPRISEPREMIUM_NOPSTNCONF" 'Office 365 Extra File Storage' = "SHAREPOINTSTORAGE" 'Office 365 Extra File Storage for GCC' = "SHAREPOINTSTORAGE_GOV" 'Office 365 F3' = "DESKLESSPACK" 'Office 365 G1 GCC' = "STANDARDPACK_GOV" 'Office 365 G3 GCC' = "ENTERPRISEPACK_GOV" 'Office 365 G5 GCC' = "ENTERPRISEPREMIUM_GOV" 'Office 365 Midsize Business' = "MIDSIZEPACK" 'Office 365 Planner for Government' = "PROJECTWORKMANAGEMENT_GOV" 'Office 365 Privileged Access Management' = "PAM_ENTERPRISE" 'Office 365 ProPlus' = "OFFICESUBSCRIPTION" 'Office 365 SafeDocs' = "SAFEDOCS" 'Office 365 Small Business' = "LITEPACK" 'Office 365 Small Business Premium' = "LITEPACK_P2" 'OFFICE 365 SMALL BUSINESS SUBSCRIPTION' = "OFFICE_PRO_PLUS_SUBSCRIPTION_SMBIZ" 'Office for the web' = "SHAREPOINTWAC" 'Office for the web (Education)' = "SHAREPOINTWAC_EDU" 'OFFICE FOR THE WEB (GOVERNMENT)' = "SHAREPOINTWAC_GOV" 'Office for the Web for Education' = "SHAREPOINTWAC_EDU" 'Office for the Web for Government' = "SHAREPOINTWAC_GOV" 'Office Mobile Apps for Office 365' = "OFFICEMOBILE_SUBSCRIPTION" 'Office Mobile Apps for Office 365 for GCC' = "OFFICEMOBILE_SUBSCRIPTION_GOV" 'OFFICE ONLINE' = "SHAREPOINTWAC" 'OFFICE ONLINE FOR DEVELOPER' = "SHAREPOINTWAC_DEVELOPER" 'Office Shared Computer Activation' = "OFFICE_SHARED_COMPUTER_ACTIVATION" 'OFFICEMOBILE_SUBSCRIPTION' = "OFFICEMOBILE_SUBSCRIPTION" 'OFFICESUBSCRIPTION' = "OFFICESUBSCRIPTION" 'OFFICESUBSCRIPTION_GOV' = "OFFICESUBSCRIPTION_GOV" 'OneDrive for Business (Basic 2)' = "ONEDRIVE_BASIC_P2" 'OneDrive for Business (Basic)' = "ONEDRIVE_BASIC" 'OneDrive for Business (Plan 1)' = "WACONEDRIVESTANDARD" 'OneDrive for Business (Plan 2)' = "WACONEDRIVEENTERPRISE" 'OneDrive for business Basic' = "ONEDRIVE_BASIC" 'ONEDRIVE FOR BUSINESS BASIC FOR GOVERNMENT' = "ONEDRIVE_BASIC_GOV" 'ONEDRIVEENTERPRISE' = "ONEDRIVEENTERPRISE" 'ONEDRIVESTANDARD' = "ONEDRIVESTANDARD" 'OUTLOOK CUSTOMER MANAGER' = "O365_SB_Relationship_Management" 'PAD for Windows' = "POWERAUTOMATE_DESKTOP_FOR_WIN" 'Power Apps (Plan 2)' = "POWERAPPS_P2" 'Power Apps and Logic Flows' = "POWERAPPS_INDIVIDUAL_USER" 'Power Apps for Customer Service Pro' = "POWERAPPS_CUSTOMER_SERVICE_PRO" 'Power Apps for Dynamics 365' = "POWERAPPS_DYN_TEAM" 'Power Apps for Dynamics 365 vTrial' = "POWER_APPS_DYN365_VIRAL_TRIAL" 'Power Apps for Guides' = "POWERAPPS_GUIDES" 'Power Apps for Office 365' = "POWERAPPS_O365_P2" 'Power Apps for Office 365 (Plan 3)' = "POWERAPPS_O365_P3" 'Power Apps for Office 365 F3' = "POWERAPPS_O365_S1" 'Power Apps for Office 365 F3 for Government' = "POWERAPPS_O365_S1_GOV" 'Power Apps for Office 365 for Government' = "POWERAPPS_O365_P3_GOV" 'Power Apps for Sales Pro' = "POWERAPPS_SALES_PRO" 'Power Apps per app' = "POWERAPPS_PER_APP_NEW" 'Power Apps per app plan' = "POWERAPPS_PER_APP" 'Power Apps per app plan (1 app or portal)' = "POWERAPPS_PER_APP_NEW" 'Power Apps per user plan' = "POWERAPPS_PER_USER" 'Power Apps per user plan for Government' = "POWERAPPS_PER_USER_GCC" 'Power Apps Portals Login Capacity Add-On' = "POWERAPPS_PORTALS_LOGIN" 'Power Apps Portals Login Capacity Add-On for Government' = "POWERAPPS_PORTALS_LOGIN_GCC" 'Power Apps Portals login capacity add-on Tier 2 (10 unit min)' = "POWERAPPS_PORTALS_LOGIN_T2" 'Power Apps Portals login capacity add-on Tier 2 (10 unit min) for Government' = "POWERAPPS_PORTALS_LOGIN_T2_GCC" 'Power Apps Portals login capacity add-on Tier 3 (50 unit min)' = "POWERAPPS_PORTALS_LOGIN_T3" 'Power Apps Portals page view capacity add-on' = "POWERAPPS_PORTALS_PAGEVIEW" 'Power Apps Portals page view capacity add-on for Government' = "POWERAPPS_PORTALS_PAGEVIEW_GCC" 'Power Automate (Plan 1) for Government' = "FLOW_P1_GOV" 'Power Automate (Plan 2)' = "FLOW_P2" 'Power Automate for Customer Service Pro' = "FLOW_CUSTOMER_SERVICE_PRO" 'Power Automate for Dynamics 365' = "FLOW_DYN_TEAM" 'Power Automate for Dynamics 365 Customer Voice' = "FLOW_FORMS_PRO" 'Power Automate for Dynamics 365 vTrial' = "POWER_AUTOMATE_DYN365_VIRAL_TRIAL" 'Power Automate for Office 365' = "FLOW_O365_P2" 'Power Automate for Office 365 F3' = "FLOW_O365_S1" 'Power Automate for Office 365 F3 for Government' = "FLOW_O365_S1_GOV" 'Power Automate for Office 365 for Government' = "FLOW_O365_P3_GOV" 'Power Automate for Power Apps per App Plan' = "Flow_Per_APP" 'Power Automate for Power Apps per User Plan' = "Flow_PowerApps_PerUser" 'Power Automate for Power Apps per User Plan for GCC' = "Flow_PowerApps_PerUser_GCC" 'Power Automate for Project' = "FLOW_FOR_PROJECT" 'POWER AUTOMATE FOR PROJECT P1' = "Power_Automate_For_Project_P1" 'Power Automate for Virtual Agent' = "FLOW_VIRTUAL_AGENT_BASE" 'Power Automate per flow plan' = "FLOW_BUSINESS_PROCESS" 'Power Automate per user plan' = "FLOW_PER_USER" 'Power Automate per user plan dept' = "FLOW_PER_USER_DEPT" 'Power Automate per user plan for Government' = "FLOW_PER_USER_GCC" 'Power Automate per user with attended RPA plan' = "POWERAUTOMATE_ATTENDED_RPA" 'Power Automate RPA Attended' = "POWER_AUTOMATE_ATTENDED_RPA" 'Power Automate unattended RPA add-on' = "POWERAUTOMATE_UNATTENDED_RPA" 'Power BI' = "POWER_BI_INDIVIDUAL_USER" 'Power BI (free)' = "POWER_BI_STANDARD" 'Power BI for Office 365 Add-On' = "POWER_BI_ADDON" 'Power BI Premium P' = "PBI_PREMIUM_P1_ADDON" 'Power BI Premium P1' = "PBI_PREMIUM_P1_ADDON" 'Power BI Premium Per User' = "PBI_PREMIUM_PER_USER" 'Power BI Premium Per User Add-On' = "PBI_PREMIUM_PER_USER_ADDON" 'Power BI Premium Per User Dept' = "PBI_PREMIUM_PER_USER_DEPT" 'Power BI Premium Per User for Faculty' = "PBI_PREMIUM_PER_USER_FACULTY" 'Power BI Pro' = "POWER_BI_PRO" 'Power BI Pro CE' = "POWER_BI_PRO_CE" 'Power BI Pro Dept' = "POWER_BI_PRO_DEPT" 'Power BI Pro for Faculty' = "POWER_BI_PRO_FACULTY" 'Power BI Pro for GCC' = "POWERBI_PRO_GOV" 'Power BI Pro for Government' = "BI_AZURE_P_2_GOV" 'Power Pages Internal User' = "Power_Pages_Internal_User" 'Power Pages vTrial for Makers' = "Power_Pages_vTrial_for_Makers" 'Power Virtual Agent' = "VIRTUAL_AGENT_BASE" 'Power Virtual Agent User License' = "VIRTUAL_AGENT_USL" 'Power Virtual Agents for Chat' = "POWER_VIRTUAL_AGENTS_D365_CS_CHAT" 'Power Virtual Agents for Customer Service Voice' = "POWER_VIRTUAL_AGENTS_D365_CS_VOICE" 'Power Virtual Agents for Digital Messaging' = "POWER_VIRTUAL_AGENTS_D365_CS_MESSAGING" 'Power Virtual Agents for Office 365' = "POWER_VIRTUAL_AGENTS_O365_P2" 'Power Virtual Agents for Office 365 F1' = "POWER_VIRTUAL_AGENTS_O365_F1" 'POWER VIRTUAL AGENTS FOR OFFICE 365 P1' = "POWER_VIRTUAL_AGENTS_O365_P1" 'Power Virtual Agents for Office 365 P2' = "POWER_VIRTUAL_AGENTS_O365_P2" 'Power Virtual Agents for Office 365 P3' = "POWER_VIRTUAL_AGENTS_O365_P3" 'Power Virtual Agents Viral Trial' = "CCIBOTS_PRIVPREV_VIRAL" 'PowerApps for Developer' = "POWERAPPS_DEV_VIRAL" 'PowerApps for Dynamics 365' = "POWERAPPS_DYN_APPS" 'POWERAPPS FOR OFFICE 36' = "POWERAPPS_O365_P2" 'POWERAPPS FOR OFFICE 365' = "POWERAPPS_O365_P1" 'PowerApps for Office 365 Plan 3' = "POWERAPPS_O365_P3" 'PowerApps per app baseline access' = "POWERAPPS_PER_APP_IW" 'PowerApps Plan 1 for Government' = "POWERAPPS_P1_GOV" 'PowerApps Trial' = "POWERAPPS_P2_VIRAL" 'POWERAPPS_O365_P3_GOV' = "POWERAPPS_O365_P3_GOV" 'Premium Encryption in Office 365' = "PREMIUM_ENCRYPTION" 'PREMIUM_ENCRYPTION' = "PREMIUM_ENCRYPTION" 'Priva - Risk' = "PRIVACY_MANGEMENT_RISK" 'Priva - Risk (Exchange)' = "PRIVACY_MANGEMENT_RISK_EXCHANGE" 'Privacy Management � risk' = "PRIVACY_MANAGEMENT_RISK" 'Privacy Management - risk for EDU' = "PRIVACY_MANAGEMENT_RISK_EDU" 'Privacy Management - risk GCC' = "PRIVACY_MANAGEMENT_RISK_GCC" 'Privacy Management - risk_USGOV_DOD' = "PRIVACY_MANAGEMENT_RISK_USGOV_DOD" 'Privacy Management - risk_USGOV_GCCHIGH' = "PRIVACY_MANAGEMENT_RISK_USGOV_GCCHIGH" 'Privacy Management - Subject Rights Request' = "PRIVACY_MANGEMENT_DSR" 'Privacy Management - Subject Rights Request (1 - Exchange)' = "PRIVACY_MANGEMENT_DSR_1" 'Privacy Management - subject rights request (1)' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2" 'Privacy Management - subject rights request (1) for EDU' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_EDU_V2" 'Privacy Management - subject rights request (1) GCC' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2_GCC" 'Privacy Management - subject rights request (1) USGOV_DOD' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2_USGOV_DOD" 'Privacy Management - subject rights request (1) USGOV_GCCHIGH' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_1_V2_USGOV_GCCHIGH" 'Privacy Management - Subject Rights Request (10 - Exchange)' = "PRIVACY_MANGEMENT_DSR_EXCHANGE_10" 'Privacy Management - subject rights request (10)' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2" 'Privacy Management - subject rights request (10) for EDU' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_EDU_V2" 'Privacy Management - subject rights request (10) GCC' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2_GCC" 'Privacy Management - subject rights request (10) USGOV_DOD' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2_USGOV_DOD" 'Privacy Management - subject rights request (10) USGOV_GCCHIGH' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_10_V2_USGOV_GCCHIGH" 'Privacy Management - Subject Rights Request (100 - Exchange)' = "PRIVACY_MANGEMENT_DSR_EXCHANGE_100" 'Privacy Management - subject rights request (100)' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2" 'Privacy Management - subject rights request (100) for EDU' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_EDU_V2" 'Privacy Management - subject rights request (100) GCC' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2_GCC" 'Privacy Management - subject rights request (100) USGOV_DOD' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2_USGOV_DOD" 'Privacy Management - subject rights request (100) USGOV_GCCHIGH' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_100_V2_USGOV_GCCHIGH" 'Privacy Management - subject rights request (50)' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_50_V2" 'Privacy Management - subject rights request (50) for EDU' = "PRIVACY_MANAGEMENT_SUB_RIGHTS_REQ_50_EDU_V2" 'Privacy Management - Subject Rights Request (Exchange)' = "PRIVACY_MANGEMENT_DSR_EXCHANGE" 'Project for Office (Plan E1)' = "PROJECT_O365_P1" 'Project for Office (Plan E3)' = "PROJECT_O365_P2" 'Project for Office (Plan E5)' = "PROJECT_O365_P3" 'Project for Office (Plan F)' = "PROJECT_O365_F3" 'Project for Office 365' = "PROJECTCLIENT" 'Project for Project Operations' = "PROJECT_FOR_PROJECT_OPERATIONS" 'Project Online Desktop Client' = "PROJECT_CLIENT_SUBSCRIPTION" 'Project Online Desktop Client for Government' = "PROJECT_CLIENT_SUBSCRIPTION_GOV" 'Project Online Essentials' = "PROJECTESSENTIALS" 'Project Online Essentials for Faculty' = "PROJECTESSENTIALS_FACULTY" 'Project Online Essentials for GCC' = "PROJECTESSENTIALS_GOV" 'Project Online Essentials for Government' = "PROJECT_ESSENTIALS_GOV" 'Project Online Premium' = "PROJECTPREMIUM" 'Project Online Premium Without Project Client' = "PROJECTONLINE_PLAN_1" 'Project Online Service' = "SHAREPOINT_PROJECT" 'Project Online Service for Education' = "SHAREPOINT_PROJECT_EDU" 'Project Online Service for Government' = "SHAREPOINT_PROJECT_GOV" 'Project Online With Project for Office 365' = "PROJECTONLINE_PLAN_2" 'PROJECT P1' = "PROJECT_P1" 'Project P3' = "PROJECT_PROFESSIONAL" 'Project P3 for Faculty' = "PROJECT_PROFESSIONAL_FACULTY" 'Project Plan 1' = "PROJECT_P1" 'Project Plan 1 (for Department)' = "PROJECT_PLAN1_DEPT" 'Project Plan 3' = "PROJECTPROFESSIONAL" 'Project Plan 3 (for Department)' = "PROJECT_PLAN3_DEPT" 'Project Plan 3 for Faculty' = "PROJECTPROFESSIONAL_FACULTY" 'Project Plan 3 for GCC' = "PROJECTPROFESSIONAL_GOV" 'Project Plan 5 for GCC' = "PROJECTPREMIUM_GOV" 'Project Plan 5 without Project Client for Faculty' = "PROJECTONLINE_PLAN_1_FACULTY" 'PROJECTWORKMANAGEMENT' = "PROJECTWORKMANAGEMENT" 'PROJECTWORKMANAGEMENT_GOV' = "PROJECTWORKMANAGEMENT_GOV" 'RECORDS_MANAGEMENT' = "RECORDS_MANAGEMENT" 'Remote help' = "REMOTE_HELP" 'RETIRED - Field Service � Automated Routing Engine Add-On' = "CRM_AUTO_ROUTING_ADDON" 'RETIRED - Microsoft Communications Compliance' = "COMMUNICATIONS_COMPLIANCE" 'RETIRED - Microsoft Insider Risk Management' = "INSIDER_RISK_MANAGEMENT" 'Retired - Microsoft Social Engagement' = "NBENTERPRISE" 'RETIRED - Outlook Customer Manager' = "O365_SB_Relationship_Management" 'Rights Management Adhoc' = "RIGHTSMANAGEMENT_ADHOC" 'Rights Management Service Basic Content Protection' = "RMSBASIC" 'RMS_S_ENTERPRISE' = "RMS_S_ENTERPRISE" 'RMS_S_ENTERPRISE_GOV' = "RMS_S_ENTERPRISE_GOV" 'RMS_S_PREMIUM' = "RMS_S_PREMIUM" 'School Data Sync (Plan 1)' = "SCHOOL_DATA_SYNC_P1" 'School Data Sync (Plan 2)' = "SCHOOL_DATA_SYNC_P2" 'SecOps Investigation for MDI' = "ADALLOM_FOR_AATP" 'Sensor Data Intelligence Additional Machines Add-in for Dynamics 365 Supply Chain Management' = "DYN365_IOT_INTELLIGENCE_ADDL_MACHINES" 'Sensor Data Intelligence Scenario Add-in for Dynamics 365 Supply Chain Management' = "DYN365_IOT_INTELLIGENCE_SCENARIO" 'SHAREPOINT' = "SHAREPOINTSTANDARD" 'SharePoint (Plan 1)' = "SHAREPOINTSTANDARD" 'SharePoint (Plan 1) for Education' = "SHAREPOINTSTANDARD_EDU" 'SharePoint (Plan 2)' = "SHAREPOINTENTERPRISE" 'SharePoint (Plan 2) for Education' = "SHAREPOINTENTERPRISE_EDU" 'SharePoint (Plan 2)Dynamics 365 for Sales Pro Attach' = "SHAREPOINTENTERPRISE" 'SHAREPOINT FOR DEVELOPER' = "SHAREPOINT_S_DEVELOPER" 'SharePoint Kiosk' = "SHAREPOINTDESKLESS" 'SharePoint KioskG' = "SHAREPOINTDESKLESS_GOV" 'SharePoint Multi-Geo' = "SHAREPOINTONLINE_MULTIGEO" 'SharePoint Online (Plan 1)' = "SHAREPOINTSTANDARD" 'SharePoint Online (Plan 2)' = "SHAREPOINTENTERPRISE" 'SharePoint Online Kiosk' = "SHAREPOINTDESKLESS" 'SHAREPOINT PLAN 1' = "SHAREPOINTENTERPRISE_MIDMARKET" 'SharePoint Plan 1G' = "SharePoint Plan 1G" 'SharePoint Plan 2 for EDU' = "SHAREPOINTENTERPRISE_EDU" 'SharePoint Plan 2G' = "SHAREPOINTENTERPRISE_GOV" 'SHAREPOINT STANDARD' = "SHAREPOINTSTANDARD" 'SharePoint Syntex' = "Intelligent_Content_Services" 'SharePoint Syntex - SPO type' = "Intelligent_Content_Services_SPO_type" 'SHAREPOINT_PROJECT' = "SHAREPOINT_PROJECT" 'SHAREPOINTDESKLESS' = "SHAREPOINTDESKLESS" 'SHAREPOINTENTERPRISE_GOV' = "SHAREPOINTENTERPRISE_GOV" 'SHAREPOINTLITE' = "SHAREPOINTLITE" 'SHAREPOINTSTANDARD' = "SHAREPOINTSTANDARD" 'SHAREPOINTSTORAGE_GOV' = "SHAREPOINTSTORAGE_GOV" 'SHAREPOINTWAC_GOV' = "SHAREPOINTWAC_GOV" 'SKYPE FOR BUSINESS CLOUD PBX FOR SMALL AND MEDIUM BUSINESS' = "MCOEVSMB" 'Skype for Business Online (Plan 1)' = "MCOIMP" 'Skype for Business Online (Plan 1) for Government' = "MCOIMP_GOV" 'Skype for Business Online (Plan 2)' = "MCOSTANDARD" 'Skype for Business Online (Plan 2) for Government' = "MCOSTANDARD_GOV" 'SKYPE FOR BUSINESS ONLINE (PLAN 2) FOR MIDSIZ' = "MCOSTANDARD_MIDMARKET" 'SKYPE FOR BUSINESS ONLINE (PLAN 3)' = "MCOVOICECONF" 'SKYPE FOR BUSINESS ONLINE (PLAN P1)' = "MCOLITE" 'Skype for Business PSTN Domestic and International Calling' = "MCOPSTN2" 'Skype for Business PSTN Domestic Calling' = "MCOPSTN1" 'Skype for Business PSTN Domestic Calling (120 Minutes)' = "MCOPSTN5" 'Skype for Business PSTN Usage Calling Plan' = "MCOPSTNPP" 'Stream for Office 365' = "STREAM_O365_SMB" 'Stream for Office 365 for Government (E5)' = "STREAM_O365_E5_GOV" 'STREAM_O365_E5_GOV' = "STREAM_O365_E5_GOV" 'STREAM_O365_K' = "STREAM_O365_K" 'Sway' = "SWAY" 'TEAMS FREE SERVICE' = "TEAMS_FREE_SERVICE" 'Teams Multi-Geo' = "TEAMSMULTIGEO" 'Teams Phone with Calling Plan' = "MCOTEAMS_ESSENTIALS" 'Teams Room Basic' = "Teams_Room_Basic" 'Teams Room Pro' = "Teams_Room_Pro" 'Teams Room Standard' = "Teams_Room_Standard" 'Teams Rooms Premium' = "MTR_PREM" 'Teams Rooms Test 1' = "Teams_Room_Basic" 'Teams Rooms Test 2' = "Teams_Room_Pro" 'TEAMS_GOV' = "TEAMS_GOV" 'TEAMS1' = "TEAMS1" 'TELSTRA Calling for O365' = "MCOPSTNEAU2" 'THREAT_INTELLIGENCE_GOV' = "THREAT_INTELLIGENCE_GOV" 'To-Do (Firstline)' = "BPOS_S_TODO_FIRSTLINE" 'To-Do (Plan 1)' = "BPOS_S_TODO_1" 'To-Do (Plan 2)' = "BPOS_S_TODO_2" 'To-Do (Plan 3)' = "BPOS_S_TODO_3" 'Universal Print' = "UNIVERSAL_PRINT" 'Universal Print Without Seeding' = "UNIVERSAL_PRINT_NO_SEEDING" 'Virtual Agent' = "VIRTUAL_AGENT_USL" 'Virtual Agent Base' = "VIRTUAL_AGENT_BASE" 'Visio Desktop App' = "VISIO_CLIENT_SUBSCRIPTION" 'VISIO DESKTOP APP FOR Government' = "VISIO_CLIENT_SUBSCRIPTION_GOV" 'Visio Online Plan 1' = "VISIOONLINE_PLAN1" 'Visio Online Plan 2' = "VISIOCLIENT" 'Visio Plan 1' = "VISIO_PLAN1_DEPT" 'Visio Plan 2' = "VISIO_PLAN2_DEPT" 'Visio Plan 2 for Faculty' = "VISIOCLIENT_FACULTY" 'Visio Plan 2 for GCC' = "VISIOCLIENT_GOV" 'Visio web app' = "VISIOONLINE" 'VISIO WEB APP FOR GOVERNMENT' = "VISIOONLINE_GOV" 'Viva Engage Communities and Communications' = "VIVAENGAGE_COMMUNITIES_AND_COMMUNICATIONS" 'Viva Engage Core' = "VIVAENGAGE_CORE" 'Viva Engage Knowledge' = "VIVAENGAGE_KNOWLEDGE" 'Viva Goals' = "Viva_Goals_Premium" 'Viva Learning' = "VIVA_LEARNING_PREMIUM" 'Viva Learning Seeded' = "VIVA_LEARNING_SEEDED" 'Viva Topics' = "TOPIC_EXPERIENCES" 'Whiteboard (Firstline)' = "WHITEBOARD_FIRSTLINE1" 'Whiteboard (Plan 1)' = "WHITEBOARD_PLAN1" 'Whiteboard (Plan 2)' = "WHITEBOARD_PLAN2" 'Whiteboard (Plan 3)' = "WHITEBOARD_PLAN3" 'WINDOWS 10 ENTERPRISE' = "WIN10_PRO_ENT_SUB" 'Windows 10 Enterprise (New)' = "Virtualization Rights for Windows 10 (E3/E5+VDA)" 'Windows 10 Enterprise E3 (Local Only)' = "WIN10_ENT_LOC_F1" 'Windows 10/11 Business' = "WINBIZ" 'Windows 10/11 Enterprise' = "Virtualization Rights for Windows 10 (E3/E5+VDA)" 'Windows 10/11 Enterprise (Original)' = "WIN10_PRO_ENT_SUB" 'Windows 10/11 Enterprise A3 for faculty' = "WIN10_ENT_A3_FAC" 'Windows 10/11 Enterprise A3 for students' = "WIN10_ENT_A3_STU" 'Windows 10/11 Enterprise A5 for faculty' = "WIN10_ENT_A5_FAC" 'Windows 10/11 Enterprise E3' = "WIN10_VDA_E3" 'Windows 10/11 Enterprise E3 VDA' = "E3_VDA_only" 'Windows 10/11 Enterprise E5' = "WIN10_VDA_E5" 'Windows 10/11 Enterprise E5 (Original)' = "WIN_ENT_E5" 'Windows 10/11 Enterprise E5 Commercial (GCC Compatible)' = "WINE5_GCC_COMPAT" 'Windows 365 Business 1 vCPU 2 GB 64 GB' = "CPC_B_1C_2RAM_64GB" 'Windows 365 Business 2 vCPU 4 GB 128 GB' = "CPC_B_2C_4RAM_128GB" 'Windows 365 Business 2 vCPU 4 GB 256 GB' = "CPC_B_2C_4RAM_256GB" 'Windows 365 Business 2 vCPU 4 GB 64 GB' = "CPC_B_2C_4RAM_64GB" 'Windows 365 Business 2 vCPU 8 GB 128 GB' = "CPC_B_2C_8RAM_128GB" 'Windows 365 Business 2 vCPU 8 GB 256 GB' = "CPC_B_2C_8RAM_256GB" 'Windows 365 Business 2 vCPU, 8 GB, 128 GB' = "CPC_SS_2" 'Windows 365 Business 4 vCPU 16 GB 128 GB' = "CPC_B_4C_16RAM_128GB" 'Windows 365 Business 4 vCPU 16 GB 128 GB (with Windows Hybrid Benefit)' = "CPC_B_4C_16RAM_128GB_WHB" 'Windows 365 Business 4 vCPU 16 GB 256 GB' = "CPC_B_4C_16RAM_256GB" 'Windows 365 Business 4 vCPU 16 GB 512 GB' = "CPC_B_4C_16RAM_512GB" 'Windows 365 Business 8 vCPU 32 GB 128 GB' = "CPC_B_8C_32RAM_128GB" 'Windows 365 Business 8 vCPU 32 GB 256 GB' = "CPC_B_8C_32RAM_256GB" 'Windows 365 Business 8 vCPU 32 GB 512 GB' = "CPC_B_8C_32RAM_512GB" 'Windows 365 Enterprise 1 vCPU 2 GB 64 GB' = "CPC_E_1C_2GB_64GB" 'Windows 365 Enterprise 2 vCPU 4 GB 128 GB' = "CPC_E_2C_4GB_128GB" 'Windows 365 Enterprise 2 vCPU 4 GB 128 GB (Preview)' = "CPC_LVL_1" 'Windows 365 Enterprise 2 vCPU 4 GB 256 GB' = "CPC_E_2C_4GB_256GB" 'Windows 365 Enterprise 2 vCPU 4 GB 64 GB' = "CPC_E_2C_4GB_64GB" 'Windows 365 Enterprise 2 vCPU 8 GB 128 GB' = "CPC_E_2C_8GB_128GB" 'Windows 365 Enterprise 2 vCPU 8 GB 128 GB (Preview)' = "CPC_LVL_2" 'Windows 365 Enterprise 2 vCPU 8 GB 256 GB' = "CPC_E_2C_8GB_256GB" 'Windows 365 Enterprise 4 vCPU 16 GB 128 GB' = "CPC_E_4C_16GB_128GB" 'Windows 365 Enterprise 4 vCPU 16 GB 256 GB' = "CPC_E_4C_16GB_256GB" 'Windows 365 Enterprise 4 vCPU 16 GB 256 GB (Preview)' = "CPC_LVL_3" 'Windows 365 Enterprise 4 vCPU 16 GB 512 GB' = "CPC_E_4C_16GB_512GB" 'Windows 365 Enterprise 8 vCPU 32 GB 128 GB' = "CPC_E_8C_32GB_128GB" 'Windows 365 Enterprise 8 vCPU 32 GB 256 GB' = "CPC_E_8C_32GB_256GB" 'Windows 365 Enterprise 8 vCPU 32 GB 512 GB' = "CPC_E_8C_32GB_512GB" 'Windows 365 Shared Use 2 vCPU 4 GB 128 GB' = "Windows_365_S_2vCPU_4GB_128GB" 'Windows 365 Shared Use 2 vCPU 4 GB 256 GB' = "Windows_365_S_2vCPU_4GB_256GB" 'Windows 365 Shared Use 2 vCPU 4 GB 64 GB' = "Windows_365_S_2vCPU_4GB_64GB" 'Windows 365 Shared Use 2 vCPU 8 GB 128 GB' = "Windows_365_S_2vCPU_8GB_128GB" 'Windows 365 Shared Use 2 vCPU 8 GB 256 GB' = "Windows_365_S_2vCPU_8GB_256GB" 'Windows 365 Shared Use 4 vCPU 16 GB 128 GB' = "Windows_365_S_4vCPU_16GB_128GB" 'Windows 365 Shared Use 4 vCPU 16 GB 256 GB' = "Windows_365_S_4vCPU_16GB_256GB" 'Windows 365 Shared Use 4 vCPU 16 GB 512 GB' = "Windows_365_S_4vCPU_16GB_512GB" 'Windows 365 Shared Use 8 vCPU 32 GB 128 GB' = "Windows_365_S_8vCPU_32GB_128GB" 'Windows 365 Shared Use 8 vCPU 32 GB 256 GB' = "Windows_365_S_8vCPU_32GB_256GB" 'Windows 365 Shared Use 8 vCPU 32 GB 512 GB' = "Windows_365_S_8vCPU_32GB_512GB" 'Windows Autopatch' = "Windows_Autopatch" 'Windows Store for Business' = "WINDOWS_STORE" 'Windows Store for Business EDU Faculty' = "WSFB_EDU_FACULTY" 'Windows Store for Business EDU Store_faculty' = "Windows Store for Business EDU Store_faculty" 'Windows Store Service' = "WINDOWS_STORE" 'Windows Update for Business Deployment Service' = "WINDOWSUPDATEFORBUSINESS_DEPLOYMENTSERVICE" 'YAMMER ENTERPRIS' = "YAMMER_ENTERPRISE" 'Yammer Enterprise' = "YAMMER_ENTERPRISE" 'Yammer for Academic' = "YAMMER_EDU" 'YAMMER MIDSIZE' = "YAMMER_MIDSIZE" 'YAMMER_ENTERPRISE' = "YAMMER_ENTERPRISE" 'YAMMER_MIDSIZE' = "YAMMER_MIDSIZE" } } Process { if (-not $ToSku) { $ConvertedLicenses = foreach ($LicenseToProcess in $License) { if ($LicenseToProcess -is [string]) { $L = $LicenseToProcess } elseif ($LicenseToProcess -is [Microsoft.Online.Administration.UserLicense]) { $L = $LicenseToProcess.AccountSkuId } else { continue } $L = $L -replace '.*(:)' $Conversion = $O365SKU[$L] if ($null -eq $Conversion) { $L } else { $Conversion } } } else { $ConvertedLicenses = :Outer foreach ($L in $License) { $Conversion = $SKUO365[$L] if ($null -eq $Conversion) { $L } else { $Conversion } } } if ($ReturnArray) { $ConvertedLicenses } else { $ConvertedLicenses -join $Separator } } End { } } function Convert-Size { # Original - https://techibee.com/powershell/convert-from-any-to-any-bytes-kb-mb-gb-tb-using-powershell/2376 # # Changelog - Modified 30.03.2018 - przemyslaw.klys at evotec.pl # - Added $Display Switch [cmdletbinding()] param( [validateset("Bytes", "KB", "MB", "GB", "TB")] [string]$From, [validateset("Bytes", "KB", "MB", "GB", "TB")] [string]$To, [Parameter(Mandatory = $true)] [double]$Value, [int]$Precision = 4, [switch]$Display ) switch ($From) { "Bytes" { $value = $Value } "KB" { $value = $Value * 1024 } "MB" { $value = $Value * 1024 * 1024 } "GB" { $value = $Value * 1024 * 1024 * 1024 } "TB" { $value = $Value * 1024 * 1024 * 1024 * 1024 } } switch ($To) { "Bytes" { return $value } "KB" { $Value = $Value / 1KB } "MB" { $Value = $Value / 1MB } "GB" { $Value = $Value / 1GB } "TB" { $Value = $Value / 1TB } } if ($Display) { return "$([Math]::Round($value,$Precision,[MidPointRounding]::AwayFromZero)) $To" } else { return [Math]::Round($value, $Precision, [MidPointRounding]::AwayFromZero) } } function Convert-TimeToDays { [CmdletBinding()] param ( $StartTime, $EndTime, #[nullable[DateTime]] $StartTime, # can't use this just yet, some old code uses strings in StartTime/EndTime. #[nullable[DateTime]] $EndTime, # After that's fixed will change this. [string] $Ignore = '*1601*' ) if ($null -ne $StartTime -and $null -ne $EndTime) { try { if ($StartTime -notlike $Ignore -and $EndTime -notlike $Ignore) { $Days = (New-TimeSpan -Start $StartTime -End $EndTime).Days } } catch { } } elseif ($null -ne $EndTime) { if ($StartTime -notlike $Ignore -and $EndTime -notlike $Ignore) { $Days = (New-TimeSpan -Start (Get-Date) -End ($EndTime)).Days } } elseif ($null -ne $StartTime) { if ($StartTime -notlike $Ignore -and $EndTime -notlike $Ignore) { $Days = (New-TimeSpan -Start $StartTime -End (Get-Date)).Days } } return $Days } function Convert-ToDateTime { [CmdletBinding()] param ( [string] $Timestring, [string] $Ignore = '*1601*' ) Try { $DateTime = ([datetime]::FromFileTime($Timestring)) } catch { $DateTime = $null } if ($null -eq $DateTime -or $DateTime -like $Ignore) { return $null } else { return $DateTime } } function Convert-ToTimeSpan { [CmdletBinding()] param ( [DateTime] $StartTime = (Get-Date), [DateTime] $EndTime ) if ($StartTime -and $EndTime) { try { $TimeSpan = (New-TimeSpan -Start $StartTime -End $EndTime) } catch { $TimeSpan = $null } } if ($null -ne $TimeSpan) { return $TimeSpan } else { return $null } } function Convert-TwoArraysIntoOne { [CmdletBinding()] param ( $Object, $ObjectToAdd ) $Value = for ($i = 0; $i -lt $Object.Count; $i++) { "$($Object[$i]) ($($ObjectToAdd[$i]))" } return $Value } Function Convert-UAC { <# .SYNOPSIS Converts values from Events into proper format .DESCRIPTION Converts values from Events into proper format .PARAMETER UAC Parameter description .EXAMPLE Convert-UAC -UAC '%%1793' Convert-UAC -UAC '1793' Output: TEMP_DUPLICATE_ACCOUNT, NORMAL_ACCOUNT, RESERVED Convert-UAC -UAC '1793', '1794' Convert-UAC -UAC '121793' Output: PASSWD_CANT_CHANGE, ENCRYPTED_TEXT_PWD_ALLOWED, TEMP_DUPLICATE_ACCOUNT, NORMAL_ACCOUNT, INTERDOMAIN_TRUST_ACCOUNT, WORKSTATION_TRUST_ACCOUNT, RESERVED, RESERVED, DONT_EXPIRE_PASSWORD Convert-UAC -UAC 'C:\Onet33' Output: Same input as output Convert-UAC -UAC '121793' -OutputPerLine Output: One entry per line PASSWD_CANT_CHANGE ENCRYPTED_TEXT_PWD_ALLOWED TEMP_DUPLICATE_ACCOUNT NORMAL_ACCOUNT INTERDOMAIN_TRUST_ACCOUNT WORKSTATION_TRUST_ACCOUNT RESERVED RESERVED DONT_EXPIRE_PASSWORD .NOTES General notes #> [CmdletBinding()] param( [string[]] $UAC, [string] $Separator ) $Output = foreach ($String in $UAC) { $NumberAsString = $String.Replace('%', '') -as [int] if ($null -eq $NumberAsString) { return $UAC } $PropertyFlags = @( "SCRIPT", "ACCOUNTDISABLE", "RESERVED", "HOMEDIR_REQUIRED", "LOCKOUT", "PASSWD_NOTREQD", "PASSWD_CANT_CHANGE", "ENCRYPTED_TEXT_PWD_ALLOWED", "TEMP_DUPLICATE_ACCOUNT", "NORMAL_ACCOUNT", "RESERVED", "INTERDOMAIN_TRUST_ACCOUNT", "WORKSTATION_TRUST_ACCOUNT", "SERVER_TRUST_ACCOUNT", "RESERVED", "RESERVED", "DONT_EXPIRE_PASSWORD", "MNS_LOGON_ACCOUNT", "SMARTCARD_REQUIRED", "TRUSTED_FOR_DELEGATION", "NOT_DELEGATED", "USE_DES_KEY_ONLY", "DONT_REQ_PREAUTH", "PASSWORD_EXPIRED", "TRUSTED_TO_AUTH_FOR_DELEGATION", "RESERVED", "PARTIAL_SECRETS_ACCOUNT" "RESERVED" "RESERVED" "RESERVED" "RESERVED" "RESERVED" ) 1..($PropertyFlags.Length) | Where-Object { $NumberAsString -bAnd [math]::Pow(2, $_) } | ForEach-Object { $PropertyFlags[$_] } } if ($Separator -eq '') { $Output } else { $Output -join $Separator } } function Convert-UserAccountControl { [cmdletBinding()] param( [alias('UAC')][int] $UserAccountControl, [string] $Separator ) $UserAccount = [ordered] @{ "SCRIPT" = 1 "ACCOUNTDISABLE" = 2 "HOMEDIR_REQUIRED" = 8 "LOCKOUT" = 16 "PASSWD_NOTREQD" = 32 "ENCRYPTED_TEXT_PWD_ALLOWED" = 128 "TEMP_DUPLICATE_ACCOUNT" = 256 "NORMAL_ACCOUNT" = 512 "INTERDOMAIN_TRUST_ACCOUNT" = 2048 "WORKSTATION_TRUST_ACCOUNT" = 4096 "SERVER_TRUST_ACCOUNT" = 8192 "DONT_EXPIRE_PASSWORD" = 65536 "MNS_LOGON_ACCOUNT" = 131072 "SMARTCARD_REQUIRED" = 262144 "TRUSTED_FOR_DELEGATION" = 524288 "NOT_DELEGATED" = 1048576 "USE_DES_KEY_ONLY" = 2097152 "DONT_REQ_PREAUTH" = 4194304 "PASSWORD_EXPIRED" = 8388608 "TRUSTED_TO_AUTH_FOR_DELEGATION" = 16777216 "PARTIAL_SECRETS_ACCOUNT" = 67108864 } $Output = foreach ($_ in $UserAccount.Keys) { $binaryAnd = $UserAccount[$_] -band $UserAccountControl if ($binaryAnd -ne "0") { $_ } } if ($Separator) { $Output -join $Separator } else { $Output } } function ConvertFrom-DistinguishedName { <# .SYNOPSIS Converts a Distinguished Name to CN, OU, Multiple OUs or DC .DESCRIPTION Converts a Distinguished Name to CN, OU, Multiple OUs or DC .PARAMETER DistinguishedName Distinguished Name to convert .PARAMETER ToOrganizationalUnit Converts DistinguishedName to Organizational Unit .PARAMETER ToDC Converts DistinguishedName to DC .PARAMETER ToDomainCN Converts DistinguishedName to Domain Canonical Name (CN) .PARAMETER ToCanonicalName Converts DistinguishedName to Canonical Name .EXAMPLE $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName -ToOrganizationalUnit Output: OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz .EXAMPLE $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName Output: Przemyslaw Klys .EXAMPLE ConvertFrom-DistinguishedName -DistinguishedName 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToMultipleOrganizationalUnit -IncludeParent Output: OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz OU=Production,DC=ad,DC=evotec,DC=xyz .EXAMPLE ConvertFrom-DistinguishedName -DistinguishedName 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToMultipleOrganizationalUnit Output: OU=Production,DC=ad,DC=evotec,DC=xyz .EXAMPLE $Con = @( 'CN=Windows Authorization Access Group,CN=Builtin,DC=ad,DC=evotec,DC=xyz' 'CN=Mmm,DC=elo,CN=nee,DC=RootDNSServers,CN=MicrosoftDNS,CN=System,DC=ad,DC=evotec,DC=xyz' 'CN=e6d5fd00-385d-4e65-b02d-9da3493ed850,CN=Operations,CN=DomainUpdates,CN=System,DC=ad,DC=evotec,DC=xyz' 'OU=Domain Controllers,DC=ad,DC=evotec,DC=pl' 'OU=Microsoft Exchange Security Groups,DC=ad,DC=evotec,DC=xyz' ) ConvertFrom-DistinguishedName -DistinguishedName $Con -ToLastName Output: Windows Authorization Access Group Mmm e6d5fd00-385d-4e65-b02d-9da3493ed850 Domain Controllers Microsoft Exchange Security Groups .EXAMPLEE ConvertFrom-DistinguishedName -DistinguishedName 'DC=ad,DC=evotec,DC=xyz' -ToCanonicalName ConvertFrom-DistinguishedName -DistinguishedName 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToCanonicalName ConvertFrom-DistinguishedName -DistinguishedName 'CN=test,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToCanonicalName Output: ad.evotec.xyz ad.evotec.xyz\Production\Users ad.evotec.xyz\Production\Users\test .NOTES General notes #> [CmdletBinding(DefaultParameterSetName = 'Default')] param( [Parameter(ParameterSetName = 'ToOrganizationalUnit')] [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')] [Parameter(ParameterSetName = 'ToDC')] [Parameter(ParameterSetName = 'ToDomainCN')] [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'ToLastName')] [Parameter(ParameterSetName = 'ToCanonicalName')] [alias('Identity', 'DN')][Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)][string[]] $DistinguishedName, [Parameter(ParameterSetName = 'ToOrganizationalUnit')][switch] $ToOrganizationalUnit, [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')][alias('ToMultipleOU')][switch] $ToMultipleOrganizationalUnit, [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')][switch] $IncludeParent, [Parameter(ParameterSetName = 'ToDC')][switch] $ToDC, [Parameter(ParameterSetName = 'ToDomainCN')][switch] $ToDomainCN, [Parameter(ParameterSetName = 'ToLastName')][switch] $ToLastName, [Parameter(ParameterSetName = 'ToCanonicalName')][switch] $ToCanonicalName ) Process { foreach ($Distinguished in $DistinguishedName) { if ($ToDomainCN) { $DN = $Distinguished -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1' $CN = $DN -replace ',DC=', '.' -replace "DC=" if ($CN) { $CN } } elseif ($ToOrganizationalUnit) { $Value = [Regex]::Match($Distinguished, '(?=OU=)(.*\n?)(?<=.)').Value if ($Value) { $Value } } elseif ($ToMultipleOrganizationalUnit) { if ($IncludeParent) { $Distinguished } while ($true) { $Distinguished = $Distinguished -replace '^.+?,(?=..=)' if ($Distinguished -match '^DC=') { break } $Distinguished } } elseif ($ToDC) { $Value = $Distinguished -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1' if ($Value) { $Value } } elseif ($ToLastName) { $NewDN = $Distinguished -split ",DC=" if ($NewDN[0].Contains(",OU=")) { [Array] $ChangedDN = $NewDN[0] -split ",OU=" } elseif ($NewDN[0].Contains(",CN=")) { [Array] $ChangedDN = $NewDN[0] -split ",CN=" } else { [Array] $ChangedDN = $NewDN[0] } if ($ChangedDN[0].StartsWith('CN=')) { $ChangedDN[0] -replace 'CN=', '' } else { $ChangedDN[0] -replace 'OU=', '' } } elseif ($ToCanonicalName) { $Domain = $null $Rest = $null foreach ($O in $Distinguished -split '(?<!\\),') { if ($O -match '^DC=') { $Domain += $O.Substring(3) + '.' } else { $Rest = $O.Substring(3) + '\' + $Rest } } if ($Domain -and $Rest) { $Domain.Trim('.') + '\' + ($Rest.TrimEnd('\') -replace '\\,', ',') } elseif ($Domain) { $Domain.Trim('.') } elseif ($Rest) { $Rest.TrimEnd('\') -replace '\\,', ',' } } else { $Regex = '^CN=(?<cn>.+?)(?<!\\),(?<ou>(?:(?:OU|CN).+?(?<!\\),)+(?<dc>DC.+?))$' $Found = $Distinguished -match $Regex if ($Found) { $Matches.cn } } } } } function ConvertFrom-ErrorRecord { param ( # we receive either a legit error record... [Management.Automation.ErrorRecord[]] [Parameter( Mandatory, ValueFromPipeline, ParameterSetName = 'ErrorRecord')] $ErrorRecord, # ...or a special stop exception which is raised by # cmdlets with -ErrorAction Stop [Management.Automation.ActionPreferenceStopException[]] [Parameter( Mandatory, ValueFromPipeline, ParameterSetName = 'StopException')] $Exception ) process { if ($PSCmdlet.ParameterSetName -eq 'StopException') { $ErrorRecord = $Exception.ErrorRecord } $ErrorRecord | ForEach-Object { [PSCustomObject]@{ Exception = $_.Exception.Message Reason = $_.CategoryInfo.Reason Target = $_.CategoryInfo.TargetName Script = $_.InvocationInfo.ScriptName Line = $_.InvocationInfo.ScriptLineNumber Column = $_.InvocationInfo.OffsetInLine } } } } function ConvertFrom-LanguageCode { [cmdletBinding()] param( [string] $LanguageCode ) $LanguageCodeDictionary = @{ '1' = "Arabic" '4' = "Chinese (Simplified)?? China" '9' = "English" '1025' = "Arabic (Saudi Arabia)" '1026' = "Bulgarian" '1027' = "Catalan" '1028' = "Chinese (Traditional) Taiwan" '1029' = "Czech" '1030' = "Danish" '1031' = "German (Germany)" '1032' = "Greek" '1033' = "English (United States)" '1034' = "Spanish (Traditional Sort)" '1035' = "Finnish" '1036' = "French (France)" '1037' = "Hebrew" '1038' = "Hungarian" '1039' = "Icelandic" '1040' = "Italian (Italy)" '1041' = "Japanese" '1042' = "Korean" '1043' = "Dutch (Netherlands)" '1044' = "Norwegian (Bokmal)" '1045' = "Polish" '1046' = "Portuguese (Brazil)" '1047' = "Rhaeto-Romanic" '1048' = "Romanian" '1049' = "Russian" '1050' = "Croatian" '1051' = "Slovak" '1052' = "Albanian" '1053' = "Swedish" '1054' = "Thai" '1055' = "Turkish" '1056' = "Urdu" '1057' = "Indonesian" '1058' = "Ukrainian" '1059' = "Belarusian" '1060' = "Slovenian" '1061' = "Estonian" '1062' = "Latvian" '1063' = "Lithuanian" '1065' = "Persian" '1066' = "Vietnamese" '1069' = "Basque (Basque)" '1070' = "Serbian" '1071' = "Macedonian (FYROM)" '1072' = "Sutu" '1073' = "Tsonga" '1074' = "Tswana" '1076' = "Xhosa" '1077' = "Zulu" '1078' = "Afrikaans" '1080' = "Faeroese" '1081' = "Hindi" '1082' = "Maltese" '1084' = "Scottish Gaelic (United Kingdom)" '1085' = "Yiddish" '1086' = "Malay (Malaysia)" '2049' = "Arabic (Iraq)" '2052' = "Chinese (Simplified) PRC" '2055' = "German (Switzerland)" '2057' = "English (United Kingdom)" '2058' = "Spanish (Mexico)" '2060' = "French (Belgium)" '2064' = "Italian (Switzerland)" '2067' = "Dutch (Belgium)" '2068' = "Norwegian (Nynorsk)" '2070' = "Portuguese (Portugal)" '2072' = "Romanian (Moldova)" '2073' = "Russian (Moldova)" '2074' = "Serbian (Latin)" '2077' = "Swedish (Finland)" '3073' = "Arabic (Egypt)" '3076' = "Chinese Traditional (Hong Kong SAR)" '3079' = "German (Austria)" '3081' = "English (Australia)" '3082' = "Spanish (International Sort)" '3084' = "French (Canada)" '3098' = "Serbian (Cyrillic)" '4097' = "Arabic (Libya)" '4100' = "Chinese Simplified (Singapore)" '4103' = "German (Luxembourg)" '4105' = "English (Canada)" '4106' = "Spanish (Guatemala)" '4108' = "French (Switzerland)" '5121' = "Arabic (Algeria)" '5127' = "German (Liechtenstein)" '5129' = "English (New Zealand)" '5130' = "Spanish (Costa Rica)" '5132' = "French (Luxembourg)" '6145' = "Arabic (Morocco)" '6153' = "English (Ireland)" '6154' = "Spanish (Panama)" '7169' = "Arabic (Tunisia)" '7177' = "English (South Africa)" '7178' = "Spanish (Dominican Republic)" '8193' = "Arabic (Oman)" '8201' = "English (Jamaica)" '8202' = "Spanish (Venezuela)" '9217' = "Arabic (Yemen)" '9226' = "Spanish (Colombia)" '10241' = "Arabic (Syria)" '10249' = "English (Belize)" '10250' = "Spanish (Peru)" '11265' = "Arabic (Jordan)" '11273' = "English (Trinidad)" '11274' = "Spanish (Argentina)" '12289' = "Arabic (Lebanon)" '12298' = "Spanish (Ecuador)" '13313' = "Arabic (Kuwait)" '13322' = "Spanish (Chile)" '14337' = "Arabic (U.A.E.)" '14346' = "Spanish (Uruguay)" '15361' = "Arabic (Bahrain)" '15370' = "Spanish (Paraguay)" '16385' = "Arabic (Qatar)" '16394' = "Spanish (Bolivia)" '17418' = "Spanish (El Salvador)" '18442' = "Spanish (Honduras)" '19466' = "Spanish (Nicaragua)" '20490' = "Spanish (Puerto Rico)" } $Output = $LanguageCodeDictionary[$LanguageCode] if ($Output) { $Output } else { "Unknown (Undocumented)" } } function ConvertFrom-NetbiosName { [cmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)] [string[]] $Identity ) process { foreach ($Ident in $Identity) { if ($Ident -like '*\*') { $NetbiosWithObject = $Ident -split "\\" if ($NetbiosWithObject.Count -eq 2) { $LDAPQuery = ([ADSI]"LDAP://$($NetbiosWithObject[0])") $DomainName = ConvertFrom-DistinguishedName -DistinguishedName $LDAPQuery.distinguishedName -ToDomainCN [PSCustomObject] @{ DomainName = $DomainName Name = $NetbiosWithObject[1] } } else { [PSCustomObject] @{ DomainName = '' Name = $Ident } } } else { [PSCustomObject] @{ DomainName = '' Name = $Ident } } } } } function ConvertFrom-ObjectToString { <# .SYNOPSIS Helps with converting given objects to their string representation. .DESCRIPTION Helps with converting given objects to their string representation. .PARAMETER Objects Objects to convert to string representation. .PARAMETER IncludeProperties Properties to include in the string representation. .PARAMETER ExcludeProperties Properties to exclude from the string representation. .PARAMETER OutputType Type of the output object. Options are: Hashtable, Ordered, PSCustomObject. If not specified, the output type is hashtable (string) .PARAMETER NumbersAsString If specified, numbers are converted to strings. Default is number are presented in their (unquoted) numerica form .PARAMETER QuotePropertyNames If specified, all property names are quoted. Default: property names are quoted only if they contain spaces. .PARAMETER DateTimeFormat Format for DateTime values. Default: 'yyyy-MM-dd HH:mm:ss' .EXAMPLE Get-Process -Name "PowerShell" | ConvertFrom-ObjectToString -IncludeProperties 'ProcessName', 'Id', 'Handles' OUTPUT: @{ 'Handles' = '543' 'Id' = '8092' 'ProcessName' = 'powershell' } @{ 'Handles' = '636' 'Id' = '11360' 'ProcessName' = 'powershell' } .NOTES General notes #> [CmdletBinding()] param( [parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Mandatory)][Array] $Objects, [string[]] $IncludeProperties, [string[]] $ExcludeProperties, [ValidateSet('Hashtable', 'Ordered', 'PSCustomObject')][string] $OutputType = 'Hashtable', [switch] $NumbersAsString, [switch] $QuotePropertyNames, [string] $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' ) begin { if ($OutputType -eq 'Hashtable') { $Type = '' } elseif ($OutputType -eq 'Ordered') { $Type = '[Ordered] ' } else { $Type = '[PSCustomObject] ' } } process { filter IsNumeric() { return $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] ` -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] ` -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] } function GetFormattedPair () { # returns 'key' = <valuestring> or just <valuestring> if key is empty # valuestring is either $null, '<string>', or number param ( [string] $Key, [object] $Value ) if ($key -eq '') { $left = '' } elseif ($key -match '\s' -or $QuotePropertyNames) { $left = "'$Key' = " } else { $left = "$Key = " } if ($null -eq $value) { "$left`$null" } elseif ($Value -is [System.Collections.IList]) { $arrayStrings = foreach ($element in $Object.$Key) { GetFormattedPair -Key '' -Value $element } "$left@(" + ($arrayStrings -join ', ') + ")" } elseif ($Value -is [System.Collections.IDictionary]) { if ($IncludeProperties -and $Key -notin $IncludeProperties) { return } if ($Key -in $ExcludeProperties) { return } $propertyString = foreach ($Key in $Value.Keys) { GetFormattedPair -Key $key -Value $Value[$key] } "$left@{" + ($propertyString -join '; ') + "}" } elseif ($value -is [DateTime]) { "$left'$($Value.ToString($DateTimeFormat))'" } elseif (($value | IsNumeric) -and -not $NumbersAsString) { "$left$($Value)" } else { "$left'$($Value)'" } } foreach ($Object in $Objects) { if ($Object -is [System.Collections.IDictionary]) { Write-Host Write-Host -Object "$Type@{" foreach ($Key in $Object.Keys) { if ($IncludeProperties -and $Key -notin $IncludeProperties) { continue } if ($Key -in $ExcludeProperties) { continue } Write-Host -Object " $(GetFormattedPair -Key $Key -Value $Object.$Key)" -ForegroundColor Cyan } Write-Host -Object "}" } elseif ($Object -is [Object]) { Write-Host Write-Host -Object "$Type@{" foreach ($Key in $Object.PSObject.Properties.Name) { if ($IncludeProperties -and $Key -notin $IncludeProperties) { continue } if ($Key -in $ExcludeProperties) { continue } Write-Host -Object " $(GetFormattedPair -Key $Key -Value $Object.$Key)" -ForegroundColor Cyan } Write-Host -Object "}" } else { Write-Host -Object $Object } } } } Function ConvertFrom-OperationType { param ( [string] $OperationType ) $Known = @{ '%%14674' = 'Value Added' '%%14675' = 'Value Deleted' '%%14676' = 'Unknown' } foreach ($id in $OperationType) { if ($name = $Known[$id]) { return $name } } return $OperationType } function ConvertFrom-ScriptBlock { [CmdletBinding()] param( [ScriptBlock] $ScriptBlock ) [Array] $Output = foreach ($Line in $ScriptBlock.Ast.EndBlock.Statements.Extent) { [string] $Line + [System.Environment]::NewLine } return $Output } function ConvertFrom-SID { <# .SYNOPSIS Small command that can resolve SID values .DESCRIPTION Small command that can resolve SID values .PARAMETER SID Value to resolve .PARAMETER OnlyWellKnown Only resolve SID when it's well know SID. Otherwise return $null .PARAMETER OnlyWellKnownAdministrative Only resolve SID when it's administrative well know SID. Otherwise return $null .PARAMETER DoNotResolve Uses only dicrionary values without querying AD .EXAMPLE ConvertFrom-SID -SID 'S-1-5-8', 'S-1-5-9', 'S-1-5-11', 'S-1-5-18', 'S-1-1-0' -DoNotResolve .NOTES General notes #> [cmdletbinding(DefaultParameterSetName = 'Standard')] param( [Parameter(ParameterSetName = 'Standard')] [Parameter(ParameterSetName = 'OnlyWellKnown')] [Parameter(ParameterSetName = 'OnlyWellKnownAdministrative')] [string[]] $SID, [Parameter(ParameterSetName = 'OnlyWellKnown')][switch] $OnlyWellKnown, [Parameter(ParameterSetName = 'OnlyWellKnownAdministrative')][switch] $OnlyWellKnownAdministrative, [Parameter(ParameterSetName = 'Standard')][switch] $DoNotResolve ) $WellKnownAdministrative = @{ 'S-1-5-18' = [PSCustomObject] @{ Name = 'NT AUTHORITY\SYSTEM' SID = 'S-1-5-18' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-5-32-544' = [PSCustomObject] @{ Name = 'BUILTIN\Administrators' SID = 'S-1-5-32-544' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } } $wellKnownSIDs = @{ 'S-1-0' = [PSCustomObject] @{ Name = 'Null AUTHORITY' SID = 'S-1-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-0-0' = [PSCustomObject] @{ Name = 'NULL SID' SID = 'S-1-0-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-1' = [PSCustomObject] @{ Name = 'WORLD AUTHORITY' SID = 'S-1-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-1-0' = [PSCustomObject] @{ Name = 'Everyone' SID = 'S-1-1-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-2' = [PSCustomObject] @{ Name = 'LOCAL AUTHORITY' SID = 'S-1-2' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-2-0' = [PSCustomObject] @{ Name = 'LOCAL' SID = 'S-1-2-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-2-1' = [PSCustomObject] @{ Name = 'CONSOLE LOGON' SID = 'S-1-2-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3' = [PSCustomObject] @{ Name = 'CREATOR AUTHORITY' SID = 'S-1-3' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-0' = [PSCustomObject] @{ Name = 'CREATOR OWNER' SID = 'S-1-3-0' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-3-1' = [PSCustomObject] @{ Name = 'CREATOR GROUP' SID = 'S-1-3-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-2' = [PSCustomObject] @{ Name = 'CREATOR OWNER SERVER' SID = 'S-1-3-2' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-3' = [PSCustomObject] @{ Name = 'CREATOR GROUP SERVER' SID = 'S-1-3-3' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-4' = [PSCustomObject] @{ Name = 'OWNER RIGHTS' SID = 'S-1-3-4' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-0' = [PSCustomObject] @{ Name = 'NT SERVICE\ALL SERVICES' SID = 'S-1-5-80-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-4' = [PSCustomObject] @{ Name = 'Non-unique Authority' SID = 'S-1-4' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5' = [PSCustomObject] @{ Name = 'NT AUTHORITY' SID = 'S-1-5' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-1' = [PSCustomObject] @{ Name = 'NT AUTHORITY\DIALUP' SID = 'S-1-5-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-2' = [PSCustomObject] @{ Name = 'NT AUTHORITY\NETWORK' SID = 'S-1-5-2' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-3' = [PSCustomObject] @{ Name = 'NT AUTHORITY\BATCH' SID = 'S-1-5-3' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-4' = [PSCustomObject] @{ Name = 'NT AUTHORITY\INTERACTIVE' SID = 'S-1-5-4' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-6' = [PSCustomObject] @{ Name = 'NT AUTHORITY\SERVICE' SID = 'S-1-5-6' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-7' = [PSCustomObject] @{ Name = 'NT AUTHORITY\ANONYMOUS LOGON' SID = 'S-1-5-7' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-8' = [PSCustomObject] @{ Name = 'NT AUTHORITY\PROXY' SID = 'S-1-5-8' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-9' = [PSCustomObject] @{ Name = 'NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS' SID = 'S-1-5-9' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-10' = [PSCustomObject] @{ Name = 'NT AUTHORITY\SELF' SID = 'S-1-5-10' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-11' = [PSCustomObject] @{ Name = 'NT AUTHORITY\Authenticated Users' SID = 'S-1-5-11' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-12' = [PSCustomObject] @{ Name = 'NT AUTHORITY\RESTRICTED' SID = 'S-1-5-12' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-13' = [PSCustomObject] @{ Name = 'NT AUTHORITY\TERMINAL SERVER USER' SID = 'S-1-5-13' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-14' = [PSCustomObject] @{ Name = 'NT AUTHORITY\REMOTE INTERACTIVE LOGON' SID = 'S-1-5-14' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-15' = [PSCustomObject] @{ Name = 'NT AUTHORITY\This Organization' SID = 'S-1-5-15' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-17' = [PSCustomObject] @{ Name = 'NT AUTHORITY\IUSR' SID = 'S-1-5-17' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-18' = [PSCustomObject] @{ Name = 'NT AUTHORITY\SYSTEM' SID = 'S-1-5-18' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-5-19' = [PSCustomObject] @{ Name = 'NT AUTHORITY\LOCAL SERVICE' SID = 'S-1-5-19' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-20' = [PSCustomObject] @{ Name = 'NT AUTHORITY\NETWORK SERVICE' SID = 'S-1-5-20' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-544' = [PSCustomObject] @{ Name = 'BUILTIN\Administrators' SID = 'S-1-5-32-544' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-5-32-545' = [PSCustomObject] @{ Name = 'BUILTIN\Users' SID = 'S-1-5-32-545' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-546' = [PSCustomObject] @{ Name = 'BUILTIN\Guests' SID = 'S-1-5-32-546' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-547' = [PSCustomObject] @{ Name = 'BUILTIN\Power Users' SID = 'S-1-5-32-547' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-548' = [PSCustomObject] @{ Name = 'BUILTIN\Account Operators' SID = 'S-1-5-32-548' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-549' = [PSCustomObject] @{ Name = 'BUILTIN\Server Operators' SID = 'S-1-5-32-549' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-550' = [PSCustomObject] @{ Name = 'BUILTIN\Print Operators' SID = 'S-1-5-32-550' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-551' = [PSCustomObject] @{ Name = 'BUILTIN\Backup Operators' SID = 'S-1-5-32-551' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-552' = [PSCustomObject] @{ Name = 'BUILTIN\Replicators' SID = 'S-1-5-32-552' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-64-10' = [PSCustomObject] @{ Name = 'NT AUTHORITY\NTLM Authentication' SID = 'S-1-5-64-10' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-64-14' = [PSCustomObject] @{ Name = 'NT AUTHORITY\SChannel Authentication' SID = 'S-1-5-64-14' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-64-21' = [PSCustomObject] @{ Name = 'NT AUTHORITY\Digest Authentication' SID = 'S-1-5-64-21' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80' = [PSCustomObject] @{ Name = 'NT SERVICE' SID = 'S-1-5-80' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-83-0' = [PSCustomObject] @{ Name = 'NT VIRTUAL MACHINE\Virtual Machines' SID = 'S-1-5-83-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-0' = [PSCustomObject] @{ Name = 'Untrusted Mandatory Level' SID = 'S-1-16-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-4096' = [PSCustomObject] @{ Name = 'Low Mandatory Level' SID = 'S-1-16-4096' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-8192' = [PSCustomObject] @{ Name = 'Medium Mandatory Level' SID = 'S-1-16-8192' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-8448' = [PSCustomObject] @{ Name = 'Medium Plus Mandatory Level' SID = 'S-1-16-8448' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-12288' = [PSCustomObject] @{ Name = 'High Mandatory Level' SID = 'S-1-16-12288' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-16384' = [PSCustomObject] @{ Name = 'System Mandatory Level' SID = 'S-1-16-16384' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-20480' = [PSCustomObject] @{ Name = 'Protected Process Mandatory Level' SID = 'S-1-16-20480' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-28672' = [PSCustomObject] @{ Name = 'Secure Process Mandatory Level' SID = 'S-1-16-28672' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-554' = [PSCustomObject] @{ Name = 'BUILTIN\Pre-Windows 2000 Compatible Access' SID = 'S-1-5-32-554' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-555' = [PSCustomObject] @{ Name = 'BUILTIN\Remote Desktop Users' SID = 'S-1-5-32-555' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-556' = [PSCustomObject] @{ Name = 'BUILTIN\Network Configuration Operators' SID = 'S-1-5-32-556' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-557' = [PSCustomObject] @{ Name = 'BUILTIN\Incoming Forest Trust Builders' SID = 'S-1-5-32-557' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-558' = [PSCustomObject] @{ Name = 'BUILTIN\Performance Monitor Users' SID = 'S-1-5-32-558' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-559' = [PSCustomObject] @{ Name = 'BUILTIN\Performance Log Users' SID = 'S-1-5-32-559' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-560' = [PSCustomObject] @{ Name = 'BUILTIN\Windows Authorization Access Group' SID = 'S-1-5-32-560' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-561' = [PSCustomObject] @{ Name = 'BUILTIN\Terminal Server License Servers' SID = 'S-1-5-32-561' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-562' = [PSCustomObject] @{ Name = 'BUILTIN\Distributed COM Users' SID = 'S-1-5-32-562' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-568' = [PSCustomObject] @{ Name = 'BUILTIN\IIS_IUSRS' SID = 'S-1-5-32-568' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-569' = [PSCustomObject] @{ Name = 'BUILTIN\Cryptographic Operators' SID = 'S-1-5-32-569' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-573' = [PSCustomObject] @{ Name = 'BUILTIN\Event Log Readers' SID = 'S-1-5-32-573' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-574' = [PSCustomObject] @{ Name = 'BUILTIN\Certificate Service DCOM Access' SID = 'S-1-5-32-574' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-575' = [PSCustomObject] @{ Name = 'BUILTIN\RDS Remote Access Servers' SID = 'S-1-5-32-575' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-576' = [PSCustomObject] @{ Name = 'BUILTIN\RDS Endpoint Servers' SID = 'S-1-5-32-576' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-577' = [PSCustomObject] @{ Name = 'BUILTIN\RDS Management Servers' SID = 'S-1-5-32-577' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-578' = [PSCustomObject] @{ Name = 'BUILTIN\Hyper-V Administrators' SID = 'S-1-5-32-578' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-579' = [PSCustomObject] @{ Name = 'BUILTIN\Access Control Assistance Operators' SID = 'S-1-5-32-579' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-580' = [PSCustomObject] @{ Name = 'BUILTIN\Remote Management Users' SID = 'S-1-5-32-580' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-90-0' = [PSCustomObject] @{ Name = 'Window Manager\Window Manager Group' SID = 'S-1-5-90-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-3139157870-2983391045-3678747466-658725712-1809340420' = [PSCustomObject] @{ Name = 'NT SERVICE\WdiServiceHost' SID = 'S-1-5-80-3139157870-2983391045-3678747466-658725712-1809340420' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-3880718306-3832830129-1677859214-2598158968-1052248003' = [PSCustomObject] @{ Name = 'NT SERVICE\MSSQLSERVER' SID = 'S-1-5-80-3139157870-2983391045-3678747466-658725712-1809340420' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-344959196-2060754871-2302487193-2804545603-1466107430' = [PSCustomObject] @{ Name = 'NT SERVICE\SQLSERVERAGENT' SID = 'S-1-5-80-344959196-2060754871-2302487193-2804545603-1466107430' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-2652535364-2169709536-2857650723-2622804123-1107741775' = [PSCustomObject] @{ Name = 'NT SERVICE\SQLTELEMETRY' SID = 'S-1-5-80-2652535364-2169709536-2857650723-2622804123-1107741775' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-3245704983-3664226991-764670653-2504430226-901976451' = [PSCustomObject] @{ Name = 'NT SERVICE\ADSync' SID = 'S-1-5-80-3245704983-3664226991-764670653-2504430226-901976451' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-4215458991-2034252225-2287069555-1155419622-2701885083' = [PSCustomObject] @{ Name = 'NT Service\himds' SID = 'S-1-5-80-4215458991-2034252225-2287069555-1155419622-2701885083' DomainName = '' Type = 'WellKnownGroup' Error = '' } } foreach ($S in $SID) { if ($OnlyWellKnownAdministrative) { if ($WellKnownAdministrative[$S]) { $WellKnownAdministrative[$S] } } elseif ($OnlyWellKnown) { if ($wellKnownSIDs[$S]) { $wellKnownSIDs[$S] } } else { if ($wellKnownSIDs[$S]) { $wellKnownSIDs[$S] } else { if ($DoNotResolve) { if ($S -like "S-1-5-21-*-519" -or $S -like "S-1-5-21-*-512") { [PSCustomObject] @{ Name = $S SID = $S DomainName = '' Type = 'Administrative' Error = '' } } else { [PSCustomObject] @{ Name = $S SID = $S DomainName = '' Error = '' Type = 'NotAdministrative' } } } else { if (-not $Script:LocalComputerSID) { $Script:LocalComputerSID = Get-LocalComputerSid } try { if ($S.Length -le 18) { $Type = 'NotAdministrative' $Name = (([System.Security.Principal.SecurityIdentifier]::new($S)).Translate([System.Security.Principal.NTAccount])).Value [PSCustomObject] @{ Name = $Name SID = $S DomainName = '' Type = $Type Error = '' } } else { if ($S -like "S-1-5-21-*-519" -or $S -like "S-1-5-21-*-512") { $Type = 'Administrative' } else { $Type = 'NotAdministrative' } $Name = (([System.Security.Principal.SecurityIdentifier]::new($S)).Translate([System.Security.Principal.NTAccount])).Value [PSCustomObject] @{ Name = $Name SID = $S DomainName = if ($S -like "$Script:LocalComputerSID*") { '' } else { (ConvertFrom-NetbiosName -Identity $Name).DomainName } Type = $Type Error = '' } } } catch { [PSCustomObject] @{ Name = $S SID = $S DomainName = '' Error = $_.Exception.Message -replace [environment]::NewLine, ' ' Type = 'Unknown' } } } } } } } function ConvertFrom-X500Address { <# .EXAMPLE By default returns string without @evotec.pl in the end. This is because the string from NDR needs domain name removed to be able to add it back to Exchange ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=5209048016da47689b4421790ad1763f-EVOTEC+20PL+20Recepcja+20G@evotec.pl' ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=8bcad655e07c46788fe1f796162cd87f-EVOTEC+20PL+20Recepcja+20G@evotec.pl' ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=0d4540e9a8f845d798625c9c0ad753bf-Test-All-Group@evotec.pl' ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=0d4540e9a8f845d798625c9c0ad753bf-Test-All-Group@evotec.pl' .EXAMPLE ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=5209048016da47689b4421790ad1763f-EVOTEC+20PL+20Recepcja+20G@evotec.pl' -Full ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=8bcad655e07c46788fe1f796162cd87f-EVOTEC+20PL+20Recepcja+20G@evotec.pl' -Full ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=0d4540e9a8f845d798625c9c0ad753bf-Test-All-Group@evotec.pl' -Full ConvertFrom-X500Address -IMCEAEXString 'IMCEAEX-_o=AD_ou=Exchange+20Administrative+20Group+20+28FYDIBOHF23SPDLT+29_cn=Recipients_cn=0d4540e9a8f845d798625c9c0ad753bf-Test-All-Group@evotec.pl' -Full #> param( [string] $IMCEAEXString, [switch] $Full ) $Final = $IMCEAEXString.Replace("IMCEAEX-", "").Replace("_", "/").Replace("+20", " ").Replace("+28", "(").Replace("+29", ")").Replace("+2E", ".").Replace("+2C", ",").Replace("+5F", "_") if ($Full) { return $Final } else { return ($Final -split '@')[0] } } function ConvertTo-DistinguishedName { <# .SYNOPSIS Converts CanonicalName to DistinguishedName .DESCRIPTION Converts CanonicalName to DistinguishedName for 3 different options .PARAMETER CanonicalName One or multiple canonical names .PARAMETER ToOU Converts CanonicalName to OrganizationalUnit DistinguishedName .PARAMETER ToObject Converts CanonicalName to Full Object DistinguishedName .PARAMETER ToDomain Converts CanonicalName to Domain DistinguishedName .EXAMPLE $CanonicalObjects = @( 'ad.evotec.xyz/Production/Groups/Security/ITR03_AD Admins' 'ad.evotec.xyz/Production/Accounts/Special/SADM Testing 2' ) $CanonicalOU = @( 'ad.evotec.xyz/Production/Groups/Security/NetworkAdministration' 'ad.evotec.xyz/Production' ) $CanonicalDomain = @( 'ad.evotec.xyz/Production/Groups/Security/ITR03_AD Admins' 'ad.evotec.pl' 'ad.evotec.xyz' 'test.evotec.pl' 'ad.evotec.xyz/Production' ) $CanonicalObjects | ConvertTo-DistinguishedName -ToObject $CanonicalOU | ConvertTo-DistinguishedName -ToOU $CanonicalDomain | ConvertTo-DistinguishedName -ToDomain Output: CN=ITR03_AD Admins,OU=Security,OU=Groups,OU=Production,DC=ad,DC=evotec,DC=xyz CN=SADM Testing 2,OU=Special,OU=Accounts,OU=Production,DC=ad,DC=evotec,DC=xyz Output2: OU=NetworkAdministration,OU=Security,OU=Groups,OU=Production,DC=ad,DC=evotec,DC=xyz OU=Production,DC=ad,DC=evotec,DC=xyz Output3: DC=ad,DC=evotec,DC=xyz DC=ad,DC=evotec,DC=pl DC=ad,DC=evotec,DC=xyz DC=test,DC=evotec,DC=pl DC=ad,DC=evotec,DC=xyz .NOTES General notes #> [cmdletBinding(DefaultParameterSetName = 'ToDomain')] param( [Parameter(ParameterSetName = 'ToOU')] [Parameter(ParameterSetName = 'ToObject')] [Parameter(ParameterSetName = 'ToDomain')] [alias('Identity', 'CN')][Parameter(ValueFromPipeline, Mandatory, ValueFromPipelineByPropertyName, Position = 0)][string[]] $CanonicalName, [Parameter(ParameterSetName = 'ToOU')][switch] $ToOU, [Parameter(ParameterSetName = 'ToObject')][switch] $ToObject, [Parameter(ParameterSetName = 'ToDomain')][switch] $ToDomain ) Process { foreach ($CN in $CanonicalName) { if ($ToObject) { $ADObject = $CN.Replace(',', '\,').Split('/') [string]$DN = "CN=" + $ADObject[$ADObject.count - 1] for ($i = $ADObject.count - 2; $i -ge 1; $i--) { $DN += ",OU=" + $ADObject[$i] } $ADObject[0].split(".") | ForEach-Object { $DN += ",DC=" + $_ } } elseif ($ToOU) { $ADObject = $CN.Replace(',', '\,').Split('/') [string]$DN = "OU=" + $ADObject[$ADObject.count - 1] for ($i = $ADObject.count - 2; $i -ge 1; $i--) { $DN += ",OU=" + $ADObject[$i] } $ADObject[0].split(".") | ForEach-Object { $DN += ",DC=" + $_ } } else { $ADObject = $CN.Replace(',', '\,').Split('/') $DN = 'DC=' + $ADObject[0].Replace('.', ',DC=') } $DN } } } function ConvertTo-FlatHashtable { <# .SYNOPSIS Converts nested hashtable into flat hashtable using delimiter .DESCRIPTION Converts nested hashtable into flat hashtable using delimiter .PARAMETER InputObject Ordered Dictionary or Hashtable .PARAMETER Delimiter Delimiter for key name when merging nested hashtables. By default colon is used .EXAMPLE ConvertTo-FlatHashTable -InputObject ([ordered] @{ RootEntry = 'OK1' Parent = @{ Child1 = 'OK2' Child2 = 'Ok3' } ParentDifferent = @{ Child7 = 'NotOk' Child8 = @{ Child10 = 'OKLetsSee' Child11 = @{ SpecialCase = 'Oooop' } } } }) | Format-Table * .NOTES General notes #> [CmdletBinding()] param( [System.Collections.IDictionary] $InputObject, [string] $Delimiter = ':', [Parameter(DontShow)][string] $Name ) Begin { $Output = [ordered] @{} } Process { foreach ($Key in $InputObject.Keys) { if ($Name) { $MergedName = "$Name$($Delimiter)$Key" } else { $MergedName = $Key } if ($InputObject[$Key] -is [System.Collections.IDictionary]) { $Found = ConvertTo-FlatHashtable -InputObject $InputObject[$Key] -Name $MergedName $Output = $Output + $Found } else { $Output[$MergedName] = $InputObject[$Key] } } } End { $Output } } Function ConvertTo-FlatObject { <# .SYNOPSIS Flattends a nested object into a single level object. .DESCRIPTION Flattends a nested object into a single level object. .PARAMETER Objects The object (or objects) to be flatten. .PARAMETER Separator The separator used between the recursive property names .PARAMETER Base The first index name of an embedded array: - 1, arrays will be 1 based: <Parent>.1, <Parent>.2, <Parent>.3, … - 0, arrays will be 0 based: <Parent>.0, <Parent>.1, <Parent>.2, … - "", the first item in an array will be unnamed and than followed with 1: <Parent>, <Parent>.1, <Parent>.2, … .PARAMETER Depth The maximal depth of flattening a recursive property. Any negative value will result in an unlimited depth and could cause a infinitive loop. .PARAMETER Uncut The maximal depth of flattening a recursive property. Any negative value will result in an unlimited depth and could cause a infinitive loop. .PARAMETER ExcludeProperty The propertys to be excluded from the output. .EXAMPLE $Object3 = [PSCustomObject] @{ "Name" = "Przemyslaw Klys" "Age" = "30" "Address" = @{ "Street" = "Kwiatowa" "City" = "Warszawa" "Country" = [ordered] @{ "Name" = "Poland" } List = @( [PSCustomObject] @{ "Name" = "Adam Klys" "Age" = "32" } [PSCustomObject] @{ "Name" = "Justyna Klys" "Age" = "33" } [PSCustomObject] @{ "Name" = "Justyna Klys" "Age" = 30 } [PSCustomObject] @{ "Name" = "Justyna Klys" "Age" = $null } ) } ListTest = @( [PSCustomObject] @{ "Name" = "Sława Klys" "Age" = "33" } ) } $Object3 | ConvertTo-FlatObject .NOTES Based on https://powersnippets.com/convertto-flatobject/ #> [CmdletBinding()] Param ( [Parameter(ValueFromPipeLine)][Object[]]$Objects, [String]$Separator = ".", [ValidateSet("", 0, 1)]$Base = 1, [int]$Depth = 5, [string[]] $ExcludeProperty, [Parameter(DontShow)][String[]]$Path, [Parameter(DontShow)][System.Collections.IDictionary] $OutputObject ) Begin { $InputObjects = [System.Collections.Generic.List[Object]]::new() } Process { foreach ($O in $Objects) { if ($null -ne $O) { $InputObjects.Add($O) } } } End { If ($PSBoundParameters.ContainsKey("OutputObject")) { $Object = $InputObjects[0] $Iterate = [ordered] @{} if ($null -eq $Object) { } elseif ($Object.GetType().Name -in 'String', 'DateTime', 'TimeSpan', 'Version', 'Enum') { $Object = $Object.ToString() } elseif ($Depth) { $Depth-- If ($Object -is [System.Collections.IDictionary]) { $Iterate = $Object } elseif ($Object -is [Array] -or $Object -is [System.Collections.IEnumerable]) { $i = $Base foreach ($Item in $Object.GetEnumerator()) { $NewObject = [ordered] @{} If ($Item -is [System.Collections.IDictionary]) { foreach ($Key in $Item.Keys) { if ($Key -notin $ExcludeProperty) { $NewObject[$Key] = $Item[$Key] } } } elseif ($Item -isnot [Array] -and $Item -isnot [System.Collections.IEnumerable]) { foreach ($Prop in $Item.PSObject.Properties) { if ($Prop.IsGettable -and $Prop.Name -notin $ExcludeProperty) { $NewObject["$($Prop.Name)"] = $Item.$($Prop.Name) } } } else { $NewObject = $Item } $Iterate["$i"] = $NewObject $i += 1 } } else { foreach ($Prop in $Object.PSObject.Properties) { if ($Prop.IsGettable -and $Prop.Name -notin $ExcludeProperty) { $Iterate["$($Prop.Name)"] = $Object.$($Prop.Name) } } } } If ($Iterate.Keys.Count) { foreach ($Key in $Iterate.Keys) { if ($Key -notin $ExcludeProperty) { ConvertTo-FlatObject -Objects @(, $Iterate["$Key"]) -Separator $Separator -Base $Base -Depth $Depth -Path ($Path + $Key) -OutputObject $OutputObject -ExcludeProperty $ExcludeProperty } } } else { $Property = $Path -Join $Separator if ($Property) { if ($Object -is [System.Collections.IDictionary] -and $Object.Keys.Count -eq 0) { $OutputObject[$Property] = $null } else { $OutputObject[$Property] = $Object } } } } elseif ($InputObjects.Count -gt 0) { foreach ($ItemObject in $InputObjects) { $OutputObject = [ordered]@{} ConvertTo-FlatObject -Objects @(, $ItemObject) -Separator $Separator -Base $Base -Depth $Depth -Path $Path -OutputObject $OutputObject -ExcludeProperty $ExcludeProperty [PSCustomObject] $OutputObject } } } } function ConvertTo-Identity { [cmdletBinding()] param( [string] $Identity, [System.Collections.IDictionary] $ADAdministrativeGroups, [alias('ForestName')][string] $Forest, [string[]] $ExcludeDomains, [alias('Domain', 'Domains')][string[]] $IncludeDomains, [System.Collections.IDictionary] $ExtendedForestInformation ) Begin { if (-not $ExtendedForestInformation) { $ForestInformation = Get-WinADForestDetails -Extended -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } else { $ForestInformation = $ExtendedForestInformation } if (-not $ADAdministrativeGroups) { $ADAdministrativeGroups = Get-ADADministrativeGroups -Type DomainAdmins, EnterpriseAdmins -Forest $Forest -IncludeDomains $IncludeDomains -ExcludeDomains $ExcludeDomains -ExtendedForestInformation $ExtendedForestInformation } if (-not $Script:GlobalCacheIdentity) { $Script:GlobalCacheIdentity = @{ } } } Process { $AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($Identity)"] if ($AdministrativeGroup) { [PSCustomObject] @{ Name = $Identity SID = $AdministrativeGroup.SID.Value Type = 'Administrative' Class = $AdministrativeGroup.ObjectClass Error = '' } } else { if ($Identity -like '*@*') { Write-Warning "ConvertTo-Identity - Not implemented." } elseif ($Identity -like '*\*') { if ($Script:GlobalCacheIdentity[$Identity]) { $Script:GlobalCacheIdentity[$Identity] } else { $MyIdentity = $Identity.Split("\") $DNSRoot = $ForestInformation['DomainsExtendedNetBIOS'][$($MyIdentity[0])]['DNSRoot'] $QueryServer = $ForestInformation['QueryServers'][$DNSRoot]['HostName'][0] $ADObject = Get-ADObject -Filter "SamAccountName -eq '$($MyIdentity[1])'" -Server $QueryServer -Properties AdminCount, CanonicalName, Name, sAMAccountName, DisplayName, DistinguishedName, ObjectClass, objectSid if ($ADObject) { $Script:GlobalCacheIdentity[$Identity] = [PSCustomObject] @{ Name = $Identity SID = $ADObject.objectSid.Value Type = 'NotAdministrative' Class = $AdObject.ObjectClass Error = '' } $Script:GlobalCacheIdentity[$Identity] } else { [PSCustomObject] @{ Name = $Identity SID = $Identity Type = 'Unknown' Class = 'unknown' Error = 'Object not found.' } } } } elseif ($Identity -like '*-*-*-*') { $Data = ConvertFrom-SID -SID $Identity if ($Data) { if ($Data.Error) { [PSCustomObject] @{ Name = $Data.Name SID = $Data.Sid Type = $Data.Type Class = 'unknown' Error = $Data.Error } } else { $AdministrativeGroup = $ADAdministrativeGroups['ByNetBIOS']["$($Data.Name)"] if ($AdministrativeGroup) { [PSCustomObject] @{ Name = $Data.Name SID = $AdministrativeGroup.SID.Value Type = 'Administrative' Class = $AdministrativeGroup.ObjectClass Error = '' } } else { [PSCustomObject] @{ Name = $Data.Name SID = $Data.Sid Type = $Data.Type Class = '' Error = $Data.Error } } } } else { [PSCustomObject] @{ Name = $Identity SID = $Identity Type = 'Unknown' Class = 'unknown' Error = 'SID not found' } } } else { [PSCustomObject] @{ Name = $Identity SID = $Identity Type = 'Unknown' Class = 'unknown' Error = 'Identity unknown' } } } } End { } } function ConvertTo-ImmutableID { [CmdletBinding()] param( [Parameter(Mandatory = $false, ParameterSetName = 'User')] [alias('ADuser')] [Microsoft.ActiveDirectory.Management.ADAccount] $User, [Parameter(Mandatory = $false, ParameterSetName = 'Guid')] [alias('GUID')] [string] $ObjectGUID ) if ($User) { if ($User.ObjectGUID) { $ObjectGUID = $User.ObjectGuid } } if ($ObjectGUID) { $ImmutableID = [System.Convert]::ToBase64String(($User.ObjectGUID).ToByteArray()) return $ImmutableID } return } function ConvertTo-JsonLiteral { <# .SYNOPSIS Converts an object to a JSON-formatted string. .DESCRIPTION The ConvertTo-Json cmdlet converts any object to a string in JavaScript Object Notation (JSON) format. The properties are converted to field names, the field values are converted to property values, and the methods are removed. .PARAMETER Object Specifies the objects to convert to JSON format. Enter a variable that contains the objects, or type a command or expression that gets the objects. You can also pipe an object to ConvertTo-JsonLiteral .PARAMETER Depth Specifies how many levels of contained objects are included in the JSON representation. The default value is 0. .PARAMETER AsArray Outputs the object in array brackets, even if the input is a single object. .PARAMETER DateTimeFormat Changes DateTime string format. Default "yyyy-MM-dd HH:mm:ss" .PARAMETER NumberAsString Provides an alternative serialization option that converts all numbers to their string representation. .PARAMETER BoolAsString Provides an alternative serialization option that converts all bool to their string representation. .PARAMETER PropertyName Uses PropertyNames provided by user (only works with Force) .PARAMETER NewLineFormat Provides a way to configure how new lines are converted for property names .PARAMETER NewLineFormatProperty Provides a way to configure how new lines are converted for values .PARAMETER PropertyName Allows passing property names to be used for custom objects (hashtables and alike are unaffected) .PARAMETER ArrayJoin Forces any array to be a string regardless of depth level .PARAMETER ArrayJoinString Uses defined string or char for array join. By default it uses comma with a space when used. .PARAMETER Force Forces using property names from first object or given thru PropertyName parameter .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -Depth 3 .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NewLineFormat $NewLineFormat = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" } -NumberAsString -BoolAsString .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NumberAsString -BoolAsString -DateTimeFormat "yyyy-MM-dd HH:mm:ss" .EXAMPLE # Keep in mind this advanced replace will break ConvertFrom-Json, but it's sometimes useful for projects like PSWriteHTML Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NewLineFormat $NewLineFormat = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" } -NumberAsString -BoolAsString -AdvancedReplace @{ '.' = '\.'; '$' = '\$' } .NOTES General notes #> [cmdletBinding()] param( [alias('InputObject')][Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory)][Array] $Object, [int] $Depth, [switch] $AsArray, [string] $DateTimeFormat = "yyyy-MM-dd HH:mm:ss", [switch] $NumberAsString, [switch] $BoolAsString, [System.Collections.IDictionary] $NewLineFormat = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $NewLineFormatProperty = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $AdvancedReplace, [string] $ArrayJoinString, [switch] $ArrayJoin, [string[]]$PropertyName, [switch] $Force ) Begin { $TextBuilder = [System.Text.StringBuilder]::new() $CountObjects = 0 filter IsNumeric() { return $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] ` -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] ` -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] } filter IsOfType() { return $_ -is [bool] -or $_ -is [char] -or $_ -is [datetime] -or $_ -is [string] ` -or $_ -is [timespan] -or $_ -is [URI] ` -or $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] ` -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] ` -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] } [int] $MaxDepth = $Depth [int] $InitialDepth = 0 } Process { for ($a = 0; $a -lt $Object.Count; $a++) { $CountObjects++ if ($CountObjects -gt 1) { $null = $TextBuilder.Append(',') } if ($Object[$a] -is [System.Collections.IDictionary]) { $null = $TextBuilder.AppendLine("{") for ($i = 0; $i -lt ($Object[$a].Keys).Count; $i++) { $Property = ([string[]]$Object[$a].Keys)[$i] $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $Value = ConvertTo-StringByType -Value $Object[$a][$Property] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace $null = $TextBuilder.Append("$Value") if ($i -ne ($Object[$a].Keys).Count - 1) { $null = $TextBuilder.AppendLine(',') } } $null = $TextBuilder.Append("}") } elseif ($Object[$a] | IsOfType) { $Value = ConvertTo-StringByType -Value $Object[$a] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace $null = $TextBuilder.Append($Value) } else { $null = $TextBuilder.AppendLine("{") if ($Force -and -not $PropertyName) { $PropertyName = $Object[0].PSObject.Properties.Name } elseif ($Force -and $PropertyName) { } else { $PropertyName = $Object[$a].PSObject.Properties.Name } $PropertyCount = 0 foreach ($Property in $PropertyName) { $PropertyCount++ $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $Value = ConvertTo-StringByType -Value $Object[$a].$Property -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace $null = $TextBuilder.Append("$Value") if ($PropertyCount -ne $PropertyName.Count) { $null = $TextBuilder.AppendLine(',') } } $null = $TextBuilder.Append("}") } $InitialDepth = 0 } } End { if ($CountObjects -gt 1 -or $AsArray) { "[$($TextBuilder.ToString())]" } else { $TextBuilder.ToString() } } } function ConvertTo-OperatingSystem { <# .SYNOPSIS Allows easy conversion of OperatingSystem, Operating System Version to proper Windows 10 naming based on WMI or AD .DESCRIPTION Allows easy conversion of OperatingSystem, Operating System Version to proper Windows 10 naming based on WMI or AD .PARAMETER OperatingSystem Operating System as returned by Active Directory .PARAMETER OperatingSystemVersion Operating System Version as returned by Active Directory .EXAMPLE $Computers = Get-ADComputer -Filter * -Properties OperatingSystem, OperatingSystemVersion | ForEach-Object { $OPS = ConvertTo-OperatingSystem -OperatingSystem $_.OperatingSystem -OperatingSystemVersion $_.OperatingSystemVersion Add-Member -MemberType NoteProperty -Name 'OperatingSystemTranslated' -Value $OPS -InputObject $_ -Force $_ } $Computers | Select-Object DNS*, Name, SamAccountName, Enabled, OperatingSystem*, DistinguishedName | Format-Table .EXAMPLE $Registry = Get-PSRegistry -ComputerName 'AD1' -RegistryPath 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion' ConvertTo-OperatingSystem -OperatingSystem $Registry.ProductName -OperatingSystemVersion $Registry.CurrentBuildNumber .NOTES General notes #> [CmdletBinding()] param( [string] $OperatingSystem, [string] $OperatingSystemVersion ) if ($OperatingSystem -like 'Windows 10*' -or $OperatingSystem -like 'Windows 11*') { $Systems = @{ '10.0 (22621)' = 'Windows 11 22H2' '10.0 (22000)' = 'Windows 11 21H2' '10.0 (19045)' = 'Windows 10 22H2' '10.0 (19044)' = 'Windows 10 21H2' '10.0 (19043)' = 'Windows 10 21H1' '10.0 (19042)' = 'Windows 10 20H2' '10.0 (19041)' = 'Windows 10 2004' '10.0 (18898)' = 'Windows 10 Insider Preview' '10.0 (18363)' = "Windows 10 1909" '10.0 (18362)' = "Windows 10 1903" '10.0 (17763)' = "Windows 10 1809" '10.0 (17134)' = "Windows 10 1803" '10.0 (16299)' = "Windows 10 1709" '10.0 (15063)' = "Windows 10 1703" '10.0 (14393)' = "Windows 10 1607" '10.0 (10586)' = "Windows 10 1511" '10.0 (10240)' = "Windows 10 1507" '10.0.22621' = 'Windows 11 22H2' '10.0.22000' = 'Windows 11 21H2' '10.0.19045' = 'Windows 10 22H2' '10.0.19044' = 'Windows 10 21H2' '10.0.19043' = 'Windows 10 21H1' '10.0.19042' = 'Windows 10 20H2' '10.0.19041' = 'Windows 10 2004' '10.0.18898' = 'Windows 10 Insider Preview' '10.0.18363' = "Windows 10 1909" '10.0.18362' = "Windows 10 1903" '10.0.17763' = "Windows 10 1809" '10.0.17134' = "Windows 10 1803" '10.0.16299' = "Windows 10 1709" '10.0.15063' = "Windows 10 1703" '10.0.14393' = "Windows 10 1607" '10.0.10586' = "Windows 10 1511" '10.0.10240' = "Windows 10 1507" '22621' = 'Windows 11 22H2' '22000' = 'Windows 11 21H2' '19045' = 'Windows 10 22H2' '19044' = 'Windows 10 21H2' '19043' = 'Windows 10 21H1' '19042' = 'Windows 10 20H2' '19041' = 'Windows 10 2004' '18898' = 'Windows 10 Insider Preview' '18363' = "Windows 10 1909" '18362' = "Windows 10 1903" '17763' = "Windows 10 1809" '17134' = "Windows 10 1803" '16299' = "Windows 10 1709" '15063' = "Windows 10 1703" '14393' = "Windows 10 1607" '10586' = "Windows 10 1511" '10240' = "Windows 10 1507" } $System = $Systems[$OperatingSystemVersion] if (-not $System) { $System = $OperatingSystemVersion } } elseif ($OperatingSystem -like 'Windows Server*') { $Systems = @{ '10.0 (20348)' = 'Windows Server 2022' '10.0 (19042)' = 'Windows Server 2019 20H2' '10.0 (19041)' = 'Windows Server 2019 2004' '10.0 (18363)' = 'Windows Server 2019 1909' '10.0 (18362)' = "Windows Server 2019 1903" '10.0 (17763)' = "Windows Server 2019 1809" '10.0 (17134)' = "Windows Server 2016 1803" '10.0 (14393)' = "Windows Server 2016 1607" '6.3 (9600)' = 'Windows Server 2012 R2' '6.1 (7601)' = 'Windows Server 2008 R2' '5.2 (3790)' = 'Windows Server 2003' '10.0.20348' = 'Windows Server 2022' '10.0.19042' = 'Windows Server 2019 20H2' '10.0.19041' = 'Windows Server 2019 2004' '10.0.18363' = 'Windows Server 2019 1909' '10.0.18362' = "Windows Server 2019 1903" '10.0.17763' = "Windows Server 2019 1809" '10.0.17134' = "Windows Server 2016 1803" '10.0.14393' = "Windows Server 2016 1607" '6.3.9600' = 'Windows Server 2012 R2' '6.1.7601' = 'Windows Server 2008 R2' '5.2.3790' = 'Windows Server 2003' '20348' = 'Windows Server 2022' '19042' = 'Windows Server 2019 20H2' '19041' = 'Windows Server 2019 2004' '18363' = 'Windows Server 2019 1909' '18362' = "Windows Server 2019 1903" '17763' = "Windows Server 2019 1809" '17134' = "Windows Server 2016 1803" '14393' = "Windows Server 2016 1607" '9600' = 'Windows Server 2012 R2' '7601' = 'Windows Server 2008 R2' '3790' = 'Windows Server 2003' } $System = $Systems[$OperatingSystemVersion] if (-not $System) { $System = $OperatingSystemVersion } } else { $System = $OperatingSystem } if ($System) { $System } else { 'Unknown' } } function ConvertTo-OrderedDictionary { [CmdletBinding()] Param ( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $HashTable ) $OrderedDictionary = [ordered]@{ } if ($HashTable -is [System.Collections.IDictionary]) { $Keys = $HashTable.Keys | Sort-Object foreach ($_ in $Keys) { $OrderedDictionary.Add($_, $HashTable[$_]) } } elseif ($HashTable -is [System.Collections.ICollection]) { for ($i = 0; $i -lt $HashTable.count; $i++) { $OrderedDictionary.Add($i, $HashTable[$i]) } } else { Write-Error "ConvertTo-OrderedDictionary - Wrong input type." } return $OrderedDictionary } function ConvertTo-PrettyObject { <# .SYNOPSIS Command to help with converting standard objects that could be nested objects into single level PSCustomObject .DESCRIPTION Command to help with converting standard objects that could be nested objects into single level PSCustomObject This is a help command for PSWriteHTML module and probably PSWriteOffice module to create tables from objects and make sure those tables are not nested and can be easily converted to HTML or Office tables without having to manually flatten them .PARAMETER Object Specifies the objects to convert to pretty format. Enter a variable that contains the objects, or type a command or expression that gets the objects. You can also pipe an object to ConvertTo-JsonLiteral .PARAMETER DateTimeFormat Changes DateTime string format. Default "yyyy-MM-dd HH:mm:ss" .PARAMETER NumberAsString Provides an alternative serialization option that converts all numbers to their string representation. .PARAMETER BoolAsString Provides an alternative serialization option that converts all bool to their string representation. .PARAMETER PropertyName Uses PropertyNames provided by user (only works with Force) .PARAMETER NewLineFormat Provides a way to configure how new lines are converted for property names .PARAMETER NewLineFormatProperty Provides a way to configure how new lines are converted for values .PARAMETER PropertyName Allows passing property names to be used for custom objects (hashtables and alike are unaffected) .PARAMETER ArrayJoin Forces any array to be a string regardless of depth level .PARAMETER ArrayJoinString Uses defined string or char for array join. By default it uses comma with a space when used. .PARAMETER Force Forces using property names from first object or given thru PropertyName parameter .EXAMPLE $Test1 = [PSCustomObject] @{ Number = 1 Number2 = 2.2 Bool = $false Array = @( 'C:\Users\1Password.exe' "C:\Users\Ooops.exe" "\\EvoWin\c$\Users\przemyslaw klys\AppData\Local\1password\This is other\7\1Password.exe" "\\EvoWin\c$\Users\przemyslaw.klys\AppData\Local\1password\This is other\7\1Password.exe" ) EmptyArray = @() EmptyList = [System.Collections.Generic.List[string]]::new() HashTable = @{ NumberAgain = 2 OrderedDictionary = [ordered] @{ String = 'test' HashTable = @{ StringAgain = "oops" } } Array = @( 'C:\Users\1Password.exe' "C:\Users\Ooops.exe" "\\EvoWin\c$\Users\przemyslaw klys\AppData\Local\1password\This is other\7\1Password.exe" "\\EvoWin\c$\Users\przemyslaw.klys\AppData\Local\1password\This is other\7\1Password.exe" ) } DateTime = Get-Date } $Test1 | ConvertTo-PrettyObject -ArrayJoinString "," -ArrayJoin | ConvertTo-Json | ConvertFrom-Json .NOTES General notes #> [CmdletBinding()] param( [alias('InputObject')][Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory)][Array] $Object, [int] $Depth, [switch] $AsArray, [string] $DateTimeFormat = "yyyy-MM-dd HH:mm:ss", [switch] $NumberAsString, [switch] $BoolAsString, [System.Collections.IDictionary] $NewLineFormat = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $NewLineFormatProperty = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $AdvancedReplace, [string] $ArrayJoinString, [switch] $ArrayJoin, [string[]]$PropertyName, [switch] $Force ) Begin { filter IsNumeric() { return $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] ` -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] ` -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] } filter IsOfType() { return $_ -is [bool] -or $_ -is [char] -or $_ -is [datetime] -or $_ -is [string] ` -or $_ -is [timespan] -or $_ -is [URI] ` -or $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] ` -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] ` -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] } } Process { for ($a = 0; $a -lt $Object.Count; $a++) { $NewObject = [ordered] @{} if ($Object[$a] -is [System.Collections.IDictionary]) { for ($i = 0; $i -lt ($Object[$a].Keys).Count; $i++) { $Property = ([string[]]$Object[$a].Keys)[$i] $DisplayProperty = $Property.Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $Value = $Object[$a].$Property if ($null -eq $Value) { $NewObject[$DisplayProperty] = "" } elseif ($Value -is [string]) { foreach ($Key in $AdvancedReplace.Keys) { $Value = $Value.Replace($Key, $AdvancedReplace[$Key]) } $NewObject[$DisplayProperty] = $Value } elseif ($Value -is [DateTime]) { $NewObject[$DisplayProperty] = $Object[$a].$Property.ToString($DateTimeFormat) } elseif ($Value -is [bool]) { if ($BoolAsString) { $NewObject[$DisplayProperty] = "$Value" } else { $NewObject[$DisplayProperty] = $Value } } elseif ($Value -is [System.Collections.IDictionary]) { $NewObject[$DisplayProperty] = "$Value" } elseif ($Value -is [System.Collections.IList] -or $Value -is [System.Collections.ReadOnlyCollectionBase]) { if ($ArrayJoin) { $Value = $Value -join $ArrayJoinString $Value = "$Value".Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $NewObject[$DisplayProperty] = "$Value" } else { $Value = "$Value".Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $NewObject[$DisplayProperty] = "$Value" } } elseif ($Value -is [System.Enum]) { $NewObject[$DisplayProperty] = ($Value).ToString() } elseif (($Value | IsNumeric) -eq $true) { $Value = $($Value).ToString().Replace(',', '.') if ($NumberAsString) { $NewObject[$DisplayProperty] = "$Value" } else { $NewObject[$DisplayProperty] = $Value } } elseif ($Value -is [PSObject]) { $NewObject[$DisplayProperty] = "$Value" } else { $Value = $Value.ToString().Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $NewObject[$DisplayProperty] = "$Value" } } [PSCustomObject] $NewObject } elseif ($Object[$a] | IsOfType) { $Object[$a] } else { if ($Force -and -not $PropertyName) { $PropertyName = $Object[0].PSObject.Properties.Name } elseif ($Force -and $PropertyName) { } else { $PropertyName = $Object[$a].PSObject.Properties.Name } foreach ($Property in $PropertyName) { $DisplayProperty = $Property.Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $Value = $Object[$a].$Property if ($null -eq $Value) { $NewObject[$DisplayProperty] = "" } elseif ($Value -is [string]) { foreach ($Key in $AdvancedReplace.Keys) { $Value = $Value.Replace($Key, $AdvancedReplace[$Key]) } $NewObject[$DisplayProperty] = $Value } elseif ($Value -is [DateTime]) { $NewObject[$DisplayProperty] = $Object[$a].$Property.ToString($DateTimeFormat) } elseif ($Value -is [bool]) { if ($BoolAsString) { $NewObject[$DisplayProperty] = "$Value" } else { $NewObject[$DisplayProperty] = $Value } } elseif ($Value -is [System.Collections.IDictionary]) { $NewObject[$DisplayProperty] = "$Value" } elseif ($Value -is [System.Collections.IList] -or $Value -is [System.Collections.ReadOnlyCollectionBase]) { if ($ArrayJoin) { $Value = $Value -join $ArrayJoinString $Value = "$Value".Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $NewObject[$DisplayProperty] = "$Value" } else { $Value = "$Value".Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $NewObject[$DisplayProperty] = "$Value" } } elseif ($Value -is [System.Enum]) { $NewObject[$DisplayProperty] = ($Value).ToString() } elseif (($Value | IsNumeric) -eq $true) { if ($NumberAsString) { $NewObject[$DisplayProperty] = "$Value" } else { $NewObject[$DisplayProperty] = $Value } } elseif ($Value -is [PSObject]) { $NewObject[$DisplayProperty] = "$Value" } else { $Value = $Value.ToString().Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $NewObject[$DisplayProperty] = "$Value" } } [PSCustomObject] $NewObject } } } } function ConvertTo-SID { [cmdletBinding()] param( [string[]] $Identity ) Begin { if (-not $Script:GlobalCacheSidConvert) { $Script:GlobalCacheSidConvert = @{ } } } Process { foreach ($Ident in $Identity) { if ($Script:GlobalCacheSidConvert[$Ident]) { $Script:GlobalCacheSidConvert[$Ident] } else { try { $Script:GlobalCacheSidConvert[$Ident] = [PSCustomObject] @{ Name = $Ident Sid = ([System.Security.Principal.NTAccount] $Ident).Translate([System.Security.Principal.SecurityIdentifier]).Value Error = '' } } catch { [PSCustomObject] @{ Name = $Ident Sid = '' Error = $_.Exception.Message } } $Script:GlobalCacheSidConvert[$Ident] } } } End { } } function Find-DatesCurrentDayMinusDayX ($days) { $DateTodayStart = (Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0).AddDays( - $Days) $DateTodayEnd = (Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0).AddDays(1).AddDays( - $Days).AddMilliseconds(-1) $DateParameters = @{ DateFrom = $DateTodayStart DateTo = $DateTodayEnd } return $DateParameters } function Find-DatesCurrentDayMinuxDaysX ($days) { $DateTodayStart = (Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0).AddDays( - $Days) $DateTodayEnd = (Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0).AddDays(1).AddMilliseconds(-1) $DateParameters = @{ DateFrom = $DateTodayStart DateTo = $DateTodayEnd } return $DateParameters } function Find-DatesCurrentHour () { $DateTodayStart = (Get-Date -Minute 0 -Second 0 -Millisecond 0) $DateTodayEnd = $DateTodayStart.AddHours(1) $DateParameters = @{ DateFrom = $DateTodayStart DateTo = $DateTodayEnd } return $DateParameters } function Find-DatesDayPrevious () { $DateToday = (Get-Date).Date $DateYesterday = $DateToday.AddDays(-1) $DateParameters = @{ DateFrom = $DateYesterday DateTo = $dateToday } return $DateParameters } function Find-DatesDayToday () { $DateToday = (Get-Date).Date $DateTodayEnd = $DateToday.AddDays(1).AddSeconds(-1) $DateParameters = @{ DateFrom = $DateToday DateTo = $DateTodayEnd } return $DateParameters } function Find-DatesMonthCurrent () { $DateMonthFirstDay = (Get-Date -Day 1).Date $DateMonthLastDay = Get-Date $DateMonthFirstDay.AddMonths(1).AddSeconds(-1) $DateParameters = @{ DateFrom = $DateMonthFirstDay DateTo = $DateMonthLastDay } return $DateParameters } function Find-DatesMonthPast ([bool] $Force) { $DateToday = (Get-Date).Date $DateMonthFirstDay = (Get-Date -Day 1).Date $DateMonthPreviousFirstDay = $DateMonthFirstDay.AddMonths(-1) if ($Force -eq $true -or $DateToday -eq $DateMonthFirstDay) { $DateParameters = @{ DateFrom = $DateMonthPreviousFirstDay DateTo = $DateMonthFirstDay } return $DateParameters } else { return $null } } function Find-DatesPastHour () { $DateTodayEnd = Get-Date -Minute 0 -Second 0 -Millisecond 0 $DateTodayStart = $DateTodayEnd.AddHours(-1) $DateParameters = @{ DateFrom = $DateTodayStart DateTo = $DateTodayEnd } return $DateParameters } function Find-DatesPastWeek($DayName) { $DateTodayStart = Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0 if ($DateTodayStart.DayOfWeek -ne $DayName) { return $null } $DateTodayEnd = (Get-Date -Hour 0 -Minute 0 -Second 0 -Millisecond 0).AddDays(-7) $DateParameters = @{ DateFrom = $DateTodayEnd DateTo = $DateTodayStart } return $DateParameters } function Find-DatesQuarterCurrent ([bool] $Force) { $Today = (Get-Date) $Quarter = [Math]::Ceiling($Today.Month / 3) $LastDay = [DateTime]::DaysInMonth([Int]$Today.Year.ToString(), [Int]($Quarter * 3)) $StartDate = (Get-Date -Year $Today.Year -Month ($Quarter * 3 - 2) -Day 1).Date $EndDate = (Get-Date -Year $Today.Year -Month ($Quarter * 3) -Day $LastDay).Date.AddDays(1).AddTicks(-1) $DateParameters = @{ DateFrom = $StartDate DateTo = $EndDate } return $DateParameters } function Find-DatesQuarterLast ([bool] $Force) { #https://blogs.technet.microsoft.com/dsheehan/2017/09/21/use-powershell-to-determine-the-first-day-of-the-current-calendar-quarter/ $Today = (Get-Date).AddDays(-90) $Yesterday = ((Get-Date).AddDays(-1)) $Quarter = [Math]::Ceiling($Today.Month / 3) $LastDay = [DateTime]::DaysInMonth([Int]$Today.Year.ToString(), [Int]($Quarter * 3)) $StartDate = (Get-Date -Year $Today.Year -Month ($Quarter * 3 - 2) -Day 1).Date $EndDate = (Get-Date -Year $Today.Year -Month ($Quarter * 3) -Day $LastDay).Date.AddDays(1).AddTicks(-1) if ($Force -eq $true -or $Yesterday.Date -eq $EndDate.Date) { $DateParameters = @{ DateFrom = $StartDate DateTo = $EndDate } return $DateParameters } else { return $null } } function Set-DnsServerIpAddress { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ComputerName ComputerName/ServerName where to Set DNS Server .PARAMETER NicName Service is the name of the Network Card (takes wildcard) .PARAMETER IpAddresses IpAddresses can be one or more values .EXAMPLE Set-DnsServerIpAddress -ComputerName $ServerName -NicName "Service*" -IpAddresses '8.8.8.8','8.8.4.4','8.8.8.1' .NOTES Probably needs a rewrite #> [CmdletBinding()] param( [string] $ComputerName, [string] $NicName, [string] $IpAddresses ) if (Test-Connection -ComputerName $ComputerName -Count 2 -Quiet) { Invoke-Command -ComputerName $ComputerName -ScriptBlock { param ($ComputerName, $NicName, $IpAddresses) Write-Host "Setting on $ComputerName on interface $NicName a new set of DNS Servers $IpAddresses" Set-DnsClientServerAddress -InterfaceAlias $NicName -ServerAddresses $IpAddresses } -ArgumentList $ComputerName, $NicName, $IpAddresses } else { Write-Warning "Set-DnsServerIpAddress - Can't access $ComputerName. Computer is not online." } } function Get-HTML { [CmdletBinding()] param ( $text ) $text = $text.Split("`r") foreach ($t in $text) { Write-Host $t } } function Send-Email { [CmdletBinding(SupportsShouldProcess = $true)] param ( [alias('EmailParameters')][System.Collections.IDictionary] $Email, [string] $Body, [string[]] $Attachment, [System.Collections.IDictionary] $InlineAttachments, [string] $Subject, [string[]] $To, [PSCustomObject] $Logger ) try { if ($Email.EmailTo) { $EmailParameters = $Email.Clone() $EmailParameters.EmailEncoding = $EmailParameters.EmailEncoding -replace "-", '' $EmailParameters.EmailEncodingSubject = $EmailParameters.EmailEncodingSubject -replace "-", '' $EmailParameters.EmailEncodingBody = $EmailParameters.EmailEncodingSubject -replace "-", '' $EmailParameters.EmailEncodingAlternateView = $EmailParameters.EmailEncodingAlternateView -replace "-", '' } else { $EmailParameters = @{ EmailFrom = $Email.From EmailTo = $Email.To EmailCC = $Email.CC EmailBCC = $Email.BCC EmailReplyTo = $Email.ReplyTo EmailServer = $Email.Server EmailServerPassword = $Email.Password EmailServerPasswordAsSecure = $Email.PasswordAsSecure EmailServerPasswordFromFile = $Email.PasswordFromFile EmailServerPort = $Email.Port EmailServerLogin = $Email.Login EmailServerEnableSSL = $Email.EnableSsl EmailEncoding = $Email.Encoding -replace "-", '' EmailEncodingSubject = $Email.EncodingSubject -replace "-", '' EmailEncodingBody = $Email.EncodingBody -replace "-", '' EmailEncodingAlternateView = $Email.EncodingAlternateView -replace "-", '' EmailSubject = $Email.Subject EmailPriority = $Email.Priority EmailDeliveryNotifications = $Email.DeliveryNotifications EmailUseDefaultCredentials = $Email.UseDefaultCredentials } } } catch { return @{ Status = $False Error = $($_.Exception.Message) SentTo = '' } } $SmtpClient = [System.Net.Mail.SmtpClient]::new() if ($EmailParameters.EmailServer) { $SmtpClient.Host = $EmailParameters.EmailServer } else { return @{ Status = $False Error = "Email Server Host is not set." SentTo = '' } } if ($EmailParameters.EmailServerPort) { $SmtpClient.Port = $EmailParameters.EmailServerPort } else { return @{ Status = $False Error = "Email Server Port is not set." SentTo = '' } } if ($EmailParameters.EmailServerLogin) { $Credentials = Request-Credentials -UserName $EmailParameters.EmailServerLogin ` -Password $EmailParameters.EmailServerPassword ` -AsSecure:$EmailParameters.EmailServerPasswordAsSecure ` -FromFile:$EmailParameters.EmailServerPasswordFromFile ` -NetworkCredentials $SmtpClient.Credentials = $Credentials } if ($EmailParameters.EmailServerEnableSSL) { $SmtpClient.EnableSsl = $EmailParameters.EmailServerEnableSSL } $MailMessage = [System.Net.Mail.MailMessage]::new() $MailMessage.From = $EmailParameters.EmailFrom if ($To) { foreach ($T in $To) { $MailMessage.To.add($($T)) } } else { if ($EmailParameters.Emailto) { foreach ($To in $EmailParameters.Emailto) { $MailMessage.To.add($($To)) } } } if ($EmailParameters.EmailCC) { foreach ($CC in $EmailParameters.EmailCC) { $MailMessage.CC.add($($CC)) } } if ($EmailParameters.EmailBCC) { foreach ($BCC in $EmailParameters.EmailBCC) { $MailMessage.BCC.add($($BCC)) } } if ($EmailParameters.EmailReplyTo) { $MailMessage.ReplyTo = $EmailParameters.EmailReplyTo } $MailMessage.IsBodyHtml = $true if ($Subject -eq '') { $MailMessage.Subject = $EmailParameters.EmailSubject } else { $MailMessage.Subject = $Subject } $MailMessage.Priority = [System.Net.Mail.MailPriority]::$($EmailParameters.EmailPriority) if ($EmailParameters.EmailEncodingSubject) { $MailMessage.SubjectEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncodingSubject) } elseif ($EmailParameters.EmailEncoding) { $MailMessage.SubjectEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncoding) } if ($EmailParameters.EmailEncodingBody) { $MailMessage.BodyEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncodingBody) } elseif ($EmailParameters.EmailEncoding) { $MailMessage.BodyEncoding = [System.Text.Encoding]::$($EmailParameters.EmailEncoding) } if ($EmailParameters.EmailUseDefaultCredentials) { $SmtpClient.UseDefaultCredentials = $EmailParameters.EmailUseDefaultCredentials } if ($EmailParameters.EmailDeliveryNotifications) { $MailMessage.DeliveryNotificationOptions = $EmailParameters.EmailDeliveryNotifications } if ($PSBoundParameters.ContainsKey('InlineAttachments')) { if ($EmailParameters.EmailEncodingAlternateView) { $BodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, [System.Text.Encoding]::$($EmailParameters.EmailEncodingAlternateView) , 'text/html' ) } else { $BodyPart = [Net.Mail.AlternateView]::CreateAlternateViewFromString($Body, [System.Text.Encoding]::UTF8, 'text/html' ) } $MailMessage.AlternateViews.Add($BodyPart) foreach ($Entry in $InlineAttachments.GetEnumerator()) { try { $FilePath = $Entry.Value Write-Verbose $FilePath if ($Entry.Value.StartsWith('http', [System.StringComparison]::CurrentCultureIgnoreCase)) { $FileName = $Entry.Value.Substring($Entry.Value.LastIndexOf("/") + 1) $FilePath = Join-Path $env:temp $FileName Invoke-WebRequest -Uri $Entry.Value -OutFile $FilePath } $ContentType = Get-MimeType -FileName $FilePath $InAttachment = [Net.Mail.LinkedResource]::new($FilePath, $ContentType ) $InAttachment.ContentId = $Entry.Key $BodyPart.LinkedResources.Add( $InAttachment ) } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " Write-Error "Error inlining attachments: $ErrorMessage" } } } else { $MailMessage.Body = $Body } if ($PSBoundParameters.ContainsKey('Attachment')) { foreach ($Attach in $Attachment) { if (Test-Path -LiteralPath $Attach) { try { $File = [Net.Mail.Attachment]::new($Attach) $MailMessage.Attachments.Add($File) } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " if ($Logger) { $Logger.AddErrorRecord("Error attaching file $Attach`: $ErrorMessage") } else { Write-Error "Error attaching file $Attach`: $ErrorMessage" } } } } } try { $MailSentTo = "$($MailMessage.To) $($MailMessage.CC) $($MailMessage.BCC)".Trim() if ($pscmdlet.ShouldProcess("$MailSentTo", "Send-Email")) { $SmtpClient.Send($MailMessage) $MailMessage.Dispose(); return [PSCustomObject] @{ Status = $True Error = "" SentTo = $MailSentTo } } else { return [PSCustomObject] @{ Status = $False Error = 'Email not sent (WhatIf)' SentTo = $MailSentTo } } } catch { $MailMessage.Dispose(); return [PSCustomObject] @{ Status = $False Error = $($_.Exception.Message) SentTo = "" } } } function Set-EmailBody { [CmdletBinding()] param( [Object] $TableData, [alias('TableWelcomeMessage')][string] $TableMessageWelcome, [string] $TableMessageNoData = 'No changes happened during that period.' ) $Body = "<p><i><u>$TableMessageWelcome</u></i></p>" if ($($TableData | Measure-Object).Count -gt 0) { $Body += $TableData | ConvertTo-Html -Fragment | Out-String } else { $Body += "<p><i>$TableMessageNoData</i></p>" } return $body } function Set-EmailBodyPreparedTable ($TableData, $TableWelcomeMessage) { $body = "<p><i><u>$TableWelcomeMessage</u></i></p>" $body += $TableData return $body } function Set-EmailBodyReplacement { [CmdletBinding()] param( [string] $Body, [hashtable] $ReplacementTable, [ValidateSet('Colors', 'Bold')][string] $Type ) switch ($Type) { 'Colors' { foreach ($Field in $ReplacementTable.Keys) { $Value = $ReplacementTable.$Field $Body = $Body -replace $Field, "<font color=`"$Value`">$Field</font>" } } 'Bold' { foreach ($Field in $ReplacementTable.Keys) { $Value = $ReplacementTable.$Field if ($Value -eq $true) { $Body = $Body -replace $Field, "<b>$Field</b>" } } } } return $Body } function Set-EmailBodyReplacementTable { [CmdletBinding()] [alias('Set-EmailBodyTableReplacement')] param ( [string] $Body, [string] $TableName, [Array] $TableData ) $TableData = $TableData | ConvertTo-Html -Fragment | Out-String $Body = $Body -replace "<<$TableName>>", $TableData return $Body } function Set-EmailFormatting { [CmdletBinding()] param ( $Template, [System.Collections.IDictionary] $FormattingParameters, [System.Collections.IDictionary] $ConfigurationParameters, [PSCustomObject] $Logger, [switch] $SkipNewLines, [string[]] $AddAfterOpening, [string[]] $AddBeforeClosing, [string] $Image ) if ($ConfigurationParameters) { $WriteParameters = $ConfigurationParameters.DisplayConsole } else { $WriteParameters = @{ ShowTime = $true; LogFile = ""; TimeFormat = "yyyy-MM-dd HH:mm:ss" } } if ($Image) { $Template = $Template -replace '<<Image>>', $Image } $Body = "<body>" if ($AddAfterOpening) { $Body += $AddAfterOpening } if (-not $SkipNewLines) { $Template = $Template.Split("`n") if ($Logger) { $Logger.AddInfoRecord("Preparing template - adding HTML <BR> tags...") } else { Write-Color @WriteParameters -Text "[i] Preparing template ", "adding", " HTML ", "<BR>", " tags." -Color White, Yellow, White, Yellow } foreach ($t in $Template) { $Body += "$t<br>" } } else { $Body += $Template } foreach ($style in $FormattingParameters.Styles.GetEnumerator()) { foreach ($value in $style.Value) { if ($value -eq "") { continue } if ($Logger) { $Logger.AddInfoRecord("Preparing template - adding HTML $($style.Name) tag for $value.") } else { Write-Color @WriteParameters -Text "[i] Preparing template ", "adding", " HTML ", "$($style.Name)", " tag for ", "$value", ' tags...' -Color White, Yellow, White, Yellow, White, Yellow } $Body = $Body.Replace($value, "<$($style.Name)>$value</$($style.Name)>") } } foreach ($color in $FormattingParameters.Colors.GetEnumerator()) { foreach ($value in $color.Value) { if ($value -eq "") { continue } if ($Logger) { $Logger.AddInfoRecord("Preparing template - adding HTML $($color.Name) tag for $value.") } else { Write-Color @WriteParameters -Text "[i] Preparing template ", "adding", " HTML ", "$($color.Name)", " tag for ", "$value", ' tags...' -Color White, Yellow, White, Yellow, White, Yellow } $Body = $Body.Replace($value, "<span style=color:$($color.Name)>$value</span>") } } foreach ($links in $FormattingParameters.Links.GetEnumerator()) { foreach ($link in $links.Value) { if ($link.Link -like "*@*") { if ($Logger) { $Logger.AddInfoRecord("Preparing template - adding EMAIL Links for $($links.Key).") } else { Write-Color @WriteParameters -Text "[i] Preparing template ", "adding", " EMAIL ", "Links for", " $($links.Key)..." -Color White, Yellow, White, White, Yellow, White } $Body = $Body -replace "<<$($links.Key)>>", "<span style=color:$($link.Color)><a href='mailto:$($link.Link)?subject=$($Link.Subject)'>$($Link.Text)</a></span>" } else { if ($Logger) { $Logger.AddInfoRecord("[i] Preparing template - adding HTML Links for $($links.Key)") } else { Write-Color @WriteParameters -Text "[i] Preparing template ", "adding", " HTML ", "Links for", " $($links.Key)..." -Color White, Yellow, White, White, Yellow, White } $Body = $Body -replace "<<$($links.Key)>>", "<span style=color:$($link.Color)><a href='$($link.Link)'>$($Link.Text)</a></span>" } } } if ($AddAfterOpening) { $Body += $AddBeforeClosing } $Body += '</body>' if ($ConfigurationParameters) { if ($ConfigurationParameters.DisplayTemplateHTML -eq $true) { Get-HTML($Body) } } return $Body } function Set-EmailHead { [cmdletBinding()] param( [System.Collections.IDictionary] $FormattingOptions ) $head = @" <!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta content="width=device-width, initial-scale=1" name="viewport"> <meta name="description" content="Password Expiration Email"> <style> BODY { background-color: white; font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } TABLE { border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse; font-family: $($FormattingOptions.FontTableDataFamily); font-size: $($FormattingOptions.FontTableDataSize); } TH { border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #00297A; color: white; font-family: $($FormattingOptions.FontTableHeadingFamily); font-size: $($FormattingOptions.FontTableHeadingSize); } TR { font-family: $($FormattingOptions.FontTableDataFamily); font-size: $($FormattingOptions.FontTableDataSize); } UL { font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } LI { font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } TD { border-width: 1px; padding-right: 2px; padding-left: 2px; padding-top: 0px; padding-bottom: 0px; border-style: solid; border-color: black; background-color: white; font-family: $($FormattingOptions.FontTableDataFamily); font-size: $($FormattingOptions.FontTableDataSize); } H2 { font-family: $($FormattingOptions.FontHeadingFamily); font-size: $($FormattingOptions.FontHeadingSize); } P { font-family: $($FormattingOptions.FontFamily); font-size: $($FormattingOptions.FontSize); } </style> </head> "@ return $Head } function Set-EmailReportBranding { [cmdletBinding()] param( [alias('FormattingOptions')] $FormattingParameters ) if ($FormattingParameters.CompanyBranding.Link) { $Report = "<a style=`"text-decoration:none`" href=`"$($FormattingParameters.CompanyBranding.Link)`" class=`"clink logo-container`">" } else { $Report = '' } if ($FormattingParameters.CompanyBranding.Inline) { $Report += "<img width=<fix> height=<fix> src=`"cid:logo`" border=`"0`" class=`"company-logo`" alt=`"company-logo`"></a>" } else { $Report += "<img width=<fix> height=<fix> src=`"$($FormattingParameters.CompanyBranding.Logo)`" border=`"0`" class=`"company-logo`" alt=`"company-logo`"></a>" } if ($FormattingParameters.CompanyBranding.Width -ne "") { $Report = $Report -replace "width=<fix>", "width=$($FormattingParameters.CompanyBranding.Width)" } else { $Report = $Report -replace "width=<fix>", "" } if ($FormattingParameters.CompanyBranding.Height -ne "") { $Report = $Report -replace "height=<fix>", "height=$($FormattingParameters.CompanyBranding.Height)" } else { $Report = $Report -replace "height=<fix>", "" } return $Report } function Set-EmailWordReplacements($Body, $Replace, $ReplaceWith, [switch] $RegEx) { if ($RegEx) { $Body = $Body -Replace $Replace, $ReplaceWith } else { $Body = $Body.Replace($Replace, $ReplaceWith) } return $Body } function Set-EmailWordReplacementsHash { [CmdletBinding()] param ( $Body, $Substitute ) foreach ($Key in $Substitute.Keys) { Write-Verbose "Set-EmailWordReplacementsHash - Key: $Key Value: $($Substitute.$Key)" $Body = Set-EmailWordReplacements -Body $Body -Replace $Key -ReplaceWith $Substitute.$Key } return $Body } function Get-FileEncoding { <# .SYNOPSIS Get the encoding of a file (ASCII, UTF8, UTF8BOM, Unicode, BigEndianUnicode, UTF7) .DESCRIPTION Get the encoding of a file (ASCII, UTF8, UTF8BOM, Unicode, BigEndianUnicode, UTF7). Encoding is determined by the first few bytes of the file or by the presence of non-ASCII characters. .PARAMETER Path Path to the file to check .EXAMPLE Get-FileEncoding -Path 'C:\Users\pklys\Desktop\test.txt' .NOTES General notes #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0)] [string] $Path ) if (-not (Test-Path -Path $Path)) { if ($ErrorActionPreference -eq 'Stop') { throw "Get-FileEncoding - File not found: $Path" } Write-Warning -Message "Get-FileEncoding - File not found: $Path" return } $byte = [System.IO.File]::ReadAllBytes($Path) if ($byte[0] -eq 0xef -and $byte[1] -eq 0xbb -and $byte[2] -eq 0xbf) { return 'UTF8BOM' } elseif ($byte[0] -eq 0xff -and $byte[1] -eq 0xfe) { return 'Unicode' } elseif ($byte[0] -eq 0xfe -and $byte[1] -eq 0xff) { return 'BigEndianUnicode' } elseif ($byte[0] -eq 0x2b -and $byte[1] -eq 0x2f -and $byte[2] -eq 0x76) { return 'UTF7' } else { for ($i = 0; $i -lt $byte.Length; $i++) { if ($byte[$i] -gt 0x7F) { return 'UTF8' } } return 'ASCII' } } function Get-FileInformation { <# .SYNOPSIS Get information about file such as Name, FullName and Size .DESCRIPTION Get information about file such as Name, FullName and Size .PARAMETER File File to get information about .EXAMPLE Get-FileInformation -File 'C:\Support\GitHub\PSSharedGoods\Public\FilesFolders\Get-FileInformation.ps1' .NOTES General notes #> [CmdletBinding()] param( [alias('LiteralPath', 'Path')][string] $File ) if (Test-Path -LiteralPath $File) { $Item = Get-Item -LiteralPath $File [PSCustomObject] @{ Name = $Item.Name FullName = $Item.FullName Size = Get-FileSize -Bytes $Item.Length IsReadOnly = $Item.IsReadOnly LastWriteTime = $Item.LastWriteTime } } } function Get-FileMetaData { <# .SYNOPSIS Small function that gets metadata information from file providing similar output to what Explorer shows when viewing file .DESCRIPTION Small function that gets metadata information from file providing similar output to what Explorer shows when viewing file .PARAMETER File FileName or FileObject .EXAMPLE Get-ChildItem -Path $Env:USERPROFILE\Desktop -Force | Get-FileMetaData | Out-HtmlView -ScrollX -Filtering -AllProperties .EXAMPLE Get-ChildItem -Path $Env:USERPROFILE\Desktop -Force | Where-Object { $_.Attributes -like '*Hidden*' } | Get-FileMetaData | Out-HtmlView -ScrollX -Filtering -AllProperties .NOTES #> [CmdletBinding()] param ( [Parameter(Position = 0, ValueFromPipeline)][Object] $File, [ValidateSet('None', 'MACTripleDES', 'MD5', 'RIPEMD160', 'SHA1', 'SHA256', 'SHA384', 'SHA512')][string] $HashAlgorithm = 'None', [switch] $Signature, [switch] $AsHashTable ) Process { foreach ($F in $File) { $MetaDataObject = [ordered] @{} if ($F -is [string]) { if ($F -and (Test-Path -LiteralPath $F)) { $FileInformation = Get-ItemProperty -Path $F if ($FileInformation -is [System.IO.DirectoryInfo]) { continue } } else { Write-Warning "Get-FileMetaData - Doesn't exists. Skipping $F." continue } } elseif ($F -is [System.IO.DirectoryInfo]) { continue } elseif ($F -is [System.IO.FileInfo]) { $FileInformation = $F } else { Write-Warning "Get-FileMetaData - Only files are supported. Skipping $F." continue } $ShellApplication = New-Object -ComObject Shell.Application $ShellFolder = $ShellApplication.Namespace($FileInformation.Directory.FullName) $ShellFile = $ShellFolder.ParseName($FileInformation.Name) $MetaDataProperties = [ordered] @{} 0..400 | ForEach-Object -Process { $DataValue = $ShellFolder.GetDetailsOf($null, $_) $PropertyValue = (Get-Culture).TextInfo.ToTitleCase($DataValue.Trim()).Replace(' ', '') if ($PropertyValue -ne '') { $MetaDataProperties["$_"] = $PropertyValue } } foreach ($Key in $MetaDataProperties.Keys) { $Property = $MetaDataProperties[$Key] $Value = $ShellFolder.GetDetailsOf($ShellFile, [int] $Key) if ($Property -in 'Attributes', 'Folder', 'Type', 'SpaceFree', 'TotalSize', 'SpaceUsed') { continue } If (($null -ne $Value) -and ($Value -ne '')) { $MetaDataObject["$Property"] = $Value } } if ($FileInformation.VersionInfo) { $SplitInfo = ([string] $FileInformation.VersionInfo).Split([char]13) foreach ($Item in $SplitInfo) { $Property = $Item.Split(":").Trim() if ($Property[0] -and $Property[1] -ne '') { if ($Property[1] -in 'False', 'True') { $MetaDataObject["$($Property[0])"] = [bool] $Property[1] } else { $MetaDataObject["$($Property[0])"] = $Property[1] } } } } $MetaDataObject["Attributes"] = $FileInformation.Attributes $MetaDataObject['IsReadOnly'] = $FileInformation.IsReadOnly $MetaDataObject['IsHidden'] = $FileInformation.Attributes -like '*Hidden*' $MetaDataObject['IsSystem'] = $FileInformation.Attributes -like '*System*' if ($Signature) { $DigitalSignature = Get-AuthenticodeSignature -FilePath $FileInformation.Fullname $MetaDataObject['SignatureCertificateSubject'] = $DigitalSignature.SignerCertificate.Subject $MetaDataObject['SignatureCertificateIssuer'] = $DigitalSignature.SignerCertificate.Issuer $MetaDataObject['SignatureCertificateSerialNumber'] = $DigitalSignature.SignerCertificate.SerialNumber $MetaDataObject['SignatureCertificateNotBefore'] = $DigitalSignature.SignerCertificate.NotBefore $MetaDataObject['SignatureCertificateNotAfter'] = $DigitalSignature.SignerCertificate.NotAfter $MetaDataObject['SignatureCertificateThumbprint'] = $DigitalSignature.SignerCertificate.Thumbprint $MetaDataObject['SignatureStatus'] = $DigitalSignature.Status $MetaDataObject['IsOSBinary'] = $DigitalSignature.IsOSBinary } if ($HashAlgorithm -ne 'None') { $MetaDataObject[$HashAlgorithm] = (Get-FileHash -LiteralPath $FileInformation.FullName -Algorithm $HashAlgorithm).Hash } if ($AsHashTable) { $MetaDataObject } else { [PSCustomObject] $MetaDataObject } } } } function Get-FileName { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Extension Parameter description .PARAMETER Temporary Parameter description .PARAMETER TemporaryFileOnly Parameter description .EXAMPLE Get-FileName -Temporary Output: 3ymsxvav.tmp .EXAMPLE Get-FileName -Temporary Output: C:\Users\pklys\AppData\Local\Temp\tmpD74C.tmp .EXAMPLE Get-FileName -Temporary -Extension 'xlsx' Output: C:\Users\pklys\AppData\Local\Temp\tmp45B6.xlsx .NOTES General notes #> [CmdletBinding()] param( [string] $Extension = 'tmp', [switch] $Temporary, [switch] $TemporaryFileOnly ) if ($Temporary) { return [io.path]::Combine([System.IO.Path]::GetTempPath(), "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).$Extension") } if ($TemporaryFileOnly) { return "$($([System.IO.Path]::GetRandomFileName()).Split('.')[0]).$Extension" } } function Get-FileOwner { [cmdletBinding()] param( [Array] $Path, [switch] $Recursive, [switch] $JustPath, [switch] $Resolve, [switch] $AsHashTable ) Begin { } Process { foreach ($P in $Path) { if ($P -is [System.IO.FileSystemInfo]) { $FullPath = $P.FullName } elseif ($P -is [string]) { $FullPath = $P } if ($FullPath -and (Test-Path -Path $FullPath)) { if ($JustPath) { $FullPath | ForEach-Object -Process { $ACL = Get-Acl -Path $_ $Object = [ordered]@{ FullName = $_ Owner = $ACL.Owner } if ($Resolve) { $Identity = Convert-Identity -Identity $ACL.Owner if ($Identity) { $Object['OwnerName'] = $Identity.Name $Object['OwnerSid'] = $Identity.SID $Object['OwnerType'] = $Identity.Type } else { $Object['OwnerName'] = '' $Object['OwnerSid'] = '' $Object['OwnerType'] = '' } } if ($AsHashTable) { $Object } else { [PSCustomObject] $Object } } } else { Get-ChildItem -LiteralPath $FullPath -Recurse:$Recursive -Force | ForEach-Object -Process { $File = $_ $ACL = Get-Acl -Path $File.FullName $Object = [ordered] @{ FullName = $_.FullName Extension = $_.Extension CreationTime = $_.CreationTime LastAccessTime = $_.LastAccessTime LastWriteTime = $_.LastWriteTime Attributes = $_.Attributes Owner = $ACL.Owner } if ($Resolve) { $Identity = Convert-Identity -Identity $ACL.Owner if ($Identity) { $Object['OwnerName'] = $Identity.Name $Object['OwnerSid'] = $Identity.SID $Object['OwnerType'] = $Identity.Type } else { $Object['OwnerName'] = '' $Object['OwnerSid'] = '' $Object['OwnerType'] = '' } } if ($AsHashTable) { $Object } else { [PSCustomObject] $Object } } } } } } End { } } function Get-FilePermission { [alias('Get-PSPermissions', 'Get-FilePermissions')] [cmdletBinding()] param( [Array] $Path, [switch] $Inherited, [switch] $NotInherited, [switch] $ResolveTypes, [switch] $Extended, [switch] $IncludeACLObject, [switch] $AsHashTable, [System.Security.AccessControl.FileSystemSecurity] $ACLS ) foreach ($P in $Path) { if ($P -is [System.IO.FileSystemInfo]) { $FullPath = $P.FullName } elseif ($P -is [string]) { $FullPath = $P } $TestPath = Test-Path -Path $FullPath if ($TestPath) { if (-not $ACLS) { try { $ACLS = (Get-Acl -Path $FullPath -ErrorAction Stop) } catch { Write-Warning -Message "Get-FilePermission - Can't access $FullPath. Error $($_.Exception.Message)" continue } } $Output = foreach ($ACL in $ACLS.Access) { if ($Inherited) { if ($ACL.IsInherited -eq $false) { continue } } if ($NotInherited) { if ($ACL.IsInherited -eq $true) { continue } } $TranslateRights = Convert-GenericRightsToFileSystemRights -OriginalRights $ACL.FileSystemRights $ReturnObject = [ordered] @{ } $ReturnObject['Path' ] = $FullPath $ReturnObject['AccessControlType'] = $ACL.AccessControlType if ($ResolveTypes) { $Identity = Convert-Identity -Identity $ACL.IdentityReference if ($Identity) { $ReturnObject['Principal'] = $ACL.IdentityReference $ReturnObject['PrincipalName'] = $Identity.Name $ReturnObject['PrincipalSid'] = $Identity.Sid $ReturnObject['PrincipalType'] = $Identity.Type } else { $ReturnObject['Principal'] = $Identity $ReturnObject['PrincipalName'] = '' $ReturnObject['PrincipalSid'] = '' $ReturnObject['PrincipalType'] = '' } } else { $ReturnObject['Principal'] = $ACL.IdentityReference.Value } $ReturnObject['FileSystemRights'] = $TranslateRights $ReturnObject['IsInherited'] = $ACL.IsInherited if ($Extended) { $ReturnObject['InheritanceFlags'] = $ACL.InheritanceFlags $ReturnObject['PropagationFlags'] = $ACL.PropagationFlags } if ($IncludeACLObject) { $ReturnObject['ACL'] = $ACL $ReturnObject['AllACL'] = $ACLS } if ($AsHashTable) { $ReturnObject } else { [PSCustomObject] $ReturnObject } } $Output } else { Write-Warning "Get-PSPermissions - Path $Path doesn't exists. Skipping." } } } function Get-FilesInFolder { [CmdletBinding()] param( [string] $Folder, [string] $Extension = '*.evtx' ) $Files = Get-ChildItem -Path $Folder -Filter $Extension -Recurse $ReturnFiles = foreach ($File in $Files) { $File.FullName } return $ReturnFiles } function Get-FileSize { [CmdletBinding()] param( $Bytes ) $sizes = 'Bytes,KB,MB,GB,TB,PB,EB,ZB' -split ',' for ($i = 0; ($Bytes -ge 1kb) -and ($i -lt $sizes.Count); $i++) { $Bytes /= 1kb } $N = 2; if ($i -eq 0) { $N = 0 } return "{0:N$($N)} {1}" -f $Bytes, $sizes[$i] } function Get-PathSeparator { [CmdletBinding()] param() return [IO.Path]::PathSeparator } function Get-PathTemporary { [CmdletBinding()] param() return [IO.path]::GetTempPath() } function Get-TemporaryDirectory { param( ) $TemporaryFolder = Get-RandomStringName -Size 13 -LettersOnly -ToLower $TemporaryPath = [system.io.path]::GetTempPath() $Output = New-Item -ItemType Directory -Path $TemporaryPath -Name $TemporaryFolder -Force if (Test-Path -LiteralPath $Output.FullName) { $Output } } function Remove-FilePermission { [cmdletBinding()] param( [string] $Path, [string] $UserOrGroup = "", [switch] $All ) $ACL = Get-Acl -Path $Path if ($UserOrGroup -ne "") { foreach ($access in $ACL.Access) { if ($access.IdentityReference.Value -eq $UserOrGroup) { $ACL.RemoveAccessRule($access) | Out-Null } } } if ($All -eq $true) { foreach ($access in $ACL.Access) { $ACL.RemoveAccessRule($access) | Out-Null } } Set-Acl -Path $Path -AclObject $ACL } function Set-FileInheritance { [cmdletBinding()] param( [string] $StartingDir, [switch] $DisableInheritance, [switch] $KeepInheritedAcl ) $acl = Get-Acl -Path $StartingDir $acl.SetAccessRuleProtection($DisableInheritance, $KeepInheritedAcl) $acl | Set-Acl -Path $StartingDir } function Set-FileOwner { [cmdletBinding(SupportsShouldProcess)] param( [Array] $Path, [switch] $Recursive, [string] $Owner, [string[]] $Exlude, [switch] $JustPath ) Begin { } Process { foreach ($P in $Path) { if ($P -is [System.IO.FileSystemInfo]) { $FullPath = $P.FullName } elseif ($P -is [string]) { $FullPath = $P } $OwnerTranslated = [System.Security.Principal.NTAccount]::new($Owner) if ($FullPath -and (Test-Path -Path $FullPath)) { if ($JustPath) { $FullPath | ForEach-Object -Process { $File = $_ try { $ACL = Get-Acl -Path $File -ErrorAction Stop } catch { Write-Warning "Set-FileOwner - Getting ACL failed with error: $($_.Exception.Message)" } if ($ACL.Owner -notin $Exlude -and $ACL.Owner -ne $OwnerTranslated) { if ($PSCmdlet.ShouldProcess($File, "Replacing owner $($ACL.Owner) to $OwnerTranslated")) { try { $ACL.SetOwner($OwnerTranslated) Set-Acl -Path $File -AclObject $ACL -ErrorAction Stop } catch { Write-Warning "Set-FileOwner - Replacing owner $($ACL.Owner) to $OwnerTranslated failed with error: $($_.Exception.Message)" } } } } } else { Get-ChildItem -LiteralPath $FullPath -Recurse:$Recursive -ErrorAction SilentlyContinue -ErrorVariable err | ForEach-Object -Process { $File = $_ try { $ACL = Get-Acl -Path $File.FullName -ErrorAction Stop } catch { Write-Warning "Set-FileOwner - Getting ACL failed with error: $($_.Exception.Message)" } if ($ACL.Owner -notin $Exlude -and $ACL.Owner -ne $OwnerTranslated) { if ($PSCmdlet.ShouldProcess($File.FullName, "Replacing owner $($ACL.Owner) to $OwnerTranslated")) { try { $ACL.SetOwner($OwnerTranslated) Set-Acl -Path $File.FullName -AclObject $ACL -ErrorAction Stop } catch { Write-Warning "Set-FileOwner - Replacing owner $($ACL.Owner) to $OwnerTranslated failed with error: $($_.Exception.Message)" } } } } foreach ($e in $err) { Write-Warning "Set-FileOwner - Errors processing $($e.Exception.Message) ($($e.CategoryInfo.Reason))" } } } } } End { } } function Set-FilePermission { [cmdletBinding()] param ( [string] $Path, [alias('UserOrGroup')][string] $Principal, [System.Security.AccessControl.InheritanceFlags] $InheritedFolderPermissions = @( [System.Security.AccessControl.InheritanceFlags]::ContainerInherit, [System.Security.AccessControl.InheritanceFlags]::ObjectInherit ), [System.Security.AccessControl.AccessControlType] $AccessControlType = [System.Security.AccessControl.AccessControlType]::Allow, [System.Security.AccessControl.PropagationFlags] $PropagationFlags = [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.FileSystemRights] $AclRightsToAssign ) if ($Principal) { $User = [System.Security.Principal.NTAccount]::new($Principal) $ACL = Get-Acl -Path $Path $Rule = [System.Security.AccessControl.FileSystemAccessRule]::new($User, $AclRightsToAssign, $InheritedFolderPermissions, $PropagationFlags, $AccessControlType) $ACL.SetAccessRule($Rule) Try { Set-Acl -Path $Path -AclObject $ACL } catch { Write-Warning "Set-FilePermission - Setting permission $AclRightsToAssign failed with error: $($_.Exception.Message)" } } } function Get-GitHubLatestRelease { <# .SYNOPSIS Gets one or more releases from GitHub repository .DESCRIPTION Gets one or more releases from GitHub repository .PARAMETER Url Url to github repository .EXAMPLE Get-GitHubLatestRelease -Url "https://api.github.com/repos/evotecit/Testimo/releases" | Format-Table .NOTES General notes #> [CmdLetBinding()] param( [parameter(Mandatory)][alias('ReleasesUrl')][uri] $Url ) $ProgressPreference = 'SilentlyContinue' $Responds = Test-Connection -ComputerName $URl.Host -Quiet -Count 1 if ($Responds) { Try { [Array] $JsonOutput = (Invoke-WebRequest -Uri $Url -ErrorAction Stop | ConvertFrom-Json) foreach ($JsonContent in $JsonOutput) { [PSCustomObject] @{ PublishDate = [DateTime] $JsonContent.published_at CreatedDate = [DateTime] $JsonContent.created_at PreRelease = [bool] $JsonContent.prerelease Version = [version] ($JsonContent.name -replace 'v', '') Tag = $JsonContent.tag_name Branch = $JsonContent.target_commitish Errors = '' } } } catch { [PSCustomObject] @{ PublishDate = $null CreatedDate = $null PreRelease = $null Version = $null Tag = $null Branch = $null Errors = $_.Exception.Message } } } else { [PSCustomObject] @{ PublishDate = $null CreatedDate = $null PreRelease = $null Version = $null Tag = $null Branch = $null Errors = "No connection (ping) to $($Url.Host)" } } $ProgressPreference = 'Continue' } function Get-GitHubVersion { <# .SYNOPSIS Get the latest version of a GitHub repository and compare with local version .DESCRIPTION Get the latest version of a GitHub repository and compare with local version .PARAMETER Cmdlet Cmdlet to find module for .PARAMETER RepositoryOwner Repository owner .PARAMETER RepositoryName Repository name .EXAMPLE Get-GitHubVersion -Cmdlet 'Start-DelegationModel' -RepositoryOwner 'evotecit' -RepositoryName 'DelegationModel' .NOTES General notes #> [cmdletBinding()] param( [Parameter(Mandatory)][string] $Cmdlet, [Parameter(Mandatory)][string] $RepositoryOwner, [Parameter(Mandatory)][string] $RepositoryName ) $App = Get-Command -Name $Cmdlet -ErrorAction SilentlyContinue if ($App) { [Array] $GitHubReleases = (Get-GitHubLatestRelease -Url "https://api.github.com/repos/$RepositoryOwner/$RepositoryName/releases" -Verbose:$false) $LatestVersion = $GitHubReleases[0] if (-not $LatestVersion.Errors) { if ($App.Version -eq $LatestVersion.Version) { "Current/Latest: $($LatestVersion.Version) at $($LatestVersion.PublishDate)" } elseif ($App.Version -lt $LatestVersion.Version) { "Current: $($App.Version), Published: $($LatestVersion.Version) at $($LatestVersion.PublishDate). Update?" } elseif ($App.Version -gt $LatestVersion.Version) { "Current: $($App.Version), Published: $($LatestVersion.Version) at $($LatestVersion.PublishDate). Lucky you!" } } else { "Current: $($App.Version)" } } else { "Current: Unknown" } } function Get-IPAddressRangeInformation { <# .SYNOPSIS Provides information about IP Address range .DESCRIPTION Provides information about IP Address range .PARAMETER Network Network in form of IP/NetworkLength (e.g. 10.2.10.0/24') .PARAMETER IPAddress IP Address to use .PARAMETER NetworkLength Network length to use .PARAMETER CIDRObject CIDRObject to use .EXAMPLE $CidrObject = @{ Ip = '10.2.10.0' NetworkLength = 24 } Get-IPAddressRangeInformation -CIDRObject $CidrObject | Format-Table .EXAMPLE Get-IPAddressRangeInformation -Network '10.2.10.0/24' | Format-Table .EXAMPLE Get-IPAddressRangeInformation -IPAddress '10.2.10.0' -NetworkLength 24 | Format-Table .NOTES General notes #> [cmdletBinding(DefaultParameterSetName = 'Network')] param( [Parameter(ParameterSetName = 'Network', Mandatory)][string] $Network, [Parameter(ParameterSetName = 'IPAddress', Mandatory)][string] $IPAddress, [Parameter(ParameterSetName = 'IPAddress', Mandatory)][int] $NetworkLength, [Parameter(ParameterSetName = 'CIDR', Mandatory)][psobject] $CIDRObject ) $IPv4Regex = '(?:(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)\.){3}(?:0?0?\d|0?[1-9]\d|1\d\d|2[0-5][0-5]|2[0-4]\d)' if ($Network) { $CIDRObject = @{ Ip = $Network.Split('/')[0] NetworkLength = $Network.Split('/')[1] } } elseif ($IPAddress -and $NetworkLength) { $CIDRObject = @{ Ip = $IPAddress NetworkLength = $NetworkLength } } elseif ($CIDRObject) { } else { Write-Error "Get-IPAddressRangeInformation - Invalid parameters specified" return } $o = [ordered] @{} $o.IP = [string] $CIDRObject.IP $o.BinaryIP = Convert-IPToBinary $o.IP if (-not $o.BinaryIP) { return } $o.NetworkLength = [int32] $CIDRObject.NetworkLength $o.SubnetMask = Convert-BinaryToIP ('1' * $o.NetworkLength).PadRight(32, '0') $o.BinarySubnetMask = ('1' * $o.NetworkLength).PadRight(32, '0') $o.BinaryNetworkAddress = $o.BinaryIP.SubString(0, $o.NetworkLength).PadRight(32, '0') if ($Contains) { if ($Contains -match "\A${IPv4Regex}\z") { return Test-IPIsInNetwork $Contains $o.BinaryNetworkAddress $o.BinaryNetworkAddress.SubString(0, $o.NetworkLength).PadRight(32, '1') } else { Write-Error "Get-IPAddressRangeInformation - Invalid IPv4 address specified with -Contains" return } } $o.NetworkAddress = Convert-BinaryToIP $o.BinaryNetworkAddress if ($o.NetworkLength -eq 32 -or $o.NetworkLength -eq 31) { $o.HostMin = $o.IP } else { $o.HostMin = Convert-BinaryToIP ([System.Convert]::ToString(([System.Convert]::ToInt64($o.BinaryNetworkAddress, 2) + 1), 2)).PadLeft(32, '0') } [string] $BinaryBroadcastIP = $o.BinaryNetworkAddress.SubString(0, $o.NetworkLength).PadRight(32, '1') $o.BinaryBroadcast = $BinaryBroadcastIP [int64] $DecimalHostMax = [System.Convert]::ToInt64($BinaryBroadcastIP, 2) - 1 [string] $BinaryHostMax = [System.Convert]::ToString($DecimalHostMax, 2).PadLeft(32, '0') $o.HostMax = Convert-BinaryToIP $BinaryHostMax $o.TotalHosts = [int64][System.Convert]::ToString(([System.Convert]::ToInt64($BinaryBroadcastIP, 2) - [System.Convert]::ToInt64($o.BinaryNetworkAddress, 2) + 1)) $o.UsableHosts = $o.TotalHosts - 2 if ($o.NetworkLength -eq 32) { $o.Broadcast = $Null $o.UsableHosts = [int64] 1 $o.TotalHosts = [int64] 1 $o.HostMax = $o.IP } elseif ($o.NetworkLength -eq 31) { $o.Broadcast = $Null $o.UsableHosts = [int64] 2 $o.TotalHosts = [int64] 2 [int64] $DecimalHostMax2 = [System.Convert]::ToInt64($BinaryBroadcastIP, 2) [string] $BinaryHostMax2 = [System.Convert]::ToString($DecimalHostMax2, 2).PadLeft(32, '0') $o.HostMax = Convert-BinaryToIP $BinaryHostMax2 } elseif ($o.NetworkLength -eq 30) { $o.UsableHosts = [int64] 2 $o.TotalHosts = [int64] 4 $o.Broadcast = Convert-BinaryToIP $BinaryBroadcastIP } else { $o.Broadcast = Convert-BinaryToIP $BinaryBroadcastIP } if ($Enumerate) { $IPRange = @(Get-IPRange $o.BinaryNetworkAddress $o.BinaryNetworkAddress.SubString(0, $o.NetworkLength).PadRight(32, '1')) if ((31, 32) -notcontains $o.NetworkLength ) { $IPRange = $IPRange[1..($IPRange.Count - 1)] $IPRange = $IPRange[0..($IPRange.Count - 2)] } $o.IPEnumerated = $IPRange } else { $o.IPEnumerated = @() } [PSCustomObject]$o } function Get-Logger { <# .SYNOPSIS Returns an instance of the logger object. .DESCRIPTION Long description .PARAMETER LogPath Parameter description .PARAMETER LogsDir Parameter description .PARAMETER Filename Parameter description .PARAMETER ShowTime Parameter description .PARAMETER TimeFormat Parameter description .EXAMPLE # with full log name $Logger = Get-Logger -ShowTime -LogPath 'C:\temp\test.log' $Logger.AddErrorRecord("test error") $Logger.AddInfoRecord("test info") $Logger.AddSuccessRecord("test success") $Logger.AddRecord("test record") .EXAMPLE # with directory name and auto-generated log name $Logger = Get-Logger -ShowTime -LogsDir 'C:\temp' $Logger.AddErrorRecord("test error") .EXAMPLE # with directory name and logo name defined separately $Logger = Get-Logger -ShowTime -Directory 'C:\temp' -Filename 'test.log' $Logger.AddErrorRecord("test error") .EXAMPLE # without logfile, only console output $Logger = Get-Logger -ShowTime $Logger.AddErrorRecord("test error") .NOTES General notes #> [CmdletBinding(DefaultParameterSetName = "All")] param ( [Parameter(Mandatory = $false, ParameterSetName = 'Logpath')][string] $LogPath, [Parameter(Mandatory = $false, ParameterSetName = 'Complexpath')][string] $LogsDir, [Parameter(Mandatory = $false, ParameterSetName = 'Complexpath')][string] $Filename, [switch] $ShowTime, [string] $TimeFormat = 'yyyy-MM-dd HH:mm:ss' ) if ($PSCmdlet.ParameterSetName -eq 'Complexpath') { if (-not $Filename) { $CallerName = [System.IO.Path]::GetFileNameWithoutExtension((Split-Path $MyInvocation.PSCommandPath -Leaf)) $Filename = "$([DateTime]::Now.ToString($TimeFormat) -replace('[^.\-\w]', '_'))_$CallerName.log" } $LogPath = Join-Path $LogsDir $Filename } if ($LogPath) { $LogsDir = [System.IO.Path]::GetDirectoryName($LogPath) New-Item $LogsDir -ItemType Directory -Force | Out-Null New-Item $LogPath -ItemType File -Force | Out-Null } $Logger = [PSCustomObject]@{ LogPath = $LogPath ShowTime = $ShowTime TimeFormat = $TimeFormat } Add-Member -InputObject $Logger -MemberType ScriptMethod AddErrorRecord -Value { param( [Parameter(Mandatory = $true)] [string]$String ) if (-not $this.LogPath) { Write-Color -Text "[Error] ", $String -Color Red, White -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } else { Write-Color -Text "[Error] ", $String -Color Red, White -LogFile:$this.LogPath -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } } Add-Member -InputObject $Logger -MemberType ScriptMethod AddInfoRecord -Value { param( [Parameter(Mandatory = $true)] [string]$String ) if (-not $this.LogPath) { Write-Color -Text "[Info] ", $String -Color Yellow, White -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } else { Write-Color -Text "[Info] ", $String -Color Yellow, White -LogFile:$this.LogPath -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } } Add-Member -InputObject $Logger -MemberType ScriptMethod AddWarningRecord -Value { param( [Parameter(Mandatory = $true)] [string]$String ) if (-not $this.LogPath) { Write-Color -Text "[Warning] ", $String -Color Magenta, White -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } else { Write-Color -Text "[Warning] ", $String -Color Magenta, White -LogFile:$this.LogPath -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } } Add-Member -InputObject $Logger -MemberType ScriptMethod AddRecord -Value { param( [Parameter(Mandatory = $true)] [string]$String ) if (-not $this.LogPath) { Write-Color -Text " $String" -Color White -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } else { Write-Color -Text " $String" -Color White -LogFile:$this.LogPath -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } } Add-Member -InputObject $Logger -MemberType ScriptMethod AddSuccessRecord -Value { param( [Parameter(Mandatory = $true)] [string]$String ) if (-not $this.LogPath) { Write-Color -Text "[Success] ", $String -Color Green, White -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } else { Write-Color -Text "[Success] ", $String -Color Green, White -LogFile:$this.LogPath -ShowTime:$this.ShowTime -TimeFormat $this:TimeFormat } } return $Logger } function Add-ToArray { [CmdletBinding()] param( [System.Collections.ArrayList] $List, [Object] $Element ) [void] $List.Add($Element) } function Add-ToArrayAdvanced { [CmdletBinding()] param( [System.Collections.ArrayList] $List, [Object] $Element, [switch] $SkipNull, [switch] $RequireUnique, [switch] $FullComparison, [switch] $Merge ) if ($SkipNull -and $null -eq $Element) { return } if ($RequireUnique) { if ($FullComparison) { foreach ($ListElement in $List) { if ($ListElement -eq $Element) { $TypeLeft = Get-ObjectType -Object $ListElement $TypeRight = Get-ObjectType -Object $Element if ($TypeLeft.ObjectTypeName -eq $TypeRight.ObjectTypeName) { return } } } } else { if ($List -contains $Element) { return } } } if ($Merge) { [void] $List.AddRange($Element) } else { [void] $List.Add($Element) } } function Add-ToHashTable($Hashtable, $Key, $Value) { if ($null -ne $Value -and $Value -ne '') { $Hashtable.Add($Key, $Value) } } function Clear-DataInformation { [CmdletBinding()] param( [System.Collections.IDictionary] $Data, [Array] $TypesRequired, [switch] $DontRemoveSupportData, [switch] $DontRemoveEmpty ) foreach ($Domain in $Data.FoundDomains.Keys) { $RemoveDomainKeys = foreach ($Key in $Data.FoundDomains.$Domain.Keys) { if ($null -eq $Data.FoundDomains.$Domain.$Key) { if (-not $DontRemoveEmpty) { $Key } continue } if ($Key -notin $TypesRequired -and $DontRemoveSupportData -eq $false) { $Key } } foreach ($Key in $RemoveDomainKeys) { $Data.FoundDomains.$Domain.Remove($Key) } } $RemoveDomains = foreach ($Domain in $Data.FoundDomains.Keys) { if ($Data.FoundDomains.$Domain.Count -eq 0) { $Domain } } foreach ($Domain in $RemoveDomains) { $Data.FoundDomains.Remove($Domain) } if ($Data.FoundDomains.Count -eq 0) { $Data.Remove('FoundDomains') } $RemoveKeys = foreach ($Key in $Data.Keys) { if ($Key -eq 'FoundDomains') { continue } if ($null -eq $Data.$Key) { if (-not $DontRemoveEmpty) { $Key } continue } if ($Key -notin $TypesRequired -and $DontRemoveSupportData -eq $false) { $Key } } foreach ($Key in $RemoveKeys) { $Data.Remove($Key) } } function Compare-MultipleObjects { [CmdLetBinding()] param( [System.Collections.IList] $Objects, [Array] $ObjectsName = @(), [switch] $CompareSorted, [switch] $FormatOutput, [switch] $FormatDifferences, [switch] $Summary, [string] $Splitter = ', ', [string[]] $Property, [string[]] $ExcludeProperty, [switch] $AllProperties, [switch] $SkipProperties, [int] $First, [int] $Last, [Array] $Replace, [switch] $FlattenObject ) if ($null -eq $Objects -or $Objects.Count -eq 1) { Write-Warning "Compare-MultipleObjects - Unable to compare objects. Not enough objects to compare ($($Objects.Count))." return } if (-not $ObjectsName) { $ObjectsName = @() } if ($ObjectsName.Count -gt 0 -and $Objects.Count -gt $ObjectsName.Count) { Write-Warning -Message "Compare-MultipleObjects - Unable to rename objects. ObjectsName small then amount of Objects ($($Objects.Count))." } function Compare-TwoArrays { [CmdLetBinding()] param( [string] $FieldName, [Array] $Object1, [Array] $Object2, [Array] $Replace ) $Result = [ordered] @{ Status = $false Same = [System.Collections.Generic.List[string]]::new() Add = [System.Collections.Generic.List[string]]::new() Remove = [System.Collections.Generic.List[string]]::new() } if ($Replace) { foreach ($R in $Replace) { if (($($R.Keys[0]) -eq '') -or ($($R.Keys[0]) -eq $FieldName)) { if ($null -ne $Object1) { $Object1 = $Object1 -replace $($R.Values)[0], $($R.Values)[1] } if ($null -ne $Object2) { $Object2 = $Object2 -replace $($R.Values)[0], $($R.Values)[1] } } } } if ($null -eq $Object1 -and $null -eq $Object2) { $Result['Status'] = $true } elseif (($null -eq $Object1) -or ($null -eq $Object2)) { $Result['Status'] = $false foreach ($O in $Object1) { $Result['Add'].Add($O) } foreach ($O in $Object2) { $Result['Remove'].Add($O) } } else { $ComparedObject = Compare-Object -ReferenceObject $Object1 -DifferenceObject $Object2 -IncludeEqual foreach ($_ in $ComparedObject) { if ($_.SideIndicator -eq '==') { $Result['Same'].Add($_.InputObject) } elseif (($_.SideIndicator -eq '<=')) { $Result['Add'].Add($_.InputObject) } elseif (($_.SideIndicator -eq '=>')) { $Result['Remove'].Add($_.InputObject) } } IF ($Result['Add'].Count -eq 0 -and $Result['Remove'].Count -eq 0) { $Result['Status'] = $true } else { $Result['Status'] = $false } } $Result } if ($ObjectsName[0]) { $ValueSourceName = $ObjectsName[0] } else { $ValueSourceName = "Source" } [Array] $Objects = foreach ($Object in $Objects) { if ($null -eq $Object) { [PSCustomObject] @{} } else { $Object } } if ($FlattenObject) { try { [Array] $Objects = ConvertTo-FlatObject -Objects $Objects -ExcludeProperty $ExcludeProperty } catch { Write-Warning "Compare-MultipleObjects - Unable to flatten objects. ($($_.Exception.Message))" } } if ($First -or $Last) { [int] $TotalCount = $First + $Last if ($TotalCount -gt 1) { $Objects = $Objects | Select-Object -First $First -Last $Last } else { Write-Warning "Compare-MultipleObjects - Unable to compare objects. Not enough objects to compare ($TotalCount)." return } } $ReturnValues = @( $FirstElement = [ordered] @{ } $FirstElement['Name'] = 'Properties' if ($Summary) { $FirstElement['Same'] = $null $FirstElement['Different'] = $null } $FirstElement['Status'] = $false $FirstObjectProperties = Select-Properties -Objects $Objects -Property $Property -ExcludeProperty $ExcludeProperty -AllProperties:$AllProperties if (-not $SkipProperties) { if ($FormatOutput) { $FirstElement[$ValueSourceName] = $FirstObjectProperties -join $Splitter } else { $FirstElement[$ValueSourceName] = $FirstObjectProperties } [Array] $IsSame = for ($i = 1; $i -lt $Objects.Count; $i++) { if ($ObjectsName[$i]) { $ValueToUse = $ObjectsName[$i] } else { $ValueToUse = $i } if ($Objects[0] -is [System.Collections.IDictionary]) { [string[]] $CompareObjectProperties = $Objects[$i].Keys } else { [string[]] $CompareObjectProperties = $Objects[$i].PSObject.Properties.Name [string[]] $CompareObjectProperties = Select-Properties -Objects $Objects[$i] -Property $Property -ExcludeProperty $ExcludeProperty -AllProperties:$AllProperties } if ($FormatOutput) { $FirstElement["$ValueToUse"] = $CompareObjectProperties -join $Splitter } else { $FirstElement["$ValueToUse"] = $CompareObjectProperties } if ($CompareSorted) { $Value1 = $FirstObjectProperties | Sort-Object $Value2 = $CompareObjectProperties | Sort-Object } else { $Value1 = $FirstObjectProperties $Value2 = $CompareObjectProperties } $Status = Compare-TwoArrays -FieldName 'Properties' -Object1 $Value1 -Object2 $Value2 -Replace $Replace if ($FormatDifferences) { $FirstElement["$ValueToUse-Add"] = $Status['Add'] -join $Splitter $FirstElement["$ValueToUse-Remove"] = $Status['Remove'] -join $Splitter $FirstElement["$ValueToUse-Same"] = $Status['Same'] -join $Splitter } else { $FirstElement["$ValueToUse-Add"] = $Status['Add'] $FirstElement["$ValueToUse-Remove"] = $Status['Remove'] $FirstElement["$ValueToUse-Same"] = $Status['Same'] } $Status } if ($IsSame.Status -notcontains $false) { $FirstElement['Status'] = $true } else { $FirstElement['Status'] = $false } if ($Summary) { [Array] $Collection = (0..($IsSame.Count - 1)).Where( { $IsSame[$_].Status -eq $true }, 'Split') if ($FormatDifferences) { $FirstElement['Same'] = ($Collection[0] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } ) -join $Splitter $FirstElement['Different'] = ($Collection[1] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } ) -join $Splitter } else { $FirstElement['Same'] = $Collection[0] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } $FirstElement['Different'] = $Collection[1] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } } } [PSCustomObject] $FirstElement } foreach ($NameProperty in $FirstObjectProperties) { $EveryOtherElement = [ordered] @{ } $EveryOtherElement['Name'] = $NameProperty if ($Summary) { $EveryOtherElement['Same'] = $null $EveryOtherElement['Different'] = $null } $EveryOtherElement.Status = $false if ($FormatOutput) { $EveryOtherElement[$ValueSourceName] = $Objects[0].$NameProperty -join $Splitter } else { $EveryOtherElement[$ValueSourceName] = $Objects[0].$NameProperty } [Array] $IsSame = for ($i = 1; $i -lt $Objects.Count; $i++) { $Skip = $false if ($ObjectsName[$i]) { $ValueToUse = $ObjectsName[$i] } else { $ValueToUse = $i } if ($Objects[$i] -is [System.Collections.IDictionary]) { if ($Objects[$i].Keys -notcontains $NameProperty) { $Status = [ordered] @{ Status = $false Same = @() Add = @() Remove = @() } $Skip = $true } } elseif ($Objects[$i].PSObject.Properties.Name -notcontains $NameProperty) { $Status = [ordered] @{ Status = $false; Same = @() Add = @() Remove = @() } $Skip = $true } if ($FormatOutput) { $EveryOtherElement["$ValueToUse"] = $Objects[$i].$NameProperty -join $Splitter } else { $EveryOtherElement["$ValueToUse"] = $Objects[$i].$NameProperty } if ($CompareSorted) { $Value1 = $Objects[0].$NameProperty | Sort-Object $Value2 = $Objects[$i].$NameProperty | Sort-Object } else { $Value1 = $Objects[0].$NameProperty $Value2 = $Objects[$i].$NameProperty } if ($Value1 -is [PSCustomObject]) { [ordered] @{ Status = $null; Same = @(); Add = @(); Remove = @() } continue } elseif ($Value1 -is [System.Collections.IDictionary]) { [ordered] @{ Status = $null; Same = @(); Add = @(); Remove = @() } continue } elseif ($Value1 -is [Array] -and $Value1.Count -ne 0 -and $Value1[0] -isnot [string]) { [ordered] @{ Status = $null; Same = @(); Add = @(); Remove = @() } continue } if (-not $Skip) { $Status = Compare-TwoArrays -FieldName $NameProperty -Object1 $Value1 -Object2 $Value2 -Replace $Replace } else { $Status['Add'] = $Value1 } if ($FormatDifferences) { $EveryOtherElement["$ValueToUse-Add"] = $Status['Add'] -join $Splitter $EveryOtherElement["$ValueToUse-Remove"] = $Status['Remove'] -join $Splitter $EveryOtherElement["$ValueToUse-Same"] = $Status['Same'] -join $Splitter } else { $EveryOtherElement["$ValueToUse-Add"] = $Status['Add'] $EveryOtherElement["$ValueToUse-Remove"] = $Status['Remove'] $EveryOtherElement["$ValueToUse-Same"] = $Status['Same'] } $Status } if ($null -eq $IsSame.Status) { $EveryOtherElement['Status'] = $null } elseif ($IsSame.Status -notcontains $false) { $EveryOtherElement['Status'] = $true } else { $EveryOtherElement['Status'] = $false } if ($Summary) { [Array] $Collection = (0..($IsSame.Count - 1)).Where( { $IsSame[$_].Status -eq $true }, 'Split') if ($FormatDifferences) { $EveryOtherElement['Same'] = ($Collection[0] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } ) -join $Splitter $EveryOtherElement['Different'] = ($Collection[1] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } ) -join $Splitter } else { $EveryOtherElement['Same'] = $Collection[0] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } $EveryOtherElement['Different'] = $Collection[1] | ForEach-Object { $Count = $_ + 1 if ($ObjectsName[$Count]) { $ObjectsName[$Count] } else { $Count } } } } [PSCuStomObject] $EveryOtherElement } ) if ($ReturnValues.Count -eq 1) { return , $ReturnValues } else { return $ReturnValues } } function Compare-ObjectsAdvanced { param( [object] $Object1, [object] $Object2, [alias('Property')][string] $CommonProperty = 'DistinguishedName', [string[]] $AddObjectArrayName, [object[]] $AddObjectArray, [string] $Object1Property, [string] $Object2Property, [string] $ObjectPropertySubstitute = 'SpecialValueToCompare', [switch] $RemoveSideIndicator, [switch] $KeepTemporaryProperty, [ValidateSet('Left', 'Right')][string] $Side = 'Left' # May need Both later on ) $Objects = New-GenericList if ($null -eq $Object1 -and $null -eq $Object2) { } elseif ($null -eq $Object1) { } elseif ($null -eq $Object2) { foreach ($G in $Object1) { for ($a = 0; $a -lt $AddObjectArrayName.Count; $a++) { $G | Add-Member -MemberType NoteProperty -Name $AddObjectArrayName[$a] -Value $AddObjectArray[$a] -Force } $Objects.Add($G) } } else { $Terminate = New-GenericList -Type [bool] if ($Object1Property -and $Object2Property) { if ($Object1[0].PSObject.Properties.Name -notcontains $Object1Property) { Write-Warning -Message "Compare-InfrastructureObjects - Object1 property doesn't exists $Object1Property" $Terminate.Add($true) } if ($Object2[0].PSObject.Properties.Name -notcontains $Object2Property) { Write-Warning -Message "Compare-InfrastructureObjects - Object2 property doesn't exists $Object2Property" $Terminate.Add($true) } if ($Terminate -contains $true) { return } $Object1 | Add-Member -MemberType AliasProperty -Name $ObjectPropertySubstitute -Value $Object1Property -Force $Object2 | Add-Member -MemberType AliasProperty -Name $ObjectPropertySubstitute -Value $Object2Property -Force $Compare = Compare-Object -ReferenceObject $Object1 -DifferenceObject $Object2 -Property $ObjectPropertySubstitute -PassThru } else { if ($Object1[0].PSObject.Properties.Name -notcontains $CommonProperty) { Write-Warning -Message "Compare-InfrastructureObjects - Object1 property doesn't exists $CommonProperty" $Terminate.Add($true) } if ($Object2[0].PSObject.Properties.Name -notcontains $CommonProperty) { Write-Warning -Message "Compare-InfrastructureObjects - Object2 property doesn't exists $CommonProperty" $Terminate.Add($true) } if ($Terminate -contains $true) { return } $Compare = Compare-Object -ReferenceObject $Object1 -DifferenceObject $Object2 -Property $CommonProperty -PassThru } if ($Side -eq 'Left') { $Compare = $Compare | Where-Object { $_.SideIndicator -eq '<=' } } elseif ($Side -eq 'Right') { $Compare = $Compare | Where-Object { $_.SideIndicator -eq '=>' } } else { $Compare = $Compare | Where-Object { $_.SideIndicator -eq '==' } } foreach ($G in $Compare) { if ($RemoveSideIndicator) { $G.PSObject.Members.Remove('SideIndicator') } if (-not $KeepTemporaryProperty) { $G.PSObject.Members.Remove($ObjectPropertySubstitute) } for ($a = 0; $a -lt $AddObjectArrayName.Count; $a++) { $G | Add-Member -MemberType NoteProperty -Name $AddObjectArrayName[$a] -Value $AddObjectArray[$a] -Force } $Objects.Add($G) } } return $Objects } Function Compare-ObjectProperties { Param( [PSObject]$ReferenceObject, [PSObject]$DifferenceObject, [switch]$CaseSensitive = $false ) $objprops = @( $($ReferenceObject | Get-Member -MemberType Property, NoteProperty | ForEach-Object Name), $($DifferenceObject | Get-Member -MemberType Property, NoteProperty | ForEach-Object Name) ) $objprops = $objprops | Sort-Object -Unique $diffs = foreach ($objprop in $objprops) { $diff = Compare-Object $ReferenceObject $DifferenceObject -Property $objprop -CaseSensitive:$CaseSensitive if ($diff) { $diffprops = [PsCustomObject] @{ PropertyName = $objprop RefValue = ($diff | Where-Object { $_.SideIndicator -eq '<=' } | ForEach-Object $($objprop)) DiffValue = ($diff | Where-Object { $_.SideIndicator -eq '=>' } | ForEach-Object $($objprop)) } $diffprops } } if ($diffs) { return ($diffs | Select-Object PropertyName, RefValue, DiffValue) } } function Copy-Dictionary { <# .SYNOPSIS Copies dictionary/hashtable .DESCRIPTION Copies dictionary uusing PS Serializer. Replaces usage of BinnaryFormatter due to no support in PS 7.4 .PARAMETER Dictionary Dictionary to copy .EXAMPLE $Test = [ordered] @{ Test = 'Test' Test1 = @{ Test2 = 'Test2' Test3 = @{ Test4 = 'Test4' } } Test2 = @( "1", "2", "3" ) Test3 = [PSCustomObject] @{ Test4 = 'Test4' Test5 = 'Test5' } } $New1 = Copy-Dictionary -Dictionary $Test $New1 .NOTES #> [alias('Copy-Hashtable', 'Copy-OrderedHashtable')] [cmdletbinding()] param( [System.Collections.IDictionary] $Dictionary ) $clone = [System.Management.Automation.PSSerializer]::Serialize($Dictionary, [int32]::MaxValue) return [System.Management.Automation.PSSerializer]::Deserialize($clone) } function Copy-DictionaryManual { [CmdletBinding()] param( [System.Collections.IDictionary] $Dictionary ) $clone = [ordered] @{} foreach ($Key in $Dictionary.Keys) { $value = $Dictionary.$Key $clonedValue = switch ($Dictionary.$Key) { { $null -eq $_ } { $null continue } { $_ -is [System.Collections.IDictionary] } { Copy-DictionaryManual -Dictionary $_ continue } { $type = $_.GetType() $type.IsPrimitive -or $type.IsValueType -or $_ -is [string] } { $_ continue } default { $_ | Select-Object -Property * } } if ($value -is [System.Collections.IList]) { $clone[$Key] = @($clonedValue) } else { $clone[$Key] = $clonedValue } } $clone } function Format-AddSpaceToSentence { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Text Parameter description .EXAMPLE $test = @( 'OnceUponATime', 'OnceUponATime1', 'Money@Risk', 'OnceUponATime123', 'AHappyMan2014' 'OnceUponATime_123' ) Format-AddSpaceToSentence -Text $Test $Test | Format-AddSpaceToSentence -ToLowerCase .NOTES General notes #> [CmdletBinding()] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)][string[]] $Text, [switch] $ToLowerCase ) Begin { } Process { $Value = foreach ($T in $Text) { ($T -creplace '([A-Z\W_]|\d+)(?<![a-z])', ' $&').trim() } if ($ToLowerCase) { $Value.ToLower() } else { $Value } } End { } } function Format-Dictionary { <# .SYNOPSIS Sorts dictionary/hashtable keys including nested hashtables and returns ordered dictionary .DESCRIPTION Sorts dictionary/hashtable keys including nested hashtables and returns ordered dictionary .PARAMETER Hashtable Hashtable to sort .EXAMPLE $Hashtable = [ordered] @{ ModuleVersion = '2.0.X' #PreReleaseTag = 'Preview5' CompatiblePSEditions = @('Desktop', 'Core') RunMe = @{ Name = 'RunMe' Type = 'Script' Path = 'RunMe.ps1' } GUID = 'eb76426a-1992-40a5-82cd-6480f883ef4d' Author = 'Przemyslaw Klys' CompanyName = 'Evotec' Copyright = "(c) 2011 - $((Get-Date).Year) Przemyslaw Klys @ Evotec. All rights reserved." Description = 'Simple project allowing preparing, managing, building and publishing modules to PowerShellGallery' PowerShellVersion = '5.1' Tags = @('Windows', 'MacOS', 'Linux', 'Build', 'Module') IconUri = 'https://evotec.xyz/wp-content/uploads/2019/02/PSPublishModule.png' ProjectUri = 'https://github.com/EvotecIT/PSPublishModule' DotNetFrameworkVersion = '4.5.2' } $Hashtable = Format-Dictionary -Hashtable $Hashtable $Hashtable .EXAMPLE $Hashtable = Format-Dictionary -Hashtable $Hashtable -ByValue $Hashtable .EXAMPLE $Hashtable = Format-Dictionary -Hashtable $Hashtable -ByValue -Descending $Hashtable .NOTES General notes #> [alias('Sort-Dictionary')] [CmdletBinding()] param( [alias('Dictionary', 'OrderedDictionary')] [Parameter(Mandatory, ValueFromPipeline)] [System.Collections.IDictionary] $Hashtable, [switch] $Descending, [switch] $ByValue ) $Ordered = [ordered] @{} if ($ByValue) { $Hashtable.GetEnumerator() | Sort-Object -Property Value -Descending:$Descending.IsPresent | ForEach-Object { if ($_.Value -is [System.Collections.IDictionary]) { $Ordered[$_.Key] = Format-Dictionary -Hashtable $_.Value -Descending:$Descending.IsPresent -ByValue:$ByValue.IsPresent } else { $Ordered[$_.Key] = $_.Value } } } else { foreach ($K in [string[]] $Hashtable.Keys | Sort-Object -Descending:$Descending.IsPresent) { if ($Hashtable[$K] -is [System.Collections.IDictionary]) { $Ordered[$K] = Format-Dictionary -Hashtable $Hashtable[$K] -Descending:$Descending.IsPresent -ByValue:$ByValue.IsPresent } else { $Ordered[$K] = $Hashtable[$K] } } } $Ordered } function Format-FirstXChars { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Text Parameter description .PARAMETER NumberChars Parameter description .EXAMPLE Format-FirstChars -Text "VERBOSE: Loading module from path 'C:\Users\pklys\.vscode\extensions\ms-vs" -NumberChars 15 .NOTES General notes #> param( [string] $Text, [int] $NumberChars ) return ($Text.ToCharArray() | Select-Object -First $NumberChars) -join '' } function Format-PSTable { [CmdletBinding()] param ( [parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)][System.Collections.ICollection] $Object, [switch] $SkipTitle, [string[]] $Property, [string[]] $ExcludeProperty, [Object] $OverwriteHeaders, [switch] $PreScanHeaders, [string] $Splitter = ';' ) if ($Object[0] -is [System.Collections.IDictionary]) { $Array = @( if (-not $SkipTitle) { , @('Name', 'Value') } foreach ($O in $Object) { foreach ($Name in $O.Keys) { $Value = $O[$Name] if ($O[$Name].Count -gt 1) { $Value = $O[$Name] -join $Splitter } else { $Value = $O[$Name] } , @($Name, $Value) } } ) if ($Array.Count -eq 1) { , $Array } else { $Array } } elseif ($Object[0].GetType().Name -match 'bool|byte|char|datetime|decimal|double|ExcelHyperLink|float|int|long|sbyte|short|string|timespan|uint|ulong|URI|ushort') { return $Object } else { if ($Property) { $Object = $Object | Select-Object -Property $Property } $Array = @( if ($PreScanHeaders) { $Titles = Get-ObjectProperties -Object $Object } elseif ($OverwriteHeaders) { $Titles = $OverwriteHeaders } else { $Titles = $Object[0].PSObject.Properties.Name } if (-not $SkipTitle) { , $Titles } foreach ($O in $Object) { $ArrayValues = foreach ($Name in $Titles) { $Value = $O."$Name" if ($Value.Count -gt 1) { $Value -join $Splitter } elseif ($Value.Count -eq 1) { if ($Value.Value) { $Value.Value } else { $Value } } else { '' } } , $ArrayValues } ) if ($Array.Count -eq 1) { , $Array } else { $Array } } } function Format-Stream { [alias('FS', 'Format-TableStream', 'Format-ListStream')] ##[alias('ftv','ftd','fto','fth','fti','flv','fld','flo','flh','fli','Format-TableVerbose', 'Format-TableDebug', 'Format-TableInformation', 'Format-TableWarning')] [CmdletBinding(DefaultParameterSetName = 'All')] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 1)] [Array] $InputObject, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 0, ParameterSetName = 'Property')] [string[]] $Property, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 2, ParameterSetName = 'ExcludeProperty')] [string[]] $ExcludeProperty, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 3)] [switch] $HideTableHeaders, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 4)] [int] $ColumnHeaderSize, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 5)] [switch] $AlignRight, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 6)] [validateset('Output', 'Host', 'Warning', 'Verbose', 'Debug', 'Information')] [string] $Stream = 'Verbose', [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 7)] [alias('AsList')][switch] $List, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 8)] [alias('Rotate', 'RotateData', 'TransposeColumnsRows', 'TransposeData')] [switch] $Transpose, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 9)] [ValidateSet('ASC', 'DESC', 'NONE')] [string] $TransposeSort = 'NONE', [alias('Color')] [System.ConsoleColor[]] $ForegroundColor, [alias('ColorRow')] [int[]] $ForegroundColorRow ) Begin { $IsVerbosePresent = $PSCmdlet.MyInvocation.BoundParameters['Verbose'].IsPresent if ($Stream -eq 'Output') { } elseif ($Stream -eq 'Host') { } elseif ($Stream -eq 'Warning') { [System.Management.Automation.ActionPreference] $WarningCurrent = $WarningPreference $WarningPreference = 'continue' } elseif ($Stream -eq 'Verbose') { [System.Management.Automation.ActionPreference] $VerboseCurrent = $VerbosePreference $VerbosePreference = 'continue' } elseif ($Stream -eq 'Debug') { [System.Management.Automation.ActionPreference] $DebugCurrent = $DebugPreference $DebugPreference = 'continue' } elseif ($Stream -eq 'Information') { [System.Management.Automation.ActionPreference] $InformationCurrent = $InformationPreference $InformationPreference = 'continue' } [bool] $FirstRun = $True [bool] $FirstLoop = $True [bool] $FirstList = $True [int] $ScreenWidth = $Host.UI.RawUI.WindowSize.Width - 12 $ArrayList = @() } Process { if ($InputObject.Count -eq 0) { break } if ($FirstRun) { $FirstRun = $false if ($Transpose) { $InputObject = Format-TransposeTable -Object $InputObject -Sort $TransposeSort } $Data = Format-PSTable -Object $InputObject -Property $Property -ExcludeProperty $ExcludeProperty -NoAliasOrScriptProperties:$NoAliasOrScriptProperties -DisplayPropertySet:$DisplayPropertySet -PreScanHeaders:$PreScanHeaders $Headers = $Data[0] if ($HideTableHeaders) { $Data.RemoveAt(0); } $ArrayList += $Data } else { if ($Transpose) { $InputObject = Format-TransposeTable -Object $InputObject -Sort $TransposeSort } $Data = Format-PSTable -Object $InputObject -Property $Property -ExcludeProperty $ExcludeProperty -NoAliasOrScriptProperties:$NoAliasOrScriptProperties -DisplayPropertySet:$DisplayPropertySet -PreScanHeaders:$PreScanHeaders -OverwriteHeaders $Headers -SkipTitle $ArrayList += $Data } } End { if (-not $ColumnHeaderSize) { $ColumnLength = [int[]]::new($Headers.Count); foreach ($Row in $ArrayList) { $i = 0 foreach ($Column in $Row) { $Length = "$Column".Length if ($Length -gt $ColumnLength[$i]) { $ColumnLength[$i] = $Length } $i++ } } if ($IsVerbosePresent) { Write-Verbose "Format-TableVerbose - ScreenWidth $ScreenWidth" Write-Verbose "Format-TableVerbose - Column Lengths $($ColumnLength -join ',')" } } if ($Stream -eq 'Output') { Write-Output -InputObject '' } elseif ($Stream -eq 'Host') { Write-Host -Object '' } elseif ($Stream -eq 'Warning') { Write-Warning -Message '' } elseif ($Stream -eq 'Verbose') { Write-Verbose -Message '' } elseif ($Stream -eq 'Debug') { Write-Debug -Message '' } elseif ($Stream -eq 'Information') { Write-Information -MessageData '' } if ($List) { [int] $RowCount = 1 foreach ($Row in $ArrayList ) { [string] $Output = '' [int] $ColumnNumber = 0 [int] $CurrentColumnLength = 0 if ($ColumnHeaderSize) { $PadLength = $ColumnHeaderSize } else { $PadLength = (($Headers.Length | Measure-Object -Maximum).Maximum) + 1 } if (-not $FirstList) { $i = 0 foreach ($ColumnValue in $Row) { if (-not $HideTableHeaders) { if ($AlignRight) { $Head = $($Headers[$i]).PadLeft($PadLength) } else { $Head = $($Headers[$i]).PadRight($PadLength) } $Output = "$Head`: $ColumnValue" } else { $Output = "$ColumnValue" } if ($Stream -eq 'Output') { Write-Output -InputObject $Output } elseif ($Stream -eq 'Host') { Write-Host -Object $Output } elseif ($Stream -eq 'Warning') { Write-Warning -Message $Output } elseif ($Stream -eq 'Verbose') { Write-Verbose -Message $Output } elseif ($Stream -eq 'Debug') { Write-Debug -Message $Output } elseif ($Stream -eq 'Information') { Write-Information -MessageData $Output } $i++ } $RowCount++ if ($RowCount -ne $ArrayList.Count) { if ($Stream -eq 'Output') { Write-Output -InputObject '' } elseif ($Stream -eq 'Host') { Write-Host -Object '' } elseif ($Stream -eq 'Warning') { Write-Warning -Message '' } elseif ($Stream -eq 'Verbose') { Write-Verbose -Message '' } elseif ($Stream -eq 'Debug') { Write-Debug -Message '' } elseif ($Stream -eq 'Information') { Write-Information -MessageData '' } } } $FirstList = $false } } else { [int] $RowCountColors = 1 foreach ($Row in $ArrayList ) { [string] $Output = '' [int] $ColumnNumber = 0 [int] $CurrentColumnLength = 0 foreach ($ColumnValue in $Row) { if ($ColumnHeaderSize) { $PadLength = $ColumnHeaderSize } else { $PadLength = $ColumnLength[$ColumnNumber] + 1 } $CurrentColumnLength += $PadLength if ($CurrentColumnLength -ge $ScreenWidth) { break } if ($ColumnHeaderSize) { $ColumnValue = ("$ColumnValue".ToCharArray() | Select-Object -First ($PadLength - 1)) -join '' } else { $ColumnValue = ("$ColumnValue".ToCharArray() | Select-Object -First ($PadLength)) -join '' } if ($Output -eq '') { if ($AlignRight) { $Output = "$ColumnValue".PadLeft($PadLength) } else { $Output = "$ColumnValue".PadRight($PadLength) } } else { if ($AlignRight) { $Output = $Output + "$ColumnValue".PadLeft($PadLength) } else { $Output = $Output + "$ColumnValue".PadRight($PadLength) } } $ColumnNumber++ } if ($Stream -eq 'Output') { Write-Output -InputObject $Output } elseif ($Stream -eq 'Host') { if ($ForegroundColorRow -contains $RowCountColors) { [int] $Index = $ForegroundColorRow.IndexOf($RowCountColors) Write-Host -Object $Output -ForegroundColor $ForegroundColor[$Index] } else { Write-Host -Object $Output } } elseif ($Stream -eq 'Warning') { Write-Warning -Message $Output } elseif ($Stream -eq 'Verbose') { Write-Verbose -Message $Output } elseif ($Stream -eq 'Debug') { Write-Debug -Message $Output } elseif ($Stream -eq 'Information') { Write-Information -MessageData $Output } if (-not $HideTableHeaders) { if ($FirstLoop) { $HeaderUnderline = $Output -Replace '\w', '-' if ($Stream -eq 'Output') { Write-Output -InputObject $HeaderUnderline } elseif ($Stream -eq 'Host') { if ($ForegroundColorRow -contains $RowCountColors) { [int] $Index = $ForegroundColorRow.IndexOf($RowCountColors) Write-Host -Object $HeaderUnderline -ForegroundColor $ForegroundColor[$Index] } else { Write-Host -Object $HeaderUnderline } } elseif ($Stream -eq 'Warning') { Write-Warning -Message $HeaderUnderline } elseif ($Stream -eq 'Verbose') { Write-Verbose -Message $HeaderUnderline } elseif ($Stream -eq 'Debug') { Write-Debug -Message $HeaderUnderline } elseif ($Stream -eq 'Information') { Write-Information -MessageData $HeaderUnderline } } } $FirstLoop = $false $RowCountColors++ } } if ($Stream -eq 'Output') { Write-Output -InputObject '' } elseif ($Stream -eq 'Host') { Write-Host -Object '' } elseif ($Stream -eq 'Warning') { Write-Warning -Message '' } elseif ($Stream -eq 'Verbose') { Write-Verbose -Message '' } elseif ($Stream -eq 'Debug') { Write-Debug -Message '' } elseif ($Stream -eq 'Information') { Write-Information -MessageData '' } if ($Stream -eq 'Output') { } elseif ($Stream -eq 'Host') { } elseif ($Stream -eq 'Warning') { $WarningPreference = $WarningCurrent } elseif ($Stream -eq 'Verbose') { $VerbosePreference = $VerboseCurrent } elseif ($Stream -eq 'Debug') { $DebugPreference = $DebugCurrent } elseif ($Stream -eq 'Information') { $InformationPreference = $InformationCurrent } } } function Format-ToTitleCase { <# .SYNOPSIS Formats string or number of strings to Title Case .DESCRIPTION Formats string or number of strings to Title Case allowing for prettty display .PARAMETER Text Sentence or multiple sentences to format .PARAMETER RemoveWhiteSpace Removes spaces after formatting string to Title Case. .PARAMETER RemoveChar Array of characters to remove .EXAMPLE Format-ToTitleCase 'me' Output: Me .EXAMPLE 'me i feel good' | Format-ToTitleCase Output: Me I Feel Good Not Feel .EXAMPLE 'me i feel', 'not feel' | Format-ToTitleCase Output: Me I Feel Good Not Feel .EXAMPLE Format-ToTitleCase -Text 'This is my thing' -RemoveWhiteSpace Output: ThisIsMyThing .EXAMPLE Format-ToTitleCase -Text "This is my thing: That - No I don't want all chars" -RemoveWhiteSpace -RemoveChar ',', '-', "'", '\(', '\)', ':' .NOTES General notes #> [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)][string[]] $Text, [switch] $RemoveWhiteSpace, [string[]] $RemoveChar ) Begin { } Process { $Conversion = foreach ($T in $Text) { $Output = (Get-Culture).TextInfo.ToTitleCase($T) foreach ($Char in $RemoveChar) { $Output = $Output -replace $Char } if ($RemoveWhiteSpace) { $Output = $Output -replace ' ', '' } $Output } $Conversion } End { } } function Format-TransposeTable { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)][System.Collections.ICollection] $Object, [ValidateSet("ASC", "DESC", "NONE")][String] $Sort = 'NONE' ) process { foreach ($myObject in $Object) { if ($myObject -is [System.Collections.IDictionary]) { if ($Sort -eq 'ASC') { [PSCustomObject] $myObject.GetEnumerator() | Sort-Object -Property Name -Descending:$false } elseif ($Sort -eq 'DESC') { [PSCustomObject] $myObject.GetEnumerator() | Sort-Object -Property Name -Descending:$true } else { [PSCustomObject] $myObject } } else { $Output = [ordered] @{ } if ($Sort -eq 'ASC') { $myObject.PSObject.Properties | Sort-Object -Property Name -Descending:$false | ForEach-Object { $Output["$($_.Name)"] = $_.Value } } elseif ($Sort -eq 'DESC') { $myObject.PSObject.Properties | Sort-Object -Property Name -Descending:$true | ForEach-Object { $Output["$($_.Name)"] = $_.Value } } else { $myObject.PSObject.Properties | ForEach-Object { $Output["$($_.Name)"] = $_.Value } } $Output } } } } function Format-View { [alias('FV', 'Format-Verbose', 'Format-Debug', 'Format-Warning')] [CmdletBinding(DefaultParameterSetName = 'All')] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [object] $InputObject, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 1, ParameterSetName = 'Property')] [Object[]] $Property, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 2, ParameterSetName = 'ExcludeProperty')] [Object[]] $ExcludeProperty, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 3)] [switch] $HideTableHeaders, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 6)] [validateset('Output', 'Host', 'Warning', 'Verbose', 'Debug', 'Information')] [string] $Stream = 'Verbose', [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 7)] [alias('AsList')][switch] $List, [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 8)] [switch] $Autosize ) Begin { $IsVerbosePresent = $PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent if ($Stream -eq 'Output') { } elseif ($Stream -eq 'Host') { } elseif ($Stream -eq 'Warning') { [System.Management.Automation.ActionPreference] $WarningCurrent = $WarningPreference $WarningPreference = 'continue' } elseif ($Stream -eq 'Verbose') { [System.Management.Automation.ActionPreference] $VerboseCurrent = $VerbosePreference $VerbosePreference = 'continue' } elseif ($Stream -eq 'Debug') { [System.Management.Automation.ActionPreference] $DebugCurrent = $DebugPreference $DebugPreference = 'continue' } elseif ($Stream -eq 'Information') { [System.Management.Automation.ActionPreference] $InformationCurrent = $InformationPreference $InformationPreference = 'continue' } [bool] $FirstRun = $True [bool] $FirstLoop = $True [bool] $FirstList = $True [int] $ScreenWidth = $Host.UI.RawUI.WindowSize.Width - 12 $MyList = [System.Collections.Generic.List[Object]]::new() } Process { $MyList.Add($InputObject) } End { $Parameters = @{} if ($Property) { $Parameters.Property = $Property } if ($ExcludeProperty) { $Parameters.ExcludeProperty = $ExcludeProperty } if ($HideTableHeaders) { $Parameters.HideTableHeaders = $HideTableHeaders } if ($List) { if ($Stream -eq 'Output') { $MyList | Format-List @Parameters | Out-String | Write-Output } elseif ($Stream -eq 'Host') { $MyList | Format-List @Parameters | Out-String | Write-Host } elseif ($Stream -eq 'Warning') { $MyList | Format-List @Parameters | Out-String | Write-Warning $WarningPreference = $WarningCurrent } elseif ($Stream -eq 'Verbose') { $MyList | Format-List @Parameters | Out-String | Write-Verbose $VerbosePreference = $VerboseCurrent } elseif ($Stream -eq 'Debug') { $MyList | Format-List @Parameters | Out-String | Write-Debug $DebugPreference = $DebugCurrent } elseif ($Stream -eq 'Information') { $MyList | Format-List @Parameters | Out-String | Write-Information $InformationPreference = $InformationCurrent } } else { if ($Stream -eq 'Output') { $MyList | Format-Table @Parameters | Out-String | Write-Output } elseif ($Stream -eq 'Host') { $MyList | Format-Table @Parameters | Out-String | Write-Host } elseif ($Stream -eq 'Warning') { $MyList | Format-Table @Parameters | Out-String | Write-Warning $WarningPreference = $WarningCurrent } elseif ($Stream -eq 'Verbose') { $MyList | Format-Table @Parameters | Out-String | Write-Verbose $VerbosePreference = $VerboseCurrent } elseif ($Stream -eq 'Debug') { $MyList | Format-Table @Parameters | Out-String | Write-Debug $DebugPreference = $DebugCurrent } elseif ($Stream -eq 'Information') { $MyList | Format-Table @Parameters | Out-String | Write-Information $InformationPreference = $InformationCurrent } } } } function Get-Colors { [CmdletBinding()] param( [string[]] $Color ) if ($Color) { foreach ($_ in $Color) { $Script:RGBColors.$_ } } else { return $Script:RGBColors } } $ScriptBlockColors = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $Script:RGBColors.Keys | Where-Object { $_ -like "*$wordToComplete*" } } Register-ArgumentCompleter -CommandName Get-Colors -ParameterName Color -ScriptBlock $ScriptBlockColors function Get-DataInformation { [CmdletBinding()] param( [ScriptBlock] $Content, [string] $Text, [Array] $TypesRequired, [Array] $TypesNeeded, [Array] $Commands, [switch] $SkipAvailability ) if (Find-TypesNeeded -TypesRequired $TypesRequired -TypesNeeded $TypesNeeded) { Write-Verbose -Message $Text $Time = Start-TimeLog if ($Commands.Count -gt 0 -and -not $SkipAvailability) { $Available = Test-AvailabilityCommands -Commands $Commands if ($Available -contains $false) { $EndTime = Stop-TimeLog -Time $Time -Option OneLiner Write-Warning "Get-DataInformation - Commands $($Commands -join ", ") is/are not available. Data gathering skipped." Write-Verbose "$Text - Time: $EndTime" return } } if ($null -ne $Content) { & $Content } $EndTime = Stop-TimeLog -Time $Time -Option OneLiner Write-Verbose "$Text - Time: $EndTime" } } function Get-HashMaxValue { [CmdletBinding()] param ( [Object] $hashTable, [switch] $Lowest ) if ($Lowest) { return ($hashTable.GetEnumerator() | Sort-Object value -Descending | Select-Object -Last 1).Value } else { return ($hashTable.GetEnumerator() | Sort-Object value -Descending | Select-Object -First 1).Value } } function Get-MimeType { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $FileName ) $MimeMappings = @{ '.jpeg' = 'image/jpeg' '.jpg' = 'image/jpeg' '.png' = 'image/png' } $Extension = [System.IO.Path]::GetExtension( $FileName ) $ContentType = $MimeMappings[ $Extension ] if ([string]::IsNullOrEmpty($ContentType)) { return New-Object System.Net.Mime.ContentType } else { return New-Object System.Net.Mime.ContentType($ContentType) } } function Get-ObjectCount { [CmdletBinding()] param( [parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)][Object]$Object ) return $($Object | Measure-Object).Count } function Get-ObjectData { [CmdletBinding()] param( $Object, $Title, [switch] $DoNotAddTitles ) [Array] $Values = $Object.$Title [Array] $ArrayList = @( if ($Values.Count -eq 1 -and $DoNotAddTitles -eq $false) { "$Title - $($Values[0])" } else { if ($DoNotAddTitles -eq $false) { $Title } foreach ($Value in $Values) { "$Value" } } ) return $ArrayList } Function Get-ObjectEnumValues { param( [string]$enum ) $enumValues = @{} [enum]::getvalues([type]$enum) | ForEach-Object { $enumValues.add($_, $_.value__) } $enumValues } function Get-ObjectKeys { param( [object] $Object, [string] $Ignore ) $Data = $Object.Keys | where { $_ -notcontains $Ignore } return $Data } function Get-ObjectProperties { [CmdletBinding()] param ( [System.Collections.ICollection] $Object, [string[]] $AddProperties, # provides ability to add some custom properties [switch] $Sort, [bool] $RequireUnique = $true ) $Properties = @( foreach ($O in $Object) { $ObjectProperties = $O.PSObject.Properties.Name $ObjectProperties } foreach ($Property in $AddProperties) { $Property } ) if ($Sort) { return $Properties | Sort-Object -Unique:$RequireUnique } else { return $Properties | Select-Object -Unique:$RequireUnique } } function Get-ObjectPropertiesAdvanced { [CmdletBinding()] param ( [object] $Object, [string[]] $AddProperties, # provides ability to add some custom properties [switch] $Sort ) $Data = @{ } $Properties = New-ArrayList $HighestCount = 0 foreach ($O in $Object) { $ObjectProperties = $O.PSObject.Properties.Name $Count = $ObjectProperties.Count if ($Count -gt $HighestCount) { $Data.HighestCount = $Count $Data.HighestObject = $O $HighestCount = $Count } foreach ($Property in $ObjectProperties) { Add-ToArrayAdvanced -List $Properties -Element $Property -SkipNull -RequireUnique } } foreach ($Property in $AddProperties) { Add-ToArrayAdvanced -List $Properties -Element $Property -SkipNull -RequireUnique } $Data.Properties = if ($Sort) { $Properties | Sort-Object } else { $Properties } return $Data } function Get-ObjectTitles { [CmdletBinding()] param( $Object ) $ArrayList = New-Object System.Collections.ArrayList Write-Verbose "Get-ObjectTitles - ObjectType $($Object.GetType())" foreach ($Title in $Object.PSObject.Properties) { Write-Verbose "Get-ObjectTitles - Value added to array: $($Title.Name)" $ArrayList.Add($Title.Name) | Out-Null } Write-Verbose "Get-ObjectTitles - Array size: $($ArrayList.Count)" return $ArrayList } function Get-ObjectType { [CmdletBinding()] param( [Object] $Object, [string] $ObjectName = 'Random Object Name', [switch] $VerboseOnly ) $ReturnData = [ordered] @{} $ReturnData.ObjectName = $ObjectName if ($Object -ne $null) { try { $TypeInformation = $Object.GetType() $ReturnData.ObjectTypeName = $TypeInformation.Name $ReturnData.ObjectTypeBaseName = $TypeInformation.BaseType $ReturnData.SystemType = $TypeInformation.UnderlyingSystemType } catch { $ReturnData.ObjectTypeName = '' $ReturnData.ObjectTypeBaseName = '' $ReturnData.SystemType = '' } try { $TypeInformationInsider = $Object[0].GetType() $ReturnData.ObjectTypeInsiderName = $TypeInformationInsider.Name $ReturnData.ObjectTypeInsiderBaseName = $TypeInformationInsider.BaseType $ReturnData.SystemTypeInsider = $TypeInformationInsider.UnderlyingSystemType } catch { $ReturnData.ObjectTypeInsiderName = '' $ReturnData.ObjectTypeInsiderBaseName = '' $ReturnData.SystemTypeInsider = '' } } else { $ReturnData.ObjectTypeName = '' $ReturnData.ObjectTypeBaseName = '' $ReturnData.SystemType = '' $ReturnData.ObjectTypeInsiderName = '' $ReturnData.ObjectTypeInsiderBaseName = '' $ReturnData.SystemTypeInsider = '' } Write-Verbose "Get-ObjectType - ObjectTypeName: $($ReturnData.ObjectTypeName)" Write-Verbose "Get-ObjectType - ObjectTypeBaseName: $($ReturnData.ObjectTypeBaseName)" Write-Verbose "Get-ObjectType - SystemType: $($ReturnData.SystemType)" Write-Verbose "Get-ObjectType - ObjectTypeInsiderName: $($ReturnData.ObjectTypeInsiderName)" Write-Verbose "Get-ObjectType - ObjectTypeInsiderBaseName: $($ReturnData.ObjectTypeInsiderBaseName)" Write-Verbose "Get-ObjectType - SystemTypeInsider: $($ReturnData.SystemTypeInsider)" if ($VerboseOnly) { return } else { return Format-TransposeTable -Object $ReturnData } } Function Get-Types { [CmdletBinding()] param ( [Object] $Types ) $TypesRequired = foreach ($Type in $Types) { $Type.GetEnumValues() } return $TypesRequired } function Join-Uri { <# .SYNOPSIS Provides ability to join two Url paths together .DESCRIPTION Provides ability to join two Url paths together .PARAMETER BaseUri Primary Url to merge .PARAMETER RelativeOrAbsoluteUri Additional path to merge with primary url .EXAMPLE Join-Uri 'https://evotec.xyz/' '/wp-json/wp/v2/posts' .EXAMPLE Join-Uri 'https://evotec.xyz/' 'wp-json/wp/v2/posts' .EXAMPLE Join-Uri -BaseUri 'https://evotec.xyz/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .EXAMPLE Join-Uri -BaseUri 'https://evotec.xyz/test/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .NOTES General notes #> [alias('Join-Url')] [cmdletBinding()] param( [parameter(Mandatory)][uri] $BaseUri, [parameter(Mandatory)][uri] $RelativeOrAbsoluteUri ) return ($BaseUri.OriginalString.TrimEnd('/') + "/" + $RelativeOrAbsoluteUri.OriginalString.TrimStart('/')) } function Join-UriQuery { <# .SYNOPSIS Provides ability to join two Url paths together including advanced querying .DESCRIPTION Provides ability to join two Url paths together including advanced querying which is useful for RestAPI/GraphApi calls .PARAMETER BaseUri Primary Url to merge .PARAMETER RelativeOrAbsoluteUri Additional path to merge with primary url (optional) .PARAMETER QueryParameter Parameters and their values in form of hashtable .PARAMETER EscapeUriString If set, will escape the url string .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' -QueryParameter @{ page = 1 per_page = 20 search = 'SearchString' } .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz/wp-json/wp/v2/posts' -QueryParameter @{ page = 1 per_page = 20 search = 'SearchString' } .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .NOTES General notes #> [alias('Join-UrlQuery')] [CmdletBinding()] param ( [parameter(Mandatory)][uri] $BaseUri, [parameter(Mandatory = $false)][uri] $RelativeOrAbsoluteUri, [Parameter()][System.Collections.IDictionary] $QueryParameter, [alias('EscapeUrlString')][switch] $EscapeUriString ) Begin { Add-Type -AssemblyName System.Web } Process { if ($BaseUri -and $RelativeOrAbsoluteUri) { $Url = Join-Uri -BaseUri $BaseUri -RelativeOrAbsoluteUri $RelativeOrAbsoluteUri } else { $Url = $BaseUri } if ($QueryParameter) { $Collection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($key in $QueryParameter.Keys) { $Collection.Add($key, $QueryParameter.$key) } } $uriRequest = [System.UriBuilder] $Url if ($Collection) { $uriRequest.Query = $Collection.ToString() } if (-not $EscapeUriString) { $uriRequest.Uri.AbsoluteUri } else { [System.Uri]::EscapeUriString($uriRequest.Uri.AbsoluteUri) } } } function Merge-Array { <# .SYNOPSIS Merge-Array allows to merge two or more arrays together. .DESCRIPTION Merge-Array allows to merge two or more arrays together. It copies headers from each Array and merges them together allowing for fulll output. When used with Prescan parameter it actually is able to show headers from all arrays .PARAMETER Array List of Arrays to process .PARAMETER Prescan Scans each element of each array for headers. .EXAMPLE $Array1 = @( [PSCustomObject] @{ Name = 'Company1'; Count = 259 } [PSCustomObject] @{ Name = 'Company2'; Count = 300 } ) $Array2 = @( [PSCustomObject] @{ Name = 'Company1'; Count = 25 } [PSCustomObject] @{ Name = 'Company2'; Count = 100 } ) $Array3 = @( [PSCustomObject] @{ Name1 = 'Company1'; Count3 = 25 } [PSCustomObject] @{ Name1 = 'Company2'; Count3 = 100 } [PSCustomObject] @{ Name2 = 'Company2'; Count3 = 100 } ) $Array1 | Format-Table -AutoSize $Array2 | Format-Table -AutoSize $Array3 | Format-Table -AutoSize Merge-Array -Array $Array1, $Array2, $Array3 | Format-Table -AutoSize Merge-Array -Array $Array1, $Array2, $Array3 -Prescan | Format-Table -AutoSize .NOTES General notes #> param( [Array[]] $Array, [switch] $Prescan ) $PropertyNames = foreach ($A in $Array) { if ($Prescan) { foreach ($O in $A) { $O.PSObject.Properties.Name } } else { $A[0].PSObject.Properties.Name } } $PropertyNames = $PropertyNames | Sort-Object -Unique foreach ($A in $Array) { $A | Select-Object -Property $PropertyNames } } function Merge-Objects { [CmdletBinding()] param ( [Object] $Object1, [Object] $Object2 ) $Object = [ordered] @{} foreach ($Property in $Object1.PSObject.Properties) { $Object.($Property.Name) = $Property.Value } foreach ($Property in $Object2.PSObject.Properties) { $Object.($Property.Name) = $Property.Value } return [pscustomobject] $Object } function New-ArrayList { [CmdletBinding()] param() $List = [System.Collections.ArrayList]::new() return , $List } function New-GenericList { [CmdletBinding()] param( [Object] $Type = [System.Object] ) return New-Object "System.Collections.Generic.List[$Type]" } function Remove-DuplicateObjects { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Object Parameter description .PARAMETER Property Parameter description .EXAMPLE $Array = @() $Array += [PSCustomObject] @{ 'Name' = 'Test'; 'Val1' = 'Testor2'; 'Val2' = 'Testor2'} $Array += [PSCustomObject] @{ 'Name' = 'Test'; 'Val1' = 'Testor2'; 'Val2' = 'Testor2'} $Array += [PSCustomObject] @{ 'Name' = 'Test1'; 'Val1' = 'Testor2'; 'Val2' = 'Testor2'} $Array += [PSCustomObject] @{ 'Name' = 'Test1'; 'Val1' = 'Testor2'; 'Val2' = 'Testor2'} Write-Color 'Before' -Color Red $Array | Format-Table -A Write-Color 'After' -Color Green $Array = $Array | Sort-Object -Unique -Property 'Name', 'Val1','Val2' $Array | Format-Table -AutoSize .NOTES General notes #> [CmdletBinding()] param( [System.Collections.IList] $Object, [string[]] $Property ) if ($Object.Count -eq 0) { return $Object } else { return $Object | Sort-Object -Property $Property -Unique } } function Remove-EmptyValue { [alias('Remove-EmptyValues')] [CmdletBinding()] param( [alias('Splat', 'IDictionary')][Parameter(Mandatory)][System.Collections.IDictionary] $Hashtable, [string[]] $ExcludeParameter, [switch] $Recursive, [int] $Rerun, [switch] $DoNotRemoveNull, [switch] $DoNotRemoveEmpty, [switch] $DoNotRemoveEmptyArray, [switch] $DoNotRemoveEmptyDictionary ) foreach ($Key in [string[]] $Hashtable.Keys) { if ($Key -notin $ExcludeParameter) { if ($Recursive) { if ($Hashtable[$Key] -is [System.Collections.IDictionary]) { if ($Hashtable[$Key].Count -eq 0) { if (-not $DoNotRemoveEmptyDictionary) { $Hashtable.Remove($Key) } } else { Remove-EmptyValue -Hashtable $Hashtable[$Key] -Recursive:$Recursive } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } } if ($Rerun) { for ($i = 0; $i -lt $Rerun; $i++) { Remove-EmptyValue -Hashtable $Hashtable -Recursive:$Recursive } } } function Remove-FromArray { [CmdletBinding()] param( [System.Collections.ArrayList] $List, [Object] $Element, [switch] $LastElement ) if ($LastElement) { $LastID = $List.Count - 1 $List.RemoveAt($LastID) > $null } else { $List.Remove($Element) > $null } } function Remove-ObjectsExistingInTarget { param( $ObjectSource, $ObjectTarget, [string] $ComparePropertySource, [string] $ComparePropertyTarget, [switch] $Reverse # returns only existing objects ) $ObjectsExistingInTarget = @() $ObjectsNotExistingInTarget = @() foreach ($Object in $ObjectSource) { if ($ObjectTarget.$ComparePropertySource -contains $Object.$ComparePropertyTarget) { $ObjectsExistingInTarget += $Object } else { $ObjectsNotExistingInTarget += $Object } } if ($Reverse) { return $ObjectsExistingInTarget } else { return $ObjectsNotExistingInTarget } } function Remove-WhiteSpace { param( [string] $Text ) $Text = $Text -replace '(^\s+|\s+$)', '' -replace '\s+', ' ' return $Text } Function Rename-LatinCharacters { <# .SYNOPSIS Renames a name to a name without special chars. .DESCRIPTION Renames a name to a name without special chars. .PARAMETER String Provide a string to rename .EXAMPLE Rename-LatinCharacters -String 'Przemysław Kłys' .EXAMPLE Rename-LatinCharacters -String 'Przemysław' .NOTES General notes #> [alias('Remove-StringLatinCharacters')] [cmdletBinding()] param( [string] $String ) [Text.Encoding]::ASCII.GetString([Text.Encoding]::GetEncoding("Cyrillic").GetBytes($String)) } function Rename-UserValuesFromHash { [CmdletBinding()] param( $Users, $MatchData, $FieldTypes ) Write-Verbose "FieldTypes: $($FieldTypes -join ',')" foreach ($User in $Users) { foreach ($Match in $MatchData.Keys) { $Key = $Match $Value = $MatchData.$Match Write-Verbose "User: $($User.UserPrincipalName) Key: $Key Value: $Value" foreach ($Field in $FieldTypes) { if ($User.$Field) { $User.$Field = $($User.$Field).ToLower().Replace($Key, $Value) } } } } return $Users } function Select-Properties { <# .SYNOPSIS Allows for easy selecting property names from one or multiple objects .DESCRIPTION Allows for easy selecting property names from one or multiple objects. This is especially useful with using AllProperties parameter where we want to make sure to get all properties from all objects. .PARAMETER Objects One or more objects .PARAMETER Property Properties to include .PARAMETER ExcludeProperty Properties to exclude .PARAMETER AllProperties All unique properties from all objects .PARAMETER PropertyNameReplacement Default property name when object has no properties .EXAMPLE $Object1 = [PSCustomobject] @{ Name1 = '1' Name2 = '3' Name3 = '5' } $Object2 = [PSCustomobject] @{ Name4 = '2' Name5 = '6' Name6 = '7' } Select-Properties -Objects $Object1, $Object2 -AllProperties #OR: $Object1, $Object2 | Select-Properties -AllProperties -ExcludeProperty Name6 -Property Name3 .EXAMPLE $Object3 = [Ordered] @{ Name1 = '1' Name2 = '3' Name3 = '5' } $Object4 = [Ordered] @{ Name4 = '2' Name5 = '6' Name6 = '7' } Select-Properties -Objects $Object3, $Object4 -AllProperties $Object3, $Object4 | Select-Properties -AllProperties .NOTES General notes #> [CmdLetBinding()] param( [Array][Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] $Objects, [string[]] $Property, [string[]] $ExcludeProperty, [switch] $AllProperties, [string] $PropertyNameReplacement = '*' ) Begin { function Select-Unique { [CmdLetBinding()] param( [System.Collections.IList] $Object ) [Array] $CleanedList = foreach ($O in $Object) { if ($null -ne $O) { $O } } $New = $CleanedList.ToLower() | Select-Object -Unique $Selected = foreach ($_ in $New) { $Index = $Object.ToLower().IndexOf($_) if ($Index -ne -1) { $Object[$Index] } } $Selected } $ObjectsList = [System.Collections.Generic.List[Object]]::new() } Process { foreach ($Object in $Objects) { $ObjectsList.Add($Object) } } End { if ($ObjectsList.Count -eq 0) { Write-Warning 'Select-Properties - Unable to process. Objects count equals 0.' return } if ($ObjectsList[0] -is [System.Collections.IDictionary]) { if ($AllProperties) { [Array] $All = foreach ($_ in $ObjectsList) { $_.Keys } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $ObjectsList[0].Keys } if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_ -and $ExcludeProperty -notcontains $_) { $_ continue } } } elseif ($Property.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_) { $_ continue } } } elseif ($ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($ExcludeProperty -notcontains $_) { $_ continue } } } } elseif ($ObjectsList[0].GetType().Name -match 'bool|byte|char|datetime|decimal|double|ExcelHyperLink|float|int|long|sbyte|short|string|timespan|uint|ulong|URI|ushort') { $FirstObjectProperties = $PropertyNameReplacement } else { if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property $Property -ExcludeProperty $ExcludeProperty } elseif ($Property.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property $Property } elseif ($ExcludeProperty.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property '*' -ExcludeProperty $ExcludeProperty } if ($AllProperties) { [Array] $All = foreach ($_ in $ObjectsList) { $ListProperties = $_.PSObject.Properties.Name if ($null -ne $ListProperties) { $ListProperties } } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $ObjectsList[0].PSObject.Properties.Name } } $FirstObjectProperties } } function Split-Array { <# .SYNOPSIS Split an array into multiple arrays of a specified size or by a specified number of elements .DESCRIPTION Split an array into multiple arrays of a specified size or by a specified number of elements .PARAMETER Objects Lists of objects you would like to split into multiple arrays based on their size or number of parts to split into. .PARAMETER Parts Parameter description .PARAMETER Size Parameter description .EXAMPLE This splits array into multiple arrays of 3 Example below wil return 1,2,3 + 4,5,6 + 7,8,9 Split-array -Objects @(1,2,3,4,5,6,7,8,9,10) -Parts 3 .EXAMPLE This splits array into 3 parts regardless of amount of elements Split-array -Objects @(1,2,3,4,5,6,7,8,9,10) -Size 3 .NOTES #> [CmdletBinding()] param( [alias('InArray', 'List')][Array] $Objects, [int]$Parts, [int]$Size ) if ($Objects.Count -eq 1) { return $Objects } if ($Parts) { $PartSize = [Math]::Ceiling($inArray.count / $Parts) } if ($Size) { $PartSize = $Size $Parts = [Math]::Ceiling($Objects.count / $Size) } $outArray = [System.Collections.Generic.List[Object]]::new() for ($i = 1; $i -le $Parts; $i++) { $start = (($i - 1) * $PartSize) $end = (($i) * $PartSize) - 1 if ($end -ge $Objects.count) { $end = $Objects.count - 1 } $outArray.Add(@($Objects[$start..$end])) } , $outArray } function Test-IsDistinguishedName { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Identity Parameter description .EXAMPLE An example .NOTES Original source: https://github.com/PsCustomObject/IT-ToolBox/blob/master/Public/Test-IsValidDn.ps1 #> [alias('Test-IsDN')] [cmdletBinding()] param ( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('DN', 'DistinguishedName')][string] $Identity ) Process { [regex]$distinguishedNameRegex = '^(?:(?<cn>CN=(?<name>(?:[^,]|\,)*)),)?(?:(?<path>(?:(?:CN|OU)=(?:[^,]|\,)+,?)+),)?(?<domain>(?:DC=(?:[^,]|\,)+,?)+)$' $Identity -match $distinguishedNameRegex } } function Find-MyProgramData { [CmdletBinding()] param ( $Data, $FindText ) foreach ($Sub in $Data) { if ($Sub -like $FindText) { $Split = $Sub.Split(' ') return $Split[1] } } return '' } function Initialize-ModulePortable { [CmdletBinding()] param( [alias('ModuleName')][string] $Name, [string] $Path = $PSScriptRoot, [switch] $Download, [switch] $Import ) function Get-RequiredModule { param( [string] $Path, [string] $Name ) $PrimaryModule = Get-ChildItem -LiteralPath "$Path\$Name" -Filter '*.psd1' -Recurse -ErrorAction SilentlyContinue -Depth 1 if ($PrimaryModule) { $Module = Get-Module -ListAvailable $PrimaryModule.FullName -ErrorAction SilentlyContinue -Verbose:$false if ($Module) { [Array] $RequiredModules = $Module.RequiredModules.Name if ($null -ne $RequiredModules) { $null } $RequiredModules foreach ($_ in $RequiredModules) { Get-RequiredModule -Path $Path -Name $_ } } } else { Write-Warning "Initialize-ModulePortable - Modules to load not found in $Path" } } if (-not $Name) { Write-Warning "Initialize-ModulePortable - Module name not given. Terminating." return } if (-not $Download -and -not $Import) { Write-Warning "Initialize-ModulePortable - Please choose Download/Import switch. Terminating." return } if ($Download) { try { if (-not $Path -or -not (Test-Path -LiteralPath $Path)) { $null = New-Item -ItemType Directory -Path $Path -Force } Save-Module -Name $Name -LiteralPath $Path -WarningVariable WarningData -WarningAction SilentlyContinue -ErrorAction Stop } catch { $ErrorMessage = $_.Exception.Message if ($WarningData) { Write-Warning "Initialize-ModulePortable - $WarningData" } Write-Warning "Initialize-ModulePortable - Error $ErrorMessage" return } } if ($Download -or $Import) { [Array] $Modules = Get-RequiredModule -Path $Path -Name $Name | Where-Object { $null -ne $_ } if ($null -ne $Modules) { [array]::Reverse($Modules) } $CleanedModules = [System.Collections.Generic.List[string]]::new() foreach ($_ in $Modules) { if ($CleanedModules -notcontains $_) { $CleanedModules.Add($_) } } $CleanedModules.Add($Name) $Items = foreach ($_ in $CleanedModules) { Get-ChildItem -LiteralPath "$Path\$_" -Filter '*.psd1' -Recurse -ErrorAction SilentlyContinue -Depth 1 } [Array] $PSD1Files = $Items.FullName } if ($Download) { $ListFiles = foreach ($PSD1 in $PSD1Files) { $PSD1.Replace("$Path", '$PSScriptRoot') } $Content = @( '$Modules = @(' foreach ($_ in $ListFiles) { " `"$_`"" } ')' "foreach (`$_ in `$Modules) {" " Import-Module `$_ -Verbose:`$false -Force" "}" ) $Content | Set-Content -Path $Path\$Name.ps1 -Force } if ($Import) { $ListFiles = foreach ($PSD1 in $PSD1Files) { $PSD1 } foreach ($_ in $ListFiles) { Import-Module $_ -Verbose:$false -Force } } } function Invoke-CommandCustom { [cmdletBinding()] param( [scriptblock] $ScriptBlock, [System.Collections.IDictionary] $Parameter, [array] $Argument, [switch] $ReturnVerbose, [switch] $ReturnError, [switch] $ReturnWarning, [switch] $AddParameter ) $Output = [ordered]@{} $ps = [PowerShell]::Create() if ($ReturnVerbose) { $null = $ps.AddScript('$VerbosePreference = "Continue"').AddStatement() } if ($ScriptBlock) { if ($Parameter -and $AddParameter) { $Count = 0 [string] $ScriptBlockParams = @( "param(" foreach ($Key in $Parameter.Keys) { $Count++ if ($Count -eq $Parameter.Keys.Count) { "`$$($Key)" } else { "`$$($Key)," } } ")" $ScriptBlock.ToString() ) $ScriptBlockScript = [scriptblock]::Create($ScriptBlockParams) $null = $ps.AddScript($ScriptBlockScript) } else { $null = $ps.AddScript($ScriptBlock) } } if ($Parameter) { foreach ($Key in $Parameter.Keys) { $null = $ps.AddParameter($Key, $Parameter[$Key]) } } if ($Argument) { foreach ($Arg in $Argument) { $null = $ps.AddArgument($Arg) } } $ErrorCaught = $null try { $InvokedCommand = $ps.Invoke() } catch { $ErrorCaught = $_ } if ($InvokedCommand) { $Output['Output'] = $InvokedCommand } if ($ReturnVerbose) { if ($Ps.Streams.Verbose) { $Output['Verbose'] = $ps.Streams.Verbose } } if ($ReturnWarning) { if ($ps.Streams.Warning) { $Output['Warning'] = $ps.Streams.Warning } } if ($ReturnError) { if ($ErrorCaught) { $Output['Error'] = $ErrorCaught } else { if ($Ps.Streams.Error) { $Output['Error'] = $ps.Streams.Error } } } if ($ReturnError -or $ReturnVerbose -or $ReturnWarning) { $Output } else { $Output.Output } } function Start-InternalFunction { [CmdletBinding()] param( [ScriptBlock] $ScriptBlock, [string] $Module ) $InternalModule = Import-Module -Name $Module -PassThru & $InternalModule $ScriptBlock } function Start-MyProgram { [CmdletBinding()] param ( [string] $Program, [string[]] $CmdArgList, [System.Collections.IDictionary] $LoggerParameters ) $Output = (cmd /c $Program $CmdArgList '2>&1') if (-not $LoggerParameters) { if ($Output) { return $Output } } else { $Logger = Get-Logger @LoggerParameters if ($null -ne $Output) { $Logger.AddInfoRecord("Running program $Program with output: $Output") } else { $Logger.AddInfoRecord("Running program $Program $CmdArgList") } } } function Get-RandomCharacters { [cmdletbinding()] param( [int] $length, [string] $characters ) if ($length -ne 0 -and $characters -ne '') { $random = 1..$length | ForEach-Object { Get-Random -Maximum $characters.length } $private:ofs = "" return [String]$characters[$random] } else { return } } function Get-RandomFileName { [cmdletbinding()] param( $Length = 16, $Extension ) $File = Get-RandomStringName -Size $Length -LettersOnly -ToLower return "$File.$Extension" } function Get-RandomPassword { [cmdletbinding()] param( [int] $LettersLowerCase = 4, [int] $LettersHigherCase = 2, [int] $Numbers = 1, [int] $SpecialChars = 0, [int] $SpecialCharsLimited = 1 ) $Password = @( Get-RandomCharacters -length $LettersLowerCase -characters 'abcdefghiklmnoprstuvwxyz' Get-RandomCharacters -length $LettersHigherCase -characters 'ABCDEFGHKLMNOPRSTUVWXYZ' Get-RandomCharacters -length $Numbers -characters '1234567890' Get-RandomCharacters -length $SpecialChars -characters '!$%()=?{@#' Get-RandomCharacters -length $SpecialCharsLimited -characters '!$#' ) $StringPassword = $Password -join '' $StringPassword = ($StringPassword.ToCharArray() | Get-Random -Count $StringPassword.Length) -join '' return $StringPassword } function Get-RandomStringName { [cmdletbinding()] param( [int] $Size = 31, [switch] $ToLower, [switch] $ToUpper, [switch] $LettersOnly ) [string] $MyValue = @( if ($LettersOnly) { ( -join ((1..$Size) | ForEach-Object { (65..90) + (97..122) | Get-Random } | ForEach-Object { [char]$_ })) } else { ( -join ((48..57) + (97..122) | Get-Random -Count $Size | ForEach-Object { [char]$_ })) } ) if ($ToLower) { return $MyValue.ToLower() } if ($ToUpper) { return $MyValue.ToUpper() } return $MyValue } function Dismount-PSRegistryPath { [alias('Dismount-RegistryPath')] [cmdletbinding()] param( [Parameter(Mandatory)][string] $MountPoint, [switch] $Suppress ) [gc]::Collect() $pinfo = [System.Diagnostics.ProcessStartInfo]::new() $pinfo.FileName = "reg.exe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = " unload $MountPoint" $pinfo.CreateNoWindow = $true $pinfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden $p = [System.Diagnostics.Process]::new() $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $Output = $p.StandardOutput.ReadToEnd() $Errors = $p.StandardError.ReadToEnd() if ($Errors) { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $Errors } else { Write-Warning -Message "Dismount-PSRegistryPath - Couldn't unmount $MountPoint. $Errors" } } else { if ($Output -like "*operation completed*") { if (-not $Suppress) { return $true } } } if (-not $Suppress) { return $false } } function Get-PSRegistry { <# .SYNOPSIS Get registry key values. .DESCRIPTION Get registry key values. .PARAMETER RegistryPath The registry path to get the values from. .PARAMETER ComputerName The computer to get the values from. If not specified, the local computer is used. .PARAMETER ExpandEnvironmentNames Expand environment names in the registry value. By default it doesn't do that. If you want to expand environment names, use this parameter. .EXAMPLE Get-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters' -ComputerName AD1 .EXAMPLE Get-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters' .EXAMPLE Get-PSRegistry -RegistryPath "HKLM\SYSTEM\CurrentControlSet\Services\DFSR\Parameters" -ComputerName AD1,AD2,AD3 | ft -AutoSize .EXAMPLE Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Directory Service' .EXAMPLE Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Windows PowerShell' | Format-Table -AutoSize .EXAMPLE Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Directory Service' -ComputerName AD1 -Advanced .EXAMPLE Get-PSRegistry -RegistryPath "HKLM:\Software\Microsoft\Powershell\1\Shellids\Microsoft.Powershell\" .EXAMPLE # Get default key and it's value Get-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -Key "" .EXAMPLE # Get default key and it's value (alternative) Get-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -DefaultKey .NOTES General notes #> [cmdletbinding()] param( [alias('Path')][string[]] $RegistryPath, [string[]] $ComputerName = $Env:COMPUTERNAME, [string] $Key, [switch] $Advanced, [switch] $DefaultKey, [switch] $ExpandEnvironmentNames, [Parameter(DontShow)][switch] $DoNotUnmount ) $Script:CurrentGetCount++ Get-PSRegistryDictionaries $RegistryPath = Resolve-PrivateRegistry -RegistryPath $RegistryPath [Array] $Computers = Get-ComputerSplit -ComputerName $ComputerName [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary -ExpandEnvironmentNames:$ExpandEnvironmentNames.IsPresent if ($PSBoundParameters.ContainsKey("Key") -or $DefaultKey) { [Array] $RegistryValues = Get-PSSubRegistryTranslated -RegistryPath $RegistryTranslated -HiveDictionary $Script:HiveDictionary -Key $Key foreach ($Computer in $Computers[0]) { foreach ($R in $RegistryValues) { Get-PSSubRegistry -Registry $R -ComputerName $Computer -ExpandEnvironmentNames:$ExpandEnvironmentNames.IsPresent } } foreach ($Computer in $Computers[1]) { foreach ($R in $RegistryValues) { Get-PSSubRegistry -Registry $R -ComputerName $Computer -Remote -ExpandEnvironmentNames:$ExpandEnvironmentNames.IsPresent } } } else { [Array] $RegistryValues = Get-PSSubRegistryTranslated -RegistryPath $RegistryTranslated -HiveDictionary $Script:HiveDictionary foreach ($Computer in $Computers[0]) { foreach ($R in $RegistryValues) { Get-PSSubRegistryComplete -Registry $R -ComputerName $Computer -Advanced:$Advanced -ExpandEnvironmentNames:$ExpandEnvironmentNames.IsPresent } } foreach ($Computer in $Computers[1]) { foreach ($R in $RegistryValues) { Get-PSSubRegistryComplete -Registry $R -ComputerName $Computer -Remote -Advanced:$Advanced -ExpandEnvironmentNames:$ExpandEnvironmentNames.IsPresent } } } $Script:CurrentGetCount-- if ($Script:CurrentGetCount -eq 0) { if (-not $DoNotUnmount) { Unregister-MountedRegistry } } } function Mount-PSRegistryPath { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER MountPoint Parameter description .PARAMETER FilePath Parameter description .EXAMPLE Mount-PSRegistryPath -MountPoint 'HKEY_USERS\.DEFAULT_USER111' -FilePath 'C:\Users\Default\NTUSER.DAT' .NOTES General notes #> [alias('Mount-RegistryPath')] [cmdletbinding()] param( [Parameter(Mandatory)][string] $MountPoint, [Parameter(Mandatory)][string] $FilePath ) $pinfo = [System.Diagnostics.ProcessStartInfo]::new() $pinfo.FileName = "reg.exe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = " load $MountPoint $FilePath" $pinfo.CreateNoWindow = $true $pinfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden $p = [System.Diagnostics.Process]::new() $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $Output = $p.StandardOutput.ReadToEnd() $Errors = $p.StandardError.ReadToEnd() if ($Errors) { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $Errors } else { Write-Warning -Message "Mount-PSRegistryPath - Couldn't mount $MountPoint. $Errors" } } else { if ($Output -like "*operation completed*") { if (-not $Suppress) { return $true } } } if (-not $Suppress) { return $false } } function New-PSRegistry { <# .SYNOPSIS Provides a way to create new registry paths .DESCRIPTION Provides a way to create new registry paths .PARAMETER ComputerName The computer to run the command on. Defaults to local computer. .PARAMETER RegistryPath Registry Path to Create .PARAMETER Suppress Suppresses the output of the command. By default the command outputs PSObject with the results of the operation. .EXAMPLE New-PSRegistry -RegistryPath "HKCU:\\Tests1\CurrentControlSet\Control\Lsa" -Verbose -WhatIf .EXAMPLE New-PSRegistry -RegistryPath "HKCU:\\Tests1\CurrentControlSet\Control\Lsa" .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [Parameter(Mandatory)][string] $RegistryPath, [switch] $Suppress ) Get-PSRegistryDictionaries [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName $RegistryPath = Resolve-PrivateRegistry -RegistryPath $RegistryPath [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary foreach ($Registry in $RegistryTranslated) { $RegistryValue = Get-PrivateRegistryTranslated -RegistryPath $Registry -HiveDictionary $Script:HiveDictionary -Key $Key -ReverseTypesDictionary $Script:ReverseTypesDictionary if ($RegistryValue.HiveKey) { foreach ($Computer in $ComputersSplit[0]) { New-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } foreach ($Computer in $ComputersSplit[1]) { New-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -Remote -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { Unregister-MountedRegistry throw } else { Write-Warning "New-PSRegistry - Setting registry to $RegistryPath have failed. Couldn't translate HIVE." } } } Unregister-MountedRegistry } function Remove-PSRegistry { <# .SYNOPSIS Remove registry keys and folders .DESCRIPTION Remove registry keys and folders using .NET methods .PARAMETER ComputerName The computer to run the command on. Defaults to local computer. .PARAMETER RegistryPath The registry path to remove. .PARAMETER Key The registry key to remove. .PARAMETER Recursive Forces deletion of registry folder and all keys, including nested folders .PARAMETER Suppress Suppresses the output of the command. By default the command outputs PSObject with the results of the operation. .EXAMPLE Remove-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests\Ok\MaybeNot" -Recursive .EXAMPLE Remove-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests\Ok\MaybeNot" -Key "LimitBlankPass1wordUse" .EXAMPLE Remove-PSRegistry -RegistryPath "HKCU:\Tests\Ok" .NOTES General notes #> [cmdletBinding(SupportsShouldProcess)] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [Parameter(Mandatory)][string] $RegistryPath, [Parameter()][string] $Key, [switch] $Recursive, [switch] $Suppress ) Get-PSRegistryDictionaries [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName $RegistryPath = Resolve-PrivateRegistry -RegistryPath $RegistryPath [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary foreach ($Registry in $RegistryTranslated) { $RegistryValue = Get-PrivateRegistryTranslated -RegistryPath $Registry -HiveDictionary $Script:HiveDictionary -Key $Key -ReverseTypesDictionary $Script:ReverseTypesDictionary if ($RegistryValue.HiveKey) { foreach ($Computer in $ComputersSplit[0]) { Remove-PrivateRegistry -Key $Key -RegistryValue $RegistryValue -Computer $Computer -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } foreach ($Computer in $ComputersSplit[1]) { Remove-PrivateRegistry -Key $Key -RegistryValue $RegistryValue -Computer $Computer -Remote -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { Unregister-MountedRegistry throw } else { Write-Warning "Remove-PSRegistry - Removing registry $RegistryPath have failed (recursive: $($Recursive.IsPresent)). Couldn't translate HIVE." } } } Unregister-MountedRegistry } function Set-PSRegistry { <# .SYNOPSIS Sets/Updates registry entries locally and remotely using .NET methods. .DESCRIPTION Sets/Updates registry entries locally and remotely using .NET methods. If the registry path to key doesn't exists it will be created. .PARAMETER ComputerName The computer to run the command on. Defaults to local computer. .PARAMETER RegistryPath Registry Path to Update .PARAMETER Type Registry type to use. Options are: REG_SZ, REG_EXPAND_SZ, REG_BINARY, REG_DWORD, REG_MULTI_SZ, REG_QWORD, string, expandstring, binary, dword, multistring, qword .PARAMETER Key Registry key to set. If the path to registry key doesn't exists it will be created. .PARAMETER Value Registry value to set. .PARAMETER Suppress Suppresses the output of the command. By default the command outputs PSObject with the results of the operation. .EXAMPLE Set-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics' -Type REG_DWORD -Key "16 LDAP Interface Events" -Value 2 -ComputerName AD1 .EXAMPLE Set-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics' -Type REG_SZ -Key "LDAP Interface Events" -Value 'test' -ComputerName AD1 .EXAMPLE Set-PSRegistry -RegistryPath "HKCU:\\Tests" -Key "LimitBlankPass1wordUse" -Value "0" -Type REG_DWORD .EXAMPLE Set-PSRegistry -RegistryPath "HKCU:\\Tests\MoreTests\Tests1" -Key "LimitBlankPass1wordUse" -Value "0" -Type REG_DWORD .EXAMPLE # Setting default value $ValueData = [byte[]] @( 0, 1, 0, 0, 9, 0, 0, 0, 128, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 0, 0, 5, 0, 10, 0, 14, 0, 3, 0, 5, 0, 6, 0, 6, 0, 4, 0, 4, 0 ) Set-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -Key '' -Value $ValueData -Type 'NONE' .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [string[]] $ComputerName = $Env:COMPUTERNAME, [Parameter(Mandatory)][string] $RegistryPath, [Parameter(Mandatory)][ValidateSet('REG_SZ', 'REG_NONE', 'None', 'REG_EXPAND_SZ', 'REG_BINARY', 'REG_DWORD', 'REG_MULTI_SZ', 'REG_QWORD', 'string', 'binary', 'dword', 'qword', 'multistring', 'expandstring')][string] $Type, [Parameter()][string] $Key, [Parameter(Mandatory)][object] $Value, [switch] $Suppress ) Unregister-MountedRegistry Get-PSRegistryDictionaries [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName $RegistryPath = Resolve-PrivateRegistry -RegistryPath $RegistryPath [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary foreach ($Registry in $RegistryTranslated) { $RegistryValue = Get-PrivateRegistryTranslated -RegistryPath $Registry -HiveDictionary $Script:HiveDictionary -Key $Key -Value $Value -Type $Type -ReverseTypesDictionary $Script:ReverseTypesDictionary if ($RegistryValue.HiveKey) { foreach ($Computer in $ComputersSplit[0]) { Set-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } foreach ($Computer in $ComputersSplit[1]) { Set-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -Remote -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { Unregister-MountedRegistry throw } else { Write-Warning "Set-PSRegistry - Setting registry to $Registry have failed. Couldn't translate HIVE." } } } Unregister-MountedRegistry } function Test-PSRegistry { [cmdletbinding()] param( [alias('Path')][string[]] $RegistryPath, [string] $ComputerName = $Env:COMPUTERNAME, [string] $Key ) $Output = Get-PSRegistry -RegistryPath $RegistryPath -ComputerName $ComputerName if ($Output.PSConnection -eq $true -and $Output.PSError -eq $false) { if ($Key) { if ($null -ne $Output.$Key) { return $true } else { return $false } } else { return $true } } else { return $false } } function New-Runspace { [cmdletbinding()] param ( [int] $minRunspaces = 1, [int] $maxRunspaces = [int]$env:NUMBER_OF_PROCESSORS + 1 ) $RunspacePool = [RunspaceFactory]::CreateRunspacePool($minRunspaces, $maxRunspaces) $RunspacePool.Open() return $RunspacePool } function Start-Runspace { [cmdletbinding()] param ( [ScriptBlock] $ScriptBlock, [System.Collections.IDictionary] $Parameters, [System.Management.Automation.Runspaces.RunspacePool] $RunspacePool ) if ($ScriptBlock -ne '') { $runspace = [PowerShell]::Create() $null = $runspace.AddScript($ScriptBlock) if ($null -ne $Parameters) { $null = $runspace.AddParameters($Parameters) } $runspace.RunspacePool = $RunspacePool [PSCustomObject]@{ Pipe = $runspace Status = $runspace.BeginInvoke() } } } function Stop-Runspace { [cmdletbinding()] param( [Array] $Runspaces, [string] $FunctionName, [System.Management.Automation.Runspaces.RunspacePool] $RunspacePool, [switch] $ExtendedOutput ) [Array] $List = While (@($Runspaces | Where-Object -FilterScript { $null -ne $_.Status }).count -gt 0) { foreach ($Runspace in $Runspaces | Where-Object { $_.Status.IsCompleted -eq $true }) { $Errors = foreach ($e in $($Runspace.Pipe.Streams.Error)) { Write-Error -ErrorRecord $e $e } foreach ($w in $($Runspace.Pipe.Streams.Warning)) { Write-Warning -Message $w } foreach ($v in $($Runspace.Pipe.Streams.Verbose)) { Write-Verbose -Message $v } if ($ExtendedOutput) { @{ Output = $Runspace.Pipe.EndInvoke($Runspace.Status) Errors = $Errors } } else { $Runspace.Pipe.EndInvoke($Runspace.Status) } $Runspace.Status = $null } } $RunspacePool.Close() $RunspacePool.Dispose() if ($List.Count -eq 1) { return , $List } else { return $List } } function Get-PSService { <# .SYNOPSIS Alternative way to Get-Service .DESCRIPTION Alternative way to Get-Service which works using CIM queries .PARAMETER ComputerName ComputerName(s) to query for services .PARAMETER Protocol Protocol to use to gather services .PARAMETER Service Limit output to just few services .PARAMETER All Return all data without filtering .PARAMETER Extended Return more data .EXAMPLE Get-PSService -ComputerName AD1, AD2, AD3, AD4 -Service 'Dnscache', 'DNS', 'PeerDistSvc', 'WebClient', 'Netlogon' .EXAMPLE Get-PSService -ComputerName AD1, AD2 -Extended .EXAMPLE Get-PSService .EXAMPLE Get-PSService -Extended .NOTES General notes #> [cmdletBinding()] param( [alias('Computer', 'Computers')][string[]] $ComputerName = $Env:COMPUTERNAME, [ValidateSet('Default', 'Dcom', 'Wsman')][string] $Protocol = 'Default', [alias('Services')][string[]] $Service, [switch] $All, [switch] $Extended ) [string] $Class = 'win32_service' [string] $Properties = '*' if ($Service) { $CachedServices = @{} foreach ($S in $Service) { $CachedServices[$S] = $true } } $Information = Get-CimData -ComputerName $ComputerName -Protocol $Protocol -Class $Class -Properties $Properties if ($All) { if ($Service) { foreach ($Entry in $Information) { if ($CachedServices[$Entry.Name]) { $Entry } } } else { $Information } } else { foreach ($Data in $Information) { if ($Service) { if (-not $CachedServices[$Data.Name]) { continue } } $OutputService = [ordered] @{ ComputerName = if ($Data.PSComputerName) { $Data.PSComputerName } else { $Env:COMPUTERNAME } Status = $Data.State Name = $Data.Name ServiceType = $Data.ServiceType StartType = $Data.StartMode DisplayName = $Data.DisplayName } if ($Extended) { $OutputServiceExtended = [ordered] @{ StatusOther = $Data.Status ExitCode = $Data.ExitCode DesktopInteract = $Data.DesktopInteract ErrorControl = $Data.ErrorControl PathName = $Data.PathName Caption = $Data.Caption Description = $Data.Description Started = $Data.Started SystemName = $Data.SystemName AcceptPause = $Data.AcceptPause AcceptStop = $Data.AcceptStop ServiceSpecificExitCode = $Data.ServiceSpecificExitCode StartName = $Data.StartName TagId = $Data.TagId CheckPoint = $Data.CheckPoint DelayedAutoStart = $Data.DelayedAutoStart ProcessId = $Data.ProcessId WaitHint = $Data.WaitHint } [PSCustomObject] ($OutputService + $OutputServiceExtended) } else { [PSCustomObject] $OutputService } } } } function Set-ServiceRecovery { <# .SYNOPSIS # .DESCRIPTION Long description .PARAMETER ServiceDisplayName Parameter description .PARAMETER Server Parameter description .PARAMETER action1 Parameter description .PARAMETER time1 Parameter description .PARAMETER action2 Parameter description .PARAMETER time2 Parameter description .PARAMETER actionLast Parameter description .PARAMETER timeLast Parameter description .PARAMETER resetCounter Parameter description .EXAMPLE Set-ServiceRecovery -ServiceDisplayName "Pulseway" -Server "MAIL1" .NOTES General notes #> [alias('Set-Recovery')] param ( [string] [Parameter(Mandatory = $true)] $ServiceDisplayName, [string] [Parameter(Mandatory = $true)] $Server, [string] $action1 = "restart", [int] $time1 = 30000, # in miliseconds [string] $action2 = "restart", [int] $time2 = 30000, # in miliseconds [string] $actionLast = "restart", [int] $timeLast = 30000, # in miliseconds [int] $resetCounter = 4000 # in seconds ) $serverPath = "\\" + $server $services = Get-CimInstance -ClassName 'Win32_Service' -ComputerName $Server | Where-Object { $_.DisplayName -imatch $ServiceDisplayName } $action = $action1 + "/" + $time1 + "/" + $action2 + "/" + $time2 + "/" + $actionLast + "/" + $timeLast foreach ($service in $services) { $output = sc.exe $serverPath failure $($service.Name) actions= $action reset= $resetCounter } } function Get-SqlQueryColumnInformation { [CmdletBinding()] param ( [string] $SqlServer, [string] $SqlDatabase, [string] $Table ) $Table = $Table.Replace("dbo.", '').Replace('[', '').Replace(']', '') $SqlDatabase = $SqlDatabase.Replace('[', '').Replace(']', '') $SqlDatabase = "[$SqlDatabase]" $Query = "SELECT * FROM $SqlDatabase.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '$Table'" $SqlReturn = @( try { Invoke-DbaQuery -ErrorAction Stop -SqlInstance $SqlServer -Query $Query } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " "Error occured (Get-SqlQueryColumnInformation): $ErrorMessage" } ) return $SQLReturn } function New-SqlQuery { [CmdletBinding()] param ( [Object] $SqlSettings, [Object] $Object, [Object] $TableMapping ) $ArraySQLQueries = New-ArrayList if ($null -ne $Object) { foreach ($O in $Object) { $ArrayMain = New-ArrayList $ArrayKeys = New-ArrayList $ArrayValues = New-ArrayList if (-not $O.AddedWhen) { Add-Member -InputObject $O -MemberType NoteProperty -Name "AddedWhen" -Value (Get-Date) -Force } if (-not $O.AddedWho) { Add-Member -InputObject $O -MemberType NoteProperty -Name "AddedWho" -Value ($Env:USERNAME) -Force } $DuplicateString = [System.Text.StringBuilder]::new() foreach ($E in $O.PSObject.Properties) { $FieldName = $E.Name $FieldValue = $E.Value foreach ($MapKey in $TableMapping.Keys) { if ($FieldName -eq $MapKey) { $MapValue = $TableMapping.$MapKey $MapValueSplit = $MapValue -Split ',' if ($FieldValue -is [DateTime]) { $FieldValue = Get-Date $FieldValue -Format "yyyy-MM-dd HH:mm:ss" } if ($FieldValue -like "*'*") { $FieldValue = $FieldValue -Replace "'", "''" } Add-ToArray -List $ArrayKeys -Element "[$($MapValueSplit[0])]" if ([string]::IsNullOrWhiteSpace($FieldValue)) { Add-ToArray -List $ArrayValues -Element "NULL" } else { foreach ($ColumnName in $SqlSettings.SqlCheckBeforeInsert) { $DuplicateColumn = $ColumnName.Replace("[", '').Replace("]", '') if ($MapValueSplit[0] -eq $DuplicateColumn) { if ($DuplicateString.Length -ne 0) { $null = $DuplicateString.Append(" AND ") } $null = $DuplicateString.Append("[$DuplicateColumn] = '$FieldValue'") } } Add-ToArray -List $ArrayValues -Element "'$FieldValue'" } } } } if ($ArrayKeys) { if ($null -ne $SqlSettings.SqlCheckBeforeInsert -and $DuplicateString.Length -gt 0) { Add-ToArray -List $ArrayMain -Element "IF NOT EXISTS (" Add-ToArray -List $ArrayMain -Element "SELECT 1 FROM " Add-ToArray -List $ArrayMain -Element "$($SqlSettings.SqlTable) " Add-ToArray -List $ArrayMain -Element "WHERE $($DuplicateString.ToString())" Add-ToArray -List $ArrayMain -Element ")" } Add-ToArray -List $ArrayMain -Element "BEGIN" Add-ToArray -List $ArrayMain -Element "INSERT INTO $($SqlSettings.SqlTable) (" Add-ToArray -List $ArrayMain -Element ($ArrayKeys -join ',') Add-ToArray -List $ArrayMain -Element ') VALUES (' Add-ToArray -List $ArrayMain -Element ($ArrayValues -join ',') Add-ToArray -List $ArrayMain -Element ')' Add-ToArray -List $ArrayMain -Element "END" Add-ToArray -List $ArraySQLQueries -Element ([string] ($ArrayMain) -replace "`n", "" -replace "`r", "") } } } return $ArraySQLQueries } function New-SqlQueryAlterTable { [CmdletBinding()] param ( [Object]$SqlSettings, [Object]$TableMapping, [string[]] $ExistingColumns ) $ArraySQLQueries = New-ArrayList $ArrayMain = New-ArrayList $ArrayKeys = New-ArrayList foreach ($MapKey in $TableMapping.Keys) { $MapValue = $TableMapping.$MapKey $Field = $MapValue -Split ',' if ($ExistingColumns -notcontains $MapKey -and $ExistingColumns -notcontains $Field[0]) { if ($Field.Count -eq 1) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] [nvarchar](max) NULL" } elseif ($Field.Count -eq 2) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) NULL" } elseif ($Field.Count -eq 3) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) $($Field[2])" } } } if ($ArrayKeys) { Add-ToArray -List $ArrayMain -Element "ALTER TABLE $($SqlSettings.SqlTable) ADD" Add-ToArray -List $ArrayMain -Element ($ArrayKeys -join ',') Add-ToArray -List $ArrayMain -Element ';' Add-ToArray -List $ArraySQLQueries -Element ([string] ($ArrayMain) -replace "`n", "" -replace "`r", "") } return $ArraySQLQueries } function New-SqlQueryCreateTable { [CmdletBinding()] param ( [Object]$SqlSettings, [Object]$TableMapping ) $ArraySQLQueries = New-ArrayList $ArrayMain = New-ArrayList $ArrayKeys = New-ArrayList foreach ($MapKey in $TableMapping.Keys) { $MapValue = $TableMapping.$MapKey $Field = $MapValue -Split ',' if ($Field.Count -eq 1) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] [nvarchar](max) NULL" } elseif ($Field.Count -eq 2) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) NULL" } elseif ($Field.Count -eq 3) { Add-ToArray -List $ArrayKeys -Element "[$($Field[0])] $($Field[1]) $($Field[2])" } } if ($ArrayKeys) { Add-ToArray -List $ArrayMain -Element "CREATE TABLE $($SqlSettings.SqlTable) (" Add-ToArray -List $ArrayMain -Element "ID int IDENTITY(1,1) PRIMARY KEY," Add-ToArray -List $ArrayMain -Element ($ArrayKeys -join ',') Add-ToArray -List $ArrayMain -Element ')' Add-ToArray -List $ArraySQLQueries -Element ([string] ($ArrayMain) -replace "`n", "" -replace "`r", "") } return $ArraySQLQueries } function New-SqlTableMapping { [CmdletBinding()] param( [Object] $SqlTableMapping, [Object] $Object, $Properties, [switch] $BasedOnSqlTable ) if ($SqlTableMapping) { $TableMapping = $SqlTableMapping } else { $TableMapping = @{} if ($BasedOnSqlTable) { foreach ($Property in $Properties) { $FieldName = $Property $FieldNameSql = $Property $TableMapping.$FieldName = $FieldNameSQL } } else { foreach ($O in $Properties.HighestObject) { foreach ($Property in $Properties.Properties) { $FieldName = $Property $FieldValue = $O.$Property $FieldNameSQL = $FieldName.Replace(' ', '') if ($FieldValue -is [DateTime]) { $TableMapping.$FieldName = "$FieldNameSQL,[datetime],null" } elseif ($FieldValue -is [int] -or $FieldValue -is [Int64]) { $TableMapping.$FieldName = "$FieldNameSQL,[bigint]" } elseif ($FieldValue -is [bool]) { $TableMapping.$FieldName = "$FieldNameSQL,[bit]" } else { $TableMapping.$FieldName = "$FieldNameSQL" } } } } } return $TableMapping } function Send-SqlInsert { [CmdletBinding()] param( [Array] $Object, [System.Collections.IDictionary] $SqlSettings ) if ($SqlSettings.SqlTableTranspose) { $Object = Format-TransposeTable -Object $Object } $SqlTable = Get-SqlQueryColumnInformation -SqlServer $SqlSettings.SqlServer -SqlDatabase $SqlSettings.SqlDatabase -Table $SqlSettings.SqlTable $PropertiesFromAllObject = Get-ObjectPropertiesAdvanced -Object $Object -AddProperties 'AddedWhen', 'AddedWho' $PropertiesFromTable = $SqlTable.Column_name if ($null -eq $SqlTable) { if ($SqlSettings.SqlTableCreate) { Write-Verbose "Send-SqlInsert - SqlTable doesn't exists, table creation is allowed, mapping will be done either on properties from object or from TableMapping defined in config" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject $CreateTableSQL = New-SqlQueryCreateTable -SqlSettings $SqlSettings -TableMapping $TableMapping } else { Write-Verbose "Send-SqlInsert - SqlTable doesn't exists, no table creation is allowed. Terminating" return "Error occured: SQL Table doesn't exists. SqlTableCreate option is disabled" } } else { if ($SqlSettings.SqlTableAlterIfNeeded) { if ( $SqlSettings.SqlTableMapping) { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is allowed, but SqlTableMapping is already defined" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject } else { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is allowed, and SqlTableMapping is not defined" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject $AlterTableSQL = New-SqlQueryAlterTable -SqlSettings $SqlSettings -TableMapping $TableMapping -ExistingColumns $SqlTable.Column_name } } else { if ( $SqlSettings.SqlTableMapping) { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is not allowed, SqlTableMaping is already defined" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromAllObject } else { Write-Verbose "Send-SqlInsert - Sql Table exists, Alter is not allowed, SqlTableMaping is not defined, using SqlTable Columns" $TableMapping = New-SqlTableMapping -SqlTableMapping $SqlSettings.SqlTableMapping -Object $Object -Properties $PropertiesFromTable -BasedOnSqlTable } } } $Queries = @( if ($CreateTableSQL) { foreach ($Sql in $CreateTableSQL) { $Sql } } if ($AlterTableSQL) { foreach ($Sql in $AlterTableSQL) { $Sql } } $SqlQueries = New-SqlQuery -Object $Object -SqlSettings $SqlSettings -TableMapping $TableMapping foreach ($Sql in $SqlQueries) { $Sql } ) $ReturnData = foreach ($Query in $Queries) { try { if ($Query) { $Query Invoke-DbaQuery -SqlInstance "$($SqlSettings.SqlServer)" -Database "$($SqlSettings.SqlDatabase)" -Query $Query -ErrorAction Stop } } catch { $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " " "Error occured (Send-SqlInsert): $ErrorMessage" } } return $ReturnData } function Find-TypesNeeded { [CmdletBinding()] param ( [Array] $TypesRequired, [Array] $TypesNeeded ) [bool] $Found = $False foreach ($Type in $TypesNeeded) { if ($TypesRequired -contains $Type) { $Found = $true break } } return $Found } Function Get-ModulesAvailability { [cmdletBinding()] param( [string]$Name ) if (-not(Get-Module -Name $Name)) { if (Get-Module -ListAvailable | Where-Object { $_.Name -eq $Name }) { try { Import-Module -Name $Name return $true } catch { return $false } } else { return $false } } else { return $true } } function Search-Command { [cmdletbinding()] param ( [string] $CommandName ) return [bool](Get-Command -Name $CommandName -ErrorAction SilentlyContinue) } function Test-AvailabilityCommands { [cmdletBinding()] param ( [string[]] $Commands ) $CommandsStatus = foreach ($Command in $Commands) { $Exists = Get-Command -Name $Command -ErrorAction SilentlyContinue if ($Exists) { Write-Verbose "Test-AvailabilityCommands - Command $Command is available." } else { Write-Verbose "Test-AvailabilityCommands - Command $Command is not available." } $Exists } return $CommandsStatus } function Test-ComputerAvailability { [CmdletBinding()] param( [string[]] $Servers, [ValidateSet('All', 'Ping', 'WinRM', 'PortOpen', 'Ping+WinRM', 'Ping+PortOpen', 'WinRM+PortOpen')] $Test = 'All', [int[]] $Ports = 135, [int] $PortsTimeout = 100, [int] $PingCount = 1 ) $OutputList = @( foreach ($Server in $Servers) { $Output = [ordered] @{ } $Output.ServerName = $Server if ($Test -eq 'All' -or $Test -like 'Ping*') { $Output.Pingable = Test-Connection -ComputerName $Server -Quiet -Count $PingCount } if ($Test -eq 'All' -or $Test -like '*WinRM*') { $Output.WinRM = (Test-WinRM -ComputerName $Server).Status } if ($Test -eq 'All' -or '*PortOpen*') { $Output.PortOpen = (Test-ComputerPort -Server $Server -PortTCP $Ports -Timeout $PortsTimeout).Status } [PSCustomObject] $Output } ) return $OutputList } function Test-ComputerPort { [CmdletBinding()] param ( [alias('Server')][string[]] $ComputerName, [int[]] $PortTCP, [int[]] $PortUDP, [int]$Timeout = 5000 ) begin { if ($Global:ProgressPreference -ne 'SilentlyContinue') { $TemporaryProgress = $Global:ProgressPreference $Global:ProgressPreference = 'SilentlyContinue' } } process { foreach ($Computer in $ComputerName) { foreach ($P in $PortTCP) { $Output = [ordered] @{ 'ComputerName' = $Computer 'Port' = $P 'Protocol' = 'TCP' 'Status' = $null 'Summary' = $null 'Response' = $null } $TcpClient = Test-NetConnection -ComputerName $Computer -Port $P -InformationLevel Detailed -WarningAction SilentlyContinue if ($TcpClient.TcpTestSucceeded) { $Output['Status'] = $TcpClient.TcpTestSucceeded $Output['Summary'] = "TCP $P Successful" } else { $Output['Status'] = $false $Output['Summary'] = "TCP $P Failed" $Output['Response'] = $Warnings } [PSCustomObject]$Output } foreach ($P in $PortUDP) { $Output = [ordered] @{ 'ComputerName' = $Computer 'Port' = $P 'Protocol' = 'UDP' 'Status' = $null 'Summary' = $null } $UdpClient = [System.Net.Sockets.UdpClient]::new($Computer, $P) $UdpClient.Client.ReceiveTimeout = $Timeout $Encoding = [System.Text.ASCIIEncoding]::new() $byte = $Encoding.GetBytes("Evotec") [void]$UdpClient.Send($byte, $byte.length) $RemoteEndpoint = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any, 0) try { $Bytes = $UdpClient.Receive([ref]$RemoteEndpoint) [string]$Data = $Encoding.GetString($Bytes) If ($Data) { $Output['Status'] = $true $Output['Summary'] = "UDP $P Successful" $Output['Response'] = $Data } } catch { $Output['Status'] = $false $Output['Summary'] = "UDP $P Failed" $Output['Response'] = $_.Exception.Message } $UdpClient.Close() $UdpClient.Dispose() [PSCustomObject]$Output } } } end { if ($TemporaryProgress) { $Global:ProgressPreference = $TemporaryProgress } } } function Test-ConfigurationCredentials { [CmdletBinding()] param ( [Object] $Configuration, $AllowEmptyKeys ) $Object = foreach ($Key in $Configuration.Keys) { if ($AllowEmptyKeys -notcontains $Key -and [string]::IsNullOrWhiteSpace($Configuration.$Key)) { Write-Verbose "Test-ConfigurationCredentials - Configuration $Key is Null or Empty! Terminating" @{ Status = $false; Output = $User.SamAccountName; Extended = "Credentials configuration $Key is Null or Empty!" } } } return $Object } function Test-ForestConnectivity { [CmdletBinding()] param( ) Try { $null = Get-ADForest return $true } catch { return $False } } function Test-Key { [CmdletBinding()] param( $ConfigurationTable, $ConfigurationSection = "", $ConfigurationKey, $DisplayProgress = $false ) if ($null -eq $ConfigurationTable) { return $false } try { $value = $ConfigurationTable.ContainsKey($ConfigurationKey) } catch { $value = $false } if ($value -eq $true) { if ($DisplayProgress -eq $true) { Write-Color @script:WriteParameters -Text "[i] ", "Parameter in configuration of ", "$ConfigurationSection.$ConfigurationKey", " exists." -Color White, White, Green, White } return $true } else { if ($DisplayProgress -eq $true) { Write-Color @script:WriteParameters -Text "[i] ", "Parameter in configuration of ", "$ConfigurationSection.$ConfigurationKey", " doesn't exist." -Color White, White, Red, White } return $false } } function Test-ModuleAvailability { [CmdletBinding()] param( ) if (Search-Command -CommandName 'Get-AdForest') { } else { Write-Warning 'Modules required to run not found.' Exit } } function Test-WinRM { [CmdletBinding()] param ( [alias('Server')][string[]] $ComputerName ) $Output = foreach ($Computer in $ComputerName) { $Test = [PSCustomObject] @{ Output = $null Status = $null ComputerName = $Computer } try { $Test.Output = Test-WSMan -ComputerName $Computer -ErrorAction Stop $Test.Status = $true } catch { $Test.Status = $false } $Test } $Output } function Get-TimeSettings { [alias('Get-TimeSynchronization')] param( [string[]] $ComputerName, # [string] $Domain, [switch] $Formatted, [string] $Splitter ) $Types = @{ NT5DS = 'The time service synchronizes from the domain hierarchy.' NTP = 'The time service synchronizes from the servers specified in the NtpServer registry entry.' ALLSync = 'The time service uses all the available synchronization mechanisms.' NoSync = 'The time service does not synchronize with other sources.' } [flags()] enum NtpServerFlags { None = 0 SpecialInterval = 0x1 UseAsFallbackOnly = 0x2 SymmetricActive = 0x4 Client = 0x8 } $CrossSiteSyncFlags = @{ '0' = 'None' '1' = 'PdcOnly' '2' = 'All' } $AnnounceFlags = @{ '0' = 'Not a time server' '1' = 'Always time server' '2' = 'Automatic time server' '4' = 'Always reliable time server' '8' = 'Automatic reliable time server' '10' = 'The default value for domain members is 10. The default value for stand-alone clients and servers is 10.' } foreach ($_ in $ComputerName) { [bool] $AppliedGPO = $false $TimeParameters = Get-PSRegistry -ComputerName $_ -RegistryPath "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\W32time\Parameters" if ($null -eq $TimeParameters.NtpServer) { $TimeParameters = Get-PSRegistry -ComputerName $_ -RegistryPath "HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Parameters" $AppliedGPO = $true } $TimeConfig = Get-PSRegistry -ComputerName $_ -RegistryPath "HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Config" $TimeNTPClient = Get-PSRegistry -ComputerName $_ -RegistryPath "HKLM\SOFTWARE\Policies\Microsoft\W32time\TimeProviders\NtpClient" if ($null -eq $TimeNTPClient.CrossSiteSyncFlags) { $TimeNTPClient = Get-PSRegistry -ComputerName $_ -RegistryPath "HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NTPClient" } $TimeNTPServer = Get-PSRegistry -ComputerName $_ -RegistryPath "HKLM\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NTPServer" $TimeVMProvider = Get-PSRegistry -ComputerName $_ -RegistryPath "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\VMICTimeProvider" $NtpServers = $TimeParameters.NtpServer -split ' ' $Ntp = foreach ($NtpServer in $NtpServers) { $SplitNTP = $NtpServer -split ',' if ($SplitNTP.Count -eq 2) { if ($flagVal = $SplitNTP[1] -as [int]) { if ($flags = $flagVal -as [NtpServerFlags]) { $Intervals = $flags.ToString().Replace(', ', '+') } else { Write-Warning -Message "Get-TimeSettings - NtpServer flag value `"$flagVal`" could not be converted to NtpServerFlags enum" $Intervals = 'Incorrect' } } else { Write-Warning -Message "Get-TimeSettings - NtpServer flag value `"$($SplitNTP[1])`" could not be parsed as an integer" $Intervals = 'Incorrect' } } else { $Intervals = 'Missing' } [PSCustomObject] @{ NtpServer = $SplitNTP[0] Intervals = $Intervals } } [PSCustomObject] @{ ComputerName = $_ NtpServer = if ($Splitter) { $Ntp.NtpServer -join $Splitter } else { $Ntp.NtpServer } NtpServerIntervals = if ($Splitter) { $Ntp.Intervals -join $Splitter } else { $Ntp.Intervals } NtpType = $TimeParameters.Type NtpTypeComment = $Types["$($TimeParameters.Type)"] AppliedGPO = $AppliedGPO VMTimeProvider = [bool] $TimeVMProvider.Enabled WindowsSecureTimeSeeding = if ($null -eq $TimeConfig.UtilizeSslTimeData) { $true } elseif ($TimeConfig.UtilizeSslTimeData -eq 0) { $false } else { $true } AnnounceFlags = $TimeConfig.AnnounceFlags AnnounceFlagsComment = $AnnounceFlags["$($TimeConfig.AnnounceFlags)"] NtpServerEnabled = [bool]$TimeNTPServer.Enabled NtpServerInputProvider = [bool]$TimeNTPServer.InputProvider MaxPosPhaseCorrection = $TimeConfig.MaxPosPhaseCorrection MaxnegPhaseCorrection = $TimeConfig.MaxnegPhaseCorrection MaxAllowedPhaseOffset = $TimeConfig.MaxAllowedPhaseOffset MaxPollInterval = $TimeConfig.MaxPollInterval MinPollInterval = $TimeConfig.MinPollInterval UpdateInterval = $TimeConfig.UpdateInterval ResolvePeerBackoffMinutes = $TimeNTPClient.ResolvePeerBackoffMinutes ResolvePeerBackoffMaxTimes = $TimeNTPClient.ResolvePeerBackoffMaxTimes SpecialPollInterval = $TimeNTPClient.SpecialPollInterval EventLogFlags = $TimeConfig.EventLogFlags NtpClientEnabled = [bool] $TimeNTPClient.Enabled NtpClientCrossSiteSyncFlags = $CrossSiteSyncFlags["$($TimeNTPClient.CrossSiteSyncFlags)"] NtpClientInputProvider = [bool] $TimeNTPClient.InputProvider TimeNTPClient = $TimeNTPClient.SpecialPollInterval } } } function Get-TimeZoneAdvanced { param( [string[]]$ComputerName = $Env:COMPUTERNAME, [System.Management.Automation.PSCredential] $Credential = [System.Management.Automation.PSCredential]::Empty ) foreach ($computer in $computerName) { $TimeZone = Get-WmiObject -Class win32_timezone -ComputerName $computer -Credential $Credential $LocalTime = Get-WmiObject -Class win32_localtime -ComputerName $computer -Credential $Credential $Output = @{ 'ComputerName' = $localTime.__SERVER; 'TimeZone' = $timeZone.Caption; 'CurrentTime' = (Get-Date -Day $localTime.Day -Month $localTime.Month); } $Object = New-Object -TypeName PSObject -Property $Output Write-Output $Object } } function Get-TimeZoneLegacy () { return ([System.TimeZone]::CurrentTimeZone).StandardName } function Measure-Collection { param( [string] $Name, [ScriptBlock] $ScriptBlock ) $Time = [System.Diagnostics.Stopwatch]::StartNew() Invoke-Command -ScriptBlock $ScriptBlock $Time.Stop() "Name: $Name, $($Time.Elapsed.Days) days, $($Time.Elapsed.Hours) hours, $($Time.Elapsed.Minutes) minutes, $($Time.Elapsed.Seconds) seconds, $($Time.Elapsed.Milliseconds) milliseconds, ticks $($Time.Elapsed.Ticks)" } function Set-TimeSynchronization { param( [string[]] $TimeSource = 'time.windows.com', [int] $MaxPosPhaseCorrection = 86400, [int] $MaxnegPhaseCorrection = 86400, [int] $PollInterval = 1800 ) Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters -Name Type -Value 'NTP' Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config -Name AnnounceFlags -Value 5 Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer -Name Enabled -Value 1 Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Parameters -Name NtpServer -Value "$TimeSource,0x1" Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient -Name SpecialPollInterval -Value $PollInterval Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config -Name MaxPosPhaseCorrection -Value $MaxPosPhaseCorrection Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\W32Time\Config -Name MaxnegPhaseCorrection -Value $MaxnegPhaseCorrection Stop-Service -Name W32Time Start-Service -Name W32Time } function Start-TimeLog { [CmdletBinding()] param() [System.Diagnostics.Stopwatch]::StartNew() } function Stop-TimeLog { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)][System.Diagnostics.Stopwatch] $Time, [ValidateSet('OneLiner', 'Array')][string] $Option = 'OneLiner', [switch] $Continue ) Begin { } Process { if ($Option -eq 'Array') { $TimeToExecute = "$($Time.Elapsed.Days) days", "$($Time.Elapsed.Hours) hours", "$($Time.Elapsed.Minutes) minutes", "$($Time.Elapsed.Seconds) seconds", "$($Time.Elapsed.Milliseconds) milliseconds" } else { $TimeToExecute = "$($Time.Elapsed.Days) days, $($Time.Elapsed.Hours) hours, $($Time.Elapsed.Minutes) minutes, $($Time.Elapsed.Seconds) seconds, $($Time.Elapsed.Milliseconds) milliseconds" } } End { if (-not $Continue) { $Time.Stop() } return $TimeToExecute } } function Show-Array { [CmdletBinding()] param( [System.Collections.ArrayList] $List, [switch] $WithType ) foreach ($Element in $List) { $Type = Get-ObjectType -Object $Element if ($WithType) { Write-Output "$Element (Type: $($Type.ObjectTypeName))" } else { Write-Output $Element } } } function Show-DataInVerbose { [CmdletBinding()] param( [Object] $Object ) foreach ($O in $Object) { foreach ($E in $O.PSObject.Properties) { $FieldName = $E.Name $FieldValue = $E.Value Write-Verbose "Display-DataInVerbose - FieldName: $FieldName FieldValue: $FieldValue" } } } function Show-TableVisualization { [CmdletBinding()] param ( [parameter(ValueFromPipelineByPropertyName, ValueFromPipeline)] $Object ) if ($Color) { Write-Color "[i] This is how table looks like in Format-Table" -Color Yellow } Write-Verbose '[i] This is how table looks like in Format-Table' $Object | Format-Table -AutoSize $Data = Format-PSTable $Object Write-Verbose "[i] Rows Count $($Data.Count) Column Count $($Data[0].Count)" $RowNr = 0 if ($Color) { Write-Color "[i] Presenting table after conversion" -Color Yellow } foreach ($Row in $Data) { $ColumnNr = 0 foreach ($Column in $Row) { Write-Verbose "Row: $RowNr Column: $ColumnNr Data: $Column" $ColumnNr++ } $RowNr++ } } function Save-XML { param ( [string] $FilePath, [System.Xml.XmlNode] $xml ) $utf8WithoutBom = New-Object System.Text.UTF8Encoding($false) $writer = New-Object System.IO.StreamWriter($FilePath, $false, $utf8WithoutBom) $xml.Save( $writer ) $writer.Close() } function Set-XML { param ( [string] $FilePath, [string[]]$Paths, [string] $Node, [string] $Value ) [xml]$xmlDocument = Get-Content -Path $FilePath -Encoding UTF8 $XmlElement = $xmlDocument foreach ($Path in $Paths) { $XmlElement = $XmlElement.$Path } $XmlElement.$Node = $Value $xmlDocument.Save($FilePath) } function Get-ProtocolDefaults { <# .SYNOPSIS Gets a list of default settings for SSL/TLS protocols .DESCRIPTION Gets a list of default settings for SSL/TLS protocols .PARAMETER WindowsVersion Windows Version to search for .PARAMETER AsList If true, returns a list of protocol names for all Windows Versions, otherwise returns a single entry for the specified Windows Version .EXAMPLE Get-ProtocolDefaults -AsList | Format-Table .EXAMPLE Get-ProtocolDefaults -WindowsVersion 'Windows 10 1809' | Format-Table .NOTES Based on: https://docs.microsoft.com/en-us/windows/win32/secauthn/protocols-in-tls-ssl--schannel-ssp- According to this https://github.com/MicrosoftDocs/windowsserverdocs/issues/2783 SCHANNEL service requires direct enablement so the list is kind of half useful #> [cmdletbinding(DefaultParameterSetName = 'WindowsVersion')] param( [Parameter(Mandatory, ParameterSetName = 'WindowsVersion')][string] $WindowsVersion, [Parameter(Mandatory, ParameterSetName = 'AsList')][switch] $AsList ) $Defaults = [ordered] @{ 'Windows Server 2022' = [ordered] @{ 'Version' = 'Windows Server 2022' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Enabled' 'TLS13Server' = 'Enabled' } 'Windows Server 2019 20H2' = [ordered] @{ 'Version' = 'Windows Server 2019 20H2' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows Server 2019 2004' = [ordered] @{ 'Version' = 'Windows Server 2019 2004' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows Server 2019 1909' = [ordered] @{ 'Version' = 'Windows Server 2019 1909' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows Server 2019 1903" = [ordered] @{ 'Version' = 'Windows Server 2019 1903' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows Server 2019 1809" = [ordered] @{ 'Version' = 'Windows Server 2019 1809' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows Server 2016 1803" = [ordered] @{ 'Version' = 'Windows Server 2016 1803' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows Server 2016 1607" = [ordered] @{ 'Version' = 'Windows Server 2019 1607' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows Server 2012 R2' = [ordered] @{ 'Version' = 'Windows Server 2012 R2' 'PCT10' = 'Not supported' 'SSL2Client' = 'Disabled' 'SSL2Server' = 'Disabled' 'SSL3Client' = 'Enabled' 'SSL3Server' = 'Enabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows Server 2012' = [ordered] @{ 'Version' = 'Windows Server 2012' 'PCT10' = 'Not supported' 'SSL2Client' = 'Disabled' 'SSL2Server' = 'Disabled' 'SSL3Client' = 'Enabled' 'SSL3Server' = 'Enabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows Server 2008 R2' = [ordered] @{ 'Version' = 'Windows Server 2008 R2' 'PCT10' = 'Not supported' 'SSL2Client' = 'Disabled' 'SSL2Server' = 'Enabled' 'SSL3Client' = 'Enabled' 'SSL3Server' = 'Enabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Disabled' 'TLS11Server' = 'Disabled' 'TLS12Client' = 'Disabled' 'TLS12Server' = 'Disabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows Server 2008' = [ordered] @{ 'Version' = 'Windows Server 2008' 'PCT10' = 'Not supported' 'SSL2Client' = 'Disabled' 'SSL2Server' = 'Enabled' 'SSL3Client' = 'Enabled' 'SSL3Server' = 'Enabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Disabled' 'TLS11Server' = 'Disabled' 'TLS12Client' = 'Disabled' 'TLS12Server' = 'Disabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows 11 21H2' = [ordered] @{ 'Version' = 'Windows 11 21H2' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Enabled' 'TLS13Server' = 'Enabled' } 'Windows 10 21H1' = [ordered] @{ 'Version' = 'Windows 10 21H1' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows 10 20H2' = [ordered] @{ 'Version' = 'Windows 10 20H2' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows 10 2004' = [ordered] @{ 'Version' = 'Windows 10 2004' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } 'Windows 10 Insider Preview' = [ordered] @{ 'Version' = 'Windows 10 Insider Preview' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1909" = [ordered] @{ 'Version' = 'Windows 10 1909' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1903" = [ordered] @{ 'Version' = 'Windows 10 1903' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1809" = [ordered] @{ 'Version' = 'Windows 10 1809' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1803" = [ordered] @{ 'Version' = 'Windows 10 1803' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1709" = [ordered] @{ 'Version' = 'Windows 10 1709' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1703" = [ordered] @{ 'Version' = 'Windows 10 1703' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1607" = [ordered] @{ 'Version' = 'Windows 10 1607' 'PCT10' = 'Not supported' 'SSL2Client' = 'Not supported' 'SSL2Server' = 'Not supported' 'SSL3Client' = 'Disabled' 'SSL3Server' = 'Disabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1511" = [ordered] @{ 'Version' = 'Windows 10 1511' 'PCT10' = 'Not supported' 'SSL2Client' = 'Disabled' 'SSL2Server' = 'Disabled' 'SSL3Client' = 'Enabled' 'SSL3Server' = 'Enabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } "Windows 10 1507" = [ordered] @{ 'Version' = 'Windows 10 1507' 'PCT10' = 'Not supported' 'SSL2Client' = 'Disabled' 'SSL2Server' = 'Disabled' 'SSL3Client' = 'Enabled' 'SSL3Server' = 'Enabled' 'TLS10Client' = 'Enabled' 'TLS10Server' = 'Enabled' 'TLS11Client' = 'Enabled' 'TLS11Server' = 'Enabled' 'TLS12Client' = 'Enabled' 'TLS12Server' = 'Enabled' 'TLS13Client' = 'Not supported' 'TLS13Server' = 'Not supported' } } if ($AsList) { foreach ($Key in $Defaults.Keys) { [PSCustomObject] $Defaults[$Key] } } else { if ($Defaults[$WindowsVersion]) { $Defaults[$WindowsVersion] } else { [ordered] @{ 'Version' = 'Unknown' 'PCT10' = 'Unknown' 'SSL2Client' = 'Unknown' 'SSL2Server' = 'Unknown' 'SSL3Client' = 'Unknown' 'SSL3Server' = 'Unknown' 'TLS10Client' = 'Unknown' 'TLS10Server' = 'Unknown' 'TLS11Client' = 'Unknown' 'TLS11Server' = 'Unknown' 'TLS12Client' = 'Unknown' 'TLS12Server' = 'Unknown' 'TLS13Client' = 'Unknown' 'TLS13Server' = 'Unknown' } } } } Add-Type -TypeDefinition @" public enum RGBColors { None, Black, Navy, DarkBlue, MediumBlue, Blue, DarkGreen, Green, Teal, DarkCyan, DeepSkyBlue, DarkTurquoise, MediumSpringGreen, Lime, SpringGreen, Aqua, Cyan, MidnightBlue, DodgerBlue, LightSeaGreen, ForestGreen, SeaGreen, DarkSlateGray, DarkSlateGrey, LimeGreen, MediumSeaGreen, Turquoise, RoyalBlue, SteelBlue, DarkSlateBlue, MediumTurquoise, Indigo, DarkOliveGreen, CadetBlue, CornflowerBlue, MediumAquamarine, DimGray, DimGrey, SlateBlue, OliveDrab, SlateGray, SlateGrey, LightSlateGray, LightSlateGrey, MediumSlateBlue, LawnGreen, Chartreuse, Aquamarine, Maroon, Purple, Olive, Grey, Gray, //Grey, SkyBlue, LightSkyBlue, BlueViolet, DarkRed, DarkMagenta, SaddleBrown, DarkSeaGreen, LightGreen, MediumPurple, DarkViolet, PaleGreen, DarkOrchid, YellowGreen, Sienna, Brown, DarkGray, DarkGrey, LightBlue, GreenYellow, PaleTurquoise, LightSteelBlue, PowderBlue, FireBrick, DarkGoldenrod, MediumOrchid, RosyBrown, DarkKhaki, Silver, MediumVioletRed, IndianRed, Peru, Chocolate, Tan, LightGray, LightGrey, Thistle, Orchid, Goldenrod, PaleVioletRed, Crimson, Gainsboro, Plum, BurlyWood, LightCyan, Lavender, DarkSalmon, Violet, PaleGoldenrod, LightCoral, Khaki, AliceBlue, Honeydew, Azure, SandyBrown, Wheat, Beige, WhiteSmoke, MintCream, GhostWhite, Salmon, AntiqueWhite, Linen, LightGoldenrodYellow, OldLace, Red, Fuchsia, Magenta, DeepPink, OrangeRed, Tomato, HotPink, Coral, DarkOrange, LightSalmon, Orange, LightPink, Pink, Gold, PeachPuff, NavajoWhite, Moccasin, Bisque, MistyRose, BlanchedAlmond, PapayaWhip, LavenderBlush, Seashell, Cornsilk, LemonChiffon, FloralWhite, Snow, Yellow, LightYellow, Ivory, White } "@ Export-ModuleMember -Function @('Add-ToArray', 'Add-ToArrayAdvanced', 'Add-ToHashTable', 'Add-WinADUserGroups', 'Clear-DataInformation', 'Compare-MultipleObjects', 'Compare-ObjectProperties', 'Compare-ObjectsAdvanced', 'Convert-ADGuidToSchema', 'Convert-ADSchemaToGuid', 'Convert-BinaryToHex', 'Convert-BinaryToString', 'Convert-Color', 'Convert-CountryCodeToCountry', 'Convert-CountryToContinent', 'Convert-CountryToCountryCode', 'Convert-DomainFqdnToNetBIOS', 'Convert-DomainToSid', 'Convert-ExchangeEmail', 'Convert-ExchangeItems', 'Convert-ExchangeRecipient', 'Convert-ExchangeSize', 'ConvertFrom-Color', 'ConvertFrom-DistinguishedName', 'ConvertFrom-ErrorRecord', 'ConvertFrom-LanguageCode', 'ConvertFrom-NetbiosName', 'ConvertFrom-ObjectToString', 'ConvertFrom-OperationType', 'ConvertFrom-ScriptBlock', 'ConvertFrom-SID', 'ConvertFrom-X500Address', 'Convert-HexToBinary', 'Convert-Identity', 'Convert-IpAddressToPtr', 'Convert-KeyToKeyValue', 'Convert-Office365License', 'Convert-Size', 'Convert-TimeToDays', 'Convert-ToDateTime', 'ConvertTo-DistinguishedName', 'ConvertTo-FlatHashtable', 'ConvertTo-FlatObject', 'ConvertTo-Identity', 'ConvertTo-ImmutableID', 'ConvertTo-JsonLiteral', 'ConvertTo-OperatingSystem', 'ConvertTo-OrderedDictionary', 'ConvertTo-PrettyObject', 'ConvertTo-SID', 'Convert-ToTimeSpan', 'Convert-TwoArraysIntoOne', 'Convert-UAC', 'Convert-UserAccountControl', 'Copy-Dictionary', 'Copy-DictionaryManual', 'Dismount-PSRegistryPath', 'Find-ADConnectServer', 'Find-DatesCurrentDayMinusDayX', 'Find-DatesCurrentDayMinuxDaysX', 'Find-DatesCurrentHour', 'Find-DatesDayPrevious', 'Find-DatesDayToday', 'Find-DatesMonthCurrent', 'Find-DatesMonthPast', 'Find-DatesPastHour', 'Find-DatesPastWeek', 'Find-DatesQuarterCurrent', 'Find-DatesQuarterLast', 'Find-ExchangeServer', 'Find-HyperVServer', 'Find-MyProgramData', 'Find-ServerTypes', 'Find-TypesNeeded', 'Find-UsersProxyAddressesStatus', 'Format-AddSpaceToSentence', 'Format-Dictionary', 'Format-FirstXChars', 'Format-PSTable', 'Format-Stream', 'Format-ToTitleCase', 'Format-TransposeTable', 'Format-View', 'Get-ADADministrativeGroups', 'Get-ADEncryptionTypes', 'Get-ADTrustAttributes', 'Get-CimData', 'Get-Colors', 'Get-Computer', 'Get-ComputerApplication', 'Get-ComputerBios', 'Get-ComputerCPU', 'Get-ComputerCulture', 'Get-ComputerDevice', 'Get-ComputerDisk', 'Get-ComputerDiskLogical', 'Get-ComputerInstalledUpdates', 'Get-ComputerMemory', 'Get-ComputerMissingDrivers', 'Get-ComputerNetwork', 'Get-ComputerOemInformation', 'Get-ComputerOperatingSystem', 'Get-ComputerRAM', 'Get-ComputerRDP', 'Get-ComputerRoles', 'Get-ComputerService', 'Get-ComputerSMB', 'Get-ComputerSMBShare', 'Get-ComputerSMBShareList', 'Get-ComputerSMBSharePermissions', 'Get-ComputerStartup', 'Get-ComputerSystem', 'Get-ComputerTask', 'Get-ComputerTime', 'Get-ComputerTimeNtp', 'Get-ComputerWindowsFeatures', 'Get-ComputerWindowsUpdates', 'Get-DataInformation', 'Get-FileEncoding', 'Get-FileInformation', 'Get-FileMetaData', 'Get-FileName', 'Get-FileOwner', 'Get-FilePermission', 'Get-FilesInFolder', 'Get-FileSize', 'Get-GitHubLatestRelease', 'Get-GitHubVersion', 'Get-HashMaxValue', 'Get-HTML', 'Get-IPAddressInformation', 'Get-IPAddressRangeInformation', 'Get-Logger', 'Get-MimeType', 'Get-ModulesAvailability', 'Get-MyIpAddress', 'Get-ObjectCount', 'Get-ObjectData', 'Get-ObjectEnumValues', 'Get-ObjectKeys', 'Get-ObjectProperties', 'Get-ObjectPropertiesAdvanced', 'Get-ObjectTitles', 'Get-ObjectType', 'Get-OperatingSystem', 'Get-PathSeparator', 'Get-PathTemporary', 'Get-ProtocolDefaults', 'Get-PSRegistry', 'Get-PSService', 'Get-RandomCharacters', 'Get-RandomFileName', 'Get-RandomPassword', 'Get-RandomStringName', 'Get-SqlQueryColumnInformation', 'Get-TemporaryDirectory', 'Get-TimeSettings', 'Get-TimeZoneAdvanced', 'Get-TimeZoneLegacy', 'Get-Types', 'Get-WinADDSAGuid', 'Get-WinADForestControllers', 'Get-WinADForestDetails', 'Get-WinADForestOptions', 'Get-WinADOrganizationalUnitData', 'Get-WinADOrganizationalUnitFromDN', 'Get-WinADUsersByDN', 'Get-WinADUsersByOU', 'Get-WinADUserSnapshot', 'Initialize-ModulePortable', 'Invoke-CommandCustom', 'Join-Uri', 'Join-UriQuery', 'Measure-Collection', 'Merge-Array', 'Merge-Objects', 'Mount-PSRegistryPath', 'New-ArrayList', 'New-GenericList', 'New-PSRegistry', 'New-Runspace', 'New-SqlQuery', 'New-SqlQueryAlterTable', 'New-SqlQueryCreateTable', 'New-SqlTableMapping', 'Remove-DuplicateObjects', 'Remove-EmptyValue', 'Remove-FilePermission', 'Remove-FromArray', 'Remove-ObjectsExistingInTarget', 'Remove-PSRegistry', 'Remove-WhiteSpace', 'Remove-WinADUserGroups', 'Rename-LatinCharacters', 'Rename-UserValuesFromHash', 'Save-XML', 'Search-Command', 'Select-Properties', 'Send-Email', 'Send-SqlInsert', 'Set-DnsServerIpAddress', 'Set-EmailBody', 'Set-EmailBodyPreparedTable', 'Set-EmailBodyReplacement', 'Set-EmailBodyReplacementTable', 'Set-EmailFormatting', 'Set-EmailHead', 'Set-EmailReportBranding', 'Set-EmailWordReplacements', 'Set-EmailWordReplacementsHash', 'Set-FileInheritance', 'Set-FileOwner', 'Set-FilePermission', 'Set-PasswordRemotely', 'Set-PSRegistry', 'Set-ServiceRecovery', 'Set-TimeSynchronization', 'Set-WinADGroupSynchronization', 'Set-WinADUserFields', 'Set-WinADUserSettingGAL', 'Set-WinADUserStatus', 'Set-XML', 'Show-Array', 'Show-DataInVerbose', 'Show-TableVisualization', 'Split-Array', 'Start-InternalFunction', 'Start-MyProgram', 'Start-Runspace', 'Start-TimeLog', 'Stop-Runspace', 'Stop-TimeLog', 'Test-AvailabilityCommands', 'Test-ComputerAvailability', 'Test-ComputerPort', 'Test-ConfigurationCredentials', 'Test-ForestConnectivity', 'Test-IsDistinguishedName', 'Test-Key', 'Test-ModuleAvailability', 'Test-PSRegistry', 'Test-WinRM') -Alias @('Add-ADUserGroups', 'Convert-ExchangeRecipientDetails', 'Convert-FromColor', 'Copy-Hashtable', 'Copy-OrderedHashtable', 'Dismount-RegistryPath', 'Find-ADSyncServer', 'Format-Debug', 'Format-ListStream', 'Format-TableStream', 'Format-Verbose', 'Format-Warning', 'FS', 'FV', 'Get-ADUserSnapshot', 'Get-ComputerApplications', 'Get-ComputerNetworkCard', 'Get-ComputerServices', 'Get-ComputerTasks', 'Get-FilePermissions', 'Get-MyIP', 'Get-PSPermissions', 'Get-RDPSecurity', 'Get-ServerRoles', 'Get-TimeSynchronization', 'Get-WinADDomainControllers', 'Get-WinADDomainGUIDs', 'Get-WinADForestGUIDs', 'Join-Url', 'Join-UrlQuery', 'Mount-RegistryPath', 'Remove-ADUserGroups', 'Remove-EmptyValues', 'Remove-StringLatinCharacters', 'Set-ADUserName', 'Set-ADUserSettingGAL', 'Set-ADUserStatus', 'Set-EmailBodyTableReplacement', 'Set-Recovery', 'Sort-Dictionary', 'Test-IsDN') # SIG # Begin signature block # MIItsQYJKoZIhvcNAQcCoIItojCCLZ4CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD796JxEr0ZQ/jb # dhXsCKo7ehhGsOpk6eiFkgyTS7LR8KCCJrQwggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggWQMIIDeKADAgECAhAFmxtXno4hMuI5B72nd3VcMA0GCSqG # SIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIw # aTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLK # EdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4Tm # dDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembu # d8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnD # eMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1 # XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVld # QnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTS # YW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSm # M9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzT # QRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6Kx # fgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD # VR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwPTzANBgkq # hkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNkaA9Wz3eucPn9mkqZucl4 # XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjSPMFDQK4dUPVS/JA7u5iZ # aWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK7VB6fWIhCoDIc2bRoAVg # X+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eBcg3AFDLvMFkuruBx8lbk # apdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp5aPNoiBB19GcZNnqJqGL # FNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msgdDDS4Dk0EIUhFQEI6FUy # 3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vriRbgjU2wGb2dVf0a1TD9u # KFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ79ARj6e/CVABRoIoqyc54 # zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5nLGbsQAe79APT0JsyQq8 # 7kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3i0objwG2J5VT6LaJbVu8 # aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0HEEcRrYc9B9F1vM/zZn4w # ggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBH # NDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1 # c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqG # SIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbS # g9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9 # /UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXn # HwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0 # VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4f # sbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40Nj # gHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0 # QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvv # mz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T # /jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk # 42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5r # mQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E # FgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5n # P+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcG # CCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu # Y29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln # aUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8v # Y3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNV # HSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIB # AH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxp # wc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIl # zpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQ # cAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfe # Kuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+j # Sbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJsh # IUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6 # OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDw # N7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR # 81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2 # VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIGsDCCBJigAwIBAgIQ # CK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQGEwJVUzEV # MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t # MSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjEwNDI5MDAw # MDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBT # aWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zrPYGXcMW7xIUmMJ+k # jmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHMgQM+TXAkZLON4gh9 # NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8IrgnQnAZaf6mIBJNYc9 # URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyCEUhSaN4QvRRXXegY # E2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0p6MDDnSlrzm2q2AS # 4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQakhCBj7A7CdfHmzJa # wv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0XLyTRSiDNipmKF+w # c86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960IHnWmZcy740hQ83eR # Gv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2FKZbS110YU0/EpF2 # 3r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBHX8mBUHOFECMhWWCK # ZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q27IwyCQLMbDwMVhEC # AwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGg34Ou2 # O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9P # MA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB3BggrBgEFBQcB # AQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggr # BgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwHAYDVR0gBBUwEzAH # BgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBADojRD2NCHbuj7w6 # mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6jfCbVN7w6XUhtldU/ # SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmImoqKwba9oUgYftzY # gBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtfJqGVWEjVGv7XJz/9 # kNF2ht0csGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrxoj7bQ7gzyE84FJKZ # 9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3LIU/Gs4m6Ri+kAew # Q3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx4b6cpwoG1iZnt5Lm # Tl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9Oj9FpsToFpFSi0HA # SIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+ICw2/O/TOHnuO77Xr # y7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug0wcCampAMEhLNKhR # ILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5Vzu0nAPthkX0tGFu # v2jiJmCG6sivqf6UHedjGzqGVnhOMIIGwjCCBKqgAwIBAgIQBUSv85SdCDmmv9s/ # X+VhFjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGln # aUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5 # NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIzMDcxNDAwMDAwMFoXDTM0MTAx # MzIzNTk1OVowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMzCCAiIwDQYJKoZIhvcN # AQEBBQADggIPADCCAgoCggIBAKNTRYcdg45brD5UsyPgz5/X5dLnXaEOCdwvSKOX # ejsqnGfcYhVYwamTEafNqrJq3RApih5iY2nTWJw1cb86l+uUUI8cIOrHmjsvlmbj # aedp/lvD1isgHMGXlLSlUIHyz8sHpjBoyoNC2vx/CSSUpIIa2mq62DvKXd4ZGIX7 # ReoNYWyd/nFexAaaPPDFLnkPG2ZS48jWPl/aQ9OE9dDH9kgtXkV1lnX+3RChG4PB # uOZSlbVH13gpOWvgeFmX40QrStWVzu8IF+qCZE3/I+PKhu60pCFkcOvV5aDaY7Mu # 6QXuqvYk9R28mxyyt1/f8O52fTGZZUdVnUokL6wrl76f5P17cz4y7lI0+9S769Sg # LDSb495uZBkHNwGRDxy1Uc2qTGaDiGhiu7xBG3gZbeTZD+BYQfvYsSzhUa+0rRUG # FOpiCBPTaR58ZE2dD9/O0V6MqqtQFcmzyrzXxDtoRKOlO0L9c33u3Qr/eTQQfqZc # ClhMAD6FaXXHg2TWdc2PEnZWpST618RrIbroHzSYLzrqawGw9/sqhux7UjipmAmh # cbJsca8+uG+W1eEQE/5hRwqM/vC2x9XH3mwk8L9CgsqgcT2ckpMEtGlwJw1Pt7U2 # 0clfCKRwo+wK8REuZODLIivK8SgTIUlRfgZm0zu++uuRONhRB8qUt+JQofM604qD # y0B7AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAW # BgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg # hkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0O # BBYEFKW27xPn783QZKHVVqllMaPe1eNJMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6 # Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEy # NTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUF # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6 # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZT # SEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAIEa1t6g # qbWYF7xwjU+KPGic2CX/yyzkzepdIpLsjCICqbjPgKjZ5+PF7SaCinEvGN1Ott5s # 1+FgnCvt7T1IjrhrunxdvcJhN2hJd6PrkKoS1yeF844ektrCQDifXcigLiV4JZ0q # BXqEKZi2V3mP2yZWK7Dzp703DNiYdk9WuVLCtp04qYHnbUFcjGnRuSvExnvPnPp4 # 4pMadqJpddNQ5EQSviANnqlE0PjlSXcIWiHFtM+YlRpUurm8wWkZus8W8oM3NG6w # QSbd3lqXTzON1I13fXVFoaVYJmoDRd7ZULVQjK9WvUzF4UbFKNOt50MAcN7MmJ4Z # iQPq1JE3701S88lgIcRWR+3aEUuMMsOI5ljitts++V+wQtaP4xeR0arAVeOGv6wn # LEHQmjNKqDbUuXKWfpd5OEhfysLcPTLfddY2Z1qJ+Panx+VPNTwAvb6cKmx5Adza # ROY63jg7B145WPR8czFVoIARyxQMfq68/qTreWWqaNYiyjvrmoI1VygWy2nyMpqy # 0tg6uLFGhmu6F/3Ed2wVbK6rr3M66ElGt9V/zLY4wNjsHPW2obhDLN9OTH0eaHDA # dwrUAuBcYLso/zjlUlrWrBciI0707NMX+1Br/wd3H3GXREHJuEbTbDJ8WC9nR2Xl # G3O2mflrLAZG70Ee8PBf4NvZrZCARK+AEEGKMIIHXzCCBUegAwIBAgIQB8JSdCgU # otar/iTqF+XdLjANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UE # ChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQg # Q29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMB4XDTIzMDQxNjAw # MDAwMFoXDTI2MDcwNjIzNTk1OVowZzELMAkGA1UEBhMCUEwxEjAQBgNVBAcMCU1p # a2/FgsOzdzEhMB8GA1UECgwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMSEwHwYD # VQQDDBhQcnplbXlzxYJhdyBLxYJ5cyBFVk9URUMwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCUmgeXMQtIaKaSkKvbAt8GFZJ1ywOH8SwxlTus4McyrWmV # OrRBVRQA8ApF9FaeobwmkZxvkxQTFLHKm+8knwomEUslca8CqSOI0YwELv5EwTVE # h0C/Daehvxo6tkmNPF9/SP1KC3c0l1vO+M7vdNVGKQIQrhxq7EG0iezBZOAiukNd # GVXRYOLn47V3qL5PwG/ou2alJ/vifIDad81qFb+QkUh02Jo24SMjWdKDytdrMXi0 # 235CN4RrW+8gjfRJ+fKKjgMImbuceCsi9Iv1a66bUc9anAemObT4mF5U/yQBgAuA # o3+jVB8wiUd87kUQO0zJCF8vq2YrVOz8OJmMX8ggIsEEUZ3CZKD0hVc3dm7cWSAw # 8/FNzGNPlAaIxzXX9qeD0EgaCLRkItA3t3eQW+IAXyS/9ZnnpFUoDvQGbK+Q4/bP # 0ib98XLfQpxVGRu0cCV0Ng77DIkRF+IyR1PcwVAq+OzVU3vKeo25v/rntiXCmCxi # W4oHYO28eSQ/eIAcnii+3uKDNZrI15P7VxDrkUIc6FtiSvOhwc3AzY+vEfivUkFK # RqwvSSr4fCrrkk7z2Qe72Zwlw2EDRVHyy0fUVGO9QMuh6E3RwnJL96ip0alcmhKA # BGoIqSW05nXdCUbkXmhPCTT5naQDuZ1UkAXbZPShKjbPwzdXP2b8I9nQ89VSgQID # AQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYD # VR0OBBYEFHrxaiVZuDJxxEk15bLoMuFI5233MA4GA1UdDwEB/wQEAwIHgDATBgNV # HSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3Js # My5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQw # OTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQu # Y29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAy # MUNBMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0 # cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGUBggrBgEFBQcBAQSBhzCBhDAkBggr # BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBo # dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2Rl # U2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqG # SIb3DQEBCwUAA4ICAQC3EeHXUPhpe31K2DL43Hfh6qkvBHyR1RlD9lVIklcRCR50 # ZHzoWs6EBlTFyohvkpclVCuRdQW33tS6vtKPOucpDDv4wsA+6zkJYI8fHouW6Tqa # 1W47YSrc5AOShIcJ9+NpNbKNGih3doSlcio2mUKCX5I/ZrzJBkQpJ0kYha/pUST2 # CbE3JroJf2vQWGUiI+J3LdiPNHmhO1l+zaQkSxv0cVDETMfQGZKKRVESZ6Fg61b0 # djvQSx510MdbxtKMjvS3ZtAytqnQHk1ipP+Rg+M5lFHrSkUlnpGa+f3nuQhxDb7N # 9E8hUVevxALTrFifg8zhslVRH5/Df/CxlMKXC7op30/AyQsOQxHW1uNx3tG1DMgi # zpwBasrxh6wa7iaA+Lp07q1I92eLhrYbtw3xC2vNIGdMdN7nd76yMIjdYnAn7r38 # wwtaJ3KYD0QTl77EB8u/5cCs3ShZdDdyg4K7NoJl8iEHrbqtooAHOMLiJpiL2i9Y # n8kQMB6/Q6RMO3IUPLuycB9o6DNiwQHf6Jt5oW7P09k5NxxBEmksxwNbmZvNQ65Z # n3exUAKqG+x31Egz5IZ4U/jPzRalElEIpS0rgrVg8R8pEOhd95mEzp5WERKFyXhe # 6nB6bSYHv8clLAV0iMku308rpfjMiQkqS3LLzfUJ5OHqtKKQNMLxz9z185UCszGC # BlMwggZPAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBS # U0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQB8JSdCgUotar/iTqF+XdLjANBglghkgB # ZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJ # AzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8G # CSqGSIb3DQEJBDEiBCCKFnPGiutAlxjA3mPReueM32/HtW+/GUjCvkw7fqC58jAN # BgkqhkiG9w0BAQEFAASCAgAyNLWM4rqIF/YgdpUBLVkLDgShYfC7527mD4thjjgt # KjJPTgG2iPJhpcL6GUmW7pxRwNyEqOyK3PG1koY1xkF/VjpzuuBhCEwWP/0KqHrb # DFYdsp8m/kYZD6WNtzK/PgqW/FLxzARiy5mJ9AxgwL1+vSDWzBzZJptSX9VEDTKy # G3bNdURiXE69m1IBV7aAuzxyfTHU/VH4GPlA61UVy7snLlQFxx7+hKy7exS+dNzK # 9YI4VsHCBhrh6yytPzSVkw8veESMtksXJNT7717Ms6nUb62snXkJdF6GUoaCUTtT # qdlP0W4m0Y8z2WV48ZvEgXK6iD1+BWANtFdxR+tr1+8GBzec/hvVgL+49BMF3S2u # Nt7Hj4+RjYVL9XUW+zVRDrnSgATJDiVFHJD00vJflSYK54DEHcr3CHmDADtRuTsz # oRv7VZslGjuKsBFpp5V351uTrgS3uTFyto1JILmSVUbzswCitqYNgNUftfxM9wp9 # lXt9RTfuioOikfBqqxt5oafPFOUxg5qUzwp0vJzuAYZajLM3HU2VR32IuaA1E53f # bXty+j83tkFuR344AUx7phpt9Eou/ZHEw2371fIZqpjcGQC8Fl66lzY52jAlFPCJ # kHweC7bmxW+OCTEY0HDvTT9StHxQpmfCNzL1f+owgJpLNsfivVfq95Kp4kNGffqY # jqGCAyAwggMcBgkqhkiG9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJBgNVBAYTAlVT # MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1 # c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAVEr/OUnQg5 # pr/bP1/lYRYwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN # AQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA0MDkyMDA1MjRaMC8GCSqGSIb3DQEJBDEi # BCArUPlekupJv59koMaiF4hdzFbiy2aUoOUN/SaSn44BbTANBgkqhkiG9w0BAQEF # AASCAgCe61u4AEZa+jXD71izaaLcG1L0OLGWrONJHfNvZm/GoRwAkw3lGh4zKjoU # Gs7zb7SYl4uPzuKLqvVV9SVCHuZljxYMl9ZGsrQLJO8CAmbn4hJrfGOJ/XUD/mLS # DoYGQLfxHXFQvaAFLBelefMDKoF0UjG1JWNeRfcDzbWJNZENto8egNV+s9yQjZla # be6YSg0oMNZDxRiT7UyR4Z5mlPF+UwYRLjL+SWf5c3SYUt1qeKSxNtBzN/7gAvWT # K9PD8WtFx+VzN+BslavIaxV0QFxS14gTn2Tt3bib9M6yAkXXLM7y1bA5oRH9c12K # m721BAwP4rP4ZX/I4fL0SGeUyMvBCCWzFjL2XR2hd40jn6Au1kKXC5/YdgtY5mgt # 0ovTBP/QWPoHzeen0fD9zZVsC3Dqwx0TWgce68y82jDlnOLDFHI/ZRKUx6WWHgvc # lBLocBZPy98rClf9s1XZPHvlXROs/12nlLn+ugUGjBnAbG9HUAl6ZYJfnXjPKmMT # fQtPyYek/TVIeKXv5oBf/7nDU7I1fs4x6F7Bsdw7vRv6mwJC7H/5dBvAVA+KCm8P # qC/9CN8vaySU15ysv0dqBprbyxxVz+poyaSV5t1CRmvI0AffVqL4nx2iwKlsMBb9 # rtByJ8p6jSH3n+50keUNQH/DBXrgpVvD8QpcznXUXIJILst67Q== # SIG # End signature block |