Showing posts with label administrators. Show all posts
Showing posts with label administrators. Show all posts

Friday, 1 February 2019

Update Job Title and Department in Active Directory with Powershell

 

 

Here is a short powershell script to update job title and department in Active Directory, though this could be used to update any of the AD fields.  Obviously you will need to create a CSV file beforehand which is populated with the required information.  When the CSV is imported, no headers are specified in the script so ensure these are in the first row file already.  As a minimum here I needed SAMAccountName, Title and Department.

 

The script will first check to see if the user in the file actually exists (I am working in an environment with multiple domains and forests and I didn’t want the script to produce lots of ugly errors if the user weren’t found).  This is done with try and catch.  If you are adapting this script for a different use you will need to make sure you catch the correct error.  The way I got the correct error text was to run the command that produces the error and then run:

 

$Error[0].Exception.GetType().FullName

 

 

I then used ‘catch’ to pick up the accounts that didn’t exist (ie that errored) and set a variable to skip the next command, which is done by the ‘if’ statement.  At the end of that particular row in the ‘foreach’ loop, I set $Nextaction back to $null ready for the next check and so on…

 

 

 

$LogFilePath = $env:LOCALAPPDATA + "\Cloudwyse\Logs\update_job_titles_" + $(get-date -Format ddMMyy_HHmmss) + ".log"

Start-Transcript -Path $LogFilePath -NoClobber

$NewPass = cat C:\cloudwyse\secureinfo.txt | convertto-securestring

$NewCred = new-object -typename System.Management.Automation.PSCredential -argumentlist "contoso\username",$NewPass

$NewEnvDC = "server01.contoso.com"

$JobStart = Get-Date

$Totalprocessed = $null

$Totalupdated = $null

$Userlistpath = "C:\cloudwyse\jobtitles.csv"

$Userlist = Import-csv $Userlistpath

$NewSession = New-PSSession -ComputerName $NewEnvDC -Credential $NewCred

Invoke-Command $NewSession -Scriptblock {Import-Module ActiveDirectory}

Import-PSSession $NewSession -Module ActiveDirectory

 

foreach ($User in $Userlist) {

       Try    {

             Get-ADuser $User.SAMAccountName -ErrorAction Stop | out-null

             }

       Catch [System.Management.Automation.RemoteException]        {

             Write-Host -ForegroundColor Cyan "The user" $User.SAMAccountName "was not found... skipping to next record..."

             $NextAction = "skip"

             }

       Finally {

             if ($NextAction -ne "skip") {

             Set-ADUser $User.SAMAccountName -Department $User.Department -Title $User.Title

             Write-Host -ForegroundColor Magenta "The title for" $User.SAMAccountName "was set to" $User.Title "and the department was set to" $User.Department

             $totalupdated = $totalupdated +1

             $NextAction = $null

             } else {

             $NextAction = $null

             }

             }

       $totalprocessed = $totalprocessed +1

       }                                                                 

$JobEnd = Get-Date

$JobSecondsTaken = ($JobEnd - $JobStart)

Write-Host -ForegroundColor Yellow "Processed $totalprocessed record(s) in" $JobSecondsTaken.Minutes "minute(s) and" $JobSecondsTaken.Seconds "second(s)."

Write-Host -ForegroundColor Yellow "Updated $totalupdated record(s)"

Remove-PSSession $NewSession

Stop-Transcript

 

 

Thanks and feel free to recycle/reuse.

 

 

 

Wednesday, 19 December 2018

Windows 10 NLA Public vs Private profiles - what's the difference?

In a recent post I described how I used Powershell to configure a dual-homed Radius server where I wanted to firewall everything on the DMZ interface but not affect the production interface.  I did this using a Windows feature known as NLA – Network Location Awareness – which has been around in one form or another since Windows XP, although many people still know very little about it.
NLA in Windows 10 uses 3 different network profiles: Domain, Public and Private.  Windows assigns the network connection to one of these profiles when a new network is discovered.  It’s important to know the differences because this actually provides us with a really powerful tool to lock down our machines using the built in Windows Firewall.

How the appropriate location is determined

Domain

Microsoft explain that Windows checks the connection specific DNS name against “HKEY_Local_Machine\Software\Microsoft\Windows\CurrentVersion\Group Policy\History\NetworkName” (although on my test machine this was an empty key but “HKEY_Local_Machine\Software\Microsoft\Windows\CurrentVersion\Group Policy\History\MachineDomain” contained the domain DNS name).  If this matches and the machine is able to go on and contact a Domain Controller via LDAP, then you are assigned the Domain profile.

Public vs Private

