Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <#
- Written by David Ott
- Modified by Ed Hammond 3.9.2017 - http://edhammond.blogspot.com/
- Ed Hammond v2.1 Change log:
- -Added more details and graphics to the email
- -Added a better description inside the QR Code so that your Company and Email address show up in Google Authenticator. (line 237)
- -When the Powershell writes back to the database on line 232 I added Feitian Serial and the 30 second time out to that line. Feitian Serial seems to be required and not Google Authenticator for some reason.
- This script is for mass deployment of SMS2 TOTP codes (version 2!) for use with Google/Azure Authenticator
- *****You need to run this with an account that has modify rights to the SMS2 database!*****
- Read through the script and note any variables you need to change for your environment - I have
- marked them with comments ##### <-- just search for that
- Take special care to read anything marked with "*****"
- I wrote it because as of right now there is no tool for SMS2 to deploy multiple TOTP keys at once (you
- have to do them one at a time)
- ***** you will need qrcode.exe from https://code.google.com/p/qrencode-win32/wiki/Downloads for generating QR barcodes *****
- I have to give credit to this page https://gist.github.com/JonFriesen/234c7471c3e3199f97d5 for
- the conversion of the base32 secret to hex (which is used in the database)
- Also, this page http://www.sharepointfire.com/MyBlog/2011/12/send-email-with-images-in-powershell/ for
- helping me edit my sendmail function to imbed an image
- I in no way shape or form provide technical support for this script. Do not use it in production until you have
- tested it in a development environment!
- #>
- #requires -version 4
- <#####***** This version requires the Active Directory module! *****#####>
- try {
- ipmo activedirectory
- } catch {
- write-host "Requires Active Directory module" -f Red
- break
- }
- function Convert-Base32ToHex($base32) {
- $base32chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
- $bits = "";
- $hex = "";
- for ($i = 0; $i -lt $base32.Length; $i++) {
- $val = $base32chars.IndexOf($base32.Chars($i));
- $binary = [Convert]::ToString($val, 2)
- $staticLen = 5
- $padder = '0'
- $bits += Add-LeftPad $binary.ToString() $staticLen $padder
- }
- for ($i = 0; $i+4 -le $bits.Length; $i+=4) {
- $chunk = $bits.Substring($i, 4)
- $intChunk = [Convert]::ToInt32($chunk, 2)
- $hexChunk = Convert-IntToHex($intChunk)
- $hex = $hex + $hexChunk
- }
- return $hex;
- }
- function Convert-IntToHex([int]$num) {
- return ('{0:x}' -f $num)
- }
- function Add-LeftPad($str, $len, $pad) {
- if(($len + 1) -ge $str.Length) {
- while (($len - 1) -ge $str.Length) {
- $str = ($pad + $str)
- }
- }
- return $str;
- }
- function sendMail{
- <##### Change the smtp server to yours #####>
- $smtpServer = "yoursmtp.company.com"
- $msg = new-object Net.Mail.MailMessage
- $att1 = new-object Net.Mail.Attachment($img)
- $att1.ContentType.MediaType = “image/png”
- $att1.ContentId = “Attachment”
- $msg.Priority = [System.Net.Mail.Mailpriority]::High
- $msg.IsBodyHtml = $true
- $msg.Attachments.add($att1)
- $smtp = new-object Net.Mail.SmtpClient($smtpServer)
- <##### set your from address #####>
- $msg.From = "Notification@yourcompany.com"
- $msg.To.Add($address)
- $msg.subject = "Two Factor Authentication"
- $msg.body = $message
- $smtp.Send($msg)
- }
- <##### csv file to store information - just make sure the folder exists #####>
- $file = "\\server\share\logs\totplog.csv"
- <##### Directory to store the QR .png files #####>
- $qrdir = "\\server\share\QR\"
- <##### Place qrcode.exe (link above) in the same directory where you are putting the QR .png files
- you can change this if you want but you have to update the path to qrcode.exe below #####>
- $qrcode = Join-Path $qrdir "qrcode.exe"
- if (!(test-path $file)) {
- $oldlog = @()
- } else {
- $oldlog = Import-Csv $file
- }
- <##### Edit the $sqlserver variable to equal your sql server name and if the database is not SMS_DB
- update the $sqldbname variable - remember you must run this script as an AD user who has rights to edit
- the database!! #####>
- $SQLServer = "SQLServerName"
- $SQLDBName = "SMS_DB"
- $SqlQuery = "select * from SMS_Contact"
- $SqlQuery1 = "select * from UserProviders"
- $SqlConnection = New-Object System.Data.SqlClient.SqlConnection
- $SqlConnection.ConnectionString = "Server = $SQLServer; Database = $SQLDBName; Integrated Security = True; MultipleActiveResultSets = True"
- $SqlCmd = New-Object System.Data.SqlClient.SqlCommand
- $SqlCmd.CommandText = $SqlQuery
- $SqlCmd.Connection = $SqlConnection
- $SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
- $SqlAdapter.SelectCommand = $SqlCmd
- $DataSet = New-Object System.Data.DataSet
- $SqlAdapter.Fill($DataSet)
- $SqlCmd1 = New-Object System.Data.SqlClient.SqlCommand
- $SqlCmd1.CommandText = $SqlQuery1
- $SqlCmd1.Connection = $SqlConnection
- $SqlAdapter1 = New-Object System.Data.SqlClient.SqlDataAdapter
- $SqlAdapter1.SelectCommand = $SqlCmd1
- $DataSet1 = New-Object System.Data.DataSet
- $SqlAdapter1.Fill($DataSet1)
- [array]$users = $dataset.tables[0] | ?{$_.userstatus -eq "1"}
- [array]$codes = $dataset1.tables[0]
- <#####***** Here is where this script starts to really differ from the first one I created. This next bit will prompt you
- for the SAMACCOUNTNAME of an AD group. If the group does not exist, or is invalid it will start gathering information on
- ALL users in AD. This can take some time to process depending on how many users are in the group/domain. It has to compare
- 2 tables in the database for each user to see if there is a TOTP value or not - in the end lets you know which users are
- already configured in the out-gridview *****#####>
- $gp = Read-Host "Enter the SamAccountName of the AD Group you wish to focus on`r`nIf you do not supply a any information, or if the SamAccountName`r`nis invalid you will be returned all users"
- $gpt = "0"
- try {
- $testgp = Get-ADGroup $gp
- $gpt = "1"
- } catch {
- $gpt = "0"
- }
- $users1 = $null
- if ($gpt -eq "0") {
- <#####***** If the group SAMACCOUNTNAME is invalid or not supplied this will get a count of all users in the database.
- I filter out some based on name. "Radiusu" is the user I use from the netscaler to monitor SMS2, so if you have something
- like that you should filter that user out. I also filter out some default accounts, and computer accounts *****#####>
- Write-Host "AD group name invalid, or not entered. Gathering information on ALL users.`r`nThis will take a long time... get some coffee" -f Red
- $z = 0
- <#####***** Gets the count of all users in the database (you may need to edit the filters for your environment), so the progress bar
- will work *****#####>
- $adc = ($users | ?{$_.ad_username -ne "radiusu"` #####***** Radiusu is a user I use to monitor SMS2 from the Netscaler
- -and $_.ad_username -notlike "*$*"`
- -and $_.ad_username -notlike "sm_*"`
- -and $_.ad_username -notlike "cntd_*"`
- -and $_.ad_username -notlike "IUSR_*"`
- -and $_.ad_username -notlike "IWAM_*"`
- -and $_.ad_username -notlike "ILS_*"}).count
- <#####***** Gets all the users in the database (again you may need to edit the filters for your environment). Then for each
- one checks to see if they already have a totp code setup (that can take a while depending on how many users it has to process).
- Once it has gathered all the information it will spit it out in a grid and you can select which users you want to configure.
- *****#####>
- $users1 = $users | ?{$_.ad_username -ne "radiusu"` #####***** Radiusu is a user I use to monitor SMS2 from the Netscaler
- -and $_.ad_username -notlike "*$*"`
- -and $_.ad_username -notlike "sm_*"`
- -and $_.ad_username -notlike "cntd_*"`
- -and $_.ad_username -notlike "IUSR_*"`
- -and $_.ad_username -notlike "IWAM_*"`
- -and $_.ad_username -notlike "ILS_*"} | select id,ad_username,display_name,email | %{
- $z++
- Write-Progress -Activity "Gathering Users" -Status "User $z of $adc" -PercentComplete ($z/$adc*100)
- $bid = $null
- $bid = $_.id
- $_ | select id,ad_username,display_name,email,@{name="Configured";expression={if (($codes | ?{$_.userid -eq $bid -and $_.authproviderid -eq "2"} | select -expand config) -like "totp*"){$true}else{$false} }}
- } | sort configured | Out-GridView -PassThru -Title "Users"
- } else {
- <#####***** If the SAMACCOUNTNAME of the group is valid the script grabs every user object in the group recursively (nested
- groups). Then for each user - if the user is enabled in AD - it will process like above. *****#####>
- $adus = $null
- $adus = Get-ADGroupMember $gp -Recursive | ?{$_.objectclass -eq "user"} | select -expand samaccountname | %{
- if ((Get-ADUser $_).enabled -eq $true) {
- $_
- }
- } | sort -unique
- Write-Host "Group $gp is valid. Please wait as information is gathered on" $adus.count "users." -f Green
- $z = 0
- $adc = $adus.count
- $users1 = $users | ?{$adus -eq $_.ad_username} | select id,ad_username,display_name,email | %{
- $z++
- Write-Progress -Activity "Gathering Users" -Status "User $z of $adc" -PercentComplete ($z/$adc*100)
- $bid = $null
- $bid = $_.id
- $_ | select id,ad_username,display_name,email,@{name="Configured";expression={if (($codes | ?{$_.userid -eq $bid -and $_.authproviderid -eq "2"} | select -expand config) -like "totp*"){$true}else{$false} }}
- } | sort configured | Out-GridView -PassThru -Title "Users"
- }
- <#####***** If you don't select any users in the gridview this will end the script *****#####>
- if (($users1 | Measure-Object).count -lt "1") {break}
- <#####***** Here is where the magic starts to happen! For each user you selected it will create a random totp string, convert
- it to hex (which is used in the database), update the .csv log file, write the totp information to the database, create the
- QR .png file, email the information to the user (if they do not appear to have an email address it will display the
- information in the PS window to send the user on the screen), and finally remove the user from the exclusion group (see
- the very end of the script for more info). *****#####>
- $arrayall = @()
- $arrayall += $oldlog
- $SqlConnection.open()
- foreach ($user in $users1) {
- $totp = (([char[]](Get-Random -Input $(50..55 + 65..90 + 97..122) -Count 16)) -join "").toupper()
- $hex = (Convert-Base32ToHex -base32 $totp).toupper()
- $id = $null
- $un = $null
- $em = $null
- [string]$id = $user.ID
- [string]$un = ($user.AD_USERNAME).toupper()
- [string]$em = ($user.email).tolower()
- if ($arrayall | ?{$_.username -eq "$un"}) {
- $userupdate = $null
- $userupdate = ($arrayall | ?{$_.username -eq "$un"})
- $userupdate.totp = $totp
- $userupdate.hex = $hex
- } else {
- $update = $null
- $update = New-Object psobject
- $update | Add-Member -type NoteProperty -name 'id' -Value $id
- $update | Add-Member -type NoteProperty -name 'username' -Value $un
- $update | Add-Member -type NoteProperty -name 'email' -Value $em
- $update | Add-Member -type NoteProperty -name 'totp' -Value $totp
- $update | Add-Member -type NoteProperty -name 'hex' -Value $hex
- $arrayall += $update
- }
- $arrayall | Export-Csv $file
- $SqlCmd2 = $null
- $SqlCmd2 = New-Object System.Data.SqlClient.SqlCommand
- $sqlcmd2.commandtext = "update userProviders
- set config = 'TOTP,$hex,0,30,Default,Feitian Serial'
- where userId = '$id' AND authProviderId = '2'"
- $sqlcmd2.Connection = $SqlConnection
- $sqlcmd2.ExecuteReader()
- <#####***** You can replace the "Work-VPN" with your company on the end of the next line. If you add spaces you will need to escape or quote them correctly *****#####>
- Invoke-Expression -Command "$qrcode -o $qrdir\$un.png -s 3 -l H otpauth://totp/$em`?secret=$totp""&""issuer=Work-VPN"
- if ($em -notlike "*@*") {
- Write-Host "User $un does not have an email address associated with their account!" -f Red
- Write-Host "You will need to give this user their secret key `"$totp`" and/or QR code`r`n $qrdir\$un.png`r`n"
- } else {
- $address = $em
- $img = "$qrdir\$un.png"
- <#####***** Below is the message in HTML format that your users will be sent to your users. I suggest setting up a test
- URL for your users (you will need to edit the message to fit your environment). Also, if you have a helpdesk email address edit
- that line as well. In order for the QR code and totp string to show up in the email make sure you leave the
- <img src="cid:Attachment"><br>
- $totp
- lines alone.
- *****#####>
- $message = @"
- <html>
- <body>
- <style>
- body {
- background-color: White;
- }
- p,ul,li {
- font-family: Arial, sans-serif;
- font-size: 14px;
- }
- </style>
- <img src="###http://mycompanyhomepage.com/logo.png###"><br>
- <p>We are adding a Two factor Authentication requirement for VPN access.
- <br>You will need to install Google Authenticator from the app store on your phone and then scan the QR code with Google Authenticator app.
- <br>Your Secure QR code and secret key can be found below.
- <br>Please use either the code or the secret key to setup the Google Authenticator token on your smartphone, and then delete this email.
- <br>Be aware that it is crucial to keep this information safe from hackers by deleting this email when your done.<br>
- <img src="cid:Attachment"><br>
- $totp
- </p>
- <p>When you connect to the VPN, you will login as usual and then a second window will ask you to enter the code from Google Authenicator.<br><br><br>
- If authentication fails, please contact the <a href="mailto:helpdesk@yourcompany.com?subject=Two Factor Authentication Help">Help Desk</a> for assistance.
- <br><br>
- <a href="https://itunes.apple.com/us/app/google-authenticator/id388497605?mt=8">Get Google Authenticator for your iPhone</a><br><br>
- <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en">Get Google Authenticator for your Android Phone</a><br><br>
- <img src="http://a2.mzstatic.com/us/r30/Purple49/v4/a8/3d/8c/a83d8cde-dd69-de15-3561-a118d59b4be4/screen696x696.jpeg">
- </body>
- </html>
- "@
- Write-Host "Sending email to $un"
- sendMail
- }
- <#####***** In my environment I have a 2 factor exclusion group. If you are in it you don't have to supply a token code when
- logging in (or can put in anything in that box). This will remove the user from that group. If you have something similar
- edit the group name below. If not then remove or comment out the next 5 lines. *****#####>
- try {
- Remove-ADGroupMember 2factorexclude $un -Confirm:$false
- } catch {
- $null
- }
- }
- $SqlConnection.close()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement