├── Configure Script.lnk ├── README.md ├── input └── configfilegoeshere.txt ├── output └── outputgoeshere.txt └── script.ps1 /Configure Script.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/psconfigui/5d1ee18248f6d1a75087d8a9965967813519f236/Configure Script.lnk -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # psconfigui 2 | PowerShell GUI for Script Configuration 3 | 4 | For an overview on using this code, please read this article: 5 | http://www.gngrninja.com/script-ninja/2016/12/23/powershell-configure-your-scripts-with-a-gui 6 | -------------------------------------------------------------------------------- /input/configfilegoeshere.txt: -------------------------------------------------------------------------------- 1 | Your config file will be stored in this directory! 2 | -------------------------------------------------------------------------------- /output/outputgoeshere.txt: -------------------------------------------------------------------------------- 1 | Script output will be placed in this directory 2 | -------------------------------------------------------------------------------- /script.ps1: -------------------------------------------------------------------------------- 1 | [cmdletbinding()] 2 | param( 3 | [Parameter( 4 | Mandatory = $false 5 | )] 6 | [Switch] 7 | $ConfigScript = $false, 8 | [Parameter( 9 | Mandatory = $false 10 | )] 11 | [ValidateSet('XML','JSON')] 12 | [String] 13 | $ImportAs = 'XML' 14 | ) 15 | 16 | #Setup paths 17 | $scriptPath = Split-Path -parent $MyInvocation.MyCommand.Definition 18 | $inputDir = "$scriptPath\Input" 19 | $outputDir = "$scriptPath\Output" 20 | 21 | #Set the correct file extension 22 | Switch ($ImportAs) { 23 | 24 | 'JSON' { 25 | 26 | $importExtension = '.json' 27 | 28 | } 29 | 30 | 'XML' { 31 | 32 | $importExtension = '.xml' 33 | 34 | } 35 | 36 | } 37 | 38 | #Set config file correctly 39 | $configFile = "$inputDir\config$($importExtension)" 40 | 41 | function Import-Config { #Begin function Import-Config 42 | [cmdletbinding()] 43 | param() 44 | 45 | Switch ($ImportAs) { 46 | 47 | 'JSON' { 48 | 49 | $script:configData = Get-Content -Path $configFile | ConvertFrom-Json 50 | 51 | } 52 | 53 | 'XML' { 54 | 55 | $script:configData = Import-Clixml -Path $configFile 56 | 57 | } 58 | 59 | } 60 | 61 | } #End function Import-Config 62 | 63 | function Export-Config { #Begin function Export-Config 64 | [cmdletbinding()] 65 | param( 66 | [Parameter( 67 | Mandatory 68 | )] 69 | [ValidateSet('JSON','XML')] 70 | $ExportAs, 71 | [Parameter( 72 | Mandatory 73 | )] 74 | $ConfigurationOptions 75 | ) 76 | 77 | #If there's a file, we're gonna back it up! 78 | if (Test-Path -Path $configFile) { 79 | 80 | $backup = $true 81 | 82 | } 83 | 84 | Switch ($ExportAs) { #Begin config type switch 85 | 86 | 'JSON' { 87 | 88 | if ($backup) { 89 | 90 | Get-Content $configFile | Out-File -FilePath $configFile.Replace('.json','.json.bak') 91 | 92 | Write-Verbose "Backed up existing configuration to $($configFile.Replace('.json','.json.bak'))!" 93 | Write-Verbose "" 94 | 95 | } 96 | 97 | $ConfigurationOptions | ConvertTo-Json | Out-File -FilePath $configFile 98 | 99 | } 100 | 101 | 'XML' { 102 | 103 | if ($backup) { 104 | 105 | Get-Content $configFile | Out-File -FilePath $configFile.Replace('.xml','.xml.bak') 106 | 107 | Write-Verbose "Backed up existing configuration to $($configFile.Replace('.xml','.xml.bak'))!" 108 | Write-Verbose "" 109 | 110 | } 111 | 112 | $ConfigurationOptions | Export-Clixml -Path $configFile 113 | 114 | } 115 | 116 | } #End config type switch 117 | 118 | } #End function Export-Config 119 | 120 | function Invoke-UserAction { #Begin function Invoke-UserAction 121 | [cmdletbinding()] 122 | param( 123 | [Parameter( 124 | Mandatory, 125 | ValueFromPipeline 126 | )] 127 | $usersToProcess 128 | ) 129 | 130 | Begin { #Begin begin block for Invoke-UserAction 131 | 132 | #Create array to store results in 133 | [System.Collections.ArrayList]$processedArray = @() 134 | 135 | Write-Verbose "User processing started!" 136 | Write-Verbose "" 137 | 138 | } #End begin block for Invoke-UserAction 139 | 140 | Process { #Begin process block for function Invoke-UserAction 141 | 142 | foreach ($user in $usersToProcess) { #Begin user foreach loop 143 | 144 | #Set variables to null so they are not set by the last iteration 145 | $lastLogonDays = $null 146 | $userAction = $null 147 | 148 | $notes = 'N/A' 149 | 150 | #Some error handling for getting the last logon days 151 | Try { 152 | 153 | #Set value based on calculation using the LastLogon value of the user 154 | $lastLogonDays = ((Get-Date) - $user.LastLogon).Days 155 | 156 | } 157 | 158 | Catch { 159 | 160 | #Capture message into variable $errorMessage, and set other variables accordingly 161 | $errorMessage = $_.Exception.Message 162 | $lastLogonDays = $null 163 | $notes = $errorMessage 164 | 165 | Write-Warning "Issue encountered while calculating last logon days [$errorMessage]" 166 | Write-Warning "" 167 | 168 | } 169 | 170 | Write-Verbose "Checking on [$($user.DisplayName)], who last logged on [$lastLogonDays] days ago..." 171 | Write-Verbose "" 172 | 173 | #Switch statement to switch out the value of $lastLogonDays 174 | Switch ($lastLogonDays) { #Begin action switch 175 | 176 | #This expression compares the value of $lastLogondays to the script scoped variable for warning days, set with the configuration data file 177 | {$_ -lt $script:configData.DisableDays -and $_ -ge $script:configData.WarnDays} { #Begin actions for warning 178 | 179 | $userAction = 'Warn' 180 | 181 | Write-Verbose "Warning, [$($user.DisplayName)] will be disabled in [$($script:configData.DisableDays - $lastLogonDays)] days!" 182 | Write-Verbose "" 183 | 184 | Break 185 | 186 | } #End actions for warning 187 | 188 | #This expression compares the value of $lastLogondays to the script scoped variable for disable days, set with the configuration data file 189 | {$_ -ge $script:configData.DisableDays} { #Begin actions for disable 190 | 191 | $userAction = 'Disable' 192 | 193 | Write-Verbose "[$($user.DisplayName)] is going to be disabled, and is [$($lastLogonDays - $script:ConfigData.DisableDays)] days past the threshold!" 194 | Write-Verbose "" 195 | 196 | Break 197 | 198 | } #End actions for disable 199 | 200 | {$_ -eq $null} { #Begin actions for a null value 201 | 202 | $userAction = 'Error' 203 | 204 | Write-Verbose "Something went wrong, no value specified for last logon days!" 205 | Write-Verbose "" 206 | 207 | Break 208 | 209 | } #End actions for a null value 210 | 211 | #Adding a default to catch other values 212 | default { #Begin default actions 213 | 214 | $userAction = 'None' 215 | Write-Verbose "$($user.DisplayName) is good to go, they last logged on [$($lastLogonDays)] days ago!" 216 | Write-Verbose "" 217 | 218 | } #Begin default actions 219 | 220 | } #End action switch 221 | 222 | #Create object to store in array 223 | $processedObject = [PSCustomObject]@{ 224 | 225 | DisplayName = $user.DisplayName 226 | UserName = $user.UserName 227 | OU = $user.OU 228 | LastLogon = $user.LastLogon 229 | LastLogonDays = $lastLogonDays 230 | Action = $userAction 231 | Notes = $notes 232 | 233 | } 234 | 235 | #Add object to array of processed users 236 | $processedArray.Add($processedObject) | Out-Null 237 | 238 | } #End user foreach loop 239 | 240 | } #End process block for function Invoke-UserAction 241 | 242 | End { #Begin end block for Invoke-UserAction 243 | 244 | Write-Verbose "User processing ended!" 245 | Write-Verbose "" 246 | 247 | #Return array 248 | Return $processedArray 249 | 250 | } #End end block for Invoke-UserAction 251 | 252 | } #End function Invoke-UserAction 253 | 254 | function Invoke-ConfigurationGeneration { #Begin function Invoke-ConfigurationGeneration 255 | [cmdletbinding()] 256 | param( 257 | [Parameter( 258 | Mandatory = $false 259 | )] 260 | [ValidateSet('XML','JSON')] 261 | [String] 262 | $ExportAs = $ImportAs, 263 | [Parameter( 264 | Mandatory = $false 265 | )] 266 | $ConfigurationOptions 267 | ) 268 | 269 | if (!$configurationOptions) { #Actions if we don't pass in any options to the function 270 | 271 | #The OU list will be an array 272 | [System.Collections.ArrayList]$ouList = @() 273 | 274 | #These variables will be used to evaluate last logon dates of users 275 | [int]$warnDays = 23 276 | [int]$disableDays = 30 277 | 278 | #Add some fake OUs for testing purposes 279 | $ouList.Add('OU=Marketing,DC=FakeDomain,DC=COM') | Out-Null 280 | $ouList.Add('OU=Sales,DC=FakeDomain,DC=COM') | Out-Null 281 | 282 | #Create a custom object to store things in 283 | $configurationOptions = [PSCustomObject]@{ 284 | 285 | WarnDays = $warnDays 286 | DisableDays = $disableDays 287 | OUList = $ouList 288 | 289 | } 290 | 291 | #Handle different types 292 | #Export the object we created as the current configuration 293 | Export-Config -configurationOptions $ConfigurationOptions -ExportAs $ExportAs 294 | 295 | Write-Verbose "Exporting generated configuration file to [$configFile]!" 296 | 297 | } else { #End actions for no options passed in, begin actions for if they are 298 | 299 | Export-Config -configurationOptions $ConfigurationOptions -ExportAs $ExportAs 300 | 301 | Write-Verbose "Exporting passed in options as configuration file to [$configFile]!" 302 | 303 | } #End if for options passed into function 304 | 305 | } #End function Invoke-ConfigurationGeneration 306 | 307 | function Invoke-UserDiscovery { #Begin function Invoke-UserDiscovery 308 | [cmdletbinding()] 309 | param() 310 | 311 | #Create empty arrayList object 312 | [System.Collections.ArrayList]$userList = @() 313 | 314 | #Create users and add them to array 315 | $testUser2 = [PSCustomObject]@{ 316 | 317 | DisplayName = 'Mike Jones' 318 | UserName = 'jonesm' 319 | LastLogon = (Get-Date).AddDays(-35) 320 | OU = Get-Random -inputObject $script:configData.OUList 321 | 322 | } 323 | 324 | $testUser1 = [PSCustomObject]@{ 325 | 326 | DisplayName = 'John Doe' 327 | UserName = 'doej' 328 | LastLogon = (Get-Date).AddDays(-24) 329 | OU = Get-Random -inputObject $script:configData.OUList 330 | 331 | } 332 | 333 | $testUser3 = [PSCustomObject]@{ 334 | 335 | DisplayName = 'Jim Doe' 336 | UserName = 'doeji' 337 | LastLogon = (Get-Date).AddDays(-10) 338 | OU = Get-Random -inputObject $script:configData.OUList 339 | 340 | } 341 | 342 | 343 | $testUser4 = [PSCustomObject]@{ 344 | 345 | DisplayName = 'This WontWork' 346 | UserName = 'wontworkt' 347 | LastLogon = $null 348 | OU = Get-Random -inputObject $script:configData.OUList 349 | 350 | } 351 | 352 | $testUser5 = [PSCustomObject]@{ 353 | 354 | DisplayName = 'This AlsoWontWork' 355 | UserName = 'alsowontworkt' 356 | LastLogon = 'this many!' 357 | OU = Get-Random -inputObject $script:configData.OUList 358 | 359 | } 360 | 361 | $testUser6 = [PSCustomObject]@{ 362 | 363 | DisplayName = 'Sally Smith' 364 | UserName = 'smiths' 365 | LastLogon = (Get-Date).AddDays(-30) 366 | OU = Get-Random -inputObject $script:configData.OUList 367 | 368 | } 369 | 370 | #Add users to arraylist 371 | $userList.Add($testUser1) | Out-Null 372 | $userList.Add($testUser2) | Out-Null 373 | $userList.Add($testUser3) | Out-Null 374 | $userList.Add($testUser4) | Out-Null 375 | $userList.Add($testUser5) | Out-Null 376 | $userList.Add($testUser6) | Out-Null 377 | 378 | #Return list 379 | Return $userList 380 | 381 | } #End function Invoke-UserDiscovery 382 | 383 | function Invoke-GUI { #Begin function Invoke-GUI 384 | [cmdletbinding()] 385 | Param() 386 | 387 | #We technically don't need these, but they may come in handy later if you want to pop up message boxes, etc 388 | [void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 389 | [void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework') 390 | 391 | #Input XAML here 392 | $inputXML = @" 393 | 403 | 404 |