Jump to content

HPlum78

Members
  • Posts

    1,530
  • Joined

  • Last visited

Everything posted by HPlum78

  1. Yeah I bet.... Thought that someone would say that I had over done it! Question I am asking myself is have I? (do the functions make sense, or have I scared everyone off it because of all the code) What I do is have those functions in a separate module and then call them from my other scripts. What is not there is another few functions that I use for searching the log location on the script sever. As already noted the functions set out a framework for logging means that all my scripts log in the same format accross the board.
  2. Just noticed that i have mangled the log file in my attempts to anonymise the data but its there to show the format of the logging rather than anything else. If anyone needs more info on what those functions do that i have added feel free to ask but they are essentially the framework to enable logging of what you are doing in a PS script one of the functions sets out the formatting with the pipes and the likes in the log file. Hope they help. H.
  3. Script: UPN change # Author: CaptainQwerty # Date Created: 28/07/2019 #Script updated by: Hplum78 #Date updated: 29/07/2019 #Added functions for Script logging and error handling, Script will now create a log file in the following location C:\PowerShell\Logs\ Folder #Depending on how this is run (in the ISE/ as a PS script) the log will take the form of or will be #Added -whatif to the SET-ADUser command (Remove this after you have tested the script) #requires -module ActiveDirectory #requires -RunAsAdministrator # Change the two variables, the top one is your domain and the second one is the OU that contains the users - removed the requirement for changing the domain var if this script is running on the domain that you are working in (HPlum78. <# .DESCRIPTION This function returns the filename with no extension of the current script .PARAMETER StackDepth the stackdepth the retrieve #> function Get-ScriptFilenameNoExtension { [CmdletBinding()] Param ( [Parameter(Position=0,Mandatory=$false)] [string]$StackDepth = 1 ) return [io.path]::GetFileNameWithoutExtension( $((Get-PSCallStack)[$StackDepth].ScriptName)) } <# .DESCRIPTION Setup global variable with full file path and filename of log file .PARAMETER None #> function Get-DefaultLogLocation { $LogRootPath = 'C:\PowerShell\Logs\' $scriptname = Get-ScriptFilenameNoExtension -stackdepth 3 return "$($LogRootPath)$scriptname\" + "$scriptname`_$(get-date -Format "yyyyMMdd_HHmmss").log" } <# .DESCRIPTION This function check to see if the object passed in is either null, empty or whitespace .PARAMETER o The object for the test to be carried out on #> Function Get-IsNotNullEmptyOrSpace { [CmdletBinding()] Param ( [Parameter(Position=0,Mandatory=$false)]$o ) $return = $false try { IF([string]::IsNullOrWhiteSpace($o)) { Write-verbose "Given object is NULL/empty/whitespace" } else { Write-verbose "Given object has a value" $return = $true } } catch { Write-verbose "Error: Given object is NULL/empty/whitespace" } return $return } <# .DESCRIPTION This function pads a string with chars .PARAMETER Str The string to be padded .PARAMETER PadChar The padding char .PARAMETER MaxLength The length of the string for the padding to add to .PARAMETER PadLeft If true, the padding will appear at the begining of the string otherwise by default it will appear at the end of the string #> function Set-PaddingToString { Param ( [Parameter(Position=0,Mandatory=$true)] [string]$Str, [Parameter(Position=1,Mandatory=$false)] [char]$PadChar = " ", [Parameter(Position=2,Mandatory=$false)] [int]$MaxLength = 7, [Parameter(Position=3,Mandatory=$false)] [bool]$PadLeft = $false ) try { if (!($PadLeft)) { $return = $Str.PadRight($MaxLength,$PadChar) } else { $return = $Str.PadLeft($MaxLength,$PadChar) } } catch { $return = $Str } return $return } <# .DESCRIPTION Enabled file based logging output from script .PARAMETER None #> function Set-FileLogging { $LogRootPath = 'C:\PowerShell\Logs\' if (Test-Path $LogRootPath){ $logfullpath = split-path (Get-DefaultLogLocation) Log-WriteDebug "Log root path exists need to check subfolder: $logfullpath exists" if (!(Test-Path ($logfullpath))) { Write-LogDebug "Need to create logging folder: $logfullpath" mkdir $logfullpath } $global:logfile = Get-DefaultLogLocation Log-WriteDebug "Setup global variable for logging path toer: $logfile exists" } else { Log-WriteWarn "Default root log folder does not exist" } } <# .DESCRIPTION Breakdown and output attributes of the error .PARAMETER ErrorRecord Error object to resolve #> function Resolve-Error { [CmdletBinding()] param( $ErrorRecord = ($error[0]) ) Write-verbose "Error Occurred. formatting..." $spacer = "-"*80 Set-StrictMode -Off #$output = "`n`r" | out-string $output += "Error details:" | out-string $output += $errorRecord | Format-List * -Force | out-string $output += $spacer | out-string $output += "InvocationInfo :" | out-string $output += $errorRecord.InvocationInfo | Format-List * | out-string $output += $spacer | out-string $output += "TargetObject :" | out-string $output += $errorRecord.TargetObject | Format-List * | out-string $output += $spacer | out-string $output += "Exception :" | out-string $output += $exception = $errorRecord.Exception | out-string for ($i = 0; $exception; $i++, ($exception = $exception.InnerException)) { $output += "Inner Exception $i :" | out-string $output += $exception | Format-List * -Force | out-string } return $output } <# .DESCRIPTION This function outputs message to console and/or output file (if set) .PARAMETER Message The message to write in the log file .PARAMETER ForColour name of a Colour to be used for in the forColour attribute .PARAMETER LogType the log type "INFO" #> Function Log-Write { [CmdletBinding()] Param ( [Parameter(Position=0,Mandatory=$false)] [string]$Message, [Parameter(Position=1,Mandatory=$false)] [string]$ForColour = "", [Parameter(Position=2,Mandatory=$false)] [string]$LogType = "INFO" ) if (Get-IsNotNullEmptyOrSpace $logFile) { $timeStamp = (get-date).ToString() #get the date and time on the system now $logentry = (Set-PaddingToString $LogType) + " | " + $timeStamp + " | " + $Message $logentry | out-file -filepath $logFile -Append } if( $ForColour -eq "") { Write-Host "$LogType | $Message" } else { Write-Host "$LogType | $Message" -foregroundcolor $ForColour } } <# .DESCRIPTION Display and/or log to file of error message in appropriate Colour .PARAMETER Message message to be displayed/logged .PARAMETER ErrorRecord Describes a terminating or nonterminating error that occurred during the processing of a command #> function Log-WriteError { [CmdletBinding()] Param ( [Parameter(Position=0,Mandatory=$false)] [string]$Message, [Parameter(Position=1,Mandatory=$false)] [system.Management.Automation.ErrorRecord]$ErrorRecord=$null ) if ($Message -ne $null -and $ErrorRecord -eq $null) { Log-Write -forColour "red" -logtype "ERROR" -message $Message } if ($ErrorRecord -ne $null) { Log-WriteError -forColour "red" -logtype "ERROR" -message ("$Message | Error Details:`n`r$(Resolve-Error($ErrorRecord))" ) } } <# .DESCRIPTION Display and/or log to file a warning message in appropriate Colour .PARAMETER Message Message to be displayed/logged #> function Log-WriteWarn { [CmdletBinding()] Param ( [Parameter(Position=0,Mandatory=$true)] [string]$Message ) Log-Write -forColour "darkyellow" -logtype "WARN" -message "$Message" } <# .DESCRIPTION Display and/or log to file of info message in appropriate Colour .PARAMETER Message Message to be displayed/logged #> function Log-WriteInfo { [CmdletBinding()] Param ( [Parameter(Position=0,Mandatory=$true)][string]$Message ) Log-Write -message $Message -logtype "INFO" } <# .DESCRIPTION Display and/or log to file of debug message in appropriate Colour .PARAMETER Message debug message to be displayed/logged #> function Log-WriteDebug { [CmdletBinding()] Param ( [Parameter(Position=0,Mandatory=$true)] [string]$Message ) if ($debug -eq 1) { Log-Write -message $Message -logtype "DEBUG" } } Set-FileLogging $domain = $env:USERDNSDOMAIN Log-WriteInfo "Working Doamin is $($Domain)" #$ou = "OU=Staff,DC=Example,DC=co,DC=uk" Log-WriteInfo "Working OU is $($ou)" Log-WriteInfo "Importing ActiveDirectory" Try{ Import-Module ActiveDirectory Log-WriteInfo "ActiveDirectory Module imported sucessfuly" } Catch{ Log-WriteError "Failed to Import ActiveDirectory Module - Terminating Script" } # Getting all users from the OU Try{ Log-WriteInfo "Getting Users info from $($ou)" $users = Get-ADUser -filter * -SearchBase $ou } Catch{ Log-WriteError "Failed to get Users from $($ou)" } # For each user in the OU change their UPN foreach($user in $users){ Try{ # Generating the UPN Log-WriteInfo "Gernerating UPN for User $(($user).name)" $firstname = $user.GivenName $firstInitial = $firstname.substring(0,1) $upn = "$firstInitial.$($user.surname)@$domain" Log-WriteInfo "New UPN for $(($user).name) is $($upn)" # Setting the users UPN Log-WriteInfo "Setting UPN for User $(($user).name)" set-aduser $user -UserPrincipalName $upn -whatif #Remove -whatif to arm this script } Catch{ Log-WriteError "Failed to set UPN for $(($user).name)" } } The Error logging can been seen in the attached file. Feel free to grab the error handling functions from the above to use in your own scripts. Harry _20190729_085817.txt
  4. Hay @QwertyMash I was not calling you there was just adding my suggestions based on your saying it had been thrown together.
  5. I would put a try catch on the set is my only thought on a quick pass on the script above. And some logging, by that i dont mean write-host... :-P
  6. Yeah you should be good, just worth checking that the FRS service is stopped and set to disabled on your DCs now.
  7. Repadmin /SyncAll /AeD run that on the DC's that do not hold the PDC emulator.
  8. Ah OK that explains why it's allowed you to use FRS missed that you where doing it as an in place.
  9. Yeah I can be available tomorrow, I think @snagrat is right mind it a requirement of sever 2019 to use DFSR for the domain shares.... (I will stand to be Corrected though) Did you get the graphical AD Rep tool installed?
  10. If needs be I will take a look at this with you will send you my number if we decide that would be any use.
  11. Download the graphical replication tool it's in the docs run it and let's go from there. In fact here:- https://www.microsoft.com/en-gb/download/details.aspx?id=30005
  12. Don't panic it's still serving the sysvol and netlogon via FRS
  13. Yeah I would get in to a position where FRS and DFS are running in parallel if their are no replication errors.
  14. If they are replicating then the ACL's are also replicating demoting DC's is not going to fix the issue and may well introduce some others!
  15. Yeah stright forward don't panic overly. All the usual apply like backups and that mind just because it's straightforward we don't know your setup and all that
  16. We could even solve that issue fairly quickly with PS an all
  17. I script so I can argue that I could script the whole solution quicker than you clicking :-p - - - Updated - - - In fact i probably have a basic version that could be used...
  18. No PowerShell is the way forward with this, how do you manage when MS gives kazala to all your users? Please tell me that you are not sitting in front of the portal managing licences for anything more than 10 users (even then I would script) Sorry I know that might not be the answer you looking for but it's the best I have. Scripting means that you could do stuff like have AD/ AAD groups for licensed apps and users added to the group will get the app added/ removed based on group membership.
  19. The thing is with the Azure SSPR solution is that it has no client for resets at the login screen. If you are all Windows 10 and those devices are AAD joined then you can reset from there. Also it's only free unless it's not... If its a hybrid setup then it's not free. My one line answer made a lot of assumptions.
  20. MIM has the ability to do this...
  21. So a few pointers that I think may help here, and based on my own experience setting up and using Teams. Set out your service and life cycle policy's for your Teams service. You should include things like a Team needs to meet a certain naming convention, it must have a primary and secondary owner at all times, the data that is allowed to be stored and the deletion policy. Make sure that you outline what happens to any data stored within a team at the end of its life cycle. And above all be sure to not use it as a definitive document library. Do not mandate what can be a team as teams are organic and its not down to you as an IT department to mandate its use or how it is used. By that I mean what you are going to classify as a Team on behalf of your organisation. Your users should be able to make a Team for finance as well as make a Team for a project that the finance team are working on. (Don't limit Teams to your organisational structure, is what i am saying here) After all that is defined you can then script the creation of teams we let users do this via our help desk and use Flow to pull the details from the request. We then have scripts that manage the life cycle checking for the number of owners and after a period of time mailing the owners and asking if the team is still required and the likes. The creation scripts also check if they meet the naming convention and don't have any banned words in them so on... Also a note to the op MS have what seems to be an ever growing product portfolio and those do overlap some of this is due to acquisitions but they are also trying to give everyone a broad range of tools for a connected work place. It down to you to decide what best fits your organizational needs.
  22. To start with @jmak any command with a -Filter * -properties * is a really bad idea, so much so I will let you look through my previous posts on running commands like that... The best of it is you are doing a select to return the properties you want so put that after the -Properties part of the statement. The next thing to note is that LastLogon is not a replicated attribute (or better said, not to do what you are looking for), so you would need to return this from all the DC's in your domain potentially (could be site but I don't know your setup..) https://blogs.technet.microsoft.com/askds/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works/ Added the above for some additional info, i will fish out some more on this when I have more time.
  23. @mhaddock good luck with your hybrid setup, all of these solutions need to be have a unique take on them to make work for you. Hope it works out. H.
  24. It's a fully supported route by Microsoft these days of building new, the days of migrating have gone (I used to be against in place) more pressing question is why 16 over 19?
×
×
  • Create New...