Thursday, 29 June 2017

PerfC Vaccination for ExPetr/Petya/NotPetya Wiper

This is a script I've written to 'vaccinate' our domain against the ExPetr/Petya/NotPetya Wiper.

In short, it finds all computer objects in the domain, with an OS that isn't 'Unknown' or 'Windows Server 2003', and attempts to copy 'perfc' to the C:\Windows directory of each machine. I'm not supplying a copy of the file, only the mechanism to deploy it.

If you wish to test the scripts behaviour on a subset of computers on your domain, I've deliberately left a (commented out) searchbase filter on line 24 -


#$WindowsComputers = (get-adcomputer -server $dc -filter * -SearchBase "ou=SOMEOU,dc=YOUR,dc=DOMAIN,dc=HERE").name

....that you can adjust as necessary. Once you've amended line 24, comment out line 20 -

$WindowsComputers = (Get-ADComputer -Server $DC -filter {}).name



This script is provided 'as-is' without warranty of any kind.

EDIT: Fixed bug where summary reported the successful count as the failed count and vice versa
       


#
# Powershell script to copy PerfC vaccine to computers found in Active Directory
#           by Daniel Shuttleworth 
#                credit to @KieranWalsh for his WannaCry PoSH script that this script makes use of
#


# You must specify a source location for PerfC
$Source = "C:\Windows\Perfc"

# You must specify a domain controller here
$DC = "somedc.your.domain"

# Log directory
$log = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath "PerfC presence status for $($ENV:USERDOMAIN).log"

#=========================================================

# Find computer objects in Active Directory
$WindowsComputers = (Get-ADComputer -Server $DC -filter {(OperatingSystem  -notlike 'Windows Server 2003*') -and (OperatingSystem -notlike 'Unknown')}).name | Sort-Object


# If you want to test the script and filter on an OU, I've left the below in..
#$WindowsComputers = (get-adcomputer -server $dc -filter * -SearchBase "ou=SOMEOU,dc=YOUR,dc=DOMAIN,dc=HERE").name

# Count computers found in the domain
$ComputerCount = $WindowsComputers.count
"There are $ComputerCount computers in the domain"

#=========================================================

# Create arrays to deliver counts at the end of processing

$PerfCPresent = @()
$Offline = @()
$CopyFail = @()
$CopySuccess = @()

#=========================================================

# Loop through each computer found in the domain and vaccinate if required 


foreach ($computer in $WindowsComputers)
{
 
 # Check computer is online
 try
 {
  if (Test-Connection $computer -Count 1 -ErrorAction Stop)
  {
   
   # Check if device already has a PerfC file
   $CheckPerfC = Test-Path \\$computer\C$\Windows\Perfc
   
   # If it does, skip to the next computer
   if ($CheckPerfC -eq $true)
   {
    Write-Host -fore Green "File already present, skipping " -NoNewline; write-host -fore White $computer
    $PerfCPresent += $computer
   }
   
   # If it doesn't exist, copy the file and check it copies successfully
   if ($CheckPerfC -eq $false)
   {
    
    write-host -fore Yellow "Copying to " -NoNewline; write-host -fore white $computer
    
    # Copy the file
    Copy-Item C:\Windows\perfc \\$Computer\C$\Windows\
                $CheckPerfCCopy = Test-Path \\$Computer\C$\Windows\perfc
    
    if ($CheckPerfCCopy -eq $true)
    {
     Write-Host -fore Green "File copied successfully to " -NoNewline; write-host -fore White $computer
     $CopySuccess += $computer
    }
    if ($CheckPerfCCopy -eq $false)
    {
     Write-Host -fore Yellow "File not found on " -NoNewline; write-host -fore White $computer -nonewline; write-host -fore Yellow " copy appears to have failed!"
     $CopyFail += $computer
    }
   }
  }
  
 }

 Catch { $Offline+=$Computer }
}


#=========================================================
 
 # Summarise findings
 
 "Summary for domain: $ENV:USERDNSDOMAIN"
 "PerfC Present ($($PerfCPresent.count)):" | Out-File -FilePath $log -Append
 $PerfCPresent -join (', ') | Out-File -FilePath $log -Append
 '' | Out-File -FilePath $log -Append
 "PerfC Copy Succeeded($($CopySuccess.count)):" | Out-File -FilePath $log -Append
 $CopySuccess -join (', ') | Out-File -FilePath $log -Append
 '' | Out-File -FilePath $log -Append
 "PerfC Copy Failed($($CopyFail.count)):" | Out-File -FilePath $log -Append
 $CopyFail -join (', ') | Out-File -FilePath $log -Append
 '' | Out-File -FilePath $log -Append
 "Offline/Untested($(($Offline).count)):" | Out-File -FilePath $log -Append
 $Offline -join (', ') | Out-File -FilePath $log -Append
 
 "Of the $($WindowsComputers.count) windows computers in active directory, $($Offline.count) were off, $($CopyFail.count) had issues copying PerfC, $($CopySuccess.count) were vaccinated this run and $($PerfCPresent.count) had a PerfC vaccine present already."
 'Full details in the log file.'
 
 try
 {
  Start-Process -FilePath notepad++ -ArgumentList $log
 }
 catch
 {
  Start-Process -FilePath notepad.exe -ArgumentList $log
 }


#=========================================================


 

Thursday, 30 March 2017

Opening a CD drive using PowerShell

Whether you want the code because April 1st looms large, or because you're trying to show someone at a remote site which desktop they need to do something with, here it is - 



       

Invoke-Command -ComputerName PC-0101 -ScriptBlock {

$ShApp = New-Object -ComObject "Shell.Application"
$ShApp.Namespace(17).Items() | 
    Where-Object { $_.Type -eq "CD Drive" } | 
        foreach { $_.InvokeVerb("Eject") }
 }

       
 

Tuesday, 21 February 2017

Creating and managing licpath.lic files for use with Autodesk Revit/Autocad network licenses


***Clearing out an old blog, repost from four years ago!***


The Licpath.lic file is the fourth location Autodesk applications look in when determining where to go to obtain a license.

Licpath.lic files can be configured per machine or included in an admin image/deployment script.

Licpath files are created using any plain text editor - Notepad should cover the majority of
users out there. 


They MUST be named Licpath.lic and placed in the applications program files directoy. For example:


C:\Program Files\Autodesk\Revit Architecture 2013\Program\Licpath.lic




The licpath.lic file must be in the following format:


SERVER <server name> <Host ID>
USE_SERVER


For example:



SERVER adsk_flex1 010203040506
USE_SERVER








In this example, our server hostname is adsk_flex1 and its MAC address is 010203040506

If for whatever reason you're using a non-standard port, you can also set this in the licpath file:

SERVER adsk_flex2 010203040506 33868
USE_SERVER

The above file would attempt to communicate using port 33868. (Without a port defined, the software will attempt to access the license server via the default port, 27000)







Additional Information



http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=2887766&linkID=9240617


Creating and managing the adskflex.opt Options File for use with AutoDesk Network License Manager/Flex License Manager

***Clearing out an old blog, repost from four years ago!***


Managing the adskflex.opt Options File




Options files are created using any plain text editor - Notepad should cover the majority of users out there. They MUST be named ADSKFLEX.OPT and placed in the same directory as your license file to take effect.






Options are defined on separate lines and can be as complex or simple as your organisation requires. To insert comments, lines should begin with a #




An example options file used in our environment is as follows:
#Adskflex.opt V1.8
REPORTLOG +"D:\Licenses\Autodesk\REPORT.RL"
MAX 0 71200ACD_2010_0F INTERNET *.*.*.*
MAX 0 85536ACD_2011_0F INTERNET *.*.*.*
MAX 0 85730ACD_2012_0F INTERNET *.*.*.*




#Adskflex.opt V1.8 - This is a comment, as indicated by the # at the start of the line. Use comments regularly to make your file as easy to read as possible.




REPORTLOG +"D:\Licenses\Autodesk\REPORT.RL" -  This line defines the location of the options file report log, useful to check how regularly your options rules are matched






MAX 0 71200ACD_2010_0F INTERNET *.*.*.* 


The above line can be broken up into multiple parts.


Max 0 -  The "Max" option allows us to restrict the maximum license usage. We can restrict by groups of users, IP address, IP address ranges or using the LM_PROJECT variable.


In the rule above, we allow for 0 users of AutoCAD 2010 to obtain a license, with a scope of any IP address


71200AC_2010_0F




This defines the feature code of the application we want to control access to. In this case,. the AutoCAD 2010 feature code is defined. A full list of feature codes for the various Autodesk applications can be accessed via the links below:


Autodesk 2010 Product Suite


Autodesk 2011 Product Suite


Autodesk 2012 Product Suite


Autodesk 2013 Product Suite


Internet


This is the scope the option will apply to. In the example above we apply the option to all IP addresses, as indicated by the wildcard *.*.*.* (Any IP address)
Additional Information


http://usa.autodesk.com/adsk/servlet/ps/dl/item?siteID=123112&id=7459915&linkID=9240617

http://www.globes.com/support/utilities/fnp_LicAdmin_11_9_1.pdf







Output all AD user 'scriptpath' attributes to CSV

As the title suggests, a one liner to output all 'scriptpath' attributes currently set within Active Directory.


Get-ADUser -filter * -properties scriptpath | ft Name, Scriptpath > C:\Temp\AD-ScriptPaths.txt


You may wish to expand on your search by filtering out accurate values, say logon\logon.bat. The following would achieve this -


Get-ADUser -filter {scriptpath -notlike "logon\logon.bat"} -properties scriptpath | ft Name, Scriptpath > C:\Temp\AD-ScriptPaths.txt

Add AD users to group, based on email address

This is a short script I wrote to add a user account to a group, using only the email address associated with the account.

As a side note, this is my first post of the year so perhaps a 'Happy New Year!' is required?!!

To use the script, modify $DC, $users and $group. Remember that $users should point to a text file containing mail addresses, if you wish to use it as I did.
       

# Import AD Module

Import-Module ActiveDirectory

# Get Credentials

$Creds = Get-Credential -Credential "$env:USERNAME"

# Domain Controller to use

$DC = "some.dc.network"

# Path to text file containing usernames to be added to the group
$Users = Get-Content "\\here\are\my\users.txt"

# Group name to add users to
$Group = "Some Group"


# Add users to the group
foreach ($user in $users){
write-host -fore white "Finding user.."
$FoundUser = Get-ADUser -Filter {EmailAddress -eq $user} -Credential $Creds
write-host -fore white "Adding $user to $group"
Try{
Add-ADGroupMember $group $founduser.sid -Credential $Creds -server $DC}
Catch {
write-host -fore Red "Failed to add $user to $group"
}

       
 

Thursday, 1 September 2016

Importing, looping and looping some more..

I've had some issues deploying PowerShell scripts recently via SCCM because some of our clients remain on old versions of the Windows Management Framework and PS2.0. To get around the issue I wrote a short script that makes the required changes from my own machine - or some other, logged on with the appropriate rights.

The example script imports the contents of a specified CSV file, loops through each computer, loops through each user profile on that computer and manipulates an ini file, if found, within any user profile on the device.

       


$Computers = Get-Content "\\server\some\share\computers.csv"

# Loop through computers

foreach ($computer in $computers)
{
 Write-Host "Connecting to $computer"
 $CheckComp = Test-Path "\\$computer\C$"
 
 #If computer is offline
 if ($CheckComp -eq $False)
 {
  Write-Host -fore Red "Can't contact $computer - is it online?"
  sleep 1
  #exit
 }
 
 #If computer is online
 if ($CheckComp -eq $True)
 {
  # Grab the remote contents of C:\Users
  $users = get-childitem "\\$computer\C$\Users\"
  
  # Loop through the remote users and manipulate the .ini file
  foreach ($user in $users)
  {
   $Path = "\\$computer\C$\Users\$user\AppData\Roaming\SomeApplication\LicenseDetails.ini"
   $PathExists = Test-Path $path
   if ($PathExists -eq $true)
   {
    (Get-Content $Path).replace('proxyUse=-1', 'proxyUse=-0') | set-content $Path
    (Get-Content $Path).replace('proxyHost=proxy.some.company.com', 'proxyHost=') | set-content $Path
    (Get-Content $Path).replace('proxyPort=8080', 'proxyPort=') | set-content $Path
    write-host "$user's license file changed"
   }
  }
  
  }
 }

       
 

Friday, 1 July 2016

PowerShell Disk Monitor

Added V1 of my PowerShell Disk Monitor to the TechNet Gallery today.

This is a script written in PowerShell to deliver HTML disk reports via email, based on customisable, per-disk thresholds. It is designed to work in conjunction with a scheduled task.

You can find it with usage notes here - https://gallery.technet.microsoft.com/PowerShell-Disk-Monitor-08b6d759

Monday, 27 June 2016

Lansweeper: Add 'Uptime' to your reports

Found a really useful post here on how to add system uptime to your Lansweeper reports. Add the following to your query to add an additional 'Uptime' column
       

Cast(DateDiff(d, 0, DateAdd(second, DateDiff(s, tblAssets.Lastseen, GetDate()) + 
tblAssets.Uptime, 0)) As VARCHAR(15)) + ' day(s) ' + Convert(VARCHAR(8),DateAdd(second, 
DateDiff(s, tblAssets.Lastseen, GetDate()) + tblAssets.Uptime, 0),108) As Uptime

       
 

Monday, 9 May 2016

Automated Report of Domain Admins using PowerShell

This is a short and simple PowerShell script to output all direct and indirect members of the default Active Directory, Domain Admins group to a CSV. 

To setup the process, take the code below, adjust accordingly and save to a computer with access to the Active Directory PowerShell module.

In the format below, the script will output the Name, Date account was created, Date password was last set, whether the user can change the password, if the account is enabled and finally, the SID.

The above information is outputted to the folder $Path and the default file name is DomainAdmins_dd-MM-yyyy.csv

Items in bold should be correctly configured.

       

Import-Module ActiveDirectory

$Today = Get-Date -Format dd-MM-yyyy
$Path = "\\some\path"
$File = "DomainAdmins" + "_" + $Today + ".csv"

Get-ADGroupMember "Domain Admins" -Recursive | Get-ADUser -Properties PasswordLastSet,CannotChangePassword,Enabled,SID,Created | Select-Object Name,Created,PasswordLastSet,CannotChangePassword,Enabled,SID | export-csv -path "$Path\$File.csv" -NoTypeInformation

       
 


To automate this task, save it to a machine where the AD PowerShell module is available and build a scheduled task suited to your requirements.


General
- Name: Domain Admins Report
- When running the task, use the following user account: domain\service-account
- Run whether user is logged on or not


Triggers
Begin the task: On a schedule
Settings - Weekly
Start *SomeDate* 22:00:00
   - Recur every: 1 weeks on Friday
Stop task if it runs longer than 1 hour (or 30mins for a small environment)
Enabled

Actions
Action: Start a program

Settings
Program/script: powershell.exe
Add arguments (optional): -nologo -File "C:\Scripts\ReportDomainAdmins.ps1"


Right click your newly created task and select 'Run' to test.


Tuesday, 3 May 2016

Account Lockout Notifications using PowerShell


This is a short and simple PowerShell script to alert an administrative mailbox, group mailbox or even the account in question that its account has locked out.

To setup the process, take the code below, adjust accordingly and save to your PDC, the DC your lockouts will always hit.

In the format below the script will send an email to $MailTo, from $MailFrom with a subject of $MailSubject via mail server $SMTPServer on port $SMTPPort.
The content of the email is held within $MailBody.

Items in bold should be correctly configured.

       

Import-Module ActiveDirectory

$AccountLockOutEvent=Get-EventLog -LogName "Security" -InstanceID 4740 -Newest 1
$LockedAccount = $($AccountLockOutEvent.ReplacementStrings[0])
$AccountLockOutEventTime = $AccountLockOutEvent.TimeGenerated
$AccountLockOutEventMessage = $AccountLockOutEvent.Message

$ADUserDisplayName = (Get-ADUser $LockedAccount -Properties DisplayName).DisplayName

$MailFrom = "AccountLockout@company.co"
$MailTo = "SomeUser@company.co"
$SMTPServer = "mailserver.company.local"
$SMTPPort = "25"
$MailSubject = "User Account Locked Out: $LockedAccount / $ADUserDisplayName" 
$MailBody = "Account $LockedAccount was locked out on $AccountLockOutEventTime.`n`nEvent Details:`n`n$AccountLockOutEventMessage`n`nUser: $ADUserDisplayName"

$EmailMessage = New-Object System.Net.Mail.MailMessage($MailFrom , $MailTo)
$emailMessage.Subject = $Mailsubject
$emailMessage.Body = $Mailbody

$SmtpClient = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort)
$SmtpClient.Send($emailMessage)

       
 