This is the bit most people get confused about and it is a distinction which appeared from Windows Vista onwards (in XP the profiles were Domain and Standard).  The way that the location is determined is via the prompt that you receive when connecting to a new network ie “Do you want to allow your PC to be discoverable by other PCs and devices on this network?”.  Selecting “Yes” assigns the Private profile whilst “No” assigns the Public profile.

It’s useful to know of this distinction as it will allow you to configure specific rules on the firewall which will behave differently depending on whether you are connected to a trusted or untrusted network.

Wednesday, 12 December 2018

Connect to O365 exchange with powershell using session import

 

It seems fairly obvious but a lot of people are unsure how to import a remote powershell session to O365. Simply do the following:

 

 

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection

Import-PSSession $Session

 

 

 

Friday, 30 November 2018

Disable inbound advanced firewall rules on public interface only with Powershell for a Windows Radius/NPS server

 

 

Recently I built an NPS server for Radius authentication, and had to dual home it with one NIC in the DMZ and one on the production network.  I wanted to firewall everything on the DMZ interface but not affect the production interface.  That way I could then allow the traffic I wanted to enable on the DMZ interface port by port.  Assuming windows has correctly detected the profile on the two interfaces as “Domain” and “Public”, which it should based on the resources visible on each network, you can run the following script to disable traffic just on the public interface.

 

 

 

$LogFilePath = $env:LOCALAPPDATA + "\Cloudwyse\Logs\adv_firewall" + $(get-date -Format ddMMyy_HHmmss) + ".log"

Start-Transcript -Path $LogFilePath -NoClobber

 

$rules = Get-NetFirewallRule

$total = 0

foreach ($rule in $rules) {

if (($rule.Profile -like "any" -or $rule.Profile -match "public") -and $rule.enabled -like "True" -and $rule.direction -like "Inbound") {

if ($rule.Profile -like "any") {

  Set-NetFirewallRule -Name $rule.Name -Profile "Domain, Private"

  write-host "Setting" $rule.DisplayName "Domain, Private" }

elseif ($rule.Profile -match "Domain" -and $rule.Profile -match "private" -and  $rule.Profile -match "public" ) {

  Set-NetFirewallRule -Name $rule.Name -Profile "Domain, Private"

  write-host "Setting" $rule.DisplayName "Domain, Private" }

elseif ($rule.Profile -match "Domain" -and  $rule.Profile -match "public" ) {

  Set-NetFirewallRule -Name $rule.Name -Profile "Domain"

  write-host "Setting" $rule.DisplayName "Domain" }

elseif ($rule.Profile -match "Private" -and  $rule.Profile -match "public" ) {

  Set-NetFirewallRule -Name $rule.Name -Profile "Private"

  write-host "Setting" $rule.DisplayName "Private" }

elseif ($rule.Profile -like "public" ) {

  Disable-NetFirewallRule -Name $rule.Name

  write-host "Disabling" $rule.DisplayName }

else {write-host -ForegroundColor Red "Error - check logs"}

$total = $total +1  }}

write-host -ForegroundColor Yellow "$total rules processed"

 

stop-transcript

 

 

 

 

Thursday, 27 September 2018

Powershell script in SCCM task sequence to name device based on asset/service tag no.

 

 

This script is used within the SCCM task sequence and performs two functions.  Firstly it determines whether or not the machine is a Hyper-V VM, and if it is, it assigns a task sequence variable called “PSisVM”.  This is useful to hold in the TS as there are certain things that only need to be done on laptops and not VMs (such as Bitlocker, TPM etc).

 

Secondly, it assigns the "OSDComputerName" TS variable which SCCM will use to name the machine.  It does this by taking the dell service tag number, along with a sitecode and applying a ‘D’ for desktops or ‘L’ for laptops at the end.  It also has a failsafe in there if no serial number is picked up, so that the TS will succeed and the machine will get a unique name.

 

There is also extensive logging throughout to help with troubleshooting if the TS fails.

 

 

# Functions

BEGIN

{

  try {

    $TSEnv = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop

  }

  catch [System.Exception] {

    Write-Warning -Message "Unable to construct Microsoft.SMS.TSEnvironment object"; break

  }

}