The second and final step is to configure a scheduled task to run when a 4740 error (Account Locked Out) is logged to the security event log.

The parameters for my scheduled task are as follows:


General
- Name: Account Lockout Email
- Run whether user is logged on or not

Triggers
Begin the task: On an event
Settings - Basic
Log: Security 
Source: Microsoft Windows security audting.
Event ID: 4740
Enabled: True

Actions
Action: Start a program

Settings
Program/script: powershell.exe
Add arguments (optional): -nologo -File "C:\Scripts\EmailOnLockout.ps1"




Tuesday, 15 March 2016

Comparison of VMXNet3 vs. E1000E


I'm a big fan of VMWare and we utilise their products heavily day to day. I found the following post whilst looking for some detailed information on the various virtual network adapters available.

The results are fascinating and have prompted me to rethink existing adapter selection, as well as future.

Credit to Rickard Nobel for the post - 

http://rickardnobel.se/vmxnet3-vs-e1000e-and-e1000-part-1/

Pushing Lync phone updates to a test device


As we look to move away from SHA-1 internally, there is a need to once again update our Lync Phone edition devices, this time with the December 2015 phone edition cumulative update that provides support for SHA-2 based certificates ( https://support.microsoft.com/en-us/kb/3108721 )


The process is very simple to implement, though you'll need some patience...



First of all, you'll need to bring your updates into your Lync environment. You can't do this via the GUI so you'll need to jump into the Lync Management Shell.


The cmdlet you want is Import-CsDeviceUpdate (Technet page here)


The parameters you'll want to use are -identity , used to point the cmdlet to your pool and -FileName to point to your extracted UCUpdates.cab


Something like...


       

            Import-CsDeviceUpdate -Identity service:WebServer:lync.dshu.local -FileName C:\Updates\UCUpdates.cab

       
 
The cmdlet will take a few seconds to complete but once done, the updates should be visible within the Lync Server Control Panel > Clients > Device Update. Devices should now show a Pending Version


You can also confirm the import was successful by accessing the Lync File Share and looking inside the Device Update Store -


\\localhost\lyncshare\1-WebServices-1\DeviceUpdateStore\UCPhone\POLYCOM\CX600\Rev-6\ENU\4.0.7577.4487\CPE


Now that your updates are imported, you can configure your test device..




  1. Open the Lync Server Control Panel
  2. Go to Clients > Test Device
  3. New > Global / Site Test Device
  4. Give the device a name that makes sense and then add the phone’s MAC address or serial number in the "Unique identifier" field
  5. Now wait...or...
The theory goes that the device will check to see if there are updates available within a minute of going idle. Once this timer is hit, the device will wait for a further 10minutes before beginning the installation - the idea being that the device is truly idle and can be updated without impacting upon a user. However, if you reboot the phone it will sign itself back in (assuming it was signed in), lock and immediately start your inactivity timer.

Logs can be found in C:\inetpub\logs\LogFiles\W3SVC and will give you an idea as to what is going on throughout the process. 


The key to having your device update as quickly as possible is to leave it alone - resist the temptation to touch it!


FYI - Updates do not need to be approved to be installed by test devices

Tuesday, 1 March 2016

Deploying a Powershell script via SCCM 2012


Create your package as normal, in my example I created a package that will house all of my PS scripts. Make sure it's distributed to all of your DPs / Dist groups.

Once created, setup your package with the following program for each script - 

       

            powershell.exe -executionpolicy Bypass -nologo -noninteractive -file .\SomeScript.ps1

       
 

Et voilĂ !

Wednesday, 17 February 2016

Lync/SfB Federation Finder

This is a simple PowerShell script I wrote to assist in locating a 3rd party federated edge server.

The script takes user input to then use DNS to attempt to resolve _sipfederationtls._tcp.somedomain 

       
$Domain = Read-Host "Domain to find SIP Federation SRV record for?
$SRVRecord = Resolve-DnsName -Name ("_sipfederationtls._tcp." + $Domain) -Type SRV
$SRVRecord
       
 

PerfC Vaccination for ExPetr/Petya/NotPetya Wiper

This is a script I've written to 'vaccinate' our domain against the ExPetr/Petya/NotPetya Wiper. In short, it finds all comput...