PROCESS {

# Set Logs Directory

  $LogsDirectory = Join-Path -Path $TSEnv.Value("_SMSTSLogPath") -ChildPath ""

 

function Write-TSLogEntry {

    param (

      [parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")]

      [ValidateNotNullOrEmpty()]

      [string]$Value,

      [parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")]

      [ValidateNotNullOrEmpty()]

      [ValidateSet("1", "2", "3")]

      [string]$Severity,

      [parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")]

      [ValidateNotNullOrEmpty()]

      [string]$FileName = "OSDCompName.log"

    )

 

# Determine log file location

$LogFilePath = Join-Path -Path $LogsDirectory -ChildPath $FileName

 

# Construct time stamp for log entry

$Time = -join @((Get-Date -Format "HH:mm:ss.fff"), "+", (Get-WmiObject -Class Win32_TimeZone | Select-Object -ExpandProperty Bias))

   

# Construct date for log entry

$Date = (Get-Date -Format "MM-dd-yyyy")

   

# Construct context for log entry

$Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)

   

# Construct final log entry

$LogText = "<![LOG[$($Value)]LOG]!><time=""$($Time)"" date=""$($Date)"" component=""OSDCompName"" context=""$($Context)"" type=""$($Severity)"" thread=""$($PID)"" file="""">"

   

# Add value to log file

try {

     Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop

    }

    catch [System.Exception] {

     Write-Warning -Message "Unable to append log entry to OSDCompName.log file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)"

    }

}

 

# check whether the device is a laptop - this affects the naming

Write-TSLogEntry -Value "Checking for the presence of a battery in this device" -Severity 1

$BatteryExists = (Get-WmiObject -Class Win32_Battery | Select-Object BatteryStatus).BatteryStatus

Write-TSLogEntry -Value "Battery status is returned as $BatteryExists on host system" -Severity 1

 

# gather the service tag of the device which will form part of the name

Write-TSLogEntry -Value "Checking for the serial number of this device" -Severity 1

$ServiceTag = (Get-WmiObject -Class Win32_BIOS | Select-Object SerialNumber).SerialNumber

Write-TSLogEntry -Value "Serial number of this device is reported as $ServiceTag" -Severity 1

 

# if the service tag or serial number is blank, generate a random name so that the build can continue

if (!$ServiceTag) { $Namestring = ("ERR" + (Get-Random -Minimum 1000 -Maximum 9999))

       Write-TSLogEntry -Value "The serial number of this device was blank, using $Namestring instead" -Severity 2

       } ElseIf ($ServiceTag.length -gt 10) { $NameString = ($ServiceTag.substring(0, 10))

       Write-TSLogEntry -Value "Serial number of this device was $ServiceTag which was too long and was truncated to $NameString" -Severity 1

       } Else {

       $Namestring = $ServiceTag

       Write-TSLogEntry -Value "The serial number of this device is $Namestring" -Severity 1

       }

 

# determine whether device is a vm - we will handle naming these differently do to some issues with hyper-v

Write-TSLogEntry -Value "Checking if this is a virtual machine" -Severity 1

$sysMan = (Get-wmiobject -query "Select Manufacturer from Win32_SystemEnclosure") | select-object -expand Manufacturer

Write-TSLogEntry -Value "Query returned $sysMan" -Severity 1

 

if ($sysMan -like "*Microsoft*") {

       $PSisVM = "True"

       } Else {

       $PSisVM = "False"

       }

 

# check if the device is a laptop or desktop for naming purposes

if ($BatteryExists -gt 0) {

    $OSDComputerName = "YOR" + $Namestring + "L"

       Write-TSLogEntry -Value "This device was identified as a laptop and the device name was set to $OSDComputerName" -Severity 1

       } Else {

       Write-TSLogEntry -Value "This device was NOT identified as being a laptop" -Severity 1

       }

 

if ($BatteryExists -eq 0) {

    $OSDComputerName = "YOR" + $Namestring + "D"

       Write-TSLogEntry -Value "This device was identified as a desktop and the device name was set to $OSDComputerName" -Severity 1

       } Else {

       Write-TSLogEntry -Value "This device was NOT identified as being a desktop" -Severity 1

       }

 

# some virtual machines will return a null value so that is handled here

if (!$BatteryExists) {

       $FailSafe = ("VM" + (Get-Random -Minimum 1000 -Maximum 9999))

       Write-TSLogEntry -Value "Battery NULL Failsafe enacted" -Severity 2

       $OSDComputerName = "YOR" + $FailSafe + "D"

       Write-TSLogEntry -Value "BatteryExists variable was a null value so the name was set to $OSDComputerName" -Severity 1

       } Else {

       Write-TSLogEntry -Value "BatteryExists variable was not a null value" -Severity 1

       }

 

# create task sequence variables for the computer name and vm or physical

$TSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

$TSEnv.Value("PSisVM") = "$PSisVM"

$TSEnv.Value("OSDComputerName") = "$OSDComputerName"

   

}

 

 

Much of the logging part of the script was ‘borrowed’ from scripts over at scconfigmgr.com so thank you to them 👍🏼

 

You can see the detailed Task Sequence steps in this post.